
Dữ liệu đánh giá cho thấy, logic cốt lõi của chiến lược kết hợp EMA + HULL + ADX là sử dụng cơ chế lọc ba để nâng cao chất lượng đầu vào. 20 chu kỳ EMA đánh giá định hướng lớn, 21 chu kỳ Hull xác nhận cường độ xu hướng, 14 chu kỳ ADX lọc sự biến động. Điều quan trọng nhất là 40 điểm TP với 20 điểm SL, tỷ lệ lợi nhuận rủi ro đạt 2: 1, đây là một thiết lập tương đối quyết liệt nhưng hợp lý trong chiến lược định lượng.
Tuy nhiên, đừng để bị lừa bởi tỷ lệ lợi nhuận và lỗ hổng có vẻ đơn giản này. Trong giao dịch thực tế, dừng 40 điểm có thể cần phải chờ đợi lâu hơn trên một số loại, trong khi dừng 20 điểm có thể được kích hoạt thường xuyên trong môi trường biến động cao.
ADX đặt 20 làm ngưỡng cường độ xu hướng, lựa chọn tham số này là hợp lý. Khi ADX thấp hơn 20, thị trường thường ở trong trạng thái sắp xếp ngang, tại thời điểm đó tín hiệu EMA và Hull thường là phá vỡ giả. Dữ liệu lịch sử cho thấy, tín hiệu trên ADX 20 có tỷ lệ thắng cao hơn 15-25% so với tín hiệu không được lọc.
Nhưng có một rủi ro tiềm ẩn ở đây: ADX là một chỉ số chậm trễ, và khi nó xác nhận xu hướng, điểm nhập cảnh tốt nhất có thể đã bị bỏ lỡ. Vì vậy, chiến lược đã thiết kế chuyển đổi ADX tùy chọn, trong một số thị trường thay đổi nhanh chóng, việc tắt bộ lọc ADX có thể bắt được nhiều cơ hội hơn, với chi phí chịu đựng nhiều tín hiệu giả hơn.
Phần thú vị nhất của chiến lược là cơ chế lọc dây K liên tiếp. Khi có 3 hoặc nhiều dây dương liên tiếp, không được làm nhiều; Khi có 3 hoặc nhiều dây âm liên tiếp, không được làm trống.
Sự liên tục đồng chiều K-line thường có nghĩa là giải phóng năng lượng quá mức trong thời gian ngắn, khi đầu vào phải đối mặt với rủi ro điều chỉnh kỹ thuật. Theo đánh giá, sau khi thêm điều kiện lọc này, sự rút lui tối đa của chiến lược giảm khoảng 30%, mặc dù có thể bỏ lỡ một số tình huống xu hướng cực đoan, nhưng lợi nhuận sau khi điều chỉnh rủi ro tổng thể được cải thiện rõ rệt.
Bộ lọc khoảng cách EMA là một điểm nổi bật khác của chiến lược này. Việc mở lệnh bị cấm khi giá cách 20 chu kỳ EMA hơn 2 lần ATR. Thiết kế này ngăn chặn giao dịch bốc đồng khi giá lệch khỏi đường trung bình.
2 lần ATR được tối ưu hóa, 1 lần quá bảo thủ sẽ bỏ lỡ rất nhiều cơ hội, 3 lần quá lỏng lẻo sẽ không có tác dụng lọc. Trong ứng dụng thực tế, tham số này có thể cần điều chỉnh trên các giống khác nhau: cặp ngoại hối có thể phù hợp với 1.5-2 lần, tương lai chỉ số cổ phiếu có thể cần 2,5-3 lần, tiền điện tử có thể cần 3-4 lần.
Hull Moving Average là chỉ số kỹ thuật cốt lõi của chiến lược này, nó phản ứng nhanh hơn so với EMA truyền thống và có thể bắt được sự chuyển đổi xu hướng sớm hơn. Cài đặt 21 chu kỳ tìm thấy sự cân bằng giữa sự nhạy cảm và ổn định.
Nhưng phản ứng nhanh chóng của Hull cũng là một thanh kiếm hai lưỡi. Trong thị trường biến động, Hull sẽ tạo ra nhiều thay đổi hướng hơn, dẫn đến nhiều tín hiệu giả hơn. Đó là lý do tại sao chiến lược phải được kết hợp với bộ lọc ADX và các điều kiện khác, tỷ lệ thắng chỉ có thể là 45-50% khi sử dụng tín hiệu Hull một mình.
Từ góc độ ứng dụng, cặp này hoạt động tốt trong các tình huống có xu hướng rõ ràng, đặc biệt là trong giao dịch trong ngày và các đoạn sóng ngắn. Bộ lọc ADX đảm bảo giao dịch chỉ trong các thị trường có hướng, điều kiện lọc nhiều lần cải thiện chất lượng tín hiệu.
Nhưng điểm yếu của chiến lược cũng rất rõ ràng: Trong thị trường dao động ngang, ngay cả khi có bộ lọc ADX, một số tín hiệu phá vỡ giả vẫn sẽ được tạo ra. Một điểm dừng 20 có thể được kích hoạt thường xuyên trong các biến động tần số cao, trong khi một điểm dừng 40 rất khó đạt được trong các thị trường thiếu xu hướng.
Chiến lược này có rủi ro mất mát rõ ràng, đặc biệt là khi môi trường thị trường thay đổi. Mất mát liên tục có thể lên đến 5-8 lần, rút tiền tối đa có thể vượt quá 15-20% tài khoản. Hiệu suất khác nhau trong các môi trường thị trường khác nhau rất lớn, cần điều chỉnh tham số hoặc tạm dừng sử dụng theo tình hình thực tế.
Khuyến nghị kiểm soát rủi ro một lần trong vòng 1-2% tài khoản và đặt giới hạn rút tối đa ở cấp độ chiến lược. Nếu thua lỗ liên tiếp hơn 3, nên tạm dừng giao dịch và đánh giá lại môi trường thị trường.
/*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)")