15、策略回测框架:回测引擎设计、订单流数据回放、滑点与手续费模型、回测结果评估指标

回测,说白了就是让策略在历史数据上跑一遍。我见过太多人,策略回测曲线漂亮得像艺术品,一上实盘就崩。为什么?因为回测框架没搭好,忽略了太多细节。今天我就把这块硬骨头啃下来。

15.1 回测引擎的核心设计

回测引擎是整个框架的心脏。我个人习惯把它拆成三个模块:数据层、策略层、执行层。

  • 数据层:负责喂数据,包括订单流数据、Tick级数据、K线数据。要支持时间戳对齐,不然回测结果就是错的。
  • 策略层:接收数据,生成买卖信号。这里要保证信号生成逻辑和实盘完全一致。
  • 执行层:模拟撮合、计算滑点、扣手续费。这是最容易出bug的地方。

我曾经犯过一个低级错误——回测时用了未来数据。策略在T时刻看到了T+1的成交量,结果回测收益翻倍,实盘亏成狗。嗯,从那以后我强制要求所有数据必须按时间顺序逐笔推送。

15.2 订单流数据回放

订单流数据回放,说白了就是模拟交易所的撮合过程。每一笔挂单、撤单、成交都要按时间戳重演。

你想想看,如果只用K线回测,你根本不知道价格是怎么从A点走到B点的。中间可能经历了大单砸盘、流动性枯竭,这些细节K线全丢了。订单流回放能让你看到真实的买卖博弈。

回放的核心逻辑:

  • 按时间戳排序,逐笔推送
  • 维护一个虚拟的订单簿(Order Book)
  • 策略的挂单要插入到订单簿中,等待被吃
  • 成交后更新持仓和资金
// 伪代码:订单流回放核心
while (dataStream.hasNext()) {
    Event event = dataStream.next();
    if (event.type == TRADE) {
        // 外部成交,更新订单簿
        orderBook.applyTrade(event.price, event.volume);
        // 检查策略挂单是否被成交
        checkPendingOrders(event.price);
    } else if (event.type == ORDER) {
        // 外部挂单/撤单
        orderBook.applyOrder(event);
    }
    // 推送数据给策略
    strategy.onEvent(event);
}

这里有个坑:回放速度。如果逐笔回放,一天的数据可能要跑几分钟。我建议加一个「加速模式」,跳过无成交的闲时阶段,只保留关键事件。但要注意,加速不能改变事件顺序。

15.3 滑点与手续费模型

滑点和手续费是回测和实盘差距的最大来源。我见过有人回测时设0滑点、0手续费,结果实盘手续费吃掉一半利润。

滑点模型

滑点说白了就是你下单的价格和实际成交价格之间的差价。原因很多:流动性不足、网络延迟、大单冲击。

我个人常用的三种滑点模型:

  • 固定滑点:比如每笔交易固定加1个tick。简单粗暴,适合快速验证。
  • 比例滑点:按成交金额的千分之几计算。更接近真实情况。
  • 基于订单簿的滑点:根据当前盘口的挂单量,模拟你的订单吃掉了多少档位。这个最准,但计算量大。

我的经验:对于高频策略,一定要用基于订单簿的滑点模型。对于中低频,固定滑点加一个安全边际就够了。我曾经用固定滑点回测一个高频策略,结果实盘滑点比回测大了3倍,直接导致策略失效。

手续费模型

手续费各家交易所不一样。有的按成交金额收,有的按成交量收,还有的给VIP折扣。回测时一定要精确模拟。

交易所 Taker费率 Maker费率 备注
Binance 0.1% 0.075% VIP等级有折扣
OKX 0.08% 0.05% 挂单返佣
Bybit 0.075% 0.025% 合约费率不同

注意:有些交易所对Maker单是负费率(倒贴你钱)。如果你策略是挂单型,这部分收入不能忽略。

15.4 回测结果评估指标

回测跑完了,一堆数字摆在你面前。怎么判断策略好不好?光看收益率是远远不够的。

夏普比率

夏普比率衡量的是「每承担一单位风险,能获得多少超额收益」。公式很简单:

夏普比率 = (策略收益率 - 无风险利率) / 收益率标准差

一般来说,夏普比率大于1算及格,大于2算优秀,大于3就是顶级策略了。但我得提醒你,夏普比率对高频策略不太适用——高频策略的收益率分布往往不是正态的,用标准差衡量风险会失真。

最大回撤

最大回撤就是你从最高点跌到最低点的幅度。这个指标直接反映了策略的「抗揍能力」。

举个例子:你策略从100万涨到200万,然后跌到120万,再涨到300万。最大回撤就是 (200-120)/200 = 40%。

注意:最大回撤只看历史,不代表未来。但如果你回测中的最大回撤超过20%,实盘时心理压力会非常大。我见过有人回测最大回撤30%,实盘跌到15%就扛不住平仓了——结果后面涨了3倍。

其他重要指标

  • 胜率:盈利交易次数 / 总交易次数。胜率高不代表赚钱,还要看盈亏比。
  • 盈亏比:平均盈利 / 平均亏损。一般盈亏比大于2才算健康。
  • 卡玛比率:年化收益率 / 最大回撤。比夏普更直观,我比较喜欢用这个。
  • 索提诺比率:类似夏普,但只考虑下行风险。适合非正态分布的策略。

15.5 回测框架的整体结构

说了这么多,我画一张图帮你理清思路。

回测框架核心结构 数据层 订单流数据 Tick级数据 K线数据 策略层 信号生成 风控检查 仓位管理 执行层 撮合模拟 滑点计算 手续费扣减 订单流数据回放引擎 按时间戳逐笔推送 → 维护虚拟订单簿 → 触发策略信号 回测结果评估 夏普比率 最大回撤 胜率/盈亏比 卡玛比率

这张图把回测框架的四个核心模块串起来了。数据层喂数据给回放引擎,回放引擎驱动策略层,策略层生成信号交给执行层,最后所有结果汇总到评估层。

15.6 避坑指南

最后,我总结几个回测中容易踩的坑:

  • 未来函数:回测时用了未来数据。比如用当天的收盘价计算当天的信号。检查方法:把回测日志打印出来,看信号时间戳是否在数据时间戳之后。
  • 幸存者偏差:只回测了现在还活着的股票/币种。退市的、归零的都被忽略了。结果回测曲线好看,实盘一买就跌。
  • 过拟合:参数调得太精细,完美拟合了历史数据。换个时间段就失效。解决办法:做样本外测试,或者用交叉验证。
  • 忽略交易成本:滑点和手续费设得太低。我建议回测时把滑点设成实盘的2倍,给自己留点安全边际。

一个小技巧:回测完成后,把交易记录逐笔打印出来,手动检查前100笔交易。看成交价格是否合理,滑点是否在预期范围内。这一步虽然费时间,但能发现很多隐藏的bug。

回测框架搭建好了,你的策略才算有了「试金石」。别急着上实盘,先在历史数据里把策略「揍」一遍。扛得住回测的,才有资格面对真实市场。


无相订单流研究社 微信Lucian808555