Beispiel #1
0
def create_instrument_quotes(quotes_effective_date, today, instrument_prices,
                             analyst_scope_code, api_factory):
    # Create prices via instrument, analytic
    # Set our quotes effective dates
    now = datetime.now(pytz.UTC).replace(hour=0,
                                         minute=0,
                                         second=0,
                                         microsecond=0)
    quotes_effective_date = now - timedelta(days=3)
    today = now

    instrument_quotes = {}

    # Create prices for all instruments except cash
    for index, instrument in instrument_prices.iterrows():

        if 'Cash' in instrument['instrument_name']:
            continue

        # Get our Lusid Instrument Id
        luid = api_factory.build(lusid.api.InstrumentsApi).get_instrument(
            identifier_type='Figi',
            identifier=instrument['figi']).lusid_instrument_id

        instrument_quotes[
            luid + str(quotes_effective_date)] = models.UpsertQuoteRequest(
                quote_id=models.QuoteId(quote_series_id=models.QuoteSeriesId(
                    provider='DataScope',
                    instrument_id=luid,
                    instrument_id_type='LusidInstrumentId',
                    quote_type='Price',
                    field='Mid'),
                                        effective_at=quotes_effective_date),
                metric_value=models.MetricValue(
                    value=instrument["price_original"],
                    unit=instrument["currency"]),
                lineage='InternalSystem')

        instrument_quotes[luid + str(today)] = models.UpsertQuoteRequest(
            quote_id=models.QuoteId(quote_series_id=models.QuoteSeriesId(
                provider='DataScope',
                instrument_id=luid,
                instrument_id_type='LusidInstrumentId',
                quote_type='Price',
                field='Mid'),
                                    effective_at=today),
            metric_value=models.MetricValue(value=instrument["price_current"],
                                            unit=instrument["currency"]),
            lineage='InternalSystem')

    response = api_factory.build(lusid.api.QuotesApi).upsert_quotes(
        scope=analyst_scope_code, request_body=instrument_quotes)

    prettyprint.upsert_quotes_response(response)
    def upsert_ratings_property(self, figi, fitch_value=None, moodys_value=None):

        properties = {
            f"Instrument/{scope}/FitchRating": fitch_value,
            f"Instrument/{scope}/MoodysRating": moodys_value,
        }

        # upsert property definition
        for key in properties:
            if properties[key] is not None:
                property_request = [
                    models.UpsertInstrumentPropertyRequest(
                        identifier_type="Figi",
                        identifier=figi,
                        properties=[
                            models.ModelProperty(
                                key=key,
                                value=models.PropertyValue(
                                    metric_value=models.MetricValue(
                                        value=properties[key]
                                    )
                                ),
                            )
                        ],
                    )
                ]

                self.instruments_api.upsert_instruments_properties(
                    upsert_instrument_property_request=property_request
                )
    def test_create_portfolio_with_metric_property(self):
        uuid = self.get_guid()
        effective_date = datetime(year=2018, month=1, day=1, tzinfo=pytz.utc)

        # details of property to be created
        metric_property_definition = models.CreatePropertyDefinitionRequest(
            domain="Portfolio",
            scope=TestDataUtilities.tutorials_scope,
            code="fund-NAV-{}".format(uuid),
            display_name="fund NAV",
            life_time="Perpetual",
            value_required=False,
            data_type_id=models.resource_id.ResourceId(
                scope="system", code="currencyAndAmount"))

        # create property definitions
        metric_property_definition_result = self.property_definitions_api.create_property_definition(
            metric_property_definition)

        # create the property values
        metric_property_value_request = models.PropertyValue(
            metric_value=models.MetricValue(value=1100000, unit="GBP"))
        # metric_property_value_request = models.PropertyValue(label_value="Active")

        # Details of the new portfolio to be created, created here with the minimum set of mandatory fields
        create_portfolio_request = models.CreateTransactionPortfolioRequest(
            code="ud-{}".format(uuid),
            display_name="portfolio-{}".format(uuid),
            base_currency="GBP",
            created=effective_date,
            properties={
                metric_property_definition_result.key:
                models.PerpetualProperty(
                    key=metric_property_definition_result.key,
                    value=metric_property_value_request)
            })

        # Create portfolio
        portfolio_result = self.transaction_portfolios_api.create_portfolio(
            scope=TestDataUtilities.tutorials_scope,
            create_transaction_portfolio_request=create_portfolio_request)
        portfolio_properties = self.portfolios_api.get_portfolio_properties(
            scope=TestDataUtilities.tutorials_scope,
            code=portfolio_result.id.code).properties
        metric_property = portfolio_properties[
            metric_property_definition_result.key]

        # Perform assertions on codes, keys, values and units
        self.assertEqual(portfolio_result.id.code,
                         create_portfolio_request.code)
        self.assertEqual(
            list(portfolio_properties.keys())[0],
            metric_property_definition_result.key)
        self.assertEqual(metric_property.value.metric_value.value,
                         metric_property_value_request.metric_value.value)
        self.assertEqual(metric_property.value.metric_value.unit,
                         metric_property_value_request.metric_value.unit)
Beispiel #4
0
def create_property_values(row, null_value, scope, domain, dtypes):
    """
    This function generates the property values for a row in a file

    :param Pandas Series row:
    :param number null_value:
    :param str scope:
    :param str domain:
    :return: dict {str, models.PerpetualProperty} properties:
    """
    # Ensure that all data types in the file have been mapped
    if not (set([str(data_type) for data_type in dtypes.unique()]) <= set(
            globals['data_type_mapping'])):
        raise Exception(
            '''There are data types in the data_frame which have not been mapped to LUSID data types,
            please ensure that all data types have been mapped before retrying'''
        )

    # Initialise the empty properties dictionary
    properties = {}

    # Iterate over each column name and data type
    for column_name, data_type in dtypes.iteritems():

        # Set the data type to be a string so that it is easier to work with
        string_data_type = str(data_type)
        # Convert the numpy data type to a LUSID data type using the global mapping
        lusid_data_type = globals['data_type_mapping'][string_data_type]
        # Get the value of the column from the row
        row_value = row[column_name]

        # Use the correct LUSID property value based on the data type
        if lusid_data_type == 'string':
            if pd.isna(row_value):
                row_value = str(null_value)
            property_value = models.PropertyValue(label_value=row_value)

        if lusid_data_type == 'number':
            # Handle null values given the input null value override
            if pd.isnull(row_value):
                row_value = null_value

            property_value = models.PropertyValue(
                metric_value=models.MetricValue(value=row_value))

        # Set the property
        properties['{}/{}/{}'.format(
            domain, scope,
            make_code_lusid_friendly(column_name))] = models.PerpetualProperty(
                key='{}/{}/{}'.format(domain, scope,
                                      make_code_lusid_friendly(column_name)),
                value=property_value)

    return properties
    def test_add_quote(self):

        request = models.UpsertQuoteRequest(quote_id=models.QuoteId(
            models.QuoteSeriesId(provider="DataScope",
                                 instrument_id="BBG000B9XRY4",
                                 instrument_id_type="Figi",
                                 quote_type="Price",
                                 field="mid"),
            effective_at=datetime(2019, 4, 15, tzinfo=pytz.utc)),
                                            metric_value=models.MetricValue(
                                                value=199.23, unit="USD"))

        self.quotes_api.upsert_quotes(TestDataUtilities.tutorials_scope,
                                      request_body={"quote1": request})
Beispiel #6
0
def upsert_quotes(
    api_factory,
    scope,
    data_frame,
    instrument_identifier_mapping,
    instrument_identifier_heirarchy,
    required_mapping,
):
    """
    This function takes quotes from a data_frame and upserts them into LUSID
    
    param (lusid.utilities.ClientApiFactory) api_factory: The LUSID api factory to use
    param (str) scope: The LUSID scope to upsert the quotes into
    param (Pandas DataFrame) data_frame: The DataFrame that the quotes are in
    param (dict) instrument_identifier_mapping : The dictionary with the instrument identifier mapping between LUSID and the dataframe
    param (list[str]) instrument_identifier_heirarchy : The heirarchy to use for the LUSID instrument identifiers when upserting quotes
    param (dict) required_mapping: The mapping of the LUSID required quote fields to the dataframe fields
    
    
    returns (Pandas DataFrame): The succesfully upserted quotes
    """

    # Initialise an empty instrument quotes list to hold the quotes
    instrument_quotes = {}

    quote_type_values = {
        "mid_price": {
            "quote_type": "Price",
            "price_side": "Mid",
            "value": "price",
        },
        "mid_rate": {
            "quote_type": "Rate",
            "price_side": "Mid",
            "value": "rate",
        },
    }

    # Iterate over the quotes
    for index, quote in data_frame.iterrows():

        quote_type = quote_type_values[quote[
            required_mapping["quote_type"]]]["quote_type"]
        field = quote_type_values[quote[
            required_mapping["quote_type"]]]["price_side"]

        for identifier in instrument_identifier_heirarchy:

            identifier_value = quote[instrument_identifier_mapping[
                "identifier_mapping"][identifier]]

            if (identifier == "CurrencyPair") and (len(identifier_value) == 6):
                identifier_value = identifier_value[:
                                                    3] + "/" + identifier_value[
                                                        3:]

            if not pd.isna(identifier_value):
                break

        # Add the quote to the list of upsert quote requests
        effective_date = quote[required_mapping["effective_at"]]

        instrument_quotes[identifier + "_" + identifier_value + "_" +
                          effective_date] = models.UpsertQuoteRequest(
                              quote_id=models.QuoteId(
                                  quote_series_id=models.QuoteSeriesId(
                                      provider="DataScope",
                                      instrument_id=identifier_value,
                                      instrument_id_type=identifier,
                                      quote_type=quote_type,
                                      field=field,
                                  ),
                                  effective_at=effective_date,
                              ),
                              metric_value=models.MetricValue(
                                  value=quote[required_mapping["value"]],
                                  unit=quote[required_mapping["currency"]],
                              ),
                              lineage="InternalSystem",
                          )

    # Upsert the quotes into LUSID
    response = api_factory.build(lusid.api.QuotesApi).upsert_quotes(
        scope=scope, request_body=instrument_quotes)

    # Pretty print the response
    # prettyprint.upsert_quotes_response(response)
    return prettyprint.upsert_quotes_response(response)
    def test_portfolio_aggregation(self):

        effective_date = datetime(2019, 4, 15, tzinfo=pytz.utc)

        portfolio_code = self.test_data_utilities.create_transaction_portfolio(
            TestDataUtilities.tutorials_scope)

        transactions = [
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[0],
                units=100,
                price=101,
                currency="GBP",
                trade_date=effective_date,
                transaction_type="StockIn"),
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[1],
                units=100,
                price=102,
                currency="GBP",
                trade_date=effective_date,
                transaction_type="StockIn"),
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[2],
                units=100,
                price=103,
                currency="GBP",
                trade_date=effective_date,
                transaction_type="StockIn")
        ]

        self.transaction_portfolios_api.upsert_transactions(
            scope=TestDataUtilities.tutorials_scope,
            code=portfolio_code,
            transactions=transactions)

        prices = [
            models.InstrumentAnalytic(self.instrument_ids[0], 100),
            models.InstrumentAnalytic(self.instrument_ids[1], 200),
            models.InstrumentAnalytic(self.instrument_ids[2], 300)
        ]

        requests = []
        for i in range(3):
            requests.append(
                models.UpsertQuoteRequest(
                    quote_id=models.QuoteId(models.QuoteSeriesId(
                        provider="DataScope",
                        instrument_id=self.instrument_ids[i],
                        instrument_id_type="LusidInstrumentId",
                        quote_type="Price",
                        field="mid"),
                                            effective_at=effective_date),
                    metric_value=models.MetricValue(value=prices[i].value,
                                                    unit="GBP")))

        self.quotes_api.upsert_quotes(
            TestDataUtilities.tutorials_scope,
            quotes={
                "quote" + str(request_number): requests[request_number]
                for request_number in range(len(requests))
            })

        inline_recipe = models.ConfigurationRecipe(
            code='quotes_recipe',
            market=models.MarketContext(
                market_rules=[],
                suppliers=models.MarketContextSuppliers(equity='DataScope'),
                options=models.MarketOptions(
                    default_supplier='DataScope',
                    default_instrument_code_type='LusidInstrumentId',
                    default_scope=TestDataUtilities.tutorials_scope)))

        aggregation_request = models.AggregationRequest(
            inline_recipe=inline_recipe,
            metrics=[
                models.AggregateSpec("Instrument/default/Name", "Value"),
                models.AggregateSpec("Holding/default/PV", "Proportion"),
                models.AggregateSpec("Holding/default/PV", "Sum")
            ],
            group_by=["Instrument/default/Name"],
            effective_at=effective_date)

        #   do the aggregation
        aggregation = self.aggregation_api.get_aggregation_by_portfolio(
            scope=TestDataUtilities.tutorials_scope,
            code=portfolio_code,
            request=aggregation_request)

        for item in aggregation.data:
            print("\t{}\t{}\t{}".format(item["Instrument/default/Name"],
                                        item["Proportion(Holding/default/PV)"],
                                        item["Sum(Holding/default/PV)"]))

        # Asserts
        self.assertEqual(len(aggregation.data), 3)
        self.assertEqual(aggregation.data[0]["Sum(Holding/default/PV)"], 10000)
        self.assertEqual(aggregation.data[1]["Sum(Holding/default/PV)"], 20000)
        self.assertEqual(aggregation.data[2]["Sum(Holding/default/PV)"], 30000)
Beispiel #8
0
def metric(m):
    return api.models.PropertyValue(metric_value=models.MetricValue(
        value=float(m)))
Beispiel #9
0
    def test_portfolio_aggregation(self):

        effective_date = datetime(2019, 4, 15, tzinfo=pytz.utc)

        portfolio_code = self.test_data_utilities.create_transaction_portfolio(TestDataUtilities.tutorials_scope)
        self.id_generator.add_scope_and_code("portfolio", TestDataUtilities.tutorials_scope, portfolio_code)

        transactions = [
            self.test_data_utilities.build_transaction_request(instrument_id=self.instrument_ids[0],
                                                               units=100,
                                                               price=101,
                                                               currency="GBP",
                                                               trade_date=effective_date,
                                                               transaction_type="StockIn"),
            self.test_data_utilities.build_transaction_request(instrument_id=self.instrument_ids[1],
                                                               units=100,
                                                               price=102,
                                                               currency="GBP",
                                                               trade_date=effective_date,
                                                               transaction_type="StockIn"),
            self.test_data_utilities.build_transaction_request(instrument_id=self.instrument_ids[2],
                                                               units=100,
                                                               price=103,
                                                               currency="GBP",
                                                               trade_date=effective_date,
                                                               transaction_type="StockIn")
        ]

        self.transaction_portfolios_api.upsert_transactions(scope=TestDataUtilities.tutorials_scope,
                                                            code=portfolio_code,
                                                            transaction_request=transactions)

        prices = [
            (self.instrument_ids[0], 100),
            (self.instrument_ids[1], 200),
            (self.instrument_ids[2], 300)
        ]

        requests = [
            models.UpsertQuoteRequest(
                quote_id=models.QuoteId(
                    models.QuoteSeriesId(
                        provider="DataScope",
                        instrument_id=price[0],
                        instrument_id_type="LusidInstrumentId",
                        quote_type="Price",
                        field="mid"
                    ),
                    effective_at=effective_date
                ),
                metric_value=models.MetricValue(
                    value=price[1],
                    unit="GBP"
                )
            )
            for price in prices
        ]

        self.quotes_api.upsert_quotes(TestDataUtilities.tutorials_scope,
                                      request_body={"quote" + str(request_number): requests[request_number]
                                              for request_number in range(len(requests))})

        recipe_scope = 'cs-tutorials'
        recipe_code = 'quotes_recipe'

        self.id_generator.add_scope_and_code("recipe", recipe_scope, recipe_code)

        demo_recipe = models.ConfigurationRecipe(
            scope=recipe_scope,
            code=recipe_code,
            market=models.MarketContext(
                market_rules=[],
                suppliers=models.MarketContextSuppliers(
                    equity='DataScope'
                ),
                options=models.MarketOptions(
                    default_supplier='DataScope',
                    default_instrument_code_type='LusidInstrumentId',
                    default_scope=TestDataUtilities.tutorials_scope)
            )
        )
        upsert_recipe_request = models.UpsertRecipeRequest(demo_recipe)
        self.recipes_api.upsert_configuration_recipe(upsert_recipe_request)

        valuation_request = models.ValuationRequest(
            recipe_id=models.ResourceId(scope=recipe_scope,code=recipe_code),
            metrics=[
                models.AggregateSpec("Instrument/default/Name", "Value"),
                models.AggregateSpec("Holding/default/PV", "Proportion"),
                models.AggregateSpec("Holding/default/PV", "Sum")
            ],
            group_by=["Instrument/default/Name"],
            portfolio_entity_ids = [
                models.PortfolioEntityId(scope = TestDataUtilities.tutorials_scope, code = portfolio_code)
            ],
            valuation_schedule=models.ValuationSchedule(effective_at=effective_date)
        )

        #   do the aggregation
        aggregation = self.aggregation_api.get_valuation(valuation_request=valuation_request)

        for item in aggregation.data:
            print("\t{}\t{}\t{}".format(item["Instrument/default/Name"], item["Proportion(Holding/default/PV)"],
                                        item["Sum(Holding/default/PV)"]))

        # Asserts
        self.assertEqual(len(aggregation.data),3)
        self.assertEqual(aggregation.data[0]["Sum(Holding/default/PV)"], 10000)
        self.assertEqual(aggregation.data[1]["Sum(Holding/default/PV)"], 20000)
        self.assertEqual(aggregation.data[2]["Sum(Holding/default/PV)"], 30000)
Beispiel #10
0
    def setup_portfolio(cls, effective_date, portfolio_code) -> None:
        """
        Sets up instrument, quotes and portfolio data from TestDataUtilities
        :param datetime effective_date: The portfolio creation date
        :param str portfolio_code: The code of the the test portfolio
        :return: None
        """

        transactions = [
            cls.test_data_utilities.build_transaction_request(
                instrument_id=cls.instrument_ids[0],
                units=100,
                price=101,
                currency="GBP",
                trade_date=effective_date,
                transaction_type="StockIn",
            ),
            cls.test_data_utilities.build_transaction_request(
                instrument_id=cls.instrument_ids[1],
                units=100,
                price=102,
                currency="GBP",
                trade_date=effective_date,
                transaction_type="StockIn",
            ),
            cls.test_data_utilities.build_transaction_request(
                instrument_id=cls.instrument_ids[2],
                units=100,
                price=103,
                currency="GBP",
                trade_date=effective_date,
                transaction_type="StockIn",
            ),
        ]

        cls.transaction_portfolios_api.upsert_transactions(
            scope=TestDataUtilities.tutorials_scope,
            code=portfolio_code,
            transaction_request=transactions,
        )

        prices = [
            (cls.instrument_ids[0], 100),
            (cls.instrument_ids[1], 200),
            (cls.instrument_ids[2], 300),
        ]

        requests = [
            models.UpsertQuoteRequest(
                quote_id=models.QuoteId(
                    models.QuoteSeriesId(
                        provider="Lusid",
                        instrument_id=price[0],
                        instrument_id_type="LusidInstrumentId",
                        quote_type="Price",
                        field="mid",
                    ),
                    effective_at=effective_date,
                ),
                metric_value=models.MetricValue(value=price[1], unit="GBP"),
            ) for price in prices
        ]

        cls.quotes_api.upsert_quotes(
            TestDataUtilities.tutorials_scope,
            request_body={
                "quote" + str(request_number): requests[request_number]
                for request_number in range(len(requests))
            },
        )
Beispiel #11
0
def load_transactions(client, scope, code, data_frame,
                      transaction_mapping_required,
                      transaction_mapping_optional, source):
    """
    This function loads transactions for a given portfolio into LUSID

    :param LusidApi client: The LusidApi client to use
    :param str scope: The scope of the portfolio to upsert the transactions into
    :param str code: The code of the portfolio to upsert the transactions into
    :param Pandas DataFrame data_frame: The dataframe containing the data
    :param dict {str, str} transaction_mapping: The mapping of the fields from the dataframe to LUSID
    :param str source: The source system of the transactions, used to fetch the correct transaction types
    :return: UpsertPortfolioTransactionsResponse response: Response from LUSID to the upsert request
    """
    # Initialise a list to hold the requests
    transaction_requests = []
    dtypes = data_frame.drop(
        ['resolvable', 'foundWith', 'LusidInstrumentId', 'comment'],
        axis=1).dtypes

    # Iterate over each transaction
    for index, transaction in data_frame.iterrows():

        # Set the identifier for the transaction which was found earlier
        if transaction['comment'] == 'Resolved as cash with a currency':
            identifier_key = 'Currency'
        else:
            identifier_key = 'LusidInstrumentId'

        identifiers = {
            'Instrument/default/{}'.format(identifier_key):
            transaction['LusidInstrumentId']
        }

        # Set the properties for the transaction
        properties = create_property_values(transaction, -1, scope,
                                            'Transaction', dtypes)

        exchange_rate = None

        if ('exchange_rate' in transaction_mapping_optional.keys()) and (
                transaction_mapping_optional['exchange_rate'] is not None):

            exchange_rate = transaction[
                transaction_mapping_optional['exchange_rate']]

            properties[
                'Transaction/default/TradeToPortfolioRate'] = models.PerpetualProperty(
                    key='Transaction/default/TradeToPortfolioRate',
                    value=models.PropertyValue(metric_value=models.MetricValue(
                        value=1 / exchange_rate)))

        # Create the transaction request
        transaction_requests.append(
            models.TransactionRequest(
                transaction_id=make_code_lusid_friendly(transaction[
                    transaction_mapping_required['transaction_id']]),
                type=transaction[
                    transaction_mapping_required['transaction_type']],
                instrument_identifiers=identifiers,
                transaction_date=convert_datetime_utc(transaction[
                    transaction_mapping_required['transaction_date']]),
                settlement_date=convert_datetime_utc(transaction[
                    transaction_mapping_required['settlement_date']]),
                units=transaction[transaction_mapping_required['units']],
                transaction_price=models.TransactionPrice(price=transaction[
                    transaction_mapping_required['transaction_price.price']],
                                                          type='Price'),
                total_consideration=models.CurrencyAndAmount(
                    amount=transaction[transaction_mapping_required[
                        'total_consideration.amount']],
                    currency=make_code_lusid_friendly(
                        transaction[transaction_mapping_required[
                            'total_consideration.currency']])),
                exchange_rate=exchange_rate,
                transaction_currency=make_code_lusid_friendly(transaction[
                    transaction_mapping_required['transaction_currency']]),
                source=source,
                properties=properties))

    # Call LUSID to upsert the transactions
    response = client.transaction_portfolios.upsert_transactions(
        scope=scope, code=code, transactions=transaction_requests)

    return response