Connect the bybit deploy book's multi-year BACKFILL (persisted paper_nav, venue="bybit") to the fund
headline so the page leads with the REAL record ($393,955 · +294% · real Sharpe · maxDD · since 2021)
plus a small live-readiness chip (gate days/min · status) — never the not-started forward track's
0.00 / 0 forward days.
- nav_stats.nav_backfill_stats: pure, unit-tested helper computing total return / annualised Sharpe
(mean daily ret / pstdev × sqrt(365)) / maxDD / final equity from a persisted NAV equity series.
- Short pre-gate forward Sharpes are kept ("fun to watch") but rendered DIMMED with a "· pre-gate"
marker; cleared tracks render bright. One caption explains it.
- Compact edges table (edge · class · record · forward · nav); not-started 0-day trackers collapsed
into a "warming" subsection so they don't dominate.
- Cut clutter: removed the two prose paragraphs (folded into title= tooltips), removed the duplicate
"Go to" footer, and replaced the grouped Live/Backtest nav with one tidy row
(Overview · Paper · Replay · Backtest).
- Reusable Jinja macros (_macros.html: headline_card, provisional_num, track_row) for the
cockpit-wide consistency roll-out. FleetRow gains gate_min_days for the forward "days/min" denominator.
Presentation + data-connection only — no edge return or gate logic changed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
72 lines
3.0 KiB
Python
72 lines
3.0 KiB
Python
"""Web smoke: routes return 200 and render the seeded fleet + a strategy detail + healthz."""
|
|
from __future__ import annotations
|
|
|
|
import datetime as dt
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
from fxhnt.adapters.persistence.forward_nav import ForwardNavRepo
|
|
from fxhnt.adapters.web.app import create_app
|
|
from fxhnt.application.forward_models import BacktestSummary
|
|
from fxhnt.application.forward_models import ForwardNavRow as Row
|
|
from fxhnt.application.forward_models import ForwardSummary
|
|
|
|
|
|
def _client() -> TestClient:
|
|
repo = ForwardNavRepo("sqlite://")
|
|
repo.migrate()
|
|
at = dt.datetime(2026, 6, 14, 23, 30)
|
|
repo.upsert_rows([Row("combined", "2026-06-05", 0.01, 1.01),
|
|
Row("combined", "2026-06-06", 0.0099, 1.0201)], at)
|
|
repo.upsert_summary(ForwardSummary("combined", "2026-06-06", 2, 1.0201, 0.0201, 1.2, -0.01),
|
|
"WAIT", "2/20 forward days", at)
|
|
repo.upsert_backtest_summary(BacktestSummary(
|
|
"xsfunding", "2026-05-30", cagr=0.12, ann_vol=0.18, sharpe=0.85, max_drawdown=-0.22,
|
|
passed=True, dsr=0.61, is_sharpe=0.9, oos_sharpe=0.7, pvalue=0.03), at)
|
|
return TestClient(create_app(repo))
|
|
|
|
|
|
def test_healthz() -> None:
|
|
assert _client().get("/healthz").status_code == 200
|
|
|
|
|
|
def test_cockpit_lists_fleet() -> None:
|
|
r = _client().get("/")
|
|
assert r.status_code == 200
|
|
assert "Crypto momentum book" in r.text and "WAIT" in r.text
|
|
|
|
|
|
def test_cockpit_shows_record_and_forward_columns() -> None:
|
|
# Redesigned compact edges table: edge · class · record · forward · nav (the standalone backtest
|
|
# reference is folded into the "record" column; the gate status into "forward").
|
|
r = _client().get("/")
|
|
assert r.status_code == 200
|
|
for header in (">edge<", ">class<", ">record<", ">forward<", ">nav<"):
|
|
assert header in r.text, f"column header {header!r} missing"
|
|
assert "badge WAIT" in r.text # a gate status badge rendered in the forward column
|
|
|
|
|
|
def test_cockpit_has_responsive_markup() -> None:
|
|
r = _client().get("/")
|
|
assert r.status_code == 200
|
|
assert 'class="fleet"' in r.text # fleet table marked for card reflow
|
|
assert 'data-label="forward"' in r.text # per-cell labels for mobile card view
|
|
|
|
|
|
def test_strategy_detail_renders_backtest_verdict() -> None:
|
|
r = _client().get("/strategy/xsfunding")
|
|
assert r.status_code == 200
|
|
assert "backtest verdict" in r.text # verdict block header present
|
|
assert "badge PASS" in r.text # PASS badge rendered
|
|
assert "DSR" in r.text # backtest metric label present
|
|
|
|
|
|
def test_strategy_detail_renders() -> None:
|
|
r = _client().get("/strategy/combined")
|
|
assert r.status_code == 200 and "2026-06-06" in r.text
|
|
assert "weekly" in r.text and "rolling mean" in r.text # period-aware section present
|
|
|
|
|
|
def test_strategy_detail_unknown_404() -> None:
|
|
assert _client().get("/strategy/nope").status_code == 404
|