「トレンドが出ているのか、レンジなのか」を判断できたら、EAの精度は格段に上がりますよね。そんなときに頼りになるのがADX(Average Directional Index)というインジケーターです。
MQL4には、ADXの値を簡単に取得できるiADX()関数が用意されています。この記事では、iADX()関数のパラメーターを一つひとつ解説し、実際にEAで使えるサンプルコードまで紹介します。
ADXインジケーターとは?
ADXは、J. Welles Wilder Jr.(ワイルダー)が開発したテクニカル指標で、トレンドの「強さ」を0〜100の数値で表すものです。トレンドの方向(上昇・下降)ではなく、「どれくらい強いトレンドが出ているか」を測定します。
ADXは以下の3本のラインで構成されています。
- ADX(メインライン) — トレンドの強さを示す(値が大きいほどトレンドが強い)
- +DI(プラス方向指標) — 上昇の勢いを示す
- -DI(マイナス方向指標) — 下降の勢いを示す
一般的には、ADXが25以上でトレンドが発生していると判断します。また、+DIが-DIより上にあれば上昇トレンド、-DIが+DIより上にあれば下降トレンドと判断できます。
iADX()関数の書式とパラメーター
MQL4のiADX()関数の書式は以下の通りです。
double iADX(
string symbol, // 通貨ペア名
int timeframe, // 時間足
int period, // 計算期間
int applied_price, // 適用価格
int mode, // 取得するライン
int shift // シフト(何本前の足か)
);
各パラメーターの意味を詳しく見ていきましょう。
symbol(通貨ペア名)
対象の通貨ペアを文字列で指定します。現在のチャートの通貨ペアを使う場合はNULLまたはSymbol()と記述します。
timeframe(時間足)
計算に使う時間足を指定します。現在のチャートの時間足を使う場合は0またはPERIOD_CURRENTを指定します。他にもPERIOD_M1、PERIOD_H1、PERIOD_D1などが使えます。
period(計算期間)
ADXの計算期間です。ワイルダーが推奨した14がデフォルトとしてよく使われます。
applied_price(適用価格)
価格の種類を指定します。ADXでは通常PRICE_CLOSE(終値)を指定します。
mode(取得するライン)
ADXの3本のラインのうち、どれを取得するかを指定します。ここが最も重要なパラメーターです。
| 定数 | 値 | 説明 |
|---|---|---|
| MODE_MAIN | 0 | ADXメインライン(トレンドの強さ) |
| MODE_PLUSDI | 1 | +DI(上昇の勢い) |
| MODE_MINUSDI | 2 | -DI(下降の勢い) |
shift(シフト)
何本前の足のデータを取得するかを指定します。0が現在の足(形成中)、1が1本前の確定済み足です。EAのロジックでは、確定した値を使うために1以上を指定するのが一般的です。
基本的な値の取得方法
まずは、3本のラインの値をそれぞれ取得する基本コードを見てみましょう。
void OnTick()
{
// 1本前の確定足からADXの各ラインを取得(期間14)
double adxValue = iADX(NULL, 0, 14, PRICE_CLOSE, MODE_MAIN, 1);
double plusDI = iADX(NULL, 0, 14, PRICE_CLOSE, MODE_PLUSDI, 1);
double minusDI = iADX(NULL, 0, 14, PRICE_CLOSE, MODE_MINUSDI,1);
// ログに出力して確認
Print("ADX=", DoubleToString(adxValue, 2),
" +DI=", DoubleToString(plusDI, 2),
" -DI=", DoubleToString(minusDI, 2));
}
このコードをEAに貼り付けてストラテジーテスターで実行すると、操作ログにADXの各値が表示されます。まずはここから試してみてください。
実践サンプル①:ADXをトレンドフィルターとして使う
ADXの最もポピュラーな使い方は、トレンドフィルターです。「ADXが一定値以上のときだけエントリーする」というルールを加えるだけで、レンジ相場での無駄なエントリーを減らせます。
// --- 入力パラメーター ---
input int ADX_Period = 14; // ADX期間
input double ADX_Threshold = 25.0; // トレンド判定のしきい値
void OnTick()
{
double adxValue = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MAIN, 1);
double plusDI = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_PLUSDI, 1);
double minusDI = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MINUSDI, 1);
// トレンドが弱い場合は何もしない
if(adxValue < ADX_Threshold)
{
// レンジ相場と判断 → エントリーしない
return;
}
// +DI > -DI なら上昇トレンド
if(plusDI > minusDI)
{
// ここに買いエントリーのロジックを記述
Print("上昇トレンド検出! ADX=", DoubleToString(adxValue, 2));
}
// -DI > +DI なら下降トレンド
else if(minusDI > plusDI)
{
// ここに売りエントリーのロジックを記述
Print("下降トレンド検出! ADX=", DoubleToString(adxValue, 2));
}
}
この仕組みを他の売買ロジック(移動平均線のクロスなど)と組み合わせることで、エントリー精度を高められます。
実践サンプル②:+DI/-DIクロスで売買するEA
ここでは、+DIと-DIのクロスをシグナルとして実際にエントリーを行うEAの完全なコードを紹介します。
売買ルール
- 買い条件:+DIが-DIを上抜け(ゴールデンクロス)+ ADXがしきい値以上
- 売り条件:-DIが+DIを上抜け(デッドクロス)+ ADXがしきい値以上
- 既に同方向のポジションがある場合はエントリーしない
//+------------------------------------------------------------------+
//| ADX Cross EA |
//+------------------------------------------------------------------+
#property strict
// --- 入力パラメーター ---
input int ADX_Period = 14; // ADX期間
input double ADX_Threshold = 25.0; // ADXしきい値
input double LotSize = 0.1; // ロットサイズ
input int StopLossPips = 50; // ストップロス(pips)
input int TakeProfitPips= 100; // テイクプロフィット(pips)
input int MagicNumber = 12345; // マジックナンバー
//+------------------------------------------------------------------+
//| pip補正値を取得する関数 |
//+------------------------------------------------------------------+
double PipPoint()
{
if(Digits == 3 || Digits == 5)
return Point * 10;
else
return Point;
}
//+------------------------------------------------------------------+
//| 指定方向のポジション数を数える関数 |
//+------------------------------------------------------------------+
int CountOrders(int orderType)
{
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if(OrderType() == orderType)
count++;
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| OnTick - メイン処理 |
//+------------------------------------------------------------------+
void OnTick()
{
// --- 1本前(確定足)の値 ---
double adx_1 = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MAIN, 1);
double plusDI_1 = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_PLUSDI, 1);
double minusDI_1 = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MINUSDI, 1);
// --- 2本前の値(クロス判定に使用) ---
double plusDI_2 = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_PLUSDI, 2);
double minusDI_2 = iADX(NULL, 0, ADX_Period, PRICE_CLOSE, MODE_MINUSDI, 2);
double pip = PipPoint();
// --- 買いシグナル判定 ---
// 2本前は +DI <= -DI だったのに、1本前で +DI > -DI になった(ゴールデンクロス)
bool buySignal = (plusDI_2 <= minusDI_2) && (plusDI_1 > minusDI_1) && (adx_1 >= ADX_Threshold);
// --- 売りシグナル判定 ---
// 2本前は -DI <= +DI だったのに、1本前で -DI > +DI になった(デッドクロス)
bool sellSignal = (minusDI_2 <= plusDI_2) && (minusDI_1 > plusDI_1) && (adx_1 >= ADX_Threshold);
// --- 買いエントリー ---
if(buySignal && CountOrders(OP_BUY) == 0)
{
double sl = Ask - StopLossPips * pip;
double tp = Ask + TakeProfitPips * pip;
int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, sl, tp,
"ADX Cross Buy", MagicNumber, 0, clrBlue);
if(ticket > 0)
Print("買いエントリー成功 ADX=", DoubleToString(adx_1, 2),
" +DI=", DoubleToString(plusDI_1, 2),
" -DI=", DoubleToString(minusDI_1, 2));
else
Print("買いエントリー失敗 Error=", GetLastError());
}
// --- 売りエントリー ---
if(sellSignal && CountOrders(OP_SELL) == 0)
{
double sl = Bid + StopLossPips * pip;
double tp = Bid - TakeProfitPips * pip;
int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, 3, sl, tp,
"ADX Cross Sell", MagicNumber, 0, clrRed);
if(ticket > 0)
Print("売りエントリー成功 ADX=", DoubleToString(adx_1, 2),
" +DI=", DoubleToString(plusDI_1, 2),
" -DI=", DoubleToString(minusDI_1, 2));
else
Print("売りエントリー失敗 Error=", GetLastError());
}
}
コードのポイント解説
クロス判定の仕組み:2本前の足と1本前の足で+DIと-DIの大小関係が逆転したかどうかで判定しています。例えば、2本前は「+DI ≤ -DI」だったのに1本前で「+DI > -DI」になっていれば、+DIが-DIを上抜けた(ゴールデンクロス)と判断します。
pip補正(PipPoint関数):3桁・5桁の通貨ペア(例:ドル円が110.123のように小数点3桁)では、Pointが0.001になります。pipsとして扱うにはPoint×10が必要なので、Digitsに応じて補正しています。
重複エントリー防止:CountOrders()関数で同方向のポジションが既にあるかチェックし、重複エントリーを防いでいます。マジックナンバーで他のEAのポジションと区別している点も実用的なテクニックです。
iADX()を使うときの注意点
1. 確定足の値を使おう
shift=0で取得する値は、現在形成中の足の値なので、ティックごとに変動します。売買判定にはshift=1以上(確定済みの足)の値を使うのが安定したロジックのコツです。
2. ADXは「方向」を示さない
ADXのメインラインはあくまで「トレンドの強さ」だけを示します。上昇・下降の方向は+DIと-DIの位置関係で判断する必要があります。ADXが高い=上昇トレンドではない点に注意してください。
3. MQL5との違い
MQL4のiADX()は直接double値を返しますが、MQL5ではiADX()が「ハンドル」(整数値)を返し、実際の値はCopyBuffer()で配列にコピーして取得する仕組みに変わっています。MQL5に移行する際はコードの書き換えが必要になるので覚えておきましょう。
他のインジケーターとの組み合わせ
ADXは単体でも有用ですが、他のインジケーターと組み合わせるとさらに効果的です。
移動平均線(MA)+ ADX
MAのゴールデンクロス・デッドクロスをエントリーシグナルとし、ADXが25以上のときだけエントリーするフィルターとして使います。レンジ相場でのダマシを大幅に減らせます。
RSI + ADX
RSIの買われすぎ・売られすぎをシグナルとしつつ、ADXが低い(レンジ相場)ときだけ逆張りエントリーする手法です。ADXが高いとき(トレンド発生時)にはRSIの逆張りを控えることで、トレンドに逆らうリスクを回避できます。
マルチタイムフレーム分析
iADX()のtimeframe引数を変えれば、異なる時間足のADX値を取得できます。例えば、日足のADXでトレンドを確認し、1時間足で具体的なエントリータイミングを計る、といった使い方が可能です。
// 日足のADX値を取得
double adx_daily = iADX(NULL, PERIOD_D1, 14, PRICE_CLOSE, MODE_MAIN, 1);
// 1時間足の+DI/-DIを取得
double plusDI_H1 = iADX(NULL, PERIOD_H1, 14, PRICE_CLOSE, MODE_PLUSDI, 1);
double minusDI_H1 = iADX(NULL, PERIOD_H1, 14, PRICE_CLOSE, MODE_MINUSDI, 1);
// 日足でトレンドが出ていて、1時間足で+DI優勢なら買い
if(adx_daily >= 25 && plusDI_H1 > minusDI_H1)
{
Print("マルチタイムフレーム分析:買い条件成立");
}
まとめ
この記事では、MQL4のiADX()関数の使い方を基礎から実践まで解説しました。ポイントを振り返りましょう。
- ADXはトレンドの「強さ」を0〜100で数値化するインジケーター
- iADX()関数のmode引数で、ADX本体・+DI・-DIの3つのラインを切り替えて取得する
- ADXが25以上でトレンド発生、+DIと-DIの位置関係でトレンドの方向を判定
- 売買判定には確定足(shift=1以上)の値を使うのが基本
- 他のインジケーターのトレンドフィルターとして組み合わせると効果的
ADXはシンプルながら非常に強力なインジケーターです。まずは基本の値取得から試して、自分のEAにトレンドフィルターとして組み込んでみてください。レンジ相場での無駄なエントリーが減り、トレード成績の改善が期待できるはずです!

