You can model a foreign exchange or currency forward contract as an instrument of type FxForward in LUSID. See how to do this.
LUSID provides the following instrument events for a FxForward, which you can handle or trigger as required:
FxForwardSettlementEvent. This event is automatically emitted on the maturity date specified in the instrument definition. More information.MaturityEvent. This event is also automatically emitted on the maturity date. More information.EarlyCloseOutEvent. This event is not automatically emitted by LUSID, but can be manually loaded to trigger an early closure. More information.
Mastering an instrument and establishing a position
Imagine on 1 January 2024 we want to enter into a contract to pay/sell 900 EUR and buy/receive 1000 USD in 5 months' time. We can model this contract as an instrument of type FxForward using the following economic definition:
{
"instrumentType": "FxForward",
"startDate": "2024-01-01T00:00:00.0000000+00:00",
"maturityDate": "2024-06-01T00:00:00.0000000+00:00",
"domCcy": "USD",
"domAmount": 1000,
"fgnCcy": "EUR",
"fgnAmount": -900,
"isNdf": false
}Note the following:
The
startDateis 1 January andmaturityDateis 1 June 2024, signifying a five month contract.The
domCcymust be the currency in which we want our holding in this instrument to be valued. It could be EUR, but we have chosen USD.The
domAmountis the amount ofdomCcy. It could be negative, but we have chosen positive since we are buying/receiving USD.The
fgnCcyis the other currency, in this case EUR. Note our holding will not be valued in this currency.The
fgnAmountis the amount offgnCcy. It must have the opposite sign todomAmount, so in this example negative sincedomAmountis positive.isNdfis false (the default) to signify this is a deliverable contract. Note instrument events have different behavior for NDFs (not examined in this article).
We can now purchase a single unit of this contract in a portfolio that happens to be denominated in a third currency, GBP:
[
{
"transactionId": "Txn-00001",
"type": "StockIn",
"instrumentIdentifiers": {"Instrument/default/ClientInternal": "FxForward-EURUSD-5M"},
"transactionDate": "2024-01-01T00:00:00.0000000+00:00",
"settlementDate": "2024-01-01T00:00:00.0000000+00:00",
"units": 1,
"transactionCurrency": "USD",
"totalConsideration": {"currency": "USD"},
"properties": {
"Transaction/default/TradeToPortfolioRate": {
"key": "Transaction/default/TradeToPortfolioRate",
"value": {
"metricValue": {
"value": 0.79
}
}
}
}
}
]Note the following:
The type is
StockInsince there is no cash outlay, but it could beBuyor some other long transaction type.The
transactionDateandsettlementDateboth mark the start of the contract, 1 January 2024. The instrument defines the length.The number of
unitspurchased is1.The
transactionPricefield is deliberately omitted, so LUSID sets the price to0.The
transactionCurrencyandtotalConsideration.currency(settlement currency) is thedomCcyof the instrument, so in this caseUSD.The
totalConsideration.amountfield is deliberately omitted, so LUSID sets the cost to0.The
Transaction/default/TradeToPortfolioRatesystem property records the spot rate on 1 January 2024 from transaction (USD) to portfolio (GBP) currency, in this example 0.79. Note we have chosen to hard-code this rate but you can configure LUSID to look it up dynamically in the Quote Store. See how to do this.
If we examine our holdings in this portfolio on 1 January we see we have a settled position in the FxForward with a cost of zero:

Handling instrument maturity
Providing our position is held to maturity on 1 June 2024, LUSID automatically emits, in the following order:
A
FxForwardSettlementEvent. You should handle this event to exchange the two cashflows.A
MaturityEvent. You should handle this event to set your position in the instrument to zero, so it drops out of holding reports.
For more information on these events, start by calling the GetTransactionTemplate API for each to examine the default transaction template provided by LUSID. Note you can create custom transaction templates for one or both to configure this process if you wish.
Handling FxForwardSettlementEvent
To handle this event using the default transaction template, you must create FxForwardDomPrincipal and FxForwardFgnPrincipal transaction types grouped in the default source.
Note: Transaction types are grouped in sources and reside in scopes. For more information on the difference, see this article.
The definition of FxForwardDomPrincipal and FxForwardFgnPrincipal can actually be the same, so our recommendation is a single transaction type with two aliases, for example:
{
"aliases": [
{
"type": "FxForwardDomPrincipal",
"description": "Settle the domestic leg of a FxForwardSettlementEvent",
"transactionClass": "CashFlows",
"transactionRoles": "AllRoles",
"isDefault": false
},
{
"type": "FxForwardFgnPrincipal",
"description": "Settle the foreign leg of a FxForwardSettlementEvent",
"transactionClass": "CashFlows",
"transactionRoles": "AllRoles",
"isDefault": false
}
],
"movements": [
{
"name": "Virtually sell the individual legs to calculate realised gain/loss",
"movementTypes": "StockMovement",
"side": "SignedSide1",
"direction": -1,
"movementOptions": ["Virtual"]
},
{
"name": "Manifest the cash holdings",
"movementTypes": "CashCommitment",
"side": "Side2",
"direction": 1,
}
],
"calculations": [
{
"type": "Txn:TradeToPortfolioRate"
},
{
"type": "Txn:ExchangeRate"
}
]
}Note the following:
The first movement uses the
Virtualoption to calculate realised gain/loss for each leg without actually effecting a sale. Note the direction is negative and a customSignedSide1is used (see below).The second movement creates currency holdings using the built-in
Side2. Note the direction is positive, but the side respects the sign of each leg's total consideration, so the USD holding ends up positive and the EUR holding ends up negative.The calculation types configure LUSID to look up exchange rates from transaction to portfolio and from transaction to settlement currencies respectively in the Quote Store, which is required for the maturity date. See how to set this up.
Our recommendation for the custom SignedSide1 is as follows:
{
"security": "Txn:LusidInstrumentId",
"currency": "Txn:TradeCurrency",
"rate": "Txn:TradeToPortfolioRate",
"units": "Txn:Units",
"amount": "Txn:TotalConsiderationInTradeCurrency"
}This is similar to the built-in Side1 except the amount field is set to Txn:TotalConsiderationInTradeCurrency instead of Txn:TradeAmount, to respect the sign of the amount instead of converting it to match the units. This is important because the total consideration of one leg (EUR in our example) is negative. More information.
Handling MaturityEvent
To handle this event using the default transaction template provided with LUSID, you must create a Maturity transaction type grouped in the default source. This can have any economic impact you like, but our recommendation is as follows to reduce the units to zero:
{
"aliases": [
{
"type": "Maturity",
"description": "Generic transaction type for maturity events for many different instrument types",
"transactionClass": "Basic",
"transactionRoles": "AllRoles",
"isDefault": false
}
],
"movements": [
{
"name": "Reduce holding to zero",
"movementTypes": "StockMovement",
"side": "Side1",
"direction": -1
}
]
}Loading spot rates for the maturity date into the LUSID Quote Store
In order that LUSID may calculate realised gains/losses for the output transactions generated by FxForwardSettlementEvent, we must load the following exchange rates into the LUSID Quote Store for the maturity date, 1 June 2024:
Rate from the
domCcyof the instrument (USD in our example) to thefgnCcy(EUR). Let's imagine the USD/EUR rate has moved in our favour from the implied strike rate of 0.90 in the instrument definition to 0.93.Rate from the
domCcy(USD) to the portfolio currency (GBP). Let's imagine the USD/GBP rate has slipped from 0.79 (hard-coded in the purchase transaction) to 0.75.
We can call the UpsertQuotes API to load these exchange rates into the Quote Store. See an example.
In order for LUSID to locate and apply these exchange rates, we must also:
Apply the
Txn:TradeToPortfolioRateandTxn:ExchangeRatecalculation types to theFxForwardDomPrincipalandFxForwardFgnPrincipaltransaction types, as demonstrated above.Create a new (or configure an existing) recipe to have market data rules able to locate the rates loaded into the Quote Store. See an example.
Register this recipe with the portfolio(s) holding the
FxForward. See how to patch an existing portfolio.
Examining the impact of events on the portfolio at maturity date
Calling the GetHoldings API on 1 June 2024 reveals that the FxForwardSettlementEvent has generated two cash holdings in the portfolio representing the exchange of the two currencies, one for 1000 USD and one for -900 EUR:

Note the following:
We no longer have a holding in the
FxForwardinstrument itself since the number of units was set to zero byMaturityEvent.The portfolio cost of the USD holding reflects the cost of ‘purchasing’ 1000 USD at the USD/GBP (trade to portfolio rate) of 0.75 on 1 June 2024, namely £750.
The portfolio cost of the EUR holding reflects the same original cost minus the gain we have made from entering into the forward contract (relative to not having done so): £750 - £24.19 = £725.81.
We can call the BuildTransactions API with a suitable window to see the three output transactions that have contributed to these positions, and examine the gain/loss calculations in more detail. The first two transactions are generated by FxForwardSettlementEvent and the third by MaturityEvent:

To see the realised gain/loss calculations, click the +/- button at the end of each row (highlighted in red above). For the first transaction settling the domestic (USD) leg, we can see we made a loss of -£40 because the USD/GBP exchange rate slipped from 0.79 on 1 January to 0.75 on 1 June:

However, for the foreign (EUR) leg we see we made a gain of £64.19 because the USD/EUR exchange rate improved from 0.9 (implied) on 1 January to 0.93 on 1 June. Our total realised gain for the instrument as a whole is therefore £64.19 - £40 = £24.19, or $32.26 at the USD/GBP exchange rate of 0.75:

We can see this more clearly by creating an A2B report for the period 31 December 2023 11:59:59 to 1 June 2024 (note setting the start date to just before the initial purchase of the FxForward prevents LUSID calculating a MarketValue (Start), which is not useful in this situation):

Closing a position early
You can choose to close position(s) in a FxForward instrument early by manually loading an EarlyCloseOutEvent into LUSID. To do this:
Create a corporate action source and subscribe all portfolios with a holding in the
FxForwardto that source. See how to do this.Load the
EarlyCloseOutEventinto the corporate action source. See this article for general information, and also the example coming soon.
It’s important to re-iterate that only portfolios subscribed to the corporate action source will be impacted.