
単一の均等線で取引するのをやめなさい. この戦略は,25/50/100の3つのEMAで完全なトレンド識別システムを構築し,EMAが順番に並べられ,同方向に傾く必要があることを要求し,さらに0.10倍ATRの最小の間隔を要求します. この三重フィルタリング機構は,揺れ動いている市場の偽突破を効果的に回避し,真のトレンドの状況でのみ動作します.
鍵となるのは”クリーンなEMA配列”である:多頭時25>50>100で全部上傾き,空頭時25<50<100で全部下傾きである.間隔フィルタは,傾向が十分に強くなり,均等粘着状態の無効信号を避けるようにする.
策略の核心は,撤回検出機構である.多頭撤回は,価格が25または50EMAに触れて100EMA以上にとどまるように要求し,空頭撤回は,価格が25または50EMAに触れて100EMA以下にとどまるように要求する.この設計は,伝統的な”サポートを破って購入する”より正確である.
15周期の引き戻しウィンドウの設定は合理的です. 裏付けデータによると,真のトレンド引き戻しは通常10〜15サイクルで反転を完了し,この時間ウィンドウを超えた引き戻しは,傾向が変化する可能性を示します.
入場誘発条件は極めて厳格である.K線が確認された後,全K線 (開盤,最高,最低,閉盤) が25EMAの正しい側に完全に位置しなければならない.この設計は偽突破とディスク中のノイズを避け,真の反転が確認された後にのみ入場することを保証する.
多頭入場要求:開盤>25EMA,最低>25EMA,閉盤>25EMA。空頭入場要求:開盤<25EMA,最高<25EMA,閉盤<25EMA。この”全K線確認”の方法は,入場品質を大幅に高め,無効取引を減少させる。
戦略のデフォルト10%ポジション設定は適中で,十分な収益を得ると同時に単一のリスクをコントロールする. 0.05%の手数料は実際の取引コストに近い設定で,反測結果はより参考価値があります. 多空双方向取引をサポートし,異なる市場環境に対応する一方操作も選択できます.
重要提醒:戦略は入場論理のみを含み,止まり止まり損は設定されていません. 实体での使用は,厳格なリスク管理と連携する必要があります.2-3倍ATRの止まり損と1.5-2倍リスクリターン比の止まりを設定することが推奨されています.
策略は明瞭なトレンド市場において優れていて,一面的な市場情勢の引き戻し買いには特に適している.しかし横軸波動市場では,EMA並列条件は満たすのが困難で,取引機会は比較的少ない.これは実際には策略の優位性であり,不利な環境下での過度な取引を避けている.
リスクヒント: 過去の反転は将来の利益を意味せず,戦略は連続した損失のリスクがあります. 揺れ動いている市場は長期にわたってシグナルなしの状態に現れます.適切な市場環境を待つために忍耐が必要です. 使用する前に充分な模擬取引の検証が推奨されます.
/*backtest
start: 2025-01-01 00:00:00
end: 2025-09-27 08:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Futures_Bybit","currency":"ETH_USDT","balance":500000}]
*/
//@version=6
strategy("Clean 25/50/100 EMA Pullback Scalper — Entries Only (Side Select)",
overlay=true, calc_on_every_tick=true, calc_on_order_fills=true,
initial_capital=10000, commission_type=strategy.commission.percent, commission_value=0.05,
pyramiding=0, default_qty_type=strategy.percent_of_equity, default_qty_value=10)
// === Side selector ===
side = input.string("Both", "Trade Side", options=["Both", "Long Only", "Short Only"])
longsEnabled = side == "Both" or side == "Long Only"
shortsEnabled = side == "Both" or side == "Short Only"
// === Inputs ===
lenFast = input.int(25, "Fast EMA (pullback)", minval=1)
lenMid = input.int(50, "Mid EMA (filter)", minval=1)
lenSlow = input.int(100, "Slow EMA (safety)", minval=1)
useSlope = input.bool(true, "Require EMAs sloping same way?")
useSpread = input.bool(true, "Require clean spacing (min spread)?")
spreadPct = input.float(0.10, "Min spread vs ATR (0.10 = 0.10×ATR)", step=0.01, minval=0.0)
pullLookback = input.int(15, "Max bars after pullback", minval=1, maxval=100)
showSignals = input.bool(true, "Show entry markers?")
// === Series ===
ema25 = ta.ema(close, lenFast)
ema50 = ta.ema(close, lenMid)
ema100 = ta.ema(close, lenSlow)
atr = ta.atr(14)
// === Trend & spacing ===
isUpStack = ema25 > ema50 and ema50 > ema100
isDownStack = ema25 < ema50 and ema50 < ema100
slopeUp = ema25 > ema25[1] and ema50 > ema50[1] and ema100 > ema100[1]
slopeDown = ema25 < ema25[1] and ema50 < ema50[1] and ema100 < ema100[1]
minGap = atr * spreadPct
spreadUpOK = (ema25 - ema50) > minGap and (ema50 - ema100) > minGap
spreadDownOK = (ema100 - ema50) > minGap and (ema50 - ema25) > minGap
trendLongOK = isUpStack and (useSlope ? slopeUp : true) and (useSpread ? spreadUpOK : true)
trendShortOK = isDownStack and (useSlope ? slopeDown : true) and (useSpread ? spreadDownOK : true)
// === Pullback detection state ===
var bool pullArmedLong = false
var bool pullArmedShort = false
var int pullBarIdxLong = na
var int pullBarIdxShort = na
var float pullMinLong = na
var float pullMaxShort = na
// Long pullback state
if trendLongOK
touched25 = low <= ema25
touched50 = low <= ema50
stayedAbove100 = low > ema100
if (touched25 or touched50) and stayedAbove100
pullArmedLong := true
pullBarIdxLong := bar_index
pullMinLong := na(pullMinLong) ? low : math.min(pullMinLong, low)
else if pullArmedLong
pullMinLong := na(pullMinLong) ? low : math.min(pullMinLong, low)
if low <= ema100 or (bar_index - pullBarIdxLong > pullLookback)
pullArmedLong := false
pullMinLong := na
else
pullArmedLong := false
pullMinLong := na
// Short pullback state
if trendShortOK
touched25s = high >= ema25
touched50s = high >= ema50
stayedBelow100 = high < ema100
if (touched25s or touched50s) and stayedBelow100
pullArmedShort := true
pullBarIdxShort := bar_index
pullMaxShort := na(pullMaxShort) ? high : math.max(pullMaxShort, high)
else if pullArmedShort
pullMaxShort := na(pullMaxShort) ? high : math.max(pullMaxShort, high)
if high >= ema100 or (bar_index - pullBarIdxShort > pullLookback)
pullArmedShort := false
pullMaxShort := na
else
pullArmedShort := false
pullMaxShort := na
// === Entry triggers (confirmed bar & whole candle outside 25 EMA) ===
longEntryRaw = pullArmedLong and barstate.isconfirmed and (open > ema25 and low > ema25 and close > ema25) and (na(pullMinLong) or pullMinLong > ema100)
shortEntryRaw = pullArmedShort and barstate.isconfirmed and (open < ema25 and high < ema25 and close < ema25) and (na(pullMaxShort) or pullMaxShort < ema100)
longEntry = longsEnabled and longEntryRaw
shortEntry = shortsEnabled and shortEntryRaw
// Disarm after trigger
if longEntry
pullArmedLong := false
pullMinLong := na
if shortEntry
pullArmedShort := false
pullMaxShort := na
// === Orders (entries only; no TP/SL) ===
if longEntry and strategy.position_size <= 0
strategy.entry("Long", strategy.long)
if shortEntry and strategy.position_size >= 0
strategy.entry("Short", strategy.short)
// === Plots & visuals ===
plot(ema25, "EMA 25", color=color.new(color.teal, 0))
plot(ema50, "EMA 50", color=color.new(color.orange, 0))
plot(ema100, "EMA 100", color=color.new(color.purple, 0))
bgcolor(trendLongOK ? color.new(color.green, 92) : na)
bgcolor(trendShortOK ? color.new(color.red, 92) : na)
if showSignals and longEntry
label.new(bar_index, low, "▲ BUY\nFull candle above 25 EMA", style=label.style_label_up, textcolor=color.white, color=color.new(color.green, 0))
if showSignals and shortEntry
label.new(bar_index, high, "▼ SELL\nFull candle below 25 EMA", style=label.style_label_down, textcolor=color.white, color=color.new(color.red, 0))