保持敬畏之心
交易是一场持久战

Pine Script(76):为什么Pyramiding的加仓设置会失效

#Pine Script入门教学

你是否遇到过这样的困惑:在 strategy() 函数里明明白白地设置了 pyramiding=0(禁止加仓),结果回测一看,策略居然在同一根K线上开了好几笔同向订单,持仓量远超预期。

这并不是 TradingView 的Bug,而是其回测工作机制中一个非常重要的细节所导致的,问题的根源在于 订单生成和订单执行之间存在一个时间差和逻辑差。

我们可以把TradingView处理订单的过程想象成两个独立的部门:

订单生成: 这个部门负责审查你的代码逻辑,当代码在某根K线上运行时,它会逐行检查你的开仓条件。假设你写了三个独立的if语句来分别判断三个不同的开仓信号,在代码运行的那一瞬间,策略的持仓还是0。因此当第一个 if 条件满足时,“生成部”一看,当前没仓位,符合 pyramiding=0 的规则,于是批准生成一个订单A。紧接着代码运行到第二个 if,它的条件也满足了,“生成部”再检查持仓,由于订单A此时还只是生成状态,并未执行,所以系统看到的持仓依然是0!于是,它也批准生成了订单B。同理订单C也可能被批准。

订单执行: 这个部门负责把“生成部”批准的订单拿到市场上去撮合。现在订单A、B、C都被送到了这里,如果它们都是市价单,或者它们的止损/限价都被当前K线的价格波动所触及,那么“执行部”就会把它们全部成交。等到订单A成交后,系统才反应过来已经有持仓了,但此时已经来不及取消订单B和C了,因为它们几乎是同时被执行的。

结论就是,在订单生成的那个瞬间,每个订单都是合规的。但由于它们在订单执行阶段被打包成交,最终导致了对 pyramiding 规则的违反。

经典的超额开仓策略

我们来看一个具体的例子。下面这个策略有三个独立的做多信号,并且我们明确设置了 pyramiding=0,禁止任何加仓。

策略代码如下:

//@version=6
strategy(title="加仓与多个开仓订单", pyramiding=0,overlay=true)

// 三个独立的开仓条件
fiveBarHigh     = high == ta.highest(high, 5)
volumeCrossover = ta.crossover(volume, ta.sma(volume, 5))
maCrossover     = ta.crossover(ta.ema(close, 2), ta.ema(close, 15))

// 根据不同条件提交订单
if fiveBarHigh
    strategy.entry("Long Entry #1", strategy.long)

if volumeCrossover
    strategy.entry("Long Entry #2", strategy.long, stop=high)

if maCrossover
    strategy.entry("Long Entry #3", strategy.long,
         stop=high + 10 * syminfo.mintick)

// 周五平掉所有仓位
if dayofweek == dayofweek.friday
    strategy.close_all()

代码的逻辑很清晰:我们用三个独立的 if 语句来提交订单,这三个条件并非互斥,完全可能在同一根K线上同时满足。当我们把这个策略加载到图表上,会发现尽管加仓已经被禁用,但策略依然在很多地方开了多笔同向订单。

这就是前面提到的“生成 vs 执行”机制在作祟,我们有两种方法可以解决这个问题。

方案一:使用OCA订单组(好,但不完美)

OCA 的全称是 “One-Cancels-All”,即一笔成交,其余取消。我们可以把这三个可能同时触发的开仓订单放进同一个OCA组里。这样当其中任何一笔订单成交后,TradingView会自动尝试取消组内的其他所有待处理订单。

修改后的代码如下:

//@version=6
strategy(title="加仓与多个开仓订单", pyramiding=0,overlay=true)

// 交易条件不变
fiveBarHigh     = high == ta.highest(high, 5)
volumeCrossover = ta.crossover(volume, ta.sma(volume, 5))
maCrossover     = ta.crossover(ta.ema(close, 2), ta.ema(close, 15))

//增加oca参数,捆绑在一起
if fiveBarHigh
    strategy.entry("Long Entry #1", strategy.long,
         oca_type=strategy.oca.cancel, oca_name="Long Entry")

if volumeCrossover
    strategy.entry("Long Entry #2", strategy.long, stop=high,
         oca_type=strategy.oca.cancel, oca_name="Long Entry")

if maCrossover
    strategy.entry("Long Entry #3", strategy.long,
         stop=high + 10 * syminfo.mintick,
         oca_type=strategy.oca.cancel, oca_name="Long Entry")

if dayofweek == dayofweek.friday
    strategy.close_all()

我们为每个 strategy.entry() 函数增加了两个参数:oca_type=strategy.oca.canceloca_name="Long Entry"。这就像给这三笔订单贴上了同一个小组标签,系统知道它们是关联的。

OCA 方案并非100%可靠!如果你的多个订单都是市价单,或者挂单价格非常接近,那么在第一个订单成交的瞬间,TradingView可能根本来不及取消其他订单,导致多笔成交。在我们的例子中,由于一个是市价单,另外两个是不同价格的止损单,价格有区分度,所以OCA能够生效。

方案二:创建互斥的开仓条件(釜底抽薪,强烈推荐)

与其在订单执行层面去补救,不如在订单生成的源头就掐断所有可能。我们可以重构代码逻辑,确保在任何一根K线上,最多只有一个开仓条件能够成立,这就是互斥条件。

修改后的代码如下:

//@version=6
strategy(title="加仓与多个开仓订单", pyramiding=0,overlay=true)

// 条件不变
fiveBarHigh     = high == ta.highest(high, 5)
volumeCrossover = ta.crossover(volume, ta.sma(volume, 5))
maCrossover     = ta.crossover(ta.ema(close, 2), ta.ema(close, 15))

// 逻辑互斥
if fiveBarHigh and not volumeCrossover and not maCrossover
    strategy.entry("Long Entry #1", strategy.long)

if volumeCrossover and not fiveBarHigh and not maCrossover
    strategy.entry("Long Entry #2", strategy.long, stop=high)

if maCrossover and not fiveBarHigh and not volumeCrossover
    strategy.entry("Long Entry #3", strategy.long,
         stop=high + 10 * syminfo.mintick)

if dayofweek == dayofweek.friday
    strategy.close_all()

if 语句的变化:我们现在要求,当一个条件(如 fiveBarHigh)为 true 时,另外两个条件必须同时为 falsenot volumeCrossover and not maCrossover),才会提交订单。这就从根本上杜绝了在同一根K线上生成多个订单的可能性。

这种方法很可靠,无论你用的是市价单还是限价单,它都能保证策略严格遵守你的 pyramiding 设置。虽然这种写法会稍微增加代码的复杂度,但它强迫你思考信号的优先级,当多个信号同时出现时,你的策略到底该听谁的?互斥逻辑能让你把这种优先级清晰地定义在代码中,这本身就是一种严谨的策略设计思路。

总结

pyramiding 设置“失效”并非Bug,而是回测引擎在处理并发订单时的固有机制。

要解决这个问题,你有两种选择:

  1. OCA订单组: 简单快捷,但在处理多个市价单或价格相近的挂单时可能失效。
  2. 互斥的开仓条件:能从逻辑源头保证单次计算只生成一个订单,是更稳健的解决方案。

下次当你再遇到类似问题时,就不要再怀疑了,检查一下你的开仓逻辑,看看是不是给了回测引擎同时批准多个订单的机会。

赞(0)
未经允许不得转载:图道交易 » Pine Script(76):为什么Pyramiding的加仓设置会失效
分享到

评论 抢沙发

登录

找回密码

注册