Jackhai的博客

回测里的幸存者名单

回测最容易骗人的地方,不是指标。

是名单。

你以为自己在问:“这个策略在过去一段时间表现如何?”

但如果标的名单不对,实际问出来的问题可能是:“这个策略在一批事后看起来还不错的标的上表现如何?”

这两个问题差别很大。

当时能看到什么

实盘交易不是面对一个抽象市场。

系统在每个时刻能交易什么,取决于当时的筛选规则、数据状态、交易所状态、流动性、风控限制,以及程序实际保存下来的 universe。

很多回测会默认跳过这一层。

拿一段历史 K 线,拿当前可交易标的列表,套上策略逻辑,跑出收益曲线。这个流程看起来很自然,因为代码能跑,图也能画出来。

但它隐含了一个很强的假设:今天这份标的列表,也代表过去那个时间点系统能看到的标的。

这个假设通常不成立。

一只标的今天还在列表里,可能是因为它后来活下来了、涨上来了、成交量变好了。一只标的今天不在列表里,可能是因为它后来跌没了、下架了、流动性变差了,或者只是后来不符合筛选条件了。

如果回测时只使用今天的名单,历史就被重新筛选了一遍。

这就是幸存者偏差。

幸存者偏差不一定表现为夸大收益

很多人提到幸存者偏差,会下意识认为它一定让回测收益变好。

不一定。

在股票市场里,长期留下来的公司往往更强,剔除退市公司后,回测结果容易变得更好。这是最典型的情况。

但在短线或加密市场里,情况更复杂。

有些后来消失的标的,在当时可能有极强的波动和流动性,正是短线策略最容易赚钱或最容易亏钱的地方。把它们删掉,不一定让收益更好,也可能让风险看起来更低,或者让策略错过当时真正的交易机会。

所以问题不只是“收益有没有被高估”。

更根本的问题是:回测对象已经不是当时那个市场。

只要对象变了,后面的收益、回撤、胜率、交易次数,都只能算在另一个问题上。

这也是为什么我现在更关心 universe 的时间一致性,而不是只关心回测程序能不能跑起来。

真实 universe 比完整历史更重要

听起来最理想的回测,是拥有全市场完整历史数据。

这当然好。

但对一个实盘系统来说,还有一个更具体的问题:线上系统当时到底选择了哪些标的?

全市场历史回答的是“理论上可以交易什么”。

真实 universe 回答的是“我的系统当时实际会看什么”。

这两个答案都重要,但它们不是同一个东西。

如果我想评估一个策略思想在整个市场上的普适性,全市场历史更有用。

如果我想评估一次策略改动对当前系统有没有帮助,真实 universe 更有用。

因为实盘不会在全市场里手动挑最适合的标的。实盘只会按照系统当时的筛选结果运行。

策略改动最终也是作用在这个筛选结果上。

所以对我来说,真实 universe snapshot 的意义不是让回测更华丽,而是让回测问题更诚实。

它把问题从:

“这个策略在历史上表现怎么样?”

改成:

“如果当时系统就是这样运行,这个改动会让结果变好吗?”

后者更窄,但更有用。

复制了表,不等于用了历史

做这件事还有一个坑。

你把历史 universe 保存下来了,不代表回测真的用了它。

程序里很容易出现这种情况:

这类错误很隐蔽。

因为结果仍然会正常产出。没有异常,没有崩溃,甚至指标看起来还挺合理。

但你验证的已经不是历史场景。

所以回测需要一个明确的验收点:它必须告诉你本轮 universe 的来源是什么。

不是“我有没有复制历史数据”。

而是“本次计算实际使用的 universe source 是不是历史记录”。

这类检查看起来很琐碎,但它比多跑十个指标更重要。

因为如果样本源错了,指标越多,只是错得越精细。

回测要尽量像当时的系统

我现在对回测的要求变得更朴素:

尽量像当时。

不是尽量复杂,也不是尽量全。

当时系统用什么 universe,就用什么 universe。

当时系统按什么时间粒度看数据,就按什么时间粒度。

当时系统有什么风控和仓位限制,就保留这些限制。

当时系统不会知道后面哪只标的会爆发,回测也不应该知道。

这个原则看起来简单,但实际很容易被破坏。

比如一次策略优化里,为了方便调试,你临时扩大了标的池。又比如为了让样本更多,你把 current latest universe 作为 fallback。再比如为了避免空结果,你在历史缺失时自动退回当前配置。

这些 fallback 在普通业务系统里可能是容错。

在回测里,它们可能是污染。

因为交易回测的目标不是“尽量跑出结果”,而是“尽量回答正确的问题”。

如果回答不了,应该明确失败,而不是悄悄换一个问题继续回答。

为什么这件事以前没那么重要

手工做策略时,很多东西其实在脑子里。

你知道自己当时看的是哪几只票,知道某个机会为什么没做,知道某个标的当时流动性很差。即便复盘不严格,人的记忆也会补上一些上下文。

系统化以后,这些上下文会消失。

程序只认数据。

如果没有把当时的 universe 存下来,过几天再回头看,就只能猜。

工具越自动化,越不能依赖“我大概记得”。

因为自动化系统会把很多微小决策放大:一个筛选条件、一个 fallback、一个默认值,都会影响后面的交易路径。

所以真实 universe snapshot 本质上不是一个回测功能。

它是记忆。

它让系统记住自己当时看见的市场,而不是让今天的你替昨天的系统重新选择一次市场。

小结

回测不是把策略放进历史行情里跑一遍。

更准确地说,回测是在重建一个过去的决策环境。

行情只是环境的一部分。

标的名单也是环境的一部分。

执行约束也是环境的一部分。

如果 universe 错了,回测就不是轻微失真,而是问题本身变了。

所以我现在更愿意先把这类基础问题做扎实:保存当时的 universe,确认回放真的使用它,在结果里暴露 source,而不是只看最后的收益曲线。

收益曲线很直观。

但在它出现之前,先要确认一件更基础的事:

你回测的,到底是不是当时那个市场。


本文创建日期: 2026-06-14

最后更新日期: 2026-06-14