What is a movement?

Prev Next

A movement is a component of a transaction type that updates the units and cost of a holding. This can either be a security holding (a position in an equity, bond, swap, option and so on) or a currency holding.

A transaction type must have at least one movement, and can have two or more. For example, the built-in Buy transaction type provided with LUSID—intended to signal a purchase of an instrument such as an equity—has two movements, a StockMovement and a CashCommitment. For each transaction upserted to a portfolio with a transaction type of Buy, LUSID automatically:

  • Applies the StockMovement to increase the quantity and cost of the security holding (ie. BP or MSFT) by the number of units purchased and the transaction cost.

  • Applies the CashCommitment to decrease a holding in the settlement currency (ie. GBP or USD) by the total consideration.

Understand how LUSID uses transaction types to generate holdings.

A movement has the following fields, some mandatory and some optional.

name field

Optional. Specifies a name for the movement.

movementTypes field

Mandatory. Must be one of the built-in movement types controlling how and when a holding is updated.

direction field

Mandatory. Controls whether the update is an increase or decrease. Allowed values are 1 and -1.

If transactions have unsigned units and amounts then 1 signals an increase and -1 signals a decrease. However, the opposite is true if units and amounts are signed. So for example if a sell transaction is for -30 units, then 1 signals a decrease.

side field

A side is a plug-and-play component that determines which holding is impacted and what attributes of transactions contribute to the change.

Allowed values are either the built-in sides provided with LUSID (currently Side1, Side2, BondInt and Side2WithoutBondInterest), or you can create your own custom sides.

condition field

Optional. By default, a movement always occurs for every transaction belonging to a transaction type.

You can make a movement conditional so that it only occurs for particular transactions, or for transactions in particular portfolios.

You can use LUSID's filter syntax to include any field or property from a portfolio or transaction in the condition, including the transaction’s underlying instrument type. And you can chain expressions using the and and or operators if necessary.

Example

Movement only occurs if a transaction...

condition = "Transaction.Instrument.InstrumentDefinition.InstrumentType eq 'Equity'"

Is in an equity.

condition = "Transaction.totalConsideration.amount gt 2000"

Has a total consideration of more than 2000.

condition = "Transaction.units gte 100 and Transaction.Properties[Transaction/Broker/Commission] exists"

Is for 100 units or more and records broker commission.

condition = "Portfolio.baseCurrency eq 'GBP'"

Is in a GBP portfolio.

condition = "Portfolio.created gte 2024-01-01 and Portfolio.Properties[Portfolio/Manager/Name] in 'John Doe', 'Jane Doe'"

Is in a 2024 portfolio managed by John Doe or Jane Doe.

condition = "Transaction.units gte 100 and Portfolio.created gte 2024-01-01"

Is for 100 units or more in a 2024 portfolio.

mappings field

Optional. Allocates one or more sub-holding keys (SHKs) to override or supplement strategy tags applied directly to transactions.

Specify a 3-stage propertyKey representing a SHK registered with the parent portfolio, and one of the following options:

Mapping option

Data type

Explanation

setTo

String

Sets the SHK to a new, static value. For an example, see this tutorial on breaking out broker commission as a separate cash holding.

mapFrom

String

Maps the SHK from the value of an existing transaction property, for example Transaction/MyProperties/Trader.

templateFrom

String

Uses Mustache template syntax to map the SHK from the value of an existing:

  • Transaction property, for example {{Properties[Transaction/MyProperties/Trader]}}

  • Transaction field, for example {{TransactionPrice.Price}}

  • Instrument property, for example {{Properties[Instrument/MyProperties/Country]}}

  • Instrument identifier, for example {{InstrumentIdentifiers[Instrument/default/Figi]}}

  • Instrument field, for example {{Instrument.InstrumentDefinition.InstrumentType}}

  • Portfolio property, for example {{Properties[Portfolio/MyProperties/Manager]}

Note the Mustache syntax means you can optionally mix text and variables, for example

"My text {{TransactionPrice.Price}} more text {{Properties[Instrument/MyProperties/Country}} some text"

nullify

Boolean

Specify true to de-allocate an existing SHK (nulls the property value rather than setting to an empty string).

movementOptions field

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

Option

Notes

DirectAdjustment

Applicability: movementTypes set to StockMovement.

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

  1. Adjust the number of holding units by the number of units specified by the side.

  2. Adjust the holding cost by the amount specified by the side.

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

This option can be used to adjust the units of holdings 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 units are reduced by the transaction units, as normal.

  • The cost is not affected (that is, adjustment is zero).

Note that taxlots are not supported.

IncludesTradedInterest

More information coming soon.

Virtual

Applicability: movementTypes set to StockMovement.

Specify this option to calculate realised gain/loss without actually effecting a sale. See example use cases for FxForwards and for bonds.

settlementDayOverride field

Optional. For any movement type that impacts holdings on settlement date, overrides contractual settlement dates specified in transactions and uses dates in the specified custom property added to those transactions instead.

This field must be set to the 3-stage key of a custom property in the Transaction domain, for example Transaction/myscope/mysettlementdate. Note the underlying property type must have a data type that itself has a primitive value type of DateTime. See how to set this up.

Note if a particular transaction does not have a property of this type, or the property value does not resolve to a valid date and time, then the contractual settlement date for the transaction is used.

Note: A more intuitive and configurable way to override contractual settlement dates using settlement instructions is now available.

properties field

Optional. This can be any number of:

  • Custom properties to extend the data model and store extra information about movements. These properties must be from the TransactionConfiguration domain.

  • System properties that are valid for movements.