Backtesting
Walk-forward backtests with cuFOLIO under the hood. Solve-once for instant feedback; AutoResearch sweeps for parameter discovery; history table with one-click reload and save-as-strategy.
What it is · how it works · why it matters
Walk-forward backtester with a one-click parameter sweep. Backtest a sleeve in 12 seconds; sweep 8 candidates in 30 seconds on GB10.
Walk-forward loops cuFOLIO solves over rebalance dates; stitches the equity curve from realized weights × forward returns. AutoResearch sweeps a grid of (α, n_scenarios, max_pos) and scores each against a goal vector (CAGR, max_DD, Sharpe). Winner → save as a sleeve YAML.
The bottleneck in quant research isn't ideas — it's iteration speed. GB10 + cuOpt turns "what if α=0.99?" into a 30-second question instead of an overnight job.
Overview
The Backtesting page composes a run config (universe, date range, sleeve, optimizer knobs) and dispatches to BacktestAgent, which loops cuFOLIO solves over rebalance dates and stitches the resulting equity curve.
Run config
Universe
List of tickers. Presets cover Mega-cap-8, S&P 50, NASDAQ-100. Custom — paste tickers comma-separated. Universe size drives wall-clock superlinearly; 50 symbols + 10000 scenarios + monthly rebalance over 5 years runs about 1.5 minutes on GB10.
Window
Start + end dates. Defaults: trailing 18 months. The backtest can extend up to the latest yfinance close (typically T-1 settlement).
Rebalance cadence
| cadence | typical use |
|---|---|
| daily | aggressive momentum sleeves; not recommended for compliance reasons |
| weekly | tactical sleeves; turnover budget should be elevated |
| monthly | default; balanced sleeves; tax-aware |
| quarterly | core / passive sleeves |
Optimizer knobs
Sets the cuFOLIO solve config for every step. See cuFOLIO docs for the full surface.
- α (CVaR confidence) — 0.90 ≤ α ≤ 0.99. Higher = more tail-averse. Default 0.95.
- n_scenarios — 500 to 50000. Default 5000 (balanced).
- max_position_pct — single-name cap. Default 25%.
- cash_floor_pct — minimum cash. Default 2%.
- transaction_cost_bps — round-trip cost assumption. Default 5 bps.
Solve once
Click to fire a single cuFOLIO solve at the current config + current data. Telemetry tiles update: scenario-gen ms, LP-solve ms, total ms, α used, scenarios used. Weight bar chart shows the proposed allocation. This is the loop you'll use most when tuning a sleeve config — instant feedback per knob change.
AutoResearch sweep
Toggle AutoResearch loop in the run config. NVTrader sweeps over a candidate grid (default 8 combinations of α × n_scenarios × max_pos), runs a full walk-forward for each, scores against your goal vector, and surfaces the winner. Save the winner as a strategy with one click.
The grid is configurable in configs/autoresearch.yaml. Goal vector defaults to {CAGR, max_DD, Sharpe} with equal weights; tune the weights or change the goal set there.
Reading the curve + history table
The equity curve shows portfolio NAV vs SPY. Each rebalance step is marked with a dot. Hover any dot to see that step's weights + the cuFOLIO solve telemetry.
The history table at the bottom appends a row per run. Columns: CAGR, vol, Sharpe, max DD, turnover, hit-rate, calmar, run config hash. Filter and sort. Click any row to reload that run's config.
If two runs have the same CAGR but very different turnover, the lower-turnover one is almost always preferable — it survives transaction-cost stress better and is more tax-efficient.
Adding a custom metric
Edit src/traderspace/backtest/metrics.py — add your function to the METRICS dict. The backtest runner picks it up automatically and the history table adds a column.
REST surface
| Verb | Path | Purpose |
|---|---|---|
| POST | /api/backtest/run | Walk-forward. Streams progress events. |
| POST | /api/backtest/solve_once | Single cuFOLIO solve. |
| POST | /api/backtest/autoresearch | Parameter sweep + scoring. |
| GET | /api/backtest/history | Past runs. |
| POST | /api/backtest/save_strategy | Persist a run as a sleeve YAML. |