← 返回文章库

样本内外与前视偏差:回测最容易骗自己的两个地方

2026-07-08 · L5

有段时间我做过一个”神策略”——用财务指标选股,回测十年,年化能到35%,最大回撤只有12%,那条曲线漂亮得我自己都有点不敢信。我把它当宝贝一样雕琢了两周,信心满满地拿小仓位实盘。结果第一个月就亏了,第二个月接着亏,三个月下来回撤直接干到了回测里从没出现过的深度。我翻来覆去查代码,查了整整一个周末才找到问题:选股用的”财报数据”里,有一栏是季度净利润,而我在回测里是用”财报公布当天”就直接拿这个数字去做当天的选股决策——可现实里,那份财报要再过一两周才真正公布。换句话说,我的策略在历史上,一直在用还没发生的未来帮自己选股。这不是策略厉害,这是我自己提前把考试答案抄进了草稿纸,回测当然能考满分。

这个坑在量化圈有两个正式的名字:一个叫样本内/样本外,另一个叫前视偏差。它们性质不一样,但共同点是:都会让你在电脑上看到一个漂亮到不真实的策略,而这份漂亮,纯粹是”偷看”换来的。这篇就把这两个最容易让人栽跟头的地方讲透。

样本内 vs 样本外

先说样本内和样本外,这是个纪律问题,不是技术问题。

样本内,就是你用来开发、调试、优化策略的那段历史数据。你在这段数据上试参数、加条件、改逻辑,一遍一遍地跑,直到策略在这段数据上表现出色。样本外,则是你专门留出来、开发过程中完全不碰的一段数据,等策略定稿之后,才第一次拿去检验。

问题出在哪?如果你在同一批数据上,既拿它来”出题”(调参数),又拿它来”打分”(算收益),那这场考试从头到尾就是自己跟自己玩——分数再高也说明不了什么。这跟学生自己出模拟题、自己对着答案给自己判满分是一回事:题目本来就是照着答案反推出来的,能不满分吗?可一到真正的考场,题目变了,答案是提前没见过的,原形立刻毕露。策略也是同样的道理:在样本内数据上反复打磨出来的参数,天然就是”贴合”这段历史的,拿去检验这段历史当然表现好,这根本证明不了它在没见过的行情里也能一样好。关于策略在历史数据上”贴合过头”是怎么发生的,可以先看 回测与过拟合 里对过拟合的解释,这两个问题是一体两面。

正确的做法,是把数据老老实实切成两段。假设你手上有2015到2024这十年数据,规矩是这样的:只拿2015到2021去开发——试逻辑、调参数、改规则,想怎么折腾都行;但2022到2024这三年,从头到尾锁起来不许看,连眼神都不许瞟过去。等策略在样本内定稿了,才第一次拿到2022到2024上跑一遍,看看结果如何。

这里最容易松懈的地方,是”只能用一次”这条纪律。很多人跑完样本外发现结果不理想,心里一咯噔,忍不住想:“是不是有个小地方没调好?”于是回头改改参数,再跑一次样本外。这么来回两三轮之后,那段所谓的”样本外”数据,其实早就被你反复看穿、间接拿去调参了——它已经名存实亡地变回了样本内。样本外真正的价值,就在于它对策略而言是”没见过的”;一旦你为了让它好看而回头改策略,这份价值就被你亲手废掉了。所以纪律必须提前定死:样本外只跑一次,不管结果好坏,都得诚实接受,而不是拿它当第二次调参的机会。

前视偏差:用了当时根本拿不到的信息

如果说样本内外考验的是”纪律”,那前视偏差(look-ahead bias)考验的就是”细节”——它比过拟合更隐蔽,因为很多时候你根本意识不到自己在犯错。

前视偏差,指的是回测里用到了某个时间点上,现实中根本还不存在或还没公布的信息。 我开头那个财报的例子就是标准的前视偏差:季度报表要延后公布,但我的回测程序在”财报归属的那个季度末”当天就直接读到了数字,提前用上了未来才会出现的信息。历史数据库里,这个数字确实是”贴”在那一天的,但现实里那一天根本没人能看到它——这份数据表面上没问题,坑就藏在时间对不上这一层。

前视偏差最常见的几种形式:

  • 用当天收盘价决定当天的买卖:很多新手写回测,逻辑是”今天收盘价触发买入信号,就按今天收盘价成交”。可现实里,你是看到收盘价之后才能下单,而下单最快也要等到下一个交易时段。回测里这一秒的时间差被抹平了,等于你在用”已经知道的结果”去做”当时还没结果”的决策。
  • 用后来修正过的数据:很多财经数据库会对历史数据做事后修正——GDP初值后来会被修订、公司财报会有更正版。如果你的历史数据库存的是”修正后的最终版”,而当年市场上流通的其实是”未修正的初版”,那你回测用的信息,是当年的交易者根本不可能拿到的。
  • 用退市、并购之后才确定的名单:比如你现在去筛选”沪深300成分股”,拿这份今天的名单去倒推十年前的选股,这份名单本身就是用后来发生的事(谁被剔除、谁被纳入)反推出来的,十年前根本不存在这份名单。

这几种情况有个共同特征:数据本身没有错,错的是时间戳对不上。回测系统看到的是”某月某日发生了什么”,但没有对齐”这个信息在现实里是哪一天才真正可以被交易者获取的”。这道时间差,肉眼很难发现,往往要等实盘验证才会暴露——就像我那次,足足亏了三个月才揪出来。

还有哪些”偷看未来”的坑

前视偏差和过拟合还有几个近亲,都是同一类问题的变体,值得一并列出来提防:

  • 幸存者偏差:如果你用来选股、测策略的股票池,是”今天还在交易的公司名单”,那些已经退市、被摘牌、清盘倒闭的公司早就被悄悄抹掉了。用这样一份”只剩下活下来的人”的名单去测历史,相当于拿全班”考上大学的学生”去算全班的平均分,数字自然好看得不真实。
  • 数据快照没有对齐:类似前面提到的财报延迟,任何”事件发生日”和”信息实际可得日”之间有时间差的数据,都要小心核对。财报、评级调整、指数成分调整,几乎都存在这个延迟,直接拿”事件发生当天”去做决策,大概率就踩了前视偏差。
  • 用全样本算出来的统计量去筛选区间:比如你先看完全部十年数据,算出”这只股票这十年年化最高”,然后拿它去做样本内的开发对象——这个”挑选”动作本身,就已经用到了你本该看不到的样本外信息,选股这一步就被污染了。

这几个坑的共同本质是一样的:你在某个时间点做决策时,手里握着的信息,比现实里那个时间点该有的信息更多。 只要多出来的这一点信息里藏着未来的答案,回测就会变得比真实交易容易,漂亮得毫无意义。

怎么防

这几类坑没有一劳永逸的解药,但有几条实操性很强的习惯,能把风险压到最低:

  • 样本外只留一次机会:开发阶段就把数据切好、锁死,策略定稿之前坚决不碰样本外那一段,验证完了不管好坏都不回头改。
  • 做滚动验证(walk-forward):如果担心一次性切分不够稳,可以用滚动的方式反复验证——比如用2015到2018开发,拿2019验证;再把窗口往后挪,用2016到2019开发,拿2020验证,依此类推。这样能看到策略在不同时间段切换时,是不是每一段都还站得住,而不是只靠运气蒙对了一次切分点。
  • 给每条数据标好”实际可得时间”,而不是”事件发生时间”:财报数据要按公告日对齐,不要按报告期对齐;成分股名单要用”当时那一天”的历史名单,而不是今天倒推的名单。这条最琐碎,但也最容易被忽略,值得在写回测代码时专门花时间核对每一个数据源的时间戳逻辑。
  • 测试环境里模拟”信息延迟”:如果拿不准某个数据到底有没有延迟公布,干脆保守处理,人为往后错开一两天甚至更久再让策略”看到”它。宁可保守到漏掉一点点收益,也不要乐观到偷看了未来。
  • 对幸存者偏差保持警惕:选股票池时,主动确认数据源是否包含已退市、已摘牌的历史成分,而不是默认”能查到的就是全部”。

小结

样本内外和前视偏差,说到底都是同一件事的不同表现:回测的可信度,建立在”当时的你,只能看到当时该看到的信息”这个前提上。 只要这个前提被打破——不管是因为你在同一批数据上又出题又判分,还是因为某个数据源悄悄让你提前看到了未来才有的数字——回测就会变成一场马后炮式的表演,曲线越漂亮,离真相就越远。

[!pitfall] 任何形式的”未来函数”,都会让回测从”检验策略”变成”马后炮式复盘”——你不是在测策略有没有用,而是在验证”如果我提前知道答案,能考多高分”。这个分数再高,对判断策略未来能不能赚钱,没有任何参考价值,反而会给你一份虚假的信心,让你在实盘里交更贵的学费。

我常提醒自己的一句话是:回测的意义,不在于让曲线好看,而在于诚实地模拟当年那个只能看到当年信息的自己,会怎么做决策。如果做不到这份诚实,回测跑得再久、曲线画得再顺滑,也只是一份自己写给自己看的满分答卷。对回测方法论感兴趣的话,可以回头看看 回测与过拟合 里过拟合的部分,再配合本文的样本外纪律和时间对齐习惯一起用,能少踩很多这类”看不见的坑”。想系统梳理量化这条路的知识框架,也可以从 L5 量化投资 的目录里找到相关内容。


本文仅为投资教育科普,不构成任何投资建议。回测方法本身存在局限,历史数据不代表未来表现,投资有风险,决策需谨慎。