Пример #1
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
Пример #2
0
    def test_edit_instrument_property(self):

        property_value = models.PropertyValue(label_value="Insurance")
        property_key = f"Instrument/{TestDataUtilities.tutorials_scope}/CustomSector"
        identifier_type = "Figi"
        identifier = "BBG00KTDTF73"

        # update the instrument
        self.instruments_api.upsert_instruments_properties(
            upsert_instrument_property_request=[
                models.UpsertInstrumentPropertyRequest(
                    identifier_type=identifier_type,
                    identifier=identifier,
                    properties=[
                        models.ModelProperty(key=property_key,
                                             value=property_value)
                    ])
            ])

        # get the instrument with value
        instrument = self.instruments_api.get_instrument(
            identifier_type=identifier_type,
            identifier=identifier,
            property_keys=[property_key])

        self.assertGreaterEqual(len(instrument.properties), 1)

        prop = list(
            filter(
                lambda p: p.key == property_key and p.value.label_value ==
                property_value.label_value, instrument.properties))

        self.assertEqual(
            len(prop), 1,
            f"cannot find property key=${property_key} value={property_value}")
    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
                )
Пример #4
0
    def test_create_portfolio_with_properties(self):

        _, scope, property_code, _ = self.id_generator.generate_scope_and_code(
            "property_definition",
            scope=TestDataUtilities.tutorials_scope,
            code_prefix="fund-style-",
            annotations=["Portfolio"])

        data_type_id = models.ResourceId("system", "string")

        #   property definition
        property_definition = models.CreatePropertyDefinitionRequest(
            domain="Portfolio",
            scope=TestDataUtilities.tutorials_scope,
            code=property_code,
            value_required=False,
            display_name="Fund Style",
            life_time="Perpetual",
            data_type_id=data_type_id)

        #   create the property definition
        property_definition_result = self.property_definitions_api.create_property_definition(
            create_property_definition_request=property_definition)

        #  property value
        property_value = "Active"
        portfolio_property = models.ModelProperty(
            key=property_definition_result.key,
            value=models.PropertyValue(label_value=property_value))

        _, scope, portfolio_code = self.id_generator.generate_scope_and_code(
            "portfolio",
            scope=TestDataUtilities.tutorials_scope,
            code_prefix="portfolio-")

        #  details of the portfolio to be created
        request = models.CreateTransactionPortfolioRequest(
            display_name=portfolio_code,
            code=portfolio_code,
            base_currency="GBP",

            # set the property value when creating the portfolio
            properties={property_definition_result.key: portfolio_property})

        # create the portfolio
        portfolio = self.transaction_portfolios_api.create_portfolio(
            scope=scope, create_transaction_portfolio_request=request)

        portfolio_code = portfolio.id.code
        self.assertEqual(portfolio_code, request.code)

        portfolio_properties = self.portfolios_api.get_portfolio_properties(
            TestDataUtilities.tutorials_scope, portfolio_code)

        self.assertEqual(len(portfolio_properties.properties), 1)
        self.assertEqual(
            portfolio_properties.properties[
                property_definition_result.key].value.label_value,
            property_value)
Пример #5
0
    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)
Пример #6
0
def create_properties_request(input_transaction, transaction_type) -> dict:
    properties = {
        "Transaction/generated/Commission": models.PerpetualProperty(
            key="Transaction/generated/Commission",
            value=models.PropertyValue(label_value=input_transaction.transaction_id)
        ),
        "Transaction/generated/Type": models.PerpetualProperty(
            key="Transaction/generated/Type",
            value=models.PropertyValue(label_value=transaction_type)
        ),
        # TODO: This property to come from a global config file
        "Transaction/generated/LinkedTransactionId": models.PerpetualProperty(
            key="Transaction/generated/LinkedTransactionId",
            value=models.PropertyValue(label_value=input_transaction.transaction_id)
        )
    }

    return properties
Пример #7
0
    def test_create_portfolio_with_label_property(self):
        # Details of property to be created
        uuid = self.get_guid()
        effective_date = datetime(year=2018, month=1, day=1, tzinfo=pytz.utc)

        label_property_definition = models.CreatePropertyDefinitionRequest(
            domain="Portfolio",
            scope=TestDataUtilities.tutorials_scope,
            code="fund-style-{}".format(uuid),
            display_name="fund style",
            life_time="Perpetual",
            value_required=False,
            data_type_id=models.resource_id.ResourceId(scope="system",
                                                       code="string"))

        # create property definition
        label_property_definition_request = self.property_definitions_api.create_property_definition(
            label_property_definition)

        # create property values
        property_value = models.PropertyValue(label_value="Active")

        # Details of new portfolio to be created
        create_portfolio_request = models.CreateTransactionPortfolioRequest(
            code="ud-{}".format(uuid),
            display_name="portfolio-{}".format(uuid),
            base_currency="GBP",
            created=effective_date,
            properties={
                label_property_definition_request.key:
                models.PerpetualProperty(
                    key=label_property_definition_request.key,
                    value=property_value)
            })

        # create portfolio
        portfolio_request = self.transaction_portfolios_api.create_portfolio(
            scope=TestDataUtilities.tutorials_scope,
            create_transaction_portfolio_request=create_portfolio_request)

        # get properties for assertions
        portfolio_properties = self.portfolios_api.get_portfolio_properties(
            scope=TestDataUtilities.tutorials_scope,
            code=portfolio_request.id.code).properties

        label_property = portfolio_properties[
            label_property_definition_request.key]

        # Perform assertions on keys, codes and values
        self.assertEqual(
            list(portfolio_properties.keys())[0],
            label_property_definition_request.key)
        self.assertEqual(portfolio_request.id.code,
                         create_portfolio_request.code)
        self.assertEqual(label_property.value.label_value,
                         property_value.label_value)
Пример #8
0
def upsert_trades(analyst_transactions, strategy_property_key, scope,
                  portfolio_code, api_factory):
    # Initialise a list to hold our transactions
    batch_transaction_requests = []

    # Iterate over the transactions for each portfolio
    for index, transaction in analyst_transactions.iterrows():

        if 'Cash' in transaction['instrument_name']:
            identifier_key = 'Instrument/default/Currency'
        else:
            identifier_key = 'Instrument/default/Figi'

        batch_transaction_requests.append(
            models.TransactionRequest(
                transaction_id=transaction['transaction_id'],
                type=transaction['type'],
                instrument_identifiers={
                    identifier_key: transaction['instrument_uid']
                },
                transaction_date=transaction['transaction_date'],
                settlement_date=transaction['settlement_date'],
                units=transaction['units'],
                transaction_price=models.TransactionPrice(
                    price=transaction['transaction_price'], type='Price'),
                total_consideration=models.CurrencyAndAmount(
                    amount=transaction['total_cost'],
                    currency=transaction['transaction_currency']),
                source='Client',
                transaction_currency=transaction['transaction_currency'],
                properties={
                    strategy_property_key:
                    models.PerpetualProperty(
                        key=strategy_property_key,
                        value=models.PropertyValue(
                            label_value=transaction['strategy']))
                }))

    # Call LUSID to upsert our transactions
    transaction_response = api_factory.build(
        lusid.api.TransactionPortfoliosApi).upsert_transactions(
            scope=scope,
            code=portfolio_code,
            transaction_request=batch_transaction_requests)

    # Pretty print the response from LUSID
    prettyprint.transactions_response(transaction_response, scope,
                                      portfolio_code)
    def test_add_transaction_to_portfolio_with_property(self):
        guid = str(uuid.uuid4())
        property_name = "traderId-{0}".format(guid)

        #   details of the property to be created
        property_definition = models.CreatePropertyDefinitionRequest(

            # The domain the property is to be applied to
            domain="Transaction",

            # the scope the property will be created in
            scope=TestDataUtilities.tutorials_scope,
            life_time="Perpetual",

            # when the property value is set it will be valid forever and cannot be changed.
            # properties whose values can change over time should be created with LifeTimeEnum.TIMEVARIANT
            code=property_name,
            value_required=False,
            display_name="Trader Id",
            data_type_id=models.ResourceId("system", "string"))

        #   create the property definition
        property_definition_result = self.property_definitions_api.create_property_definition(
            definition=property_definition)

        # effective date for which portfolio is created
        effective_date = datetime(2018, 1, 1, tzinfo=pytz.utc)

        # create the portfolio
        portfolio_id = self.test_data_utilities.create_transaction_portfolio(
            TestDataUtilities.tutorials_scope)

        property_value_as_string = "A Trader"
        property_value = models.PropertyValue(property_value_as_string)

        #   details of the transaction to be added
        transaction = models.TransactionRequest(
            transaction_id=str(uuid.uuid4()),
            type="Buy",
            instrument_identifiers={
                TestDataUtilities.lusid_luid_identifier: self.instrument_ids[0]
            },
            transaction_date=effective_date,
            settlement_date=effective_date,
            units=100,
            transaction_price=models.TransactionPrice(12.3),
            total_consideration=models.CurrencyAndAmount(1230, "GBP"),
            source="Client",

            # add the property to the transaction
            properties={
                property_definition_result.key:
                models.PerpetualProperty(property_definition_result.key,
                                         property_value)
            })

        #   add the transaction
        self.transaction_portfolios_api.upsert_transactions(
            TestDataUtilities.tutorials_scope,
            portfolio_id,
            transactions=[transaction])

        #   get the trades
        trades = self.transaction_portfolios_api.get_transactions(
            TestDataUtilities.tutorials_scope, portfolio_id)

        self.assertEqual(len(trades.values), 1)
        self.assertEqual(trades.values[0].transaction_id,
                         transaction.transaction_id)
        self.assertEqual(
            trades.values[0].properties[
                property_definition_result.key].value.label_value,
            property_value_as_string)
def property_def(full_property, label_value):
    prop = models.ModelProperty(
        key=full_property, value=models.PropertyValue(label_value=label_value))

    return prop
    def test_create_portfolio_with_mv_property(self):
        # Details of property to be created
        effective_date = datetime(year=2018, month=1, day=1, tzinfo=pytz.utc)
        scope = "MultiValueProperties"
        code = "MorningstarQuarterlyRating"
        portfolio_code = "Portfolio-MVP"

        multi_value_property_definition = models.CreatePropertyDefinitionRequest(
            domain="Portfolio",
            scope=scope,
            code=code,
            display_name=code,
            constraint_style="Collection",
            data_type_id=lusid.ResourceId(scope="system", code="string"),
        )

        # create property definition
        try:
            self.property_definitions_api.create_property_definition(
                create_property_definition_request=
                multi_value_property_definition)
        except lusid.ApiException as e:
            if json.loads(e.body)["name"] == "PropertyAlreadyExists":
                logging.info(
                    f"Property {multi_value_property_definition.domain}/{multi_value_property_definition.scope}/{multi_value_property_definition.display_name} already exists"
                )
        finally:
            self.id_generator.add_scope_and_code(
                "property_definition", multi_value_property_definition.scope,
                multi_value_property_definition.code, ["Portfolio"])

        schedule = [
            '{ "2019-12-31" : "5"}',
            '{ "2020-03-31" : "4"}',
            '{ "2020-06-30" : "3"}',
            '{ "2020-09-30" : "3"}',
        ]

        # Details of new portfolio to be created
        create_portfolio_request = models.CreateTransactionPortfolioRequest(
            code=portfolio_code,
            display_name=portfolio_code,
            base_currency="GBP",
            created=effective_date,
        )

        # create portfolio
        try:
            self.transaction_portfolios_api.create_portfolio(
                scope=scope,
                create_transaction_portfolio_request=create_portfolio_request,
            )
        except lusid.ApiException as e:
            if json.loads(e.body)["name"] == "PortfolioWithIdAlreadyExists":
                logging.info(
                    f"Portfolio {create_portfolio_request.code} already exists"
                )
        finally:
            self.id_generator.add_scope_and_code("portfolio", scope,
                                                 portfolio_code)

        self.portfolios_api.upsert_portfolio_properties(
            scope=scope,
            code=portfolio_code,
            request_body={
                f"Portfolio/{scope}/{code}":
                models.ModelProperty(
                    key=f"Portfolio/{scope}/{code}",
                    value=models.PropertyValue(
                        label_value_set=models.LabelValueSet(values=schedule)),
                )
            },
        )

        # get properties for assertions
        portfolio_properties = self.portfolios_api.get_portfolio_properties(
            scope=scope, code=portfolio_code).properties
        label_value_set = portfolio_properties[
            f"Portfolio/MultiValueProperties/{code}"].value.label_value_set.values
        self.assertCountEqual(label_value_set, schedule)
Пример #12
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
Пример #13
0
def set_transaction_mapping(client, transaction_mapping):
    """
    Sets the transaction mapping in LUSID so that the system can resolve the transactions into movements

    :param LusidApi client: The LusidApi client to use
    :param dict transaction_mapping: The transaction mapping configuration
    :return: ResourceListOfTransactionConfigurationData response: The response from LUSID
    """

    # Initialise your list of configuration requests, one for each transaction type
    configuration_requests = []

    # Iterate over your configurations in the default mapping
    for configuration in transaction_mapping['values']:

        # Initialise your list of aliases for this configuration
        aliases = []

        # Iterate over the aliases in the imported config
        for alias in configuration['aliases']:
            # Append the alias to your list
            aliases.append(
                models.TransactionConfigurationTypeAlias(
                    type=alias['type'],
                    description=alias['description'],
                    transaction_class=alias['transactionClass'],
                    transaction_group=alias['transactionGroup'],
                    transaction_roles=alias['transactionRoles']))

        # Initialise your list of movements for this configuration
        movements = []

        # Iterate over the movements in the impoted config
        for movement in configuration['movements']:

            # Add properties if they exist in the config
            if len(movement['properties']) > 0:
                key = movement['properties'][0]['key']
                value = models.PropertyValue(
                    label_value=movement['properties'][0]['value'])
                properties = {
                    key: models.PerpetualProperty(key=key, value=value)
                }
            else:
                properties = {}

            if len(movement['mappings']) > 0:
                mappings = [
                    models.TransactionPropertyMappingRequest(
                        property_key=movement['mappings'][0]['propertyKey'],
                        set_to=movement['mappings'][0]['setTo'])
                ]
            else:
                mappings = []

            # Append the movement to your list
            movements.append(
                models.TransactionConfigurationMovementDataRequest(
                    movement_types=movement['movementTypes'],
                    side=movement['side'],
                    direction=movement['direction'],
                    properties=properties,
                    mappings=mappings))

        # Build your configuration for this transaction type
        configuration_requests.append(
            models.TransactionConfigurationDataRequest(aliases=aliases,
                                                       movements=movements,
                                                       properties=None))

    # Call LUSID to set your configuration for our transaction types
    response = client.system_configuration.set_configuration_transaction_types(
        types=configuration_requests)

    return response