Views:

A posting module assigns journal entry lines generated by LUSID to represent economic activity in portfolios to general ledger accounts. See how to create a posting module.

A posting module contains posting rules in a specific order. A posting rule assigns debit or credit amounts for journal entry lines matching a set of criteria to a specific account. Syntax of a posting rule.

For each journal entry line, LUSID applies the first matching posting rule found in the posting module. Unmatched journal entry lines remain unassigned. The goal of a posting module is to create a waterfall of logic that ensures all economic activity is assigned.

Consider the following example, of a posting module with five rules:

{
  "values": [
    {
      "ruleId": "rule_01",
      "account": "3-Capital",
      "ruleFilter": "EconomicBucket startswith 'CA'"
    },
    {
      "ruleId": "rule_02",
      "account": "1-Investments",
      "ruleFilter": "HoldType eq 'P' and EconomicBucket startswith 'NA'"
    },
    {
      "ruleId": "rule_03",
      "account": "4-PnL",
      "ruleFilter": "EconomicBucket startswith 'PL'"
    },
    {
      "ruleId": "rule_04",
      "account": "2-Cash",
      "ruleFilter": "HoldType neq 'P' and EconomicBucket startswith 'NA'"
    },
    {
      "ruleId": "rule_05",
      "account": "Error",
      "ruleFilter": "True"
    }
  ]
}

For each generated journal entry line, LUSID automatically:

  1. Assigns the amount to the 3-Capital account if the economic bucket starts with CA.
  2. If not, assigns the amount to the 1-Investments account if the economic bucket starts with NA and the holding type code is P (position, signifying a non-currency holding).
  3. If not, assigns the amount to the 4-PnL account if the economic bucket starts with PL.
  4. If not, assigns the amount to the 2-Cash account if the economic bucket starts with NA and the holding type code is not equal to P (that is, currency holdings).
  5. If not, assigns the amount to an Error account for manual remediation.

In this example, rule 5 is a 'catch all' rule that assigns unmatched journal entry lines to a general-purpose account. You could omit rule 5, in which case any journal entry lines failing to match rules 1, 2, 3 and 4 remain unassigned.

Syntax of a posting rule

A posting rule consists of:

  • A ruleId that uniquely identifies the posting rule in the posting module.
  • An account that is the code of an account in the parent chart of accounts (CoA).
  • A ruleFilter expression that describes criteria for matching journal entry lines to the account.

The syntax of a ruleFilter expression is:

<attribute> <operator> <value>

...where:

<attribute>Data typeExample expressionExplanation/origin of <value>
SourceTypeStringSourceType eq 'LusidTransaction'Either LusidTransaction or LusidValuation. Use LusidValuation to map LUSID's automatic mark-to-market valuation activity to an account.
ActivityDateDateTimeActivityDate gt 2023-01-01For a transaction, this is the trade date. For a valuation, this is the date of the latest detected change to market data.
EconomicBucketStringEconomicBucket startswith 'PL_Real'LUSID automatically categorises every journal entry line into a broad economic bucket. More information.
SourceIdStringSourceId eq 'Txn01'

For a transaction, this is the unique identifier in the portfolio (txnId).


For a valuation, this is the date and time of the latest change to market data (stored as a string, so only string operators are available).

TaxLotIdStringSourceId eq 'Txn01'For a transaction, if the underlying instrument is a currency and the trade is settled (holding type of B), the value is 1 (stored as a string). Otherwise, this is the same as the SourceId.
LocalAmountDecimalLocalAmount lte 1000The amount in the transaction currency.
BaseAmountDecimalBaseAmount gt 450000The amount in the portfolio base currency.
DefaultCurrencyStringDefaultCurrency in 'GBP', 'USD'The currency of the underlying instrument, if specified.
InstrumentScopeStringInstrumentScope startswith 'Custom'The instrument scope in which the underlying instrument is mastered.
LusidInstrumentIdStringLusidInstrumentId not startswith 'CCY'The LUID (globally unique ID) of the underlying instrument.
HoldTypeStringHoldType eq 'P'One of the LUSID holding type codes.
MovementNameStringMovementName eq 'Side1'

For a transaction, this is the name of the movement in the transaction type to which the transaction belongs. If the movement does not have a name (and note its name field is optional), then this is the name of the movement's side.
 

For a valuation, this is always MarkToMarket.

MovementSignStringMovementSign eq 'Long'Either Long or Short.
A sub-holding key on the portfolioUser-definedsubholdingkeys[Transaction/Ibor/Strategy] eq 'Income'Under-the-hood, a SHK is defined as a custom property with a 3-stage key in the Transaction domain.
A portfolio fieldSystem-defined

Portfolio.displayName eq 'UK-Equities'

Portfolio.parentPortfolioId.Code eq 'FixedIncome'

This can be any of the stored fields for a portfolio except the href, links and version fields, prefixed by Portfolio. Nested fields can be accessed using dot notation.
A portfolio propertyUser-definedproperties[Portfolio/Ibor/Manager] in 'John Smith', 'Jane Jones'This can be any property with a 3-stage key in the Portfolio domain.
An instrument fieldSystem-definedInstrument.identifiers['LusidInstrumentId'] eq 'LUID_ZZZZZZZZ'

Instrument.instrumentDefinition.instrumentType in 'Equity', 'Bond'
This can be any of the stored fields for an instrument except the href, links and version fields, prefixed by Instrument. Nested fields can be accessed using dot notation.
An instrument propertyUser-definedproperties[Instrument/Ibor/AnalystRating] any (~ startswith 'A')This can be any property with a 3-stage key in the Instrument domain.
A transaction fieldSystem-defined

Transaction.totalConsideration.amount gt 2000

Transaction.instrumentScope eq 'ProtectedScope'

This can be any of the stored fields for a transaction, prefixed by Transaction. Nested fields can be accessed using dot notation.
A transaction propertyUser-definedproperties[Transaction/Ibor/Broker] eq 'AcmeCorp'This can be any property with a 3-stage key in the Transaction domain.
An account fieldSystem-definedAccount.type in 'Asset', 'Liabilities'This can be any of the stored fields for an account, prefixed by Account. Nested fields can be accessed using dot notation.
An account propertyUser-definedproperties[Account/Type/AssetClass] eq 'Equity'This can be any property with a 3-stage key in the Account domain.
An ABOR propertyUser-definedproperties[Abor/Client/Accountant] not in 'Fred Bloggs', 'Sarah Smart'This can be any property with a 3-stage key in the Abor domain.

Note the following:

  • A ruleFilter expression is case-insensitive.
  • A string <value> must be enclosed in single straight quote marks (the %27 UTF-8 encoding).
  • You can concatenate expressions using the and and or operators, for example:
    MovementName eq 'Side1' and subholdingkeys[Transaction/Ibor/Strategy] eq 'Income'

    If you use both, standard boolean operator precedence applies:

    InstrumentScope startswith 'Custom' or (LocalAmount lte 1000 and HoldType eq 'P')