Bond Assets
Bonds are canonical Asset rows with asset_type="bond" plus a one-to-one
BondAssetDetailsTable row for issuer, currency, lifecycle dates, and status.
Issuers are reference data, not assets. Use Issuer for the issuer row and
link the bond detail row to IssuerTable.uid.
+-----------------------------+ one-to-one extension +-----------------------------+
| AssetTable |-------------------------------->| BondAssetDetailsTable |
|-----------------------------| asset_uid PK/FK |-----------------------------|
| uid PK | | asset_uid PK/FK |
| unique_identifier unique | | issuer_uid FK |
| asset_type = bond | | currency_asset_uid FK |
+-----------------------------+ | issue_date |
^ | maturity_date |
| | status |
+------------------------ currency_asset_uid -------+-----------------------------+
issuer_uid
|
v
+-----------------------------+
| IssuerTable |
|-----------------------------|
| uid PK |
| unique_identifier unique |
| display_name |
+-----------------------------+
Scope
The bond extension stores minimal asset identity facts:
- who issued the bond;
- which currency asset denominates it;
- issue and maturity dates;
- lifecycle status.
It does not store coupons, schedules, day-count conventions, curves, accrued interest, or serialized pricing terms. Those belong in pricing or instrument contracts.
API
Application code should use msm.api.issuers.Issuer and
msm.api.assets.Bond.
import datetime as dt
from msm.api.assets import Asset, AssetType, Bond
from msm.api.issuers import Issuer
AssetType.upsert(asset_type="currency", display_name="Currency")
AssetType.upsert(asset_type="bond", display_name="Bond")
issuer = Issuer.upsert(
unique_identifier="example-issuer",
display_name="Example Issuer",
)
usd = Asset.upsert(unique_identifier="USD", asset_type="currency")
bond = Bond.upsert(
unique_identifier="example-usd-bond-2031",
issuer_uid=issuer.uid,
currency_asset_uid=usd.uid,
issue_date=dt.date(2026, 5, 27),
maturity_date=dt.date(2031, 5, 27),
status="ACTIVE",
)
Bond.upsert(...) performs these writes:
- verify
issuer_uidresolves to anIssuerTablerow; - verify
currency_asset_uidresolves to anAssetTablerow; - upsert
AssetType(asset_type="bond"); - upsert
Asset(unique_identifier=<bond>, asset_type="bond"); - upsert
BondAssetDetailsTable(asset_uid=<bond uid>, ...); - return a typed
Bondobject with the asset identity and detail fields.
Schema
IssuerTable is declared under msm.models.issuers.
| Field | Meaning |
|---|---|
uid |
Internal issuer row identity. |
unique_identifier |
Stable local or provider issuer identity. |
display_name |
Human-readable issuer name. |
metadata_json |
Optional provider-specific issuer attributes. |
BondAssetDetailsTable is declared under msm.models.assets.bonds.
| Field | Meaning |
|---|---|
asset_uid |
Primary key and foreign key to the canonical bond asset. |
issuer_uid |
Foreign key to IssuerTable.uid. |
currency_asset_uid |
Foreign key to the currency AssetTable.uid. |
issue_date |
Date the bond was issued. |
maturity_date |
Date the bond matures, nullable for perpetual bonds. |
status |
ACTIVE, MATURED, DEFAULTED, CALLED, REDEEMED, or UNKNOWN. |
asset_uid cascades on asset deletion because the detail row should not outlive
the bond asset. issuer_uid and currency_asset_uid restrict deletion while
bonds reference those rows.
Registration
Bond.__required_tables__ declares the minimum dependency set in order:
AssetTypeTable
AssetTable
IssuerTable
BondAssetDetailsTable
Production code normally assumes these MetaTables already exist. Application startup can register this dependency set explicitly:
import msm
msm.start_engine(models=["AssetType", "Asset", "Issuer", "BondAssetDetails"])
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.
Example
See examples/msm/assets/bond_workflow.py for a minimal workflow that creates an
issuer, a USD currency asset, and a USD bond using the user-facing API.
See examples/msm/assets/us_treasury_bond_workflow.py for a concrete US Treasury
example using:
- issuer
US_TREASURY; - CUSIP
91282CQQ7as the canonical bondAsset.unique_identifier; - FIGI
BBG0221YLR31inOpenFigiDetails; - inferred
issue_date=2026-05-15because the source provides10Ytenor andmaturity_date=2036-05-15; maturity_date=2036-05-15inBondAssetDetailsTable.
The Treasury example deliberately does not add coupon_rate or
maturity_tenor_at_issue to BondAssetDetailsTable. coupon_rate is a
pricing/instrument term, and tenor is a source/reference term. The example
preserves both in provider/raw metadata while keeping the canonical bond detail
schema minimal.