Backtesting
A backtest is one historical simulation of a strategy on an instrument over a date range. It is the unit everything else builds on — the gauntlet stages are all variations of it, and the metrics it produces feed the research ladder.
Reproducible by construction
Section titled “Reproducible by construction”- Backtests read only from the local data catalog, never a live API.
- Strategies act on closed bars, and market orders fill on the next bar — so there is no look-ahead, and the same inputs always produce the same outputs.
- Costs are modeled: IB-style commissions, and (for intraday) the measured spread per fill.
The run lifecycle
Section titled “The run lifecycle”A backtest is an asynchronous job — the API never runs the engine itself (see architecture):
- Submit — from the Backtests tab (or
POST /api/backtests). ABacktestRunrow is written with statusQUEUEDand a job is enqueued on Redis. - Run — the worker picks up the job, resolves the strategy from the registry, and runs it on a
NautilusTrader
BacktestEnginefed by the catalog. Progress is published to Redis. - Persist — artifacts (equity curve, fills, positions, and per-kind JSON) are written to
./artifacts/<run-id>/, and the summary metrics to the run row; status becomesDONE(orFAILEDwith the error). - Review — the UI renders the result: full metrics, the candlestick chart with fills, the mark-to-market equity curve overlaid with buy-and-hold, a drawdown subplot, a calendar-year vs buy-and-hold table, the round-trip trades, and a Monte Carlo panel.
Launching from the Backtests tab
Section titled “Launching from the Backtests tab”Pick a strategy, set the symbol, date range, starting cash, and commission model, then choose a Mode. Each mode is a run kind:
- Single backtest — one run (above).
- Walk-forward / WFO, Optimize, Rule test — the gauntlet stages; see the gauntlet.
- Cross-sectional / Pairs / Portfolio / Portfolio-search / Book — the multi-instrument builders; see multi-instrument engines.
Tick up to 3 runs in the log to compare them side by side. The runs log is paginated and filterable, and every run has a deep-linkable detail view.
Intraday realism
Section titled “Intraday realism”For intraday (1-minute) strategies, fills are charged the measured spread from the ingested data’s
sidecar (--slippage-bps auto), so the whole ladder runs net of honest costs. Metrics annualize with
the right factor for the cadence automatically — see metrics.
Doing it from the command line
Section titled “Doing it from the command line”python -m ats.research --strategy <key> --symbols SPY,TLT,GLD runs the full ladder for a strategy in
one command (the registry imports fresh each invocation, so a brand-new strategy file works without a
worker restart). See command-line research.