第十五章:回测框架:事件驱动回测、微观结构回测注意事项、生存偏差、前瞻偏差、回测评估指标

回测,说白了就是拿历史数据检验你的策略。但很多新手一上来就踩坑,回测曲线漂亮得像艺术品,实盘一跑直接崩盘。我见过太多这样的案例了。今天咱们就把回测这件事掰开揉碎,讲清楚。

事件驱动回测:这才是真实市场的玩法

传统的向量化回测,就是一次性算完所有信号。但真实交易不是这样的。你得一根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%的回撤,大概率会在底部割肉。

另外,我建议做滚动回测。就是把数据分成多个时间段,每个时间段单独跑一次。如果某个时间段表现特别差,那就要警惕了——可能是策略不适应那个市场环境。

知识体系总览

下面这张图,是我对回测框架核心逻辑的总结。你可以把它当作一个检查清单:

回测框架核心逻辑 历史数据 Tick / 分钟 / 日线 事件驱动引擎 市场/订单/定时事件 策略逻辑 信号生成 / 风控 订单执行 滑点 / 手续费 / 撮合 绩效评估 夏普 / 回撤 / 胜率 偏差检查 生存偏差 / 前瞻偏差 策略优化 参数调整 / 逻辑改进 反馈迭代 每个环节都可能引入偏差,需要逐一检查 回测不是终点,而是策略优化的起点

回测这件事,说白了就是「用历史检验未来」。但历史不会简单重复,所以回测结果只能作为参考。我见过太多人把回测曲线当圣杯,结果实盘亏得一塌糊涂。记住一句话:回测的目的是发现错误,而不是证明正确

最后分享一个我的工作流:

  1. 先用向量化回测快速验证策略逻辑
  2. 再用事件驱动回测精细模拟
  3. 检查生存偏差和前瞻偏差
  4. 做滚动回测,看稳定性
  5. 如果以上都通过了,才考虑小资金实盘测试

嗯,这套流程帮我避过不少坑。希望对你也有用。