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

PineScript策略开仓后立即平仓问题求助

Market Structure Shift (MSS) 策略开仓后立即平仓问题分析与修复

问题概述

开发PineScript的MSS策略时,出现订单开仓后立即平仓的异常。需求为顺着识别出的MSS方向开仓,出现反向MSS时平仓,此前曾通过入场后重置条件解决过单K线反复开仓问题,怀疑此次问题与条件重置逻辑相关。

原代码

//@version=5
strategy("Market Structure (working copy)", "Market Structure (working copy)", true, max_labels_count = 500, max_lines_count = 500)

pivot_strength = input.int(3, "Pivot Strength", 1)
show_pivots = input.bool(false, "Show Pivots", inline = "PIV")
highs = input.color(color.blue, "", inline = "PIV")
lows = input.color(#f23645, "", inline = "PIV")
show_bos = input.bool(false, "Show BOS/MSS")
style = input.string("Dashed", "Line Style", options = ['Solid', 'Dashed', 'Dotted'])
enableFilter = input(true,  "Enable Backtesting Range Filtering")
fromDate   = input.time(timestamp("20 Jul 2023 00:00 +0300"), "Start Date")
toDate       = input.time(timestamp("20 Jul 2099 00:00 +0300"), "End Date")
tradeDateIsAllowed = not enableFilter or (time >= fromDate and time <= toDate)
ticks_target = input.int(60, "Ticks Target")
// Times are in UTC


type swing
    int _index = na
    float _val = na

method set_val(swing s, int i, float v) =>
    s._index := i
    s._val := v

method set_na(swing s) =>
    s._index := na
    s._val := na

var swing_high = swing.new()
var swing_low = swing.new()
var temp_hi = swing.new()
var temp_lo = swing.new()

var bool bull = na

sh = false
sl = false

bull_bos = false
bull_mss = false
bear_bos = false
bear_mss = false

var line_style = switch style
    "Solid" => line.style_solid
    "Dashed" => line.style_dashed
    "Dotted" => line.style_dotted
// drawing boxes on the sh and sl's
if not na(ta.pivothigh(high, pivot_strength, pivot_strength))
    swing_high.set_val(bar_index - pivot_strength, high[pivot_strength])
    sh := true // Sh and SL are used for the shapes drawn above and below sl and sh's 
    
if not na(ta.pivotlow(low, pivot_strength, pivot_strength))
    swing_low.set_val(bar_index - pivot_strength, low[pivot_strength])
    sl := true // Sh and SL are used for the shapes drawn above and below sl and sh's 


// ID MSS section 
if not na(swing_high._val)
    if close > swing_high._val 
        mss = (bull == false or na(bull))
        if mss
            bull_mss := true
            temp_hi.set_val(swing_high._index, swing_high._val)
            bear_mss := false  // Reset bear_mss when bull_mss is true
        else
            bull_bos := true
            temp_hi.set_val(swing_high._index, swing_high._val)
        bull := true
        swing_high.set_na()
        
if not na(swing_low._val)
    if close < swing_low._val
        mss = (bull == true or na(bull))
        if mss
            bear_mss := true
            temp_lo.set_val(swing_low._index, swing_low._val)
            bull_mss := false  // Reset bull_mss when bear_mss is true
        else
            bear_bos := true
            temp_lo.set_val(swing_low._index, swing_low._val)
        bull := false
        swing_low.set_na()


// MSS direction ascertained in here. 


if show_bos
    if bull_mss[1] or bull_bos[1]
        line.new(temp_hi._index, temp_hi._val, bar_index - 1, temp_hi._val, style = line_style, color = highs)
        label.new(math.floor(math.avg(temp_hi._index, bar_index - 1)), temp_hi._val, bull_mss[1] ? "MSS" : "BOS", textcolor = highs, color = #ffffff00, style = label.style_label_down)

    if bear_mss[1] or bear_bos[1]
        line.new(temp_lo._index, temp_lo._val, bar_index - 1, temp_lo._val, style = line_style, color = lows)
        label.new(math.floor(math.avg(temp_lo._index, bar_index - 1)), temp_lo._val, bear_mss[1] ? "MSS" : "BOS", textcolor = lows, color = #ffffff00, style = label.style_label_up)

plotshape(show_pivots and sh, style = shape.triangledown, location = location.abovebar, color = highs, offset = -pivot_strength, size = size.tiny)
plotshape(show_pivots and sl, style = shape.triangleup, location = location.belowbar, color = lows, offset = -pivot_strength, size = size.tiny)


// Entry conditions
var entry_condition_long = false
var entry_condition_short = false

// Variables to reset MSS conditions one bar later
var bool bull_mss_reset = false
var bool bear_mss_reset = false

// Check for entry based on MSS 
if bull_mss and tradeDateIsAllowed and strategy.opentrades < 1
    entry_condition_long := true

if bear_mss and tradeDateIsAllowed and strategy.opentrades < 1
    entry_condition_short := true

// Entry 
if entry_condition_long and bull_mss
    strategy.entry("Buy", strategy.long, 1)

if entry_condition_short and bear_mss  
    strategy.entry("Sell", strategy.short, 1)

// Exit conditions
var exit_condition_long = false
var exit_condition_short = false

// Check for exit based on opposing MSS

if bear_mss and tradeDateIsAllowed and strategy.opentrades > 0
    exit_condition_long:= true

if bull_mss and tradeDateIsAllowed and strategy.opentrades > 0
    exit_condition_short:= true


// Exit
if exit_condition_long
    strategy.close("Buy")
if exit_condition_short
    strategy.close("Sell")

问题原因

  1. MSS标记未及时重置:bull_mss/bear_mss在识别到MSS的K线中被设为true,但后续未主动重置,可能导致同一K线内开仓条件满足后,平仓条件也同时触发。
  2. 开仓/平仓条件依赖同一变量:开仓和平仓都直接使用bull_mss/bear_mss,当这些变量在K线内保持true状态时,会触发开仓后立即平仓。
  3. entry/exit条件未重置:entry_condition_long/exit_condition_long等变量被声明为var(持久化),一旦设为true后不会自动重置,导致后续K线持续触发操作。

修复方案

关键修改点

  • 每次触发开仓后,立即重置对应的entry条件和MSS标记,避免重复触发。
  • 平仓条件仅在新的反向MSS出现时触发,而非依赖当前MSS标记。
  • 移除不必要的持久化变量,改用临时变量或在每根K线重置条件。

修改后的代码

//@version=5
strategy("Market Structure (fixed)", "Market Structure (fixed)", true, max_labels_count = 500, max_lines_count = 500)

pivot_strength = input.int(3, "Pivot Strength", 1)
show_pivots = input.bool(false, "Show Pivots", inline = "PIV")
highs = input.color(color.blue, "", inline = "PIV")
lows = input.color(#f23645, "", inline = "PIV")
show_bos = input.bool(false, "Show BOS/MSS")
style = input.string("Dashed", "Line Style", options = ['Solid', 'Dashed', 'Dotted'])
enableFilter = input(true,  "Enable Backtesting Range Filtering")
fromDate   = input.time(timestamp("20 Jul 2023 00:00 +0300"), "Start Date")
toDate       = input.time(timestamp("20 Jul 2099 00:00 +0300"), "End Date")
tradeDateIsAllowed = not enableFilter or (time >= fromDate and time <= toDate)
ticks_target = input.int(60, "Ticks Target")
// Times are in UTC


type swing
    int _index = na
    float _val = na

method set_val(swing s, int i, float v) =>
    s._index := i
    s._val := v

method set_na(swing s) =>
    s._index := na
    s._val := na

var swing_high = swing.new()
var swing_low = swing.new()
var temp_hi = swing.new()
var temp_lo = swing.new()

var bool bull = na

sh = false
sl = false

bull_bos = false
bull_mss = false
bear_bos = false
bear_mss = false

var line_style = switch style
    "Solid" => line.style_solid
    "Dashed" => line.style_dashed
    "Dotted" => line.style_dotted
// drawing boxes on the sh and sl's
if not na(ta.pivothigh(high, pivot_strength, pivot_strength))
    swing_high.set_val(bar_index - pivot_strength, high[pivot_strength])
    sh := true // Sh and SL are used for the shapes drawn above and below sl and sh's 
    
if not na(ta.pivotlow(low, pivot_strength, pivot_strength))
    swing_low.set_val(bar_index - pivot_strength, low[pivot_strength])
    sl := true // Sh and SL are used for the shapes drawn above and below sl and sh's 


// ID MSS section 
if not na(swing_high._val)
    if close > swing_high._val 
        mss = (bull == false or na(bull))
        if mss
            bull_mss := true
            temp_hi.set_val(swing_high._index, swing_high._val)
            bear_mss := false  // Reset bear_mss when bull_mss is true
        else
            bull_bos := true
            temp_hi.set_val(swing_high._index, swing_high._val)
        bull := true
        swing_high.set_na()
        
if not na(swing_low._val)
    if close < swing_low._val
        mss = (bull == true or na(bull))
        if mss
            bear_mss := true
            temp_lo.set_val(swing_low._index, swing_low._val)
            bull_mss := false  // Reset bull_mss when bear_mss is true
        else
            bear_bos := true
            temp_lo.set_val(swing_low._index, swing_low._val)
        bull := false
        swing_low.set_na()


// MSS direction ascertained in here. 


if show_bos
    if bull_mss[1] or bull_bos[1]
        line.new(temp_hi._index, temp_hi._val, bar_index - 1, temp_hi._val, style = line_style, color = highs)
        label.new(math.floor(math.avg(temp_hi._index, bar_index - 1)), temp_hi._val, bull_mss[1] ? "MSS" : "BOS", textcolor = highs, color = #ffffff00, style = label.style_label_down)

    if bear_mss[1] or bear_bos[1]
        line.new(temp_lo._index, temp_lo._val, bar_index - 1, temp_lo._val, style = line_style, color = lows)
        label.new(math.floor(math.avg(temp_lo._index, bar_index - 1)), temp_lo._val, bear_mss[1] ? "MSS" : "BOS", textcolor = lows, color = #ffffff00, style = label.style_label_up)

plotshape(show_pivots and sh, style = shape.triangledown, location = location.abovebar, color = highs, offset = -pivot_strength, size = size.tiny)
plotshape(show_pivots and sl, style = shape.triangleup, location = location.belowbar, color = lows, offset = -pivot_strength, size = size.tiny)


// Entry & Exit Logic
// 开仓:仅当无持仓且当前MSS触发时执行
if bull_mss and tradeDateIsAllowed and strategy.opentrades == 0
    strategy.entry("Buy", strategy.long, 1)
    bull_mss := false // 触发后立即重置MSS标记,避免同一K线重复操作

if bear_mss and tradeDateIsAllowed and strategy.opentrades == 0
    strategy.entry("Sell", strategy.short, 1)
    bear_mss := false // 触发后立即重置MSS标记

// 平仓:仅当持仓方向与当前MSS方向相反时执行
if bear_mss and tradeDateIsAllowed and strategy.position_size > 0
    strategy.close("Buy")
    bear_mss := false

if bull_mss and tradeDateIsAllowed and strategy.position_size < 0
    strategy.close("Sell")
    bull_mss := false

修复说明

  1. 移除冗余的entry/exit条件变量:直接使用bull_mss/bear_mss结合持仓状态判断,减少变量复杂度。
  2. 触发操作后立即重置MSS标记:开仓或平仓后立即将对应的bull_mss/bear_mss设为false,避免同一K线内重复触发开平仓。
  3. 明确持仓方向判断:平仓时检查strategy.position_size(正数为多单,负数为空单),确保仅在反向MSS出现时平仓。

内容的提问来源于stack exchange,提问作者Adam Seeber

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:58:10