Ensuring the same transaction code has different economic impacts

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-in FundsIn 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: