Understanding how LUSID uses transaction types to generate holdings

LUSID is a transaction-based system. It does not maintain a static record of your holdings (positions) in a transaction portfolio but rather generates them on demand from the stored history of transactions, replayed in date order.

Every transaction in a portfolio must resolve to:

  • An underlying instrument mastered in LUSID.

  • A known transaction type defining the precise economic impact; that is, the effect on your holding in the underlying instrument, and also potentially on holdings in other instruments in the portfolio too (for example, currency holdings).

LUSID has a number of built-in transaction types (such as FundsIn, Buy and Sell) that enable you to get started modeling basic economic activity. These are useful for understanding how transaction types work, but we recommend creating your own universe of custom transaction types for a production system.

Understanding the role of transaction types

Consider the following CSV file containing three input transactions ready for upsert to a portfolio, each with a particular txn_type:

  1. The FundsIn transaction deposits £500 in the portfolio. We would expect our cash holding in GBP to increase by £500, but no other holdings to be affected.

  2. The Buy transaction purchases 10 BP shares at £10 a share. We would expect our equity holding in BP to increase by 10 units and our cash holding in GBP to decrease by £100.

  3. The Sell transaction sells 5 BP shares at £11 a share. We would expect our equity holding in BP to decrease by 5 units and our cash holding in GBP to increase by £55.

When all trades have settled, we would expect LUSID to generate a holdings report for this portfolio with 5 BP shares and £455.

Examining the built-in LUSID transaction types

You can retrieve the definition of the built-in Buy transaction type from the default source and default scope by calling the GetTransactionType API:

{
  "aliases": [
    {
      "type": "Buy",
      "description": "Purchase",
      "transactionClass": "Basic",
      "transactionRoles": "LongLonger",
      "isDefault": false
    },
  ],
  "movements": [
    {
      "movementTypes": "StockMovement",
      "side": "Side1",
      "direction": 1,
      "properties": {},
      "mappings": [],
      "movementOptions": []
    },
    {
      "movementTypes": "CashCommitment",
      "side": "Side2",
      "direction": -1,
      "properties": {},
      "mappings": [],
      "movementOptions": []
    }
  ],
  "properties": {},
  ...
}

The built-in Buy transaction type:

  • Is grouped in the default source (data provider) and default scope (logical repository) with all the other built-in transaction types provided with LUSID. More about scopes and sources.

  • Has a single alias, which defines the name of the transaction type and other characteristics that allow you to group similar types together for reporting purposes.

  • Has two movements, each of which has:

    • A movement type that controls how and when a holding is updated. Allowed values are these built-in movement types. You cannot customise this set.

    • A direction that controls whether the change is an increase or decrease. Allowed values are 1 and -1 respectively.

    • A side that determines which economic attributes of the transaction impact the holding. Allowed values are either the built-in sides or you can create your own custom side.

The following table flattens and explains the definition of the built-in Buy transaction type:

Component

Field

Value

Explanation

Alias

type

Buy

Defines the name of the transaction type. Note names are case-sensitive, so Buy is different to BUY.

description

Purchase

Describes the transaction type.

transactionClass

Basic

Groups the transaction type with others that have the same economic impact for reporting purposes, in conjunction with the role (below). More information.

transactionRoles

LongLonger

Groups the transaction type with others that have the same economic impact for reporting purposes, in conjunction with the class (above).

isDefault

false

Specifies that this transaction type is not the default in the source, which means that unresolved transactions are not mapped to it. More information.

Movement #1

movementTypes

StockMovement

On the trade date, updates the number of units in an instrument (non-cash) holding. On the settlement date, updates the number of settled units.

direction

1

Increases the number of units in the holding.

side

Side1

Defines the name of the side. Note this built-in side is designed to generate instrument (non-cash) holdings, as per its definition below.

 

 

 

 

 

security

Txn:LusidInstrumentId

Updates the holding identified by the LUID of the instrument to which the transaction resolved upon upsert, for example LUID_ABCDEFGH.

currency

Txn:TradeCurrency

Determines the currency of the holding from the value of the transactionCurrency field on the transaction if populated, otherwise its totalConsideration.currency field (the settlement currency).

rate

Txn:TradeToPortfolioRate

If the transaction is in a foreign currency, maintains the cost basis of the portfolio by updating the costPortfolioCcy.amount field on the holding using the exchange rate specified by the TradeToPortfolioRate system property attached to the transaction.

units

Txn:Units

Updates the number of units on the holding by the value of the units field on the transaction.

amount

Txn:TradeAmount

Updates the cost of the holding by the value of the totalConsideration.amount field on the transaction.

Movement #2

movementTypes

CashCommitment

On the trade date, creates a temporary separate cash holding (of holding type C) to reflect a commitment to settling the trade. On the settlement date, updates the main cash holding (holding type B) and removes the temporary holding.

direction

-1

Decreases the number of units in the holding.

side

Side2

Defines the name of the side. Note this built-in side is designed to generate cash holdings, as per its definition below.

 

security

Txn:SettleCcy

Updates the holding identified by the LUID of the currency specified in the totalConsideration.currency field on the transaction, prefixed by CCY_  (for example CCY_GBP).

currency

Txn:SettlementCurrency

Determines the currency of the holding from the value of the totalConsideration.currency field on the transaction.

rate

SettledToPortfolioRate

If the transaction settles in a different currency to the transaction currency, and is again different to the portfolio base currency, maintains the cost basis of the portfolio by dividing the exchange rate specified by the TradeToPortfolioRate system property attached to the transaction by the value of the exchangeRate field.

Note the:

  • Transaction currency is defined by the transactionCurrency field on a transaction.

  • Settlement currency is defined by its totalConsideration.currency field.

  • Portfolio base currency is nominated when a portfolio is created.

units

Txn:TotalConsideration

Updates the number of units on the holding by the value of the totalConsideration.amount field on the transaction (since for a currency the number of units is equal to the amount).

amount

Txn:TotalConsideration

Updates the cost of the holding by the value of the totalConsideration.amount field on the transaction.

In summary, we can see that the built-in Buy transaction type:

  • Impacts one instrument (non-cash) holding and one cash holding.

  • Increases the instrument holding.

  • Decreases the cash holding.

The built-in Sell transaction type is virtually identical to Buy. The only difference is that the movement directions are reversed:

  • The  StockMovement has a direction of -1 to decrease the instrument holding by the number of units.

  • The CashCommitment has a direction of 1 to increase the cash holding by the total consideration.

By contrast, the built-in FundsIn transaction type has a single movement, with a type of CashAccrual, a direction of 1, and uses the built-in Side1. This transaction type:

  • Impacts a single cash holding.

  • On the trade date, creates a temporary separate cash holding (of holding type A) to reflect expected accrual of income.

  • On the settlement date, increases the main cash holding (holding type B) by the number of units and removes the temporary holding.

Interpreting the impact of transaction types on holdings

If we load our three transactions into a portfolio and call the GetHoldings API for end-of-day on the trade date (6 June 2022), we can see from the picture below that LUSID generates:

  • One holding (with a Holding Type of Position) for the BP equity instrument. Note the number of Settled Units is 0.

  • Three holdings for the GBP cash instrument. The first (with a Holding Type of Cash Accrual) records the (unsettled) FundsIn transaction for £500. The last two (both with a Holding Type of Cash Commitment) record the commitment to pay (from the Buy transaction) or receive (from the Sell transaction) GBP on the settlement date:

If we call the GetHoldings API again on or after the settlement date (8 June 2022), we can see from the picture below that LUSID normalises the GBP instrument to a single cash holding (with a Holding Type of Cash Balance), and that all units are now Settled Units:

There are two main reasons to configure transaction types:

  • You want to configure aliases in order to group similar or related transaction types together.

  • You want to configure movements in order to change the economic impact of transactions on holdings.

For more information, start with the tutorials for the following use cases:

Use case 1

“As a data controller, I load transactions from two providers that use a different transaction code to signal the same economic activity. I want to ensure that LUSID applies a uniform economic impact when generating holdings.”

Use case 2

“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.”

Use case 3

“As a portfolio manager, I want to generate a holdings report that reduces my cash balance by the money paid out in broker commissions, as well as by the cost of equities purchased.”

Use case 4

“As a fund accountant, I want to create a bespoke holdings report that breaks out the money paid in broker commissions on equity purchases into a separate cash holding.”