Skip to content

Futures

Futures are tradable assets whose contract terms are stored in a derivative detail table.

In the current implementation, a future is a canonical Asset row with asset_type="future". The underlying is an IndexTable row, not another Asset. This avoids creating fake assets for indexes just to satisfy a foreign key. Use msm.constants.ASSET_TYPE_FUTURE when project code needs the stable asset type key.

+-----------------------------+        one-to-one extension     +-----------------------------+
| AssetTable                  |-------------------------------->| FutureAssetDetailsTable          |
|-----------------------------|        asset_uid PK/FK          |-----------------------------|
| uid                  PK     |                                 | asset_uid            PK/FK  |
| unique_identifier    unique |                                 | kind                        |
| asset_type = future         |                                 | underlying_index_uid FK     |
+-----------------------------+                                 | quote_unit                  |
                                                               | settlement_asset            |
                                                               | margin_asset                |
                                                               | settlement_model            |
                                                               | settlement_method           |
                                                               | contract_size               |
                                                               | contract_unit               |
                                                               | expires_at                  |
                                                               | settles_at                  |
                                                               | metadata                    |
                                                               +-----------------------------+
             +-----------------------------+
             | IndexTable                  |
             |-----------------------------|
             | uid                  PK     |
             | unique_identifier    unique |
             | display_name                |
             +-----------------------------+

API

Application code should use msm.api.derivatives.Future. The class owns the multi-table workflow, so callers do not pass MetaTable handles or repository contexts.

from decimal import Decimal

from msm.api.assets import Asset
from msm.api.derivatives import Future
from msm.api.indices import Index, IndexType
from msm.constants import (
    ASSET_TYPE_CURRENCY,
    INDEX_TYPE_EQUITY,
    INDEX_TYPE_EQUITY_DEFINITION,
)

IndexType.upsert(**INDEX_TYPE_EQUITY_DEFINITION.as_payload())
spx = Index.upsert(
    unique_identifier="SPX",
    index_type=INDEX_TYPE_EQUITY,
    display_name="S&P 500 Index",
    provider="example",
)
usd = Asset.upsert(unique_identifier="USD", asset_type=ASSET_TYPE_CURRENCY)

future = Future.upsert(
    unique_identifier="CME:ESZ6",
    kind="EXPIRING",
    underlying_index_uid=spx.uid,
    quote_unit="INDEX_POINT",
    settlement_asset=usd.uid,
    margin_asset=usd.uid,
    settlement_model="LINEAR",
    settlement_method="CASH",
    contract_size=Decimal("50"),
    contract_unit="INDEX_POINT",
    expires_at="2026-12-18T22:00:00Z",
    settles_at="2026-12-18T22:00:00Z",
    metadata={"venue": "CME", "root": "ES"},
)

Future.upsert(...) performs these writes:

  1. upsert AssetType(asset_type="future");
  2. upsert Asset(unique_identifier=<future>, asset_type="future");
  3. upsert FutureAssetDetailsTable(asset_uid=<future uid>, ...);
  4. return a typed Future object with the asset identity and contract terms.

OpenFIGI-backed workflows can resolve both the underlying index FIGI and the future FIGI while keeping contract economics explicit:

from decimal import Decimal

from msm.api.assets import Asset
from msm.api.indices import IndexType
from msm.constants import INDEX_TYPE_EQUITY, INDEX_TYPE_EQUITY_DEFINITION
from msm.services import register_index_future_from_figis

IndexType.upsert(**INDEX_TYPE_EQUITY_DEFINITION.as_payload())
usd = Asset.upsert(unique_identifier="USD", asset_type="currency")
future = register_index_future_from_figis(
    "BBG01SWCTHK4",
    underlying_index_figi="BBG000KKFC45",
    underlying_index_type=INDEX_TYPE_EQUITY,
    settlement_asset_uid=usd.uid,
    margin_asset_uid=usd.uid,
    kind="EXPIRING",
    quote_unit="INDEX_POINT",
    settlement_model="LINEAR",
    settlement_method="CASH",
    contract_size=Decimal("50"),
    contract_unit="INDEX_POINT",
    expires_at="2026-12-18T22:00:00Z",
    settles_at="2026-12-18T22:00:00Z",
)

The helper requires the underlying index OpenFIGI row to have marketSector="Index". It does not infer settlement asset, margin asset, contract size, or expiry from OpenFIGI.

See examples/msm/assets/derivatives/index_future_from_openfigi.py for the concrete workflow using index FIGI BBG000KKFC45 and future FIGI BBG01SWCTHK4.

Crypto or venue-native workflows do not need FIGIs. Create the local crypto and margin assets, create a local Index row for the underlying reference, and then upsert the Future against that index. Do not write OpenFigiDetails rows when the venue does not provide FIGIs.

See examples/msm/assets/derivatives/crypto_future_without_figi.py for a BTC/USDT perpetual future that uses only local identifiers.

Contract Fields

Field Meaning
kind PERPETUAL or EXPIRING.
underlying_index_uid IndexTable.uid of the underlying index.
quote_unit Unit used to quote price, such as USD, USDT, or INDEX_POINT.
settlement_asset Asset.uid of the asset used for settlement.
margin_asset Asset.uid of the asset posted as margin.
settlement_model LINEAR, INVERSE, QUANTO, or UNKNOWN.
settlement_method CASH, PHYSICAL, or UNKNOWN.
contract_size Positive size of one contract.
contract_unit Contract-size unit, such as INDEX_POINT or another venue-defined unit.
expires_at Required for EXPIRING, null for PERPETUAL.
settles_at Final settlement or delivery timestamp, nullable for perpetuals.
metadata JSON escape hatch for rare venue-specific attributes.

Validation

The typed API currently validates:

  • canonical enum values, accepting lower-case or mixed-case input;
  • PERPETUAL futures have no expires_at;
  • EXPIRING futures have expires_at;
  • positive contract_size;
  • non-empty normalized quote_unit and contract_unit.

The SQLAlchemy contract declares foreign keys for underlying_index_uid, settlement_asset, and margin_asset. Pre-write API checks that referenced rows exist are still tracked as an open ADR task.

Registration

Future.__required_tables__ declares the minimum dependency set in order:

AssetTypeTable
AssetTable
IndexTypeTable
IndexTable
FutureAssetDetailsTable

Production code normally assumes these MetaTables already exist and the catalog has been finalized by the SDK migration upgrade flow. Application startup can attach only this dependency set explicitly:

import msm

msm.start_engine(models=["AssetType", "Asset", "IndexType", "Index", "FutureAssetDetails"])

Examples and development scripts can set MSM_AUTO_REGISTER_NAMESPACE before importing the API classes when they need an example namespace, but they still must call msm.start_engine(...) during startup before row operations.

Boundaries

The current Future workflow is for index-underlying futures. Do not add nullable polymorphic columns for asset, rate, or other underlyings into FutureAssetDetailsTable. Add a later ADR when another underlying reference model exists.