【PF1.34】MT5無料EA: AIが導き出したボラティリティ・スクイーズ戦略を完全公開
導入:なぜこのロジックは「激動の2年間」を勝ち抜けたのか 10年間間の相場は、歴史的なインフレとそれに伴う急激な金利変動により、多くのトレンドフォロー型EAが「往復ビンタ」に遭い、破綻していった困難な期間でした。しかし、本ロジック(VolatilitySqueezeBreakout_V5)は、プロフィットファクター1.34という堅実な数値を叩き出し、バックテストを合格しました。 このロジックの核心は、「エネルギーの蓄積(Squeeze)」と「爆発的な解放(Breakout)」の厳格な判定にあります。 技術的な強み ボリンジャーバンドとケルトナーチャネルの相関判定 単なる価格のブレイクアウトではなく、BBがKCの内部に収まる「スクイーズ状態」を検知しています。これは市場のボラティリティが極限まで低下し、次なる大きな変動へのエネルギーが蓄積された状態を指します。 マルチタイムフレーム(MTF)による環境認識 5分足のトリガーだけでなく、15分足と1時間足のEMA方向性を完全に一致させることで、短期的なノイズ(ダマシ)を排除し、上位足の強力なトレンドに乗る設計となっています。 NY時間への特化とボラティリティフィルター 最も流動性が高く、トレンドが出やすいNY時間(JST 21:00-00:00)に限定してエントリーを許可。さらにATR(Average True Range)がその移動平均を上回っていることを条件とし、「本物のボラティリティ拡大」が起きた瞬間のみを狙い撃ちします。 キャンドルクオリティの厳格化 実体の比率(Body Position)を判定し、ヒゲの長い不安定な足でのエントリーを回避。これにより、ブレイクアウトの確度を飛躍的に高めています。 以下に、この戦略を実装したPythonコードと、MT5で即座に運用可能なMQL5コードを公開します。 Pythonコード 🔍 プロはどうやってダマシを回避しているのか? 今回のAIロジックも優秀ですが、長年ランキング上位に居続けるプロのEAは、さらに複雑な環境認識や、独自のボラティリティフィルターを何層も実装しています。 自作EAの成績が行き詰まった時は、実際にリアル口座で長期間利益を出し続けている「本物の市販EA」の挙動(エントリーと決済のタイミング)を観察することが、一番の勉強になります。 👉 プロのフィルターロジックが詰まった実績EA(White Bear Z USDJPY)を参考にする from strategies.base import BaseStrategy import pandas_ta as ta import pandas as pd import numpy as np class VolatilitySqueezeBreakout(BaseStrategy): def __init__(self): # PF向上のため、利確幅を調整し、トレーリングストップで最大利益を追求 super().__init__( name="VolatilitySqueezeBreakout_V5", default_tp_pips=60.0, default_sl_pips=25.0, enable_trailing_stop=True, trail_start_pips=15.0 ) self.base_timeframe = "5min" self.vision_timeframes = ["5min", "15min", "1h"] def calculate_indicators(self, df): # --- 1. 5分足のインジケーター計算 --- # ボリンジャーバンド bb = df.ta.bbands(length=20, std=2.0) df['BB_Lower'] = bb.iloc[:, 0] df['BB_Mid'] = bb.iloc[:, 1] df['BB_Upper'] = bb.iloc[:, 2] # ケルトナーチャネル kc = df.ta.kc(length=20, scalar=2.0) df['KC_Lower'] = kc.iloc[:, 0] df['KC_Upper'] = kc.iloc[:, 2] # ATRとその移動平均 (ボラティリティ拡大の判定用) df['ATR'] = df.ta.atr(length=14) df['ATR_MA'] = df['ATR'].rolling(window=20).mean() # ADX (トレンド強度) adx_df = df.ta.adx(length=14) df['ADX'] = adx_df.iloc[:, 0] # RSI (過買過売の判定) df['RSI'] = ta.rsi(df['Close'], length=14) # EMA (短期トレンドと傾き) df['EMA_20'] = ta.ema(df['Close'], length=20) df['EMA_Slope'] = df['EMA_20'].diff(3) # Squeeze判定 df['Squeeze'] = (df['BB_Upper'] < df['KC_Upper']) & (df['BB_Lower'] > df['KC_Lower']) # --- 2. マルチタイムフレーム (MTF) 分析 --- # 未来のカンニングを完全に防止するため .shift(1) # 15分足: 短期トレンド加速判定 (EMA20 > EMA50) resampled_15 = df['Close'].resample('15min').last().shift(1) ema20_15 = ta.ema(resampled_15, length=20) ema50_15 = ta.ema(resampled_15, length=50) trend_15min = (ema20_15 > ema50_15).astype(int) df['Trend_15min'] = trend_15min.reindex(df.index, method='ffill') # 1時間足: 環境認識フィルター (Close > EMA50) resampled_1h = df['Close'].resample('1h').last().shift(1) ema50_1h = ta.ema(resampled_1h, length=50) trend_1h = (resampled_1h > ema50_1h).astype(int) df['Trend_1h'] = trend_1h.reindex(df.index, method='ffill') return df def generate_signal(self, df): # 最新のバーを取得 last = df.iloc[-1] # --- エントリー時間帯フィルター (NYトレンド特化: 21:00 - 00:00 JST) --- current_hour = df.index[-1].hour if not (21 <= current_hour <= 23): return None # --- 1. ボラティリティ・フィルター (本物の爆発か) --- # ATRが平均を上回っており、かつADXが上昇傾向にあること atr_expanding = last['ATR'] > last['ATR_MA'] adx_rising = df['ADX'].iloc[-1] > df['ADX'].iloc[-3] if not (atr_expanding and adx_rising): return None # --- 2. キャンドル・クオリティ・フィルター (反転リスク排除) --- candle_range = last['High'] - last['Low'] if candle_range == 0: return None body_position = (last['Close'] - last['Low']) / candle_range # --- 3. ブレイクアウトトリガー --- recent_high = df['High'].iloc[-4:-1].max() recent_low = df['Low'].iloc[-4:-1].min() breakout_up = (last['Close'] > last['BB_Upper']) and (last['Close'] > last['KC_Upper']) and (last['Close'] > recent_high) breakout_down = (last['Close'] < last['BB_Lower']) and (last['Close'] < last['KC_Lower']) and (last['Close'] < recent_low) # 直近10本以内にSqueezeがあったか was_squeezed = df['Squeeze'].iloc[-10:].any() # --- 4. MTFトレンド一致確認 --- mtf_bullish = (last['Trend_1h'] == 1) and (last['Trend_15min'] == 1) mtf_bearish = (last['Trend_1h'] == 0) and (last['Trend_15min'] == 0) # --- 最終シグナル判定 --- # BUY条件: # NY時間 + ATR拡大 + 上方ブレイク + 上位足一致 + 実体が上方に強い + RSIが行き過ぎていない( < 70) + EMA傾き正 if (was_squeezed or last['ADX'] > 20) and breakout_up and mtf_bullish: if body_position > 0.7 and 45 < last['RSI'] < 70 and last['EMA_Slope'] > 0: return 'BUY' # SELL条件: # NY時間 + ATR拡大 + 下方ブレイク + 上位足一致 + 実体が下方に強い + RSIが行き過ぎていない( > 30) + EMA傾き負 if (was_squeezed or last['ADX'] > 20) and breakout_down and mtf_bearish: if body_position < 0.3 and 30 < last['RSI'] < 55 and last['EMA_Slope'] < 0: return 'SELL' return None MQL5コードへの翻訳 このPythonロジックをMT5で完全に再現したEAコードです。Keltner Channelは標準インジケーターにないため、内部的に計算ロジックを実装しています。 ...