第十五章:回测框架:事件驱动回测、微观结构回测注意事项、生存偏差、前瞻偏差、回测评估指标
回测,说白了就是拿历史数据检验你的策略。但很多新手一上来就踩坑,回测曲线漂亮得像艺术品,实盘一跑直接崩盘。我见过太多这样的案例了。今天咱们就把回测这件事掰开揉碎,讲清楚。
事件驱动回测:这才是真实市场的玩法
传统的向量化回测,就是一次性算完所有信号。但真实交易不是这样的。你得一根K线一根K线地处理,每个Tick都可能触发新事件。事件驱动回测,就是模拟这种「边跑边看」的过程。
我个人习惯把事件分成几类:
- 市场事件:新K线来了、Tick更新了、成交量异常了
- 订单事件:委托成交了、撤单成功了、部分成交了
- 定时事件:每天收盘前5分钟、每周五下午3点
- 信号事件:策略计算出的买卖信号
核心逻辑其实就一个循环:
class EventEngine:
def __init__(self):
self.events = []
self.strategies = []
def run(self, data_stream):
for event in data_stream:
# 处理市场数据
self.process_market_data(event)
# 检查策略信号
for strategy in self.strategies:
signal = strategy.on_event(event)
if signal:
self.execute_order(signal)
# 更新持仓和风控
self.update_portfolio(event)
我在项目中遇到过一个问题:事件驱动回测跑得太慢。尤其是高频策略,一天几百万个Tick,循环处理效率很低。后来我改用时间桶+批量处理的方式,把同一秒内的事件打包处理,速度提升了10倍。嗯,这里要注意,打包粒度不能太大,否则会丢失微观结构信息。
微观结构回测注意事项:细节是魔鬼
做微观结构回测,跟做日线级别回测完全是两码事。你想想看,日线回测你只需要关心收盘价,但微观结构回测要处理的东西多得多。
核心注意事项清单:
- Tick数据对齐:不同交易所的Tick时间戳格式不同,有的精确到毫秒,有的到微秒。不对齐的话,回测结果会失真。
- 订单簿重建:不能只靠成交数据,你得重建完整的订单簿。我见过有人用成交价代替买卖价,结果回测收益翻了一倍——因为成交价永远是最优价。
- 滑点模拟:微观结构策略对滑点极其敏感。我建议用「成交量加权滑点模型」,而不是固定滑点。固定滑点会高估小单、低估大单。
- 手续费细节:不同交易所、不同品种、不同时间段的费率都不一样。别用统一费率,那会掩盖很多问题。
我曾经犯过一个低级错误:回测时用了撮合引擎的「先进先出」规则,但实盘交易所用的是「价格优先、时间优先」。结果回测成交率90%,实盘只有60%。从那以后,我每次回测都会先确认撮合规则。
生存偏差:回测曲线里的隐形杀手
生存偏差,说白了就是你只看到了活下来的股票,没看到退市的那些。这会导致回测收益被严重高估。
举个例子:你回测A股2000年到2020年的策略,只用了当前还在交易的股票。那些退市的、被ST的、暴跌90%的股票,全被你自动过滤掉了。你想想看,这策略在实盘里能一样吗?
避坑指南:
我曾经用Wind的数据做回测,默认只返回当前存续的股票。后来我发现,2000年到2010年退市的股票有300多只,其中大部分是垃圾股。如果策略恰好避开了这些垃圾股,回测收益会虚高20%-30%。
解决办法:使用「历史成分股」数据,或者自己构建「退市股票池」。每次回测时,把当时存在的所有股票都纳入考虑。
前瞻偏差:你用了未来的数据
前瞻偏差,就是你在回测时不小心用到了「未来才知道」的信息。这听起来很蠢,但实际操作中很容易犯。
常见的几种情况:
- 财务数据发布时间差:年报在4月底才出,但你回测时用了1月份的数据。实际上1月份你根本不知道年报数据。
- 复权数据问题:后复权数据包含了未来的分红送转信息。用后复权做回测,相当于提前知道了分红。
- 指数成分股调整:指数调整成分股是提前公布的,但回测时如果用了调整后的成分股,就相当于提前知道了调整结果。
我记得有一次,一个同事跑出来的回测夏普比率高达5.0,我们都觉得不可思议。查了半天,发现他用的是「未来复权」数据,把未来的分红都算进去了。修正之后,夏普比率直接掉到1.2。嗯,这就是前瞻偏差的威力。
回测评估指标:别只看收益率
很多人回测完只看总收益率,这是最危险的。我建议至少看以下几个指标:
| 指标 | 含义 | 我的经验阈值 |
|---|---|---|
| 夏普比率 | 风险调整后收益 | >1.5算不错,>2.0要警惕过拟合 |
| 最大回撤 | 最惨的时候亏多少 | <20%算正常,>30%要重新考虑 |
| 胜率 | 赚钱的交易占比 | 40%-60%比较合理,太高可能是过拟合 |
| 盈亏比 | 平均盈利/平均亏损 | >2.0比较好 |
| 卡玛比率 | 年化收益/最大回撤 | >1.0算及格,>2.0算优秀 |
我的个人习惯:
我每次回测完,会先看最大回撤,再看夏普比率。如果最大回撤超过30%,就算收益率再高我也不会用。为什么?因为实盘里你根本扛不住30%的回撤,大概率会在底部割肉。
另外,我建议做滚动回测。就是把数据分成多个时间段,每个时间段单独跑一次。如果某个时间段表现特别差,那就要警惕了——可能是策略不适应那个市场环境。
知识体系总览
下面这张图,是我对回测框架核心逻辑的总结。你可以把它当作一个检查清单:
回测这件事,说白了就是「用历史检验未来」。但历史不会简单重复,所以回测结果只能作为参考。我见过太多人把回测曲线当圣杯,结果实盘亏得一塌糊涂。记住一句话:回测的目的是发现错误,而不是证明正确。
最后分享一个我的工作流:
- 先用向量化回测快速验证策略逻辑
- 再用事件驱动回测精细模拟
- 检查生存偏差和前瞻偏差
- 做滚动回测,看稳定性
- 如果以上都通过了,才考虑小资金实盘测试
嗯,这套流程帮我避过不少坑。希望对你也有用。