Deflated Sharpe Ratio:你回测里的'赢家',有多少能扛过多重检验?
"回测无幻觉"系列文章。
📄 本文成长为了一篇研究论文。 以下每一个数字都来自同一个确定性脚本,它构建了受控的真实基准——纯噪声搜索、植入优势的搜索,以及一个真实的相关参数网格——然后对其运行 Deflated Sharpe Ratio、Harvey-Liu 多重检验折价法,以及 White's Reality Check / Hansen's SPA,直接测量每种方法的假发现率与检验功效。可在线阅读论文(交互版 + PDF):deflated-sharpe.marketmaker.cc,代码与数据见 github.com/suenot/deflated-sharpe-search。
你跑了一次参数扫描。十六种快线长度,四十种慢线长度,一条移动平均线交叉策略的 640 种组合。网格跑完,有一个格子在发光:年化夏普比率 3.9,单次检验 p 值 。十二个零的显著性。你发现了点什么。
又或者,你什么都没发现,是搜索替你"发现"了它。
参数搜索不是一次检验。它是一台专门找出 N 次尝试中最幸运那一次的机器,你给它的尝试越多,它的赢家看起来就越幸运——无论底下是否真的有优势。best-of-N 的夏普比率因选择而被虚高,其原理就跟一千个随机路人里最高的那个人显得特别高一样:不是因为"高"是真的,而是因为你搜索过了。印在赢家旁边的单次检验统计量——它的 p 值、它的 t 统计量、它那个"这显著吗?"——本来是为一个预先注册好的假设设计的。把它们喂给一次搜索的幸存者,它们每次都会自信满满地撒谎。
本文精确测量它们撒谎撒得有多严重,然后测量三种能修正它的工具。整件事的核心在于受控的真实基准:我们生成一些我们已知答案的收益序列——有时是真实优势为零的纯噪声,有时是强度已知的植入优势——这样"这种方法判断对了吗"就是一个事实,而不是一个主观判断。先把结论摆在前面。在已知零假设的搜索上——诚实的答案永远是"没有发现"——每种检验各自"狼来了"的频率如下:
| 检验 | 已知零假设搜索上的假发现率 | 结论 |
|---|---|---|
| 朴素检验"最佳夏普比率显著吗?" | 1.000 | 每一次都宣布发现 |
| Deflated Sharpe Ratio(DSR ≥ 0.95) | 0.001 | 得到控制 |
| Harvey-Liu 折价法——Bonferroni | 0.057 | 基本得到控制 |
| Harvey-Liu 折价法——Holm | 0.057 | 基本得到控制 |
| Harvey-Liu 折价法——BHY | 0.007 | 得到控制 |
| White's Reality Check(自助法) | 0.022 | 得到控制 |
每次搜索 1,000 个策略,每个策略 1,000 次观测,2,000 次独立的零假设搜索,处处真实夏普比率 = 0。合成的独立同分布正态收益,种子 0,α = 0.05,每年 252 个周期。朴素检验的假发现率不是"偏高"——而是正好等于一。
把第一行盯着看,直到它刺痛你为止。一个本应在纯噪声上以 5% 的频率触发的检验,实际触发频率是 100%——因为你给它看的不是纯噪声,而是一千次纯噪声抽取里的最大值,而一千个抛硬币的人里最靠运气的那个,看起来永远像个天才。其余每一行都是懂得这一点并对此做出修正的方法。这就是本文的全部内容:为什么第一行是 1.000,为什么其他行不是,以及唯一一处(最后一节)连好的方法也需要第二次修正才能保持诚实。
第 1 幕——陷阱:搜索凭空制造出夏普比率

从最干净的那种陷阱开始。生成 个策略,它们的收益是相互独立的标准正态噪声——没有漂移,没有技巧,全部真实夏普比率恰好为零。每个策略有 次观测。现在做每个参数搜索都会做的事:只留下最好的那个。
best-of-1000 的单期夏普比率平均为 0.1027,年化后为 1.63(推算:)。这可不是个不起眼的数字。年化夏普比率 1.63,是那种能让一个策略拿到资金、被写成报告、被实际配置资金的成绩。而它来自一台把漂移项调到零的随机数生成器。
现在把这个赢家交给朴素显著性检验——就是每个回测库都免费打印出来的那种。把它的夏普比率换算成 t 统计量(),取单侧 p 值,如果 就宣布为一次发现:
这些噪声赢家的单次检验 p 值中位数是 0.000686——一个毫无优势的策略,却拿到了三个零的"显著性"。而在 2,000 次独立的零假设搜索中,朴素检验在每一次都宣布了发现:假发现率 1.000。不是"偏高"。不是"有点高"。一个按构造在单一零假设上最多 5% 的时候会判对的检验,在一次搜索的赢家身上却 100% 判错。
这台机器一旦被点名,运作机制就不再神秘了。朴素检验问的是"在零假设下,这个夏普比率会不会纯粹出于偶然?"——如果你是在看数据之前就选中了这个策略,这是个公平的问题。但你选中它,恰恰是因为它是一千个里夏普比率最高的那个。你是在对最大值做条件,而最大值的抽样分布和单次抽取的抽样分布完全是两回事。这和我们的前视偏差分类法从另一端诊断出的其实是同一种病——那篇文章里,一根 K 线的泄漏就从噪声中凭空制造出 15 的夏普比率;这里,一次搜索完全没有任何泄漏,纯靠选择,就从噪声中制造出 1.63 的夏普比率。机制不同,症状一模一样:一个看起来很棒、却毫无意义的夏普比率。
1.63 这个数字很重要,记住它。它是这次搜索的噪声上限:1,000 个零优势策略中最幸运的那个,理应报出的夏普比率。任何对搜索赢家的诚实检验,都不该拿它去跟零比,而要拿它跟这个数字比——跟你看一千次之后,单靠运气就能拿到的东西比。
第 2 幕——工具箱:给搜索定价的三种方法

三条各自独立发展出来的研究路线,最终都得出同一个修正办法:不要再拿赢家去跟零比,而要拿它跟"这个规模的搜索单靠运气能产出什么"去比。它们的差异在于各自如何构建这个比较对象。
PSR 与 Deflated Sharpe Ratio(Bailey & López de Prado,2012 / 2014)
**Probabilistic Sharpe Ratio(概率夏普比率,PSR)**问的问题,比"夏普比率是不是正的?"要犀利得多。它问的是:给定样本长度和收益分布的形状(偏度、肥尾),真实夏普比率超过某个基准 的概率是多少?
这里 是标准正态分布的 CDF, 是偏度, 是非超额约定下的峰度(正态分布 ⇒ ;如果这里直接代入超额峰度而不加 3,折损结果就会算错)。令 ,PSR 就只是一个有限样本显著性检验。真正的魔法在于把 选好。
Deflated Sharpe Ratio(DSR)就是把 PSR 的基准从零换成整次搜索的期望最大夏普比率后算出来的结果:
这里 是全部 N 次试验夏普比率的方差(也就是搜索本身产生的离散程度), 是欧拉-马歇罗尼常数,两个逆正态项则是对 次标准正态抽取的期望最大值的极值理论(Extreme-Value-Theory)近似。写成代码短得都不够拿出来炫耀:
def expected_max_sharpe(sr_variance, N, mean_sr=0.0):
"""E[max of N independent SR estimates ~ N(mean_sr, sr_variance)]
(Bailey & LdP 2014)."""
g = EULER_MASCHERONI # 0.5772156649
a = norm.ppf(1.0 - 1.0 / N) # Z^{-1}(1 - 1/N)
b = norm.ppf(1.0 - 1.0 / (N * E)) # Z^{-1}(1 - 1/(N e))
return float(mean_sr + np.sqrt(sr_variance) * ((1.0 - g) * a + g * b))
然后 DSR 就只是用这个折损后的基准算出的 PSR:
def deflated_sharpe(sr_max, sr_estimates, T, skew=0.0, kurt=3.0, N=None):
"""DSR = PSR(sr_max, SR0). Returns (dsr, sr0)."""
v = float(np.asarray(sr_estimates).var(ddof=1)) # dispersion of the search
m = float(np.asarray(sr_estimates).mean())
if N is None:
N = len(sr_estimates)
sr0 = expected_max_sharpe(v, N, mean_sr=m)
return psr(sr_max, sr0, T, skew, kurt), sr0
DSR 本身是一个概率。当 时,我们宣布一次发现:赢家的真实夏普比率以 95% 的置信度超过了运气所能给出的最佳预期。注意 里埋着一个承重的假设:这 次试验被当作相互独立。第 5 幕整节讲的就是当它们并不独立时会发生什么。
Harvey-Liu 折价法(2015)
Harvey 和 Liu 从多重检验 p 值修正的角度攻克同一个问题——这是那套经典机制的用武之地:"我跑了 M 次检验,别让我自己骗自己"。把 个单次检验 p 值排序为 ,然后把它们放大:
Bonferroni 是那件笨重的工具(把每个 p 值都乘以 ,控制任意假阳性的概率);Holm 是它那个功效一致更高的降阶版本。第三种,Benjamini-Yekutieli(BHY),控制的是假发现率——你的拒绝结果里预期有多大比例是错的——而且关键在于,它在检验之间存在任意依赖关系的情况下依然成立,靠的是分子里的调和归一化项:
这个数,就是 BHY 为了不去假设你那 1,000 次试验相互独立所付出的代价——它把 FDR 阈值放大了一个按 增长的倍数。"折价"本身才是那个点睛的指标:把修正后的 p 值换算回夏普比率,报告出你不得不从原始夏普比率里削掉多少。折价 100% 意味着赢家完全可以用多重检验来解释;15% 意味着它基本上还站得住。
White's Reality Check 与 Hansen's SPA(2000 / 2005)
第三种工具完全不做任何分布假设。White 的 Reality Check 拿每条规则的真实收益,构造出规则间取最大值的统计量,然后直接对它的零假设分布做自助法:
这里 是规则 相对基准的平均表现。它用平稳自助法(Politis-Romano——随机长度的分块,让序列相关性在重采样中得以保留)对收益重采样,把每次抽取重新居中,使其按构造满足零假设,在每次抽取上重新计算最大值,并把 p 值报告为超过观测最大值的自助法最大值所占的比例。Hansen 的 SPA 从两个方向锐化了 RC:学生化(把每条规则的均值除以它自己的标准误,这样一条方差异常大的规则就没法劫持最大值)以及对零假设做一次一致的、依赖样本的重新居中。我们的实现加上了学生化,但没有做完整的一致重新居中步骤——所以本文中出现的任何 SPA 式p 值,都应读作学生化的 Reality Check,而不是完整的 Hansen SPA。DSR 问的是"这个赢家在这次搜索内部是不是特别?",Reality Check 问的则是"在诚实地把我试过多少条规则算进去之后,最好的那条规则还能不能跑赢现金?"——而且它通过自助法天然地处理了规则之间的相关性,完全不需要去数试验次数。记住这个区别;最后一节就建立在它之上。
第 3 幕——校准就是全部的证明

一个什么都不宣布发现的方法,假发现率也会是零——但它毫无用处。所以,检验这些工具唯一有意义的方式是双面的:在已知零假设的数据上,它们必须把假发现率控制在 或以下;在已知优势的数据上(下一节),它们依然得能触发。本节讲的是前半部分。
跑 2,000 次独立搜索,每次都在 1,000 个零优势策略上进行,统计每种方法宣布发现的次数。这个次数除以 2,000,就是假发现率——而因为真相是没有优势,所以每一次"发现"都是假的:
| 检验 | 假发现率(α = 0.05) |
|---|---|
| 朴素显著性检验 | 1.000 |
| Deflated Sharpe Ratio | 0.001 |
| Harvey-Liu——Bonferroni | 0.057 |
| Harvey-Liu——Holm | 0.057 |
| Harvey-Liu——BHY | 0.007 |
| White's Reality Check | 0.022 |
每种有理论依据的方法都落在 5% 这条线上或附近——两个 FWER 折价法略高一点,DSR/BHY/RC 略低一点——而朴素检验则停在 100。(Bonferroni 和 Holm 在这里打印出一样的 0.057,这不是巧合:对于单一的最佳策略而言,Holm 的第一步是 ,按构造就和 Bonferroni 完全相同,所以这是同一个确认,而不是两个独立确认。)但整项研究里最深刻的数字不在这张表里——而是产出 DSR 那一列的折损基准。在各次零假设搜索上取平均, 算出的单期值是 0.1030,年化后为 1.63(推算:)——正是噪声赢家平均报出的那同一个 1.63(1.63)。这不是巧合;这正是整个想法在起作用:
折损后的基准线,恰好就落在噪声上限上。 DSR 并不要求搜索赢家去打败零。它要求赢家打败单靠运气、从这个规模的搜索里所能拿到的最好成绩——这里就是年化 1.63。一个刚好打平噪声上限的赢家,DSR 得分 ≈ 0.5(跟抛硬币一样),这就是为什么零假设下的平均 DSR 是 0.495,而不是一个很小的数。要成为一次真正的发现,赢家必须打穿 1.63 而且还要多出不少——多到足以把 PSR 推过 0.95。
这重新定义了整件事。朴素检验衡量的是离零有多远;任何一次搜索都能轻而易举地跨过这道坎,这就是它没用的原因。DSR 衡量的是离噪声上限有多远,而跨过这道坎才是真正困难的——本来就该如此。Harvey-Liu 折价法和 Reality Check 走的是不同的路,却达到了同样的控制水平(BHY 用 的放大系数,RC 用自助法给出的最大值分布),最终都落在同一个区间里:0.001 到 0.057,处在 或其附近。Bonferroni/Holm 的 0.057 比 5% 这条线略高一点点,但也就一点点:在 2,000 次蒙特卡洛搜索的规模下,FDR 估计值在 0.05 附近的标准误约为 0.005,所以 0.057 大约高出 1.4 个标准误——这是蒙特卡洛噪声,不是保证失灵。而且"控制 FWER"本来就是一个渐近意义上的承诺,在 时并不是逐比特精确的。
第 4 幕——功效:它还留得住真实的优势吗?

控制假发现只是检验的一半——一个疑神疑鬼、什么都拒绝的方法能拿到满分 0.000,却毫无用处。另一半是:当真实优势确实存在时,DSR 找得到它吗?
植入一个优势试试。在 1,000 个策略组成的一片田地里,让其中 25 个带上强度已知的真实优势,其余留作噪声,然后跑搜索,看 DSR 会不会标出这个赢家。把植入的优势从弱到强扫一遍,检验功效画出一条干净的 S 形曲线(假阳性率全程维持在 ~0):
| 植入的真实夏普比率(年化) | DSR 检验功效 | DSR 假阳性率 |
|---|---|---|
| 0.79 | 0.005 | 0.000 |
| 1.27 | 0.090 | 0.000 |
| 1.90 | 0.651 | 0.000 |
| 2.54 | 0.998 | 0.000 |
| 3.17 | 1.000 | 0.000 |
看看曲线在哪里转折。低于噪声上限时——真实年化夏普比率 0.79,远低于 1.63——DSR 只有 0.5% 的时候会触发,正确地拒绝承认它:这么弱的优势,跟一次 1,000 次试验的搜索所产生的运气,真的分辨不出来,硬说能分辨出来,不是功效强,而是不诚实。刚过上限附近,曲线陡峭爬升(1.27 处 0.09,1.90 处 0.65)。到年化夏普比率 2.54 时,功效是 0.998;到 3.17 时是满分的 1.000。强优势基本每次都能被留住,假阳性率始终钉在零,而 50% 功效的交叉点落在年化夏普比率约 1.73 处(由 1.27 与 1.90 两行插值推算)——刚好高于 1.63 的噪声上限,正是一条诚实的基准线该落在的地方:优势开始跑赢一次 1,000 次试验的搜索所能凭空捏造出来的东西的那个点。
这才是你真正想要的性质,用 S 曲线来表述就是:噪声上限以下的优势被正确地判定为运气;舒舒服服高于上限的优势则以逼近一的功效被留住。 相比之下,朴素检验即便在真实夏普比率只有 0.79 时也能"检测"到 67% 的植入优势——但这个数字毫无意义,因为我们已经看到它对一个根本不存在的优势也能 100% 地"检测"到。一个什么都触发的检验没有功效可言;它没有任何区分能力。DSR 用一点点对边缘优势(0.79 和 1.27 那两行)的敏感度,换来了真正重要的东西:它给出的发现是真的。
第 5 幕——从业者的陷阱:相关网格

目前为止用的都是相互独立的策略——这是最干净的设定,也是 DSR 的独立性假设完全成立的那种设定。真实的参数网格可不是这样,而这正是一个工具一旦被天真地使用,就会变成一种新的犯错方式的地方。
拿一次诚实的移动平均线交叉搜索来说:16 种快线长度 40 种慢线长度 次试验,每次 755 次观测。这样一个网格浸透了相关性——fast=45/slow=120 和 fast=45/slow=125 几乎是同一个策略,它们的收益序列会一起动。实测 640 次试验间的平均两两相关性:约 0.61。这可不是 640 次独立的赌注。差得远了。
案例 A——随机游走(无优势):每种方法都正确地否决了它
在纯随机游走上跑这个网格。赢家看起来很诱人:参数 fast=45/slow=120,最佳年化夏普比率 0.81,单次检验 p 值 0.081。每种方法都识破了它:
| 方法 | 结果 | 结论 |
|---|---|---|
| DSR(原始 K = 640) | 0.431 | 否决(< 0.95) |
| Reality Check p | 0.570 | 否决 |
| SPA 式 p(学生化 RC) | 0.569 | 否决 |
| Harvey-Liu 折价法 | 100% | 否决 |
先看这个根本不需要任何折损就露出破绽的信号:即便是这个赢家未经修正的有限样本显著性,也就是 相对零的检验,也只有 0.918——在我们对 640 次试验中的哪怕一次做修正之前,就已经够不上 0.95 了。折损之后,它就彻底被埋了:基准是单期 ,年化约 0.91(推算:)——高于赢家的 0.81。这个最佳策略连噪声上限都够不着,DSR ≈ 0.43(比抛硬币还差),而 Reality Check、SPA 式检验和 100% 的折价率全都一致:这里什么都没有。完美。这是简单的那个案例,而它奏效了——正如我们接下来会看到的,无论我们尝试哪个有效试验数,它都始终被否决。
案例 B——一个真实的状态优势:原始 DSR 判错了
现在在一个带有真实、可利用优势的状态切换序列上跑同一个网格。赢家的信号非常强烈:参数 fast=3/slow=55,最佳年化夏普比率 3.92——这是样本内、经过挑选的夏普比率,本身就被搜索的选择效应抬高了(不是一个真实或样本外的优势),但底层的状态效应是真实的——单次检验 p 值为 ,未折损的显著性 相对零基本为 1.000。这里确实有一个真实的优势,赢家也找到了它。看看原始 DSR 还是照样否决了它:
| 方法 | 结果 | 结论 |
|---|---|---|
| DSR(原始 K = 640) | 0.748 | 否决(< 0.95)✗ 过度折损 |
| Reality Check p | 0.0024 | 确认 ✓ |
| SPA 式 p(学生化 RC) | 0.0038 | 确认 ✓ |
| Harvey-Liu 折价法 | 15% | 确认 ✓ |
原始 DSR 的 0.748 是对一个真实优势的假否决。原因就是独立性假设,这里被狠狠违反了:DSR 在构建折损基准时,把 640 次相关试验当成了 640 次独立抽取,这把期望最大值 抬高到了单期 0.221——年化约 3.51(推算:)。相对于 3.51 这道基准,赢家的 3.92 只是勉强越过,DSR 落在 0.748——够不上 0.95。有两个因素在把基准往上推:一是原始试验数(640 次"看",而不是少数几次有效的),而且试验之间还存在真实的技巧离散——有些参数组合在状态序列上确实表现更好,这拓宽了 ,把 抬到了纯粹靠运气所能达到的水平之上。两个因素朝同一个方向发力,基准最终被推得太高,因为这次搜索从来就不是真正的 640 次独立"看";它其实是少数几个独立的赌注,被重复采样了 640 次。
该给 DSR 喂的是有效试验数。上面用到的这个一行代码,是从平均两两相关性得出的一个粗略估计:
def effective_n_trials(returns_matrix):
"""N_eff = N / (1 + (N-1) * rho_bar), clipped to [1, N].
Correlated trials -> fewer independent bets."""
C = np.corrcoef(returns_matrix, rowvar=False)
rho_bar = max(np.nanmean(C[np.triu_indices(C.shape[0], k=1)]), 0.0)
N = returns_matrix.shape[1]
neff = N / (1.0 + (N - 1) * rho_bar)
return float(min(max(neff, 1.0), N))
用 和 代入,网格就坍缩成了有效 次试验(推算:),DSR 随之跳到 1.000。但先别急着为这个数字欢呼,因为它是本节全部证据里最弱的一个。在 时,折损基准会坍缩成年化 ——基本上就是试验均值,基本上等于零。这里的折损其实是被关掉了: 处的 DSR,不过是在重新报告赢家未经折损的有限样本显著性( 相对零 )而已。这个结论是从原始显著性继承来的,而不是由多重检验修正产生的。随机游走那边也有一个对称的警示:它在 处被否决,仅仅是因为那个赢家一开始独立来看就已经很勉强了( 相对零 )。如果把整个论证都押在 1.6 这个数字上,一个怀疑者完全有理由耸耸肩:你只是把修正关掉了,然后报告了底下原本就有的东西。
所以不要把论证押在单一一种估计方法上。诚实的做法——也是更有说服力的做法——是用五种不同的标准方式计算 ,然后通读整条区间上的结论。下面是把五种估计方法应用到同一个 640 次试验的信号网格上,各自对应的折损基准和产出的 DSR:
| 有效试验数估计法 | 折损基准 (年化) | DSR | 结论 | |
|---|---|---|---|---|
| 平均相关性 | 1.6 | 0.25 | 1.000 | 保留 |
| 参与率 | 2.4 | 0.43 | 1.000 | 保留 |
| PCA(95% 方差) | 16 | 1.85 | 1.000 | 保留 |
| Kaiser 准则(特征值 > 1) | 21 | 2.00 | 0.999 | 保留 |
| Cheverud-Nyholt | 370 | 3.31 | 0.845 | 否决 |
| 原始网格计数(不修正) | 640 | 3.51 | 0.748 | 否决 |
估计方法说明:平均相关性就是上面那个 的一行公式;参与率 以及 PCA-95%/Kaiser 计数,都是从相关矩阵的特征值中读出有效维度;Cheverud-Nyholt 是来自遗传学文献的一种特征值方差估计法,已知在接近等相关时会过度计数。
现在重点才真正落地,而这个重点并不是"随便什么修正都能救你"。看看那个站得住脚的中段——PCA-95%()和 Kaiser()。这两个不属于折损被关掉的那种情形;它们施加的是一道真实的年化 基准,1.85 到 2.00——一次实实在在的折价,远高于噪声,是对 16-21 次有效"看"的真正多重检验惩罚。而 3.92 这个优势依然跨了过去(DSR 1.000 和 0.999)。只要 低于 144.8(从交叉点推算),这个信号在任何估计下都能扛过 DSR;只有在 Cheverud-Nyholt 给出的 下才会失败——而这个估计法在试验接近等相关时被证明会过度计数——即便是那个原始、未经修正的 640 计数,也只是把 DSR 压到 0.748,而不是压到零。把随机游走的赢家放进同样这五种估计法里跑一遍,它在每一种估计下都被否决(找不到任何一个高于 1 的 能让它活下来)。这才是真正的结果:不是靠一个幸运的数字,而是一个在整条标准有效试验数估计区间上都稳定的结论——这比只相信其中任何一个数字都要强得多。
关于那个最粗糙的估计法,还有一个技术性的警示,它解释了为什么这个估计法处在软弱的那一端: 本质上是相关变量均值的方差缩减因子(在相关性 下,取平均究竟能给你带来多少好处)。而 DSR 的基准是一个极值量——试验的期望最大值——所以拿一个均值方差收缩量当作试验数,在功能上是不匹配的:方向是对的(相关性越强 ⇒ 有效试验数越少),但它并不是最大值分布实际依赖的那个量。这正是为什么区间中段那些基于特征值的估计法读数更值得信赖,也正是为什么真正应该交付的是这整条区间,而不是某一个点。
教训:两种工具都要用,还要喂给 DSR 正确的 N

案例 B 得出两条结论,两条都承重:
- 只要试验之间存在相关性,原始网格规模对 DSR 来说就是错误的 N——而单独任何一个有效 N 也都不是正确答案。 把 640 代入一个假设独立性的公式会过度折损:它捏造出一个远高于搜索实际达到的噪声上限,把真实优势埋在了它底下。DSR 需要的是有效试验数——但修正的办法不是去相信某一个估计法(尤其不是那个最粗糙的、在 附近就把修正关掉了的那个)。而是要通读整条标准估计法组成的区间(这里是 1.6 到 370),看看结论是否稳定。对这个优势而言,结论是稳定的:在折损真正起作用的每一处都被保留下来(在 - 处有一道真实的年化 1.85-2.00 基准),只在一种会过度计数的估计法下才失败。一个在整条区间上都稳定的结论,比任何单一数字都要有说服力得多。
- 把 DSR 和 Reality Check 配对使用。 注意到 Reality Check 及其 SPA 式(学生化)表亲,完全没有对试验数动任何手术,就在案例 B 上判对了(p = 0.0024 和 0.0038)——它们通过平稳自助法天然地处理了依赖关系,因为它们重采样的是真实的、相关的收益序列,而不是去数假想中的独立赌注数量。这就是整个有效 N 乱局的裁决者:RC 根本不需要 。DSR 和 RC 回答的是不同的问题:DSR 问的是"这个赢家在这次搜索内部是不是特别?"(需要知道这次搜索到底进行了多少次有效的"看");RC/SPA 式问的是"数据窥探之后,最好的那条规则还能不能跑赢现金?"(并直接从数据本身读出依赖关系)。这两个你都需要。当它们意见不一致时——就像这里原始计数的 DSR 和 RC 那样——这种分歧本身就是诊断信号:它通常意味着你的 错了。
这和我们的速度阶梯与IPC 税两项研究从工程一侧不断撞上的,是同一个结构性警示——一次跑了巨大相关网格的快速搜索,并不能给你买来数量巨大的独立赌注,把网格规模当成试验数会同时骗过你的优化器和你的显著性检验。即将发布的姊妹篇回测过拟合概率从重采样一侧(CSCV)攻击的是同一种选择偏差,也和这里的一切自然配对:DSR 给赢家定价,PBO 给流程定价。
诚实说明
三条直白说出来的警示,因为一项受控研究的全部意义,就在于不要把它过度包装。
- 这些收益是合成的。 校准和功效实验用的是独立同分布正态分布,真实优势案例用的是状态切换过程——这么选是为了受控的真实基准,不是为了贴近真实市场。真实收益是肥尾的、自相关的、非平稳的,而 PSR 的偏度/峰度项,存在的目的正是为了处理这三者中的第一个。这里交付的是经过校准的方法,而不是一个策略:我们只能通过在一份已知什么都没有可发现的数据上运行一个检验,来证明它确实控制了假发现。而这就需要人为构造出真实基准。
- 没有哪种有效 N 估计法是权威标准——这正是我们报告了五种的原因。 平均相关性那个一行公式 便于审阅者理解,方向也是对的(相关性越强 ⇒ 有效试验数越少),但它是均值的方差缩减因子——在功能上与 DSR 的最大值基准不匹配——而且在 附近会把折损完全关掉。基于特征值的估计法(参与率、PCA-95%、Kaiser)匹配得更好,但依然是启发式的,而 Cheverud-Nyholt 在等相关下会过度计数。更完整、更有理论依据的做法是试验聚类(Bailey & López de Prado 的 DSR 附录 3):按相关结构对试验分组,数聚类数而不是把一切都坍缩成一个标量。我们报告整条区间,正是因为这个选择本身还没有定论——一个在全部五种估计法下都稳定的结论才是诚实的主张;一个依赖于挑选某一种估计法的结论则不是。
- 这里的自助法是学生化的 Reality Check,不是完整的 Hansen SPA,而且不同实验的重采样次数不一样。 本文中出现的"SPA 式",指的都是带有逐规则学生化的 White's Reality Check;Hansen 那套完整的一致、依赖样本的重新居中并没有实现。校准实验的假发现率,用的是 400 次搜索、每次搜索 500 次平稳自助法重采样;两个案例研究里的 RC/SPA 式 p 值,各自用了 5,000 次重采样。平均分块长度全程为 20(Politis-Romano),,年化按每年 252 个周期计算。改变这些设置,小数点第三位的数字会变;但故事本身——朴素检验的 1.000 对上有理论依据方法的 0.001-0.057、一条恰好在噪声上限之上就达到 50% 功效的 S 曲线,以及一个相关网格陷阱,其结论必须通读整条有效 N 区间——不会变。
要点总结
- 参数搜索是一台多重检验机器,而朴素显著性检验对此视而不见。 在 1,000 个零优势策略上,最佳年化夏普比率平均为 1.63,单次检验 p 值中位数为 0.000686——而"这显著吗?"这个检验100% 的时候都会宣布发现(假发现率 1.000)。一个凭空而来的漂亮夏普比率,被一个从一开始就问错了问题的检验,认证为"显著"。
- Deflated Sharpe Ratio 把球门从零挪到了噪声上限。 DSR 拿赢家去比的不是零,而是 ——这个规模的搜索靠运气所能拿到的最佳预期——在零假设情形下年化落在 1.63,正好就是噪声赢家平均所在的位置(推算:)。它在零假设下的假发现率是 0.001;Harvey-Liu 折价法(Bonferroni/Holm 0.057,BHY 0.007)和 White's Reality Check(0.022)走的是另外的路,却达到了同样的控制水平。
- 它留得住真实的优势。 DSR 的检验功效画出一条 S 曲线,在年化夏普比率约 1.73 处达到 50% 功效——刚好高于 1.63 的噪声上限:真实年化夏普比率 0.79 处为 0.005,1.90 处为 0.651,2.54 处为 0.998,3.17 处为 1.000,假阳性率全程 ~0。上限以下的优势被正确地判定为和运气无法区分;上限以上的优势则以逼近一的功效被留住。
- 相关网格会打垮原始 DSR——救它的不是某一个有效 N,而是整条区间。 在一个 640 格的移动平均线交叉网格上(平均两两相关性约 0.61),原始计数的 DSR 假否决了一个真实的(样本内挑选出来的、年化 3.92)优势(0.748 < 0.95),原因是 640 次相关试验并不是 640 次独立赌注。但修正的办法不是找出一个神奇的 ——在最粗糙的估计下(),折损基本被关掉了(基准约年化 0.25),DSR 只是在附和原始显著性。真正的证据在于,这个优势在整条标准估计法的区间上都被保留——在 1.6/2.4/16/21 处 DSR 分别为 1.000/1.000/1.000/0.999,其中包括在站得住脚的 PCA-95%/Kaiser 中段处一道真实的年化 1.85-2.00 基准——只要 就能存活,只在 Cheverud-Nyholt 那个过度计数的 370 下才失败。随机游走则在每一种估计法下都被否决。要读整条区间,而不是某一个点。
- 把 DSR 和 Reality Check 配对使用,因为它们回答的是不同的问题。 Reality Check 及其 SPA 式(学生化)表亲,没有对试验数动任何手术,就确认了这个真实优势(p = 0.0024 和 0.0038)——它们通过平稳自助法天然地处理了依赖关系,而这恰恰是当有效 N 存在争议时的裁决者。DSR 问的是"这个赢家在这次搜索内部是不是特别?";RC/SPA 式问的是"数据窥探之后,最好的那个还能不能跑赢现金?"两者之间的分歧,就是你的 错了的信号。两个都要跑。
搜索的赢家在被证明清白之前,都是有罪的。朴素 p 值并不能证明清白——它是搜索自己那份被虚高了的证词,它会以十二个零的信心,为纯噪声担保。把基准折损到运气所能给出的水平,诚实地数出你的有效试验数,再用自助法对最大值求一个第二意见。能同时跨过这三道坎的,也许才是真的。只跨过朴素那一道坎的,不过是一千个抛硬币的人里最高的那一个。
完整的实验——零假设校准框架、植入优势的功效扫描、相关网格搜索,以及本文中每一个都能从同一个确定性脚本重新生成的数字——都收录在配套论文中,见 deflated-sharpe.marketmaker.cc,代码与数据见 github.com/suenot/deflated-sharpe-search。
Authors
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.