【PF1.50】10年間合格EA: ボラティリティ収縮からの爆発を狙う機関投資家ロジック
ロジック解説:ボラティリティの「蓄積」と「放出」の定量化 本ロジックは、10年間間のインフレ加速および金利変動に伴う激しいボラティリティ相場において、バックテストでPF1.50という安定した数値を記録したブレイクアウト戦略です。 多くのブレイクアウト戦略が「ダマシ」に遭い、ドローダウンを拡大させる中で、本ロジックが生き残った理由は、エントリー条件におけるフィルターの多層構造にあります。 技術的な強み ボラティリティのV字底打ち判定 (BB Width) 単に価格がバンドを抜けたことを見るのではなく、ボリンジャーバンド幅(BB Width)が過去50期間の平均を下回った状態から上昇に転じた瞬間(vol_release)を捉えています。これにより、「エネルギーが蓄積された後の放出」という相場の本質的なサイクルを定量的に判定しています。 ADXによるモメンタムの加速確認 トレンドの有無を示すADXが20以上であることに加え、「ADX自体が上昇していること」を条件に加えています。これにより、トレンドの終焉局面でのエントリーを避け、加速局面のみに限定しています。 厳格なMTF(マルチタイムフレーム)フィルター 5分足の執行足だけでなく、15分足(EMA20)と1時間足(EMA50)の方向性が完全に一致している場合のみエントリーを許可します。上位足のトレンドに逆らわない設計が、勝率50%という数値ながら高いPFを実現させています。 時間帯の限定(ロンドン市場初動) JST 16:30〜19:00という、世界的に流動性が急増するロンドン市場のオープン時間帯に限定することで、方向感のないアジア時間のノイズを完全に排除しています。 Pythonコードの公開 本ロジックのベースとなったPythonコードです。pandas_ta を用いたテクニカル分析と、厳格な条件分岐が実装されています。 💡 プロはどうやってダマシを回避しているのか? 自作EAの成績が行き詰まった時は、実際にリアル口座で長期間利益を出し続けている「本物の市販EA」の挙動を観察することが、一番の勉強になります。 👉 プロのフィルターロジックが詰まった実績EA(一本勝ち)を参考にする from strategies.base import BaseStrategy import pandas_ta as ta import pandas as pd class VolatilityBreakoutPro(BaseStrategy): """ High-Precision Volatility Breakout Strategy. Focus: London Session Energy Release with Momentum Filter. Logic: BB Width V-Bottom -> ADX Rising -> MTF Alignment -> Band Walk Start. """ def __init__(self): # トレーリングストップで利益を最大化 super().__init__( name="VolatilityBreakoutPro_v4", default_tp_pips=50.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. 短期足(5min)のインジケーター計算 --- # ボリンジャーバンド bb = ta.bbands(df['Close'], length=20, std=2.0) df['BBL'] = bb.iloc[:, 0] df['BBM'] = bb.iloc[:, 1] df['BBU'] = bb.iloc[:, 2] # BB Width とそのトレンド(ボラティリティの底打ち判定用) df['BBW'] = (df['BBU'] - df['BBL']) / df['BBM'] df['BBW_avg'] = df['BBW'].rolling(window=50).mean() df['BBW_rising'] = df['BBW'] > df['BBW'].shift(1) # ADX (トレンド強度と方向) adx_df = ta.adx(df['High'], df['Low'], df['Close'], length=14) df['ADX'] = adx_df['ADX_14'] df['ADX_rising'] = df['ADX'] > df['ADX'].shift(1) # --- 2. マルチタイムフレーム (MTF) 分析 --- # 1時間足:長期方向性 (EMA 50) df_1h_close = df['Close'].resample('1h').last().ffill() ema_1h = ta.ema(df_1h_close, length=50) df['EMA_1h'] = ema_1h.reindex(df.index, method='ffill') # 15分足:中期方向性 (EMA 20) df_15m_close = df['Close'].resample('15min').last().ffill() ema_15m = ta.ema(df_15m_close, length=20) df['EMA_15m'] = ema_15m.reindex(df.index, method='ffill') # --- 3. 相場環境の定義 --- # 1. ボラティリティの蓄積から放出への転換 # BBWが平均以下であり、かつ上昇し始めた瞬間 df['vol_release'] = (df['BBW'] < df['BBW_avg'] * 1.1) & df['BBW_rising'] # 2. バンドの傾き(バンドウォークの兆候) df['BBU_rising'] = df['BBU'] > df['BBU'].shift(1) df['BBL_falling'] = df['BBL'] < df['BBL'].shift(1) # 3. ブレイクアウト判定(BBU突破 + 直近高値更新) df['break_high'] = (df['Close'] > df['BBU']) & (df['Close'] > df['High'].shift(1).rolling(3).max()) df['break_low'] = (df['Close'] < df['BBL']) & (df['Close'] < df['Low'].shift(1).rolling(3).min()) # --- 4. 上位足トレンドフィルター --- df['trend_filter'] = 0 # 1h-EMA50 と 15m-EMA20 の両方で方向が一致していること df.loc[(df['Close'] > df['EMA_1h']) & (df['Close'] > df['EMA_15m']), 'trend_filter'] = 1 df.loc[(df['Close'] < df['EMA_1h']) & (df['Close'] < df['EMA_15m']), 'trend_filter'] = -1 return df def generate_signal(self, df): if len(df) < 2: return None last = df.iloc[-1] prev = df.iloc[-2] # --- エントリー時間帯フィルター (ロンドン初動のノイズを除いた 16:30 - 19:00 JST) --- current_hour = df.index[-1].hour current_minute = df.index[-1].minute # 16:30以降、19:00まで if not ((current_hour == 16 and current_minute >= 30) or (17 <= current_hour < 19)): return None # --- 相場環境フィルター --- # ADXが20以上であり、かつ上昇していること(トレンド加速中) if last['ADX'] < 20 or not last['ADX_rising']: return None # --- エントリーロジック --- # BUY条件: # 1. MTFトレンド一致 (1h & 15m Up) # 2. ボラティリティが低水準から上昇に転じた (vol_release) # 3. 価格がBBUを突破し、BBU自体が上昇している (Band Walk) if (last['trend_filter'] == 1 and (last['vol_release'] or prev['vol_release']) and last['break_high'] and last['BBU_rising']): return 'BUY' # SELL条件: # 1. MTFトレンド一致 (1h & 15m Down) # 2. ボラティリティが低水準から上昇に転じた (vol_release) # 3. 価格がBBLを突破し、BBL自体が下降している (Band Walk) if (last['trend_filter'] == -1 and (last['vol_release'] or prev['vol_release']) and last['break_low'] and last['BBL_falling']): return 'SELL' return None MQL5コードへの翻訳(MT5用EA) 上記のPythonロジックをMetaTrader 5 (MT5) で動作するように忠実に再現したEAコードです。 ...