【MQL4】iADX関数の使い方を徹底解説!ADXでトレンドの強さを判定するサンプルプログラム付き

【中級編】MQLプログラムの読み方・書き方

「トレンドが出ているのか、レンジなのか」を判断できたら、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_M1PERIOD_H1PERIOD_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にトレンドフィルターとして組み込んでみてください。レンジ相場での無駄なエントリーが減り、トレード成績の改善が期待できるはずです!