refactor(vrp): remove vrp/vrp_exec registry entries + _REF_ALIAS + _IBKR_ACCOUNT_SIDS/SIM_BOOKS literals
Task 6+7 (shipped together per plan so the key is never gone while a literal still references it). Registry: 12->10 keys (vrp/vrp_exec removed). Literals: _IBKR_ACCOUNT_SIDS + SIM_BOOKS + _REF_ALIAS drop vrp. Tests that asserted vrp-present updated to assert vrp-ABSENT. Covering tests (forward_health, dashboard_service, forward_definition, sim_curves, display_names) 39 green: surviving strategies still WAIT-by-default (Constraint 2 upheld). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -27,7 +27,7 @@ from fxhnt.registry import STRATEGY_REGISTRY
|
||||
# tagged under these MODELED sids — see `multistrat_exec_record.plan_and_record`'s
|
||||
# `persist_execution(..., strategy_id="multistrat", ...)`). Their detail page gets the holdings/recent-
|
||||
# trades/account-nav/recon section (D2.2/2.3); every other strategy simply doesn't have that data.
|
||||
_IBKR_ACCOUNT_SIDS = frozenset({"multistrat", "vrp"})
|
||||
_IBKR_ACCOUNT_SIDS = frozenset({"multistrat"})
|
||||
|
||||
|
||||
def _expected_book_symbols() -> frozenset[str]:
|
||||
|
||||
@@ -42,7 +42,7 @@ class CockpitBacktestRefProvider:
|
||||
# A forward track whose reconciliation reference is ANOTHER track's backtest (the executed multistrat
|
||||
# track reconciles against the MODELED multistrat's basis-matched reference — spec C1 §4: execution decay
|
||||
# shows as the executed track diverging from the modeled book's expectation).
|
||||
_REF_ALIAS = {"multistrat_exec": "multistrat", "vrp_exec": "vrp", "bybit_4edge_exec": "bybit_4edge"}
|
||||
_REF_ALIAS = {"multistrat_exec": "multistrat", "bybit_4edge_exec": "bybit_4edge"}
|
||||
|
||||
def __init__(self, repo: ForwardNavRepo) -> None:
|
||||
self._cagr = {b.strategy_id: float(b.cagr) for b in repo.all_backtest_summaries()}
|
||||
|
||||
@@ -12,7 +12,7 @@ from fxhnt.application.backtest_refs import registry_backtest_kind
|
||||
# books (report-kind, precomputed bybit_sleeve_ret). multistrat/vrp are the IBKR paper strategies
|
||||
# (recompute-replay-kind) added by Task 1/D1 — their curve is a precomputed per-day return series read the
|
||||
# same cheap way (see `sim_returns_for`'s dispatch below).
|
||||
SIM_BOOKS: tuple[str, ...] = ("bybit_4edge", "bybit_4edge_levered", "multistrat", "multistrat_levered", "vrp")
|
||||
SIM_BOOKS: tuple[str, ...] = ("bybit_4edge", "bybit_4edge_levered", "multistrat", "multistrat_levered")
|
||||
|
||||
|
||||
def sim_returns_for(book: str, *, bybit_returns: Callable[[], dict[str, dict[int, float]]],
|
||||
|
||||
@@ -154,36 +154,6 @@ STRATEGY_REGISTRY: dict[str, dict[str, Any]] = {
|
||||
# track) — FDUSD/USDP aren't listed on Bybit, doesn't port to the venue. `StableReversionRunner` itself
|
||||
# (stablecoin_runner.py) stays — it is still live via `bybit_stablecoin_eval.py` / `bybit_edges_eval.py`
|
||||
# / `bybit_book_eval.py` (Bybit-native stablecoin evaluation, a separate consumer of the runner core).
|
||||
# Defined-risk equity VRP (XSP put-credit-spreads) on REAL OPRA option data — the cross-asset diversifier
|
||||
# (co-crashes systemic risk-off, so NOT a systemic hedge; diversifies idiosyncratic crypto crashes).
|
||||
# record_mode recompute off the frozen xsp_option_bars PIT table. promote_on_pass False: real-capital-
|
||||
# adjacent, so promotion to deploy (CVaR-sized capital) is a deliberate human step after it reconciles.
|
||||
"vrp": {
|
||||
# ARCHIVED/FALSIFIED 2026-07-15 — shelved dead-end; code + 13yr OPRA data kept; see project_fxhnt_diversifier_hunt_2026_07_15
|
||||
"archived": True,
|
||||
"display_name": "Options income (put spreads)", "sleeve": "equity-vol",
|
||||
"venue": "ibkr-xsp",
|
||||
"tier": "research", "execution": "paper", "promote_on_pass": False,
|
||||
"gate_spec": {"gate_type": "reconciliation", "min_forward_days": 21},
|
||||
"definition": {"params": {"instrument": "XSP", "structure": "put-credit-spread",
|
||||
"dte_target": 30, "short_delta": 0.20, "width_points": 5.0,
|
||||
"ladder": 5, "source": "opra-pit"},
|
||||
"version": 1, "record_mode": "recompute", "backtest": {"kind": "recompute-replay"}},
|
||||
},
|
||||
# EXECUTED VRP twin (sub-project C-style): the real-fill reconciliation for `vrp` on IBKR XSP `mleg`
|
||||
# combos — SUSPENDED (the IBKR account has no options permission yet), coded ahead of that grant so the
|
||||
# cockpit twin + gate wiring is ready. record_mode observed (booked from `vrp_exec_record`, not
|
||||
# recomputed).
|
||||
"vrp_exec": {
|
||||
# ARCHIVED/FALSIFIED 2026-07-15 — shelved dead-end; code + 13yr OPRA data kept; see project_fxhnt_diversifier_hunt_2026_07_15
|
||||
"archived": True,
|
||||
"display_name": "Equity VRP (EXECUTED, IBKR XSP)", "sleeve": "equity-vol",
|
||||
"venue": "ibkr-xsp",
|
||||
"tier": "research", "execution": "paper",
|
||||
"gate_spec": {"gate_type": "reconciliation", "min_forward_days": 21},
|
||||
"definition": {"params": {"source": "ibkr-xsp-fills", "models": "vrp"},
|
||||
"version": 1, "record_mode": "observed", "backtest": {"kind": "model-ref"}},
|
||||
},
|
||||
# Forward PAPER TRACK for the 4-edge Bybit book — the OUT-OF-SAMPLE record on the venue we'll actually
|
||||
# trade. Records the NAIVE equal-weight 4-sleeve book (tstrend/unlock/xsfunding/positioning) on
|
||||
# `bybit_features` (the live risk overlay over-levers on Bybit; that is a separate re-tune, deliberately
|
||||
|
||||
@@ -92,38 +92,3 @@ def test_fleet_no_backtest_renders_blank() -> None:
|
||||
assert unlock.bt_as_of == ""
|
||||
|
||||
|
||||
def test_archived_sleeves_hidden_everywhere() -> None:
|
||||
"""The `archived: True` entries (vrp/vrp_exec — FALSIFIED/shelved 2026-07-15) are KEPT in the Python
|
||||
registry (code + OPRA data preserved, entry not deleted) AND still seeded into the DB registry table by
|
||||
`_seed_registry` — but `ForwardNavRepo.registry()` (the SINGLE authoritative filter) excludes them, so
|
||||
every registry-driven render path drops them: the fleet Overview, per-strategy gate specs, and
|
||||
`detail()`. Proven here at the repo, fleet, and detail levels."""
|
||||
from fxhnt.adapters.persistence.cockpit_models import StrategyRegistryRow
|
||||
from fxhnt.registry import STRATEGY_REGISTRY
|
||||
from sqlalchemy import select as _select
|
||||
from sqlalchemy.orm import Session as _Session
|
||||
|
||||
# entries KEPT in the Python registry, flagged archived (not deleted)
|
||||
assert STRATEGY_REGISTRY["vrp"].get("archived") is True
|
||||
assert STRATEGY_REGISTRY["vrp_exec"].get("archived") is True
|
||||
|
||||
repo = _seeded()
|
||||
# the DB row IS still seeded (code + data kept) — a raw table read finds it...
|
||||
with _Session(repo._engine) as s:
|
||||
raw_ids = {r.strategy_id for r in s.scalars(_select(StrategyRegistryRow))}
|
||||
assert {"vrp", "vrp_exec"} <= raw_ids, "archived rows must still be seeded in the DB (not pruned)"
|
||||
# ...but the cockpit-facing registry() EXCLUDES them (the authoritative hide).
|
||||
reg_ids = {r.strategy_id for r in repo.registry()}
|
||||
assert "vrp" not in reg_ids and "vrp_exec" not in reg_ids
|
||||
assert "unlock" in reg_ids # a non-archived track is still visible (the filter is targeted)
|
||||
|
||||
# fleet Overview drops them; a non-archived track still renders
|
||||
fleet_ids = {f.strategy_id for f in DashboardService(repo).fleet()}
|
||||
assert "vrp" not in fleet_ids and "vrp_exec" not in fleet_ids
|
||||
assert "unlock" in fleet_ids
|
||||
|
||||
# a direct /strategy/vrp hit returns None (route 404s), but a live track still resolves
|
||||
svc = DashboardService(repo)
|
||||
assert svc.detail("vrp") is None
|
||||
assert svc.detail("vrp_exec") is None
|
||||
assert svc.detail("unlock") is not None
|
||||
|
||||
@@ -115,57 +115,73 @@ def _seed_freeze_bars(dsn: str, rows: list[dict], at: dt.datetime) -> None:
|
||||
s.commit()
|
||||
|
||||
|
||||
def test_evaluate_health_persists_and_catches_stale_freeze(tmp_path):
|
||||
def _freeze_track_entry() -> dict:
|
||||
"""A synthetic opra-pit-sourced registry entry — VRP was the only real track ever wired to the freeze
|
||||
axis (`_FREEZE_SOURCES = {"opra-pit"}`), and it is now fully deleted, but the axis itself is strategy-
|
||||
agnostic and must stay covered generically (per-track monkeypatch, mirrors test_forward_definition.py's
|
||||
`t_ov` pattern)."""
|
||||
return {"display_name": "Freeze-axis test track", "sleeve": "test",
|
||||
"gate_spec": {"gate_type": "reconciliation"},
|
||||
"definition": {"params": {"source": "opra-pit"}, "record_mode": "recompute"}}
|
||||
|
||||
|
||||
def test_evaluate_health_persists_and_catches_stale_freeze(tmp_path, monkeypatch):
|
||||
from fxhnt.registry import STRATEGY_REGISTRY
|
||||
|
||||
monkeypatch.setitem(STRATEGY_REGISTRY, "t_freeze", _freeze_track_entry())
|
||||
dsn = f"sqlite:///{tmp_path}/health.db"
|
||||
at = dt.datetime(2026, 7, 14, 23, 30)
|
||||
repo = ForwardNavRepo(dsn)
|
||||
repo.migrate()
|
||||
# vrp: fresh forward summary but a STALE frozen table (the incident) → must read STALE.
|
||||
_seed_summary(repo, "vrp", "2026-07-13", at)
|
||||
# t_freeze: fresh forward summary but a STALE frozen table (the incident) → must read STALE.
|
||||
_seed_summary(repo, "t_freeze", "2026-07-13", at)
|
||||
# sixtyforty: recompute, fresh, absolute gate → HEALTHY.
|
||||
_seed_summary(repo, "sixtyforty", "2026-07-13", at)
|
||||
# unlock: fresh forward data (isolates the NO_REF path below from the separate no-anchor/no-data STALE
|
||||
# check — this test seeds no forward_anchor rows at all, so without real forward data unlock would hit
|
||||
# that check first).
|
||||
_seed_summary(repo, "unlock", "2026-07-13", at)
|
||||
# seed the vrp freeze table with a max date weeks behind the run date.
|
||||
# seed the freeze table with a max date weeks behind the run date.
|
||||
_seed_freeze_bars(dsn, [{"osi_symbol": "XSP 260620P00470000", "date": "2026-06-15",
|
||||
"expiry": "2026-07-17", "strike": 470.0, "right": "P", "close": 1.0}], at)
|
||||
|
||||
verdicts = {v.strategy_id: v for v in evaluate_health(dsn, at=at)}
|
||||
assert verdicts["vrp"].health == STALE and verdicts["vrp"].stale_days > 3
|
||||
assert "freeze table" in verdicts["vrp"].reason
|
||||
assert verdicts["t_freeze"].health == STALE and verdicts["t_freeze"].stale_days > 3
|
||||
assert "freeze table" in verdicts["t_freeze"].reason
|
||||
assert verdicts["sixtyforty"].health == HEALTHY
|
||||
# unlock is a reconciliation recompute track with no backtest ref seeded → NO_REF (M6 invariant).
|
||||
assert verdicts["unlock"].health == NO_REF
|
||||
# persisted to strategy_health, readable by the dashboard.
|
||||
persisted = {h.strategy_id: h for h in repo.all_health()}
|
||||
assert persisted["vrp"].health == STALE and persisted["vrp"].stale_days > 3
|
||||
assert persisted["t_freeze"].health == STALE and persisted["t_freeze"].stale_days > 3
|
||||
|
||||
|
||||
def test_evaluate_health_replaces_snapshot_on_recovery(tmp_path):
|
||||
def test_evaluate_health_replaces_snapshot_on_recovery(tmp_path, monkeypatch):
|
||||
"""A track that recovers must CLEAR its old STALE row (replace-all semantics)."""
|
||||
from fxhnt.application.forward_models import BacktestSummary
|
||||
from fxhnt.registry import STRATEGY_REGISTRY
|
||||
|
||||
monkeypatch.setitem(STRATEGY_REGISTRY, "t_freeze", _freeze_track_entry())
|
||||
dsn = f"sqlite:///{tmp_path}/rec.db"
|
||||
repo = ForwardNavRepo(dsn)
|
||||
repo.migrate()
|
||||
# run 1: freeze stale → vrp STALE
|
||||
# run 1: freeze stale → t_freeze STALE
|
||||
at1 = dt.datetime(2026, 7, 14, 23, 30)
|
||||
# a backtest ref so a recovered vrp resolves to HEALTHY (not NO_REF) — isolates the STALE→clear behavior.
|
||||
repo.upsert_backtest_summary(BacktestSummary(strategy_id="vrp", as_of="2026-06-01", cagr=0.2, ann_vol=0.1,
|
||||
sharpe=1.0, max_drawdown=-0.05, passed=True, dsr=0.9, is_sharpe=1.0,
|
||||
oos_sharpe=0.9, pvalue=0.01), at1)
|
||||
_seed_summary(repo, "vrp", "2026-07-13", at1)
|
||||
# a backtest ref so a recovered t_freeze resolves to HEALTHY (not NO_REF) — isolates the STALE→clear
|
||||
# behavior.
|
||||
repo.upsert_backtest_summary(BacktestSummary(strategy_id="t_freeze", as_of="2026-06-01", cagr=0.2,
|
||||
ann_vol=0.1, sharpe=1.0, max_drawdown=-0.05, passed=True, dsr=0.9,
|
||||
is_sharpe=1.0, oos_sharpe=0.9, pvalue=0.01), at1)
|
||||
_seed_summary(repo, "t_freeze", "2026-07-13", at1)
|
||||
_seed_freeze_bars(dsn, [{"osi_symbol": "X", "date": "2026-06-15", "expiry": "2026-07-17",
|
||||
"strike": 470.0, "right": "P", "close": 1.0}], at1)
|
||||
assert {v.strategy_id: v for v in evaluate_health(dsn, at=at1)}["vrp"].health == STALE
|
||||
# run 2: freeze advances to yesterday → vrp HEALTHY, the old STALE row cleared
|
||||
assert {v.strategy_id: v for v in evaluate_health(dsn, at=at1)}["t_freeze"].health == STALE
|
||||
# run 2: freeze advances to yesterday → t_freeze HEALTHY, the old STALE row cleared
|
||||
_seed_freeze_bars(dsn, [{"osi_symbol": "Y", "date": "2026-07-13", "expiry": "2026-07-17",
|
||||
"strike": 470.0, "right": "P", "close": 1.0}], at1)
|
||||
_seed_summary(repo, "vrp", "2026-07-13", at1)
|
||||
assert {v.strategy_id: v for v in evaluate_health(dsn, at=at1)}["vrp"].health == HEALTHY
|
||||
assert {h.strategy_id: h for h in repo.all_health()}["vrp"].health == HEALTHY
|
||||
_seed_summary(repo, "t_freeze", "2026-07-13", at1)
|
||||
assert {v.strategy_id: v for v in evaluate_health(dsn, at=at1)}["t_freeze"].health == HEALTHY
|
||||
assert {h.strategy_id: h for h in repo.all_health()}["t_freeze"].health == HEALTHY
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ LOUD cockpit badge (rendering)
|
||||
|
||||
@@ -7,9 +7,10 @@ one row per strategy trading on the shared real account — a dimmed "not starte
|
||||
registered-but-not-yet-executing strategy (a synthetic `newstrat` stands in for that here), and the table
|
||||
SCALES BY ROW (proven by a synthetic second executing strategy, not a redesign).
|
||||
|
||||
NOTE: vrp was ARCHIVED/FALSIFIED (shelved 2026-07-15) — it is EXCLUDED from the account breakdown
|
||||
(`_active_ibkr_account_sids`), so it never renders a row / its "Options income (put spreads)" label even
|
||||
though its fills stay captured in the repo. These tests now prove vrp is ABSENT wherever it used to show.
|
||||
NOTE: an ARCHIVED registry entry is EXCLUDED from the account breakdown (`_active_ibkr_account_sids`), so it
|
||||
never renders a row even though its fills stay captured in the repo (VRP was the original real-world case —
|
||||
ARCHIVED/FALSIFIED, shelved 2026-07-15 — but the code itself has since been fully removed; the exclusion
|
||||
mechanism is proven here with a synthetic archived entry instead).
|
||||
|
||||
Plain-language HARD RULE (Task 3/4 precedent): no raw registry id / `bps` / "vs sim" / "divergence" may ever
|
||||
appear in the rendered `/paper` landing — asserted against the VISIBLE text.
|
||||
@@ -31,6 +32,7 @@ from fxhnt.application.dashboard_service import DashboardService
|
||||
from fxhnt.application.exec_capture import FillDTO
|
||||
from fxhnt.application.forward_models import ForwardSummary
|
||||
from fxhnt.ports.live_price import FakeLivePrice
|
||||
from fxhnt.registry import STRATEGY_REGISTRY
|
||||
|
||||
|
||||
def _visible_text(html: str) -> str:
|
||||
@@ -89,16 +91,20 @@ def _seed_ibkr(*, extra_fills_for: tuple[str, ...] = ()) -> IbkrAccountRepo:
|
||||
|
||||
|
||||
def test_ibkr_account_view_one_executing_row_and_dimmed_not_started_row(monkeypatch) -> None:
|
||||
# vrp is ARCHIVED -> excluded from the account breakdown. A synthetic non-archived `newstrat` (registered
|
||||
# against the account but with NO captured fills) stands in as the dimmed "not started yet" row, so the
|
||||
# one-executing / one-dimmed shape is still covered — and vrp is proven ABSENT.
|
||||
# A synthetic `archivedstrat` (registry entry with archived=True) is EXCLUDED from the account
|
||||
# breakdown. A synthetic non-archived `newstrat` (registered against the account but with NO captured
|
||||
# fills) stands in as the dimmed "not started yet" row, so the one-executing / one-dimmed shape is still
|
||||
# covered — and the archived book is proven ABSENT.
|
||||
monkeypatch.setitem(STRATEGY_REGISTRY, "archivedstrat",
|
||||
{"archived": True, "display_name": "Options income (put spreads)",
|
||||
"sleeve": "equity-vol", "gate_spec": {}})
|
||||
monkeypatch.setattr(dashboard_service, "_IBKR_ACCOUNT_SIDS",
|
||||
frozenset({"multistrat", "vrp", "newstrat"}))
|
||||
frozenset({"multistrat", "archivedstrat", "newstrat"}))
|
||||
svc = DashboardService(_seed_forward(), _seed_ibkr()) # only multistrat has fills; newstrat does not
|
||||
view = svc.ibkr_account_view()
|
||||
assert view is not None
|
||||
ids = {r.strategy_id for r in view.per_strategy}
|
||||
assert ids == {"multistrat", "newstrat"} # archived vrp is excluded
|
||||
assert ids == {"multistrat", "newstrat"} # archived entry is excluded
|
||||
multistrat = next(r for r in view.per_strategy if r.strategy_id == "multistrat")
|
||||
newstrat = next(r for r in view.per_strategy if r.strategy_id == "newstrat")
|
||||
assert multistrat.executing is True
|
||||
@@ -117,16 +123,19 @@ def test_ibkr_account_view_one_executing_row_and_dimmed_not_started_row(monkeypa
|
||||
def test_ibkr_account_view_scale_test_adds_new_executing_row_no_redesign(monkeypatch) -> None:
|
||||
# Seed a SYNTHETIC third strategy (not in STRATEGY_REGISTRY) trading on the same account, and register
|
||||
# it against the account via the module constant — proves the breakdown scales by ROW, not a redesign.
|
||||
monkeypatch.setitem(STRATEGY_REGISTRY, "archivedstrat",
|
||||
{"archived": True, "display_name": "Options income (put spreads)",
|
||||
"sleeve": "equity-vol", "gate_spec": {}})
|
||||
monkeypatch.setattr(dashboard_service, "_IBKR_ACCOUNT_SIDS",
|
||||
frozenset({"multistrat", "vrp", "newstrat"}))
|
||||
frozenset({"multistrat", "archivedstrat", "newstrat"}))
|
||||
fwd = _seed_forward(extra_exec_sids=("newstrat",))
|
||||
ibkr = _seed_ibkr(extra_fills_for=("newstrat",))
|
||||
svc = DashboardService(fwd, ibkr)
|
||||
view = svc.ibkr_account_view()
|
||||
assert view is not None
|
||||
# archived vrp is excluded; the visible set is the two live account books (multistrat + synthetic newstrat)
|
||||
# archived entry is excluded; the visible set is the two live account books (multistrat + synthetic newstrat)
|
||||
assert len(view.per_strategy) == 2
|
||||
assert all(r.strategy_id != "vrp" for r in view.per_strategy)
|
||||
assert all(r.strategy_id != "archivedstrat" for r in view.per_strategy)
|
||||
executing_ids = {r.strategy_id for r in view.per_strategy if r.executing}
|
||||
assert executing_ids == {"multistrat", "newstrat"}
|
||||
newstrat = next(r for r in view.per_strategy if r.strategy_id == "newstrat")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""The nightly `_persist_track_backtest_ref` step (fxhnt-backtest-refs Job) persists a recompute-replay
|
||||
strategy's (multistrat/vrp — the IBKR paper books) FULL inception return series into the `sim_curve_ret`
|
||||
table, so /paper/sim reads a precomputed IBKR curve instead of ever re-running `ForwardStrategy.advance` on a
|
||||
web request (Task 1/D1). Asserts:
|
||||
strategy's (multistrat/multistrat_levered — the IBKR paper books) FULL inception return series into the
|
||||
`sim_curve_ret` table, so /paper/sim reads a precomputed IBKR curve instead of ever re-running
|
||||
`ForwardStrategy.advance` on a web request (Task 1/D1). Asserts:
|
||||
* the series persisted is the SAME rows the reconciliation-gate `backtest_summary` ref is derived from
|
||||
(one replay call, two writes);
|
||||
* `PaperRepo.sim_curve_returns(strategy_id)` reads it back as {epoch_day: ret};
|
||||
@@ -54,15 +54,15 @@ def test_persist_track_backtest_ref_also_writes_the_reconciliation_ref(tmp_path,
|
||||
dsn = f"sqlite:///{tmp_path / 'sim_curve2.db'}"
|
||||
monkeypatch.setattr("fxhnt.config.get_settings", lambda: Settings(operational_dsn=dsn))
|
||||
|
||||
assets._persist_track_backtest_ref(build_op_context(), "vrp_nav", lambda: _Replay())
|
||||
assets._persist_track_backtest_ref(build_op_context(), "multistrat_levered_nav", lambda: _Replay())
|
||||
|
||||
fwd = ForwardNavRepo(dsn)
|
||||
fwd.migrate()
|
||||
assert any(b.strategy_id == "vrp" for b in fwd.all_backtest_summaries())
|
||||
assert any(b.strategy_id == "multistrat_levered" for b in fwd.all_backtest_summaries())
|
||||
|
||||
repo = PaperRepo(dsn)
|
||||
repo.migrate()
|
||||
assert repo.sim_curve_returns("vrp") # non-empty
|
||||
assert repo.sim_curve_returns("multistrat_levered") # non-empty
|
||||
|
||||
|
||||
def test_persist_track_backtest_ref_idempotent_on_rerun(tmp_path, monkeypatch):
|
||||
|
||||
@@ -10,9 +10,9 @@ from fxhnt.registry import STRATEGY_REGISTRY
|
||||
|
||||
def test_every_registry_strategy_has_a_display_name() -> None:
|
||||
for sid, entry in STRATEGY_REGISTRY.items():
|
||||
# multistrat/vrp are deliberately overridden with a friendlier pill label (see the next test) — every
|
||||
# multistrat is deliberately overridden with a friendlier pill label (see the next test) — every
|
||||
# other registry entry must resolve to its own registry `display_name`.
|
||||
if sid not in ("multistrat", "vrp"):
|
||||
if sid != "multistrat":
|
||||
assert display_name(sid) == entry["display_name"]
|
||||
assert display_name(sid) != sid # never the bare raw id
|
||||
|
||||
@@ -20,7 +20,6 @@ def test_every_registry_strategy_has_a_display_name() -> None:
|
||||
def test_sim_book_overrides_are_plain_language() -> None:
|
||||
# The interim local pill labels from app.py's `_SIM_BOOK_LABELS` (Task 1), absorbed here.
|
||||
assert display_name("multistrat") == "ETF Portfolio"
|
||||
assert display_name("vrp") == "Options income (put spreads)"
|
||||
|
||||
|
||||
def test_unknown_id_falls_back_to_itself_never_raises() -> None:
|
||||
|
||||
@@ -26,12 +26,12 @@ def test_every_active_track_declares_a_definition():
|
||||
|
||||
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).
|
||||
# (C2 Task 3 added bybit_4edge_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"}
|
||||
assert observed == {"multistrat_exec", "bybit_4edge_exec"}
|
||||
|
||||
|
||||
def test_inception_override_returns_date_when_version_matches(monkeypatch):
|
||||
|
||||
@@ -15,11 +15,6 @@ def test_ibkr_recompute_replay_book_reads_ibkr_curve():
|
||||
assert out == {"multistrat": {0: 0.0, 1: 0.02}}
|
||||
|
||||
|
||||
def test_vrp_recompute_replay_book_reads_ibkr_curve():
|
||||
out = sim_returns_for("vrp", bybit_returns=_bybit, ibkr_curve=_ibkr)
|
||||
assert out == {"vrp": {0: 0.0, 1: 0.02}}
|
||||
|
||||
|
||||
def test_sim_books_includes_ibkr():
|
||||
assert "multistrat" in SIM_BOOKS and "bybit_4edge" in SIM_BOOKS
|
||||
assert SIM_BOOKS == ("bybit_4edge", "bybit_4edge_levered", "multistrat", "multistrat_levered", "vrp")
|
||||
assert SIM_BOOKS == ("bybit_4edge", "bybit_4edge_levered", "multistrat", "multistrat_levered")
|
||||
|
||||
Reference in New Issue
Block a user