跳转至

第 16 课 回测为什么会显得过分完美

许多严重问题不会让程序停止。它们会安静地改善收益、降低回撤,再把一条令人信服的曲线交给研究者。

适合谁已经会阅读回测账本与成绩单的读者
前置知识第 10、14、15 课,理解数据时间、成交与稳定性
建议用时110 分钟,可分两次完成
本课成果使用一张排雷清单检查未来信息、幸存者、反复选择、成交和报告偏差

回测曲线像冰山,水面下藏着未来数据、成本、过拟合、流动性与市场变化

水面上的净值曲线只是最终输出。水面下的每一层都可能在程序无报错的情况下抬高结果,因此审查必须沿着数据、规则、订单和报告逐层下潜。

一次完美买点暴露了时间矛盾

小岚写下一条规则。每天最低价低于过去五日平均价时,就按当天最低价买入。回测几乎每次都抓住日内低点,曲线平稳上升。这个结果的问题不在计算速度,也不在最低价这一列是否存在,而在同一条规则要求研究者同时站在一天结束和一天中途。

日内最低价要等全天交易结束后才能确定。某个价格在上午出现时,参与者不知道下午是否会出现更低价格;等收盘后确认它确实是最低点,这个成交机会早已过去。程序使用完整一天的信息作出判断,又回到当天最便宜的时点成交,相当于让过去的账户获得后来才知道的答案。

这类让历史决策使用未来信息的错误叫作前视偏差。代码中直接引用后一天价格、使用当天完整高低价决定当天早先交易,常被中文研究者称为未来函数。程序依然能完成每行运算,所以测试“是否运行成功”无法发现它,必须检查每列最早可见时间与每笔订单的先后。

偏差与普通程序错误有什么区别

程序把买入数量写成负数,可能让账本关系立刻对不上,这类错误往往能通过小测试定位。偏差则会系统性改变研究样本或可见信息,使结果朝某个方向倾斜。它不一定来自故意作弊,常常隐藏在方便的数据处理、参数选择和报告习惯中。

未来信息通常抬高信号准确度,幸存者名单提前排除失败对象,反复试验提高挑中幸运冠军的概率,理想成交让费用与未成交消失,只展示最好时期又把失败证据藏起来。几类偏差可以同时存在,修好一处日期移动不能让整项研究自动可信。

数据泄漏比直接引用明天价格更隐蔽

数据泄漏表示模型、规则或数据处理获得了在真实决策时不该拥有的信息。直接把未来收益放进输入是最明显的一种,使用整段历史计算清洗阈值、选择特征或修订旧数据也会泄漏。前视偏差强调时间方向,数据泄漏是更宽的概念,它还包括答案通过预处理或分组方式间接进入研究。

泄漏位置 程序做了什么 历史决策为何做不到
信号与成交 当日收盘生成信号,又按同日开盘或最低价成交 成交时完整收盘与最低价尚未形成
输入与答案 预测未来五日结果,却把未来价格变化放入输入 决策时还没有未来五日价格
数据清洗 使用全时期平均值、分位数或标准差处理早期数据 早期阈值吸收了后来年份分布
特征筛选 先用完整历史挑出最相关字段,再切分时间 字段选择已经看过后期答案
数据版本 用后来修订的财务和宏观数值替换初值 当时市场只能看到第一次发布版本
行业与成分 用今天的行业分类和指数成员回填多年历史 过去参与者不知道以后怎样调整

检查数据泄漏可以采用“信息护照”。每一列写明它描述的时期、最早可见时间、计算使用的原始列,以及哪些历史区间参与了参数估计。每笔订单再写决策冻结时间。字段最早可见时间晚于决策时间时,它就不能参与该决策。

预处理也属于研究模型。假设研究者用全部十年收益的均值与标准差把每一天标准化,第一年的数值已经吸收后九年分布。正确做法是在当时允许使用的早期数据中计算处理参数,再把这套参数应用到随后的数据;时间向前推进时,可以按照事先规则更新。

幸存者偏差会替过去避开失败对象

设想十年前有五家公司,今天只剩三家正常交易,另两家分别退市和被低价收购。研究者下载今天的股票清单,再回到十年前选股,退市与被收购公司从一开始就没有进入候选池。程序仿佛提前知道谁能活到研究终点。

若三家幸存公司的十年结果分别为 80%、40% 和 20%,简单平均为约 46.7%。另外两家公司若分别亏损 100% 和 70%,把它们放回最初五家公司后,平均结果会降到负 6%。这个数字只用于说明筛选方向,真实组合还要按日期、权重、退市收益和交易限制计算。

只观察后来留下对象造成的系统偏差叫作幸存者偏差。它不仅夸大平均收益,还会低估停牌、无法退出、流动性枯竭和极端损失。基金数据库若只保留仍在运营的产品,指数研究若用今天成分替代历史成分,也会遇到同类问题。

修复需要保存每个日期当时有效的上市、退市、成分和可交易状态。拿不到完整记录时,应缩小资产范围、缩短时间或明确限制,不能把数据不全解释成失败对象不存在。删除缺失严重资产也要谨慎,因为困难公司往往恰好拥有更多缺失与停牌。

尝试越多,冠军越可能来自偶然

想象一百个人分别抛十次公平硬币。多数人接近五次正面,也可能有人碰巧连续得到九次或十次正面。只把最好的人带上台,他会看起来像掌握了一种技巧;若观众看见全部一百人的记录,就会知道冠军从许多随机结果中被挑了出来。

策略研究也会进行隐形比赛。研究者尝试十种指标、二十个窗口、五种止损、三套候选池,再只公布最好的组合。即使所有规则都没有稳定优势,大量尝试仍可能产生一条历史曲线很漂亮的冠军。这种在同一批数据上进行许多检验,导致偶然好结果增加的问题叫作多重检验。

选择偏差进一步描述只保留被挑中结果所造成的误导。读者看到冠军,却不知道落选方案数量、搜索范围和挑选标准,便会把偶然优势当成独立证据。保存全部主要尝试、在结果出现前写参数范围,并把冠军附近的参数一同展示,可以让选择过程重新可见。

过度拟合表示规则记住了历史噪声

历史数据同时包含可能重复的关系与偶然波动。规则自由度越多,就越有能力贴合每一个转折。加入大量窗口、阈值、过滤条件与例外后,策略可能把某段历史的噪声记得很熟,换到新时期便失效。这种对开发数据适应过度、泛化能力下降的现象叫作过度拟合。

多重检验与过度拟合关系密切,却不完全相同。多重检验强调从许多候选中容易挑到幸运者,过度拟合强调最终规则过度适应已经看过的数据。一个极复杂模型可能在单次训练中拟合噪声,大量简单策略也可能因为反复挑选产生冠军错觉。

参数图能帮助识别脆弱形状。若二十日观察窗附近的十五、二十和二十五日结果方向相近,现象像一片平缓区域;若只有精确的十九日极好,十八和二十日都失败,结果更像偶然尖峰。邻近稳定不能证明未来有效,却能排除部分过度依赖精确数字的规则。

Harvey、Liu 与 Zhu 系统讨论了金融研究中的大量因子检验,Bailey 等人也提出描述回测过度拟合概率的方法。初学者不需要马上推导这些统计工具,可以先坚持三件事。记录尝试总数,为主要参数写来路,把未参与开发的后期数据保留到规则冻结以后。相关论文收录在参考资料中。

互动实验会让幸运冠军自己出现

过度拟合与数据切分实验能够生成没有稳定优势的随机候选。逐步增加尝试数量时,研究阶段最好的曲线通常会变得更漂亮;换到另一段数据,冠军却可能回到普通水平。这个实验让“尝试越多越容易找到赢家”从抽象提醒变成可见结果。

打开过度拟合与数据切分实验

运行时记录候选数量、研究阶段冠军和后期数据结果。不要只看最后一次,比较十个、一百个和一千个候选时,冠军差距怎样改变。

理想成交会把市场摩擦从账本中删除

策略信号正确不等于订单能够按参考价格完成。把每张订单都记在开盘价、最低价或收盘价上,并假设数量无限,会同时省略队列、价差、容量、价格限制和未成交。理想成交通常会提高收益、降低波动,也可能让高换手策略显得特别有吸引力。

理想假设 现实中缺少的环节 第一版保守修正
每张订单都按开盘价全量成交 开盘撮合、排队和可用数量 延迟成交并限制订单相对成交量
涨停仍能买入,跌停仍能卖出 价格限制下可能没有对手方 无法成交时保留现金或原持仓
大订单不会改变价格 订单会消耗多个报价档位 让滑点随交易规模提高
所有资产采用同一执行假设 不同规模资产流动性差异明显 按流动性分组设置容量限制
回测没有任何交易摩擦 佣金、税费、价差和最低收费存在 使用至少三档成本情景

第一版执行模型可以简单,前提是公开假设并主动使用更差情景。若利润只在零成本、立即全量成交时存在,当前结果尚不足以支持可执行结论。第 14 课的订单账与成交账能让执行差异具体落到价格、数量和费用。

数据清洗也可能把真实风险一起删掉

价格从 100 元突然变为 50 元,可能是拆股没有正确复权,也可能是公司遭遇真实暴跌。前者属于数据口径问题,需要根据公司行动修正;后者是投资者可能真正经历的市场事件,必须留在风险记录里。因为某个数字让曲线难看就删掉,会把策略需要承受的尾部风险清洗掉。

异常值处理要从来源调查开始。原始文件、交易所公告、相邻资产和其他供应方可以帮助判断记录是否错误。确认错误后,修正过程、原值与依据都应保存。无法确认时,可以把包含与排除两种结果并列作为敏感性检查,不能悄悄选择更有利版本。

用全时期分位数统一裁剪极端值还会带来时间泄漏。早期清洗阈值不应由多年以后的分布决定。任何从数据估计出来的均值、标准差、分位点和缺失填充值,都要遵守与策略相同的时间边界。

报告选择会在最后一公里制造错觉

完整研究可能包含许多失败版本、亏损年份和成本情景。若最终页面只展示最佳参数、最顺利时期和最低成本,读者接触到的证据已经受到筛选。这种选择并不修改回测代码,却会改变别人对策略可靠性的判断。

起止日期也能成为隐形参数。把样本从某次崩跌之后开始,或者在策略最高点结束,会同时改善收益和回撤。日期应由数据覆盖、市场制度或研究计划决定,平移起止日期后的结果也应作为稳定性检查展示。

诚实报告会说明尝试过多少主要版本,为什么选择当前版本,并展示失败环境、严格成本、参数邻近与后期保留数据。负结果不是版面噪声,它们决定正结果能够支持多大范围。

把偏差放回完整研究流程

这些偏差分别进入数据、处理、选择、订单和报告环节。沿图逐格检查,可以找到错误最早混入研究的位置,也能确定应该重算哪一步。

flowchart LR
    accTitle: 回测偏差在研究流程中的位置
    accDescr: 数据阶段检查历史成员和修订版本,处理阶段检查未来信息,研究选择阶段记录全部尝试,订单阶段模拟真实摩擦,报告阶段同时展示失败结果

    data["数据<br/>幸存者与修订值"] --> feature["处理<br/>全时期统计与泄漏"]
    feature --> choose["选择<br/>多重检验与过拟合"]
    choose --> order["订单<br/>理想价格与无限容量"]
    order --> report["报告<br/>日期与冠军选择"]

    classDef danger fill:#fff0ef,stroke:#c5463b,stroke-width:2px,color:#641d18
    class data,feature,choose,order,report danger

回测要经过未来数据、幸存者偏差、过度拟合与交易成本检查

四道检查门分别阻止未来信息、幸存名单、反复选择和理想成交直接进入结论。任何一门失守,漂亮曲线都需要重新计算。

用时间机抓住未来函数

信号时间机提供几种能顺利计算的错误案例。你要为每项数据写出最早可见时点,再检查成交是否被安排到此前。页面指出的是逻辑冲突,不会因为曲线盈利而放宽时间顺序。

打开信号时间机

让 AI 充当回测红队

红队在这里指专门寻找失败路径和薄弱假设的审查角色。把研究卡、数据字典、事件时间线、核心代码与成绩单一起提供,要求 AI 给出证据位置和最小复现测试。材料不足时,它应明确标为无法判断。

请作为回测审查者,逐项检查我提供的研究材料。范围包括数据可见时间、历史候选池、预处理、参数尝试、订单成交、费用容量和结果展示。每发现一项风险,请写出证据位置、它可能怎样影响结果、一个答案已知的最小测试,以及修复后哪些指标可能变化。材料不足的项目标为“无法判断”,不要猜测市场规则,也不要评价策略能否盈利。

AI 能快速发现常见模式,无法证明没有偏差。关键数据时间要回到供应方文档,成交要回到市场规则,账本要用手算与自动测试核对,重要结论还应由另一位读者独立复查。

一张可执行的排雷清单

数据与时间

  • 每个字段都写明描述时期、最早可见时间和历史版本。
  • 候选池包含当时成员、退市资产和不可交易状态。
  • 信号、订单、成交、持仓和收益已经画在同一条时间线上。
  • 未来结果没有直接或间接进入输入与筛选步骤。
  • 清洗和标准化只使用当时允许看到的数据。

研究选择

  • 主要参数有事先理由,搜索范围和所有主要尝试得到保存。
  • 基线在打开主要结果以前确定,并使用相同数据与费用。
  • 参数邻近不是只剩一个突出的冠军尖点。
  • 后期保留数据在规则与成本冻结以前没有参与修改。

执行与报告

  • 费用、价差、滑点、未成交和数量上限进入至少一组情景。
  • 订单规模与市场成交活跃度能够对应。
  • 起止日期有研究依据,没有只截取漂亮区间。
  • 报告展示失败时期、严格成本、收益来源和全部重要限制。

容易弄错的地方

容易产生的判断 为什么会漏检 还要沿哪里检查
加上 shift(1) 就没有未来信息 股票池、预处理和修订数据仍可能泄漏 从原始字段一直追到订单时间
当前指数成分代表历史指数 后来加入和存活信息已经进入名单 使用每个历史日期的生效成员
最佳参数足以代表研究结果 冠军参加过多少次比赛被隐藏 保存候选范围、尝试次数和邻近表现
所有极端值都应删除 真实暴跌与交易风险可能被一起清除 核对来源并保留修正证据
后期数据只看了几次问题不大 每次查看都可能影响下一轮选择 记录查看与修改,必要时寻找新数据

一分钟自测

研究者测试一千条没有真实优势的随机规则,再挑出历史成绩最好的一条。它为什么仍可能拥有漂亮曲线?

查看答案 大量随机候选中会出现幸运极端值。只展示冠军会隐藏另外九百九十九次尝试,读者便可能把偶然表现误认为稳定规律。这同时涉及多重检验与选择偏差。

本课术语

词语 先这样理解
前视偏差 历史决策使用了当时尚未出现的信息
未来函数 在代码或规则中让未来信息影响过去交易的实现
数据泄漏 输入、处理或选择过程获得本不该知道的信息
幸存者偏差 只观察后来留下对象而排除失败者的偏差
多重检验 在同一批数据上尝试许多假设,使偶然赢家增加
选择偏差 只展示被挑中结果造成的误导
过度拟合 规则过度适应已见历史,换数据后难以保持
红队审查 专门寻找失败路径、冲突和薄弱假设的检查

课后练习

1 判断未来信息

规则使用当日最高价决定买入,同时按当日开盘价成交。时间矛盾在哪里?

提示最高价什么时候才能被确认为全天最高?
答案当日交易结束以后才能确认最终最高价,而开盘成交早已发生。程序让未来完整信息影响了更早的交易。

2 计算幸存筛选

三家幸存公司收益为 50%、20% 和 10%,两家退市公司收益均为负 100%。只看幸存者与看全部五家时,简单平均分别是多少?

提示分别把三项和五项收益相加后除以对象数量。
答案只看幸存者的平均收益约为 26.7%。加入两家退市公司后,五家平均收益为负 24%。这个简化计算说明筛选方向,真实组合仍要按历史权重计算。

3 寻找预处理泄漏

研究者先用完整十年数据选出与未来收益最相关的二十个字段,再把前八年与后两年分开。为什么后两年已经不再完全独立?

提示字段选择时有没有看过后两年的答案?
答案有。完整十年的未来收益参与了字段筛选,后两年信息已经间接影响模型输入。筛选只能在允许开发的早期数据中完成。

4 动手观察冠军

在过度拟合实验中依次尝试十个、一百个和一千个候选,记录研究阶段最佳结果与后期结果。

提示候选增加时,重点比较研究阶段冠军是否持续变好,后期是否同步改善。
答案具体数字随实验变化。常见现象是研究阶段冠军随候选数量增加而更漂亮,后期结果却没有稳定同步提高。

5 开放思考

真实极端价格应当删除还是保留?

评价要点先核查原始来源、公司行动和市场规则。数据错误应修正并记录依据,真实极端成交要保留或按照可执行性建模。无法确认时可并列不同处理,不能只选择让曲线更好看的版本。
离开本页前
回测偏差会从五个位置进入研究。数据可能带着未来或幸存信息,处理步骤可能泄漏,反复尝试会藏起失败版本,成交规则可能过于理想,报告还可能只留下赢家。以后看到异常漂亮的曲线,可以沿这五处逐段排查,不必先猜策略是否找到了市场秘密。