Adds a generic build_bybit_sleeve_forward_nav(repo, store, sleeve, ...) builder in assets.py, refactors build_positioning_forward_nav to delegate to it, and moves xsfunding_nav off the standalone Binance XsFundingForward(BinanceXsFundingLive()) construction onto its own Bybit single-sleeve forward track (mirrors positioning exactly). xsfunding still runs unchanged as a sleeve inside the bybit_4edge deploy book (_DEFAULT_BYBIT_SLEEVES untouched). - bybit_forward_track.py: bybit_report_sid_kwargs() gains an xsfunding case. - cli.py: _BYBIT_BOOK_SIDS += "xsfunding" (routing only, series already computed). - registry.py: xsfunding -> venue bybit-perp, backtest.kind sleeve->report, params mirror positioning's shape, record_mode observed->recompute (required for the deterministic-engine recompute path; confirmed by the exhaustive observed-mode pin in test_forward_definition.py, updated accordingly). - migration_builders.py: replaced the xsfunding lambda:None stub (valid only under the old observed record_mode) with a real single-sleeve Bybit builder, mirroring positioning's, to avoid a latent crash if the one-time forward migration is ever re-run. Tests: new tests/unit/test_bybit_sleeve_forward_builder.py (TDD, brief-verbatim); full tests/unit + tests/integration sweep: 2056 passed, 0 failed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
35 lines
1.7 KiB
Python
35 lines
1.7 KiB
Python
from fxhnt.application.forward_definition import definition_hash, track_definition
|
|
from fxhnt.registry import STRATEGY_REGISTRY
|
|
|
|
|
|
def test_hash_is_stable_under_key_reordering():
|
|
assert definition_hash({"a": 1, "b": 2}, 1) == definition_hash({"b": 2, "a": 1}, 1)
|
|
|
|
|
|
def test_hash_changes_when_a_param_changes():
|
|
# the BTC-drop case: instruments 6 -> 5 must change the hash
|
|
six = definition_hash({"instruments": ["SPY", "IEF", "GLD", "PDBC", "DBMF", "BTC-USD"]}, 1)
|
|
five = definition_hash({"instruments": ["SPY", "IEF", "GLD", "PDBC", "DBMF"]}, 1)
|
|
assert six != five
|
|
|
|
|
|
def test_hash_changes_when_version_bumps():
|
|
assert definition_hash({"a": 1}, 1) != definition_hash({"a": 1}, 2)
|
|
|
|
|
|
def test_every_active_track_declares_a_definition():
|
|
for sid in STRATEGY_REGISTRY:
|
|
params, version, mode = track_definition(sid)
|
|
assert isinstance(params, dict) and isinstance(version, int)
|
|
assert mode in ("recompute", "observed")
|
|
|
|
|
|
def test_observed_mode_is_exactly_the_executed_twins():
|
|
# Pin is deliberately exhaustive: whenever a new track adopts record_mode="observed", update this set
|
|
# (C2 Task 3 added bybit_4edge_exec; Task 7 added vrp_exec) so the change is reviewed, not silently
|
|
# absorbed. `xsfunding` moved OFF observed (Phase 0b venue consolidation: standalone Binance
|
|
# `XsFundingForward` -> its own Bybit single-sleeve `recompute` track, mirroring `positioning`) — the
|
|
# remaining observed tracks are the OBSERVED-fills executed twins (fills are observed, not recomputable).
|
|
observed = {sid for sid in STRATEGY_REGISTRY if track_definition(sid)[2] == "observed"}
|
|
assert observed == {"multistrat_exec", "bybit_4edge_exec", "vrp_exec"}
|