概率夏普率 PSR:给你的夏普率算出一个『真的大于零』的置信度
你回测出一个年化夏普 1.5,兴奋地准备上实盘——但这个 1.5 有多可信?如果只跑了 3 个月、收益还又左偏又肥尾,那这个漂亮数字很可能是运气。传统夏普率有三个致命盲点:不看样本长度(跑 60 天和跑 5 年的 1.5 天差地别)、不看高阶矩(负偏肥尾会让真实标准误暴涨)、不给显著性(永远只有一个点估计,没有置信度)。López de Prado 的概率夏普率 PSR 一次补齐三样:它把夏普率的估计误差用偏度峰度校正后,直接算出『真实夏普 > 基准』的概率。模拟里年化 SR=1.0、跑满一年(252天)的 PSR 只有 0.84——连 95% 门槛都没过;SR 掉到 0.5 时 500 天都难达标。配套的 MinTRL(最小回测长度)反过来回答:要证明 SR>0(95%置信),正态下 SR=1.0 至少需要约 2.7 年、强负偏肥尾下要 2.9 年。5000 条蒙特卡洛验证 PSR 判据的经验行为完全自洽。本文讲清三件事:PSR 公式里偏度峰度到底怎么侵蚀置信度、MinTRL 怎么在开发前就告诉你样本够不够、以及为什么『高夏普 + 短样本』是量化里最贵的自欺(中阶)。
问题:你那个漂亮的夏普率,是真的吗?#
夏普率(Sharpe Ratio, SR)是量化里最常被引用的一个数:单位风险赚多少超额收益。回测跑出年化 1.5,几乎所有人都会点头——「不错,可以上」。
但这里藏着一个几乎所有人都会栽的坑:夏普率是一个估计量,它有抽样误差,而传统夏普率完全不告诉你这个误差有多大。
三个盲点,个个致命:
-
不看样本长度。跑 60 天算出 SR=1.5,和跑 5 年算出 SR=1.5,是完全不同的两回事。前者极可能是运气,后者才有说服力。但夏普率公式里根本没有 N,它对样本长度一无所知。
-
不看高阶矩。夏普率的标准误依赖收益分布的形状。如果收益负偏(暴跌集中)、肥尾(极端频繁),那么夏普率估计的标准误会显著变大——同样一个点估计,可信度大打折扣。但传统夏普率假装收益是正态的,对偏度峰度视而不见。
-
不给显著性。它永远只吐一个点估计。1.5 就是 1.5,没有置信区间,没有”这个策略真的有效吗”的概率答案。你没法回答老板那句「你有多确定这不是过拟合?」
概率夏普率(Probabilistic Sharpe Ratio, PSR) 由 López de Prado 和 Bailey 提出,一次性补齐这三样。它不再问「夏普率是多少」,而是问一个更本质的问题:
「真实夏普率大于某个基准 SR 的概率是多少?」*
答案是一个 0 到 1 之间的概率。PSR = 0.95 意味着「有 95% 的把握,真实夏普率超过基准」。这才是能拿去做决策的东西。
PSR 公式:把三个盲点一次补上#
PSR 的构造思路是标准的统计推断:估计量 + 标准误 → z 统计量 → 概率。
夏普率估计 SR̂ 的渐近标准误(经偏度峰度校正)是:
σ(SR̂) = sqrt[ (1 − γ₃·SR̂ + (γ₄−3)/4·SR̂²) / (N−1) ]plaintext其中 γ₃ 是偏度,γ₄ 是峰度(γ₄−3 即超额峰度),N 是样本长度。然后 PSR 就是:
PSR(SR*) = Φ[ (SR̂ − SR*)·sqrt(N−1) / sqrt(1 − γ₃·SR̂ + (γ₄−3)/4·SR̂²) ]plaintextΦ 是标准正态 CDF。拆开看这个公式怎么补三个盲点:
- sqrt(N−1):样本越长,分子越大,PSR 越接近 1。样本长度直接进公式——这补上盲点 1。
- −γ₃·SR̂ 项:偏度 γ₃<0(负偏)时,分母变大,PSR 变小。负偏惩罚可信度——这补上盲点 2 的一半。
- +(γ₄−3)/4·SR̂² 项:超额峰度>0(肥尾)时,分母变大,PSR 变小。肥尾惩罚可信度——补上盲点 2 的另一半。
- Φ[…]:输出是概率不是点估计。给出显著性——补上盲点 3。
代码就是照抄公式:
import numpy as np
from scipy import stats
def probabilistic_sharpe_ratio(returns, sr_star=0.0):
"""概率夏普率:P(真实SR > sr_star)。
returns / sr_star 用同一频率(如都是日频)。"""
sr = returns.mean() / returns.std(ddof=1) # 同频夏普率
n = len(returns)
skew = stats.skew(returns)
exkurt = stats.kurtosis(returns) # 超额峰度
denom = np.sqrt(1 - skew*sr + exkurt/4.0 * sr**2)
z = (sr - sr_star) * np.sqrt(n - 1) / denom
return stats.norm.cdf(z)
# 例:日频收益,问真实SR是否>0
rng = np.random.default_rng(7)
daily = rng.normal(1.0/np.sqrt(252), 1.0, 252) # 年化SR≈1.0, 一年数据
print("PSR(>0):", probabilistic_sharpe_ratio(daily, 0.0)) # ~0.84python注意频率一致:如果用日频收益,SR̂ 和 SR* 都要是日频的(年化 SR=1.0 对应日频 SR≈1.0/√252≈0.063)。混用频率是最常见的错误。
样本长度:同一个夏普率,长短天差地别#
先看 PSR 最直接的教训——样本长度的威力。

三条曲线是三个不同的年化夏普率(0.5 / 1.0 / 1.5),横轴是样本长度,纵轴是 PSR(真实 SR>0 的概率),红线是 95% 置信门槛:
- 年化 SR=1.5(绿):约 200 天就能过 95% 门槛。强信号,样本需求低。
- 年化 SR=1.0(蓝):要跑到约 500 天(两年)才勉强达标。注意 252 天(满一年)时 PSR 只有 0.84——连 95% 都没到。
- 年化 SR=0.5(橙):1000 天都远远够不着 95%。弱信号需要海量样本才能证明它不是零。
这张图应该钉在每个量化研究员的墙上。它说的是:“高夏普”和”可信”是两码事。 一个跑了两个月的 SR=2.0,PSR 可能还不如一个跑了五年的 SR=0.8。样本长度不是细节,它是决定一个数字有没有意义的前提。
偏度峰度:肥尾如何悄悄侵蚀你的置信度#
样本长度是显性的,高阶矩的侵蚀是隐性的——也更阴险,因为你的夏普率点估计根本不变,可信度却在暗中流失。

固定年化 SR=1.2、N=500,扫偏度峰度:
- 左图(扫偏度):偏度从 +1 降到 −1.5,PSR 一路下滑。负偏度直接拉低置信度——这符合金融直觉,负偏意味着”平时小赚、偶尔巨亏”,这种收益模式的夏普率天然更不可信,因为它的风险藏在稀有的左尾里,样本没见够那些暴跌前,你根本不知道真实风险有多大。
- 右图(扫峰度):超额峰度从 0 升到 12,PSR 同样下滑。肥尾抬高标准误、压低 PSR——极端事件越频繁,夏普率估计的抖动越大。
这就是 PSR 相比传统夏普率最深刻的地方:两个策略可以有完全相同的夏普率点估计,但如果一个正态、一个负偏肥尾,它们的可信度天差地别。 传统夏普率把它们判为平手,PSR 会告诉你负偏肥尾那个其实证据薄弱得多。
实务含义很直接:那些”稳定小赚”的策略(卖期权、套息、做市)天生负偏肥尾,它们的夏普率需要更长的样本、更严的 PSR 门槛才能确认。 因为它们的真实风险恰恰藏在还没发生的那次崩盘里。
MinTRL:开发前就知道样本够不够#
PSR 是”事后”判断——策略跑完了算它可不可信。但更实用的是”事前”问:要证明这个夏普率显著,我至少需要多长的回测?
这就是 最小回测长度(Minimum Track Record Length, MinTRL)——把 PSR 公式反解出 N:
MinTRL = 1 + (1 − γ₃·SR̂ + (γ₄−3)/4·SR̂²)·(Z_conf / (SR̂ − SR*))²plaintextZ_conf 是目标置信度对应的正态分位数(95% 对应 1.645)。
def min_track_record_length(sr, skew, exkurt, sr_star=0.0, conf=0.95):
"""最小回测长度:要以 conf 置信度证明 SR>sr_star,至少需要多少个观测。
sr / sr_star 同频。返回观测数(如日频则为交易日数)。"""
z_conf = stats.norm.ppf(conf)
if sr <= sr_star:
return np.inf
var_term = 1 - skew*sr + exkurt/4.0 * sr**2
return 1 + var_term * (z_conf / (sr - sr_star))**2
# 年化SR=1.0, 转日频
sr_d = 1.0 / np.sqrt(252)
n_normal = min_track_record_length(sr_d, 0.0, 0.0) # 正态
n_fat = min_track_record_length(sr_d, -1.0, 8.0) # 强负偏肥尾
print(f"正态: {n_normal/252:.2f} 年") # ~2.7 年
print(f"肥尾: {n_fat/252:.2f} 年") # ~2.9 年python
图里三条曲线是不同分布形状下的 MinTRL:
- 年化 SR=1.0 时,正态需要约 2.7 年,强负偏肥尾需要约 2.9 年。
- 年化 SR=0.5 时,需求飙到 10 年以上——弱信号要用极长样本才能证明。
- 年化 SR=2.0 以上时,需求降到一年以内——强信号很快就能确认。
曲线是陡峭的双曲线形状:夏普率每降一点,样本需求非线性暴涨。 这解释了为什么低夏普策略(哪怕真实有效)在实务中极难被”证明”——你可能等不到统计显著就先怀疑它失效了。
MinTRL 的最大价值是改变研发流程:在你还没开始跑长回测之前,先估个大概夏普率,用 MinTRL 反推需要多少数据。如果你手头只有 1 年数据、目标夏普 0.8,MinTRL 告诉你这根本证不出显著——那就别浪费时间做过度精细的调参,先想办法拿更多数据或找更强的信号。
蒙特卡洛验证:PSR 判据靠谱吗#
公式再漂亮也得验。用蒙特卡洛检验 PSR 判据的经验行为:

设定真实年化 SR=0.8、N=252(一年),生成 5000 条独立收益序列,每条算它的样本夏普率和 PSR。散点图横轴是样本估计的年化夏普率、纵轴是该样本的 PSR:
- 样本夏普率横向散布很宽——从负值一直到 2.0 以上。同一个真实 SR=0.8,一年样本能”抽”出千奇百怪的估计值。 这本身就是”短样本不可信”的铁证。
- 只有约 20% 的样本 PSR 超过 95% 门槛。也就是说,即便真实策略确实有 SR=0.8,用一年数据去检验,八成的时候你都无法在 95% 置信度下确认它有效。
- PSR 随样本夏普率单调上升——估出来越高,越可能过门槛,符合预期。
这个 20% 通过率说明了 PSR 判据的保守性是合理的:它宁可放过真策略(假阴性),也不轻易把运气认成 alpha(假阳性)。在量化里,把过拟合当成 alpha 上实盘的代价,远大于错过一个真策略——PSR 的门槛设计正是这个取舍。
A. 实现细节#
- 频率一致:SR̂ 和基准 SR* 必须同频。本文日频演示,年化 SR 除以 √252 转日频。混频是最常见错误,会让 PSR 完全失真。
- 偏度峰度:用 scipy
stats.skew和stats.kurtosis(后者默认返回超额峰度,公式里的 (γ₄−3) 直接用它)。 - 基准 SR*:默认设 0(问”真实 SR 是否 > 0”)。也可设为竞品策略或无风险基准的夏普率,做相对比较。
- MinTRL 单位:返回观测数,日频则为交易日数,除以 252 转年。
- 蒙卡设定:单位波动率下 μ=SR,故直接用
normal(sr_daily, 1.0, N)生成,样本夏普率 = 均值/标准差。
B. 已知偏差#
- 渐近近似:PSR 的标准误公式是大样本渐近结果,在极短样本(N<100)下本身就不准——讽刺的是,恰恰是短样本最需要 PSR,而它此时也最不可靠。
- 高阶矩估计误差:PSR 依赖偏度峰度,而这两个矩在短样本下噪声极大(峰度尤甚)。估歪的高阶矩会让 PSR 跟着歪,这是”用有误差的量去校正另一个量”的固有代价。
- 独立同分布假设:公式假设收益 i.i.d.。真实收益有自相关(尤其是低频再平衡、有杠杆或路径依赖的策略),会让有效样本量小于名义 N,PSR 因此偏乐观。
- 只管一个夏普率:PSR 检验单个策略的显著性,但如果你试了 100 个策略挑出最好的那个,PSR 不足以防过拟合——那需要 Deflated Sharpe Ratio(DSR)把多重检验的选择偏差也扣掉。
C. 结果解读#
-
“高夏普”必须配”够长样本”才有意义:这是 PSR 最硬核的教训。年化 SR=1.0 跑满一年的 PSR 只有 0.84——连显著都算不上。任何只报夏普率不报样本长度和 PSR 的回测,都应该被打个问号。
-
负偏肥尾策略要过更高的门槛:卖期权、套息、做市这类”稳定小赚”策略天然负偏肥尾,PSR 会系统性压低它们的可信度——这不是 bug 是 feature。它们的真实风险藏在还没发生的崩盘里,本就该用更长样本、更严标准来确认。
-
MinTRL 应该前置到研发流程:与其跑完长回测再发现样本不够,不如开发前用 MinTRL 估算数据需求。低夏普目标(<0.5)的 MinTRL 动辄十年以上——这直接告诉你该去找更强的信号,而不是在弱信号上过度调参。
-
PSR 是防自欺的第一道闸,但不是最后一道:它解决”单个策略是否显著”,不解决”从一堆策略里挑最好那个”的选择偏差。真要防过拟合,PSR 之后还得上 Deflated Sharpe Ratio 和组合式净化交叉验证(CPCV)。把 PSR 当成必要非充分条件——过不了 PSR 的策略直接毙掉,过了的还要继续拷问。
一句话总结:概率夏普率把”夏普率是多少”换成”夏普率真的大于零的概率是多少”,一次补齐样本长度、高阶矩、显著性三个盲点——而它配套的 MinTRL 让你在开发前就知道,手里的数据到底够不够证明你的策略不是运气。