Context (verified)
Keel has no long-term equity series. What exists today:
agent_state["equity_history"] is a 7-day rolling window maintained only for the weekly drawdown rail (keel/execution/equity.py:157-163, rebased by keel record-flow).
- The Insights "equity curve" is cumulative net P&L over closed trades, computed on demand with x-axis = trade order, not time (
keel/commands/insights.py build_equity_curve, coordinates quantised server-side into a 1000x300 viewBox).
- The agent already computes mark-to-market equity every cycle (
agent._mark_to_market_equity, keel/agent/agent.py:404) — it is simply not persisted.
Every trading dashboard's core chart is account equity over time. Keel's honest version is agent-computed MTM equity — and it currently evaporates after 7 days.
Scope
- New table
equity_points:
- Columns:
id INTEGER PRIMARY KEY AUTOINCREMENT, ts TEXT NOT NULL, mode TEXT NOT NULL ('paper' | 'live'), and equity, cash, unrealized, hwm as TEXT exact-Decimal strings — money stays TEXT per the standing convention (keel/data/db.py:10-11). No integer-cents columns; wire conversion happens at payload time.
- No
profile column: the DB is already one-per-profile (ADR 0002); mode is the load-bearing partition (paper/live flips within one DB).
- Written in the
update_drawdown call path, once per cycle, alongside the existing 7-day window (which stays — the rail keeps its own semantics).
- Migration per the standing pattern (see v3
trade_outcomes, v5, v6): DDL added to _SCHEMA_STATEMENTS + a numbered, documented no-op step (_migrate_v16_equity_points — "table creation is handled by _SCHEMA_STATEMENTS; there is deliberately NO backfill"). SCHEMA_VERSION 15 → 16.
- Insights chart upgrade: the curve becomes time-axised, segmented by
mode (paper vs live visually distinct), with the rail-11 high-water mark and weekly-drawdown ceiling rendered as threshold overlays on the same chart.
Refusals (constitutional / standing invariants)
- No floats anywhere in storage or wire — payload
Field contract only (keel/web/payload.py Rule 1; the guard test fails on any JSON number).
- Zero client-side math: coordinates and polylines quantised server-side, exactly as the existing curve does.
Acceptance
- Fresh DB stamps v16; a v15 DB migrates cleanly; re-running the migration is idempotent.
- The Insights chart has a time axis, mode-partitioned segments, and rail overlays.
- Tests: money-as-strings, migration idempotence, one row per cycle, mode flips produce two segments not one blended curve.
Sprint 1 (cockpit backbone), first — issues for Orders/Positions/Balances views build on the payload/nav patterns this establishes.
Context (verified)
Keel has no long-term equity series. What exists today:
agent_state["equity_history"]is a 7-day rolling window maintained only for the weekly drawdown rail (keel/execution/equity.py:157-163, rebased bykeel record-flow).keel/commands/insights.pybuild_equity_curve, coordinates quantised server-side into a 1000x300 viewBox).agent._mark_to_market_equity,keel/agent/agent.py:404) — it is simply not persisted.Every trading dashboard's core chart is account equity over time. Keel's honest version is agent-computed MTM equity — and it currently evaporates after 7 days.
Scope
equity_points:id INTEGER PRIMARY KEY AUTOINCREMENT,ts TEXT NOT NULL,mode TEXT NOT NULL('paper' | 'live'), andequity,cash,unrealized,hwmas TEXT exact-Decimal strings — money stays TEXT per the standing convention (keel/data/db.py:10-11). No integer-cents columns; wire conversion happens at payload time.profilecolumn: the DB is already one-per-profile (ADR 0002);modeis the load-bearing partition (paper/live flips within one DB).update_drawdowncall path, once per cycle, alongside the existing 7-day window (which stays — the rail keeps its own semantics).trade_outcomes, v5, v6): DDL added to_SCHEMA_STATEMENTS+ a numbered, documented no-op step (_migrate_v16_equity_points— "table creation is handled by_SCHEMA_STATEMENTS; there is deliberately NO backfill").SCHEMA_VERSION15 → 16.mode(paper vs live visually distinct), with the rail-11 high-water mark and weekly-drawdown ceiling rendered as threshold overlays on the same chart.Refusals (constitutional / standing invariants)
Fieldcontract only (keel/web/payload.pyRule 1; the guard test fails on any JSON number).Acceptance
Sprint 1 (cockpit backbone), first — issues for Orders/Positions/Balances views build on the payload/nav patterns this establishes.