# Interactive simulator cockpit + multi-track wiring — Design (A13)

**Date:** 2026-06-23
**Status:** Design (for sign-off)
**Repo:** fxhnt

## Goal
A *usable*, configurable paper-simulation page in the cockpit: choose capital / date range / strategy
composition / leverage / costs, see the equity curve, **scrub a timeline slider (fast-forward) to watch the
book evolve**, and compare tracks (2-edge / 3-edge / per-strategy). Plus: wire the live nightly to keep
**2-edge as the trusted live book** and run **3-edge** and **xsfunding-standalone** as separate forward
tracks for the gate to judge.

## Why now (decided upstream)
The numbers: 2-edge Sharpe 2.10 / −36% worst-year vs 3-edge Sharpe 1.54 / +1% worst-year / lower DD / higher
CAGR. Carry diversifies the tail but lowers Sharpe — a genuine trade-off best resolved on *forward* data, not
in-sample. So: run all three as parallel tracks + give a tool to explore the trade-offs interactively.

## Architecture — 3 pieces over one shared engine
### 1. `simulate_book` — pure in-memory sim engine (`src/fxhnt/application/paper_sim.py`, NEW)
`simulate_book(returns_by_sleeve, *, capital, sleeves, start, end, controller, kelly_fraction, cost_bps,
worst_basis=None) -> SimResult` where `SimResult = {dates[], equity[], drawdown[], per_day:[{weights,
leverage, killed}], metrics:{cagr, sharpe, max_dd, worst_year, best_year, end_value}}`.
- Reuses `paper_risk_overlay`/`IncrementalRiskOverlay` + the `paper_book_returns` compounding loop (the
  architecture map confirms the exact loop already exists). PURE — consumes only the cached
  `{sleeve:{epoch_day:ret}}` dict; no warehouse, no network, no live prices → milliseconds → live-slider-fast.
- `cost_bps` applies a per-turnover cost haircut (config knob — also how we model Bybit fees, see below).

### 2. Sim page + endpoints (`src/fxhnt/adapters/web/app.py` + `templates/sim.html`, NEW template)
- `GET /paper/sim` — the page (config panel + chart + slider + state panel + metrics).
- `GET /paper/sim/run?capital=&start=&end=&sleeves=&kelly=&controller=&cost_bps=` — recompute → HTML partial:
  the inline-SVG curve(s) + the metrics row + (optionally) the per-day state series for the slider.
- Reads `PaperRepo.sleeve_returns()` ONCE, runs `simulate_book`, renders with the existing `charts.py`
  `nav_sparkline()` (extended to multi-line + a cursor marker).

### 3. Live multi-track wiring (the "wire it that way" part)
- The nightly snapshot/backfill (and the read path) produce/serve THREE book tracks via `simulate_book` over
  the SAME cached sleeve returns: **`book_2edge`** (tstrend+unlock+stablecoin — the trusted live book),
  **`book_3edge`** (+xsfunding), **`xsfunding_solo`**. Stored as distinct ids (reuse `forward_nav`
  strategy_id, or a small `paper_book_tracks` table) so the gate sees three forward records.
- The live `/paper` page stays **2-edge** (unchanged trust). 3-edge + xsfunding are comparison tracks on the
  cockpit + in the sim. Decision on promoting 3-edge → live is made later on forward data.

## The UI (usable — mirrors the existing `replay.html` slider/fetch pattern; no new JS libs)
- **Config panel**: capital ($ input); start/end date pickers; composition = preset buttons
  (`2-edge` / `3-edge` / `tstrend` / `unlock` / `stablecoin` / `xsfunding`) + custom sleeve checkboxes;
  Kelly/leverage slider (0.1–1.5); controller dropdown (killswitch / combined); costs toggle + `cost_bps`
  field.
- **Chart**: inline-SVG equity curve(s); overlay selected tracks for comparison; reveal up to the cursor.
- **Timeline slider + ▶Play**: scrub a date cursor (vanilla `fetch` → partial, the `replay.html` model);
  the chart reveals to the cursor and a **state panel** shows equity / drawdown / active sleeves / weights /
  killed-flag AT the cursor. ▶Play animates the cursor = fast-forward.
- **Metrics row** (live-updates on config change): CAGR, Sharpe, max DD, worst & best calendar year, final $.

## Bybit EU (forward note — informs, doesn't block)
Live execution will likely be **Bybit EU (MiCA-regulated)**. Implications captured now:
- **Costs**: Bybit perp taker ≈ 5.5bp — the sim's `cost_bps` knob models this directly (vs Binance 5bp).
- **Universe**: Bybit-listed perps are a SUBSET of Binance; the binance.vision backtest is a **proxy** for the
  carry universe — live carry needs a Bybit-universe check.
- **Funding signal**: live carry must read **Bybit** funding (not Binance) — the edge re-validated on Bybit
  funding before capital.
- **MiCA**: possible leverage caps / coin restrictions.
- **Action now**: make cost configurable (done via `cost_bps`); FLAG that live carry on Bybit needs a
  Bybit-specific re-validation (universe + funding + fees). NOT building Bybit ingestion in this feature.

## Phasing
1. `simulate_book` engine + tests (the shared core).
2. Sim page (config + multi-line chart + slider + state panel + metrics).
3. Live multi-track wiring (3 nightly tracks; 2-edge stays live-trusted).

## Out of scope (v1)
- Bybit data ingestion / live execution wiring.
- Persisting user sim configs; auth. (Sim is read-only + stateless per request.)
- Monte-Carlo / parameter sweeps in the UI (the engine supports it; UI is single-config + compare).

## Acceptance criteria
- `simulate_book` pure + unit-tested; reproduces the backfill's causal book curve for the 2-edge config
  (golden vs `paper_nav`), and per-strat/3-edge configs compute correctly.
- `/paper/sim` page usable: config controls recompute the curve+metrics in <1s; slider scrubs the cursor with
  the state panel; ▶Play animates.
- 3 live tracks produced (2-edge/3-edge/xsfunding) without changing the trusted 2-edge `/paper`.
- Full suite green; no `*.dbn` staged.
