Handling instrument events for FxForwards

Prev Next

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 startDate is 1 January and maturityDate is 1 June 2024, signifying a five month contract.

  • The domCcy must 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 domAmount is the amount of domCcy. It could be negative, but we have chosen positive since we are buying/receiving USD.

  • The fgnCcy is the other currency, in this case EUR. Note our holding will not be valued in this currency.

  • The fgnAmount is the amount of fgnCcy. It must have the opposite sign to domAmount, so in this example negative since domAmount is positive.

  • isNdf is 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 StockIn since there is no cash outlay, but it could be Buy or some other long transaction type.

  • The transactionDate and settlementDate both mark the start of the contract, 1 January 2024. The instrument defines the length.

  • The number of units purchased is 1.

  • The transactionPrice field is deliberately omitted, so LUSID sets the price to 0.

  • The transactionCurrency and totalConsideration.currency (settlement currency) is the domCcy of the instrument, so in this case USD.

  • The totalConsideration.amount field is deliberately omitted, so LUSID sets the cost to 0.

  • The Transaction/default/TradeToPortfolioRate system 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:

  1. A FxForwardSettlementEvent. You should handle this event to exchange the two cashflows.

  2. 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 Virtual option to calculate realised gain/loss for each leg without actually effecting a sale. Note the direction is negative and a custom SignedSide1 is 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 domCcy of the instrument (USD in our example) to the fgnCcy (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:

  1. Apply the Txn:TradeToPortfolioRate and Txn:ExchangeRate calculation types to the FxForwardDomPrincipal and FxForwardFgnPrincipal transaction types, as demonstrated above.

  2. 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.

  3. 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 FxForward instrument itself since the number of units was set to zero by MaturityEvent.

  • 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:

  1. Create a corporate action source and subscribe all portfolios with a holding in the FxForward to that source. See how to do this.

  2. Load the EarlyCloseOutEvent into 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.