---
title: "Handling instrument events for FxForwards"
slug: "handling-fxforward-settlement-and-maturity-instrument-lifecycle-events"
updated: 2025-11-21T13:05:26Z
published: 2025-11-21T13:05:26Z
canonical: "support.lusid.com/handling-fxforward-settlement-and-maturity-instrument-lifecycle-events"
---

> ## Documentation Index
> Fetch the complete documentation index at: https://support.lusid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Handling instrument events for FxForwards

You can model a foreign exchange or currency forward contract as an instrument of type `FxForward` in LUSID. [See how to do this](/v1/docs/modelling-fxforwards-in-lusid).

LUSID provides the following [instrument events](/v1/docs/understanding-instrument-lifecycle-events-emitted-by-lusid) 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](/v1/docs/handling-fxforward-settlement-and-maturity-instrument-lifecycle-events#handling-instrument-maturity).
- `MaturityEvent`. This event is also automatically emitted on the maturity date. [More information](/v1/docs/handling-fxforward-settlement-and-maturity-instrument-lifecycle-events#handling-instrument-maturity).
- `EarlyCloseOutEvent`. This event is **not automatically emitted** by LUSID, but can be manually loaded to trigger an early closure. [More information](/v1/docs/handling-fxforward-settlement-and-maturity-instrument-lifecycle-events#closing-a-position-early).

## 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](/v1/docs/modelling-fxforwards-in-lusid#mastering-an-instrument) as an instrument of type `FxForward` using the following economic definition:

```json
{
  "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](/v1/docs/modelling-fxforwards-in-lusid#booking-a-transaction-to-establish-a-position) of this contract in a portfolio that happens to be denominated in a third currency, GBP:

```json
[
  {
    "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](/v1/docs/what-is-a-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](/v1/docs/what-is-a-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](/v1/docs/transactions-and-exchange-rates#looking-up-exchange-rates-dynamically-using-a-recipe).

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:

![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/InitialHoldings.png)

## 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](https://www.lusid.com/docs/api/lusid/endpoints/instrument-event-types/GetTransactionTemplate/) API for each to examine the default transaction template provided by LUSID. Note you can [create custom transaction templates](/v1/docs/how-do-i-create-a-custom-transaction-template) 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](/v1/docs/grouping-related-transaction-types-using-scopes-and-sources).

The definition of `FxForwardDomPrincipal` and `FxForwardFgnPrincipal` can actually be the same, so our recommendation is a single transaction type with two aliases, for example:

```json
{ 
 "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](/v1/docs/what-built-in-transaction-types-and-sides-are-provided-with-lusid#builtin-sides) `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](/v1/docs/what-is-a-transaction-type-calculation) 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](/v1/docs/handling-fxforward-settlement-and-maturity-instrument-lifecycle-events#loading-spot-rates-for-the-maturity-date-into-the-lusid-quote-store).

Our recommendation for the custom `SignedSide1` is as follows:

```json
{
  "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](/v1/docs/what-is-a-side#units-amount).

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

```json
{
 "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](https://www.lusid.com/docs/api/lusid/endpoints/quotes/UpsertQuotes.html) API to load these exchange rates into the Quote Store. [See an example](/v1/docs/transactions-and-exchange-rates#dynamic-lookup-quotes).

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](/v1/docs/handling-fxforward-settlement-and-maturity-instrument-lifecycle-events#handling-fxforwardsettlementevent).
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](/v1/docs/transactions-and-exchange-rates#dynamic-lookup-recipe).
3. Register this recipe with the portfolio(s) holding the `FxForward`. [See how to patch an existing portfolio](/v1/docs/transactions-and-exchange-rates#dynamic-lookup-portfolio).

### Examining the impact of events on the portfolio at maturity date

Calling the [GetHoldings](https://www.lusid.com/docs/api/lusid/endpoints/transaction-portfolios/GetHoldings.html) 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:

![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/MaturityHoldings.png)

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](https://www.lusid.com/docs/api/lusid/endpoints/transaction-portfolios/BuildTransactions.html) 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`:

![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/OutputTransactions.png)

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:

![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/USDLegGainLoss.png)

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:

![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/EURLegGainLoss.png)

We can see this more clearly by [creating an A2B report](/v1/docs/creating-an-a2b-report-to-understand-how-valuations-change-over-time) 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):

![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/A2B.png)

## 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](https://support.lusid.com/v1/docs/handling-a-cash-dividend-corporate-action-event#creating-a-corporate-action-source).
2. Load the `EarlyCloseOutEvent` into the corporate action source. See [this article](https://support.lusid.com/v1/docs/how-do-i-upload-corporate-actions-to-a-corporate-action-source) 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.
