Views:

The problem

One of the biggest challenges in migrating your investment records from one system to another is in ensuring that your transactions are represented correctly in the new system.

It is critical that the new system can interpret each transaction appropriately and determine what the underlying movements in cash and securities are.

This can be difficult when transactions are given esoteric types such as '1085' or 'STP' (STP is the MT940 SWIFT transaction type for Stamp Duty, but it could just as easily be an acronym for 'Sale Third Party' or 'Sale Transaction Processed').

The end result is typically a lot of time spent chasing down the handful of people in the organisation who understand the meaning of each transaction type and then laboriously mapping these to the new system's available types. This is one of the reasons that migrations between systems can take so long.

The solution

Rather than forcing a set of transaction types onto you, LUSID allows you to configure your own set of transaction types. Each type specifies the set of underlying movements that should occur when a transaction with this type is upserted into LUSID.

Each type also contains a set of aliases. These allow you to specify multiple transaction type codes that may have the same underlying movements. For example, the transaction types 'BUY', 'BY' and 'B' may all represent a buy transaction that results in an increase in the number of securities held and a corresponding decrease in the cash balance.

Creating a new transaction type

You can use the LUSID API endpoints in the Transaction Configuration collection to interact with transaction types.

Note: These API endpoints are currently replacing those in the System Configuration collection. It may be necessary to call API endpoints in both collections while this replacement process is underway. When complete, the System Configuration endpoints will be deprecated.

To create a new transaction type, call the SetTransactionType API, specifying:

  • A source to group the transaction type with others from the same data source, for example Goldman. Note the following:
    • If the source value you specify does not exist, it is created.
    • The built-in transaction types provided with LUSID (such as Buy and Sell) are in the default source; you can add your own transaction type to the default source if you wish.
    • A transaction expects its transaction type to be in the default source unless you explicitly set the source field on that transaction. See also the isDefault field, below.
  • A type. This is the type of the primary alias (see below) that uniquely identifies the transaction type in the source (this is relevant if it has more than one).

You must apply at least one alias and one movement to a transaction type.

Aliases

Each alias has the following fields:

Data fieldExplanation
typeDefines the name of the transaction type, for example BuyWithCommission. Note names are case-sensitive.
descriptionDescribes the transaction type.
transactionClassGroups the transaction type with others that have the same economic impact for reporting purposes, in conjunction with the role (below). More information.
transactionRolesGroups the transaction type with others that have the same economic impact for reporting purposes, in conjunction with the class. More information.
isDefault

Set to True to nominate this transaction type as the default for the source. If a transaction with an unrecognized transaction type is upserted into LUSID, it is assigned this default. Note you can configure LUSID to reject transactions with unrecognized transaction types if you wish.
 

LUSID assigns a transaction type to a transaction as follows:
 

  1. If a transaction has a value in its source field (for example, Goldman) then LUSID searches this source for the specified transaction type.
  2. If the transaction type cannot be found, LUSID searches the default source.
  3. If the transaction type cannot be found, LUSID searches the Goldman source for a transaction type with isDefault set to True.
  4. If a transaction type cannot be found, LUSID searches the default source for a transaction type with isDefault set to True.

If a transaction type still cannot be found, the transaction is upserted into LUSID but holdings calculations for the underlying instrument fail. This is to alert you to the fact that you have 'missing' transactions rather than calculate holdings wrongly from incomplete information.
 

Note it may be useful to use this fallback mechanism to create a 'memo' transaction type (with no underlying movements, and so no economic impact) to collate all transactions upserted into LUSID with unrecognized transaction types. This might make it easier to correct them.

Movements

Each movement has the following fields:

Data fieldExplanation
movementTypesControls how and when a holding is updated. Allowed values are these built-in movement types. You cannot customise this set.
directionControls whether the change is an increase or decrease. Allowed values are 1 and -1 respectively.
sideDetermines which economic attributes of the transaction impact the holding. Allowed values are either the built-in sides (currently Side1Side2BondInt and Side2WithoutBondInterest), or you can create your own custom side using the SetSideDefinition API.

Note a side has five mandatory fields (securitycurrencyrateunitsamount); the allowed values for these fields are documented here. You can retrieve the definition of the built-in sides by calling the ListConfigurationTransactionTypes API, which returns all the transaction types and the sides at the bottom; there should soon be a dedicated API for retrieving sides.
propertiesOptionally extends the information stored about holdings by adding custom properties.
mappingsOptionally maps transaction properties to holding properties to propagate useful information.
nameOptionally specifies a name for the movement.
movementOptions

A comma-separated list of options to configure the movement. The following are available:

OptionNotes
DirectAdjustment

Specify this option to override LUSID's standard logic and:
 

  1. Adjust the number of holding units by the number of units specified in the side.
  2. Adjust the holding cost by the amount specified in the side.

This is different to LUSID's default closing behavior, which is to scale the cost and calculate realised gain or loss.
 

This option can be used when movementType is StockMovement to adjust the units of a holding without impacting the cost, perhaps to model a 1-for-2 reverse stock split by loading a transaction that halves the number of units but with a total consideration of zero:
 

  • The holding units are reduced by the transaction units, as normal.
  • The cost is not affected (that is, adjustment is zero).

Use cases, examples and more information

Start with this this tutorial for an examination of four common 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.