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.

Modelling exchange-traded futures in LUSID

Prev Next

You can model an exchange-traded futures contract as an instrument of type Future in LUSID. See all supported instruments.

Note: See also this sister article on instrument events and this Jupyter Notebook implementation.

Mastering an instrument

There are numerous tools you can use to master an instrument of type Future in the LUSID Security Master.

Some fields are common to all types of instrument, such as an intuitive name, the requirement to specify a set of identifiers, and the facility to store extra information as properties.

Fields in the economic definition object are specific to Future. For more information on these fields, select Future from the definition dropdown in the UpsertInstruments API reference, or alternatively examine the Future schema:

For example, the following call to the UpsertInstruments API masters an E-mini S&P futures contract in a custom instrument scope using a ClientInternal unique identifier:

curl -X POST 'https://<your-domain>.lusid.com/api/api/instruments?scope=MyCustomInstrScope'
   -H 'Content-Type: application/json-patch+json'
   -H 'Authorization: Bearer <your-API-access-token>'
   -d '{"upsert-request-1": {
    "name": "E-mini S&P500 March 2025",
    "identifiers": {
      "ClientInternal": {
        "value": "EminiS&P500March2025"
        }
      },
    "definition": {
      "instrumentType": "Future",
      "startDate": "2024-09-21T00:00:00.0000000+00:00",
      "maturityDate": "2025-03-21T17:30:00.0000000+00:00",
      "identifiers": {},
      "contractDetails": {
        "domCcy": "USD",
        "contractCode": "ESH5",
        "contractMonth": "H",
        "contractSize": 50,
        "exchangeCode": "GLOBEX",
        "deliveryType": "Cash"
      },
      "contracts": 1,
      "markToMarketConventions": {
        calendarCode: "USD"
      },
      "refSpotPrice": 0,
    }
  }
}'

Note the following:

  • The instrumentType must be Future.

  • The nested definition.identifiers should be set to an empty object: {}.

  • The contractCode should be valid for the exchange.

  • The contracts field should be set to 1 and the amount bought or sold specified on the transaction.

  • The deliveryType defaults to Physical but should be set to Cash if you want to handle instrument events.

  • refSpotPrice should be 0 (or omitted, since this is the default) unless directed otherwise by FINBOURNE Technical Support.

Providing the request is successful, the response:

  • Confirms the globally-unique LUID for the instrument.

  • Generates extra fields that are stored as part of the instrument definition and can be filtered on.

  • Supplies default values for fields not explicitly specified in the request.

For more information on the calculationType field for use with ASX and Brazilian B3 bond futures, see the API reference documentation for that field.

{
  "values": {
    "upsert-request-1": {
      "href": "https://<your-domain>.lusid.com/api/api/instruments/LusidInstrumentId/LUID_00003E7V?scope=MyCustomInstrScope",
      "scope": "MyCustomInstrScope",
      "lusidInstrumentId": "LUID_00003E7V",
      "name": "E-mini S&P500 March 2025",
      "identifiers": {
        "LusidInstrumentId": "LUID_00003E7V",
        "ClientInternal": "EminiS&P500March2025"
      },
      "properties": [],
      "instrumentDefinition": {
        "startDate": "2024-09-21T00:00:00.0000000+00:00",
        "maturityDate": "2025-03-21T17:30:00.0000000+00:00",
        "identifiers": {},
        "contractDetails": {
          "domCcy": "USD",
          "assetClass": "Unknown",
          "contractCode": "ESH5",
          "contractMonth": "H",
          "contractSize": 50,
          "country": "",
          "description": "",
          "exchangeCode": "GLOBEX",
          "exchangeName": "",
          "tickerStep": 0,
          "unitValue": 0,
          "deliveryType": "Cash"
        },
        "contracts": 1,
        "markToMarketConventions": {
          calendarCode: "USD"
        },
        "refSpotPrice": 0,
        "calculationType": "Invalid",
        "tradingConventions": {
          "priceScaleFactor": 1,
          "minimumOrderSize": 0,
          "minimumOrderIncrement": 0
        },
        "instrumentType": "Future"
      },
      "state": "Active",
      "assetClass": "Unknown",
      "domCcy": "USD",
      "relationships": []
    }
  },
  ...
}

Booking a transaction to establish a position

Once an instrument is mastered, you can book a transaction to record the acquisition of a quantity in a particular transaction portfolio. For example, the following call to the BatchUpsertTransactions API acquires 10 contracts of an instrument identified by LUID:

curl -X POST 'https://<your-domain>.lusid.com/api/api/transactionportfolios/FixedIncome/UK/transactions/$batchUpsert?successMode=Partial&preserveProperties=true'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "transactionRequest-1": {
    "transactionId": "my_future_purchase_001",
    "type": "BuyFuture",
    "instrumentIdentifiers": {"Instrument/default/LusidInstrumentId": "LUID_00003E7V"},
    "transactionDate": "2024-09-25T09:00:00.0000000+00:00",
    "settlementDate": "2024-09-25T09: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,
            "unit": "USD"
          }
        }
      }
    }
  }
}'

Note the following:

  • The type field invokes a custom BuyFuture transaction type to confer a particular economic impact (see below).

  • The units field specifies the number of contracts.

  • The transactionPrice object records the market price. This is used by LUSID to automatically calculate gross consideration (see below).

  • The totalConsideration object:

    • Sets the settlement currency to USD.

    • Specifies a cost of 0 to enable LUSID to automatically derive total consideration (see below).

  • The cost of entering into the contract is recorded as a custom property.

Note: This example assumes the transaction, settlement and portfolio currencies are all the same. If not, you can specify exchange rates.

You might create a BuyFuture transaction type as follows:

curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/types/default/BuyFuture?scope=default'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer <your-API-access-token>'
  -d '{
  "aliases": [
    {
      "type": "BuyFuture",
      "description": "Transaction type for future purchases",
      "transactionClass": "Basic",
      "transactionRoles": "AllRoles",
      "isDefault": false
    }
  ],
  "movements": [
    {
      "name": "Increase units",
      "movementTypes": "StockMovement",
      "side": "NotionalPurchase",
      "direction": 1
    },
    {
      "name": "Decrease cash",
      "movementTypes": "CashCommitment",
      "side": "Side2",
      "direction": -1
    }
  ],
  "calculations": [
    {
      "type": "Txn:NotionalAmount"
    },
    {
      "type": "Txn:GrossConsideration"
    },
    {
      "type": "DeriveTotalConsideration",
      "formula": "Txn:GrossConsideration + Properties[Transaction/MyProperties/TradeCommission]"
    }
  ]
}'

Note the following:

  • The StockMovement references a NotionalPurchase custom side (see below).

  • The Txn:NotionalAmount transaction type calculation automatically calculates the notional amount and stores the result in the Transaction/default/NotionalAmount system property, for use in the NotionalPurchase custom side.

  • The Txn:GrossConsideration calculation sets the gross consideration to zero for transactions that increase a future position, and stores the result in the Transaction/default/GrossConsideration system property.

  • The DeriveTotalConsideration calculation calculates totalConsideration.amount according to the given formula, which in this case sums gross consideration and fees; this is the total cost of the transaction.

You might create a NotionalPurchase custom side as follows:

curl -X PUT 'https://<your-domain>.lusid.com/api/api/transactionconfiguration/sides/NotionalPurchase?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",
  "notional": "Transaction/default/NotionalAmount"
}'

Note this is the same as the built-in Side1 except:

  • The amount field is set to Txn:TotalConsideration instead of Txn:TradeAmount.

  • The notionalAmount field is set to the Transaction/default/NotionalAmount system property, to handle LUSID’s calculation of notional amount.

Confirming positions

You can call the GetHoldings API to see the impact of the transaction on security and cash holdings, for example using the LUSID web app:

Auditing LUSID’s transaction type calculations

You can call the BuildTransactions API to audit LUSID’s notional amount, gross consideration and total consideration calculations, for example using the LUSID web app in Output mode:

Valuing your position

To value your position, work through our valuation checklist.

Note: The default pricing model is SimpleStatic. We recommend changing it to ConstantTimeValueOfMoney. See how to do this.

Pricing model

Status

Notes

ConstantTimeValueOfMoney

Available

Recommended. Sets the PV to the unrealised gain whether you choose to realise it daily or not (see below).

SimpleStatic

Available

Calculates market value according to the formula quantity held * contract size * scaled price.

Assessing risk

For more on how LUSID calculates exposure, see this article.

LUSID supports both analytic and bump and valuation mechanisms for assessing risk; contact Technical Support if you need more information.

Managing P&L on a daily basis

You can choose between two models for managing P&L in a futures contract.

Mark to market model

This 'close out' mark to market model realises each day’s P&L by booking it as a cash amount and resetting the future’s cost price to today’s close (so the P&L is now 0). You can automate this process by handling the FutureMarkToMarketEvent instrument event (see below).

Cumulative P&L model

This 'non-close out' model maintains P&L as unrealised. The PV shows the lifetime unrealised gain/loss.

Monitoring the lifecycle of the instrument

An instrument representing a futures contract has a maturity date specified when you create that instrument.

As the instrument nears expiry, there are decisions to be made. Futures are almost always closed before last trade date, but you may choose to hold to maturity and take delivery of the underlying.

Note: An instrument cannot ‘expire’ in LUSID; it is still available post-maturity, although the valuation is zero. If you set your holding to zero it no longer appears in reports unless you are deliberately backdating.

Handling automatic lifecycle events

A cash-settled Future instrument is tightly integrated into LUSID’s instrument event framework. To enable this for your domain, you must:

  1. Register a recipe with every portfolio holding a Future.

  2. Create transaction types to determine the economic impact of the transactions automatically generated by Futureevents.

For much more information, see how to handle instrument events. Note that a physically-settled Future instrument does not support instrument events.

Instrument event

Event emission criteria

FutureMarkToMarketEvent

This event is automatically emitted each weekday at the time specified in the instrument definition, providing suitable market data can be found.

One transaction for a cash amount reflecting the daily gain/loss.

FutureExpiryEvent

This event is automatically emitted on the maturity date at the time specified in the instrument definition, providing suitable market data can be found.

One transaction that simultaneously reduces the holding in the Future instrument to zero and realises the final daily cash gain/loss.

Manually loading daily and final settlement transactions

If you do not want to turn on automatic instrument lifecycle events you can continue to monitor upcoming cashflows using Dashboards > CashLadder in the LUSID web app, or by calling the GetPortfolioCashLadder API directly.

You can call the GetUpsertablePortfolioCashFlows API to  return imminent cashflows as upsertable DTOs ready to manually load into LUSID as input transactions.

Note: We do not currently handle cheapest-to-deliver methods. Calendar rolls are booked as separate sells/buys.