数据再干净也修不好的回测 Bug:成交判定层的 6 个检查点

常听到一种说法:正规数据商已经把复权和清洗做好了,回测就不用担心了。数据确实能解决一部分问题,比如复权因子、退市股的历史行情(前提是供应商提供)、停牌标记。但还有一类 Bug 出在回测引擎的成交判定层,跟数据质量无关。

数据管不到的部分

  1. 未来函数:用 T 日收盘价算信号,又按 T 日收盘价成交。
  2. 成交价假设:按开盘价、收盘价还是均价成交,滑点算多少,由引擎决定。
  3. 涨跌停:数据里只有价格,能不能成交要由引擎判断。
  4. T+1:当天买入的仓位当天不能卖。
  5. 费用:佣金有最低收费,卖出还有印花税。
  6. 股票池:用今天的成分股回测历史,就会有幸存者偏差。

另外,前复权还是后复权、复权价用来算信号还是算成交,也需要自己定口径。

一个最小的成交判定示意

下面是一段通用的示意代码,只演示思路(主板按 10% 简化,没有处理创业板、科创板、ST 等不同的涨跌幅),不来自任何产品:

// 信号在第 i 天收盘产生,第 i+1 天开盘尝试成交
function tryFill(order, bar, position) {
  if (bar.paused || bar.volume === 0) return { ok: false, reason: 'paused' };
  const up = +(bar.preClose * 1.1).toFixed(2);
  const down = +(bar.preClose * 0.9).toFixed(2);
  if (order.side === 'buy' && bar.open >= up) return { ok: false, reason: 'limit_up' };
  if (order.side === 'sell') {
    if (bar.open <= down) return { ok: false, reason: 'limit_down' };
    if (position.buyDate === bar.date) return { ok: false, reason: 'T+1' };
  }
  return { ok: true, price: bar.open };
}

关键是把被拒绝的单子和原因记录下来,不要悄悄跳过,这样事后才能逐笔核对。

量级有多大

下面的数字来自我单独写的研究脚本(和我的回测工具 Quant Lab 不是一回事,用工具包无法复现):A股日线 2018–2025,股票池是今日沪深300成分加 2018 年后上交所退市股,MA20 突破,100 万本金,20 只等权。

  • 坑全踩:年化 10.51%
  • 只把当日收盘成交改成次日开盘成交:5.07%
  • 加上交易成本:4.75% → -4.71%
  • 全部修完:年化 -4.71%,最大回撤 67.84%;同期沪深300价格指数年化 1.81%

需要说明:我没有历史成分表,也没有深交所退市名单,所以幸存者偏差这一项只能当示意。

自查清单

好数据是地基,成交逻辑才是房子。

以上仅为回测方法讨论,不构成投资建议。

posted @ 2026-11-02 19:27  青灯夜001  阅读(3)  评论(0)    收藏  举报