TradingView Pine脚本重绘、移动止损失效及告警异常问题求助
问题汇总
- 策略运行存在矛盾:设置
calc_on_order_fills=true时出现重绘(repainting)问题,关闭该参数后strategy.exit内的移动止损无法在入场首根K线生效,仅能在下一根K线触发 - 策略告警触发频率过高,待确认是否与重绘相关
- 已尝试以下方案均未解决问题:
- 改用ATR计算移动止损,替换入场订单中的
trail_price、trail_offset参数 - 采用前一根K线的open/close/high/low参数计算入场订单条件
- 增加
strategy.closedtrades.entry_time(strategy.closedtrades) != time或strategy.closedtrades.entry_bar_index(strategy.closedtrades) != bar_index判断逻辑
- 改用ATR计算移动止损,替换入场订单中的
问题根因
重绘与告警过频根源
calc_on_order_fills=true的运行逻辑是订单成交时,会在当前未收盘的K线内重新执行全量脚本计算。此时当前K线的价格数据是实时变动的未定型数据,必然导致信号重绘;同时未收盘K线内的重复计算会反复触发告警,这就是告警频率过高的直接原因。
另外代码中平均K线(Heikin Ashi)计算存在未来函数问题:HAhigh、HAlow直接引用当前未收盘K线的价格数据,没有偏移引用已收盘的历史K线,也会加重重绘问题。移动止损首根K线不生效根源
关闭calc_on_order_fills后,脚本默认在K线收盘时才更新持仓状态,入场当根K线内脚本识别不到持仓,自然不会执行strategy.exit挂载止损单,只能等到下一根K线才触发出场逻辑。同时代码中trail_price = strategy.position_avg_price的写法存在逻辑问题:trail_price是移动止损的激活价格,入场当根K线strategy.position_avg_price还未完成赋值,无法正确挂载止损。
修复方案
- 策略初始化参数关闭
calc_on_order_fills,保留calc_on_every_tick = false,从根源避免未收盘K线重复计算导致的重绘、告警重复问题。 - 修正平均K线计算逻辑,所有价格参数引用已收盘的前一根K线数据,消除未来函数。
- 调整出场逻辑:入场订单直接绑定固定止盈止损,保证入场当根就挂载好出场单;持仓超过1根K线后再启动移动止损跟踪,避免首根K线持仓状态识别延迟问题。
- 移除
strategy.exit中直接引用strategy.position_avg_price作为trail_price的写法,手动计算持仓后的最高/最低盈利点位,动态调整移动止损触发价。
修复后完整代码
//@version=5 strategy("My strategy", overlay=true, calc_on_every_tick = false, calc_on_order_fills = false) // Set exit levels with input options (optional) LimitPerc = input.int(title="Take Profit (0,1%)", minval=0, step=1, defval=10) * 0.001 StopPerc = input.int(title="Stop Loss / Trailing Offset (0,1%)", minval=0, step=1, defval=5) * 0.001 TrailPerc = input.int(title="Trailing Offset (0,1%)", minval=0, step=1, defval=2) * 0.001 //Movin Averages incl Plot //EMA emaplot = input (true, title="Show EMA on chart") len = input.int(minval=1, step=1, defval=9, title="ema Length") src = close[1] out = ta.ema(src, len) up = out > out[1] down = out < out[1] mycolor = up ? color.green : down ? color.red : color.blue plot(out and emaplot ? out :na, title="EMA", color=mycolor, linewidth=3) //SMA smaplot = input (true, title="Show SMA on chart") len2 = input.int(minval=1, step=1, defval=2, title="sma Length") src2 = close[1] out2 = ta.sma(src2, len2) up2 = out2 > out2[1] down2 = out2 < out2[1] mycolor2 = up2 ? color.green : down2 ? color.red : color.blue plot(out2 and smaplot ? out2 :na , title="SMA", color=mycolor2, linewidth=1) //Stochastic Momentum Index incl Plot //Stoch RSI a = input.int(minval=1, step=1, defval=2, title = "Percent K Length") b = input.int(minval=1, step=1, defval=2, title = "Percent D Length") // Range Calculation ll = ta.lowest (low[1], a) hh = ta.highest (high[1], a) diff = hh - ll rdiff = close[1] - (hh+ll)/2 // Nested Moving Average for smoother curves avgrel = ta.ema(ta.ema(rdiff,b),b) avgdiff = ta.ema(ta.ema(diff,b),b) // SMI calculations SMI = avgdiff != 0 ? (avgrel/(avgdiff/2)*100) : 0 SMIsignal = ta.ema(SMI,b) SMIup = SMI > SMI[1] SMIdown = SMI < SMI[1] //Heikin Ashi 修正为全量引用前一根已收盘K线数据 HAopen = (open[1]+close[1])/2 HAclose = ohlc4[1] HAhigh = math.max (high[1], open[1], close[1]) HAlow = math.min (low[1], open[1], close[1]) HAup = HAopen < HAclose HAdown = HAopen > HAclose //Conditions for trades LongCondition = HAup and SMIup and up and up2 and (strategy.opentrades == 0) ShortCondition = HAdown and SMIdown and down and down2 and (strategy.opentrades == 0) // 记录入场K线索引 var longEntryBar = na var shortEntryBar = na //Submit entry orders 直接绑定固定止盈止损,入场当根生效 if (LongCondition and time>timestamp(2022, 07, 04, 07, 00)) longStop = close * (1 - StopPerc) longLimit = close * (1 + LimitPerc) strategy.entry(id = "Long", direction = strategy.long, alert_message = "Place Long Order", comment = "Long Entry", stop=longStop, limit=longLimit) longEntryBar := bar_index if (ShortCondition and time>timestamp(2022, 07, 04, 07, 00)) shortStop = close * (1 + StopPerc) shortLimit = close * (1 - LimitPerc) strategy.entry(id = "Short", direction = strategy.short, alert_message = "Place Short Order", comment = "Short Entry", stop=shortStop, limit=shortLimit) shortEntryBar := bar_index // 持仓超过1根K线后启动移动止损 if (strategy.position_size > 0 and bar_index > longEntryBar) // 计算持仓后最高价 longHighest = ta.highest(high, bar_index - longEntryBar) // 移动止损价 longTrailStop = longHighest * (1 - TrailPerc) strategy.exit(id = "Long", alert_trailing = "Exit Long Order", stop=longTrailStop, comment = "Long Exit") if (strategy.position_size < 0 and bar_index > shortEntryBar) // 计算持仓后最低价 shortLowest = ta.lowest(low, bar_index - shortEntryBar) // 移动止损价 shortTrailStop = shortLowest * (1 + TrailPerc) strategy.exit(id = "Short", alert_trailing = "Exit Short Order", stop=shortTrailStop, comment = "Short Exit") //END
内容的提问来源于stack exchange,提问作者TomTucker
相关产品推荐
相关产品推荐

