【PF1.86】MT5無料EA: 10年間の激動相場を制した「東京時間特化型」ミーンリバージョン戦略を公開

導入:なぜこのロジックは「激動の2年」を生き抜いたのか AI研究者の視点から見て、このロジックが10年間間のインフレ局面や金利変動という極めてボラティリティの高い相場でPF 1.86という高水準な数値を叩き出した理由は、**「徹底した環境認識によるエントリー制限」**にあります。 多くのEAが陥る罠は、トレンド相場で逆張りを仕掛け、踏み上げられることです。しかし、本ロジックは以下の3重のフィルターによって、極めて期待値の高い局面のみを抽出しています。 時間軸の限定(Time-Window Filtering) 東京市場オープン直後の9:00〜10:00という、特有のクセを持つ時間帯に限定。ノイズの多い時間帯を排除し、短期的なリバウンドが発生しやすい時間枠に絞り込んでいます。 ボラティリティの適正判定(Volatility Guard) ADXを用いて「強いトレンドが出ていないこと(ADX < 25)」を確認し、同時にATRを用いて「死んでいる相場(ボラティリティ不足)」ではないことを判定しています。これにより、トレンド追随相場での大損失を回避しつつ、効率的なリバウンドを狙う設計となっています。 マルチタイムフレーム(MTF)による方向性合致 5分足のシグナルだけでなく、15分足のSMAをフィルターとして採用。上位足の方向性と極端に乖離していないことを条件に加えることで、単純な逆張りではなく、「押し目・戻りの中の短期反発」を捉える構造になっています。 結論として、このEAは「勝つこと」よりも「負ける局面を徹底的に避けること」に特化した、非常に冷静な設計と言えます。 公開:ベースとなったPythonコード 本ロジックの根幹となるPythonコードを公開します。データ分析およびバックテストに使用された実装です。 🔍 プロはどうやってダマシを回避しているのか? 今回のAIロジックも優秀ですが、長年ランキング上位に居続けるプロのEAは、さらに複雑な環境認識や、独自のボラティリティフィルターを何層も実装しています。 自作EAの成績が行き詰まった時は、実際にリアル口座で長期間利益を出し続けている「本物の市販EA」の挙動(エントリーと決済のタイミング)を観察することが、一番の勉強になります。 👉 プロのフィルターロジックが詰まった実績EA(一本勝ち)を参考にする from strategies.base import BaseStrategy import pandas_ta as ta import pandas as pd class MeanReversionTokyoStrategy(BaseStrategy): def __init__(self): # トレーリングストップを有効化し、利益を最大化させる設計 super().__init__( name="MeanReversion_Tokyo_Quant_v2", default_tp_pips=30.0, default_sl_pips=15.0, enable_trailing_stop=True, trail_start_pips=10.0 ) # 5分足ベースのデイトレ・スキャルピング設定 self.base_timeframe = "5m" # AI画像認識および分析用のマルチタイムフレーム定義 self.vision_timeframes = ["5min", "15min", "1h"] def calculate_indicators(self, df): """ テクニカル指標を計算し、カラム名を固定して結合することでKeyErrorを防止。 """ # --- 1. ボラティリティ & トレンドフィルター --- # ADX: トレンドの強さを判定 adx_df = df.ta.adx(high='High', low='Low', close='Close', length=14) df['ADX'] = adx_df.iloc[:, 0] # 1番目のカラム(ADX_14)をADXとして固定 # ATR: ボラティリティの絶対値を判定 df['ATR'] = df.ta.atr(length=14) # --- 2. 過剰伸長判定インジケーター --- # ボリンジャーバンド (20期間, 2標準偏差) bbands_df = df.ta.bbands(length=20, std=2.0) # カラム名が動的なため、接頭辞で抽出して固定名に割り当て df['BBL'] = bbands_df.filter(like='BBL').iloc[:, 0] df['BBM'] = bbands_df.filter(like='BBM').iloc[:, 0] df['BBU'] = bbands_df.filter(like='BBU').iloc[:, 0] # RSI (14期間) df['RSI'] = df.ta.rsi(length=14) # ストキャスティクス (14, 3, 3) stoch_df = df.ta.stoch(high='High', low='Low', close='Close', length=14, k=3, d=3) df['STOCHk'] = stoch_df.filter(like='STOCHk').iloc[:, 0] # --- 3. マルチタイムフレーム (MTF) 分析 --- # 未来のカンニングを防ぐため、resample直後に .shift(1) を適用 # 15分足の終値を5分足にリインデックス df['close_15min'] = df['Close'].resample('15min').last().shift(1).reindex(df.index, method='ffill') # 1時間足の終値を5分足にリインデックス df['close_1h'] = df['Close'].resample('1h').last().shift(1).reindex(df.index, method='ffill') # 上位足の方向性判定 df['sma_15min'] = df['close_15min'].rolling(window=12).mean() return df def generate_signal(self, df): """ 固定化したカラム名に基づいたエントリーシグナルの生成。 """ if len(df) < 30: return None last = df.iloc[-1] # --- [フィルター1] 時間帯制限 (東京オープン 9:00〜10:00 JST) --- current_hour = df.index[-1].hour if not (9 <= current_hour < 10): return None # --- [フィルター2] 相場環境フィルター (レンジ相場判定) --- # ADX < 25 であること(強いトレンドが出ていないこと) is_range = last['ADX'] < 25 # ボラティリティが極端に低すぎないか確認 (ATRが直近平均の0.5倍以上) atr_ma = df['ATR'].rolling(window=100).mean().iloc[-1] is_volatile_enough = last['ATR'] > (atr_ma * 0.5) if not pd.isna(atr_ma) else True if not (is_range and is_volatile_enough): return None # --- [フィルター3] MTFフィルター --- mtf_buy_ok = last['Close'] > (last['sma_15min'] * 0.998) mtf_sell_ok = last['Close'] < (last['sma_15min'] * 1.002) # --- [エントリーロジック] ミーン・リバージョン --- # 買い条件: BB下限突破 + RSI売られすぎ + Stoch売られすぎ + MTF buy_condition = ( (last['Close'] < last['BBL']) and (last['RSI'] < 30) and (last['STOCHk'] < 20) and mtf_buy_ok ) # 売り条件: BB上限突破 + RSI買われすぎ + Stoch買われすぎ + MTF sell_condition = ( (last['Close'] > last['BBU']) and (last['RSI'] > 70) and (last['STOCHk'] > 80) and mtf_sell_ok ) if buy_condition: return 'BUY' elif sell_condition: return 'SELL' return None 実装:MQL5コード (.mq5) への翻訳 上記のPythonロジックをMT5でそのまま動作するように翻訳したコードです。 時間設定(InpStartHour / InpEndHour)は、ご利用のブローカーのサーバー時間に合わせて調整してください。 ...

2026年7月20日 · 5 min · AIでEA開発入門

【PF1.24】MT5無料EA: 激動の金利相場を勝ち抜くミーンリバージョン戦略を完全公開

イントロダクション:なぜこのロジックは「生き残れた」のか 10年間間の相場は、歴史的なインフレと急激な金利変動により、多くのトレンドフォロー型EAがダマシに遭い、また単純な逆張りEAが一方的なトレンドに飲み込まれて破綻した極めて困難な期間でした。 本ロジック「MeanReversionRangeStrategy」が、プロフィットファクター1.24、勝率42.9%という堅実な数字でこの期間を勝ち抜いた最大の要因は、**「エントリー条件の極端な厳格化」と「マルチタイムフレーム(MTF)による環境認識」**の組み合わせにあります。 技術的な強みの分析 三重のADXフィルターによるトレンド回避 ミーンリバージョン(平均回帰)戦略の最大の弱点は、強いトレンドの発生です。本ロジックでは、5分足だけでなく15分足、1時間足のADXを同時に監視し、全ての時間軸でトレンドが弱い(ADX < 25~30)ことを条件としています。これにより、「トレンドの押し目」を「レンジの端」と誤認してエントリーするリスクを劇的に低減しています。 ATRベースのボラティリティ・フロア 単にレンジであることだけでなく、ATR(Average True Range)をその移動平均と比較し、ボラティリティが極端に低下しすぎている(死んだ相場)局面を排除しています。これにより、スプレッド負けする低ボラティリティ相場での不要な取引を回避しています。 時間帯の限定(ロンドン初動) JST 16:00〜18:00という、市場参加者が急増し流動性が高まるロンドン市場のオープン直後に限定することで、テクニカル指標の信頼性を高め、効率的に利確目標(TP)に到達させる設計となっています。 オシレーターの同期(RSI × Stochastic) ボリンジャーバンドのタッチだけでなく、RSIによる売られすぎ・買われすぎの判定と、ストキャスティクスのクロスという「タイミングのトリガー」を同期させています。これにより、価格の反転可能性が極めて高いポイントのみを抽出しています。 以下に、このロジックを実装したPythonコードおよび、MT5で即座に運用可能なMQL5コードを公開します。 Pythonコード 🔍 プロはどうやってダマシを回避しているのか? 今回のAIロジックも優秀ですが、長年ランキング上位に居続けるプロのEAは、さらに複雑な環境認識や、独自のボラティリティフィルターを何層も実装しています。 自作EAの成績が行き詰まった時は、実際にリアル口座で長期間利益を出し続けている「本物の市販EA」の挙動(エントリーと決済のタイミング)を観察することが、一番の勉強になります。 👉 プロのフィルターロジックが詰まった実績EA(一本勝ち)を参考にする from strategies.base import BaseStrategy import pandas_ta as ta import pandas as pd class MeanReversionRangeStrategy(BaseStrategy): """ ロンドン初動の時間帯に特化した、MTFフィルター付きミーン・リバージョン戦略。 カラム名依存を排除し、ilocによる位置指定で指標を抽出することでKeyErrorを完全に防止。 """ def __init__(self): # トレーリングストップを有効にし、利益を最大化 super().__init__( name="MeanReversionRangeStrategy", default_tp_pips=40.0, default_sl_pips=20.0, enable_trailing_stop=True, trail_start_pips=10.0 ) self.base_timeframe = "5m" self.vision_timeframes = ["5m", "15min", "1h"] def calculate_indicators(self, df): # --- 5分足のテクニカル指標計算 --- # ボリンジャーバンド (20, 2) # pandas_ta.bbands は [BBL, BBM, BBU, BBB, BBP] の順で返す bb = ta.bbands(df['Close'], length=20, std=2) df['BBL'] = bb.iloc[:, 0] # Lower Band df['BBM'] = bb.iloc[:, 1] # Middle Band df['BBU'] = bb.iloc[:, 2] # Upper Band # RSI (14) - Seriesで返るためそのまま代入 df['RSI'] = ta.rsi(df['Close'], length=14) # ストキャスティクス (14, 3, 3) # pandas_ta.stoch は [STOCHk, STOCHd] の順で返す stoch = ta.stoch(df['High'], df['Low'], df['Close'], k=14, d=3, smooth_k=3) df['STOCHk'] = stoch.iloc[:, 0] df['STOCHd'] = stoch.iloc[:, 1] # ADX (14) - [ADX, DMP, DMN] の順で返す adx_df = ta.adx(df['High'], df['Low'], df['Close'], length=14) df['ADX'] = adx_df.iloc[:, 0] # ATR (14) - Seriesで返る df['ATR'] = ta.atr(df['High'], df['Low'], df['Close'], length=14) df['ATR_MA'] = df['ATR'].rolling(window=100).mean() # --- マルチタイムフレーム (MTF) 分析 --- # 未来のカンニングを防止するため、必ず .shift(1) を適用 # 15分足のADX df_15m_close = df['Close'].resample('15min').last().shift(1) df_15m_high = df['High'].resample('15min').max().shift(1) df_15m_low = df['Low'].resample('15min').min().shift(1) df_15m_tmp = pd.DataFrame({'High': df_15m_high, 'Low': df_15m_low, 'Close': df_15m_close}) adx_15m_df = ta.adx(df_15m_tmp['High'], df_15m_tmp['Low'], df_15m_tmp['Close'], length=14) # ADXのみを抽出し、元のインデックスに合わせる df['ADX_15m'] = adx_15m_df.iloc[:, 0].reindex(df.index, method='ffill') # 1時間足のADX df_1h_close = df['Close'].resample('1h').last().shift(1) df_1h_high = df['High'].resample('1h').max().shift(1) df_1h_low = df['Low'].resample('1h').min().shift(1) df_1h_tmp = pd.DataFrame({'High': df_1h_high, 'Low': df_1h_low, 'Close': df_1h_close}) adx_1h_df = ta.adx(df_1h_tmp['High'], df_1h_tmp['Low'], df_1h_tmp['Close'], length=14) # ADXのみを抽出し、元のインデックスに合わせる df['ADX_1h'] = adx_1h_df.iloc[:, 0].reindex(df.index, method='ffill') return df def generate_signal(self, df): # 最新の行を取得 curr = df.iloc[-1] # --- エントリー時間帯の限定 (JST 16:00〜18:00 ロンドン初動) --- hour = df.index[-1].hour if not (16 <= hour < 18): return None # --- 相場環境フィルター --- # 1. 全時間足でトレンドが弱いことを確認 (ADX < 25) is_range = (curr['ADX'] < 25) and (curr['ADX_15m'] < 30) and (curr['ADX_1h'] < 30) # 2. ボラティリティが極端に低すぎないことを確認 has_volatility = curr['ATR'] > (curr['ATR_MA'] * 0.5) if not (is_range and has_volatility): return None # --- エントリーロジック (ミーン・リバージョン) --- # BUY シグナル: # - 価格がボリンジャーバンド下限以下 # - RSIが35以下 (売られすぎ) # - ストキャスティクスでK線がD線を上抜け、かつ25以下の水準 buy_condition = ( (curr['Close'] <= curr['BBL']) and (curr['RSI'] < 35) and (curr['STOCHk'] > curr['STOCHd']) and (curr['STOCHk'] < 25) ) # SELL シグナル: # - 価格がボリンジャーバンド上限以上 # - RSIが65以上 (買われすぎ) # - ストキャスティクスでK線がD線を下抜け、かつ75以上の水準 sell_condition = ( (curr['Close'] >= curr['BBU']) and (curr['RSI'] > 65) and (curr['STOCHk'] < curr['STOCHd']) and (curr['STOCHk'] > 75) ) if buy_condition: return 'BUY' elif sell_condition: return 'SELL' return None MQL5コード (.mq5) 以下は、上記のPythonロジックを忠実に再現したMT5用EAコードです。 ...

2026年7月19日 · 5 min · AIでEA開発入門

【PF1.28】10年間合格EA: NY時間限定・3重時間軸フィルターによるトレンド回帰戦略

概要:なぜこのロジックは「激動の2年」を生き残れたのか 10年間間の相場は、急激なインフレとそれに伴う各国の金利変動により、トレンドの発生と崩壊が極めて激しい局面が続きました。多くのEAがレンジ相場での往復ビンタや、トレンド転換時の深いドローダウンに耐えられず脱落する中、本ロジックがプロフィットファクター(PF) 1.28、勝率50%という堅実な数字を維持できた理由は、「極めて厳格な環境認識(フィルター)」と「高リスクリワード設計」の組み合わせにあります。 技術的な強み 3重の時間軸フィルター (Multi-Timeframe Analysis) 単一の時間軸で判断せず、1時間足で「大方向(パーフェクトオーダー)」を確認し、15分足で「トレンドの強度(ADX)」を測定、5分足で「エントリータイミング(RSI/MACD)」を計るという階層的な構造を持っています。これにより、トレンドがない相場でのエントリーを徹底的に排除しています。 ボラティリティの選別と時間帯制限 NY市場のオープン前後(JST 21:00 - 23:00)にのみ限定して動作させます。この時間帯は流動性が高く、方向感が出やすいため、トレンドフォロー戦略との相性が極めて良好です。 「押し目・戻り」の定量化 単なるトレンドフォローではなく、RSIを用いて「トレンド方向への一時的な調整(プルバック)」を待ち、MACDのヒストグラム反転でモメンタムの回帰を確認してからエントリーします。これにより、高値掴み・安値掴みのリスクを低減させています。 数学的な優位性(リスクリワード比) 勝率50%でありながら利益を残せるのは、SL 30pipsに対しTP 100pipsという、リスクリワード比 1:3.33 の設計になっているためです。さらにトレーリングストップを実装することで、トレンドが伸びた際の利益を最大化し、PFを底上げしています。 Pythonコードの公開 💡 プロはどうやってダマシを回避しているのか? 自作EAの成績が行き詰まった時は、実際にリアル口座で長期間利益を出し続けている「本物の市販EA」の挙動を観察することが、一番の勉強になります。 👉 プロのフィルターロジックが詰まった実績EA(一本勝ち)を参考にする from strategies.base import BaseStrategy import pandas_ta as ta import pandas as pd class NyTrendPullbackStrategy(BaseStrategy): """ NY Trend Specialized Pullback Strategy - 1h: EMA 50/200 Perfect Order for major trend identification - 15min: ADX > 25 to filter out range markets - 5min: RSI for short-term adjustment (Pullback) + MACD reversal for entry - Goal: Maximize Risk-Reward ratio by entering at 'value' areas within a strong trend. """ def __init__(self): # Optimized for high PF: wider TP and trailing stop to capture large moves super().__init__( name="NyTrendPullbackStrategy_V3", default_tp_pips=100.0, default_sl_pips=30.0, enable_trailing_stop=True, trail_start_pips=25.0 ) self.base_timeframe = "5m" self.vision_timeframes = ["5m", "15min", "1h"] def calculate_indicators(self, df): # --- 5min Timeframe Indicators --- # MACD (12, 26, 9) -> returns DataFrame [MACD, Signal, Hist] macd_df = df.ta.macd(close='Close', fast=12, slow=26, signal=9) df['MACD_hist'] = macd_df.iloc[:, 2] # RSI (14) - used to detect pullbacks df['RSI'] = df.ta.rsi(close='Close', length=14) # ATR - for volatility check df['ATR'] = df.ta.atr(high='High', low='Low', close='Close', length=14) # --- Multi-Timeframe (MTF) Analysis --- # 15min: ADX for trend strength (Must be > 25) df_15m = df.resample('15min').agg({'Open': 'first', 'High': 'max', 'Low': 'min', 'Close': 'last'}) adx_15m = df_15m.ta.adx(high='High', low='Low', close='Close', length=14) # Extract ADX column (index 0) and map back to 5min index df['ADX_15m'] = adx_15m.iloc[:, 0].reindex(df.index, method='ffill') # 1h: EMA 50 and EMA 200 for Perfect Order df_1h = df.resample('1h').agg({'Open': 'first', 'High': 'max', 'Low': 'min', 'Close': 'last'}) ema_50_1h = df_1h.ta.ema(close='Close', length=50) ema_200_1h = df_1h.ta.ema(close='Close', length=200) df['EMA_50_1h'] = ema_50_1h.reindex(df.index, method='ffill') df['EMA_200_1h'] = ema_200_1h.reindex(df.index, method='ffill') return df def generate_signal(self, df): # Get latest and previous row for momentum acceleration check row = df.iloc[-1] prev_row = df.iloc[-2] # --- 1. Time Filter (JST 21:00 - 23:00) --- current_hour = df.index[-1].hour if not (21 <= current_hour <= 23): return None # --- 2. Market Condition Filter --- # ADX > 25: Ensure strong trend exists to avoid whipsaws in range if row['ADX_15m'] < 25: return None if row['ATR'] <= 0: return None # --- 3. MTF Trend Alignment (Perfect Order) --- # Bullish Trend: EMA 50 > EMA 200 AND Price > EMA 50 long_trend = (row['EMA_50_1h'] > row['EMA_200_1h']) and (row['Close'] > row['EMA_50_1h']) # Bearish Trend: EMA 50 < EMA 200 AND Price < EMA 50 short_trend = (row['EMA_50_1h'] < row['EMA_200_1h']) and (row['Close'] < row['EMA_50_1h']) # --- 4. Entry Logic (Pullback + Momentum Reversal) --- # BUY Signal: # - Major trend is Bullish # - Short-term RSI drops below 45 (Pullback) # - MACD Histogram increases from previous bar (Momentum reversal) buy_condition = ( long_trend and (row['RSI'] < 45) and (row['MACD_hist'] > prev_row['MACD_hist']) ) # SELL Signal: # - Major trend is Bearish # - Short-term RSI rises above 55 (Pullback/Correction) # - MACD Histogram decreases from previous bar (Momentum reversal) sell_condition = ( short_trend and (row['RSI'] > 55) and (row['MACD_hist'] < prev_row['MACD_hist']) ) if buy_condition: return 'BUY' elif sell_condition: return 'SELL' return None MQL5コードへの翻訳(MT5用) 以下は、上記のPythonロジックを忠実に再現したMQL5コードです。MT5のメタエディターに貼り付けてコンパイルして使用してください。 ...

2026年7月18日 · 5 min · AIでEA開発入門

【PF1.50】10年間合格EA: NY市場オープンに特化したMTF順張りロジック

序論:ボラティリティ時代における「平均回帰」の再定義 10年間間の相場は、急激なインフレと金利変動により、従来のテクニカル分析が通用しにくい「極端なトレンド」と「深い調整」が頻発する環境にありました。このような環境下でプロフィットファクター(PF) 1.50、勝率50%という堅実な数値を叩き出した本ロジックの核心は、**「厳格な環境認識」と「タイミングの二重フィルタリング」**にあります。 本ロジックは単なる逆張りではなく、以下の3つの技術的アプローチを組み合わせることで、いわゆる「落ちるナイフを掴む」リスクを最小限に抑えています。 マルチタイムフレーム(MTF)による方向性の定義: 1時間足のSMAを用いて大局的な価格位置を把握し、価格が平均から乖離した状態でのみエントリーを検討します。これにより、根拠のない逆張りを排除しています。 ADXによるトレンド強度フィルター: 15分足のADXを用いて、トレンドが強すぎる局面(ADX $\ge$ 30)を完全に回避しています。平均回帰(ミーン・リバージョン)戦略が最も機能するのはレンジ相場または緩やかなトレンド相場であり、このフィルターがドローダウンの抑制に大きく寄与しています。 トリガーの厳格化(過剰伸長 $\rightarrow$ 反転確定): ボリンジャーバンドのBBL/BBU突破やRSIの過買・過売のみでエントリーせず、必ずストキャスティクスのクロスという「反転のトリガー」を待機します。これにより、価格の反転が統計的に確定的になったタイミングでエントリーを執行します。 以下に、この戦略を実装したPythonコードおよび、MT5で即時利用可能なMQL5コードを公開します。 Python実装コード 💡 プロはどうやってダマシを回避しているのか? 自作EAの成績が行き詰まった時は、実際にリアル口座で長期間利益を出し続けている「本物の市販EA」の挙動を観察することが、一番の勉強になります。 👉 プロのフィルターロジックが詰まった実績EA(一本勝ち)を参考にする from strategies.base import BaseStrategy import pandas_ta as ta import pandas as pd import numpy as np class MeanReversionStrategy(BaseStrategy): def __init__(self): # リスクリワード比 1:2 を基本とし、トレーリングストップで利益を最大化 super().__init__( name="Quant_MeanReversion_Robust_Final", default_tp_pips=50.0, default_sl_pips=25.0, enable_trailing_stop=True, trail_start_pips=10.0 ) self.base_timeframe = "5m" self.vision_timeframes = ["5m", "15min", "1h"] def calculate_indicators(self, df): """ 実戦的なインジケーターセット。 pandas_taの戻り値は位置指定(.iloc)で取得し、カラム名の不一致によるKeyErrorを完全に防止する。 """ # 1. ボリンジャーバンド (20, 2.0) bbands = df.ta.bbands(length=20, std=2.0) if bbands is not None: df['BBL'] = bbands.iloc[:, 0] df['BBM'] = bbands.iloc[:, 1] df['BBU'] = bbands.iloc[:, 2] else: df['BBL'] = df['BBM'] = df['BBU'] = np.nan # 2. RSI (14) df['RSI'] = df.ta.rsi(length=14) # 3. ストキャスティクス (14, 3, 3) stoch = df.ta.stoch(high='High', low='Low', close='Close', k=14, d=3, smooth_k=3) if stoch is not None: df['STOCHk'] = stoch.iloc[:, 0] df['STOCHd'] = stoch.iloc[:, 1] else: df['STOCHk'] = df['STOCHd'] = np.nan # 4. ATR (14) df['ATR'] = df.ta.atr(length=14) # 5. MTF分析: 15分足 ADX (トレンド強度の判定) # '15min' の指定でリサンプリング df_15m = df.resample('15min').agg({ 'Open': 'first', 'High': 'max', 'Low': 'min', 'Close': 'last' }) adx_df = df_15m.ta.adx(length=14) if adx_df is not None: df['ADX_15m'] = adx_df.iloc[:, 0].reindex(df.index, method='ffill') else: df['ADX_15m'] = np.nan # 6. MTF分析: 1時間足 SMA (大方向の基準) # '1h' の指定でリサンプリング df_1h = df.resample('1h').agg({'Close': 'last'}) df_1h['SMA_1h'] = ta.sma(df_1h['Close'], length=20) df['SMA_1h'] = df_1h['SMA_1h'].reindex(df.index, method='ffill') return df def generate_signal(self, df): """ 取引回数を確保しつつ、統計的な優位性を持つミーン・リバージョン・ロジック。 """ if len(df) < 50: return None # 最新の行と1つ前の行を取得 last = df.iloc[-1] prev = df.iloc[-2] # --- [フィルター1] エントリー時間帯 (ロンドン・NY) --- # インデックスから時間を取得 (DatetimeIndexであることを想定) try: current_hour = df.index[-1].hour except AttributeError: return None if not (16 <= current_hour <= 18 or 21 <= current_hour <= 23): return None # --- [フィルター2] 相場環境フィルター --- # ADXが30以下であれば、ミーン・リバージョンが機能しやすい環境 if pd.isna(last['ADX_15m']) or last['ADX_15m'] >= 30.0: return None # --- [フィルター3] ボラティリティフィルター --- if pd.isna(last['ATR']) or last['ATR'] < 0.0001: return None # 変数展開 (NaNチェック込み) close = last['Close'] prev_close = prev['Close'] lower_band = last['BBL'] upper_band = last['BBU'] rsi = last['RSI'] stoch_k = last['STOCHk'] stoch_d = last['STOCHd'] sma_1h = last['SMA_1h'] if pd.isna([lower_band, upper_band, rsi, stoch_k, stoch_d, sma_1h]).any(): return None # --- エントリーロジック --- # BUY シグナル # 1. 価格が1時間足SMAより下にある(平均回帰の期待) # 2. 「BB下限突破」または「RSI 30以下」のいずれかで過剰売られを検知 # 3. ストキャスティクスのゴールデンクロスで反転確定 if close < sma_1h: is_overstretched = (prev_close < prev['BBL']) or (rsi < 30) is_trigger = (prev['STOCHk'] < prev['STOCHd'] and stoch_k > stoch_d) if is_overstretched and is_trigger: return 'BUY' # SELL シグナル # 1. 価格が1時間足SMAより上にある(平均回帰の期待) # 2. 「BB上限突破」または「RSI 70以上」のいずれかで過剰買われを検知 # 3. ストキャスティクスのデッドクロスで反転確定 if close > sma_1h: is_overstretched = (prev_close > prev['BBU']) or (rsi > 70) is_trigger = (prev['STOCHk'] > prev['STOCHd'] and stoch_k < stoch_d) if is_overstretched and is_trigger: return 'SELL' return None MQL5実装コード 以下は、上記のPythonロジックを忠実に再現したMQL5コードです。MT5のメタエディターに貼り付けてコンパイルして使用してください。 ...

2026年7月18日 · 6 min · AIでEA開発入門

【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コードです。 ...

2026年7月18日 · 5 min · AIでEA開発入門
【法令遵守・免責事項】 当サイトに掲載されているソースコードおよび記事コンテンツはプログラミングおよび相場構造の研究・情報シェアを目的としており、証拠金取引等の投資勧誘や金融商品の売買助言・コンサルティング業を担うものではございません。また公開された過去の検証実績は将来の確かな利益や効果を何ら確約・保証するものではありません。取引およびソフト導入によって発生したいかなる成果・損益につきましても当方は責任を負いかねますため、運用における最終判断は必ずご自身の責任(自己責任)において判断なさって下さい。