Multi-asset design#
The schema is designed for FX, crypto, bonds and equities. v1 implements and
seeds only one simulated FX pair (EURUSD).
Principle: a new asset class is added by adding rows and, at most, one subtype table. It never requires changing ``trades``, ``prices_eod``, ``pnl_eod`` or the risk tables. Those tables are deliberately asset-class-neutral.
How it works#
``instruments`` is a neutral core. Every instrument, whatever its class, has a unique
symbol, anasset_class, aquote_ccy(the currency its price, trades and P&L are denominated in) and aprice_multiplier. See Reference database (reference.db).Class-specific attributes live in a one-to-one subtype table keyed by
instrument_id(foreign key toinstruments, same database). FX’sbase_ccy,pip_sizeandlot_sizeare infx_instruments. This avoids a wide table full of nullable class-specific columns and lets each subtype carry its ownNOT NULLandCHECKrules.``price_multiplier`` absorbs differences in quoting convention. P&L per unit of quantity is
price difference * price_multiplier, and notional isquantity * price * price_multiplier. It is1.0for FX, crypto and equities, and0.01for bonds quoted in percent of par with quantity as face amount. It is positive byCHECK.``symbol`` is the system’s unique internal instrument code, not a vendor ticker. It is the cross-database key (trades, prices, P&L and risk all carry it), so it must be unique across asset classes and immutable. Vendor tickers, ISIN and FIGI belong in a separate identifiers table (below), because tickers collide across venues.
P&L carries its currency (``pnl_eod.ccy``), so positions in different currencies are never silently summed.
Mapping of the four asset classes#
FX |
Crypto |
Bond |
Equity |
|
|---|---|---|---|---|
|
|
|
|
|
Quantity means |
base-currency units |
base-asset units (fractional) |
face amount |
shares |
Price means |
quote currency per base unit |
quote asset per base unit |
clean price, percent of par |
currency per share |
|
1.0 |
1.0 |
0.01 |
1.0 |
|
quote currency |
quote asset (may be a stablecoin) |
bond currency |
listing currency |
Subtype table |
|
|
|
|
Needs beyond the core |
forwards and value-date points (later) |
trading fees; 24/7 market, so an explicit EOD cut-off (e.g. 00:00 UTC) |
coupon accrual and payments; clean vs dirty price (accrued interest) |
dividends and splits (corporate actions); adjusted price history |
(built) means implemented and tested. (designed) means specified here and added by migration when the first instrument of that class is introduced, so no empty tables exist before they are needed.
Recipe: adding an asset class#
Add the value to
AssetClassindomain/enums.py. TheCHECKoninstruments.asset_classis generated from the enum; ship a migration to update it.Create the subtype table (foreign key to
instruments.instrument_id).Insert the instrument rows with the right
quote_ccyandprice_multiplier.Load prices with an explicit
data_origin(see Market database (market.db)).Book trades as usual and run EOD. P&L and risk need no changes unless the class needs behaviour from the “Needs beyond the core” row.
If it does, add that behaviour in
domain/(pure and unit-tested) and any new table in the database that owns the data (next section).
This is exercised by tests (tests/test_multi_asset.py): a bond-style
instrument and a EUR-quoted equity are created with core rows only and run
through booking, P&L and risk.
What is not generic yet#
These are real gaps, listed so they are not mistaken for supported features.
Gap |
Owning database |
Planned table or change |
|---|---|---|
Fees and commissions on trades |
trade |
|
Coupons, dividends, other cash flows |
trade |
|
Splits, mergers, symbol changes |
market |
|
Vendor identifiers (ISIN, FIGI, ticker, venue) |
reference |
|
Currency conversion for P&L aggregation and USD notional and VaR |
market |
FX rates (e.g. via FX instruments’ own prices) and a reporting-currency setting |
Trading calendars and EOD cut-offs per instrument |
reference |
|
Accrued interest (dirty price) for bonds |
domain |
day-count-aware accrual in |
Until currency conversion exists, risk (USD notional, VaR, limits) refuses non-USD instruments with an explicit error rather than producing a wrong number. P&L works for any currency but is reported per currency.