Backtesting
Runs
Configuration and output shared by the Execution and Alpha backtest modes. Scope a run, cache its data, then read metrics, save, and open the dashboard.
Subtypes
A series can bundle several bet types under one ticker. Pass subtype to run just one across the series under a shared portfolio. Rolling and structured series carry a single bet type and need no subtype; sports leagues mix several.
Sports subtypes may add a settlement scope, e.g. spread:f5, total:corners:h1, or segment_winner:set1.
result = client.backtest(
strategy, "soccer-fifwc",
subtype="moneyline",
initial_cash=10_000,
after="2026-06-22T16:00:00Z",
before="2026-06-23T12:00:00Z",
)Offline
Pass data_dir to replay from a local Parquet cache. The first run downloads; later runs read from disk.
Execution runs cache order book history; alpha runs cache bars. See Exports for the download endpoints.
# downloads on first run, replays from cache after
result = client.backtest(
strategy, "btc-up-or-down-5m",
initial_cash=10_000,
after="2026-04-15T01:45:00Z",
before="2026-04-15T01:50:00Z",
data_dir="data",
)Metrics
Both modes return the same BacktestResult. Read metrics as properties or as a dict via result.summary().
Alpha runs compute sharpe_ratio and sortino_ratio from the per-bar equity curve and add volatility. Execution runs report them per settlement.
{
"total_pnl": "342.5000",
"total_return": "3.43%",
"win_rate": "68.00%",
"sharpe_ratio": "2.14",
"sortino_ratio": "3.01",
"max_drawdown": "1.80%",
"profit_factor": "2.35",
"expectancy": "7.2872",
"avg_holding_ms": 720000,
"capital_utilization": "42.00%",
"total_trades": 47,
"total_fees": "38.4200",
"fee_drag_bps": "8.20",
"turnover": "1.85"
}Saving
Save a result to disk and reload it later. Loaded results are read-only with no live portfolio.
from marketlens.backtest import BacktestResult
result: BacktestResult = client.backtest(...)
result.save("runs/btc-fader")
loaded = BacktestResult.load("runs/btc-fader")
loaded.summary()Dashboard
Open a local browser dashboard with equity curve, drawdown, PnL by market, PnL distribution, trade timeline, order analysis, settlements table, and run config. Pass additional results to overlay.
from marketlens.backtest import BacktestResult
result.show()
# overlay a second run
result.show(other, labels=["baseline", "tuned"])
# load saved runs from disk
BacktestResult.dashboard("runs/baseline", "runs/tuned")