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")
问题原因
- MSS标记未及时重置:
bull_mss/bear_mss在识别到MSS的K线中被设为true,但后续未主动重置,可能导致同一K线内开仓条件满足后,平仓条件也同时触发。 - 开仓/平仓条件依赖同一变量:开仓和平仓都直接使用
bull_mss/bear_mss,当这些变量在K线内保持true状态时,会触发开仓后立即平仓。 - 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
修复说明
- 移除冗余的entry/exit条件变量:直接使用
bull_mss/bear_mss结合持仓状态判断,减少变量复杂度。 - 触发操作后立即重置MSS标记:开仓或平仓后立即将对应的
bull_mss/bear_mss设为false,避免同一K线内重复触发开平仓。 - 明确持仓方向判断:平仓时检查
strategy.position_size(正数为多单,负数为空单),确保仅在反向MSS出现时平仓。
内容的提问来源于stack exchange,提问作者Adam Seeber
相关产品推荐
相关产品推荐

