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 anActive
record with the latest information unless thetransactionDate
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 Luminesce
You can use the Lusid.Portfolio.Txn.Writer
provider. More information.
Using the LUSID REST API
You can upsert (that is, create or update) up to 10,000 transactions per call to the BatchUpsertTransactions API. A transaction is created if its transactionId
is not yet registered with the portfolio, and updated if it is.
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.
Call the
BatchUpsertTransactions
API, passing in your API token and specifying in the URL:The
scope
andcode
of the parent portfolio.A
successMode
ofAtomic
to reject all transactions in the request if one fails validation. The default mode ofPartial
means each transaction is validated on its own merits. Find out more about this.
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 exampleBuy
orSell
.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 thedefault
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
orInstrument/default/LusidInstrumentId
) and an appropriate value (for example,BBG000C6K6G9
orLUID_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 asettlementDate
. 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, or a number of ETD contracts.A
transactionPrice
. Note this field is only used if you ask LUSID to automatically calculate gross consideration for you.A
totalConsideration.currency
that is the ISO 4217 code of the settlement currency, for example GBP.A
totalConsideration.amount
that represents the trade amount in the settlement currency. Note this field is mandatory out-of-the-box, but you can configure LUSID to omit it and instead automatically calculate total consideration according to a formula.Note: The mandatory API fields assume that the transaction and settlement currencies are the same. If not, or if you are booking a FX transaction to exchange two currencies, then you must additionally set the
transactionCurrency
andexchangeRate
fields. See how to do this.Optionally in the
properties
collection, any number of custom properties from theTransaction
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, if the transaction currency is GBP but the portfolio base currency is EUR, adding theTradeToPortfolioRate
system property to record the GBP/EUR spot rate enables LUSID to maintain the cost basis of the portfolio.Optionally in the
properties
collection, one or more sub-holding keys (SHKs) registered with the portfolio to strategy-tag the transaction. If omitted, LUSID generates one holding 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:
The transaction and settlement currencies are the same, so
totalConsideration.amount
is £200. Note you need to set additional fields if the transaction and settlement currencies are different, or if you are booking a FX transaction to exchange two currencies.The portfolio base currency (specified on the parent portfolio) is EUR, so the
TradeToPortfolioRate
system property records a GBP/EUR spot rate of 1.125, so LUSID can calculate the trade amount in the portfolio currency (£200 * 1.125 = €225) and thereby maintain the cost basis of the portfolio.
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": "2023-05-15T00:00:00.0000000+00:00",
"settlementDate": "2023-05-18T00:00:00.0000000+00:00",
"units": 10,
"transactionPrice": {"price": 20, "type": "Price"},
"totalConsideration": {"amount": 200, "currency": "GBP"},
"properties": {
"Transaction/MyProperties/Broker": {
"key": "Transaction/MyProperties/Broker",
"value": {
"labelValue": "JohnDoe"
}
},
"Transaction/default/TradeToPortfolioRate": {
"key": "Transaction/default/TradeToPortfolioRate",
"value": {
"metricValue": {
"value": 1.125, "unit": ""
}
}
},
"Transaction/SHKs/Strategy": {
"key": "Transaction/SHKs/Strategy",
"value": {
"labelValue": "Growth"
}
}
}
}
}'
Note the following in the response:
LUSID confirms the globally-unique
instrumentUid
(LUID) and theinstrumentScope
of the underlying instrument.LUSID sets the
transactionStatus
toActive
. If you subsequently edit the transaction, this becomesAmended
. See how to cancel a transaction.LUSID sets the
transactionCurrency
to the same as the settlement currency, at anexchangeRate
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": "2023-05-15T00:00:00.0000000+00:00",
"settlementDate": "2023-05-18T00:00:00.0000000+00:00",
"units": 10,
"transactionPrice": {
"price": 20,
"type": "Price"
},
"totalConsideration": {
"amount": 200,
"currency": "GBP"
},
"exchangeRate": 1,
"transactionCurrency": "GBP",
"properties": {
"Transaction/MyProperties/BrokerName": {
"key": "Transaction/MyProperties/BrokerName",
"value": {
"labelValue": "JohnDoe"
}
},
"Transaction/default/TradeToPortfolioRate": {
"key": "Transaction/default/TradeToPortfolioRate",
"value": {
"metricValue": {
"value": 1.125,
"unit": ""
}
}
},
"Transaction/SHKs/Strategy": {
"key": "Transaction/SHKs/Strategy",
"value": {
"labelValue": "Growth"
}
}
},
"source": "Bloomberg",
"entryDateTime": "0001-01-01T00:00:00.0000000+00:00",
"transactionStatus": "Active"
}
},
"failed": {},
"metadata": {},
...
}
Using the LUSID web app
Navigate to Dashboard > Transactions.
Click the Create transaction button and follow the instructions: