【TBQuant3-新手指南】量化回测的两大陷阱:“信号闪烁”与“偷价”

量化回测的两大陷阱:“信号闪烁”与“偷价”

在量化交易的世界里,回测是策略从构想走向实战的必经之门。一道完美的回测资金曲线,是每个交易者梦寐以求的圣杯。然而,这条曲线往往隐藏着致命的幻觉——许多在回测中表现优异的策略,一旦投入实盘,便会失效甚至亏损。究其根源,“信号闪烁”与“未来函数偷价”是制造这些幻觉的两大元凶。只有彻底理解并根除它们,才能锻造出经得起市场考验的可靠策略。

第一部分:信号闪烁

什么是信号闪烁?

信号闪烁,指的是在单根K线的形成过程中,交易信号在某个瞬间出现,但在该K线最终走完并收盘时,这个信号又消失了的现象。

信号闪烁是如何产生的?

其核心原因在于:策略逻辑错误地依赖于K线盘中不稳定的、瞬时的中间价格数据,如最新价(close),而不是一个稳定的图表价格价格。

典型场景还原:

  • 策略逻辑: “当价格close突破上一根K线的最高价时,立即开仓买入。”
//错误的写法
Events
    OnBar(ArrayRef<Integer> indexs)
    {
        Numeric a = Highest(high[1], 5);
        if(close > a)
        {
            buy(1,close);
        }
    }
  • 回测中的过程:当前K线正在运行中,价格一路上冲,瞬间突破了上一根K线的最高点。图表检测到这一突破,立刻记录一个“开多”信号,并以理想化的最新价标记成交。然而,市场并未继续上涨,价格随后回落。当这根K线最终收盘时,其收盘价已经低于了上一根K线的最高点。
  • 在回测中: 系统忽略了一次失败的开仓和平仓(由于信号消失,策略多下一单,并且丧失了平仓的方法),这次交易可能是小幅盈利或亏损,但重要的是,它掩盖了一个事实,一个开仓的事实。在实盘中: 更可能的情况是,下单后,价格已经回落,导致持仓变成无法处理的情况。
  • 图示1:错误情况的展示

如何根治信号闪烁?

黄金法则:永远基于已经确定的历史数据做决策。

  1. 使用“收盘价模型”: 这是最根本的解决方法。将策略的所有逻辑判断延迟到K线结束时进行。例如,将策略改为:“如果本根K线收盘后,其收盘价突破了上一根K线的最高价,那么在下一根K线开盘时买入。” 这样,所有的信号都建立在已经固定的数据之上,不会再发生变化。
  2. 使用正确的价格: 例如上个例子中,在编写代码时,确保条件判断引用的是已经固定或相对固定的值,比如HIGH,LOW。这个例子纠正了上面错误例子的问题。
//正确
Events
    OnBar(ArrayRef<Integer> indexs)
    {
        Numeric a = Highest(high[1], 5);
        if(high > a)
        {
            buy(1,max(open,a));
        }
    }

3. 审阅交易记录: 在回测报告中,仔细检查每一笔交易的开仓信号。问自己一个问题:“在这根K线彻底走完后,这个开仓信号是否依然成立?” 如果答案是否定的,那么你的策略就存在信号闪烁。

4. 进行逐笔数据回测: 在有条件的情况下,盘中或利用回放观察策略变化,有闪烁肉眼可以看到。

第二部分:偷价和未来函数

如果说信号闪烁是让你“抓不到”信号,那么偷价则是让你在回测中“作弊”,它制造出的完美盈利假象,危害性更大。

什么是偷价和未来函数?

  • 未来函数: 指策略在回测的某个时间点上,使用了在该时点还不可能知道的未来信息。
  • 偷价: 指在回测中,系统使用了一个在信号触发时点不可能成交的、过于理想化的价格来进行盈亏计算。

两者的共同本质: 都是在回测中开辟了一条“隧道”,让策略能够“先知先觉”,而在实盘中完全无法复现回测的辉煌战绩。

未来函数与偷价的典型场景

场景一:最低价偷价买入

  • 策略逻辑: “当价格突破20日高点时,以当日最低价开仓买入。”
  • 问题剖析: 突破行为发生在价格已经上涨到一定程度之后。此时,当天的“最低价”很可能成为过去,你绝无可能回到过去,以那个最低价格成交。这是一种典型的“偷价”行为,它极大地低估了实际的成交价,使得回测中的入场价显得过于完美。
//错误案例
Events
    OnBar(ArrayRef<Integer> indexs)
    {
        buy(1,low);
        sell(1,high);
    }


场景二:信号价格加入有利偏移


//错误
Events
    OnBar(ArrayRef<Integer> indexs)
    {
        Numeric a = Highest(high[1], 5);
        if(high > a)
        {
            buy(1,max(open,a)-10);
        }
    }

在买入开仓上,减去一个额外的点差。相当于每次偷了一个固定金额。不要小看偷得少(比如1跳),积累下来曲线就会更好看。

如何杜绝未来函数与偷价?

核心原则:在回测的任何一个时间点,策略只能使用该时点及之前的历史数据。

  1. 采用合理的成交价模型:例如使用 Open(下根K线开盘价)作为成交价。
  2. 警惕特殊函数: 某些用于识别峰谷的函数(如 zigzag 等),如果使用不当,可能会在算法中引入未来信息,需要仔细审查其机制。
  3. 注意不要错标价格,用错了价格,有时候偷价可能是无心之举。


结论:从“回测幻境”走向“实盘赢家”

“信号闪烁”与“未来函数偷价”是量化交易者在策略开发初期必须跨过的两道鸿沟。它们一个让策略信号变得虚无缥缈,无法捕捉;另一个则让策略绩效变得虚假繁荣,不堪一击。

要打造一个坚实可靠的策略,必须秉持着比法庭证据更严谨的态度对待回测:

  • 根治闪烁: 坚持使用收盘价或确定的历史数据进行逻辑判断。
  • 杜绝偷价: 确保每一个决策和成交价都立足于当下,不占未来的丝毫便宜。

最终,一个策略的价值不在于它在历史数据上能画出多美的曲线,而在于其逻辑的严谨性与在实盘中的复现能力。记住,在量化交易中,可靠性永远优先于回测收益率。 只有经得起“真实性”拷问的策略,才真正具备在残酷市场中生存并盈利的资格。

【TBQuant3-新手指南】如何查看回测报告?
如何避免偷价
【TBQuant3-新手指南】如何在K线图启动量化交易
【TBQuant3-新手指南】 委托偏移是什么?
【TBQuant3-新手指南】定时登录的设置
偷价和信号闪烁是啥意思?和滑点有啥不一样
咨询偷价问题
新手对信号闪烁的几个疑惑
回测无信号闪烁,实盘中出现信号问题。
【TBQuant3-新手指南】如何用同一个策略回测多个品种,并生成全部品种的组合曲线

王老师👍

学习了