The Sharpe ratio
▸ Pretest — guess, even if you don't know
A strategy has annualized return of 20% and annualized volatility of 10%. The risk-free rate is 4%. What's its Sharpe ratio?
The formula
Annualized Sharpe ratio:
Where:
- = annualized expected return of the strategy
- = annualized risk-free rate (typically 1-year Treasury)
- = annualized standard deviation of returns
It's a per-unit-of-volatility excess return. A unitless quantity. Higher is better (most of the time — caveats below).
How to compute it from a return series
import numpy as np
def annual_sharpe(daily_returns, rf_annual=0.04, trading_days=252):
rf_daily = rf_annual / trading_days
excess = daily_returns - rf_daily
return (excess.mean() / excess.std(ddof=1)) * np.sqrt(trading_days)
The factor annualizes because:
- Mean scales linearly (× T)
- Std dev scales as √T
- Their ratio scales as √T
Benchmarks — what's a good Sharpe?
For long-horizon strategies:
- 0.3–0.5: Buy-and-hold US equity (SPY ~0.4 over the past century).
- 0.5–1.0: Reasonable trend-following or factor strategy.
- 1.0–1.5: Strong systematic strategy.
- 1.5–2.0: Exceptional — be skeptical, audit the backtest carefully.
- >2.0: Almost always a backtest bug, look-ahead bias, transaction costs ignored, or a very specific high-frequency strategy.
For shorter horizons (daily reallocation, intraday), Sharpe can be higher because the high turnover lets the strategy compound smaller edges more often. But after honest cost modeling, even those rarely sustain above ~3 in production.
Renaissance Technologies' Medallion Fund allegedly runs Sharpe ~7+. They are a unique outlier; do not benchmark yourself against them.
The standard error of an estimated Sharpe (this is huge)
Estimating Sharpe from a finite sample is noisy. The approximate standard error (Lo 2002) for an iid normal series of observations, stated in per-period units:
Units matter here. The Sharpe in this formula is the per-period (e.g., daily) Sharpe, and is the number of those periods. To get the SE of the annualized Sharpe, compute in daily units first, then multiply by .
Worked example — annual Sharpe = 1.0, five years of daily data ():
- Daily Sharpe: .
- Per-period SE: .
- Annualized SE: .
So with 5 years of data, a strategy with measured annual Sharpe = 1.0 has a 95% confidence interval of roughly . You barely have evidence that the true Sharpe is positive. With 10 years, the interval tightens roughly to [0.4, 1.6]. With 30 years, [0.6, 1.4].
A convenient shortcut: for modest Sharpe values, the annualized SE is approximately — the same formula with counted in years. That's why 5 years of a Sharpe-1 strategy gives SE ≈ (close to the exact 0.45; the shortcut is slightly conservative).
This is why short backtests can't validate a strategy. A 2-year backtest showing Sharpe of 1.0 is consistent with a true Sharpe of zero (i.e., no edge).
Sharpe's failure modes
-
Assumes returns are roughly normal. A strategy that earns small premia steadily while occasionally suffering catastrophic losses (selling out-of-the-money options before they blow up) can show high Sharpe right up until the blowup. Sharpe doesn't see the fat tail. This is the single most important caveat.
-
Compares strategies with different timescales unfairly. A high-frequency strategy with 10× the number of independent trades naturally has a √10 ≈ 3.2× higher Sharpe than a daily strategy with the same per-trade edge.
-
Ignores higher moments. Skewness and kurtosis don't enter the formula. Sortino (denominator = downside deviation only) and Calmar (denominator = max drawdown) partially correct for this.
-
In-sample optimism bias. A backtest Sharpe that was selected from many candidates (parameter tuning, strategy search) is biased upward — this is what the deflated Sharpe ratio corrects for (López de Prado 2018). We'll see deflated Sharpe later in D4 (backtest methodology).
Try it
Implement the Sharpe computation from the code sketch above, from memory if you can:
Implement sharpe(daily_returns, rf_annual): convert the annual risk-free rate to daily (rf_annual / 252), subtract it from the daily returns to get excess returns, then return excess.mean() / excess.std(ddof=1) * sqrt(252).
Predict and pace yourself
Before the next lesson:
- If you compute Sharpe on a 5-year backtest and get 1.5, what's a rough 95% confidence interval?
- If you tested 100 random strategies on the same data and reported only the best, would its Sharpe be a reliable estimate of its true Sharpe?
⧉ Review cardWhat is the Sharpe ratio formula?
⧉ Review cardWhat's a typical Sharpe for buy-and-hold SPY?
⧉ Review cardWhat is the approximate SE of an annualized Sharpe estimate, and what CI does 5 years of data give a Sharpe-1 strategy?
⧉ Review cardWhat's Sharpe's biggest blind spot?
◈ Calibration check
Could you compute a Sharpe ratio from a return series, and explain its standard error?
1 = guessing · 5 = could teach it
⏻ End of lesson
Mark it read to book its 4 review cards into your deck.