chore(cockpit): local demo seed for browser verification of the surfacing

Adds seed_cockpit_demo.py script to populate the cockpit database with
representative forward track data (4 strategies), nav histories, backtest
summaries, and allocation/funding snapshots. Idempotent — safe to re-run
multiple times. Supports env override FXHNT_OPERATIONAL_DSN (defaults to
sqlite:///./cockpit-demo.db).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-07-10 12:27:04 +02:00
parent 146e1733f3
commit cec036e453

View File

@@ -0,0 +1,181 @@
#!/usr/bin/env python3
"""Seed the cockpit demo database with representative forward track and allocation/funding data.
Usage:
export FXHNT_OPERATIONAL_DSN="sqlite:///./cockpit-demo.db"
python scripts/seed_cockpit_demo.py
The script creates a fresh schema and seeds 4 strategies with forward summaries, nav histories,
a backtest summary, and allocation/funding snapshots. Fully idempotent — safe to re-run.
"""
import datetime as dt
import os
from sqlalchemy.orm import Session
from fxhnt.adapters.persistence.cockpit_models import (
BacktestSummaryRow,
ForwardNavRow,
ForwardSummaryRow,
StrategyAllocationRow,
StrategyFundingRow,
)
from fxhnt.adapters.persistence.forward_nav import ForwardNavRepo
def seed_cockpit_demo() -> None:
dsn = os.getenv("FXHNT_OPERATIONAL_DSN", "sqlite:///./cockpit-demo.db")
repo = ForwardNavRepo(dsn)
repo.migrate()
at = dt.datetime(2026, 7, 10, 10, 0, 0)
# Idempotent: delete existing summaries and nav rows to avoid duplication on re-runs
with Session(repo._engine) as s:
s.query(ForwardSummaryRow).delete()
s.query(ForwardNavRow).delete()
s.query(BacktestSummaryRow).delete()
s.commit()
# Seed forward summaries (4 strategies) and their nav histories
strategies = [
("bybit_4edge", 0.0031, 2),
("bybit_4edge_exec", 0.0019, 2),
("multistrat", 0.012, 1),
("positioning", 0.02, 2),
]
with Session(repo._engine) as s:
for strategy_id, total_return, days in strategies:
summary = ForwardSummaryRow(
strategy_id=strategy_id,
as_of="2026-07-10",
days=days,
nav=1.0 + total_return,
total_return=total_return,
sharpe=1.0,
maxdd=-0.05,
gate_status="WAIT",
gate_reason="",
src_updated_at=at,
)
s.add(summary)
s.commit()
# Seed nav histories (5-day ascending series for each strategy)
nav_start = dt.date(2026, 7, 6)
with Session(repo._engine) as s:
for strategy_id, total_return, _ in strategies:
# Build a 5-day nav series ascending to the final nav value
nav_step = total_return / 5
for i in range(5):
nav_val = 1.0 + (nav_step * (i + 1))
ret_val = nav_step
s.add(
ForwardNavRow(
strategy_id=strategy_id,
date=nav_start + dt.timedelta(days=i),
ret=ret_val,
nav=nav_val,
src_updated_at=at,
)
)
s.commit()
# Seed backtest summary for bybit_4edge
with Session(repo._engine) as s:
backtest = BacktestSummaryRow(
strategy_id="bybit_4edge",
as_of="2026-07-10",
cagr=0.318,
ann_vol=0.12,
sharpe=2.20,
max_drawdown=-0.08,
passed=True,
dsr=0.98,
is_sharpe=2.15,
oos_sharpe=1.95,
pvalue=0.001,
src_updated_at=at,
)
s.add(backtest)
s.commit()
# Seed allocations: bybit_4edge ($18,900 / 54%) and positioning ($9,500 / 27%)
repo.replace_allocations(
[
StrategyAllocationRow(
strategy_id="bybit_4edge",
target_weight=0.54,
target_dollars=18900.0,
policy_version=1,
policy_hash="h",
as_of="2026-07-10",
computed_at=at,
),
StrategyAllocationRow(
strategy_id="positioning",
target_weight=0.27,
target_dollars=9500.0,
policy_version=1,
policy_hash="h",
as_of="2026-07-10",
computed_at=at,
),
],
at,
)
# Seed funding: bybit_4edge (funded), positioning (decaying), multistrat (de-funded)
repo.replace_funding(
[
StrategyFundingRow(
strategy_id="bybit_4edge",
state="funded",
label="funded",
decay_run=0,
recovery_run=0,
first_pass_date=None,
policy_version=2,
policy_hash="h",
as_of="2026-07-10",
computed_at=at,
),
StrategyFundingRow(
strategy_id="positioning",
state="funded",
label="decaying",
decay_run=4,
recovery_run=0,
first_pass_date=None,
policy_version=2,
policy_hash="h",
as_of="2026-07-10",
computed_at=at,
),
StrategyFundingRow(
strategy_id="multistrat",
state="de-funded",
label="de-funded",
decay_run=0,
recovery_run=0,
first_pass_date="2026-06-20",
policy_version=2,
policy_hash="h",
as_of="2026-07-10",
computed_at=at,
),
],
at,
)
print(f"Seeded cockpit demo: {dsn}")
print(
f"Run: export FXHNT_OPERATIONAL_DSN='{dsn}' && python scripts/dev_cockpit_local.py"
)
if __name__ == "__main__":
seed_cockpit_demo()