Skip to main content

Backtest Metrics

Definitions for the metrics returned in result.metrics of a completed backtest job. Field names below match the JSON response exactly. All decimal values are returned as quoted strings to preserve precision.

sharpe

Annualized return per unit of total volatility, computed from daily returns of the equity curve.

  • Formula: sharpe = mean(daily_returns) / stddev(daily_returns) * sqrt(252)
  • Units: ratio, dimensionless.
  • Interpretation: > 1 is good, > 2 is excellent, > 3 is exceptional. Negative values mean the strategy underperformed cash on a risk-adjusted basis.

sortino

Like Sharpe, but the denominator only counts downside volatility. Penalizes losing days while ignoring large up-days.

  • Formula: sortino = mean(daily_returns) / stddev(negative_daily_returns) * sqrt(252)
  • Units: ratio, dimensionless.
  • Interpretation: Generally higher than Sharpe for the same strategy. > 1.5 is good, > 3 is excellent.

calmar

Annualized return divided by the absolute value of max drawdown. Captures how much pain you endured to earn each unit of return.

  • Formula: calmar = cagr / abs(max_drawdown)
  • Units: ratio, dimensionless.
  • Interpretation: > 0.5 is acceptable, > 1 is good, > 3 is excellent. Sensitive to a single deep drawdown.

max_drawdown

Largest peak-to-trough decline in equity over the backtest period, expressed as a fraction of the peak.

  • Formula: max_drawdown = min((equity_t - max(equity_0..t)) / max(equity_0..t))
  • Units: fraction in [-1, 0]. A value of -0.142 means a 14.2% drawdown.
  • Interpretation: Closer to 0 is better. < -0.30 (deeper than 30%) is generally uncomfortable for live capital.

win_rate

Fraction of closed trades that ended with positive PnL (after fees).

  • Formula: win_rate = count(trades where pnl > 0) / total_trades
  • Units: fraction in [0, 1].
  • Interpretation: Context-dependent. Trend-following strategies routinely run at 0.30–0.45 and still profit; mean-reversion grids often exceed 0.65. Read alongside profit_factor and expected_value.

profit_factor

Sum of winning-trade PnL divided by absolute sum of losing-trade PnL.

  • Formula: profit_factor = sum(pnl where pnl > 0) / abs(sum(pnl where pnl < 0))
  • Units: ratio, dimensionless. 1.0 means breakeven; values above 1 are net-profitable.
  • Interpretation: > 1.5 is healthy, > 2 is strong, > 3 is rare and warrants overfitting checks.

expected_value

Mean PnL per trade in quote currency (e.g. USDT for a USDT-quoted symbol), net of fees.

  • Formula: expected_value = sum(pnl) / total_trades
  • Units: quote currency per trade.
  • Interpretation: Must be meaningfully positive for a strategy to be worth running once realistic slippage and fees are layered on top. Compare against typical fees-per-trade to confirm headroom.

cagr

Compound Annual Growth Rate of the equity curve over the simulated period.

  • Formula: cagr = (equity_end / equity_start)^(1 / years) - 1, where years = duration_seconds / 31_557_600.
  • Units: annualized fraction. 0.187 means 18.7% per year.
  • Interpretation: Compare against a relevant benchmark (BTC buy-and-hold, S&P 500, risk-free rate). A high CAGR with a high max_drawdown may be inferior to a moderate CAGR with a shallow drawdown — see calmar.

avg_trade_duration

Mean holding time across all closed trades. Returned as avg_trade_duration_seconds (integer seconds).

  • Formula: avg_trade_duration_seconds = mean(trade.exit_time - trade.entry_time)
  • Units: seconds.
  • Interpretation: Diagnostic only; useful for sanity-checking that a "swing" template is not in fact scalping, or vice-versa. Pair with total_trades to estimate exchange wear.