Backtest¶
See the Backtesting guide for the walk-forward methodology and worked examples.
Engine¶
engine
¶
A vectorized walk-forward backtester.
The backtester is optimizer-agnostic: it takes any callable
optimizer(returns_window) -> PortfolioResult and rebalances on a fixed
schedule, applying linear transaction costs on turnover. It returns a
:class:BacktestResult holding the strategy return series, weight history, and a
metrics summary — ready for the plotting utilities.
BacktestResult
dataclass
¶
BacktestResult(
name: str,
returns: Series,
weights: DataFrame,
turnover: Series,
metrics: dict[str, float] = dict(),
)
Output of a backtest run.
backtest
¶
backtest(
returns: DataFrame,
optimizer: Optimizer,
*,
name: str | None = None,
lookback: int = 252,
rebalance_every: int = 21,
transaction_cost: float = 0.001,
periods_per_year: int = 252,
risk_free: float = 0.0,
) -> BacktestResult
Walk-forward backtest of a single optimizer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
DataFrame
|
Asset return panel (rows = periods, columns = assets). |
required |
optimizer
|
Optimizer
|
Callable mapping a trailing return window to a :class: |
required |
lookback
|
int
|
Number of trailing periods handed to the optimizer at each rebalance. |
252
|
rebalance_every
|
int
|
Rebalance frequency in periods (21 ≈ monthly for daily data). |
21
|
transaction_cost
|
float
|
Proportional cost per unit of turnover (one-way), e.g. |
0.001
|
Returns:
| Type | Description |
|---|---|
BacktestResult
|
Net-of-cost strategy returns, weight history, turnover, and metrics. |
Source code in src/jaxfolio/backtest/engine.py
compare
¶
compare(
returns: DataFrame,
optimizers: dict[str, Optimizer],
**kwargs,
) -> dict[str, BacktestResult]
Backtest several optimizers on the same data and return a name->result map.
Source code in src/jaxfolio/backtest/engine.py
metrics_table
¶
metrics_table(
results: dict[str, BacktestResult],
) -> DataFrame
Assemble a tidy metrics comparison table across backtest results.
Metrics¶
metrics
¶
Performance and risk metrics for return series.
All functions accept a 1-D array-like of periodic returns and return plain
floats. Annualization uses periods_per_year (252 for daily by default).
annualized_return
¶
Geometric annualized return (CAGR) of a periodic return series.
Source code in src/jaxfolio/backtest/metrics.py
annualized_volatility
¶
Annualized standard deviation of returns.
sharpe_ratio
¶
Annualized Sharpe ratio (risk_free is a per-period rate).
Source code in src/jaxfolio/backtest/metrics.py
sortino_ratio
¶
Annualized Sortino ratio (downside-deviation denominator).
With no downside (zero denominator), returns +inf for positive mean
excess return, -inf for negative, and 0 for a flat series — so a
downside-free strategy ranks above one with drawdowns rather than tying at 0.
Source code in src/jaxfolio/backtest/metrics.py
cumulative_returns
¶
drawdown_series
¶
Drawdown at each point: equity / running_peak - 1 (<= 0).
max_drawdown
¶
calmar_ratio
¶
Annualized return divided by the absolute max drawdown.
With no drawdown (zero denominator), returns +inf for a positive
annualized return, -inf for negative, and 0 for flat — so a
drawdown-free strategy is not mis-ranked as the worst performer.
Source code in src/jaxfolio/backtest/metrics.py
value_at_risk
¶
Historical Value-at-Risk at confidence alpha (a positive loss).
conditional_value_at_risk
¶
Historical CVaR / expected shortfall at confidence alpha.
Source code in src/jaxfolio/backtest/metrics.py
hit_rate
¶
summary
¶
Bundle the headline metrics into a single dict for reporting/plots.