You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
trading_hours_per_day is a single process-wide number read from CONFIG, while instrument metadata already resolves per symbol — resolve_instrument(sym, CONFIG) branches per symbol on margin mode, integer units, borrow, and calendar (see helpers/instruments.py, added in #229).
Session length is the one instrument property that stayed global. A mixed book of equities (6.5h RTH) and 24h futures (CME_ETH) therefore gets the wrong bars-per-day for one side of the book no matter which value is configured.
Concretely, on 1-hour bars with trading_hours_per_day = 6.5, a 24h futures symbol gets bpd = 6 when its true session is 24 bars — a ~4× ADV understatement on that symbol, on top of #268's truncation error.
Severity
Pre-existing, out of scope for #265, and currently latent: it only bites once a single portfolio genuinely mixes asset classes with different session lengths. Filing it so it is tracked rather than rediscovered.
Design note / open question
This is the largest of the three #265 follow-ups because it changes a function signature that the annualization path also depends on. Proposed conservative shape:
Resolve session hours per symbol via the existing instrument layer (the Instrument already carries calendar), falling back to CONFIG["trading_hours_per_day"] when the instrument doesn't specify one.
Keep the existing global-config behaviour as the exact default so no current configuration changes behaviour.
Thread the per-symbol value through the ADV path first (where correctness impact is concrete and fix(engine): scale ADV liquidity-cap window to timeframe, not a fixed 20 bars #265 already isolated the call sites); treat the annualization path as a separate decision, since changing it retroactively alters reported Sharpe/CAGR on existing futures runs.
Open question for review: whether the annualization consumer (get_bars_per_year) should move per-symbol in the same change or stay global pending an explicit decision — it has reporting-comparability consequences that the ADV path does not.
Dependency
Overlaps get_bars_per_day() with #268. #268 should land first; this builds on the exact-bars-per-day helper it introduces.
Acceptance criteria
Per-symbol session length resolved via the instrument layer, global config as fallback
ADV path uses the per-symbol value
Existing single-asset-class configs byte-for-byte unchanged; golden master green
Test covering a mixed equity + 24h-futures book
Explicit decision recorded on the annualization path
Follow-up to #264 / #265, raised as a minor in @shardul0701's round-2 review of #265.
Problem
trading_hours_per_dayis a single process-wide number read fromCONFIG, while instrument metadata already resolves per symbol —resolve_instrument(sym, CONFIG)branches per symbol on margin mode, integer units, borrow, and calendar (seehelpers/instruments.py, added in #229).Session length is the one instrument property that stayed global. A mixed book of equities (6.5h RTH) and 24h futures (
CME_ETH) therefore gets the wrong bars-per-day for one side of the book no matter which value is configured.Consumers of the assumption:
helpers/timeframe_utils.py::get_bars_per_day()→ the ADV window + rescale from fix(engine): scale ADV liquidity-cap window to timeframe, not a fixed 20 bars #265 (max_pct_advliquidity cap,volume_impact_coeffmarket impact)helpers/timeframe_utils.py::get_bars_per_year()→ annualizationConcretely, on 1-hour bars with
trading_hours_per_day = 6.5, a 24h futures symbol getsbpd = 6when its true session is 24 bars — a ~4× ADV understatement on that symbol, on top of #268's truncation error.Severity
Pre-existing, out of scope for #265, and currently latent: it only bites once a single portfolio genuinely mixes asset classes with different session lengths. Filing it so it is tracked rather than rediscovered.
Design note / open question
This is the largest of the three #265 follow-ups because it changes a function signature that the annualization path also depends on. Proposed conservative shape:
Instrumentalready carriescalendar), falling back toCONFIG["trading_hours_per_day"]when the instrument doesn't specify one.Open question for review: whether the annualization consumer (
get_bars_per_year) should move per-symbol in the same change or stay global pending an explicit decision — it has reporting-comparability consequences that the ADV path does not.Dependency
Overlaps
get_bars_per_day()with #268. #268 should land first; this builds on the exact-bars-per-day helper it introduces.Acceptance criteria