第五部分 · 量化研究如何产生可信结论 · 第 36 章
识别回测幻觉: 错误清单与拆解案例
研究最重要的能力之一,不是证明策略有效,而是尽快证明它为什么可能无效。这一章先建立错误清单,再沿着一条异常漂亮的回测曲线逐项排查:股票池是否点时、信号是否偷看收盘、成本是否算够、涨跌停是否可成交、参数是否挑过头。坏消息越早出现,真钱越安全。
本部分的问题:一个金融判断怎样变成可证伪假设,再经过数据、回测、模型和实盘约束?
读完后,你能从问题出发完成研究闭环,而不是先找模型、再给结果编故事。
读完这一章,你会明白
- 新手最常见的假收益,基本来自四处:未来函数、幸存者偏差、成本低估和过拟合。
- 样本外、容量、基准、交易规则和复盘记录,决定回测算不算一次真实的研究。
- 漂亮回测先查错再欣赏,重点查股票池、时间顺序、成本、交易限制、容量和参数稳定性。
- 每补上一个现实约束,收益下降是正常的;真实结果比虚假高收益有价值得多。
1. 看起来赚钱,其实在偷看答案
1.1. 开卷考试里提前翻了答案
未来函数是回测里最致命、也最隐蔽的错误。说白了,就是模型在历史某个时点,用了当时根本不可能知道的信息:年报还没公布就拿年报数据做决策,当天收盘价要收盘后才知道却用它生成信号还按它成交,今天的指数成分名单被拿去构造十年前的股票池。
它可怕在哪?在于它从不让你亏钱,反而让策略好得发光。模型不是更聪明了,而是提前看到了答案。更糟的是,你越优化越容易放大这个错误——优化器会专门挑那些泄漏了未来的信息往死里用。
排查方法就一招,画时间线。每个字段都老实回答六个时间点:事件发生时间、数据公布时间、你收到数据的时间、信号生成时间、下单时间、成交时间。顺序一摆,有没有偷看一目了然:只要特征可见的时间晚于决策时点,这个特征就不能用。
多说无益,直接看“就差一个字符”的现场——配套 examples/ex03_lookahead.py 里,诚实版和作弊版的全部区别:
if honest:
key = lambda s: s.prices[t] / s.prices[t - 20] - 1 1
else:
key = lambda s: s.prices[t + 1] / s.prices[t] - 1 2
ranked = sorted(stocks, key=key, reverse=True) 3
- 诚实版:只碰
[t-20, t]的历史。这行里的每个下标都值得追问:t-20 在决策时一定可见吗?t 的收盘价呢(要收盘后才有)——答案全是“是”,才能用。 - 作弊版只差一个字符:把
t - 20换成t + 1。回测引擎不会报错、不会警告,它甚至会让曲线漂亮得惊人——这份示例跑出来,诚实版净值不到 1,作弊版能超过 1.4。幻觉就喜欢长成“能骗到你”这么大。 - 排序的是同一行代码,喂什么 key 决定它是研究还是作弊。这就是为什么工程骨架章节里要塞 “asof 时点测试”——下标用错一行,测试替你喊出来;没有测试,市场替你的账户喊。
可以自己改脚本玩玩:把 t + 1 换成 t + 5,曲线会更离谱;把它换回来,灾难又不声不响消失。未来函数从来不留指纹,唯一能挡住它的不是聪明,是“每个决策时点代码碰不到之后数据”的纪律本身。
1.2. 只统计活下来的
幸存者偏差,大白话就是只看活下来的样本。拿今天仍在上市的股票名单回测十年前,就自动漏掉了中途退市、长期停牌、跌到没人看的公司。失败样本全被删掉了,回测能不好看吗?这就像只采访毕业十年还留在行业里的人,然后宣布这个行业人均年薪百万。
同样的病,基金和产品研究也躲不开。只盯着现在还在运营的基金看,清盘的、亏到关门的全不在样本里,行业平均收益就被系统性高估了。排行榜上全是赢家,不是因为行业真能赢,是因为输家被请出了排行榜。
解法也直接:用历史当时的股票池和产品样本。退市股票要留在样本里,退市前那种想卖卖不掉的风险也要处理。总原则一句话:别让你的数据库自动替你美化历史。
1.3. 手续费不是小零头
很多策略毛收益看着不错,把成本一扣,利润清零。而成本远不只是佣金:印花税、过户费、买卖价差、滑点、冲击成本、融资融券成本,做期货的还有展期和基差。每一项单看都不起眼,加起来足够吃掉一整个策略。
高换手策略尤其容易被成本杀死。单次交易就赚一点点,可一年买卖几百回,每回都交一遍过路费。举个量级上的感觉:回测里少扣 0.05%,看起来只是小数点后的事,一年累积下来的差距可能非常可观。
解决办法是做成本敏感性测试:同一策略,分别拿 0 成本、正常成本、两倍成本、三倍成本各跑一遍。健康的策略成本加一倍还能活;如果只有按最低成本假设才勉强赚钱,那它赚的可能不是市场的钱,而是你少扣的钱——对这类策略务必谨慎。
同一策略按 0、1、2、3 倍成本各跑一遍:甲毛收益 +12%,一倍成本只剩 +4.5%,两倍转负;乙毛 +15%,两倍成本还有 +3%。成本远不只是佣金——印花税、过户费、买卖价差、滑点、冲击、融资融券、展期基差,每一项单看不起眼,加起来足够吃掉一整个策略。
1.4. 把历史噪声背成了规律
过拟合就是模型把历史噪声当成规律背了下来。这在机器学习里是老概念,在量化里格外容易发生:因子可以随便试,参数可以随便调,样本区间可以随便切,组合方式成千上万。试得足够多,总能撞出一条好看的历史曲线——这不叫发现,叫穷举。
过拟合策略通常带几个记号:参数稍微动一下就崩,收益集中在少数年份,样本外表现拉跨,经济解释很牵强,交易成本一加利润就没,回撤阶段说不出原因。记号占得越多,越该怀疑。
防过拟合没有银弹,只有纪律:减少自由度,别给模型留太多旋钮;留出真正的样本外并且忍住不看;记录所有实验,包括失败的那些;做参数稳定性检查;条件差不多的情况下,优先选简单、能解释的策略。
过拟合是量化头号杀手:你在历史数据里反复调参,做出一条完美曲线,其实只是把当年的偶然噪声背了下来。换到没见过的新数据(样本外),立刻原形毕露。
1.5. 假装没偷看的偷看
样本外污染是一种体面的作弊。你号称某段数据从没参与训练,但研究过程中反复瞄它:看一次测试集结果,回去改改因子和参数,再看一次。每次根据它的结果调整方向,它就已经参与了研究决策——名义上还是样本外,实际早被你用成了验证集。
更扎心的是,金融研究里研究员本人也会过拟合。历史图形看得太多,你会下意识挑那些符合历史规律的规则。就算代码干干净净没有任何泄漏,你这个人本身就是一条泄漏通道。
解法是分层验证:训练集调模型,验证集选参数,最终测试集尽量只碰一次。再进一步,把模拟盘和小资金实盘当作真正的未来样本——那是唯一一段你绝对没偷看过的历史,因为它还没发生。
污染发生在“看一眼测试集再回去改”的那一秒,事后没有任何测试能替你测出来——数据还是那个数据,变的只是你这个人的决策。所以别指望检测器,要靠流程把门锁死:训练集调模型,验证集选参数,测试集只碰一次,每次接触留痕。门没锁,人性一定进去。
1.6. 小钱能赚的,大钱不一定赚得到
容量说的是策略能装下多少资金。很多小盘、低流动性、短周期策略,小资金跑得风生水起;资金一大,自己的买单就把价格推走了,到手的收益先被自己的冲击成本咬一口。回测只要不限制参与率,就等于默认你可以拿任意多的钱,按历史价格想成交多少成交多少。
容量问题的典型症状,是收益随规模一起缩水。机构做策略,常常要在收益率高和装得下之间取舍。个人资金小,容量压力没那么大,但也不能完全不管流动性——真到跌停板想走人的时候,想走的可不止你一个。
解法是主动给自己上限制:单日参与成交量的比例设上限,成交额太低的标的直接过滤,冲击成本提前估出来。任何需要吃掉大量成交量才能执行完的策略,收益都要重新算一遍再谈。
1.7. 把相关性当因果
做量化最容易挖到的东西就是相关性:某个指标高的股票过去涨得好,某个宏观变量一变市场就动了,某个文本词频和收益对得上号。挖到时很兴奋,但请先默念三遍:相关不等于因果。
一段相关性可能来自很多地方:两个变量被同一个轮子驱动,纯属这十年样本的巧合,因子偷偷背着行业或市值暴露,或者干脆是数据泄漏。比如某因子看着有效,拆开才发现它只是偏小盘;某宏观指标很灵,可能只是那几年政策环境特殊,环境一变就哑火。
应对是一套组合拳:做中性化、分组检验、跨时期和跨市场验证,再给出一个讲得通的经济解释。你不必在数学上证明严格因果,但至少要知道:这段相关性为什么可能在未来继续存在,什么情况下它会消失。
1.8. 把回测当实盘
回测是历史里的排练,不是正式演出。排练时没人跟你排队抢单,没有心理压力,没有网络抖动,没有券商拒单,没有临时改的规则,也没有人半夜要赎回。实盘里这些全都有,而且专挑你最脆弱的时候一起来。
还有一层常被漏掉:实盘会改变你这个人。看着账户连亏,你很难不伸手把策略停掉;看着连赚,又忍不住想加仓。每一次临场干预,都在让实盘偏离回测——模型还是原来那个模型,执行它的你已经不是原来那个你了。
出路是把情绪从回路里挪出去:先模拟盘,再小资金;日志记严格;干预规则提前写好,什么情况允许动手、动到什么程度,白纸黑字。最关键的一条:别在情绪最强的时候,临时决定策略的生死。
回测里那个执行者是完美的:它不因连亏而手软,不因连赚而加仓。实盘里执行者是你——连亏三周你会想停掉它,连赚三月你会想放大它,每一次临场干预都在让实盘偏离回测。所以干预规则要趁冷静时写好:什么情况允许动、动到什么程度,白纸黑字;情绪最强的那一刻,只准照抄,不准创作。
1.9. 赚的到底是市场的钱还是你的钱
策略赚了钱,不等于你有 Alpha。市场一年涨 30%,你的策略涨 20%,绝对收益是正的,其实是跑输;市场跌 20%,你只跌 5%,账户在亏,但相对表现已经很好。不看基准,这两个故事你一个都讲不清。
没有基准,你就不知道自己赚的到底是哪份钱:是市场整体的 Beta,是某行业的东风,是某种风格暴露,还是模型的真本事。市面上不少号称有策略的产品,拆开一看,所谓收益不过是长期满仓股票市场而已。
所以每个策略都要配一个合适的基准,然后老实报告超额收益、跟踪误差、信息比率和风险暴露。基准就是你的坐标系;没有坐标系,你说不清自己站在哪。
1.10. 同一个坑反复踩
不记录实验,人就会重复踩同一个坑。今天试一个因子,明天改一个参数,后天换一个股票池,三个月后你只记得那条最好的曲线,中间几十次失败全忘了。下次遇到类似的诱惑,你还会再试一遍。
没有复盘,研究就变成无法积累的一次性劳动。你不知道哪个方向已被证明走不通,不知道哪类错误反复出现,也说不清眼下这点收益里有多少是运气。团队如此,单打独斗也一样。
方法很朴素:写实验日志。每个想法、每组配置、每次结果、得出的结论、下一步计划,全部记账。失败记录和成功记录同样重要——失败记录是你花了真金白银买来的认知,记下来才算没白亏。
2. 一条漂亮回测曲线是怎样被拆穿的
这一章讲一个虚构但你一定会觉得眼熟的故事。一个新手做出一条年化 45%、最大回撤 8% 的股票策略曲线,兴奋得以为自己摸到了量化圣杯。别急,我们一起当他的代码审查员,一步步检查:数据时间、股票池、成交价格、成本、停牌涨跌停、容量、样本外。每揪出一个错误,曲线就掉一截。故事结束时,策略不再神奇,但研究终于变得真实——而后者值钱得多。
2.1. 曲线好得不像真的
故事主角是个量化新手,策略简单到三句话能讲完:每月底,选过去 20 日涨幅最高的 30 只股票,下个月持有,每月换仓一次。跑完十年回测,他盯着屏幕愣住了:年化收益 45%,最大回撤只有 8%,夏普 2 以上,几乎每年都跑赢指数。
看到这种曲线,第一反应不该是庆祝,而该是怀疑。想想这组条件的含金量:A 股公开日线数据、烂大街的简单动量、月频调仓。如果这样就能做出低回撤高收益,市场上无数双眼睛早就挤进来把收益压薄了,哪轮得到一个新手躺着捡?
好回测不是不可能出现,但越好越要查。尤其当策略简单、数据公开、成本假设宽松、结果还异常漂亮——几件事凑齐时,大概率不是挖到了金矿,而是哪里埋着 bug。
2.2. 用了今天的成分股
第一刀切向股票池。一查,新手用的是当前的中证 500 成分股名单,回测的是过去十年。也就是说,那些当时还没纳入、后来被剔除的股票全被错误处理了;表现差的、退市的、长期低迷的样本,很多被悄悄排除在外。他回测的根本不是历史,是幸存者的历史。
改成历史当时的成分股再跑:年化收益从 45% 直降到 31%,最大回撤从 8% 升到 15%。策略看上去还不错,但圣杯的光环已经褪了一半。
这一步的教训值得抄下来贴在墙上:股票池不是无关紧要的背景设置,它直接决定你看的是不是真实历史。凡是用到指数成分的策略,都必须用历史当时的点时成分,今天的名单只配回测今天。
2.3. 当天收盘信号当天成交
接着查时间线,第二处错误浮出来:策略用每月底的收盘价计算过去 20 日涨幅,然后假设按同一个收盘价买入。等等——收盘价是收盘之后才有的。你不能先知道收盘价,再按它成交;这就像先看到骰子点数再下注,稳赢,但赌场不允许。
把成交改成下一个交易日的开盘价,再跑:年化收益降到 24%,最大回撤升到 18%。原因很现实——月底冲得最猛的那批股票,第二天常常高开,真实买入成本比昨晚的收盘价贵出一截。
时间顺序在这里不是可以四舍五入的小数点。信号生成时间和成交时间只隔一个交易日,结果却天差地别。回测里每一条“先算出数再假设成交”的捷径,几乎都在偷偷使用未来信息付账。
2.4. 没扣真实成本
然后翻成本设置:第一版只扣了万分之一佣金,印花税、过户费、滑点全没算。而这个策略每月整仓换一次,年换手不低——成本每补上一项,收益就要掉一截。
先加简化成本:买入 0.08%、卖出 0.13%,年化收益降到 18%。再把滑点按成交额和订单参与率动态估计,年化进一步降到 15%。注意,到这一步策略还活着,但它已经从“圣杯”降级成了“还行”。
教训是,成本不是事后糊上去的修饰层,它是策略结构的一部分。高换手策略在扣成本前和扣成本后,完全可以是两个策略:一个富豪,一个打工人。
动量策略天生偏爱近期强势股,而强势股最爱干的一件事就是涨停。第一版回测假设,只要股票存在就能按价格买入;真实市场里,涨停板一封,卖盘稀稀拉拉,你挂着买单排队,未必轮得到你。
卖出端同理:手里的弱势股一旦跌停,回测说卖就卖,实盘里你只能对着没人接的卖一排队干瞪眼。把三条规则加进去——涨停不可买、跌停不可卖、停牌不可交易——年化收益降到 11%,最大回撤飙到 24%。
这一刀扎得非常现实:很多纸面上的动量收益,来自“买到”了实盘根本买不到的封板强势股。回测可以不尊重交易制度,市场可不会迁就回测。
2.5. 容量过高
再看资金假设:策略设定资金规模 1 亿元,却完全不限制成交额参与率。有些目标股票当天全市场成交额只有几千万,策略却假设自己可以稳稳买入几百万元而不惊动价格——这不是交易,这是瞬移。
加上约束:单只股票单日参与率不超过 10%。结果是一部分订单在执行周期里根本无法完全成交,组合持仓偏离目标。年化收益降到 8%,最大回撤接近 27%。
小资金回测和大资金回测,压根不是同一个问题。容量这道坎,会把很多小票上的机会变成看得见、吃不着的纸面收益——你在图上拥有的,市场里未必领得到。
2.6. 参数挑选
最后一个问题要回头追问:为什么是 20 日动量?为什么是 30 只?为什么月频?新手挠头承认:动量窗口试过 5 日、10 日、20 日、60 日,持仓数试过 10 只、30 只、50 只,最后从参数网格里挑了最好看的一组。
这就是参数过拟合。把完整的参数网格画出来,真相有点刺眼:只有少数几组组合表现出色,周围的参数全部平平;换到最近两年样本外,策略超额收益接近 0。好参数不是被发现出来的,是被挑出来的。
参数当然能调,但过程必须记录、全部留痕。试了一百组只展示最好的那一组,性质和考试前偷看答案、再声称自己会做题,没有区别。
2.7. 修正后的策略还能不能用
所有修正跑完,盘一下总账:策略从年化 45%、回撤 8%,变成年化 8%-12%、回撤 25% 左右,样本外还不稳定。圣杯是当不成了,但它未必一无是处,仍可能作为一个偏弱的动量信号,进多因子模型里尽一份力。
这就是研究最真实的样子:一个想法不一定能独挑大梁,但可能贡献一点信息。量化组合往往不是靠一个神奇因子打天下,而是让许多弱信号在成本和风险约束下合力。
对新手来说,这一轮最大的进步不是保住漂亮曲线,而是学会把曲线拆开。拆完桌上还能剩下的东西,才配得上“继续研究”四个字。
年化从 45% 掉到 8%,不是研究失败了,是研究刚上路:前面那 37 个点本来就不属于你,拆穿它们等于省下一大笔实盘学费。一个研究者的成长刻度,从来不是做出多漂亮的曲线,而是把所有假象剔干净之后,桌上剩下的东西越来越少、越来越真。
2.8. 复盘顺序
以后再遇到漂亮回测,照这个顺序查:第一,股票池是否点时;第二,数据在当时是否可见;第三,信号时间和成交时间对不对得上;第四,成本是否完整;第五,涨跌停、停牌、T+1 是否处理。
第六,容量假设合不合理;第七,参数是否稳定;第八,样本外有没有留、有没有被污染;第九,收益是否集中在少数年份;第十,收益能不能用风险暴露解释清楚。
这个顺序比闷头调模型有用得多。很多策略根本不需要更复杂的模型,只需要先把假收益一样一样剔出去——剔完还活着的,才值得被复杂化。
一轮又一轮修正,曲线一掉再掉,说不沮丧是假的。但请换个角度:你不是从 45% 亏到了 8%,你是从一个不真实的好结果,走到了一个可以相信的普通结果。普通但真实,永远比惊艳但虚假值钱。
专业研究的日常,就是把不真实收益一样一样拿掉:未来函数拿掉,幸存者偏差拿掉,漏算的成本补上,虚高的容量砍掉,过拟合挤掉。桌上最后剩下的那一小撮,才可能是你真正的优势。
如果修到最后什么都不剩,同样不是失败。它明明白白告诉你:这条路不值得一分钱实盘。一份诚实的回测帮你省下一大笔真金白银的亏损,这是研究阶段能做成最划算的买卖。
十年回测年化 45%、回撤 8%、夏普 2 以上——第一反应不该是庆祝,而该按十步顺序查:股票池、数据可见性、成交时点、成本、交易规则、容量、参数、样本外、收益集中度、风险解释。剔完假收益还剩年化 8%~12%、回撤约 25%:普通但真实,永远比惊艳但虚假值钱。
小结
这一章的正文不是让你记住几个孤立名词,而是要把它们放回同一条因果链里。读完后,先用自己的话复述下面几条判断,再顺着“小节回看”检查是否能解释每一步。
- 新手最常见的假收益,基本来自四处:未来函数、幸存者偏差、成本低估和过拟合。
- 样本外、容量、基准、交易规则和复盘记录,决定回测算不算一次真实的研究。
- 漂亮回测先查错再欣赏,重点查股票池、时间顺序、成本、交易限制、容量和参数稳定性。
- 每补上一个现实约束,收益下降是正常的;真实结果比虚假高收益有价值得多。
小节回看
- 1.1. 开卷考试里提前翻了答案
- 1.2. 只统计活下来的
- 1.3. 手续费不是小零头
- 1.4. 把历史噪声背成了规律
- 1.5. 假装没偷看的偷看
- 1.6. 小钱能赚的,大钱不一定赚得到
- 1.7. 把相关性当因果
- 1.8. 把回测当实盘
- 1.9. 赚的到底是市场的钱还是你的钱
- 1.10. 同一个坑反复踩
- 2.1. 曲线好得不像真的
- 2.2. 用了今天的成分股
- 2.3. 当天收盘信号当天成交
- 2.4. 没扣真实成本
- 2.5. 容量过高
- 2.6. 参数挑选
- 2.7. 修正后的策略还能不能用
- 2.8. 复盘顺序
自测
为什么未来函数会让回测特别好看?
因为模型提前用了当时不可能知道的信息,等于考试时偷看答案,分数自然虚高。
幸存者偏差为什么会高估收益?
退市、失败、表现差的样本被悄悄删掉,只留下活下来的资产,历史等于被美颜过。
为什么异常漂亮的简单策略要先怀疑?
公开数据加简单规则若真能长期高收益低回撤,收益早被市场挤薄;更可能是数据或交易假设里埋着错。
动量策略为什么特别要处理涨停买入?
强势股最容易涨停封板,回测假设买得到,会把根本执行不了的收益算进来。
审查量化研究: 从论文到回测报告
用同一套问题检查研报、论文和回测报告里的假设、数据、基准、成本、风险与样本外。