90% 的回测都死在"假数据"上
做量化这几年,我听过太多人抱怨"回测曲线这么漂亮,怎么实盘就亏"。以前我也以为是策略问题,加因子调参数止损止盈都试过,效果都不理想。直到去年我把 K 线数据搬回本地做了一次对照实验,才发现回测和实盘的差距,问题不在策略,在"原料"。
先说结论:90% 的回测死在"假数据"上。
我做了个对照实验:同一套均线突破策略,分别用 3 个数据源跑同一段时间的回测。结果让人吃惊——Tushare 在线接口给的年化是 187%,AkShare 抓取数据给的年化是 213%,本地数据引擎的原始 tick 合成 K 线给的年化是 89%。同一套策略、同一段时间、同一只票,差异超过 100 个百分点。
为什么差距这么大?因为不同数据源的 K 线"加工方式"不一样。
Tushare 给的 K 线,是经过"前复权 + 异常值剔除 + 成交量聚合"之后的版本。AkShare 给的 K 线,是从不同网站抓取的"拼接版",来源不统一。本地数据引擎给的是从逐笔成交合成的"原始版"。三种 K 线跑出来的回测结果当然不同。
我后来逐笔比对了某只票 2024 年某天的成交记录,发现至少有 4 个细节被 Tushare 处理掉了:一是停牌前的异常成交被剔除了一部分,二是集合竞价的量被合并进了 9:30 的第一根 K 线,三是有几笔大单被拆成了小单显示,四是"开高低收"按收盘价倒推算出来的(和真实成交对不上)。
换句话说,你在线 K 线上做的回测,可能回测的根本不是"真实发生过"的行情。这不是数据源的问题,是"加工过程"的问题。任何一个 K 线数据源都会对原始成交做加工,差别只在于"加工程度"。
更麻烦的是,这种加工在不同数据源之间是不一致的。我对比了 Tushare、AkShare、东方财富、同花顺 4 个数据源对同一只票同一时间的 K 线,发现至少有 15% 的 K 线"开高低收"对不上。也就是说,你用 A 数据源做的回测,在 B 数据源上完全无法复现。
怎么解决这个问题?答案是:自己合成 K 线,不用现成的。
我现在的做法是:用本地数据引擎的逐笔数据合成 K 线。逐笔数据路径 `time/real/trace/onebyone/{dm}`,每只票每个交易日的每一笔成交都有,包括成交时间、价格、方向、量级。我用 Python 自己合成 1 分钟、5 分钟、30 分钟 K 线,再跑回测。
实测下来,自己合成的 K 线跑出来的回测年化是 89%,实盘跟了 3 个月,年化是 78%。差距 11 个百分点,可以接受。而用 Tushare 数据做的回测年化 187%,实盘跟了 3 个月亏了 18%。差距 205 个百分点,完全无法接受。
还有一个反常识的发现:很多数据源给出的"前复权方式"不一致——有的按除权除息日复权,有的按除权除息前一日复权,结果同一只票在两个数据源上能差出 5% 的价格。回测时如果你没注意到,回测曲线漂亮得离谱,实盘一上就拉胯。
数据精度决定回测精度,精度错 1%,收益能错 200%。量化真正值钱的从来不是策略,是数据的"原材料"。
投资市场里,最容易骗人的不是消息,是"看起来很真实"的数据。
资料参考:ig50