回测可能会报告一个市场从未显示过的成交价。通常,这是因为模拟器根据不完整的数据推断出了一个看似合理的执行结果:K线的最高价和最低价、中间价,或者某笔交易触及的限价。这样一来,成交记录看似精确,却掩盖了市场实际提供过什么价格。
先问问自己:订单实际能以什么价格成交?末笔成交价K线告诉你某个时间段内出现过哪些成交价,却没有告诉你订单到达时的买价和卖价、当时可成交的数量,也没有说明你的订单能否排到队列前面。
为什么我的回测显示的成交价超出了市场价格范围?
首先,要明确“超出”是什么意思。买入成交价低于K线最低价,或卖出成交价高于最高价,显然是记账或时间处理错误。但即使成交价落在最高价与最低价之间,也可能并不真实:这个价格可能在订单存在之前就已成交,可能出现在价差的另一侧,也可能成交数量太少,不足以完成你的订单。
设想一根1分钟K线,开盘价为100.00,最低价为99.80,收盘价为100.10。策略看到完整K线后提交买单,模拟器却以99.80成交。这个最低价可能出现在这一分钟刚开始时,比信号早了50秒。K线无法证明作出决策后仍能以99.80买入。
| 你拥有的数据 | 能够说明什么 | 无法说明什么 |
|---|---|---|
| OHLCV K线 | 某时间段内观察到的成交价范围和成交量 | 价格顺序、买价和卖价,或订单到达时的可成交量 |
| 逐笔成交 | 带有时间戳和价格的已报告成交 | 静态流动性或你在队列中的位置 |
| 最优档报价 | 采样时刻显示的最佳买价和卖价 | 最佳档以外的深度,或报价在采样间隔内是否持续有效 |
| 订单簿事件 | 显示深度变化和队列事件,但受行情源覆盖范围限制 | 隐藏流动性、场所接入情况或优先成交保证 |
另一个常见原因是混淆了中间价和可执行价格。如果报价是买价99.99、卖价100.01,报告里按100.00的中间价买入,看起来很整齐。可成交的买单通常要按卖价成交,而且订单规模还可能带来冲击成本。把中间价当成成交价,就悄悄抹去了半个价差。
市场触及限价,限价单就能成交吗?
价格触及限价,只能说明有一笔交易以该限价成交,并不能证明你的挂单也会成交。如果有其他订单排在你前面,该价位的成交量可能不足以轮到你的队列位置。成交记录也可能来自另一个交易场所,而你的订单挂在别处。
假设你的买入限价是50.00,挂单后市场以该价格成交了200股。按触价成交的模拟器会把500股全部算作成交。更谨慎的模型会先查看订单到达后,以50.00或更优价格成交了多少,再估算排在你前面的队列数量。没有订单级别的订单簿数据,这个队列数量只能是假设。它应当在结果中明确展示,而不是被悄悄当成确定事实。
对于小型研究系统,我宁愿明确写出这个假设并测试一个范围,也不愿假装K线数据能揭示队列优先级。合适的范围取决于交易场所、订单规模和策略的交易频率。开盘时交易清淡的股票,与UTC 03:00时流动性稀薄的加密货币合约,面临的是不同的执行问题。
如何为K线数据选择成交模型?
模型既要匹配数据,也要匹配策略所作的主张。基于K线的回测仍可用于交易较慢的策略,但成交模型应尊重K线实际能说明的信息。
- 设定决策时间和订单到达时间。如果信号使用K线收盘价,就应在收盘后提交订单。根据下一个可用时段或报价模拟执行,而不是使用完整K线中更早出现的最低价。
- 使用价差的正确一侧。可成交买单从卖价开始计算,卖单则从买价开始。如果只有成交价K线,就从其他来源估算价差,或者说明模型未计入价差。
- 将成交量限制在合理流动性范围内。根据观察到的成交量设置参与率上限,并计入手续费和市场冲击。K线总成交量并不意味着你选定的价格上有这么多可成交量。
- 对假设做压力测试。将下一时段开盘成交与保守滑点设定进行比较,并测试结果能否承受更差的执行条件。不要为了让策略获胜而调整成交模型。
这些是建模选择,并不是从不完整数据中还原唯一真实成交价的方法。如果策略依赖捕捉几个基点,K线数据可能不足以证明这一点。
如何查明不可能的成交价是在哪一步进入回测的?
从信号到成交账本,追踪一笔可疑交易。将决策时间戳、订单提交时间戳、模拟到达时间、选用的市场观测、成交价、成交数量和手续费分别记录为独立字段。然后按顺序检查:
- 计算特征时,是否使用了决策时尚未收完的K线数据?
- 成交是否使用了K线的最高价、最低价或收盘价,而该价格在订单到达前就已出现?
- 买单是否按买价成交,或卖单是否按卖价成交?
- 模拟成交数量是否超过可用报价数量或模型的参与率上限?
- 是否在选定成交价后才应用价格舍入、合约最小变动价位和手续费?
如果无法从交易记录中回答这些问题,说明回测缺少执行依据。补上这些字段,选几笔交易对照原始数据手动重放,并确认报告的成交价符合你设定的模型。再平滑的权益曲线,也发现不了一个只存在于模拟器里的价格。
← 全部文章


