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]