Quantitative Finance & Backtest Auditing
Probabilistic Sharpe Ratio (PSR) Formula with Skewness and Kurtosis
Audit backtested Sharpe ratios against negative skewness, fat tails, and multiple-testing benchmarks SR_0 using Bailey and López de Prado’s Probabilistic Sharpe Ratio.
Catch the Pearson kurtosis (3) vs excess kurtosis (0) bug in PSR spreadsheets
Short-volatility and carry backtests often post attractive sample Sharpe ratios SR_hat alongside severe negative skewness (gam_3 < 0) and fat tails. Opdyke (2007) and Bailey & López de Prado (2012) showed that the standard error of non-annualized SR_hat over T_obs observations is SE_SR = SQRT((1 - gam_3 * SR_hat + ((gam_4 - 1) / 4) * SR_hat^2) / (T_obs - 1)), where gam_4 is Pearson raw kurtosis (gam_4 = 3 for a normal distribution, i.e., 3 + excess_kurtosis — plugging excess kurtosis 0 makes (0 - 1)/4 negative and corrupts the variance!).
Test T_obs = 37 monthly returns (B2, so T - 1 = 36), non-annualized monthly SR_hat = 0.45 (B3), benchmark threshold SR_0 = 0.20 (B4, e.g., from a multiple-testing Deflated Sharpe hurdle), skewness gam_3 = -1.50 (B5), and excess kurtosis ex_kurt = 3.00 (B6, so Pearson gam_4 = 6.00): inside the numerator, 1 - (-1.50 * 0.45) + ((6 - 1)/4) * 0.45^2 = 1 + 0.675 + 1.25 * 0.2025 = 1.928125! Dividing by 36 gives SE_SR = SQRT(0.053559) = 0.2314, Z_PSR = (0.45 - 0.20) / 0.2314 = 1.0802, and PSR = 85.9985% (< 95% confidence — whereas Gaussian SE = 0.1749 falsely claims Z = 1.4294, PSR = 92.36%!).
| PSR Audit Quantity | Formula Expression | Sample Output |
|---|---|---|
| Gaussian Sharpe SE (Ignores Tails) | SQRT((1 + 0.5 * SR_hat^2) / (T - 1)) | 0.1749 (Understates error!) |
| Non-Normal Sharpe SE (gam_4 = 3 + ex) | SQRT((1 - gam_3*SR + ((2 + ex)/4)*SR^2) / (T - 1)) | 0.2314 (+32.3% wider SE) |
| PSR Z-Statistic vs Hurdle SR_0 | (SR_hat - SR_0) / SE_SR | 1.0802 |
| Probabilistic Sharpe Ratio PSR | Normal_CDF(Z_PSR) | 0.8600 (Fails 95% hurdle!) |
Non-Normal Sharpe Standard Error SE_SR Formula (Using Excess Kurtosis Input)
Convert excess kurtosis B6 to Pearson kurtosis gam_4 = 3 + B6 automatically so (gam_4 - 1)/4 = (2 + B6)/4 reduces cleanly to 0.5 when gam_3 = 0 and ex_kurt = 0.
=LET(t_obs, B2, sr_hat, B3, sk_val, B5, ex_k, B6, num_v, 1 - sk_val * sr_hat + ((2 + ex_k) / 4) * (sr_hat^2), IF(OR(t_obs <= 2, num_v <= 0), "Invalid Moment Input", ROUND(SQRT(num_v / (t_obs - 1)), 4)))Probabilistic Sharpe Ratio PSR(SR_0) Formula
Evaluate Normal_CDF((SR_hat - SR_0) / SE_SR) inside LET. Notice that doubling track-record length T_obs in B2 from 37 to 109 (9 years) shrinks SE_SR to 0.1336 and pushes PSR above 96.9% (0.9693).
=LET(t_obs, B2, sr_hat, B3, sr_hur, B4, sk_val, B5, ex_k, B6, num_v, 1 - sk_val * sr_hat + ((2 + ex_k) / 4) * (sr_hat^2), IF(OR(t_obs <= 2, num_v <= 0), "Invalid Moment Input", LET(se_sr, SQRT(num_v / (t_obs - 1)), z_psr, (sr_hat - sr_hur) / se_sr, u_1, 1 / (1 + 0.2316419 * ABS(z_psr)), ph_1, 0.3989422804014327 * EXP(-0.5 * z_psr^2) * u_1 * (0.31938153 + u_1 * (-0.356563782 + u_1 * (1.781477937 + u_1 * (-1.821255978 + 1.330274429 * u_1)))), ROUND(IF(z_psr >= 0, 1 - ph_1, ph_1), 4))))Try the example
Use the original values or change them to test your understanding.