You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)只会关联当前最新的那个仓位,旧仓位根本没被分配对应的止损指令。
  • 数组存储未落地:虽然定义了数组存止损值,但没有把数组里的数值对应到具体仓位的退出逻辑上,等于白存。

修复方案(核心:给每个仓位绑定固定止损值)

关键思路

  1. 开仓时就计算好该仓位的止损/止盈价,和对应的入场ID一起存入数组,确保每个仓位的止损值固定不变。
  2. 遍历所有当前持仓,通过入场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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 09:33:17