TradingView Pine Script百分比止盈止损脚本运行异常排查
Pine Script 百分比止盈止损脚本异常修复
问题成因
原脚本的两个异常完全是strategy.exit()调用逻辑错误导致的:
- 两个分段止盈的exit指令都绑定了止损参数,两个指令会独立监听止损触发条件,SL触发时两个指令会分别执行平仓,直接导致重复平仓、仓位超卖
- TP1触发后没有作废对应挂单,TP2的exit指令没有正确匹配剩余仓位,导致TP2触发时仅平半仓,无法平完所有剩余头寸
- 初始仓位取值没有在开仓时锁定,TP1部分平仓后数值会偏移,导致平仓数量计算错误
核心修复逻辑
- 拆分止盈、止损指令:单独设置全仓止损的exit指令,两个分段止盈指令不再绑定止损参数,从根源避免止损触发时重复平仓
- 增加TP1成交状态标记:开仓时重置标记,TP1成交后自动取消TP1对应的挂单,仅保留TP2指令监听剩余仓位
- 开仓当根K线直接锁定初始开仓量,不会因为后续部分平仓导致仓位数值计算偏移
- 修正TP2的平仓规则,TP1部分平仓后,TP2触发时自动平掉全部剩余仓位,不会出现仓位残留
修复后完整代码
// This source code is subject to the terms of the Mozilla Public License 2.0 // © SafetyHammer // 修复分段止盈止损逻辑异常 //@version=4 strategy(title="Take profit (% of instrument price)", overlay=true, pyramiding=0, initial_capital=10000, default_qty_type=strategy.cash, default_qty_value=10000, commission_type=strategy.commission.percent, commission_value=0.1) // ————参数设置———— // 均线参数 FastPeriod = input(title="Fast MA Period", type=input.integer, defval=9, minval=1, group="Moving Average") SlowPeriod = input(title="Slow MA Period", type=input.integer, defval=50, minval=1, group="Moving Average") // 止盈止损参数 TP1Perc = input(title="Long TP1 (%)", type=input.float, minval=0.0, step=0.1, defval=0.5, group="TP & SL") TP2Perc = input(title="Long TP2 (%)", type=input.float, minval=0.0, step=0.1, defval=1, group="TP & SL") SLPerc = input(title="Long Stop Loss (%)", type=input.float, minval=0.0, step=0.1, defval=0.5, group="TP & SL") TP1_Ratio = input(title="Close Position % @ TP1", type=input.float, defval=50, step=1, group="TP & SL", tooltip="TP1触发时平仓的仓位比例,例:50代表平50%仓位")/100 // ————指标计算———— fastSMA = ema(close, FastPeriod) slowSMA = ema(close, SlowPeriod) // 交易信号 enterLong = crossover(fastSMA, slowSMA) // 绘图 plot(series=fastSMA, color=color.green, title="Fast MA", linewidth=2) plot(series=slowSMA, color=color.red, title="Slow MA", linewidth=2) // ————价格与仓位计算———— var float initialPosSize = na var bool tp1Filled = false // 开仓时锁定初始仓位,重置TP1状态 if enterLong initialPosSize := strategy.equity / close tp1Filled := false // 百分比转价格计算 tp1Price = strategy.position_size > 0 ? strategy.position_avg_price * (1 + TP1Perc / 100) : na tp2Price = strategy.position_size > 0 ? strategy.position_avg_price * (1 + TP2Perc / 100) : na slPrice = strategy.position_size > 0 ? strategy.position_avg_price * (1 - SLPerc / 100) : na // 检测TP1是否成交 if strategy.position_size > 0 and strategy.position_size < initialPosSize * 0.99 tp1Filled := true // ————下单逻辑———— // 开多单 if enterLong strategy.entry(id="Long", long=true) // 持仓时挂单 if strategy.position_size > 0 // 全仓止损,单独挂单避免重复平仓 strategy.exit("SL", from_entry="Long", stop=slPrice, qty=initialPosSize) // TP1未成交时挂TP1部分止盈单 if not tp1Filled strategy.exit("TP1", from_entry="Long", limit=tp1Price, qty=initialPosSize * TP1_Ratio) // TP1成交后挂TP2全平剩余仓位 else strategy.exit("TP2", from_entry="Long", limit=tp2Price) // ————止盈止损价位绘图———— plot(series=(strategy.position_size > 0 and not tp1Filled) ? tp1Price : na, color=color.new(color.green, 0), style=plot.style_circles, linewidth=1, title="Take Profit 1") plot(series=(strategy.position_size > 0 and tp1Filled) ? tp2Price : na, color=color.new(color.green, 0), style=plot.style_circles, linewidth=1, title="Take Profit 2") plot(series=(strategy.position_size > 0) ? slPrice : na, color=color.new(color.red, 0), style=plot.style_circles, linewidth=1, title="Stop Loss")
验证说明
- 修复后策略测试器可以正确识别TP1、TP2、SL三类成交事件
- TP1触发时仅平设定比例的仓位,TP2触发时自动平掉全部剩余仓位
- SL触发时仅执行一次全仓平仓,不会出现重复平仓的错误
- 可以直接调整参数适配不同品种、不同止盈止损比例的需求
内容的提问来源于stack exchange,提问作者Fantazma
相关产品推荐
相关产品推荐

