Currency And Currency Spot Assets
Single currencies and currency spot pairs are separate asset concepts.
- Single currencies such as
USDandEURare canonicalAssetrows withasset_type="currency". - Currency spot pairs such as
EUR/USDare canonicalAssetrows withasset_type="currency_spot"plus aCurrencySpotAssetDetailsTabledetail row that links the pair to its base and quote currency assets.
+-----------------------------+ one-to-one extension +-----------------------------+
| AssetTable |-------------------------------->| CurrencySpotAssetDetailsTable |
|-----------------------------| asset_uid PK/FK |-----------------------------|
| uid PK | | asset_uid PK/FK |
| unique_identifier unique | | base_currency_uid FK |
| asset_type = currency_spot | | quote_currency_uid FK |
+-----------------------------+ +-----------------------------+
^ |
| |
+------------- base_currency_uid / quote_currency_uid -------+
Scope
Currency code metadata, such as USD -> US Dollar, is not part of the core
library. Keep that mapping in user code, a provider integration, or an
application-specific reference source.
Use CurrencySpot for tradable spot pair identity such as EUR/USD. The base
and quote currencies must already be Asset rows. This makes the component
currency identity explicit instead of hiding asset creation inside the spot-pair
workflow.
Do not add currency-specific columns to AssetTable. The core asset table owns
only stable identity fields. The relational base/quote relationship belongs to
CurrencySpotAssetDetailsTable.
API
Application code should use msm.api.assets.CurrencySpot for the pair workflow.
The API owns the multi-table pair write, so callers do not pass table handles or
repository contexts.
from msm.api.assets import Asset, CurrencySpot
from msm.constants import ASSET_TYPE_CURRENCY
USD = {"code": "USD", "currency_name": "US Dollar"}
EUR = {"code": "EUR", "currency_name": "Euro"}
usd = Asset.upsert(unique_identifier=USD["code"], asset_type=ASSET_TYPE_CURRENCY)
eur = Asset.upsert(unique_identifier=EUR["code"], asset_type=ASSET_TYPE_CURRENCY)
eur_usd = CurrencySpot.upsert(
unique_identifier="BBG0013HGRV5",
base_currency_uid=eur.uid,
quote_currency_uid=usd.uid,
)
CurrencySpot.upsert(...) performs these writes:
- upsert
AssetType(asset_type="currency_spot"); - upsert
Asset(unique_identifier=<pair>, asset_type="currency_spot"); - upsert
CurrencySpotAssetDetailsTable(asset_uid=<pair uid>, base_currency_uid=..., quote_currency_uid=...); - return a typed
CurrencySpotobject with the pair asset identity and base/quote currency references.
The current API requires base_currency_uid and quote_currency_uid; it does
not silently create those component assets from strings.
Asset Type Normalization
Typed asset APIs normalize asset type keys before writing them:
"Currency" -> "currency"
"Currency Spot" -> "currency_spot"
"Future" -> "future"
Friendly text belongs in AssetType.display_name and description, not in the
stored asset_type key.
Schema
CurrencySpotAssetDetailsTable is declared under msm.models.assets.currency_spot and is
exported through msm.models.
Key constraints:
asset_uidis both the primary key and a foreign key toAssetTable.uid.asset_uidcascades on delete because the detail row should not outlive the pair asset.base_currency_uidandquote_currency_uidrestrict deletion of component currency assets while pairs reference them.(base_currency_uid, quote_currency_uid)is unique in this first implementation.- the typed API rejects rows where base and quote are the same currency asset.
Registration
CurrencySpot.__required_tables__ declares the minimum dependency set in order:
AssetTypeTable
AssetTable
CurrencySpotAssetDetailsTable
Production code normally assumes these MetaTables already exist. Application startup can register the dependency set explicitly:
import msm
msm.start_engine(models=["AssetType", "Asset", "CurrencySpotAssetDetails"])
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/currency_spot_workflow.py for a workflow that registers
USD and EUR currency assets, resolves BBG0013HGRV5 through OpenFIGI,
creates the EUR/USD CurrencySpot, and writes an AssetSnapshot for the
currencies and the spot pair.