When you create a transaction, the mandatory fields in the request assume that the transaction, settlement and portfolio currencies are all the same.
For example, to buy 10 units of BP @ £20, paying and settling in GBP in a GBP-denominated portfolio, you only need set the totalConsideration.currency
field to GBP and the totalConsideration.amount
field to £200. Note the transactionPrice
field is optional and shown below only for illustration; this is an informational field and not used in any calculation by LUSID.
LUSID automatically sets the transactionCurrency
field to GBP, the exchangeRate
field to 1, the TradeToPortfolioRate
system property to 1, and the SettledToPortfolioRate
calculated field to 1 (more on these in the next section).
{ "transactionRequest-1": { "transactionId": "Txn-0000001", "type": "Buy", "instrumentIdentifiers": {"Instrument/default/Figi": "BBG000C6K6G9"}, "transactionDate": "2024-06-15T00:00:00.0000000+00:00", "settlementDate": "2024-06-18T00:00:00.0000000+00:00", "units": 10, "transactionPrice": {"price": 20, "type": "Price"}, "totalConsideration": {"amount": 200, "currency": "GBP"}, } }
Handling different transaction, settlement and portfolio currencies
Hard-coding an exchange rate between transaction and settlement currencies
If a transaction has different transaction and settlement currencies, you can specify the exchangeRate
field to hard-code an exchange rate when you upsert that transaction. Note if you subsequently want to amend this rate you must re-upsert the transaction.
Consider the following example, to buy 100 units of MSFT @ $30, paying in USD but settling in EUR:
- The
transactionCurrency
field is the transaction currency, USD. - The
totalConsideration.currency
field is the settlement currency, EUR. - The
totalConsideration.amount
field is the trade amount in the settlement currency, €2,700. - The
exchangeRate
field is the USD/EUR spot rate on the transaction date, 0.9. This enables LUSID to calculate the trade amount in the transaction currency: €2,700 / 0.9 = $3,000.
{ "transactionRequest-2": { "transactionId": "Txn-0000002", "type": "Buy", "instrumentIdentifiers": {"Instrument/default/Figi": "BBG000BPH459"}, "transactionDate": "2024-06-15T00:00:00.0000000+00:00", "settlementDate": "2024-06-18T00:00:00.0000000+00:00", "units": 100, "transactionPrice": {"price": 30, "type": "Price"}, "transactionCurrency": "USD", "totalConsideration": {"amount": 2700, "currency": "EUR"}, "exchangeRate": 0.9 } }
Hard-coding an exchange rate between transaction and portfolio currencies
If a transaction has different transaction and portfolio currencies, you can specify the TradeToPortfolioRate
system property to hard-code an exchange rate when you upsert that transaction. This is optional but enables LUSID to maintain the cost basis of the portfolio. Note if you subsequently want to amend this rate you must re-upsert the transaction.
Consider the following example, to buy 100 units of MSFT @ $30, paying and settling in USD in a GBP-denominated portfolio:
- The
transactionCurrency
field is the transaction currency, USD. - The
totalConsideration.currency
field is the settlement currency, also USD. - The
totalConsideration.amount
field is the trade amount in the settlement currency, $3,000. - The
TradeToPortfolioRate
system property is the USD/GBP spot rate on the transaction date, 0.8. This enables LUSID to calculate the trade amount in the portfolio currency: $3,000 * 0.8 = £2,400.
{ "transactionRequest-3": { "transactionId": "Txn-0000003", "type": "Buy", "instrumentIdentifiers": {"Instrument/default/Figi": "BBG000BPH459"}, "transactionDate": "2024-06-15T00:00:00.0000000+00:00", "settlementDate": "2024-06-18T00:00:00.0000000+00:00", "units": 100, "transactionPrice": {"price": 30, "type": "Price"}, "transactionCurrency": "USD", "totalConsideration": {"amount": 3000, "currency": "USD"}, "properties": { "Transaction/default/TradeToPortfolioRate": { "key": "Transaction/default/TradeToPortfolioRate", "value": { "metricValue": {"value": 0.8, "unit": ""} } } } } }
Note: LUSID automatically sets the SettledToPortfolioRate
calculated field to TradeToPortfolioRate
/ exchangeRate
. In this example, this is 0.8 / 1 = 0.8, but will be different if the transaction and settlement currencies are different, and means you don't need a triangulating spot rate between the settlement and portfolio currencies. This field can be used in the rate
field of a side.
Looking up exchange rates dynamically using a recipe
You can use a combination of a transaction type and a recipe to look up exchange rates dynamically:
- From transaction currency to settlement currency, and/or
- From transaction currency to portfolio currency.
This might be more convenient than hard-coding exchange rates when you upsert transactions, and means you can amend exchange rates if required without having to re-upsert them.
Consider the following example, to buy 100 units of MSFT @ $30, paying in USD but settling in EUR in a GBP-denominated portfolio on 01 June 2024, settling three days later on 04 June 2024:
- The
transactionCurrency
field is the transaction currency, USD. - The
totalConsideration.currency
field is the settlement currency, EUR. - The
totalConsideration.amount
field is the trade amount in the settlement currency, €2,700. - The
exchangeRate
field is omitted, so LUSID requires an exchange rate from transaction to settlement currency. - The
TradeToPortfolioRate
system property is omitted, so LUSID requires an exchange rate from transaction to portfolio currency.
{ "transactionRequest-4": { "transactionId": "Txn-0000004", "type": "Buy", "instrumentIdentifiers": {"Instrument/default/Figi": "BBG000BPH459"}, "transactionDate": "2024-06-01T00:00:00.0000000+00:00", "settlementDate": "2024-06-04T00:00:00.0000000+00:00", "units": 100, "transactionPrice": {"price": 30, "type": "Price"}, "transactionCurrency": "USD", "totalConsideration": {"amount": 2700, "currency": "EUR"}, } }
If you were to call the GetHoldings API at this point, the cost.amount
(in USD) and costPortfolioCcy.amount
(in GBP) fields would both be set to the total consideration of the transaction (in EUR):
To look up exchange rates dynamically for this transaction:
- Call the SetTransactionType API to extend the
Buy
transaction type to which this transaction belongs to include both theTxn:TradeToPortfolioRate
andTxn:ExchangeRate
calculation types:{ ... "calculations": [ { "type": "Txn:TradeToPortfolioRate", } { "type": "Txn:ExchangeRate", } ] }
- Call the UpsertConfigurationRecipe API to either create a new recipe or configure an existing one to look up exchange rates in the LUSID Quote Store. In this example, two market data rules are required: the first to locate USD/EUR rates from transaction to settlement currency, and the second to locate USD/GBP rates from transaction to portfolio currency:
{ "configurationRecipe": { "scope": "MyRecipes", "code": "MyFxRateLookupRecipe", "market": { "marketRules": [ { "key": "Fx.USD.EUR", "supplier": "Lusid", "dataScope": "MyFxRates", "quoteType": "Rate", "field": "mid", "quoteInterval": "1D.0D" }, { "key": "Fx.USD.GBP", "supplier": "Lusid", "dataScope": "MyFxRates", "quoteType": "Rate", "field": "mid", "quoteInterval": "1D.0D" } ] } } }
- Call the PatchPortfolioDetails API to register the scope and code of this recipe with the portfolio containing the transaction, for example:
[ { "value": { "scope": "MyRecipes", "code": "MyFxRateLookupRecipe" }, "path": "/instrumentEventConfiguration/recipeId", "op": "add" } ]
- Call the UpsertQuotes API to load appropriate exchange rates for the transaction date (not settlement date) into the Quote Store, for example:
{ "Quote-0001": { "quoteId": { "quoteSeriesId": { "provider": "Lusid", "instrumentIdType": "CurrencyPair", "instrumentId": "USD/EUR", "quoteType": "Rate", "field": "mid" }, "effectiveAt": "2024-06-01T00:00:00Z" }, "metricValue": { "value": 0.93, "unit": "USD/EUR" } }, "Quote-0002": { "quoteId": { "quoteSeriesId": { "provider": "Lusid", "instrumentIdType": "CurrencyPair", "instrumentId": "USD/GBP", "quoteType": "Rate", "field": "mid" }, "effectiveAt": "2024-06-01T00:00:00Z" }, "metricValue": { "value": 0.75, "unit": "USD/GBP" } } }
Now if you call the GetHoldings API, LUSID looks up the exchange rates and re-calculates the cost.amount
(€2,700 / 0.93 = $2903.23) and costPortfolioCcy.amount
($3000 * 0.75 = £2250) fields:
You can call the BuildTransactions API to audit the exchange rates used:
Booking FX transactions
Booking a FX spot transaction
Consider the following example, to sell GBP and buy USD at a spot rate of 1.2:
- The
instrumentIdentifiers
field maps the transaction to the sell currency instrument, GBP. Note all major currency instruments are pre-mastered in LUSID. - The
transactionCurrency
field is the currency to sell, GBP. - The
units
field is the amount to sell, £100,000. - The
totalConsideration.currency
field is the currency to buy, USD. - The
totalConsideration.amount
field is the trade amount in the buy currency, $120,000. - The
exchangeRate
field is the GBP/USD spot rate, 1.2. This enables LUSID to calculate the trade amount in the sell currency: $120,000 / 1.2 = £100,000.
{ "transactionRequest-3": { "transactionId": "Txn-0000003", "type": "FxSell", "instrumentIdentifiers": {"Instrument/default/Currency": "GBP"}, "transactionDate": "2023-05-15T00:00:00.0000000+00:00", "settlementDate": "2023-05-18T00:00:00.0000000+00:00", "transactionCurrency": "GBP", "units": 100000, "transactionPrice": {"price": 1, "type": "Price"}, "totalConsideration": {"amount": 120000, "currency": "USD"}, "exchangeRate": 1.2 } }
Modelling a FxForward as a transaction
Note: The recommended way to model a foreign exchange or currency forward contract ("FxForward") is to master an instrument in the LUSID Security Master and then book a unitised transaction in a portfolio. This is a small amount of extra setup, but LUSID's full suite of analytical capability is available. See how to do this.
Alternatively, you can not master an instrument and instead book a forward-settled cash transaction directly in a portfolio with different buy and sell currencies, using the FwdFxBuy
and FwdFxSell
built-in transaction types provided with LUSID.
Consider the following example, of a transaction to sell GBP and buy USD in a EUR-denominated portfolio in 6 months' time at a strike rate of 1.2:
- The transaction
type
field is set toFwdFxSell
but this could equally beFwdFxBuy
with the amounts and rates reversed. - The
instrumentIdentifiers
field maps the transaction to the sell currency instrument, GBP. Note all major currency instruments are pre-mastered in LUSID. - The
transactionDate
field marks the start of the contract. - The
settlementDate
field is the maturity date. - The
transactionCurrency
field is the currency to sell, GBP. - The
units
field is the amount to sell, £100,000. - The
totalConsideration.currency
field is the currency to buy, USD. - The
totalConsideration.amount
field is the trade amount in the buy currency: $120,000. - The
exchangeRate
is the GBP/USD strike rate: 1.2. This enables LUSID to calculate the trade amount in the sell currency: $120,000 / 1.2 = £100,000. - The
TradeToPortfolioRate
system property records the GBP/EUR spot rate, 1.1. This enables LUSID to calculate the trade amount in the portfolio currency, thereby maintaining the cost basis of the portfolio: £100,000 * 1.1 = €110,000.
curl -X POST 'https://<your-domain>.lusid.com/api/api/transactionportfolios/Funds/Managed/transactions/$batchUpsert?successMode=Partial' -H 'Content-Type: application/json-patch+json' -H 'Authorization: Bearer <your-API-access-token>' -d '{ "transactionRequest-4": { "transactionId": "Txn-0000004", "type": "FwdFxSell", "instrumentIdentifiers": {"Instrument/default/Currency": "GBP"}, "transactionDate": "2023-06-07T00:00:00.0000000+00:00", "settlementDate": "2023-12-11T00:00:00.0000000+00:00", "transactionCurrency": "GBP", "units": 100000, "transactionPrice": {"price": 1, "type": "Price"}, "totalConsideration": {"amount": 120000, "currency": "USD"}, "exchangeRate": 1.2, "properties": { "Transaction/default/TradeToPortfolioRate": { "key": "Transaction/default/TradeToPortfolioRate", "value": { "metricValue": { "value": 1.1, "unit": "" } } } } } }'
LUSID generates two temporary holdings for each FxForward booked as a transaction while the contract is live, one per currency. Note the holding type is Forward FX
on the inception date, 7 June 2023, and that no units are settled:
When the contract matures, LUSID automatically updates the main cash holdings in the two currencies and removes the temporary holdings. Note the holding type is Cash Balance
on the maturity date, 11 December 2023, and that all units are now settled: