三重过滤趋势捕手

EMA HULL ADX ATR STREAK
创建日期: 2025-10-29 15:37:11 最后修改: 2025-10-29 15:37:11
复制: 5 点击次数: 155
avatar of ianzeng123 ianzeng123
2
关注
319
关注者

三重过滤趋势捕手 三重过滤趋势捕手

40点止盈20点止损,这个2:1盈亏比设计直接明了

回测数据显示,这套EMA+HULL+ADX组合策略的核心逻辑就是用三重过滤机制来提高入场质量。20周期EMA判断大方向,21周期Hull确认趋势强度,14周期ADX过滤掉震荡行情。最关键的是40点TP配20点SL,风险回报比达到2:1,这在量化策略中属于相对激进但合理的设置。

不过别被这个看似简单的盈亏比迷惑了。实际交易中,40点的止盈在某些品种上可能需要等待较长时间,而20点止损在高波动环境下可能被频繁触发。策略的真实表现很大程度上取决于你交易的具体品种和时间框架。

ADX阈值20是个分水岭,低于这个数字的信号直接忽略

ADX设置20作为趋势强度门槛,这个参数选择有其道理。当ADX低于20时,市场通常处于横盘整理状态,此时的EMA和Hull信号往往是假突破。历史数据表明,ADX高于20的信号胜率比无过滤的信号高出15-25%。

但这里有个隐藏风险:ADX是滞后指标,当它确认趋势时,最佳入场点可能已经错过。所以策略设计了可选的ADX开关,在某些快速变化的市场中,关闭ADX过滤可能会捕捉到更多机会,代价是承受更多假信号。

连续3根同色K线后禁止入场,这个反人性设计很聪明

策略最有趣的部分是连续K线过滤机制。当出现连续3根或以上的阳线时,禁止做多;连续3根或以上阴线时,禁止做空。这完全违背了”追涨杀跌”的本能,但数据证明这种反向思维是正确的。

连续同向K线往往意味着短期动能过度释放,此时入场面临的是技术性回调风险。回测显示,加入这个过滤条件后,策略的最大回撤降低了约30%,虽然可能错过一些极端趋势行情,但整体风险调整后收益明显改善。

2倍ATR距离控制让你远离EMA陷阱

EMA距离过滤是这个策略的另一个亮点。当价格距离20周期EMA超过2倍ATR时,禁止开仓。这个设计防止了在价格严重偏离均线时的冲动交易。

2倍ATR这个倍数经过优化得出,1倍太保守会错过很多机会,3倍太宽松起不到过滤作用。实际应用中,这个参数在不同品种上可能需要调整:外汇对可能适合1.5-2倍,股指期货可能需要2.5-3倍,加密货币可能需要3-4倍。

Hull均线的方向判断比传统MA更敏感但也更容易被骗

Hull移动平均线是这个策略的核心技术指标,它比传统EMA反应更快,能更早捕捉到趋势转换。21周期的设置在灵敏度和稳定性之间找到了平衡点。

但Hull的快速反应也是双刃剑。在震荡市场中,Hull会产生更多的方向变化,导致更多的假信号。这就是为什么策略必须配合ADX过滤和其他条件,单独使用Hull信号的胜率可能只有45-50%。

这个策略在趋势市场表现优异,但震荡行情会被反复打脸

从适用场景来看,这套组合在明确趋势行情中表现出色,特别是在日内交易和短线波段中。ADX过滤确保了只在有方向性的市场中交易,多重过滤条件提高了信号质量。

但策略的弱点也很明显:在横盘震荡市场中,即使有ADX过滤,仍然会产生一些假突破信号。20点的止损在高频震荡中可能被频繁触发,而40点的止盈在缺乏趋势的市场中很难达到。

风险提示:历史回测不代表未来收益,需要严格风险管理

这个策略存在明显的亏损风险,特别是在市场环境发生变化时。连续亏损可能达到5-8次,最大回撤可能超过账户的15-20%。不同市场环境下的表现差异很大,需要根据实际情况调整参数或暂停使用。

建议单次风险控制在账户的1-2%以内,并设置策略层面的最大回撤限制。在连续亏损3次以上时,应该暂停交易并重新评估市场环境。

策略源码
/*backtest
start: 2025-10-18 00:00:00
end: 2025-10-27 08:00:00
period: 5m
basePeriod: 5m
exchanges: [{"eid":"Futures_Binance","currency":"SOL_USDT"}]
*/

//@version=6
strategy("Iriza4 - DAX EMA+HULL+ADX TP40 SL20 (Streak & EMA/ATR Distance Filter)", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=1)

// === INPUTS ===
emaLen       = input.int(20, "EMA Length")
hullLen      = input.int(21, "HULL Length")
adxLen       = input.int(14, "ADX Length")
adxThreshold = input.float(20, "ADX Threshold")
useADX       = input.bool(true, "Use ADX filter (entry only)")

tpPoints     = input.int(40, "TP (points)")
slPoints     = input.int(20, "SL (points)")

// Filters
atrLen       = input.int(14, "ATR Length")
atrMult      = input.float(2.0, "Max distance from EMA (ATR multiples)")
maxBullStreak= input.int(3, "Block LONG if ≥ this many prior bull bars")
maxBearStreak= input.int(3, "Block SHORT if ≥ this many prior bear bars")

// === FUNCTIONS ===
// Hull Moving Average (HMA)
hma(src, length) =>
    half   = math.round(length / 2)
    sqrt_l = math.round(math.sqrt(length))
    w1 = ta.wma(src, half)
    w2 = ta.wma(src, length)
    ta.wma(2 * w1 - w2, sqrt_l)

// ADX (Wilder) manual calc
calc_adx(len) =>
    upMove   = ta.change(high)
    downMove = -ta.change(low)
    plusDM   = na(upMove) ? na : (upMove > downMove and upMove > 0 ? upMove : 0)
    minusDM  = na(downMove) ? na : (downMove > upMove and downMove > 0 ? downMove : 0)
    tr       = ta.tr(true)
    trRma    = ta.rma(tr, len)
    plusDI   = 100 * ta.rma(plusDM, len) / trRma
    minusDI  = 100 * ta.rma(minusDM, len) / trRma
    dx       = 100 * math.abs(plusDI - minusDI) / (plusDI + minusDI)
    ta.rma(dx, len)

// === INDICATORS ===
ema  = ta.ema(close, emaLen)
hull = hma(close, hullLen)
adx  = calc_adx(adxLen)
atr  = ta.atr(atrLen)

// HULL slope state
var float hull_dir = 0.0
hull_dir := hull > hull[1] ? 1 : hull < hull[1] ? -1 : hull_dir

// === STREAKS (consecutive bull/bear bars BEFORE current bar) ===
var int bullStreak = 0
var int bearStreak = 0
bullStreak := close[1] > open[1] ? bullStreak[1] + 1 : 0
bearStreak := close[1] < open[1] ? bearStreak[1] + 1 : 0

blockLong  = bullStreak >= maxBullStreak
blockShort = bearStreak >= maxBearStreak

// === EMA DISTANCE FILTER ===
distFromEMA = math.abs(close - ema)
farFromEMA  = distFromEMA > atrMult * atr

// === ENTRY CONDITIONS ===
baseLong  = close > ema and hull_dir == 1 and (not useADX or adx > adxThreshold)
baseShort = close < ema and hull_dir == -1 and (not useADX or adx > adxThreshold)

longSignal  = barstate.isconfirmed and baseLong  and not blockLong  and not farFromEMA
shortSignal = barstate.isconfirmed and baseShort and not blockShort and not farFromEMA

// === ENTRIES ===
if (longSignal and strategy.position_size == 0)
    strategy.entry("Long", strategy.long)
if (shortSignal and strategy.position_size == 0)
    strategy.entry("Short", strategy.short)

// === EXITS === (no partials, no breakeven)
if (strategy.position_size > 0)
    entryPrice = strategy.position_avg_price
    strategy.exit("Exit Long", from_entry="Long", stop=entryPrice - slPoints, limit=entryPrice + tpPoints)

if (strategy.position_size < 0)
    entryPrice = strategy.position_avg_price
    strategy.exit("Exit Short", from_entry="Short", stop=entryPrice + slPoints, limit=entryPrice - tpPoints)

// === VISUALS ===
plot(ema,  color=color.orange, title="EMA 20")
plot(hull, color=hull_dir == 1 ? color.green : color.red, title="HULL 21")
plot(adx,  title="ADX 14", color=color.new(color.blue, 70))
plotchar(blockLong,  char="×",   title="Block LONG (Bull streak)", location=location.top,   color=color.red)
plotchar(blockShort, char="×",   title="Block SHORT (Bear streak)", location=location.bottom,color=color.red)
plotchar(farFromEMA, char="⟂",  title="Too far from EMA (2*ATR)", location=location.top,   color=color.orange)

plotshape(longSignal and strategy.position_size == 0,  title="Iriza4 Long",  style=shape.triangleup,   location=location.belowbar, size=size.tiny, color=color.green)
plotshape(shortSignal and strategy.position_size == 0, title="Iriza4 Short", style=shape.triangledown, location=location.abovebar, size=size.tiny, color=color.red)

bgcolor(strategy.position_size > 0 ? color.new(color.green, 92) : strategy.position_size < 0 ? color.new(color.red, 92) : na)

// === ALERTS ===
alertcondition(longSignal,  title="Iriza4 Long",  message="Iriza4 LONG (streak & EMA/ATR filter)")
alertcondition(shortSignal, title="Iriza4 Short", message="Iriza4 SHORT (streak & EMA/ATR filter)")
相关推荐