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:
- upsert
AssetType(asset_type="future"); - upsert
Asset(unique_identifier=<future>, asset_type="future"); - upsert
FutureAssetDetailsTable(asset_uid=<future uid>, ...); - return a typed
Futureobject 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;
PERPETUALfutures have noexpires_at;EXPIRINGfutures haveexpires_at;- positive
contract_size; - non-empty normalized
quote_unitandcontract_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.