Esempio n. 1
0
    def test_reconcile_portfolio(self):
        # create the portfolio
        scope = TestDataUtilities.tutorials_scope
        portfolio_code = self.test_data_utilities.create_transaction_portfolio(
            scope)
        self.id_generator.add_scope_and_code("portfolio", scope,
                                             portfolio_code)

        today = datetime.now().astimezone(tz=pytz.utc)
        yesterday = today - timedelta(1)

        # create transactions for yesterday
        yesterdays_transactions = [
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[0],
                units=1000.0,
                price=100.0,
                currency="GBP",
                trade_date=yesterday + timedelta(hours=8),
                transaction_type="StockIn"),
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[0],
                units=2300.0,
                price=101.0,
                currency="GBP",
                trade_date=yesterday + timedelta(hours=12),
                transaction_type="StockIn"),
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[1],
                units=-1000.0,
                price=102.0,
                currency="GBP",
                trade_date=yesterday + timedelta(hours=9),
                transaction_type="StockIn"),
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[2],
                units=1200.0,
                price=103.0,
                currency="GBP",
                trade_date=yesterday + timedelta(hours=16),
                transaction_type="StockIn"),
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[3],
                units=2000.0,
                price=103.0,
                currency="GBP",
                trade_date=yesterday + timedelta(hours=9),
                transaction_type="StockIn"),
        ]

        # add the transactions to LUSID
        self.transaction_portfolios_api.upsert_transactions(
            scope=TestDataUtilities.tutorials_scope,
            code=portfolio_code,
            transaction_request=yesterdays_transactions)

        # transactions for today
        todays_transactions = [

            # net long 300
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[0],
                units=-3000.0,
                price=101.78,
                currency="GBP",
                trade_date=today + timedelta(hours=8),
                transaction_type="StockIn"),

            # net long 1800
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[0],
                units=1500.0,
                price=101.78,
                currency="GBP",
                trade_date=today + timedelta(hours=12),
                transaction_type="StockIn"),

            # flat
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[1],
                units=1000.0,
                price=102.0,
                currency="GBP",
                trade_date=today + timedelta(hours=12),
                transaction_type="StockIn"),

            # net long 2400
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[2],
                units=1200.0,
                price=103.0,
                currency="GBP",
                trade_date=today + timedelta(hours=16),
                transaction_type="StockIn"),

            # net long 3000
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[3],
                units=1000.0,
                price=103.0,
                currency="GBP",
                trade_date=today + timedelta(hours=9),
                transaction_type="StockIn"),

            # net long 5000
            self.test_data_utilities.build_transaction_request(
                instrument_id=self.instrument_ids[3],
                units=2000.0,
                price=103.0,
                currency="GBP",
                trade_date=today + timedelta(hours=20),
                transaction_type="StockIn"),
        ]

        # add the transactions to LUSID
        transactions_response = self.transaction_portfolios_api.upsert_transactions(
            scope=TestDataUtilities.tutorials_scope,
            code=portfolio_code,
            transaction_request=todays_transactions)

        # get the time of the last update
        last_as_at = transactions_response.version.as_at_date

        # We now have the portfolio with 2 days worth of transactions, going to reconcile from T-1 20:00 to now,
        # this should reflect breaks for each instrument equal to the transactions from yesterday till 20:00 today
        reconciliation_request = models.PortfoliosReconciliationRequest(
            left=models.PortfolioReconciliationRequest(
                portfolio_id=models.ResourceId(
                    scope=TestDataUtilities.tutorials_scope,
                    code=portfolio_code),
                effective_at=yesterday + timedelta(hours=20),
                as_at=last_as_at),
            right=models.PortfolioReconciliationRequest(
                portfolio_id=models.ResourceId(
                    scope=TestDataUtilities.tutorials_scope,
                    code=portfolio_code),
                effective_at=today + timedelta(hours=16),
                as_at=last_as_at),
            instrument_property_keys=[TestDataUtilities.lusid_luid_identifier])

        breaks = self.reconciliations_api.reconcile_holdings(
            portfolios_reconciliation_request=reconciliation_request)

        for rec_break in breaks.values:
            print("{}\t{}\t{}".format(rec_break.instrument_uid,
                                      rec_break.difference_units,
                                      rec_break.difference_cost.amount))

        rec_map = {b.instrument_uid: b for b in breaks.values}

        self.assertEqual(-1500,
                         rec_map[self.instrument_ids[0]].difference_units)
        self.assertEqual(1000,
                         rec_map[self.instrument_ids[1]].difference_units)
        self.assertEqual(1200,
                         rec_map[self.instrument_ids[2]].difference_units)
        self.assertEqual(1000,
                         rec_map[self.instrument_ids[3]].difference_units)
    def test_Perform_a_reconciliation(self):

        # load sheet
        sht = self.get_sheet("Perform a reconciliation")

        # get parameters from excel
        LeftScope = "F24"
        LeftCode = "F25"
        LeftEffectiveAt = "F26"
        LeftAsAt = "F27"
        RightScope = "F28"
        RightCode = "F29"
        RightEffectiveAt = "F30"
        RightAsAt = "F31"

        left_scope = sht.range(LeftScope).value
        left_code = sht.range(LeftCode).value
        left_effective_at = get_date(LeftEffectiveAt, sht)
        left_as_at = get_date(LeftAsAt, sht)
        right_scope = sht.range(RightScope).value
        right_code = sht.range(RightCode).value
        right_effective_at = get_date(RightEffectiveAt, sht)
        right_as_at = get_date(RightAsAt, sht)

        # get validation data
        request_reconciliation = models.PortfoliosReconciliationRequest(
            left=models.PortfolioReconciliationRequest(
                portfolio_id=models.ResourceId(scope=left_scope, code=left_code),
                effective_at=left_effective_at,
                as_at=left_as_at
            ),
            right=models.PortfolioReconciliationRequest(
                portfolio_id=models.ResourceId(scope=right_scope, code=right_code),
                effective_at=right_effective_at,
                as_at=right_as_at
            ),
            instrument_property_keys=['Instrument/default/LusidInstrumentId']
        )

        reconciliation_validation_response = self.reconciliations_api.reconcile_holdings(
            request=request_reconciliation
        ).values

        # format validation data
        reconciliation_validation = [
            {
                "Instrument Uid": data.instrument_uid,
                "Left Units": data.left_units,
                "Right Units": data.right_units,
                "Units Difference": data.difference_units,
                "Left Cost Amount": data.left_cost.amount,
                "Right Cost Amount": data.right_cost.amount,
            }
            for data in reconciliation_validation_response
        ]

        # get excel data
        reconciliation_response_excel = sht.range("E39", "O49").value
        headers = reconciliation_response_excel.pop(0)

        # format excel data
        reconciliation_excel = [
            {
                "Instrument Uid": data[headers.index('Instrument Uid')],
                "Left Units": data[headers.index("Left Units")],
                "Right Units": data[headers.index("Right Units")],
                "Units Difference": data[headers.index("Units Difference")],
                "Left Cost Amount": data[headers.index("Left Cost Amount")],
                "Right Cost Amount": data[headers.index("Right Cost Amount")]
            }
            for data in reconciliation_response_excel if (data[0] != "" and data[0] is not None)
        ]
        # assert excel data exists within validation set
        [self.assertIn(sample, reconciliation_validation) for sample in reconciliation_excel]