---
title: "Handling mark to market and expiry lifecycle events for futures"
slug: "handling-future-mark-to-market-and-expiry-events"
updated: 2026-06-12T08:33:53Z
published: 2026-06-12T08:33:53Z
canonical: "support.lusid.com/handling-future-mark-to-market-and-expiry-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 mark to market and expiry lifecycle events for futures

You can model an exchange-traded futures contract as an instrument of type `Future` in LUSID. [See how to do this](/v1/docs/modelling-exchange-traded-futures-and-options-in-lusid).

LUSID emits the following instrument lifecycle events for a `Future` providing [suitable market data can be located](/v1/docs/handling-future-mark-to-market-and-expiry-events#loading-suitable-market-data-into-the-lusid-quote-store), which you can optionally handle to reduce workload and improve efficiency:

- `FutureMarkToMarketEvent` every weekday at the time specified in the instrument definition until the day *before* maturity.
- `FutureExpiryEvent` on the maturity date at the time specified in the instrument definition.

> **Note**: For an implementation using the Python SDK see [this Jupyter Notebook](https://github.com/finbourne/finbourne-notebooks/blob/main/V3/features/instrument-events/futures-and-instrument-events.ipynb).

## Mastering an instrument and establishing a position

Imagine we have a E-mini S&P futures contract trading on the Globex exchange that matures on Friday 21 March 2025. We can model this in LUSID as an instrument of type `Future` with the following economic definition:

```json
"definition": {
  "instrumentType": "Future",
  "startDate": "2024-09-21T10:00:00.0000000+00:00",
  "maturityDate": "2025-03-21T17:30:00.0000000+00:00",
  "identifiers": {},
  "contractDetails": {
    "domCcy": "USD",
    "contractCode": "ESHS",
    "contractMonth": "H",
    "contractSize": 50,
    "exchangeCode": "GLOBEX",
    "deliveryType": "Cash"
  },
  "contracts": 1,
  "markToMarketConventions": {
    calendarCode: "USD"
  }
  "tradingConventions": {
    "priceScaleFactor": 1
  }
}
```

For much more information on modelling instruments of type `Future`, see [this article](/v1/docs/modelling-exchange-traded-futures-and-options-in-lusid). Note with regard to instrument events:

- The `contracts` field should be set to `1`.
- The `markToMarketConventions` object must be specified if you want LUSID to emit a daily `FutureMarkToMarketEvent`. If you do not, and only want LUSID to emit a single `FutureExpiryEvent` on the `maturityDate`, omit this object.
- The `markToMarketConventions.calendarCode` field should be set to the code of the most appropriate calendar for the exchange. If you omit this field, LUSID emits a `FutureMarkToMarketEvent` each weekday irrespective of whether it is a holiday in that jurisdiction. Note the scope of the calendar is determined by the `calendarScope` field in a [portfolio recipe](/v1/docs/setting-a-portfolio-recipe), which is `CoppClarkHolidayCalendars` by default.
- The time component of the `maturityDate` should be set to the time that settlement prices are released by the exchange, for example 5:30pm. LUSID emits a `FutureMarkToMarketEvent` each day at this time, beginning on the transaction date and ending on the day *before* the `maturityDate`.
- The `deliveryType` field should be set to `Cash`. LUSID does not emit instrument events for physical settlement.
- The `tradingConventions.priceScaleFactor` field can be set to `1` for most futures (this is the default), but may be set to `100` for bond futures (for example).

We can now establish a position by booking a transaction in this instrument into a suitable portfolio, for example:

```json
{
  "transactionId": "my_future_purchase_001",
  "type": "BuyFuture",
  "instrumentIdentifiers": {"Instrument/default/LusidInstrumentId": "LUID_00003E7N"},
  "transactionDate": "2024-09-21T09:00:00.0000000+00:00",
  "settlementDate": "2024-09-21T09:00:00.0000000+00:00",
  "units": 10,
  "transactionPrice": {
    "price": 6000,
    "type": "Price"
  },
  "totalConsideration": {
    "amount": 0,
    "currency": "USD"
  },
  "properties": {
    "Transaction/MyProperties/TradeCommission": {
      "key": "Transaction/MyProperties/TradeCommission",
      "value": {
        "metricValue": {
          "value": 50.00,
          "unit": "USD"
        }
      }
    }
  }
}
```

For much more information on booking transactions in `Future` instruments, including details of the recommended `BuyFuture` transaction type to automatically calculate notional amount, gross consideration and total consideration, see [this article](/v1/docs/modelling-exchange-traded-futures-and-options-in-lusid#booking-a-transaction-to-establish-a-position). Note with regard to instrument events:

- The `transactionDate` and `settlementDate` are both Wednesday 25 September 2024 at 9am. LUSID begins emitting events the same day at 5:30pm.
- LUSID calculates notional as `(units * price * contracts * contract size) / scale factor`, so in this case `(10 * 6000 * 1 * 50) / 1 = 3,000,000`.
- The fee representing the cost of entering into the contract is recorded using a custom property. This represents both the gross and total consideration for this transaction.

## Understanding lifecycle events emitted by LUSID

For our holding in this instrument in this portfolio, **and providing suitable market data can be located in the Quote Store**, LUSID automatically emits:

- A `FutureMarkToMarketEvent` at the time specified by the maturity date each weekday, beginning on the transaction date (Wednesday 25 September 2024 5:30pm in our example) and continuing until the day *before* the maturity date (Thursday 20 March 2025 5:30pm). You should handle this event to set the PV of the `Future` instrument to zero and realise daily gain or loss.
- A `FutureExpiryEvent` on the maturity date (Friday 21 March 2025 5:30pm). You should handle this event to cash settle the contract and set your position to zero, so it drops out of holding and valuation reports.

LUSID provides a [default transaction template](/v1/docs/what-is-a-transaction-template) for each type of event. In this tutorial we'll choose to use the default transaction templates for both types, but you can [create your own custom transaction templates](/v1/docs/how-do-i-create-a-custom-transaction-template) to configure the process if you wish.

### Examining the default transaction template for `FutureMarkToMarketEvent`

We can call the [GetTransactionTemplate](https://www.lusid.com/docs/api#operation/GetTransactionTemplate) API to examine the default template for `FutureMarkToMarketEvent`, which at the time of writing is as follows:

```json
{
  "instrumentType": "Future",
  "instrumentEventType": "FutureMarkToMarketEvent",
  "description": "LUSID default template for automatically generated transactions in respect of Future Mark To Market events.",
  "scope": "default",
  "componentTransactions": [
    {
      "displayName": "Mark to market",
      "transactionFieldMap": {
        "transactionId": "{{instrumentEventId}}-{{holdingId}}",
        "type": "FutureMarkToMarket",
        "source": "default",
        "instrument": "{{instrument}}",
        "transactionDate": "{{FutureMarkToMarketEvent.effectiveDate}}",
        "settlementDate": "{{FutureMarkToMarketEvent.effectiveDate}}",
        "units": "{{eligibleBalance}}",
        "transactionCurrency": "{{FutureMarkToMarketEvent.settlementCurrency}}",
        "exchangeRate": "1",
        "totalConsideration": {
          "currency": "{{FutureMarkToMarketEvent.settlementCurrency}}"
        }
      },
      "transactionPropertyMap": [
        {
          "propertyKey": "Transaction/default/GrossConsideration",
          "value": "{{FutureMarkToMarketEvent.markToMarketAmount}}"
        }
      ]
    }
  ],
  ...
}
```

Note the following:

- This template handles instrument events of type `FutureMarkToMarketEvent` emitted by instruments of type `Future`.
- It is domiciled in the `default` (that is, system) transaction template `scope`.
- It contains instructions for automatically generating a single [output transaction](/v1/docs/input-and-output-transactions) in every portfolio with a holding in the underlying instrument. Note it is possible for a template to generate multiple output transactions.
- The generated transaction has no `condition`, so it is always produced when LUSID emits this event.
- The generated transaction belongs to a `FutureMarkToMarket` [transaction type](/v1/docs/what-is-a-transaction-type) grouped in the `default` transaction type `source`.
- The quantity held (`units`) is assessed dynamically per-weekday and per-portfolio.
- The `transactionCurrency` and `totalConsideration.currency` (settlement currency) are both set to the `domCcy` of the instrument economic definition, so the `exchangeRate` between them is `1`.
- The `totalConsideration.amount` is deliberately not set. Instead, LUSID automatically calculates gross consideration and stores the result in the `Transaction/default/GrossConsideration` [system property](/v1/docs/what-is-a-system-property#transaction-system-properties). It is your responsibility to set total consideration equal to gross consideration (see below).

> **Note**: This template does not specify the `Transaction/default/TradeToPortfolioRate` system property to maintain the cost basis of the portfolio. If the transaction and portfolio currencies are different, we recommend specifying the `Txn:TradeToPortfolioRate` calculation in the `FutureMarkToMarket` transaction type to look up a spot rate dynamically in the LUSID Quote Store. [See how to do this](/v1/docs/transactions-and-exchange-rates#looking-up-exchange-rates-dynamically-using-a-recipe).

### Creating a suitable `FutureMarkToMarket` transaction type

The default transaction template mandates a `FutureMarkToMarket` transaction type grouped in the `default` transaction type source. We must create this transaction type if it does not exist.

> **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).

We can call the [SetTransactionType](https://www.lusid.com/docs/api#operation/SetTransactionType) API as follows:

```json
curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/types/default/FutureMarkToMarket?scope=default'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "aliases": [
    {
      "type": "FutureMarkToMarket",
      "description": "Transaction type for transactions automatically generated by FutureMarkToMarketEvent",
      "transactionClass": "Basic",
      "transactionRoles": "AllRoles",
      "isDefault": false
    }
  ],
  "movements": [
    {
      "name": "Adjust notional cost up or down"
      "movementTypes": "VariationMargin",
      "side": "MTMCustomSide",
      "direction": 1
    },
    {
      "name": "Realise daily gain or loss"
      "movementTypes": "CashReceivable",
      "side": "Side2",
      "direction": 1,
    }
  ],
  "calculations": [
    {
      "type": "DeriveTotalConsideration",
      "formula": "Txn:GrossConsideration"
    }
  ]
}'
```

Note the following:

- The transaction type alias is `FutureMarkToMarket`, to comply with the default transaction template.
- The transaction type source is `default` (specified in the URL), to comply with the default transaction template.
- You can design a transaction type to have [any economic impact you like](/v1/docs/what-is-a-transaction-type). This recommendation has two [movements](/v1/docs/what-movement-types-are-available):
  - The first is a `VariationMargin` movement to adjust the notional cost up or down without impacting the units of the holding. Note the `side` references a `MTMCustomSide` (see below).
  - The second is a `CashReceivable` movement that realises daily gain or loss. Note the `direction` is positive but values generated by the event are signed negative if they are losses.
- The `DeriveTotalConsideration` [transaction type calculation](/v1/docs/what-is-a-transaction-type-calculation) sets total consideration equal to gross consideration. This is important as the event itself does not emit a total consideration.

We might call the [SetSideDefinition](https://www.lusid.com/docs/api/lusid/endpoints/transaction-configuration/SetSideDefinition/) API to create a `MTMCustomSide` as follows:

```json
curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/sides/MTMCustomSide?scope=default'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "security": "Txn:LusidInstrumentId",
  "currency": "Txn:TradeCurrency",
  "rate": "Txn:TradeToPortfolioRate",
  "units": "Txn:Units",
  "amount": "Txn:TotalConsideration"
}'
```

Note this is the same as the [built-in](/v1/docs/what-built-in-transaction-types-and-sides-are-provided-with-lusid#builtin-sides) `Side1` except the `amount` field is set to `Txn:TotalConsideration` instead of `Txn:TradeAmount`, to respect the negative sign of losses.

### Examining the default transaction template for `FutureExpiryEvent`

In the same way, we can call the [GetTransactionTemplate](https://www.lusid.com/docs/api/lusid/endpoints/instrument-event-types/GetTransactionTemplate) API to examine the default transaction template for `FutureExpiryEvent`, which at the time of writing is as follows:

```json
{
  "instrumentType": "Future",
  "instrumentEventType": "FutureExpiryEvent",
  "description": "LUSID default template for automatically generated transactions in respect of Future Expiry events.",
  "scope": "default",
  "componentTransactions": [
    {
      "displayName": "Cash settlement transaction",
      "transactionFieldMap": {
        "transactionId": "{{instrumentEventId}}-{{holdingId}}",
        "type": "FutureCashSettlement",
        "source": "default",
        "instrument": "{{instrument}}",
        "transactionDate": "{{FutureExpiryEvent.expiryDate}}",
        "settlementDate": "{{FutureExpiryEvent.expiryDate}}",
        "units": "{{eligibleBalance}}",
        "transactionCurrency": "{{FutureExpiryEvent.settlementCurrency}}",
        "exchangeRate": "1",
        "totalConsideration": {
          "currency": "{{FutureExpiryEvent.settlementCurrency}}"
        }
      },
      "transactionPropertyMap": [
        {
          "propertyKey": "Transaction/default/NotionalAmount",
          "value": "{{FutureExpiryEvent.notionalAmount}}"
        }
      ]
    }
  ],
  ...
}
```

Note the following:

- This template handles instrument events of type `FutureExpiryEvent` emitted by instruments of type `Future`.
- The generated output transaction belongs to a `FutureCashSettlement` [transaction type](/v1/docs/what-is-a-transaction-type) grouped in the `default` transaction type `source`.
- The `totalConsideration.amount` is deliberately not set. It is your responsibility to ensure LUSID calculates gross consideration and total consideration (see below).

### Creating a suitable `FutureCashSettlement` transaction type

The default transaction template mandates a `FutureCashSettlement` transaction type grouped in the `default` transaction type source. We must call the [SetTransactionType](https://www.lusid.com/docs/api/lusid/endpoints/transaction-configuration/SetTransactionType) API to create this transaction type if it does not exist, for example:

```json
curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/types/default/FutureCashSettlement?scope=default'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "aliases": [
    {
      "type": "FutureCashSettlement",
      "description": "Transaction type for transactions automatically generated by FutureExpiryEvent",
      "transactionClass": "Basic",
      "transactionRoles": "AllRoles",
      "isDefault": false
    }
  ],
  "movements": [
    {
      "name": "Set units to 0"
      "movementTypes": "StockMovement",
      "side": "NotionalCustomSide",
      "direction": -1
    },
    {
      "name": "Realise contract gain or loss"
      "movementTypes": "CashReceivable",
      "side": "Side2",
      "direction": 1,
    }
  ],
  "calculations": [
    {
      "type": "Txn:GrossConsideration"
    },
    {
      "type": "DeriveTotalConsideration",
      "formula": "Txn:GrossConsideration"
    }
  ]
}'
```

Note the following:

- The transaction type alias is `FutureCashSettlement`, to comply with the default transaction template.
- The transaction type source is `default` (specified in the URL), to comply with the default transaction template.
- You can design a transaction type to have [any economic impact you like](/v1/docs/what-is-a-transaction-type). This recommendation has two [movements](/v1/docs/what-movement-types-are-available):
  - The first is a `StockMovement` movement to set the units of the holding to zero. Note the `side` references a `NotionalCustomSide` (see below).
  - The second is a `CashReceivable` movement that realises gain or loss for the contract as a whole. Note the `direction` is positive but the value generated by the event is signed negative if it is a loss.
- The `Txn:GrossConsideration` [transaction type calculation](/v1/docs/what-is-a-transaction-type-calculation) calculates gross consideration as `notionalAmount - (notionalCost + variationMargin)`.
- The `DeriveTotalConsideration` calculation sets total consideration equal to gross consideration. This is important as the event itself does not emit a total consideration.

We can call the [SetSideDefinition](https://www.lusid.com/docs/api/lusid/endpoints/transaction-configuration/SetSideDefinition/) API to create a `NotionalCustomSide` as follows:

```json
curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/sides/NotionalCustomSide?scope=default'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "security": "Txn:LusidInstrumentId",
  "currency": "Txn:TradeCurrency",
  "rate": "Txn:TradeToPortfolioRate",
  "units": "Txn:Units",
  "amount": "Txn:TotalConsideration",
  "notionalAmount": "Transaction/default/NotionalAmount"
}'
```

Note this is the same as the [built-in](https://support.lusid.com/docs/what-built-in-transaction-types-and-sides-are-provided-with-lusid#builtin-sides) `Side1` except:

- The `amount` field is set to `Txn:TotalConsideration` instead of `Txn:TradeAmount`, to respect the negative sign of losses.
- The `notionalAmount` field is set to the `Transaction/default/NotionalAmount` system property, to handle LUSID’s calculation of notional amount.

## Loading suitable market data into the LUSID Quote Store

In order that LUSID may calculate gross consideration and notional amounts for instrument lifecycle events, we must load the following market data into LUSID:

- A settlement market price for the instrument every weekday (not Saturday or Sunday). If LUSID cannot locate a price for a particular weekday, a `FutureMarkToMarketEvent` is not generated that day.
- A final market price for the instrument on the maturity date. If LUSID cannot locate a market price for that date, a `FutureExpiryEvent` is not generated.

Consider the following example dates:

| Date | Time | Price |
| --- | --- | --- |
| Wednesday 25 September 2024 | 17:29:00 | 6002 |
| Thursday 26 September 2024 | 6004 |
| Friday 27 September 2024 | 5998 |
| Monday 30 September 2024 | 6001 |
| Tuesday 1 October 2024 | 6003 |
| Friday 21 March 2025 | 6005 |

We can call the [UpsertQuotes](https://www.lusid.com/docs/api/lusid/endpoints/quotes/UpsertQuotes/) API to load these market prices into the Quote Store. In the following example, a market price for Wednesday 25 September 2024 at 5:29pm is encapsulated in a `MyFutureMarketPricesScope` (specified in the URL), and the underlying instrument is identified by [LUID](/v1/docs/what-is-a-lusid-instrument-id-or-luid):

```json
curl -X POST 'https://<your-domain>.lusid.com/api/api/quotes/MyFutureMarketPricesScope'
  -H 'Authorization: Bearer <your-API-access-token>'
  -H 'Content-Type: application/json-patch+json'
  -d '{
  "Quote-0001": {
    "quoteId": {
      "quoteSeriesId": {
        "provider": "Lusid",
        "instrumentIdType": "LusidInstrumentId",
        "instrumentId": "LUID_00003E7N",
        "quoteType": "Price",
        "field": "mid"
      },
      "effectiveAt": "2024-09-25T17:29:00Z"
    },
    "metricValue": {
      "value": 6002, "unit": "USD"
    }
  },
```

Note that in order to locate these market prices, the [portfolio recipe](/v1/docs/setting-a-portfolio-recipe) must have a market rule with:

- The `dataScope` field set to `MyFutureMarketPricesScope`, to locate the correct quote scope.
- The `quoteInterval` field set to `0D.0D`, to prevent look up of stale quotes:

```json
"market": {
  "marketRules": [
    {
      "key": "Quote.LusidInstrumentId",
      "supplier": "Lusid",
      "dataScope": "MyFutureMarketPricesScope",
      "quoteType": "Price",
      "field": "mid",
      "quoteInterval": "0D.0D"
    },
    ...
  ]
}
```

## Examining the impact of instrument lifecycle events on the portfolio

### Wednesday 25 September 2024 12pm

We can use **Portfolio Management > Valuations** in the LUSID web app to call the [GetValuation](https://www.lusid.com/docs/api/lusid/endpoints/aggregation/GetValuation/) API on the transaction date before the first `FutureMarkToMarketEvent` and see that we have:

- 10 units of the instrument holding with a notional exposure of 3,000,000.
- A cash holding of -$50 reflecting the cost of entering into the contract:

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

### Wednesday 25 September 2024 5:30pm

If we move the **Effective** time to 5:30pm we can see that the first `FutureMarkToMarketEvent` has increased the instrument exposure to 3,001,000 and the cash holding to $950, reflecting the difference between the daily settlement price (6002) and the purchase price (6000):

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

### Thursday 26 September 2024 5:30pm

If we move the **Effective** date to Thursday we can see that the second `FutureMarkToMarketEvent` has increased the instrument exposure to 3,002,000 and the cash holding to $1,950, reflecting the difference between the daily settlement price (6004) and the purchase price (6000):

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

### Friday 27 September 2024 5:30pm

If we move the **Effective** date to Friday we can see that the third `FutureMarkToMarketEvent` has decreased the instrument exposure to 2,999,000 and the cash holding to -$1,050, reflecting the difference between the daily settlement price (5998) and the purchase price (6000), and so on:

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

### Friday 21 March 2025 5:30pm

If we move the **Effective** date to the maturity date we can see that the `FutureExpiryEvent` has removed the instrument holding and set the cash holding to $2,450, reflecting the difference between the final price (6005) and the purchase price (6000). This is the total realised gain:

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

### Auditing output transactions generated by instrument events

We can use **Portfolio Management > Transactions** in **Output** mode to call the [BuildTransactions](https://www.lusid.com/docs/api/lusid/endpoints/transaction-portfolios/BuildTransactions/) API with a suitable window to examine the output transactions generated by these instrument events:

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

To confirm the total realised gain/loss, click the **+/-** button at the end of the `FutureCashSettlement` row (highlighted in yellow below):

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