diff --git a/scripts/seed_cockpit_demo.py b/scripts/seed_cockpit_demo.py new file mode 100644 index 0000000..59cf631 --- /dev/null +++ b/scripts/seed_cockpit_demo.py @@ -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()