第 7 课 · 回测是什么,以及五个作弊漏洞

【这课你会明白什么】

  • 回测的本质:让规则在历史上”重演一遍”的考场
  • 五个最常见的放水漏洞,每个都配”不堵会怎样”
  • 一个真实演示:−$23,744 的解剖报告

正文

回测=把一条写死的交易规则放回历史数据里重演一遍,算出”如果当时真这么做,结果如何”。它是想法工厂的考场。考场最大的风险不是考不出来,而是不知不觉给考生放水——回测几乎总是比实盘好看,差距就藏在漏洞里。下面五个漏洞,是我们的回测引擎逐条堵死的:

漏洞 例子 堵法 不堵会怎样
未来函数:用了当时不可能知道的信息 “收盘价站上均线(最近 N 根 K 线收盘价的平均)就按这根收盘价买入”——收盘价收盘后才知道 第 i 根 K 线收盘算信号,第 i+1 根开盘才成交 回测虚高,实盘立刻打回原形
② 零摩擦幻觉 不算佣金、滑点 每次成交按 1 tick 不利价差+佣金记账(第 4 课口径) 高频亏钱策略在纸面上变赚钱
③ K 线内部顺序不可知(第 5 课) 同一根 K 线里,止损价和止盈价(预设的”赚够就落袋”离场价)都碰到了,先算哪个? 一律按止损算(对自己最不利的假设) 挑对自己有利的顺序=系统性放水
跳空(开盘价直接越过一段价位)穿过止损 隔夜开盘直接开在止损价更坏的一侧 更差的实际开盘价成交,不按止损价 真实的隔夜大亏被”削”成小亏
⑤ 限价单触价即成 实盘限价单要排队(第 3 课) 必须穿价才算成交 一堆实盘轮不到你的成交混进统计

还有第六条:持仓不许穿越数据块边界(第 5 课的空洞),块末强制平仓——不让物理上不可能的持仓路径混进统计。

引擎本身用的是”笨办法”:逐根 K 线往前推,不用任何花哨的批量算法。原因:带止损的交易是”路径依赖”的——这一根发生什么取决于之前的持仓状态,聪明写法极易出错且错了看不出来;笨办法的每笔成交都能手工验算。我们先手算好 7 个场景的标准答案,再让引擎去对——分毫不差。8 万根 K 线跑 2 秒,够用。

解剖演示。我们故意跑了一个教科书式的反面教材:30 分钟均线上穿 120 分钟均线就买、下穿就卖,止损 10 个 tick,当天强平。十个月真实数据,5,610 笔,净亏 −$23,744。拆开看:

成分 金额 每笔平均
策略本身(无摩擦毛利) ≈ −$1,865 −$0.33 ≈ 抛硬币
滑点 −$14,025 −$2.50
佣金 −$7,854 −$1.40
净结果 −$23,744 −$4.23

三个教训:“有信号”不等于”有优势”(毛利几乎为零);92% 的亏损是摩擦——零期望+高频率=定期向收费站捐款(第 4 课的活标本,5,610 笔里 4,755 笔死在那个 10 tick 的窄止损上,每次止损重付一遍过路费);这个坏消息回测 2 秒就给出,挂模拟盘要等三个月——回测系统真正卖的商品,是廉价而诚实的坏消息。

【与我们项目的连接】

上面每条规则都实现在项目的回测引擎里(backtest.py),7 个手算场景是它的永久考卷。−$23,744 的完整解剖在《初学者手册》第 17 节。往后你在任何报告里看到”净期望”三个字,背后都默认这六条规则全部生效。

【三个自测问题】

  1. “收盘价突破就按收盘价买入”错在哪里?
  2. 同一根 K 线里止损和止盈都触发了,为什么必须按止损算?
  3. 演示策略的最大死因是什么——策略烂,还是别的?

(答案:1. 收盘价在收盘那一刻才确定,拿它当买入价等于用了未来信息;必须下一根开盘才成交。2. K 线不记录内部先后顺序,无法证明止盈在前;选择对自己不利的假设是唯一不放水的做法。3. 别的:策略本身近似抛硬币(−$0.33/笔),真正的死因是 5,610 次交易的摩擦——92% 的亏损是成本。)