17 — Backtest & Validate

Sharpe Ratio & Risk-Adjusted Returns#

Performance✓ Mathematical
◆ The PatternInterpreting Sharpe, Sortino, Calmar — return per unit of risk

Raw returns are meaningless without risk context. The Sharpe ratio measures excess return per unit of total volatility. Sortino only penalises downside volatility. Calmar divides return by maximum drawdown — the worst-case measure.

Sharpe = (Rp − Rf) / σp
Sharpe = annualised excess return / annualised std dev. >1 is good, >2 is excellent.
Sortino = (Rp − Rf) / σdownside
Sortino = only penalises negative volatility. Better for asymmetric return distributions.
Calmar = Rannual / |MaxDrawdown|
Calmar = return divided by worst-case loss. Sensitive to tail risk.
// Interactive — adjust return and volatility, see ratios
Return %12%
Volatility %15%
Sharpe
# Python — risk-adjusted ratios
import numpy as np

returns = df['returns']
rf = 0.05 / 252  # daily risk-free rate

# Sharpe (annualised)
sharpe = (returns.mean() - rf) / returns.std() * np.sqrt(252)

# Sortino (downside only)
down = returns[returns < 0].std()
sortino = (returns.mean() - rf) / down * np.sqrt(252)

# Calmar
cum = (1 + returns).cumprod()
dd = (cum / cum.cummax() - 1).min()
calmar = returns.mean() * 252 / abs(dd)
Pattern bridge: The Sharpe ratio is signal-to-noise for finance. In ML, the same concept appears as comparing model runs — is the improvement larger than the noise? Both ask: is this real or random?
← Previous
Sampling & Class Imbalance
Open in the full reader, with the topic sidebar →