回测通常会把交易视作信号直接变成持仓。模拟交易则会在两者之间加入订单。订单可能挂在簿上、部分成交、被撤销、遭到拒绝,也可能在信号改变后仍然有效。如果策略模拟跳过了这个生命周期,交易次数和风险敞口就可能与模拟账户记录相去甚远。
实际的改进方法是把订单建模为带有状态和时间戳的持久对象。信号只是尝试交易的指令,并不能证明交易已经发生。
为什么我的模拟策略交易次数比回测少?
先看看从未成交的订单。回测可能假设只要市场触及限价,限价单就会成交。但在真实市场中,价格触及并不能说明你的订单是否排在队列前面、是否有足够成交量,或订单到达交易场所时该报价是否仍然有效。
假设某个策略以 $100 挂出买入限价单,并在 30 秒后撤销。市场成交价显示为 $100.00,但该价位的成交量很小,而且有其他订单排在前面。你的订单可能只成交一部分,也可能完全没有成交。基于价格触及的回测会记为满仓。考虑队列假设的模拟账户则可能记录为完全未成交。
市价单也存在另一种偏差。回测可能按下一根 K 线的开盘价成交全部数量,而模拟交易可能会因数量违反交易所限制而拒单,或者随着订单簿变化分批成交。K 线只是对成交的概括;它不能保证你的整笔订单都能以同一个价格成交。
信号在订单成交前发生变化时,回测应该怎么处理?
在模拟器收到并处理撤单之前,让旧订单继续有效。如果买单仍挂在簿上时信号反转,策略可能想撤掉买单并提交卖单。但有撤单意图不代表买单会立即消失。撤单请求传输途中,买单仍可能成交,导致账户在新信号已经转为空头时仍持有多头仓位。
将其模拟为一个事件序列:信号改变,策略发送撤单请求,交易场所确认撤单或报告成交,之后策略才能知道订单的最终状态。即使只设置一个固定延迟,也能揭示即时撤单的回测会掩盖的竞态问题。
如果要采用刻意简化的模型,设置 1 秒撤单延迟并按下一事件处理,通常比假设撤单瞬间生效更有参考价值。合适的延迟取决于交易场所和系统;关键在于体现出延迟。即使订单是没有撤单窗口的市价单,部分成交和延迟报告也会带来同样的问题。
模拟交易系统应该记录哪些订单状态?
使用一个小型状态机,并为每次状态转换保留时间记录。各交易场所的具体术语可能不同,但核心区别是一致的:
- 新建或待处理:已提交,但尚未确认。
- 未成交挂单:已接受,仍可成交。
- 部分成交:部分数量已成交;剩余部分仍可能处于挂单状态。
- 已成交:没有剩余数量。
- 撤单待处理:撤单请求正在传输途中;订单仍可能成交。
- 已撤销、已拒绝或已过期:该订单不再有任何数量可能成交。
将已成交数量与申请数量分别记录,同时记录成交价格和费用。部分成交的订单既是一次交易,也是其剩余部分仍然有效的义务。若把它简单归为挂单或已完成,就会丢失策略决定下一步规模所需的信息。
| 订单事件 | 策略需要了解的信息 | 常见的回测简化处理 |
|---|---|---|
| 部分成交 | 已成交数量、剩余数量、平均价格 | 将整笔订单按一个价格记为已成交 |
| 撤单请求 | 请求时间,以及最终确认撤单或成交的时间 | 立即移除订单 |
| 拒单 | 拒绝原因,以及重试是否有效 | 假设申请的交易已经发生 |
| 过期 | 订单停止具备成交资格的时间 | 让订单继续挂单,直到之后价格再次触及 |
如何公平地比较回测交易与模拟交易?
先比较订单事件,再比较持仓,最后才看 P&L。如果回测成交了模拟账户从未成交的订单,那么后续的 P&L 差异只是结果,排查问题应从订单事件入手。
为每笔计划订单找到稳定的策略决策标识或订单标识,将两次运行记录对应起来。然后检查提交时间、申请价格和数量、有效时间、成交、撤单、拒单、费用以及最终持仓。模拟中未成交的订单也要记录原因:价格从未触及限价、假设中排在前面的队列尚未消化,或订单已过期。
一个小例子可以说明这个过程。信号要求交易 10 单位。两个系统都在 10:00:00 提交订单。回测假设订单在 10:00:01 全部成交。模拟交易在 10:00:01 成交 4 单位,10:00:02 收到撤单请求,随后在 10:00:03 确认撤单前又报告成交 2 单位。准确的比较应是成交 6 单位、而非 10 单位,另有 4 单位被撤销。把它们合并成一笔“交易”,就会掩盖策略实际承担的风险敞口。
要做好这件事,我需要完整的交易所模拟器吗?
不需要。回测可以从几项明确假设开始:限价被触及是否足够,价格穿越多少成交量才能消化假设中排在前面的队列,订单保持有效多久,以及如何模拟撤单延迟。用多个合理设置运行策略。如果表现依赖于每笔挂出的限价单都能全部成交,那么你已经发现了有关模型的重要信息。
模拟交易也不是执行质量的真实基准。它可能使用模拟成交,也可能没有真实队列。它在这里的价值更具体:随着事件陆续到达,它能揭示策略和订单管理器对待处理数量、撤单、持仓和重试行为的理解是否一致。
这项工作有个小小的乐趣:一份好的订单日志,能让原本令人费解的差异变得平淡无奇。“第二个子订单在撤单请求后成交了”,远胜于“模拟交易看起来不对劲”。回测与模拟账户不一致时,先沿着订单生命周期排查,再去修改信号。
← 全部文章


