How do I create or update a transaction?

Providing you have suitable access control permissions, you can create (that is, book) an input transaction in a transaction portfolio to register a change to the quantity and/or cost of one or more holdings.

A new transaction 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).

By default, LUSID operates a ‘data load first’ policy, so transactions are upserted and resolution failures must be handled manually as a post-process step. You can increase the level of validation to reject transactions that do not resolve to instruments, to transaction types, or both. Find out more about this.

A transaction in a portfolio is keyed by its unique transaction ID. If you specify the ID of an existing transaction then the original is updated rather than a new one created. Note LUSID stores every update as a separate record so you can see a full change history for a transaction by calling the GetTransactions API with ShowCancelledTransactions=True, and examining the transactionStatus field:

  • A new (never updated) transaction has a single record with a status of Active.

  • An updated transaction has one record per update with a status of Amended, followed by an Active record with the latest information unless the transactionDate field changed (see below).

  • A transaction has a status of Cancelled if you:

    • Explicitly cancelled the transaction.

    • Updated the transactionDate field. This is because LUSID automatically rebooks the transaction on the new transaction date.

Using the LUSID REST API

You can upsert (that is, create or update) up to 10,000 transactions per call to the BatchUpsertTransactions API.

Note: This API is recommended over UpsertTransactions because it resolves transactions to instruments using individual transaction dates rather than the generic date of the upsert operation itself, reducing the likelihood of instrument resolution failures.

  1. Obtain an API access token.

  2. Call the BatchUpsertTransactions API, passing in your API token and specifying in the URL:

    • The scope and code of the parent portfolio.

    • A successMode of Atomic to reject all transactions in the request if one fails validation. The default mode of Partial means each transaction is validated on its own merits. Find out more about this.

  3. In the body of the API request, specify for each transaction in the batch:

    • An ephemeral ID that can be used to track warnings and failures in the response. This can be the same as the transactionID (below), or different. It is not stored in LUSID.

    • A transactionId that uniquely identifies the transaction in the portfolio. You can use the LUSID sequence APIs to auto-generate unique IDs.

    • A type that resolves to a known transaction type determining the precise economic impact, for example Buy or Sell.

    • A source in which to locate this transaction type if it is grouped with other types from a particular data provider. If omitted, LUSID searches the default source. Note if the parent portfolio has a transaction type scope set then this transaction type must also be domiciled in that scope. More about scopes and sources.

    • A set of instrumentIdentifiers that resolve to an instrument mastered in LUSID, each consisting of a 3-stage key (for example, Instrument/default/Figi or Instrument/default/LusidInstrumentId) and an appropriate value (for example, BBG000C6K6G9 or LUID_0000G7H5). You must specify at least one unique instrument identifier; you can specify as many more (unique and non-unique) as you like to increase the likelihood of successful instrument resolution. See how LUSID resolves transactions to instruments.

    • A transactionDate and a settlementDate. Note that if the settlement date is later, LUSID categorises any cash holdings impacted by the transaction differently between the two dates.

    • A number of units to transact. Depending on the underlying instrument, this might represent a number of shares, the principle in an interest rate swap, the face value of a bond, a number of ETO contracts and so on.

    • A transactionPrice. Note this field is required if you ask LUSID to automatically calculate gross consideration for you, which is defined as total consideration before fees.

    • A totalConsideration.currency that is the ISO 4217 code of the settlement currency, for example GBP.

    • A totalConsideration.amount that represents the total amount payable or receivable in the settlement currency. Note the following:

      • While you can store any number you like, total consideration in LUSID is intended to be after fees. So for a purchase transaction, this would be the trade amount payable plus fees. For a sale transaction, this would be the trade amount receivable minus fees.

      • You can set this field to 0 and ask LUSID to automatically calculate total consideration for you according to a formula.

      Note: The mandatory API fields assume that the transaction, settlement and portfolio currencies are all the same. If not, or if you are booking a FX transaction to exchange two currencies, then you must set additional fields and properties. More information.

    • Optionally in the properties collection, any number of custom properties from the Transaction domain to extend the data model.

    • Optionally in the properties collection, any of the available system properties to record additional information that LUSID can subsequently use in business operations, for example Transaction/default/GrossConsideration or  Transaction/default/TradeToPortfolioRate.

    • Optionally in the properties collection, one or more sub-holding keys (SHKs) registered with the portfolio to assign the transaction to a specific holding once processed by the transaction type. If omitted, LUSID generates one holding in the portfolio per underlying instrument, with all transactions in that instrument contributing to the holding.

Consider the following example of a transaction to purchase 10 units of BP @ £20, paying and settling in GBP in a EUR-denominated portfolio with a £5 trade commission:

  • The totalConsideration.amount is (10 × £20) + £5 = £205.

  • The transaction has two system properties, one to record the gross consideration (10 × £20 = £200) and the other a GBP/EUR spot rate from the transaction to the portfolio currency.

  • The transaction has two custom properties, one to record the trade commission and the other to assign the result of processing the transaction to a Growth SHK:

curl -X POST 'https://<your-domain>.lusid.com/api/api/transactionportfolios/Finbourne-Examples/Global-Equity/transactions/$batchUpsert?successMode=Partial' 
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "transactionRequest-1": {
    "transactionId": "Txn-0000001",
    "type": "Buy",
    "source": "Bloomberg",
    "instrumentIdentifiers": {"Instrument/default/Figi": "BBG000C6K6G9"},
    "transactionDate": "2024-05-15T00:00:00.0000000+00:00",
    "settlementDate": "2024-05-18T00:00:00.0000000+00:00",
    "units": 10,
    "transactionPrice": {"price": 20, "type": "Price"},
    "totalConsideration": {"amount": 205, "currency": "GBP"},
    "properties": {
      "Transaction/default/GrossConsideration": {
        "key": "Transaction/default/GrossConsideration",
        "value": {
          "metricValue": {
            "value": 200,
            "unit": "GBP"
          }
        }
      },
      "Transaction/MyProperties/TotalCapitalisedFees": {
        "key": "Transaction/MyProperties/TotalCapitalisedFees",
        "value": {
          "metricValue": {
            "value": 5,
            "unit": "GBP"
          }
        }
      },
      "Transaction/default/TradeToPortfolioRate": {
        "key": "Transaction/default/TradeToPortfolioRate",
        "value": {
          "metricValue": {
            "value": 1.2,
            "unit": ""
          }
        }
      },
      "Transaction/MySHKs/Strategy": {
        "key": "Transaction/MySHKs/Strategy",
        "value": {
          "labelValue": "Growth"
        }
      }
    }
  }
}'

Note the following in the response:

  • LUSID confirms the globally-unique instrumentUid (LUID) and the instrumentScope of the underlying instrument.

  • LUSID sets the transactionStatus to Active. If you subsequently edit the transaction, this becomes Amended. See how to cancel a transaction.

  • LUSID sets the transactionCurrency to the same as the settlement currency, at an exchangeRate of 1.

  • We recommend checking the metadata section for transactions in a batch that were upserted but failed to resolve to instruments, to transaction types, or both. Find out more about this.

  • If you increased the level of validation, we recommend checking the failed section for transactions in a batch that were rejected for failing to resolve to instruments, to transaction types, or both.

{
  "values": {
    "transactionRequest-1": {
      "transactionId": "Txn-0000001",
      "type": "Buy",
      "instrumentIdentifiers": {
        "Instrument/default/Figi": "BBG000C6K6G9",
        "Instrument/default/Isin": "GB00BH4HKS39"
      },
      "instrumentScope": "default",
      "instrumentUid": "LUID_R7E12YK8",
      "transactionDate": "2024-05-15T00:00:00.0000000+00:00",
      "settlementDate": "2024-05-18T00:00:00.0000000+00:00",
      "units": 10,
      "transactionPrice": {
        "price": 20,
        "type": "Price"
      },
      "totalConsideration": {
        "amount": 205,
        "currency": "GBP"
      },
      "exchangeRate": 1,
      "transactionCurrency": "GBP",
      "properties": {
        "Transaction/default/GrossConsideration": {
          "key": "Transaction/default/GrossConsideration",
          "value": {
            "metricValue": {
              "value": 200,
              "unit": "GBP"
            }
          }
        },
        "Transaction/MyProperties/TotalCapitalisedFees": {
          "key": "Transaction/MyProperties/TotalCapitalisedFees",
          "value": {
            "metricValue": {
              "value": 5,
              "unit": "GBP"
            }
          }
        },
        "Transaction/default/TradeToPortfolioRate": {
          "key": "Transaction/default/TradeToPortfolioRate",
          "value": {
            "metricValue": {
              "value": 1.2,
              "unit": ""
            }
          }
        },
        "Transaction/MySHKs/Strategy": {
          "key": "Transaction/MySHKs/Strategy",
          "value": {
            "labelValue": "Growth"
          }
        }
      },
      "source": "Bloomberg",
      "entryDateTime": "2024-05-15T09:00:00.0000000+00:00",
      "transactionStatus": "Active"
    }
  },
  "failed": {},
  "metadata": {},
  ...
}

Using Luminesce

You can use the Lusid.Portfolio.Txn.Writer provider. More information.

Using the LUSID web app

  1. Sign in to the LUSID web app.

  2. Navigate to Dashboard > Transactions.

  3. Click the Create transaction button and follow the instructions: