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

回测异常:我的Pull-back策略为何开仓即平仓?

策略回测异常排查:开仓同时平仓问题

我采用Pull-back策略开仓,以近期Swing low(图中绿线所示)作为止损,设置1:1风险回报比。但回测时发现,代码在多数情况下会在开仓的同时平仓,仅少数交易正常。

异常交易截图

异常交易截图

开仓/平仓逻辑代码

//long condition
// we go long when there is a buy signal and no opentrades.

longCondition = buy_signal and strategy.opentrades == 0

// entry
if longCondition
    //Stop loss will be a recent swing low
    longSL = stopLevel

    //we will target for 1:1 risk/reward from stop loss
    longTP = close + (close - longSL)

    strategy.entry("LONG", strategy.long, comment = "LONG")
    strategy.exit("EXIT LONG", "LONG", stop = longSL, limit = longTP, comment = "LONG SL/TP")

正常交易示例截图

正常交易截图

Swing High/Low及Simple Pull-Back计算代码

//====LOGIC FOR SWING HIGH/LOW====
strategy("SIMPLE PULL BACK + SWING HIGH/LOW", overlay=true, precision = 4, initial_capital=1000, default_qty_type=strategy.percent_of_equity, default_qty_value=100, currency=currency.USD, process_orders_on_close=true, pyramiding=0)

// Inputs
pvtLenL       = input.int(3, minval=1, title="Pivot Length Left Hand Side")
pvtLenR       = input.int(3, minval=1, title="Pivot Length Right Hand Side")
showStop      = input.bool(true, title="Show Recent Low Stop?")

// Get High and Low Pivot Points
pvthi_ = ta.pivothigh(high, pvtLenL, pvtLenR)
pvtlo_ = ta.pivotlow(low, pvtLenL, pvtLenR)

// Force Pivot completion before plotting.
Shunt = 1 //Wait for close before printing pivot? 1 for true 0 for flase
maxLvlLen = 0 //Maximum Extension Length
pvthi = pvthi_[Shunt]
pvtlo = pvtlo_[Shunt]

// Count How many candles for current Pivot Level, If new reset.
counthi = ta.barssince(not na(pvthi))
countlo = ta.barssince(not na(pvtlo))
 
pvthis = fixnan(pvthi)
pvtlos = fixnan(pvtlo)
hipc = ta.change(pvthis) != 0 ? na : color.fuchsia
lopc = ta.change(pvtlos) != 0 ? na : color.rgb(0, 207, 7)   

// Stop Levels
stopLevel = ta.valuewhen(pvtlo_, low[pvtLenR], 0)

// ====LOGIC FOR PULL-BACK====
lookback = input(defval = 5, title = 'Lookback')

lower_barrier = input(defval = 20, title = 'Lower Barrier')
lower_threshold = input(defval = 33, title = 'Lower Threshold')

upper_barrier = input(defval = 80, title = 'Upper Barrier')
upper_threshold = input(defval = 67, title = 'Upper Threshold')

rsi = ta.rsi(close, lookback)

buy_signal  = rsi >= lower_barrier and rsi < rsi[1] and rsi[1] > lower_barrier and rsi[1] < lower_threshold and rsi[2] < lower_barrier
alertcondition(buy_signal, title = "LONG")

sell_signal = rsi <= upper_barrier and rsi > rsi[1] and rsi[1] < upper_barrier and rsi[1] > upper_threshold and rsi[2] > upper_barrier

异常原因排查及解决方案

核心问题:止损价高于开仓价,触发即时平仓

你的策略设置了process_orders_on_close=true,订单在收盘价执行。当计算出的stopLevel(近期Swing low对应价格)大于等于开仓K线的收盘价时,多单的止损逻辑(价格跌破止损价平仓)会被立刻触发——因为当前价格已经低于止损价,导致开仓的同时直接平仓。

具体修正方案

  1. 修正止损价计算逻辑
    当前用未延迟的pvtlo_取止损价,可能拿到未完全确认的Swing low,甚至价格高于当前收盘价。改用延迟后的已确认Swing low计算:

    // 取已确认的Swing low对应的最低价
    stopLevel = ta.valuewhen(not na(pvtlo), low[pvtLenR], 0)
    
  2. 添加止损价有效性校验
    在开仓条件中加入止损价必须低于当前收盘价的判断,避免无效止损触发:

    longCondition = buy_signal and strategy.opentrades == 0 and not na(stopLevel) and stopLevel < close
    
  3. 调整订单执行模式(可选)
    如果希望订单在下一根K线开盘价执行,可将process_orders_on_close改为false,避免当前K线收盘价直接触发止损,但需结合策略逻辑适配。

额外验证建议

回测时添加plot(stopLevel, color=color.red),对比stopLevel与close的数值关系,确认异常交易发生时两者的大小是否符合上述判断。


内容的提问来源于stack exchange,提问作者Saad Hassan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 21:57:56