6.7 KiB
tags
| tags | |||||||
|---|---|---|---|---|---|---|---|
|
Trade Execution: Derived Financial Quantities and Fixed-Point Arithmetic
Try it live on Compiler Explorer{ .md-button }
Overview
This example models the execution of a buy order filled in multiple tranches and computes the average fill price (cost basis) at several settlement precisions. It demonstrates two ideas that do not appear in the currency example:
- Derived financial quantities —
notional_value(price × market quantity) is a separate quantity specification, distinct fromcurrency, enforced by the type system. - Integer fixed-point arithmetic — prices are scaled to
USD_8(units of $10⁻⁸) and stored asstd::int64_tto avoid floating-point rounding during accumulation.
Key Concepts
Derived Quantity Specifications: market_quantity and notional_value
In finance, notional value = price × market quantity. This is not the same quantity as currency: you cannot directly add a price to a notional value, and dividing notional value by market quantity should recover currency, not notional value. The example encodes this with derived quantity specifications:
--8<-- "example/trade_execution.cpp:44:52"
Both market_quantity and notional_value carry is_kind, making each the root of its
own kind family:
market_quantitywithis_kind— market quantity is its own kind, distinct from genericdimensionlessquantities (ratios, percentages, etc.). Without it, a market quantity would silently convert to a plain number.notional_valuewithis_kind— notional value is its own kind, distinct from currency. Without it, a notional value would silently convert to a plain currency amount, defeating the type safety the derived quantity is meant to provide.
is_kind on market_quantity disables implicit construction from plain integers, so a
Qty helper alias is provided: Qty(137) calls the quantity spec directly as a factory.
The relationship notional_value = currency × market_quantity is the defining
equation; explicit casts still work in both directions via that equation. The
static_asserts verify the intended semantics at compile time:
--8<-- "example/trade_execution.cpp:54:57"
Integer Fixed-Point Units
Floating-point arithmetic accumulates rounding error across many fills. Instead, prices are stored as integers in a fine-grained unit:
--8<-- "example/trade_execution.cpp:59:65"
USD_8 represents $10⁻⁸ (one hundred-millionth of a dollar). A price of $12.95
becomes 1,295,000,000 USD_8 — an exact integer. Multiplying by a market quantity
count gives an exact integer notional value. No floating-point arithmetic is involved
until the final display.
Type Aliases and the Fill Struct
--8<-- "example/trade_execution.cpp:77:85"
Price— aquantity_point(price has an absolute zero; $0 is meaningful)Shares— a dimensionless market quantity countNotional— the derived notional value inUSD_8Fill— groups a price and market quantity count together; the natural unit of trade data
Code Walkthrough
Computing Notional: force_in for Lossless Scaling
--8<-- "example/trade_execution.cpp:87:91"
force_in<std::int64_t>(us_dollar_8) converts the price unit from USD to USD_8
and changes the representation from double to std::int64_t in one step. The product
price_in_usd8 * f.qty yields a derived expression (currency × market quantity)
that is implicitly convertible to notional_value; the return converts it to
Notional.
Accumulating Fills
--8<-- "example/trade_execution.cpp:99:115"
Each fill is constructed with an explicit Price{...} (the constructor is explicit, so
direct initialization is required) and Qty(137) (the market_quantity spec called
directly as a factory, required because is_kind disables implicit construction from
plain integers). The accumulator variables total_notional and total_qty are
zero-initialized via copy initialization from {}. The notional_value quantity
specification ensures that adding two price quantities does not accidentally produce a
notional value — the // does not compile comment shows what the type system prevents.
Recovering the Average Fill Price
--8<-- "example/trade_execution.cpp:117:124"
currency(total_notional / total_qty) performs an explicit quantity cast to the
currency specification — without it, the type system sees
notional_value / market_quantity as an unreduced derived expression and round<USD_N>
cannot match it. The cast is required.
Rounding is then applied at four different settlement precisions so the output shows how much information is retained at each level.
Example Usage
--8<-- "example/trade_execution.cpp:95:135"
Sample Output:
Fills:
137 @ 12.95 USD (notional: 177415000000 USD_8)
126 @ 12.4 USD (notional: 156240000000 USD_8)
85 @ 12.7 USD (notional: 107950000000 USD_8)
Total: 348 shares, notional: 441605000000 USD_8
Cost basis (exact): 12.68979885 USD
Cost basis (USD_2): 12.69 USD
Cost basis (USD_4): 12.6898 USD
Cost basis (USD_6): 12.689799 USD
Cost basis (USD_8): 12.68979885 USD
The notional values are large integers in USD_8; the cost basis is recovered as a
human-readable USD value at varying precisions.
Why This Matters
- Derived Quantities: The
notional_valuespecification makes the price × market quantity algebra compile-time-safe — you cannot confuse a notional value with a price or a plain currency amount - Kind Safety:
is_kindon bothmarket_quantityandnotional_valueensures that market quantity and notional value do not silently decay to their parent kinds (dimensionlessand currency respectively) - Lossless Accumulation: Integer arithmetic in
USD_8avoids floating-point drift across many fills; only the final display converts to floating-point - Explicit Rounding: Rounding to a specific settlement precision (
USD_2,USD_4,USD_6,USD_8) is an explicit, visible operation — not hidden inside a helper - Domain Modeling: The
Fillstruct groups related quantities, andoperator<<provides domain-appropriate output (shares @ price)
Related Example
The currency example focuses on multi-currency type safety and FX conversion. This example focuses on single-currency arithmetic precision. Together they cover the two main concerns in financial quantity modelling.