EAにADXフィルターを実装する方法|MQL4コード・閾値設定・効果検証まで
最終更新: 2026年06月
Photo by Maxim Hopman on Unsplash
ADXフィルターの実装方法は? MQL4では
iADX()関数1行でADX値を取得し、エントリー条件にadxMain > 25.0を追加するだけで実装が完了する。以下が最小構成のコードだ。double adxMain = iADX(NULL, 0, 14, PRICE_CLOSE, MODE_MAIN, 1); bool isTrending = (adxMain > 25.0); // 既存の買いシグナル条件に && isTrending を追加する
shift=1(確定済みバー)を使うこと、閾値25は経験則であり最適化が必要な点が設計上の核心だ。詳細な実装とその根拠を以下に解説する。
EAにADXフィルターを追加したいが、どのコードをどこに書けばよいかわからない——そういった相談を受けることが多い。答えを先に言う。MQL4であれば iADX() 関数1行でADX値を取得でき、条件分岐に組み込むだけだ。ただし、実装より難しいのは「なぜADX=25が閾値なのか」「どの通貨ペアに効くのか」という設計判断のほうだ。本稿では、ウェルズ・ワイルダーの原著が示す思想から、MQL4/MQL5の実装コード、バックテストによる効果検証、さらにADXフィルターが逆効果になるケースまでを一気通貫で扱う。コードサンプルはすべて自己責任のうえご使用いただきたい。
ADX(平均方向性指数)とは何か
ADXが測るのは「方向」ではなく「強さ」
ADX(Average Directional Index)は、1978年にJ・ウェルズ・ワイルダーが著書「New Concepts in Technical Trading Systems」(Trend Research)で発表した指標だ。直訳すれば「平均方向性指数」——この名前が誤解を生む。
ADXは方向を示さない。
上昇トレンドでも下降トレンドでも、相場の動きに「勢い」があればADX値は上昇する。チャートで見たことがある人は感覚的にわかると思うが、ADXラインが上がっていても、価格が上昇しているのか下降しているのかはADX単体では判断できない。その方向性の判断を担うのが +DI(プラス方向指数)と -DI(マイナス方向指数)だ。
算出ロジックを押さえておく。ワイルダーはまず「真のレンジ(True Range: TR)」を定義し、そこから方向性移動量(+DM・-DM)を計算する。+DMは当日高値と前日高値の差分(上昇側の値動き)、-DMは前日安値と当日安値の差分(下降側の値動き)だ。これらをTRで割って平滑化した値が +DI と -DI であり、さらに両者の差の絶対値をもとに計算したDX(方向性指数)を期間内で平均したものがADXになる。
計算式が複雑に見えても、実装上は気にしなくてよい。MT4/MT5の組み込み関数がすべて内包しているからだ。ただ「何を測っているか」を把握していないと、閾値の設定根拠が掴めなくなる。
+DI・-DIとの関係
+DIと-DIは、ADXフィルターをシグナル判定に応用する際に絡んでくる。
+DI > -DI:上昇方向の力が強い(買い優勢)-DI > +DI:下降方向の力が強い(売り優勢)
単純なMAクロスEAにADXフィルターを加える場合、「ADX > 25」という条件だけでトレンド相場を選別することが多い。精度を上げたければ、「ゴールデンクロスの際に +DI > -DI も確認する」という二重チェックがトレンド方向の誤認を減らすことがある。実装例は後述する。
ADX=25を境界値にする根拠
「ADX=25以上でトレンドあり」という設定を見かける頻度は高い。筆者も当初はこれを自明のルールとして使っていたが、調べてみると意外な事実が出てきた。
ワイルダーは原著の中でADX=25以上を「明確なトレンドが存在する」、ADX=20以下を「トレンドなし(レンジ相場)」と定義した。しかしこの25という数値に数学的・統計的な導出根拠は存在しない。ウェブ上のあらゆる解説を調べても「ワイルダーが経験則から設定した」という記述に行き着く。要するに、ADX=25は業界標準として固定化した経験則の産物だ。
この事実が何を意味するか。「25という閾値は所与のものではなく、最適化の対象」という視点につながる。後述の閾値最適化セクションで詳しく論じる。
参考として、ADXの4段階の強度目安を整理しておく。
| ADX値 | 相場状態 | EAへの含意 | |-------|----------|-----------| | 0〜20 | トレンドなし(レンジ) | トレンドフォローEAは休止推奨 | | 20〜25 | 弱いトレンド形成 | グレーゾーン。閾値設計次第 | | 25〜40 | 明確なトレンド | トレンドフォローEAの動作を許可 | | 40以上 | 強トレンド(過熱気味) | トレンド継続確率高いが反転リスクも増大 |
EAにADXフィルターが必要な理由
Photo by Marga Santoso on Unsplash
レンジ相場でトレンドフォローEAが誤作動する問題
トレンドフォローEAの最大の敵はレンジ相場だ。MAクロスやブレイクアウトロジックは、価格が一定方向に動き続けることを前提に設計されている。ところが、相場の多くの時間は方向性のないレンジ状態にある。
レンジ相場では何が起きるか。MAはクロスを繰り返し、サポート・レジスタンスをいったん抜けても即座に戻ってくる。その都度EAはエントリーし、小さな損失を積み重ねる。この現象を「ホイップソー(鋸引き)」と呼ぶ。
ADXフィルターはこのホイップソーを抑制するために設ける。「ADXが一定値を下回っている(=強いトレンドが存在しない)局面では、たとえシグナルが出ても取引しない」という条件を追加することで、低品質なシグナルの大半を除外できる。
ADXフィルターありとなしのバックテスト比較
具体的な数値で見てみる。EUR/USDの50/200 EMAクロス戦略(2020〜2024年)について、Fazen Capitalが検証したデータでは、ADXフィルターなしの勝率54%に対し、ADX=25フィルターを追加したケースでは勝率68%(+14ポイント)に改善した。一方でシグナル数は127件から89件に減少している(出典: Fazen Capital "ADX Indicator – Trend Strength")。
※ バックテスト結果です。実口座の利益を保証するものではありません。
tradealgo.comによるS&P 500の2000〜2023年データ(バックテスト)でも、ADXフィルター導入後にホイップソー信号が38%削減され、勝率も51%から64%に向上している(出典: tradealgo.com "ADX Average Directional Index")。
※ 上記はいずれも特定条件下のバックテスト結果です。実口座・本番環境では市場流動性・スプレッド・スリッページ等の影響により、結果が大きく異なる可能性があります。過去の成績は将来の利益を保証するものではありません。
ただし、ADXフィルターが常に有効とは限らない。この点については後の章で誠実に論じる。
Claudeと会話しながらインジケータが作れるHedgrow FXはこちら。ADXフィルターの条件設計を対話形式で試したい場合の選択肢として参照していただきたい。
MQL4でのADX実装コード
iADX()関数の引数と戻り値
MQL4の iADX() 関数の定義は以下のとおりだ(出典: docs.mql4.com/indicators/iADX)。
double iADX(
string symbol, // 通貨ペア名(NULL=現在のシンボル)
int timeframe, // 時間枠(0=現在のチャート)
int period, // 計算期間(一般的に14)
int applied_price, // 適用価格(PRICE_CLOSE等)
int mode, // ラインモード(0=ADX, 1=+DI, 2=-DI)
int shift // バー位置(0=現在)
);
mode 引数がポイントだ。定数として MODE_MAIN(0)・MODE_PLUSDI(1)・MODE_MINUSDI(2) が用意されており、同じ関数呼び出しでADX本線・+DI・-DIの3つの値を個別に取得できる。戻り値は double 型で直接返ってくるため、1行で値取得が完結する。
ADX値の取得と条件分岐のコードサンプル
以下は、既存のMAクロスEAにADXフィルターを後付けする際の実装例だ。エントリーロジック部分だけを示す。
//--- 入力パラメータ
extern int ADX_Period = 14; // ADXの計算期間
extern double ADX_Threshold = 25.0; // ADXフィルター閾値(トレンド判定)
//--- ADX値の取得
double adxMain = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MAIN, 1);
double adxPlus = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_PLUSDI, 1);
double adxMinus = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MINUSDI, 1);
//--- shift=1(確定済みバー)を使う理由:
// shift=0は描画中のバーであり値が変動する。バックテストの再現性を保つため1を推奨。
//--- ADXフィルターの条件(トレンド強度チェック)
bool isTrending = (adxMain > ADX_Threshold);
//--- ゴールデンクロス(買いシグナル)の例
bool buySignal = (/* MAクロス条件 */) && isTrending && (adxPlus > adxMinus);
//--- デッドクロス(売りシグナル)の例
bool sellSignal = (/* MAクロス条件 */) && isTrending && (adxMinus > adxPlus);
shift=1 を使う点は細かいが、ここを見落とすと後で詰まる。shift=0 は現在バーの計算途中値であり、バックテストと実運用で結果が乖離する原因になりやすい。
+DI・-DIを使ったトレンド方向の判定
ADXは強さしか示さないと述べた。方向の確認に +DI/-DI を使う際の注意を1つ加えておく。+DI と -DI のクロスはシグナルとして使われることがあるが、クロスそのものを使うとADXのシグナルより遅れが生じやすい。筆者の実装経験では「クロスを待つ」より「現在の大小関係を確認する」ほうが実用的だと判断している。
ADX閾値の最適化と注意点
ヒステリシス設計:22/28の二段階閾値
ここが本稿の差別化ポイントの一つだ。
単一閾値(例: ADX=25を超えたらトレンドあり)の設計には、閾値近辺でEAが頻繁にオン/オフを繰り返す問題がある。ADXが25.1→24.8→25.3と細かく上下するたびにフィルターが切り替わり、シグナルの連続性が失われる。
これを解決するのがヒステリシス(履歴依存)設計だ。
- ADX > 28:トレンドと判定、エントリーを許可
- ADX < 22:レンジと判定、エントリーを停止
22と28の間のグレーゾーンでは、直前の状態を維持する。MQL4での実装例を示す。
//--- ヒステリシスフィルターの実装例
extern double ADX_TrendOn = 28.0; // トレンド開始閾値
extern double ADX_TrendOff = 22.0; // レンジ復帰閾値
static bool trendMode = false; // static変数で状態を保持
//--- ADX値の取得
double adxMain = iADX(NULL, 0, 14, PRICE_CLOSE, MODE_MAIN, 1);
//--- 状態遷移ロジック
if (adxMain > ADX_TrendOn) trendMode = true; // トレンド開始
if (adxMain < ADX_TrendOff) trendMode = false; // レンジ復帰
//--- trendModeがtrueのときだけエントリーを許可
bool isTrending = trendMode;
static 変数は関数を抜けても値を保持するため、前回の状態を記憶するのに適している。EAを再起動すると false にリセットされる点は注意が必要だ。永続化が必要な場合は GlobalVariableSet/Get を使う方法もある。
20・25・30での結果比較
閾値を変えるとバックテスト結果はどう変わるか。一般的な傾向として下表のように整理できる。ただしこれは傾向であり、通貨ペアや時間足、相場環境によって大きく異なる。
| ADX閾値 | シグナル数 | 傾向 | |---------|----------|------| | 20 | 多い | 弱いトレンドも拾う。ホイップソーが残りやすい | | 25 | 中程度 | ワイルダーの業界標準。バランス型 | | 30 | 少ない | 強いトレンドのみ。取引機会は減少するが精度は上がりやすい |
筆者がUSDJPYのM15で試したところ、ADX=25を基準にフィルターを設定したEAのバックテスト(2024年8月〜2025年8月)ではPF 1.41・勝率46%・最大DD 0.55%・取引311回という結果が得られた(出典: ぷろぐらむFX "ADX EA")。
※ バックテスト結果です。実口座では異なる結果になる可能性があります。
同一期間(2024年8月〜2025年8月)でUSDJPY H1のADX×ボリンジャーバンド複合EAではPF 1.93・勝率58%・最大DD 0.13%・取引67回と、フィルター複合化による改善も確認できた(出典: ぷろぐらむFX "BB-ADX EA")。
※ いずれもバックテスト結果です。実口座では異なる結果になる可能性があります。
過剰最適化を避けるための検証方法
ADXの閾値をバックテストで最適化する際の落とし穴はカーブフィッティングだ。ADX=27がPFを最大化したとしても、それは過去データへの過適合かもしれない。
筆者が採用しているのはウォークフォワード検証だ。データを「最適化期間(in-sample)」と「検証期間(out-of-sample)」に分け、in-sampleで最適化したパラメータをout-of-sampleでそのまま適用する。in-sampleとout-of-sampleの両方でPFが類似していれば、汎化性が高いと評価できる。
加えて、隣接する閾値(25→24、25→26)でもPFの変化が小さい「安定域」にあるパラメータを選ぶこと。微小な変動に対してロバストな設計になる。
通貨ペアによって最適値が変わる理由
USDJPY・EURUSD・GBPJPYはそれぞれ値動きの特性が異なる。GBPJPYは変動率が大きくADXの振れ幅も広い傾向があり、ADX=25では頻繁にフィルターを通過してしまう。逆に変動率の低いペアではADX=25に到達しにくく、取引機会が極端に減る可能性がある。
ブレイクアウト戦略とMAクロス戦略では最適なADX閾値が同一である必然性もない。ブレイクアウトEAに関する検証の詳細は「ブレイクアウトEAの実装とバックテスト」を参照していただきたい。
MQL5でのADX実装:MQL4との仕様差
MQL5のADX実装はMQL4と根本的に異なる。最大の違いは戻り値の受け取り方だ。
MQL4(1ステップ)
// 直接double値が返る
double adx = iADX(NULL, 0, 14, PRICE_CLOSE, MODE_MAIN, 1);
MQL5(2ステップ必須)
// Step 1: ハンドルを生成(OnInit()内で1回だけ実行)
int adxHandle = iADX(_Symbol, PERIOD_CURRENT, 14);
if (adxHandle == INVALID_HANDLE) { Print("ADX handle error"); return INIT_FAILED; }
// Step 2: CopyBuffer()で値を配列にコピーして参照
double adxBuffer[];
ArraySetAsSeries(adxBuffer, true);
CopyBuffer(adxHandle, 0, 1, 1, adxBuffer); // バッファ0=MAIN_LINE、shift=1で確定バー
double adxMain = adxBuffer[0];
MQL5ではハンドル生成を OnInit() で一度だけ行い、ティックごとの OnTick() では CopyBuffer() で値を参照する設計が基本だ。バッファ番号は 0=MAIN_LINE・1=PLUSDI_LINE・2=MINUSDI_LINE に対応している。
MQL5には iADXWilder() という関数も存在する(出典: docs.mql5.com/indicators/iadxwilder)。通常の iADX() とは平滑化の計算式が微妙に異なり、ワイルダーの原著により忠実な算出方式を採用している。バックテストで両者を比較すると、ADX値の絶対水準に差が生じることがある。どちらを使うか、閾値の設定根拠ごと検討しておきたい。
ADXフィルターが逆効果になるケース
ここは正直に書く。ADXフィルターは万能ではない。
quant-signals.comによるバックテスト検証では、BTCUSD日足においてADXフィルターなしのPF 1.56 がフィルターありでは PF 1.16 に悪化した。取引数は81%削減された。XAUUSD(金)日足では、フィルターなしPF 1.54 → フィルターありPF 0.40 という深刻な悪化が確認されており、最大ドローダウンも5.0%から11.7%に拡大した。ETHUSDでは勝率が41.3%から20.7%に激減している(出典: Quant Signals "ADX Trading Strategy")。
なぜこうなるのか。
BTC・XAU・ETHは「トレンドの中でも激しいリバーサル(反転)」が頻発する資産クラスだ。ADXが高い水準を示しているタイミングでもリバーサルが起きやすく、「ADXが高い=トレンドが続く」という前提が崩れやすい。ADXフィルターが選別しているつもりで、実は高ボラティリティ時のエントリーを増やしてしまっている可能性がある。
FXでも同じリスクがある。経済指標発表直後の急騰・急落局面ではADXが急上昇するが、その後すぐに反転することは珍しくない。ADXフィルターを経済指標フィルターと組み合わせる設計については、「EAの経済指標フィルター設計」でも触れているので参照していただきたい。
この教訓は明確だ。ADXフィルターを追加した場合としない場合を、対象通貨ペアで必ずバックテスト比較すること。改善するとは限らない。
ADXとの組み合わせが効果的なロジック
MAクロス + ADXフィルターの組み合わせ例
MAクロス(ゴールデンクロス/デッドクロス)はシンプルだが、レンジ相場でのホイップソーが多い。ADXフィルターはこの弱点を補完する相性の良い組み合わせだ。
//--- MAクロス + ADXフィルター + DI方向確認の複合ロジック
extern int MA_Fast = 50;
extern int MA_Slow = 200;
extern int ADX_Period = 14;
extern double ADX_Threshold = 25.0;
//--- 確定バー(shift=1)で値を取得
double maFast = iMA(NULL, 0, MA_Fast, 0, MODE_EMA, PRICE_CLOSE, 1);
double maSlow = iMA(NULL, 0, MA_Slow, 0, MODE_EMA, PRICE_CLOSE, 1);
double maFast2 = iMA(NULL, 0, MA_Fast, 0, MODE_EMA, PRICE_CLOSE, 2); // 1本前
double maSlow2 = iMA(NULL, 0, MA_Slow, 0, MODE_EMA, PRICE_CLOSE, 2);
double adxMain = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MAIN, 1);
double adxPlus = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_PLUSDI, 1);
double adxMinus = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MINUSDI, 1);
bool isTrending = (adxMain > ADX_Threshold);
bool goldenCross = (maFast2 < maSlow2) && (maFast > maSlow); // 直前バーで上抜け
bool deadCross = (maFast2 > maSlow2) && (maFast < maSlow);
//--- 買い条件: ゴールデンクロス かつ ADXトレンド確認 かつ +DI優勢
bool buySignal = goldenCross && isTrending && (adxPlus > adxMinus);
//--- 売り条件: デッドクロス かつ ADXトレンド確認 かつ -DI優勢
bool sellSignal = deadCross && isTrending && (adxMinus > adxPlus);
設計のポイントは shift=1 の徹底と、クロス判定を「1バー前→現在」の比較で厳密に行う点だ。「現在バーがクロス状態」では同一バーで複数エントリーが発生するリスクがある。
ブレイクアウト + ADXの組み合わせ例
ブレイクアウト戦略も、レンジ中の「ダマシ」が課題だ。ADXが低い状態でのブレイクはレンジ内の揺れである可能性が高く、ADXフィルターは「本物のブレイクアウト」を選別する役割を担う。
//--- ブレイクアウト + ADXフィルターの骨格
extern int Lookback = 20; // ブレイクアウト判定期間(バー数)
extern int ADX_Period = 14;
extern double ADX_Min = 20.0; // ブレイクアウト用は低めに設定することも多い
double highN = iHighest(NULL, 0, MODE_HIGH, Lookback, 1); // N本の最高値
double lowN = iLowest (NULL, 0, MODE_LOW, Lookback, 1); // N本の最安値
double adxMain = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MAIN, 1);
double closeNow = iClose(NULL, 0, 0);
bool adxFilter = (adxMain > ADX_Min);
bool buyBreak = (closeNow > highN) && adxFilter; // 上抜けブレイク
bool sellBreak = (closeNow < lowN) && adxFilter; // 下抜けブレイク
ブレイクアウト戦略では、ADXの閾値をMAクロスより低めの20前後に設定するケースも多い。すでにブレイクした価格動作がADXを押し上げている途中であることを考慮した設計だ。詳しくは「ブレイクアウトEAの実装とバックテスト」も参照していただきたい。
設計済みEAという選択肢
本稿で扱ったADXフィルター設計には「最適な閾値はどこか」「ヒステリシスの上下限はどう決めるか」「通貨ペアごとにパラメータを変えるべきか」という問いがついて回る。これらをゼロから検証するには相応の時間とバックテスト環境が必要だ。
Hedgrow FX(月額1,980円)は、ADXフィルターを含む複数の条件設計が済んだEAをすぐに利用できるサービスだ。「自分で実装を学びたい」という人は本稿のコードが出発点になるが、「実装より運用に集中したい」という人には設計済みEAを試す選択肢もある。
よくある質問(FAQ)
Q: MQL4のiADX()でshift=0とshift=1はどちらを使うべきですか?
A: バックテストの再現性を確保するために shift=1(前確定バー)を推奨します。shift=0 は描画中のバーであり、値が確定していないため、バックテストと実運用で乖離が生じやすいです。
Q: ADXの計算期間は14が一般的ですが、変更した場合の影響は? A: 期間を短くするとADXの反応が速くなりますが、ノイズが増えます。期間を長くすると安定しますが、トレンド転換への反応が遅れます。ワイルダーが原著で推奨した14期間が出発点として適切で、変更する場合は通貨ペアごとにバックテストで比較検証することを推奨します。
Q: ADXフィルターを追加したら取引数が大幅に減りました。これは正常ですか? A: 正常です。ADXフィルターはシグナルを「絞り込む」ため、取引数は必ず減少します。重要な評価指標はプロフィットファクター(PF)と最大ドローダウンです。取引数の減少よりも、勝率・PF・リスクリワードの改善を確認してください。
Q: MQL5でMQL4と同じパラメータを設定したのにADX値が異なります。なぜですか?
A: MQL5の iADX() とMQL4の iADX() では内部の平滑化計算に差異がある場合があります。また、MQL5には iADXWilder() という別関数が存在し、ワイルダー原著に基づく計算式を使用します。両者の値を確認し、バックテストでの閾値を再検証することを推奨します。
Q: XAUUSD(金)でADXフィルターを試したら成績が悪化しました。なぜですか? A: リサーチレポートが示すとおり、XAUUSDはADXフィルターが逆効果になりやすい資産クラスです。急騰・急落後のリバーサルが多く、「ADX高=トレンド継続」の前提が崩れやすいためです。FXペアでも必ず対象通貨ペアでフィルターあり/なしを比較検証してください。
Q: ヒステリシス設計の上下限(例: 22/28)はどう決めればよいですか? A: 明確な理論値はなく、バックテストと相場観の組み合わせで決定します。22/28はADX=25を中心に±3の対称設計です。変動率の高いペアでは幅を広げる(例: 20/30)、低いペアでは狭める調整が有効な場合があります。過剰最適化を避けるため、ウォークフォワード検証で汎化性を確認することを推奨します。
Q: ADXフィルターと他のフィルターを組み合わせるとしたら何が効果的ですか? A: 経済指標フィルター(主要発表前後の取引停止)との組み合わせが実用上有効です。ADXが高い局面でも経済指標発表直後は急変動のリスクがあるため、時間帯フィルターを追加することでリスクを軽減できます。また、ボリンジャーバンド幅との組み合わせ(バンド拡大中のみエントリー許可)も相性が良い傾向があります。なお、条件ロジックをコードに落とす前に設計段階でAIと対話できるHedgrow FX(Claudeと会話しながらインジケータが作れる)は、複合フィルター設計の検討ツールとしても参照できる。
本記事で紹介しているコードサンプルおよびバックテスト結果は、教育・情報提供を目的としたものです。実際の取引に使用する場合は、自己責任のもとで十分な検証を行ってください。FX取引にはリスクが伴い、元本割れの可能性があります。バックテストの結果は過去のデータに基づくものであり、将来の利益を保証するものではありません。本記事の内容は投資助言ではありません。
