Ejemplo n.º 1
0
def populate_with_cash(holdings_effective_date, initial_cash_balance,
                       analyst_scope_code, transaction_portfolio_code,
                       api_factory):
    # Create a holding adjustment to set our initial cash balance
    holding_adjustment = [
        models.AdjustHoldingRequest(
            instrument_identifiers={'Instrument/default/Currency': 'GBP'},
            tax_lots=[
                models.TargetTaxLotRequest(units=initial_cash_balance,
                                           cost=models.CurrencyAndAmount(
                                               amount=initial_cash_balance,
                                               currency='GBP'),
                                           portfolio_cost=initial_cash_balance,
                                           price=1)
            ])
    ]

    # Call LUSID to set our initial cash balance
    set_holdings_response = api_factory.build(
        lusid.api.TransactionPortfoliosApi).set_holdings(
            scope=analyst_scope_code,
            code=transaction_portfolio_code,
            effective_at=holdings_effective_date,
            adjust_holding_request=holding_adjustment)

    # Pretty print our response from LUSID
    prettyprint.set_holdings_response(set_holdings_response,
                                      analyst_scope_code,
                                      transaction_portfolio_code)
Ejemplo n.º 2
0
 def build_cash_funds_in_adjust_holdings_request(self, currency, units):
     return models.AdjustHoldingRequest(
         instrument_identifiers={
             TestDataUtilities.lusid_cash_identifier: currency
         },
         tax_lots=[
             models.TargetTaxLotRequest(units=units,
                                        price=None,
                                        cost=None,
                                        portfolio_cost=None,
                                        purchase_date=None,
                                        settlement_date=None)
         ])
Ejemplo n.º 3
0
 def build_adjust_holdings_request(self, instrument_id, units, price, currency, trade_date):
     return models.AdjustHoldingRequest(
         instrument_identifiers={
             TestDataUtilities.lusid_luid_identifier: instrument_id
         },
         tax_lots=[
             models.TargetTaxLotRequest(units=units,
                                        price=price,
                                        cost=models.CurrencyAndAmount(amount=price * units, currency=currency),
                                        portfolio_cost=price * units,
                                        purchase_date=trade_date,
                                        settlement_date=trade_date)
         ])
Ejemplo n.º 4
0
def setup_index(analyst_scope_code, reference_portfolio_code,
                instrument_prices, api_factory):
    # Set an arbitary index level to start our index with
    index_level = 1000
    # Call LUSID - get the constituents of our index from our reference portfolio
    constituents = api_factory.build(
        lusid.api.ReferencePortfolioApi).get_reference_portfolio_constituents(
            scope=analyst_scope_code,
            code=reference_portfolio_code,
            effective_at=datetime.now(pytz.UTC))
    # Initialise our list to hold the adjustments we need to make to our index to set it up
    index_setup = []
    # Get our weights from the constituents into a better format to work with
    weights = {
        constituent.instrument_uid: constituent.weight
        for constituent in constituents.constituents
    }

    # Iterate over our pricing analytics
    for index, instrument in instrument_prices.iterrows():

        # Get our Lusid Instrument ID
        Luid = api_factory.build(lusid.api.InstrumentsApi).get_instrument(
            identifier_type='Figi',
            identifier=instrument['figi']).lusid_instrument_id
        # Get the initial price for each constituent of the index from our analytics store
        inception_price = instrument['price_original']
        # Work out how much of the index this constituent should make up using its w
        index_cost = weights[Luid] * index_level
        # Work out how many units we should therefore buy
        index_units = index_cost / inception_price
        # Create our request for this instrument
        index_setup.append(
            models.AdjustHoldingRequest(instrument_identifiers={
                'Instrument/default/Figi':
                instrument['figi']
            },
                                        tax_lots=[
                                            models.TargetTaxLotRequest(
                                                units=index_units,
                                                cost=models.CurrencyAndAmount(
                                                    amount=index_cost,
                                                    currency='GBP'),
                                                portfolio_cost=index_cost,
                                                price=inception_price)
                                        ]))
    return index_setup
Ejemplo n.º 5
0
    def test_set_target_holdings(self):

        currency = "GBP"

        day1 = datetime(2018, 1, 1, tzinfo=pytz.utc)
        day2 = datetime(2018, 1, 5, tzinfo=pytz.utc)

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

        instrument1 = self.instrument_ids[0]
        instrument2 = self.instrument_ids[1]
        instrument3 = self.instrument_ids[2]

        holdings_adjustments = [

            # cash balance
            models.AdjustHoldingRequest(
                instrument_identifiers={
                    TestDataUtilities.lusid_cash_identifier: currency
                },
                tax_lots=[models.TargetTaxLotRequest(units=100000.0)]),

            # instrument 1
            models.AdjustHoldingRequest(instrument_identifiers={
                TestDataUtilities.lusid_luid_identifier:
                instrument1
            },
                                        tax_lots=[
                                            models.TargetTaxLotRequest(
                                                units=100.0,
                                                price=101.0,
                                                cost=models.CurrencyAndAmount(
                                                    amount=10100.0,
                                                    currency=currency),
                                                portfolio_cost=10100.0,
                                                purchase_date=day1,
                                                settlement_date=day1)
                                        ]),

            # instrument 2
            models.AdjustHoldingRequest(instrument_identifiers={
                TestDataUtilities.lusid_luid_identifier:
                instrument2
            },
                                        tax_lots=[
                                            models.TargetTaxLotRequest(
                                                units=100.0,
                                                price=102.0,
                                                cost=models.CurrencyAndAmount(
                                                    amount=10200.0,
                                                    currency=currency),
                                                portfolio_cost=10200.0,
                                                purchase_date=day1,
                                                settlement_date=day1)
                                        ])
        ]

        # set the initial holdings on day 1
        self.transaction_portfolios_api.set_holdings(
            scope=TestDataUtilities.tutorials_scope,
            code=portfolio_code,
            adjust_holding_request=holdings_adjustments,
            effective_at=day1)

        # add subsequent transactions on day 2
        transactions = [
            self.test_data_utilities.build_transaction_request(
                instrument_id=instrument1,
                units=100.0,
                price=104.0,
                currency=currency,
                trade_date=day2,
                transaction_type="Buy"),
            self.test_data_utilities.build_transaction_request(
                instrument_id=instrument3,
                units=100.0,
                price=103.0,
                currency=currency,
                trade_date=day2,
                transaction_type="Buy")
        ]

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

        # get the holdings for day 2
        holdings = self.transaction_portfolios_api.get_holdings(
            scope=TestDataUtilities.tutorials_scope,
            code=portfolio_code,
            effective_at=day2)

        # sort to put the cash instrument first
        holdings.values.sort(key=lambda i: i.instrument_uid)

        # cash balance + 3 holdings
        self.assertEqual(len(holdings.values), 4)

        # remaining cash balance which takes into account the purchase transactions on day 2

        # the call to GetHoldings returns the LUID not the identifier we created
        currency_luid = "CCY_{}".format(currency)

        # cash
        self.assertEqual(holdings.values[0].instrument_uid, currency_luid)
        self.assertEqual(holdings.values[0].units, 79300.0)

        # instrument 1 - initial holding + transaction on day 2
        self.assertEqual(holdings.values[1].instrument_uid, instrument1)
        self.assertEqual(holdings.values[1].units, 200.0)
        self.assertEqual(holdings.values[1].cost.amount, 20500.0)

        # instrument 2 - initial holding
        self.assertEqual(holdings.values[2].instrument_uid, instrument2)
        self.assertEqual(holdings.values[2].units, 100.0)
        self.assertEqual(holdings.values[2].cost.amount, 10200.0)

        # instrument 3 - transaction on day 2
        self.assertEqual(holdings.values[3].instrument_uid, instrument3)
        self.assertEqual(holdings.values[3].units, 100.0)
        self.assertEqual(holdings.values[3].cost.amount, 10300.0)
Ejemplo n.º 6
0
def load_holdings(client, scope, code, data_frame, holdings_mapping_required,
                  holdings_mapping_optional):
    """
    This function sets the holdings for a given portfolio from a set of holdings

    :param LusidApi client: The LusidApi client to use
    :param str scope: The scope of the portfolio to upsert the holdings into
    :param str code: The code of the portfolio to upsert the holdings into
    :param Pandas DataFrame data_frame: The dataframe containing the data
    :param dict{str, str} holdings_mapping: The mapping of the fields from the dataframe to LUSID
    :return: response models.AdjustHolding: The response from LUSID after setting the holdings
    """
    # Initialise a list to hold the requests
    holding_adjustments = []
    # Create a Pandas Series with the column names and data types less the resolved details for property generation
    dtypes = data_frame.drop(
        ['resolvable', 'foundWith', 'LusidInstrumentId', 'comment'],
        axis=1).dtypes
    # Get all effective dates from the file
    effective_dates = list(
        data_frame[holdings_mapping_required['effective_date']].unique())
    # If there is more than one throw an error
    if len(effective_dates) > 1:
        raise Exception(
            'There are {} effective dates in the holding file, need there to be just one'
            .format(len(effective_dates)))
    # Convert the effective date to be a timezone aware datetime
    effective_date = pytz.utc.localize(parser.parse(effective_dates[0]))

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

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

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

        # Set the properties for the holding
        properties = create_property_values(holding, -1, scope, 'Holding',
                                            dtypes)

        single_cost = models.CurrencyAndAmount(amount=None, currency=None)

        for lusid_field, column_name in holdings_mapping_optional.items():
            if (lusid_field.split(".")[1] == 'cost') and (column_name
                                                          is not None):
                setattr(single_cost,
                        lusid_field.split(".")[2], holding[column_name])

        if (single_cost.amount is None) and (single_cost.currency is None):
            single_cost = None

        single_tax_lot = models.TargetTaxLotRequest(
            units=holding[holdings_mapping_required['tax_lots.units']],
            cost=single_cost)

        for lusid_field, column_name in holdings_mapping_optional.items():
            if (lusid_field.split(".")[1] != 'cost') and (column_name
                                                          is not None):
                setattr(single_tax_lot,
                        lusid_field.split(".")[2], holding[column_name])

        single_holding_adjustment = models.AdjustHoldingRequest(
            instrument_identifiers=identifiers,
            tax_lots=[single_tax_lot],
            properties=properties)

        # Create the adjust holding request
        holding_adjustments.append(single_holding_adjustment)

    # Call LUSID to upsert the transactions
    response = client.transaction_portfolios.adjust_holdings(
        scope=scope,
        code=code,
        effective_at=effective_date,
        holding_adjustments=holding_adjustments)

    return response