In this tutorial we'll see how to use LUSID to perform the following task:
“As a data controller, I load transactions from two providers that use the same transaction code to signal different economic activity. I want to ensure, for each transaction, that LUSID applies the correct economic impact when generating holdings.”
Note: You can examine and run the complete code sample for this exercise from this Jupyter Notebook, providing you have suitable access control permissions. This can most easily be achieved by assigning your LUSID user the built-in lusid-administrator
role, which should already be the case if you are the domain owner. If you are informed you do not have a license to perform a particular operation, contact support.
Imagine we source transactions from two data providers: UBS and Goldman Sachs.
Both label equity transactions with a code of 10
. For UBS this signals an equity purchase; for Goldman Sachs an equity sale.
We can create two separate 10
custom transaction types to model this behavior, each in a different source.
When transactions are upserted into a portfolio, we set the source
field on a transaction to reference the appropriate transaction type, enabling LUSID to apply the correct economic impact. However, we haven't altered the format or lineage of the imported data in any way, so it remains meaningful to the originating system.
Examining the source file
Let's assume we have amalgamated a stream of transactions from UBS and Goldman Sachs into a single CSV file, each with a particular txn_code:
We can see that:
- The first transaction has a transaction code of
FundsIn
, which we can map directly to the built-inFundsIn
transaction type to deposit £500 in the portfolio. - The second transaction is from UBS and has a transaction code of
10
to signal a purchase of 50 BP shares at a cost of £250. - The third transaction is from Goldman Sachs and has a transaction code of
10
to signal a sale of 25 BP shares for £125.
When all trades have settled, we would expect LUSID to generate a holdings report with 25 BP shares and £375.
Modelling the custom transaction types
We want our custom transaction types to have the following definitions (some components omitted for clarity):
Transaction type component | UBS (buy) | Goldman Sachs (sell) | Explanation | |
Alias | Type | 10 | 10 | Transaction types have the same name. |
Description | Equity purchase from UBS | Equity sale from Goldman Sachs | Transaction types have different descriptions. | |
Source | UBS | GoldmanSachs | Transaction types are from different providers. | |
Class | UBS | GoldmanSachs | Transaction types are not in the default Basic class, to prevent reporting clashes with the built-in transaction types. | |
Movement #1 | Type | StockMovement | StockMovement | Updates the equity holding. |
Direction | 1 | -1 | Increases/decreases units respectively. | |
Side | Side1 | Side1 | Uses the built-in Side1 designed for instrument (non-cash) holdings. | |
Movement #2 | Type | CashCommitment | CashCommitment | Updates the cash holding. |
Direction | -1 | 1 | Decreases/increases units respectively. | |
Side | Side2 | Side2 | Uses the built-in Side2 designed for cash holdings. |
Creating a custom transaction type for UBS to purchase an equity
We can call the SetTransactionType API with a source of UBS
, a type of 10
, and the ‘buy’ alias and movements defined in the table above.
Note: The PUT SetTransactionType
API operates differently to the standard PUSH Upsert*
model used elsewhere in LUSID. The transaction type is replaced rather than updated, so it's important to specify the entire definition each time.
Step 4 of the accompanying Jupyter Notebook demonstrates how to do this using the LUSID Python SDK. You can execute the Notebook in Jupyterhub for your LUSID domain and then sign in to the web app to see the custom transaction type on the System Settings > Transaction Types dashboard.
Note StockMovement is set to 1 to increase the equity holding and CashCommitment to -1 to decrease the cash holding, as per the built-in Buy
transaction type:
Creating a custom transaction type for Goldman Sachs to sell an equity
We can call the SetTransactionType API again, this time with a source of GoldmanSachs
, a type of 10
, and the ‘sell’ alias and movements defined in the table above.
Step 5 of the accompanying Jupyter Notebook demonstrates how to do this using the LUSID Python SDK. You can execute the Notebook in Jupyterhub for your LUSID domain and then sign in to the web app to see both types on the System Settings > Transaction Types dashboard.
Note StockMovement is set to -1 to decrease the equity holding and CashCommitment is 1 to increase the cash holding, as per the built-in Sell
transaction type:
Loading transactions into a LUSID portfolio
We can now call the UpsertTransactions API to load our transaction source file into a suitable portfolio.
Both equity transactions have a type
of 10
. It's important therefore to set the source
field on each transaction to reference the appropriate transaction type, so LUSID can apply the correct economic impact.
Step 6 of the accompanying Jupyter Notebook demonstrates how to do this using the LUSID Python SDK. You can execute the Notebook in Jupyterhub for your LUSID domain and then sign in to the web app to examine the Transactions dashboard.
Note that while the Type of upserted equity transactions is the same, the Description is different:
Generating a holdings report
We can now call the GetHoldings API to generate a holdings report.
Step 7 of the accompanying Jupyter Notebook demonstrates how to do this using the LUSID Python SDK. You can execute the Notebook in Jupyterhub for your LUSID domain and then sign in to the web app to examine the Holdings dashboard.
As expected, after all trades have settled, LUSID generates a holdings report with 25 BP shares and £375: