
SUPERTREND, ATR, ADX, EMA, AI
伝統的なスーパートレンド戦略の最大の痛点? 固定パラメータは異なる市場環境で大きく異なったパフォーマンスを発揮する.このAI強化版はATR倍数を動的に調整し,高波動期には倍数をベース値の2倍に上昇させ,低波動期には0.85倍に低下させる.復元データによると,この自己適応メカニズムは,揺れ動いている市場における偽信号を大幅に減らすことができる.
核心的な革新は,3層のフィルタリングシステムである:市場状態識別,AI信号評価,複数の確認機構である.もはや簡単な価格がスーパートレンド線を突破して入場するのではなく,AI評価が65分以上に達することを要求して取引信号を触発する.この評価システムは,取引量の激増,価格偏差の程度,トレンド一致性などの5つの次元を総合的に考慮する.
評価機構は精巧に設計されている.取引量激增は20ポイントの重量,価格がスーパートレンドラインから25ポイントの距離,EMAトレンド一致は20ポイント,市場状態の質は15ポイント,前期価格とトレンドラインの距離は20ポイント.合計100ポイント,デフォルトの65ポイントの門は,高品質の信号のみがフィルタリングを通過することを意味する.
具体的には,取引量が20サイクル平均値の2.5倍を超えると満点20点,価格がスーパートレンドラインの1.5倍ATRを超えると満点25点が得られる.この定量的な評価は主観的な判断を避け,各信号には明確なデータ支持がある.実用的な使用では,異なる品種の特性に応じて最低評価要件を調整することが推奨される.
戦略はATR比率とADX指標によって,3つの市場状態を識別する.トレンド期 (regime=1),高波動期 (regime=2),震動期 (regime=0).ATR比率が1.4を超えると高波動期と判断され,ADX比率が20を下回り,ATR比率が0.9を下回ると震動期と判断される.
適応的倍数調整の論理:高波動期倍数は40%増加し,震動期倍数は基値の85%に低下する.これは,3.0の基数倍数は,極端な波動時に4.2に調整され,震動期では2.55に調整されることが可能であることを意味する.このダイナミックな調整機構は,異なる市場環境下での戦略の適応性を著しく向上させる.
ATRダイナミックストップは,標準の2.5倍ATR距離が正常な波動を許容し,時効的にストップするオプションである. パーセンテージストップは,波動率が比較的安定した品種に適しており,スーパートレンドモードは,トレンドが逆転するとすぐに平仓する.
ストップセットは,リスク/利益比率モードをサポートし,デフォルト2.5:1のリスク/利益比率は統計的に優れている.ストップ追跡が有効になった後,利回りポジションのストップラインは2.5倍ATR距離に応じて動的に調整され,トレンド状況での利益を最大化する.
EMAのトレンドフィルターは50サイクルEMAの方向に一致する時にのみ入場を確保し,逆転取引を避ける.振動期フィルターは,regime=0の信号を直接スキップし,一部の機会を逃しても,偽信号率を著しく低下させる.
取引量フィルター 入場時に取引量が20サイクル平均より高いことを要求し,十分な市場参加が価格突破を支えるようにする. 10サイクル冷却期は頻繁に取引を防止し,取引コストを削減する.
暗号通貨の最低AI評価を70ポイントに上げ,従来の株式は60ポイントまで下げることを提案した.高頻度トレーダーは5サイクルまで冷却期間を短縮し,長線投資家は15サイクルまで延長することを提案した.
ATRの長さのパラメータ10は,最適化されたバランスポイントであり,短すぎると過度に敏感になり,長すぎると遅滞する.基本倍数3.0はほとんどの品種に適しており,高波動品種は3.5に調整され,低波動品種は2.5に低下する.
リスクに関する重要なヒント: 過去の反省結果は,将来の利益のパフォーマンスを意味しません. 戦略は,極端な市場条件下では,連続した損失が発生する可能性があります. 単一のポジションを総資金の30%を超えないように厳格に制御することをお勧めします. 異なる市場環境下での戦略のパフォーマンスは,継続的な監視とパラメータの調整を必要とする顕著な差異があります.
/*backtest
start: 2026-01-01 00:00:00
end: 2026-02-24 00:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"PAXG_USDT","balance":500000}]
*/
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © DefinedEdge
//@version=6
strategy("SuperTrend AI Strategy [Adaptive]", "ST AI Strategy ◈",
overlay = true,
initial_capital = 10000,
default_qty_type = strategy.percent_of_equity,
default_qty_value= 30,
commission_type = strategy.commission.percent,
commission_value = 0.06,
slippage = 2,
pyramiding = 0,
calc_on_every_tick = false,
max_labels_count = 500)
// ============================================================================
// INPUTS
// ============================================================================
// --- SuperTrend Core ---
GRP_ST = "◈ SuperTrend"
i_atLen = input.int(10, "ATR Length", minval=1, maxval=50, group=GRP_ST)
i_bMult = input.float(3.0, "Base Multiplier", minval=0.5, maxval=10.0, step=0.1, group=GRP_ST)
i_src = input.source(hl2, "Source", group=GRP_ST)
// --- Regime Detection ---
GRP_REG = "◈ Regime Detection"
i_regLen = input.int(40, "Regime Lookback", minval=10, maxval=100, group=GRP_REG)
i_adxLen = input.int(14, "ADX Length", minval=5, maxval=50, group=GRP_REG)
i_adxThr = input.float(20, "ADX Trend Threshold", minval=10, maxval=40, step=1, group=GRP_REG)
i_adapt = input.bool(true, "Adaptive Multiplier", group=GRP_REG)
// --- AI Scoring ---
GRP_AI = "◈ AI Engine"
i_trendLen = input.int(50, "Trend EMA Length", minval=10, maxval=200, group=GRP_AI)
i_volLen = input.int(20, "Volume MA Length", minval=5, maxval=50, group=GRP_AI)
i_minSc = input.int(65, "Min Signal Score", minval=0, maxval=90, group=GRP_AI, tooltip="Only enter trades when the AI score meets this threshold.")
// --- Risk Management ---
GRP_RISK = "◈ Risk Management"
i_slMode = input.string("ATR", "Stop Loss Mode", options=["ATR", "Percent", "SuperTrend"], group=GRP_RISK, tooltip="ATR: dynamic SL based on volatility. Percent: fixed %. SuperTrend: exit on trend flip.")
i_slAtr = input.float(2.5, "SL ATR Multiplier", minval=0.5, maxval=8.0, step=0.1, group=GRP_RISK)
i_slPct = input.float(3.0, "SL Percent", minval=0.5, maxval=10.0, step=0.1, group=GRP_RISK)
i_tpMode = input.string("RR", "Take Profit Mode", options=["RR", "Percent", "None"], group=GRP_RISK, tooltip="RR: risk/reward ratio based on SL distance. Percent: fixed %. None: hold until SL or flip.")
i_tpRR = input.float(2.5, "TP Risk:Reward", minval=0.5, maxval=10.0, step=0.1, group=GRP_RISK)
i_tpPct = input.float(6.0, "TP Percent", minval=0.5, maxval=20.0, step=0.1, group=GRP_RISK)
i_trail = input.bool(true, "Trailing Stop", group=GRP_RISK, tooltip="When enabled, SL trails in the direction of the trade after entry.")
i_trailAtr = input.float(2.5, "Trail ATR Mult", minval=0.5, maxval=8.0, step=0.1, group=GRP_RISK)
// --- Filters ---
GRP_FLT = "◈ Trade Filters"
i_trendF = input.bool(true, "EMA Trend Filter", group=GRP_FLT, tooltip="Only take longs above EMA, shorts below EMA.")
i_regF = input.bool(true, "Skip Ranging", group=GRP_FLT, tooltip="Skip entries during ranging regime. Reduces whipsaws.")
i_volF = input.bool(true, "Volume Filter", group=GRP_FLT, tooltip="Only enter if volume is above average.")
i_sigCD = input.int(10, "Cooldown (bars)", minval=0, maxval=50, group=GRP_FLT)
// --- Backtest Window ---
GRP_BT = "◈ Backtest"
bool inWindow = true
// --- Visuals ---
GRP_VIS = "◈ Visuals"
i_sGlow = input.bool(true, "Band Glow Effect", group=GRP_VIS)
i_sRegBg = input.bool(true, "Regime Background", group=GRP_VIS)
// --- Colors ---
GRP_COL = "◈ Colors"
i_cBull = input.color(color.new(#089981, 0), "Bull", inline="c1", group=GRP_COL)
i_cBear = input.color(color.new(#f23645, 0), "Bear", inline="c1", group=GRP_COL)
// ============================================================================
// CORE CALCULATIONS
// ============================================================================
int n = bar_index
float atr = ta.atr(i_atLen)
float safeAtr = nz(atr, 0.001)
// ── Regime Detection ──
float atrMa = ta.sma(atr, i_regLen)
float atrRatio = atrMa > 0 ? atr / atrMa : 1.0
// ADX
float upMove = high - high[1]
float dnMove = low[1] - low
float plusDM = upMove > dnMove and upMove > 0 ? upMove : 0
float minusDM = dnMove > upMove and dnMove > 0 ? dnMove : 0
float trueR = ta.tr
float smoothTR = ta.rma(trueR, i_adxLen)
float smoothPD = ta.rma(plusDM, i_adxLen)
float smoothND = ta.rma(minusDM, i_adxLen)
float plusDI = smoothTR > 0 ? 100 * smoothPD / smoothTR : 0
float minusDI = smoothTR > 0 ? 100 * smoothND / smoothTR : 0
float diSum = plusDI + minusDI
float dx = diSum > 0 ? 100 * math.abs(plusDI - minusDI) / diSum : 0
float adx = ta.rma(dx, i_adxLen)
var int regime = 1
if atrRatio > 1.4
regime := 2
else if adx < i_adxThr and atrRatio < 0.9
regime := 0
else
regime := 1
// ── Adaptive Multiplier ──
float adaptMult = i_bMult
if i_adapt
if regime == 2
adaptMult := i_bMult * (1.0 + (atrRatio - 1.0) * 0.4)
else if regime == 0
adaptMult := i_bMult * 0.85
adaptMult := math.max(math.min(adaptMult, i_bMult * 2.0), i_bMult * 0.5)
// ── SuperTrend ──
var float stBand = na
var int stDir = 1
float upperBase = i_src + adaptMult * atr
float lowerBase = i_src - adaptMult * atr
float prevBand = nz(stBand[1], stDir == 1 ? lowerBase : upperBase)
if stDir == 1
stBand := math.max(lowerBase, prevBand)
if close < stBand
stDir := -1
stBand := upperBase
else
stBand := math.min(upperBase, prevBand)
if close > stBand
stDir := 1
stBand := lowerBase
bool trendFlip = stDir != stDir[1]
// ── Trend EMA ──
float trendMa = ta.ema(close, i_trendLen)
bool trendUp = close > trendMa
bool trendDn = close < trendMa
// ── Volume ──
float volMa = ta.sma(volume, i_volLen)
// ============================================================================
// AI SIGNAL SCORING
// ============================================================================
scoreSignal(bool isBull) =>
float score = 0
// Factor 1: Volume surge (0-20)
float vRat = volMa > 0 ? volume / volMa : 1.0
score += vRat >= 2.5 ? 20 : vRat >= 1.5 ? 14 : vRat >= 1.0 ? 8 : 3
// Factor 2: Displacement beyond band (0-25)
float disp = isBull ? (close - stBand) : (stBand - close)
float dispAtr = safeAtr > 0 ? disp / safeAtr : 0
score += dispAtr >= 1.5 ? 25 : dispAtr >= 0.8 ? 18 : dispAtr >= 0.3 ? 12 : dispAtr > 0 ? 5 : 0
// Factor 3: EMA trend alignment (0-20)
bool aligned = (isBull and trendUp) or (not isBull and trendDn)
float emaDist = math.abs(close - trendMa) / safeAtr
score += aligned and emaDist > 0.5 ? 20 : aligned ? 14 : emaDist < 0.3 ? 8 : 2
// Factor 4: Regime quality (0-15)
score += regime == 1 ? 15 : regime == 2 ? 8 : 3
// Factor 5: Band distance before flip (0-20)
float prevDist = not na(stBand[1]) ? math.abs(close[1] - stBand[1]) / safeAtr : 0
score += prevDist >= 2.0 ? 20 : prevDist >= 1.0 ? 14 : prevDist >= 0.5 ? 8 : 3
int(math.min(math.round(score), 100))
// ============================================================================
// TRADE LOGIC
// ============================================================================
var int lastEntryBar = 0
var float entryPrice = 0.0
var float slPrice = 0.0
var float tpPrice = 0.0
var int lastSigScore = 0
var int lastSigDir = 0
var bool lastSigBright = false
bool longEntry = false
bool shortEntry = false
int sigScore = 0
// Cooldown check
bool cdOk = (n - lastEntryBar) > i_sigCD
if trendFlip and inWindow and cdOk and barstate.isconfirmed
if stDir == 1
sigScore := scoreSignal(true)
// Apply filters
bool passScore = sigScore >= i_minSc
bool passTrend = not i_trendF or trendUp
bool passReg = not i_regF or regime != 0
bool passVol = not i_volF or (volume > volMa)
if passScore and passTrend and passReg and passVol
longEntry := true
else
sigScore := scoreSignal(false)
bool passScore = sigScore >= i_minSc
bool passTrend = not i_trendF or trendDn
bool passReg = not i_regF or regime != 0
bool passVol = not i_volF or (volume > volMa)
if passScore and passTrend and passReg and passVol
shortEntry := true
// ── Calculate SL/TP Levels ──
float slDist = 0.0
if i_slMode == "ATR"
slDist := atr * i_slAtr
else if i_slMode == "Percent"
slDist := close * i_slPct / 100
else // SuperTrend mode
slDist := math.abs(close - stBand)
float tpDist = 0.0
if i_tpMode == "RR"
tpDist := slDist * i_tpRR
else if i_tpMode == "Percent"
tpDist := close * i_tpPct / 100
// ── Execute Entries ──
if longEntry
// Close any existing short
if strategy.position_size < 0
strategy.close("Short")
entryPrice := close
slPrice := close - slDist
tpPrice := i_tpMode != "None" ? close + tpDist : na
strategy.entry("Long", strategy.long)
if not na(slPrice) and i_tpMode != "None" and not na(tpPrice)
strategy.exit("Long Exit", "Long", stop=slPrice, limit=tpPrice,
trail_points = i_trail ? slDist / syminfo.mintick : na,
trail_offset = i_trail ? (atr * i_trailAtr) / syminfo.mintick : na)
else if not na(slPrice)
strategy.exit("Long SL", "Long", stop=slPrice,
trail_points = i_trail ? slDist / syminfo.mintick : na,
trail_offset = i_trail ? (atr * i_trailAtr) / syminfo.mintick : na)
lastEntryBar := n
lastSigScore := sigScore
lastSigDir := 1
lastSigBright := sigScore >= 70
if shortEntry
// Close any existing long
if strategy.position_size > 0
strategy.close("Long")
entryPrice := close
slPrice := close + slDist
tpPrice := i_tpMode != "None" ? close - tpDist : na
strategy.entry("Short", strategy.short)
if not na(slPrice) and i_tpMode != "None" and not na(tpPrice)
strategy.exit("Short Exit", "Short", stop=slPrice, limit=tpPrice,
trail_points = i_trail ? slDist / syminfo.mintick : na,
trail_offset = i_trail ? (atr * i_trailAtr) / syminfo.mintick : na)
else if not na(slPrice)
strategy.exit("Short SL", "Short", stop=slPrice,
trail_points = i_trail ? slDist / syminfo.mintick : na,
trail_offset = i_trail ? (atr * i_trailAtr) / syminfo.mintick : na)
lastEntryBar := n
lastSigScore := sigScore
lastSigDir := -1
lastSigBright := sigScore >= 70
// ── SuperTrend Flip Exit (if SL mode is SuperTrend) ──
if i_slMode == "SuperTrend" and trendFlip
if strategy.position_size > 0 and stDir == -1
strategy.close("Long", comment="ST Flip")
if strategy.position_size < 0 and stDir == 1
strategy.close("Short", comment="ST Flip")
// ============================================================================
// VISUALS
// ============================================================================
// ── Band Color ──
color bandCore = stDir == 1 ? i_cBull : i_cBear
color bandColor = regime == 2 ? color.new(#ffab00, 0) : regime == 0 ? color.new(#78909c, 20) : bandCore
// ── Glow ──
plot(i_sGlow ? stBand : na, "Glow Outer", color=color.new(bandColor, 85), linewidth=6, style=plot.style_linebr)
plot(i_sGlow ? stBand : na, "Glow Mid", color=color.new(bandColor, 70), linewidth=4, style=plot.style_linebr)
// ── Band ──
plot(regime != 0 ? stBand : na, "Band (Solid)", color=bandColor, linewidth=2, style=plot.style_linebr)
plot(regime == 0 ? stBand : na, "Band (Ranging)", color=bandColor, linewidth=2, style=plot.style_linebr)
// ── Flip Dot ──
plot(trendFlip ? stBand : na, "Flip Dot", color=bandCore, style=plot.style_circles, linewidth=5, join=false)
// ── Regime Background ──
bgcolor(i_sRegBg and regime == 2 ? color.new(#ffab00, 95) : na, title="Volatile BG")
bgcolor(i_sRegBg and regime == 0 ? color.new(#78909c, 96) : na, title="Ranging BG")
// ── Trend EMA ──
plot(trendMa, "Trend EMA", color=color.new(trendUp ? i_cBull : i_cBear, 65), linewidth=1)
// ============================================================================
// HIDDEN PLOTS
// ============================================================================
plot(sigScore > 0 ? sigScore : na, "Signal Score", display=display.none)
plot(adaptMult, "Adaptive Mult", display=display.none)
plot(adx, "ADX", display=display.none)
plot(float(regime), "Regime", display=display.none)
plot(float(stDir), "Trend Direction", display=display.none)