Modelling exchange-traded futures and options in LUSID

Providing you are a LUSID user with sufficient access control permissions, you can create an instrument to model a futures contract or an options contract in the LUSID instrument master. You can then:

Note: If you are the LUSID domain owner, you are automatically assigned the built-in lusid-administrator role, which has all the permissions necessary to perform the operations in this article.

Note there is an accompanying Jupyter Notebook that demonstrates many of the operations and concepts in this article.

Creating an instrument

LUSID's instrument model is designed with reference to ISDA CDM and FpML. Exchange-traded futures and options are exchange-defined financial contracts that constitute an integral part of this instrument model.

To create an instrument modelling a futures contract, call the LUSID UpsertInstruments API and specify a definition with an instrumentType of Future and a suitable start date, maturity date, and definition for the underlying. Your FuturesContractDetails object should define characteristics for the contract itself. For more information on constructing a suitable economic definition, examine the API documentation and choose Future from the dropdown box:

Note: To create an instrument modelling an options contract, specify an instrumentType of ExchangeTradedOption and choose the same from the dropdown box above to see how to construct a suitable economic definition.

For example, providing you have a valid API access token, you could run the following command in your LUSID domain to create an instrument for a EURO BUND December 2021 futures contract on the Eurex exchange:

curl -X POST "https://<your-domain>.lusid.com/api/api/instruments"
   -H "Authorization: Bearer <your-API-access-token>"
   -H "Content-Type: application/json"
   -d '{"upsert-request-1": {
    "name": "EURO-BUND FUTURE Dec21",
    "identifiers": {
      "ClientInternal": {
        "value": "bund_dec21_future-identifier"
        }
      },
    "definition": {
      "instrumentType": "Future",
      "startDate": "2021-10-13T10:00:00.0000000+00:00",
      "maturityDate": "2021-12-13T10:00:00.0000000+00:00",
      "identifiers": {},
      "contractDetails": {
           "domCcy": "EUR",
           "contractCode": "FGBL",
           "contractMonth": "Z",
           "contractSize": 100000,
           "convention": "ActualActual",
           "country": "DE",
           "description": "Euro bund future Dec 21",
           "exchangeCode": "EUREX",
           "exchangeName": "Eurex",
           "tickerStep": 0.01,
           "unitValue": 10,
           },
      "contracts": 1,
      "refSpotPrice": 1,
      "underlying": {
           "instrumentType": "ExoticInstrument",
           "instrumentFormat": {
                "sourceSystem": "custom",
                "vendor": "custom",
                "version": "1.0"
                },
           "content": "{}"
           }
      }
  }
}'

Note the following:

  • The contractCode must be valid for the exchange.

  • To choose to realise daily P&L, set the refSpotPrice to 0.

Providing the request is valid, the response contains an automatically-generated LUID (a system ID, in this case LUID_00003D55) that is guaranteed to be unique and never change. You can use this LUID to reference the instrument in subsequent API calls:

{
    "values": {
        "upsert-request-1": {
            "href": "https://<your-domain>.lusid.com/api/api/instruments/LusidInstrumentId/LUID_00003D55",
            "lusidInstrumentId": "LUID_00003D55",
            "version": {
                "effectiveFrom": "0001-01-01T00:00:00.0000000+00:00",
                "asAtDate": "2021-11-02T08:43:21.2352320+00:00"
            },
            "name": "EURO-BUND FUTURE Dec21",
            "identifiers": {
                "ClientInternal": "bund_dec21_future-identifier",
                "LusidInstrumentId": "LUID_00003D55"
            },
            "properties": [],
            "instrumentDefinition": {
                "startDate": "2021-10-13T10:00:00.0000000+00:00",
                "maturityDate": "2021-12-13T10:00:00.0000000+00:00",
                "identifiers": {},
                "contractDetails": {
                    "domCcy": "EUR",
                    "contractCode": "FGBL",
                    "contractMonth": "Z",
                    "contractSize": 100000.0,
                    "convention": "ActualActual",
                    "country": "DE",
                    "description": "Euro bund future Dec 21",
                    "exchangeCode": "EUREX",
                    "exchangeName": "Eurex",
                    "tickerStep": 0.01,
                    "unitValue": 10.0
                },
                "contracts": 1.0,
                "refSpotPrice": 1.0,
                "underlying": {
                    "instrumentFormat": {
                        "sourceSystem": "custom",
                        "vendor": "custom",
                        "version": "1.0"
                    },
                    "content": "{}",
                    "instrumentType": "ExoticInstrument"
                },
                "instrumentType": "Future"
            },
            "state": "Active"
        }
    },
    ...
}

Booking a transaction to establish a position

Once the instrument is mastered, you can call the LUSID UpsertTransactions API to purchase a quantity of the futures contract for a particular portfolio, for example:

curl -X POST "https://<your-domain>.lusid.com/api/api/transactionportfolios/<scope>/<code>/transactions"
   -H "Authorization: Bearer <your-API-access-token>"
   -H "Content-Type: application/json"
   -d '[
      {
        "transactionId": "bund_future_purchase_001",
        "type": "StockIn",
        "instrumentIdentifiers": {
          "instrument/default/LusidInstrumentId": "LUID_00003D55"
        },
        "transactionDate": "2021-10-15T00:00:00.0000000+00:00",
        "settlementDate": "2021-10-16T00:00:00.0000000+00:00",
        "units": 10,
        "transactionPrice": {
          "price": 100,
          "type": "Price"
        },
        "totalConsideration": {
          "amount": 1000000,
          "currency": "EUR"
        },
        "transactionCurrency": "EUR",
        "properties": {},
        "counterpartyId": "",
        "source": ""
    }
]'

Note this transaction uses the default StockIn transaction type, but you could define your own custom transaction type to represent futures contract purchases if you wish, as demonstrated in section 3 of the accompanying Jupyter Notebook.

You can confirm your position at any time by calling the LUSID GetHoldings API with the appropriate LUID:

curl -X GET "https://<your-domain>.lusid.com/api/api/transactionportfolios/<scope>/<code>/holdings?filter=instrumentUid%20eq%20'LUID_00003D55'"
   -H "Authorization: Bearer <your-API-access-token>"

Valuing your position

To value your position, you must load suitable market data into LUSID and then create a valuation recipe. For demonstrations, see sections 4 and 5 of the accompanying Jupyter Notebook.

In your recipe, you can choose between two valuation models. Specify:

  • SimpleStatic to set the PV to duplicate the exposure calculation (Price x Quantity Held x Contract Size)

  • ConstantTimeValueOfMoney to set the PV to the unrealised gain (whether you choose to realise it daily or not).

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

Note: To choose this model, set refSpotPrice to 0 when creating the instrument, as demonstrated in section 2.2 of the accompanying Jupyter Notebook for the March 2022 Bund futures contract.

This means that the P&L is captured and booked into a cash instrument. As demonstrated in section 5.3 of the Jupyter Notebook, there is a second line item from Day 2 for the March 2022 Bund contract representing cumulative daily cash adjustments. This can be recorded as a total for the portfolio, for the futures contract itself, or for a particular strategy combination of futures. 

Note: We can automate this close out process for you by scheduling a daily job in your LUSID environment that books transactions to reset the future's cost basis and realise the gain or loss.

Cumulative P&L  model

This 'non-close out' model maintains P&L as unrealised.

Note: To choose this model, set refSpotPrice to 1 when creating the instrument, as demonstrated in section 2.1 of the accompanying Jupyter Notebook for the December 2021 Bund futures contract.

As demonstrated in section 5.3 of the Jupyter Notebook, the December 2021 Bund contract is shown as a single line entry. The PV column in the valuation tables shows the (lifetime) unrealised contract gain. You can opt to see the exposure calculation instead in the same field by changing the valuation model in the recipe.

Changing your position

You can call the LUSID UpsertTransactions API to change your position. In the following example, the default StockOut transaction type is used to register a sale of 2 units of the EURO BUND December 2021 futures contract:

curl -X POST "https://<your-domain>.lusid.com/api/api/transactionportfolios/<scope>/<code>/transactions"
   -H "Authorization: Bearer <your-API-access-token>"
   -H "Content-Type: application/json"
   -d '[
      {
        "transactionId": "bund_future_purchase_002",
        "type": "StockOut",
        "instrumentIdentifiers": {
          "instrument/default/LusidInstrumentId": "LUID_00003D55"
        },
        "transactionDate": "2021-10-21T00:00:00.0000000+00:00",
        "settlementDate": "2021-10-22T00:00:00.0000000+00:00",
        "units": 2,
        "transactionPrice": {
          "price": 104.5,
          "type": "Price"
        },
        "totalConsideration": {
          "amount": 204500,
          "currency": "EUR"
        },
        "transactionCurrency": "EUR",
        "properties": {},
        "counterpartyId": "",
        "source": ""
    }
]'

Monitoring the lifecycle of the instrument

An instrument representing a futures contract or an options 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. Options are almost always left unexpired and the position closed out, but you may choose to hold to expiry and take delivery of the cash or underlying, or even expire ahead of maturity.

You can monitor the contract in several ways:

This mitigates the risk of missing exercise dates or closing out of open positions.

When an instrument cashflow or maturity event occurs in LUSID, it's important to note two things: 

  1. The cashflows are assumed to have been paid but are not presently auto-generated as such. This means the instrument or cashflow from the instrument drops out of your valuation.
    We will shortly implement ‘automatic settlement’, so that you can choose to auto-generate the appropriate cashflow or instrument, link it to the contract or instrument in question, and upsert it to the portfolio.
    For now, this must be done manually, using either the Manage Cashflows dashboard in the LUSID web app, or by calling the LUSID GetUpsertablePortfolioCashFlows API, which returns imminent cashflows as upsertable DTOs ready to push into LUSID as transactions. If you’d like to track the position P&L of the instrument, you would need to upsert settlement amounts with the same strategy tag you used for the main position at the time of booking. When you view your PV, you can then group by strategy tag.

  2. An instrument cannot â€˜expire’ in LUSID; it is still available post-maturity, although the valuation is 0. If you set your holding to 0, it will no longer appear in reports unless you are deliberately backdating.

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