Pine Script多仓位独立止损设置异常问题求助
多头寸独立止损异常的Pine Script策略问题
我用Pine Script写了一个可同时持有多个头寸的做空策略,想给每个头寸设置独立止损,但结果异常——只有最新仓位的止损正常,旧仓位的止损计算错误。怀疑是重绘问题但找不到解决办法,试过用数组存储止损值,求相关建议或替代方案。
附问题截图:
原代码
//@version=5 strategy("DIBS SELL", overlay=true, pyramiding=1000) // Start date of strategy startHour = input.int(title="Start Hour", defval=14, minval=0, maxval=23) startDate = input.int(title="Start Date", defval=14, minval=1, maxval=31) startMonth = input.int(title="Start Month", defval=7, minval=1, maxval=12) startYear = input.int(title="Start Year", defval=2022, minval=1800, maxval=2100) // See if this bar's time happened on/after start date afterStartDate = (time >= timestamp(syminfo.timezone, startYear, startMonth, startDate, startHour, 0)) // Session for trade to execute session = input("0000-1630,1830-0000:1234567") t = time(timeframe.period, session) // Pair currently being traded pair = syminfo.basecurrency + "/" + syminfo.currency // Condition insideBar = high < high[1] and low > low[1] prevInsideBar = ta.barssince(insideBar) // Entry point sellPoint = low - (1 * 10 * syminfo.mintick) sellStopLoss = ((high[(bar_index - strategy.opentrades.entry_bar_index(strategy.opentrades - 1)) + 1] - (strategy.opentrades.entry_price(strategy.opentrades - 1))) / syminfo.mintick) sellStopLossAlert = high + (2 * 10 * syminfo.mintick) sellTakeProfit = ((high[(bar_index - strategy.opentrades.entry_bar_index(strategy.opentrades - 1)) + 1] - (strategy.opentrades.entry_price(strategy.opentrades - 1))) / syminfo.mintick) + 20 sellTakeProfitAlert = sellPoint - (sellStopLossAlert - sellPoint) - (2 * 10 * syminfo.mintick) // Quantity calculation quantity = 100 - strategy.opentrades quantityAdd = 100 - strategy.opentrades - 1 quantityAbove = 91 + strategy.opentrades + 1 quantityAddAbove = 91 + strategy.opentrades qtyStopLoss = strategy.opentrades.size(strategy.opentrades) qtyTakeProfit = strategy.opentrades.size(strategy.opentrades) // Alert message msg_sell = 'q=' + str.tostring(quantity) + ' fsl=' + str.tostring(sellStopLossAlert) + ' e=oandapractice' + ' s=' + str.tostring(pair) + ' b=short' + ' t=market' + ' a=SUBSELL' msg_sell_add = 'q=' + str.tostring(quantityAdd) + ' fsl=' + str.tostring(sellStopLossAlert) + ' ftp=' + str.tostring(sellTakeProfitAlert) + ' e=oandapractice' + ' s=' + str.tostring(pair) + ' b=short' + ' t=market' + ' a=SUBSELL' // Entry ID tradeID = str.tostring(strategy.opentrades + strategy.closedtrades) tradeIDAdd = str.tostring(strategy.opentrades + strategy.closedtrades + 1) // Entry if insideBar and afterStartDate and not na(t) if strategy.opentrades > 10 strategy.entry(tradeID, strategy.short, qty=quantityAbove, stop=sellPoint, alert_message=msg_sell) strategy.entry(tradeIDAdd, strategy.short, qty=quantityAddAbove, stop=sellPoint, alert_message=msg_sell_add) else strategy.entry(tradeID, strategy.short, qty=quantity, stop=sellPoint, alert_message=msg_sell) strategy.entry(tradeIDAdd, strategy.short, qty=quantityAdd, stop=sellPoint, alert_message=msg_sell_add) // Cancel open order after 1 completed candle after inside bar if prevInsideBar == 1 strategy.cancel_all() // To identify inside bar candle plotshape(insideBar, style=shape.arrowdown, color=color.white) // Plot session bgcolor(not na(t) ? color.new(color.green, 90) : na) // Array sellStop = high[1] + (2 * 10 * syminfo.mintick) var label _label = na var float [] LABELARRAY = array.new_float() if bar_index and prevInsideBar == 1 and strategy.opentrades > strategy.opentrades[1] array.push(LABELARRAY, sellStop) // Stop Loss strategy.exit("Short Exit", from_entry=strategy.opentrades.entry_id(strategy.opentrades), qty=qtyStopLoss, loss=sellStopLoss)
问题核心原因
- 止损计算依赖动态变量:你用
strategy.opentrades - 1获取旧仓位的入场信息,但strategy.opentrades会随新仓位开仓持续变化,导致每次新仓位开仓后,旧仓位的止损逻辑会被重新指向最新仓位的入场数据,直接覆盖旧止损设置,这就是重绘的根源。 - 止损指令只绑定最新仓位:
strategy.exit里的from_entry=strategy.opentrades.entry_id(strategy.opentrades)只会关联当前最新的那个仓位,旧仓位根本没被分配对应的止损指令。 - 数组存储未落地:虽然定义了数组存止损值,但没有把数组里的数值对应到具体仓位的退出逻辑上,等于白存。
修复方案(核心:给每个仓位绑定固定止损值)
关键思路
- 开仓时就计算好该仓位的止损/止盈价,和对应的入场ID一起存入数组,确保每个仓位的止损值固定不变。
- 遍历所有当前持仓,通过入场ID从数组中匹配对应的止损价,给每个仓位单独设置
strategy.exit指令。
完整修复代码
//@version=5 strategy("DIBS SELL FIXED", overlay=true, pyramiding=1000) // 策略启动日期 startHour = input.int(title="Start Hour", defval=14, minval=0, maxval=23) startDate = input.int(title="Start Date", defval=14, minval=1, maxval=31) startMonth = input.int(title="Start Month", defval=7, minval=1, maxval=12) startYear = input.int(title="Start Year", defval=2022, minval=1800, maxval=2100) afterStartDate = (time >= timestamp(syminfo.timezone, startYear, startMonth, startDate, startHour, 0)) // 交易时段 session = input("0000-1630,1830-0000:1234567") t = time(timeframe.period, session) // 交易对 pair = syminfo.basecurrency + "/" + syminfo.currency // 内包K线条件 insideBar = high < high[1] and low > low[1] prevInsideBar = ta.barssince(insideBar) // 入场点计算(保留原逻辑) sellPoint = low - (1 * 10 * syminfo.mintick) // 开仓时计算当前仓位的止损/止盈,固定下来 currentTradeStopLoss = high[1] + (2 * 10 * syminfo.mintick) currentTradeTakeProfit = sellPoint - (currentTradeStopLoss - sellPoint) - (2 * 10 * syminfo.mintick) // 持仓数量计算 quantity = 100 - strategy.opentrades quantityAdd = 100 - strategy.opentrades - 1 quantityAbove = 91 + strategy.opentrades + 1 quantityAddAbove = 91 + strategy.opentrades // 警报消息 msg_sell = 'q=' + str.tostring(quantity) + ' fsl=' + str.tostring(currentTradeStopLoss) + ' e=oandapractice' + ' s=' + str.tostring(pair) + ' b=short' + ' t=market' + ' a=SUBSELL' msg_sell_add = 'q=' + str.tostring(quantityAdd) + ' fsl=' + str.tostring(currentTradeStopLoss) + ' ftp=' + str.tostring(currentTradeTakeProfit) + ' e=oandapractice' + ' s=' + str.tostring(pair) + ' b=short' + ' t=market' + ' a=SUBSELL' // 存储每个仓位的入场ID、止损、止盈的数组 var string[] entryIDs = array.new_string() var float[] stopLossValues = array.new_float() var float[] takeProfitValues = array.new_float() // 开仓逻辑 if insideBar and afterStartDate and not na(t) // 生成唯一入场ID tradeID = str.tostring(strategy.opentrades + strategy.closedtrades) tradeIDAdd = str.tostring(strategy.opentrades + strategy.closedtrades + 1) if strategy.opentrades > 10 strategy.entry(tradeID, strategy.short, qty=quantityAbove, stop=sellPoint, alert_message=msg_sell) strategy.entry(tradeIDAdd, strategy.short, qty=quantityAddAbove, stop=sellPoint, alert_message=msg_sell_add) else strategy.entry(tradeID, strategy.short, qty=quantity, stop=sellPoint, alert_message=msg_sell) strategy.entry(tradeIDAdd, strategy.short, qty=quantityAdd, stop=sellPoint, alert_message=msg_sell_add) // 开仓成功后,把ID和对应的止损、止盈存入数组(一次开两个仓位,存两次) if strategy.opentrades > strategy.opentrades[1] array.push(entryIDs, tradeID) array.push(stopLossValues, currentTradeStopLoss) array.push(takeProfitValues, currentTradeTakeProfit) array.push(entryIDs, tradeIDAdd) array.push(stopLossValues, currentTradeStopLoss) array.push(takeProfitValues, currentTradeTakeProfit) // 取消未成交订单 if prevInsideBar == 1 strategy.cancel_all() // 遍历所有持仓,给每个仓位设置独立止损止盈 for i = 0 to strategy.opentrades - 1 entryID = strategy.opentrades.entry_id(i) // 找到该ID在数组中的索引 idx = array.indexof(entryIDs, entryID) if idx != -1 sl = array.get(stopLossValues, idx) tp = array.get(takeProfitValues, idx) // 给每个仓位单独设置退出指令 strategy.exit("Exit_" + entryID, from_entry=entryID, loss=sl, limit=tp) // 绘图部分 plotshape(insideBar, style=shape.arrowdown, color=color.white) bgcolor(not na(t) ? color.new(color.green, 90) : na)
修复点说明
- 固定止损值:开仓时基于当时的K线数据计算止损/止盈,存入数组后不再变动,彻底避免重绘。
- 一对一绑定:每个入场ID对应唯一的止损值,遍历持仓时通过ID精准匹配,不会串仓。
- 遍历设置止损:用
for循环处理每一个持仓,确保每个仓位都有独立的退出指令,不会只处理最新仓位。
内容的提问来源于stack exchange,提问作者Danny Harry
相关产品推荐
相关产品推荐

