FXスイングトレードEAにフィルターを実装する方法|バックテスト改善の実践ガイド
最終更新: 2026年07月
Photo by Marga Santoso on Unsplash
FXスイングトレードEAにフィルターを実装することは、バックテストの結果を実運用に近づけるための最重要ステップの一つだ。
スイングトレードEAを自作したことがある人なら、一度は経験があるはずだ。バックテストでは見栄えの良い損益曲線が出た。しかし実運用に移した途端、横ばい相場でのポジション損失が積み重なり、プロフィットファクター(PF)がじりじりと悪化していく——あの不快感を。
問題の核心はシンプルだ。エントリーシグナルのロジックだけ洗練させても、「いつエントリーしてはいけないか」を定義しなければEAは完成しない。その定義を担うのがフィルターだ。
以下では、スイングトレードEAに実装すべきフィルターを3種類に絞り込み、MQL5の実装コードとバックテスト上での改善効果を実装ベースで解説する。日本語記事では扱いが手薄なATR Percentileフィルターや、過剰最適化の判定基準も含めて体系的に触れていく。
スイングトレードEAにフィルターが必要な理由
Photo by Maxim Hopman on Unsplash
FXスイングトレードEAにフィルターが必要な理由は、エントリーシグナルだけでは「いつエントリーしてはいけないか」を定義できないためだ。為替市場は時間比率の大半がレンジ環境であり、フィルターはこの局面での誤エントリーを機械的にスキップする機能を担う。
フィルターなしEAの欠点――横ばい相場での誤エントリー
スイングトレードのエントリーシグナルは、多くの場合、移動平均のゴールデンクロスやブレイクアウトをトリガーとする。これらのシグナルは本質的に「方向性がある相場」を前提に設計されている。
ところが為替市場は、トレンド相場よりもレンジ(横ばい)相場の方が時間比率として長い。要検証だが、経験則的には市場の60〜70%はレンジ環境だと言われる。フィルターなしのEAが10回エントリーしたとすれば、そのうち6〜7回はトレンドが存在しない局面での誤発注という計算になる。
結果として損益曲線には特徴的なパターンが現れる。トレンド相場で大きく利益を伸ばし、その後のレンジ相場でコツコツと削られる鋸歯状のドローダウンだ。フィルターの役割は、この「コツコツ削られる局面」を機械的にスキップすることにある。
フィルター追加によるリスクリワード改善効果
フィルターの導入はトレード機会の減少を伴う。これを嫌う設計者もいるが、見方を変えると「精度の低いエントリーを捨てて、精度の高いエントリーだけを残す」という操作だ。
ATRベースのボラティリティフィルターを例に取ると、複数のバックテスト事例で観察された傾向として、相対的ATR比率フィルターを適用することでPFが10〜30%程度改善するケースが見られる。取引回数は減るが、1トレードあたりの期待値が上がるため、最終的な資金曲線の安定性は向上する可能性が高まる。
Claudeと会話しながらEAのフィルター設計ができるhedgrow-fxはこちら
スイングトレードEAで有効なフィルター3種類
Photo by Jakub Żerdzicki on Unsplash
スイングトレードEAに有効なフィルターは、トレンドフィルター(MA・ADX)、ボラティリティフィルター(ATR Percentile)、時間フィルター(セッション・指標前後)の3種類が基本構成となる。
フィルターは段階的に追加していくのが原則だ。「MAフィルターのみ」から始め、「ADXを追加」「ATRを追加」「時間フィルターを追加」という順序で一つずつ検証することで、どのフィルターがPF改善に寄与したかを切り分けられる。全部まとめて追加してから「なぜ改善したか」を評価するのは過剰最適化の温床になる。
1. トレンドフィルター(MA・ADX)
移動平均(MA)は方向性フィルターの中で最も素直な実装だ。価格がMA200より上にあるときのみロングエントリーを許可する、といった使い方が典型例になる。しかし単純なMAフィルターには「MAが向いているかどうか」だけを見て「そのトレンドがどれだけ強いか」を測れない、という弱点がある。
そこでADX(Average Directional Index)を組み合わせる。ADXはトレンドの「方向」ではなく「強度」を定量化する指標で、ADX 25超が強トレンド、20未満がレンジの目安とされている(出典:OANDA Lab Education)。推奨期間は標準の14期間か、長期トレンド志向であれば20〜30期間が適切だ(出典:ThreeTrader Japan)。ただし25という閾値はあくまで起点であり、通貨ペアや時間軸ごとにバックテストで確認することで実際に機能する最適値が見えてくることが多い。
ADXをEAフィルターとして活用する詳細な設定方法と実装パターンは、ADX・DMIをEAフィルターとして実装する方法で解説している。
MQL5実装例 — トレンドフィルター(OnInit / OnTick 分離構造)
// ===== グローバル変数 =====
int g_adx_handle;
int g_ma_handle;
// ===== OnInit() — ハンドル取得(1回のみ) =====
int OnInit()
{
g_adx_handle = iADX(_Symbol, PERIOD_D1, 14);
g_ma_handle = iMA(_Symbol, PERIOD_D1, 200, 0, MODE_SMA, PRICE_CLOSE);
if(g_adx_handle == INVALID_HANDLE || g_ma_handle == INVALID_HANDLE)
return INIT_FAILED;
return INIT_SUCCEEDED;
}
// ===== OnDeinit() — ハンドル解放 =====
void OnDeinit(const int reason)
{
IndicatorRelease(g_adx_handle);
IndicatorRelease(g_ma_handle);
}
// ===== トレンドフィルター判定関数 =====
bool IsTrendFilterPassed(ENUM_ORDER_TYPE direction)
{
double adx_buf[3], ma_buf[3];
ArraySetAsSeries(adx_buf, true);
ArraySetAsSeries(ma_buf, true);
// 確定足[1]を使用 — [0]はリペイントリスクあり
if(CopyBuffer(g_adx_handle, 0, 1, 3, adx_buf) < 3) return false;
if(CopyBuffer(g_ma_handle, 0, 1, 3, ma_buf) < 3) return false;
double adx_val = adx_buf[1]; // 確定足[1]
double ma_val = ma_buf[1]; // 確定足[1]
double close_val = iClose(_Symbol, PERIOD_D1, 1);
bool adx_ok = (adx_val > 25.0); // ADX 25超 = 強トレンド
if(direction == ORDER_TYPE_BUY)
return adx_ok && (close_val > ma_val); // 価格がMA200上 + ADX強
if(direction == ORDER_TYPE_SELL)
return adx_ok && (close_val < ma_val); // 価格がMA200下 + ADX強
return false;
}
コードで一点だけ押さえておくべきなのが「確定足[1]を使う」点だ。形成中のバー[0]を参照するとバックテスト時と実運用時でシグナルがずれる「リペイント」が発生する。スイングトレードはD1足を使うことが多いため、1日1回の確定タイミング以外では[0]の値が常に変動していることを意識したい。
2. ボラティリティフィルター(ATR)
ボラティリティが著しく低い環境では、仮にトレンドがあっても値幅が取れない。逆にボラティリティが急激に上昇した局面(経済指標発表直後など)では、スプレッド拡大やスリッページのリスクが高まる。ATR(Average True Range)フィルターはこの両極端を除外するために使う。
ATRの計算式とFXボラティリティへの応用を先に把握しておくと、以降の実装コードが理解しやすい。
踏み込んで紹介したいのが**ATR Percentile(相対ボラティリティ比率)**だ。英語圏のシステムトレーダーの間では普及しているが、日本語記事での解説はほぼ見当たらない。
計算式は単純だ。
vol_ratio = ATR(14) ÷ ATR_SMA(120)
ATR(14)を過去120期間のATR平均で割ることで、「現在のボラティリティが歴史的に見て相対的にどの水準か」を0.x〜2.x程度の無次元量として把握できる。固定値のATR閾値と違い、通貨ペアや相場環境に依存しないため汎用性が高い。
MQL5実装例 — ATR Percentile フィルター
int g_atr14_handle;
int g_atr120_handle;
int OnInit()
{
// ATR(14) と ATR(120) を別々のハンドルで取得
g_atr14_handle = iATR(_Symbol, PERIOD_D1, 14);
g_atr120_handle = iATR(_Symbol, PERIOD_D1, 120);
if(g_atr14_handle == INVALID_HANDLE ||
g_atr120_handle == INVALID_HANDLE)
return INIT_FAILED;
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
IndicatorRelease(g_atr14_handle);
IndicatorRelease(g_atr120_handle);
}
// vol_ratio の適正範囲: 0.7〜1.5 を目安に設定(要バックテスト検証)
bool IsVolatilityFilterPassed(double vol_min = 0.7, double vol_max = 1.5)
{
double atr14_buf[2], atr120_buf[2];
ArraySetAsSeries(atr14_buf, true);
ArraySetAsSeries(atr120_buf, true);
if(CopyBuffer(g_atr14_handle, 0, 1, 2, atr14_buf) < 2) return false;
if(CopyBuffer(g_atr120_handle, 0, 1, 2, atr120_buf) < 2) return false;
double atr14 = atr14_buf[1];
double atr120 = atr120_buf[1];
if(atr120 <= 0.0) return false; // ゼロ除算ガード
double vol_ratio = atr14 / atr120;
// vol_ratioが範囲外ならエントリー抑制
return (vol_ratio >= vol_min && vol_ratio <= vol_max);
}
vol_min = 0.7(低ボラ除外)とvol_max = 1.5(高ボラ除外)はあくまで初期値だ。通貨ペアや時間軸によって最適値は異なるため、後述のウォークフォワード検証で個別に確認する必要がある。
要するに、ATR Percentileフィルターの強みは「現在のボラティリティが歴史的水準に対して適正範囲内か」を通貨ペア非依存の形で定量的に判定できる点にある。固定pips閾値では通じない環境変化に対して、このアプローチは頑健だ。
3. 時間フィルター(セッション・指標前後)
FX市場はセッションによってボラティリティと流動性の特性が大きく異なる。東京セッション(日本時間9:00〜17:00頃)はドル円の流動性は高いが相対的に値幅が小さく、スイングトレードのエントリーに向かないことも多い。ロンドン・NYセッションが重複する時間帯は夏時間で日本時間21:00〜翌1:00、冬時間で22:00〜翌2:00となり、最高ボラティリティ帯を形成する(出典:OANDA Lab Education)。D1足スイングトレードEAでもこの時間帯を起点に判断することが多い。
また米国雇用統計(NFP)やFOMC発表前後は、スプレッドが数十pipも拡大することがあり、EAが意図しない損失を被るリスクが高い。発表の30〜60分前からエントリーを停止する時間フィルターは必須だ。
MQL5実装例 — セッション時間フィルター
// 日本時間(UTC+9)でのセッション定義
// ロンドン・NY重複帯: 夏時間21:00〜翌1:00 / 冬時間22:00〜翌2:00(UTC+9換算)
bool IsSessionFilterPassed()
{
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt); // サーバー時間取得
int hour = dt.hour;
// サーバーがUTC+2(冬時間)の場合の例
// ロンドン・NY重複帯: UTC 12:00〜17:00 → サーバー時間 14:00〜19:00
// 実際のサーバーオフセットはブローカーに応じて調整が必要
bool in_active_session = (hour >= 14 && hour < 19);
return in_active_session;
}
// 指標発表前後の除外(例: 30分間エントリー停止)
// ※実運用では外部カレンダーAPIとの連携が望ましい
bool IsNewsFilterPassed(int minutes_before = 30, int minutes_after = 30)
{
// 簡易実装例: 特定の曜日・時間をハードコード除外
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
// 毎週金曜日 21:30(UTC)± 30分 = NFP除外ゾーン(近似)
if(dt.day_of_week == 5 && dt.hour >= 21 && dt.hour <= 22)
return false;
return true;
}
時間フィルターの実装で注意すべきはサーバー時間のオフセットだ。TimeCurrent()はMT5のサーバー時間を返す。ブローカーによってUTC+2(EET)やUTC+3(EEST、夏時間)が使われるため、日本時間に換算する際は定数でオフセットを調整するより、サーバー時間のまま扱う設計が安全だ。
時間フィルターをMQL4/MQL5の両環境で設定する際の詳細オプションはMQL4/MQL5でのEA時間フィルター設定方法にまとめている。
フィルター実装のバックテスト検証方法
Photo by Nick Chong on Unsplash
フィルター実装後の検証は、MT5ストラテジーテスターで「1フィルター追加→再バックテスト→PF/取引回数比較」を繰り返すサイクルで行う。一括追加は過剰最適化の温床となるため禁止だ。
MT5ストラテジーテスターでの検証手順
フィルターの追加は必ず「1つ追加 → バックテスト → 評価」というサイクルで行う。全フィルターをまとめて追加してからテストすると、どのフィルターが効いているかの切り分けができなくなる。
推奨する検証フロー:
- ベースEA(フィルターなし)のバックテスト結果を記録する
- MAトレンドフィルターを追加して再検証 → PF・取引回数・最大ドローダウンを比較する
- ADXフィルターを追加して再検証する
- ATR Percentileフィルターを追加して再検証する
- 時間フィルターを追加して再検証する
各ステップでPFが改善し、かつ取引回数が著しく減少していないかを確認する。
フィルター追加前後の損益曲線比較
PF 1.0超がプラス収益、1.3〜1.5が優秀水準、2.0以上になると過剰最適化の疑いが生じる(出典:EA-Lab)。フィルターを追加してPFが2.0を大幅に超えた場合、それはフィルターが未来を"覗き見"しているような最適化になっている可能性が高い。
PFの具体的な評価基準値と読み方についてはバックテストのプロフィットファクター(PF)基準値の解説を参照してほしい。
バックテスト期間を通じた取引回数は多いほど統計的信頼性が高まる。最低限100回以上は確保したいが、EA開発実務では500回以上(理想は1,000回以上)を推奨する声が多い(OANDA Lab Educationは「取引数が多いほど信頼度が増す」と記載)。取引回数が50回を下回るバックテスト結果は、統計的有意性の観点から参考値に留めるべきだ。
過剰最適化に注意(フィルターの追加しすぎ禁止)
フィルターを増やせば増やすほどバックテストのPFは向上しやすい。なぜなら、追加したフィルターが「過去の損失トレードを後付けで除外する」という機能を果たすからだ。これはカーブフィッティング(過剰適合)と呼ばれる現象で、将来の相場では全く機能しない。
カーブフィッティングの具体的な検知方法と回避策はEAのカーブフィッティング(過剰最適化)を回避する方法で詳しく解説している。
過剰最適化を検知するための4つのチェックポイントを以下に示す。
- 取引回数は十分か — サンプルが少なすぎると結果の信頼性が統計的に保証できない(最低100回、実務では500回以上が望ましい)
- PFが2.0を大幅に超えていないか — 過剰最適化の強いシグナルとして扱う
- 最適パラメータ前後(±2〜3)でも安定した成績か — 特定のパラメータ値でのみ機能するEAは脆弱だ
- アウトオブサンプル期間でも同様の成績か — 最適化期間(インサンプル)とは別の期間での検証が不可欠だ
4番目に関連して、**ウォークフォワード効率(WFE)**という指標が役立つ(参考:DEASIGN)。
WFE = 平均年間WF利益 ÷ 平均年間最適化利益 × 100(%)
WFEが60%以上であれば、最適化期間の成績がアウトオブサンプル期間でもある程度再現されていると判断できる。WFEが50%を下回る場合は、そのフィルター設定は過去に最適化されすぎている可能性が高い水準の目安となる。ただし基準は情報源により異なり(50〜60%を合格ラインとする文献が多い)、単一の数値に依存せず複数の検証指標と合わせて判断することが重要だ。
スイングトレードEAフィルター実装のよくある失敗
フィルターが多すぎてトレード機会を失う
フィルターを4〜5種類積み重ねていくと、全条件を同時に満たす相場状況が極めてまれになる。年間10回しかトレードしないEAが出来上がる、というのは実装初期によくある失敗だ。
取引頻度と精度はトレードオフの関係にある。スイングトレードEAであれば月に4〜8回程度のエントリーが一つの目安だ。それを大きく下回るようであれば、フィルターの数を減らすか、条件を緩和する方向で調整する。「条件を増やせば安全」という直感は、実運用では成り立たないことが多い。
インサンプル期間にだけ最適化されたフィルター
「2020〜2023年のバックテスト」でADX閾値25、ATR vol_ratio下限0.8を最適化したとする。その期間が特定のトレンド環境に偏っていた場合、2024年以降の相場では同じフィルターが機能しないことが多い。
対策は分割検証だ。データを「最適化期間(インサンプル)」と「検証期間(アウトオブサンプル)」に分け、インサンプルで最適化したパラメータをアウトオブサンプルに適用する。アウトオブサンプルの成績がインサンプルの60%以上のPFを維持できていれば、そのフィルター設定には一定の汎化性能があると見なせる。
これを自動化する方法がMT5の「最適化」機能に組み込まれているウォークフォワード分析だ。ストラテジーテスターのパラメーターで期間を分割し、複数のインサンプル・アウトオブサンプルの組み合わせで平均的な成績を算出する。前述のWFEはここで得られる数値から計算する。
よくある質問(FAQ)
Q: スイングトレードEAに最も効果的なフィルターは何ですか? A: 相場環境に依存するため「最も効果的」は一概に言えませんが、検証では「トレンドフィルター(ADX)」と「ATR Percentileフィルター」の組み合わせがバランス良くPF改善に寄与しやすい傾向があります。まずこの2つを個別に検証してから判断することを推奨します。
Q: ADXのパラメータは何が適切ですか? A: 標準は期間14、閾値25が業界的な基準点です(出典:OANDA Lab Education・ThreeTrader Japan)。長期トレンドを対象とするスイングトレードでは期間20〜30も選択肢になりますが、期間を延ばすほど反応が遅くなるため、バックテストで取引頻度とPFのトレードオフを確認してください。
Q: 時間フィルターは指標発表の何分前に設定すべきですか? A: 一般的には30〜60分前からエントリーを停止する設定が多く使われています。指標の重要度(NFP・FOMC・CPIなど)によってスプレッド拡大のタイミングが異なるため、実際のスプレッドデータを確認しながら調整するのが望ましいです。
Q: フィルターを追加すると取引回数が減りますが問題ないですか? A: 適切な範囲での減少であれば問題ありません。月4〜8回程度のエントリー頻度が確保できているか確認してください。取引回数が年間50回を下回ると、バックテスト結果の統計的有意性が著しく低下します。
Q: フィルター実装後のバックテスト期間はどのくらいが適切ですか? A: 最低でも5年、可能であれば10年以上のデータで検証することを推奨します。特に2020年のコロナショック、2022年の急激な利上げ相場など、構造的に異なる複数の相場環境を網羅することで、フィルターの汎化性能をより確かに評価できます(出典:OANDA Lab Education)。
まとめ
フィルター設計で結局のところ大切なのは3軸だ。「トレンドの方向と強度(MA・ADX)」「ボラティリティの水準(ATR Percentile)」「エントリー時間帯(セッション・指標発表)」——この3軸を押さえれば、個々のパラメーター調整は後から詰められる。
MQL5の実装上で一点だけ強調するとすれば、CopyBuffer()では確定足[1]を参照する原則だ。この一行を見落とすと、バックテストと実運用でまるで別物のEAになってしまう。
フィルターの追加は1つずつ段階的に。そのつどPFと取引回数をバックテストで確認するサイクルを回す。ATR Percentileのvol_ratioやADXの閾値はまず初期値で走らせ、WFEが60%以上を維持できるパラメーター範囲を探していく。
最終的にフィルターは2〜3種類に絞るのが実運用では有利に働く傾向がある。4〜5種類積み上げて年間10回しかトレードしないEAより、シンプルな構成で月5〜8回エントリーするEAの方が、長い目で見た資金曲線の安定性は高い。
「何を許可するか」ではなく「何を除外するか」——この逆転した設計思想がスイングトレードEAの品質を決定的に左右する。
Claudeと会話しながらインジケータが作れるhedgrow-fxはこちら
免責事項: 本記事はFXのEA開発・バックテスト手法に関する情報提供を目的としており、特定の投資を推奨するものではありません。外国為替取引にはリスクが伴い、投資元本を失う可能性があります。本記事のMQL5コードおよびEA・フィルターのパラメーター設定はバックテスト結果を保証するものではなく、実際の運用成績はバックテスト結果と大きく異なる場合があります。実運用前には十分なデモトレードおよびバックテスト検証を行い、投資の最終判断はご自身の責任で行ってください。
著者情報: hedgrow-media 編集部(quantペルソナ) 専門領域: FXシステムトレード・MQL5開発・バックテスト分析 最終確認日: 2026年07月
