Bug: /api/backtest/{name} only looked in backtests/results/,
but all historical backtests are saved in backtests/results/historical/.
Fix: check HISTORICAL_DIR first, then fall back to BACKTEST_DIR.
This fixes SPX backtest detail showing zero prices/fees.
Root cause: VWAP weighted the current price highest so dev≈0 always.
- Use prior 19 prices (exclude current) for mean/std calculation
- Compare current price vs prior mean, normalized by prior std
- Paper trader: was using BTC prices instead of ETH (wrong coin)
- Threshold unified: 1.0σ (was 1.5σ in paper, 1.0σ in live)
Backtests show BTC Mean Reversion: +76.42% PnL, 91% win, 22 trades.
Live node:
- Added Hurst VPIN to STRATEGIES (BTC, 0.00024 size, 00)
- Feed BTC price into dollar-bar Hurst/VPIN every 5 ticks
- Signal: BUY/SELL when H>0.55 + VPIN>0.25 + direction bias
Paper trader:
- Added Kalman Pairs, Avellaneda-Stoikov, Hurst VPIN strategies
- All 00 allocation, matching live node asset distribution
- Hurst/VPIN signal from BTC mid-price dollar bars
Strategy file: hurst_vpin_live.py (lightweight price-tick mode)
Header/Tabs: Hallmark Cobalt aesthetic
- Hairlines, cool paper bg, JetBrains Mono + Inter
- Electric cobalt accent on active tab
- No branding, no purple badges, no gradients
QuantReport: inline in strategy detail view
- Renders below trade history on every tab
- API maps strategy name -> file prefix
- Proper backtestId from historical data
Server: strategy-name-to-prefix lookup
ofi, avellaneda, iceberg, momentum, mean_rev,
funding_arb, kalman_pairs, pairs
Removed: FTDT Quant Lab branding, purple badges, green pulse dot,
shadcn Tabs dependency, backdrop blur noise
Replaced with: Hallmark Cobalt engineered aesthetic
- Hairline borders (#e0e4ec), cool paper (#f8f9fb)
- JetBrains Mono header labels, Inter tab buttons
- Electric cobalt (#0ea5e9) signal accent on active tab
- Flat text labels: Live · Paper · Historical
- Status dot + CONNECTED/OFFLINE subtle indicator
- No shadows, no gradients, no rounded cards
- API: fuzzy matcher resolves files by strategy name substring
- Frontend: backtestId now uses historical[name].name (the filename)
- Server restarted with quant_report endpoint
Backend: strategies/quant_report.py
- equityCurve: daily PnL from trade history
- monthlyReturns: heatmap matrix (years x months)
- yearlyReturns: bar chart data with mean
- monthlyReturnDistribution: histogram bins
- qqPlot: theoretical vs observed quantiles
- rollingStats: 6-month rolling return + volatility
API: /api/quant-report/{name}
Computes full report from any backtest JSON file
Frontend: QuantReport.tsx
- Strategy Performance chart (equity curve, blue line)
- Monthly Returns heatmap (blue saturation)
- Yearly Returns bar chart with mean line
- Distribution histogram
- Normal QQ plot with diagonal reference
- Rolling Statistics (6-month, dual line)
- QF-Lib header with logo and metadata
- Access via QF-Lib Report button in detail view
New: strategies/persistence.py
Tables: strategies_snap, trade_log, equity_history, fill_tracker
Auto-creates on first use, batches inserts per tick
Fix: seen_fills loads from PG (not 2000 API fills)
Before: every restart loaded all 2000 fills from API into
seen_fills, blocking new fills with matching TIDs for ~20min
After: only loads last 100 from API + full history from PG.
New fills saved to PG immediately - survives restarts.
Live node integration:
- write_metrics() → save_strategies() every tick
- On fill → save_trade() to trade_log
- On fill → TID saved to fill_tracker for cross-restart dedup
- 6 BTC strategies now have unique sizes (0.000200-0.000250)
- Fill attribution uses tighter tolerance (1e-6) for unambiguous matching
- Testnet meta API returns null -> fallback to mainnet for perp loading
- All strategies placing orders with correct isolation
Root cause: OrderBookDepthMap was only in non-OBI detail branch.
When user clicked Order Book Imbalance card, the OBIDetail component
replaced the entire detail view, and the tape was never mounted.
Fix: Added OrderBookDepthMap to OBIDetail component below trade history.
Now visible in ALL strategy detail views (both OBI and non-OBI).
Root cause: Kalman filter needs a cointegrated pair, but the
historical runner was feeding it synthetic noise (close vs SMA).
The Kalman filter found no mean-reverting spread, producing 0 signals.
Fix: Intercept kalman_pairs in main(), fetch real ETH candles,
run the full backtest_kalman_pairs() with BTC/ETH or X/ETH data.
Results (30-day, 720h candles, BTC/ETH pair):
BTC: 35 trades, -0.36% PnL
ETH: 34 trades, -0.01% PnL (ETH/BTC pair)
HYPE: 27 trades, -0.00% PnL (HYPE/BTC pair)
VVV: 33 trades, -0.01% PnL (VVV/BTC pair)
Total: 32 historical backtests (8 strategies x 4 coins)
Live node:
- Registered in STRATEGIES dict (8th strategy)
- Signal: KalmanPairsTrader.step(eth, btc) every compute_signals()
- Adaptive hedge ratio updates with every tick
Paper trader:
- Registered in STRATEGIES dict
- Signal: KalmanPairsTrader integrated into compute_signals()
- Falls back gracefully if kalman_pairs module not importable
Historical backtests:
- Ran for BTC, ETH, HYPE, VVV (4 files)
- kalman_pairs_{TICKER}_*.json in results/historical/
- Visible on dashboard under Historical tab (8 strategies x 4 coins)
Dashboard: now shows Kalman Pairs card on all three tabs.
Root cause analysis:
- Round-robin bottleneck: each strategy got attention every ~28s
- Orders cancelled immediately: POST-ONLY orders lived <=28s, near zero fill prob
- 5 strategies had over-tight thresholds (Iceberg 7/10, Momentum 2σ, etc.)
- No position management: no take-profit, no opposing signal close
Fixes applied:
1. ALL strategies execute every 4s (for name in names: parallel)
2. Orders rest 60s before refresh (was: cancelled every round)
3. Take-profit at 0.1% move + close on opposing signal
4. Aggressive 0.03% offset inside spread for higher fill probability
5. Iceberg: 7/10 -> 5/10 consecutive ticks
6. Momentum: 2σ -> 1.5σ Bollinger breakout
7. Mean Reversion: 1.5σ -> 1.0σ VWAP deviation
8. Funding Arb: uses real Hyperliquid API funding rate
9. OFI threshold kept at 0.04% (was 0.08%)
Verification:
Post-patch log shows all 7 strategies placing orders every 4 seconds.
Order Book Imbalance, Iceberg Detection, Funding Rate Arb, Pairs Trading
all confirmed active in tick 12680 output.
- Replaced single surface with dual synchronized 3D subplots:
Left: BID depth (green colorscale, -50 to 0 bps)
Right: ASK depth (red colorscale, 0 to +50 bps)
- Independent colorbars per side with proper labeling
- Camera sync via scene anchor mirroring
- Contour projection on both surfaces
- Live imbalance overlay centered between subplots
Data pipeline:
- l2SnapshotsToDualSurface() splits bid/ask into separate matrices
- L2RingBuffer unchanged (60 snapshots, O(1) append)
Removed:
- depth-map-three.tsx (Three.js alternative)
- Engine toggle buttons from OBI detail
- Three.js CDN loading
- Historical cards now deduplicated by strategy+ticker (28 entries: 7×4)
- Ticker filter bar: ALL | BTC | ETH | HYPE | VVV
- Coin badge on each card
- BacktestSummary.coin now required string field
- fetchHistorical groups by strategy · coin composite key
- Added HYPE and VVV to --coin choices
- Fixed coin field to store ticker name instead of first candle timestamp
- Added coin_name parameter to simulate_strategy_on_candles
- Next.js 16 + React + TypeScript static export
- shadcn/ui components: Card, Tabs, Badge, Sheet, Collapsible, Table
- Claude Blu 2 dark theme via oklch CSS variables
- lightweight-charts v4 for equity curve rendering
- Framer Motion for layout animations
- 3 tabs: Live Testnet, Paper Mainnet (00K), Historical
- Full-page strategy detail with equity chart + trade history
- Fee tier selector (7 official Hyperliquid tiers + staking)
- API routes prefixed with /api/ for clean Caddy proxying
- _next/ mount for Next.js static assets
- WebSocket data flowing for live metrics and paper trader
- Live node: testnet-only API for prices/orderbook/instruments
(removed mainnet fallback, added resilience wrappers)
- Paper trader: mainnet-only API — simulates with real Hyperliquid data
$120K paper capital, 12 strategies, mainnet mark prices
- Historical backtests: mainnet candle API (unchanged, already correct)
- All three tiers: strategy_equity tracking, dynamic perp lookup,
win_rate fix (pnl_net/pnl_gross), CSS contrast improvement