【MQL5】iADX関数の使い方|ADX・+DI・-DIでトレンドの強さと方向を判定するサンプルコード

【MQL5】iADX関数の使い方|ADX・+DI・-DIでトレンドの強さと方向を判定するサンプルコード MQL5リファレンス

iADX関数は、ADX(平均方向性指数)の値をMQL5プログラムから取得する関数です。ADXは「いま相場にトレンドがあるか・どれくらい強いか」を 0〜100 で表すトレンド系の指標で、方向そのものは示しません。方向は同時に得られる +DI と -DI の2本で判断します。この記事では、iADXの構文と「ハンドル+CopyBufferの2段階」、そしてコピーしてすぐ動く4つのサンプル(3本の取得・トレンドの強さ判定・+DI/-DIクロス+ADXフィルター・順張りの最小EA)を丁寧に解説します。

iADX(ADX・平均方向性指数)とは

ADXは、トレンドの強さだけを 0〜100 で表します。上か下かの方向は教えてくれません。方向は、上昇の勢いを表す +DI と、下降の勢いを表す -DI の2本で読みます。一般に ADXが25以上でトレンドあり・20以下でレンジ(方向感なし)と見ます。さらに +DIが-DIより上なら上昇優勢・下なら下降優勢。MQL5では iADX() でこの3本(ADX・+DI・-DI)をまとめて取得します。

前提:値の取り出しは「2段階」
MQL5のインジケーターは「① OnInit() でハンドルを作る → ② OnTick()CopyBuffer() により値を取り出す」の2段階です(詳しくは iMAの記事 を参照)。ADXは線が3本=バッファが3つ(0=ADX / 1=+DI / 2=-DI)あります。

iADX() の構文と引数

int  iADX(
   string           symbol,       // 通貨ペア(_Symbol で現在のペア)
   ENUM_TIMEFRAMES  period,       // 時間足(PERIOD_CURRENT 等)
   int              adx_period    // 期間(一般的に 14)
);

戻り値はハンドル(整数のID)です。引数は iStochastic などより少なく、期間ひとつだけ。バッファ番号は 0=ADX(メイン・強さ)、1=+DI、2=-DI の3本です。

サンプル①:ADX・+DI・-DI の3本を取得して表示する

ADX(14) の現在値(3本)をチャート左上に表示します。

コピペOK

int adxHandle = INVALID_HANDLE;

int OnInit()
{
   // ① ハンドルを1回だけ作る(期間14)
   adxHandle = iADX(_Symbol, PERIOD_CURRENT, 14);
   if(adxHandle == INVALID_HANDLE)
   {
      Print("iADXハンドルの作成に失敗: ", GetLastError());
      return(INIT_FAILED);
   }
   return(INIT_SUCCEEDED);
}

void OnTick()
{
   double adx[], plusDI[], minusDI[];
   ArraySetAsSeries(adx, true);              // [0]を最新足にそろえる
   ArraySetAsSeries(plusDI, true);
   ArraySetAsSeries(minusDI, true);

   // ② 3本それぞれを、バッファ番号を指定して取り出す
   if(CopyBuffer(adxHandle, 0, 0, 2, adx)     < 2) return;   // 0=ADX
   if(CopyBuffer(adxHandle, 1, 0, 2, plusDI)  < 2) return;   // 1=+DI
   if(CopyBuffer(adxHandle, 2, 0, 2, minusDI) < 2) return;   // 2=-DI

   Comment("ADX = ",  DoubleToString(adx[0], 1),
           "   +DI = ", DoubleToString(plusDI[0], 1),
           "   -DI = ", DoubleToString(minusDI[0], 1));
}

void OnDeinit(const int reason)
{
   IndicatorRelease(adxHandle);              // 後始末
}

サンプル②:トレンドの強さと向きを判定する

確定した足の値で「トレンドあり/レンジ」を判定し、ある場合は+DI・-DIで向きを見ます。形成中の足ではなく確定足で、新しい足ができた時だけチェックします。

コピペOK

input double InpTrend = 25.0;   // これ以上でトレンドあり
input double InpRange = 20.0;   // これ以下でレンジ
datetime lastBar = 0;

void OnTick()
{
   datetime t = iTime(_Symbol, PERIOD_CURRENT, 0);
   if(t == lastBar) return;                  // 新しい足の時だけ
   lastBar = t;

   double adx[], plusDI[], minusDI[];
   ArraySetAsSeries(adx, true);
   ArraySetAsSeries(plusDI, true);
   ArraySetAsSeries(minusDI, true);
   if(CopyBuffer(adxHandle, 0, 0, 2, adx)     < 2) return;
   if(CopyBuffer(adxHandle, 1, 0, 2, plusDI)  < 2) return;
   if(CopyBuffer(adxHandle, 2, 0, 2, minusDI) < 2) return;

   double a = adx[1];                        // 直近の確定足のADX
   if(a >= InpTrend)
   {
      bool up = (plusDI[1] > minusDI[1]);    // +DIが上なら上昇優勢
      Print("トレンドあり(ADX=", DoubleToString(a, 1), "):",
            up ? "上昇優勢" : "下降優勢");
   }
   else if(a <= InpRange)
   {
      Print("レンジ(ADX=", DoubleToString(a, 1), ")");
   }
}

サンプル③:+DIと-DIのクロス+ADXフィルターでシグナル

方向は+DIと-DIのクロスで取り、ADXが一定以上(トレンドが強い)ときだけ有効にします。これで「方向感のないレンジでのダマシ」を減らせます。確定足の [1] と [2] を比較します。

コピペOK

double adx[], plusDI[], minusDI[];
ArraySetAsSeries(adx, true);
ArraySetAsSeries(plusDI, true);
ArraySetAsSeries(minusDI, true);
if(CopyBuffer(adxHandle, 0, 0, 3, adx)     < 3) return;   // ADX [1],[2]
if(CopyBuffer(adxHandle, 1, 0, 3, plusDI)  < 3) return;   // +DI [1],[2]
if(CopyBuffer(adxHandle, 2, 0, 3, minusDI) < 3) return;   // -DI [1],[2]

bool strong = (adx[1] >= 25.0);                                  // トレンドが強い

// +DIが-DIを下から上抜け+トレンド強=買いシグナル
bool buySignal  = (plusDI[2] <= minusDI[2] && plusDI[1] > minusDI[1] && strong);

// -DIが+DIを下から上抜け+トレンド強=売りシグナル
bool sellSignal = (minusDI[2] <= plusDI[2] && minusDI[1] > plusDI[1] && strong);

if(buySignal)  Print("買いシグナル(+DI×-DI上抜け・ADX強)");
if(sellSignal) Print("売りシグナル(-DI×+DI上抜け・ADX強)");

サンプル④:ADX順張りで売買する最小EA

サンプル③の買いシグナルでエントリーし、-DIが+DIを上抜けたら(向きが反転)決済する、動く最小EAです。CTrade を使います。

コピペOK(デモ口座で動作確認用)

#include <Trade\Trade.mqh>
CTrade   trade;
int      adxHandle;
datetime lastBar = 0;
input double InpLot = 0.10;

int OnInit()
{
   adxHandle = iADX(_Symbol, PERIOD_CURRENT, 14);
   if(adxHandle == INVALID_HANDLE) return(INIT_FAILED);
   trade.SetExpertMagicNumber(20260627);
   return(INIT_SUCCEEDED);
}

void OnTick()
{
   datetime t = iTime(_Symbol, PERIOD_CURRENT, 0);
   if(t == lastBar) return;
   lastBar = t;

   double adx[], plusDI[], minusDI[];
   ArraySetAsSeries(adx, true);
   ArraySetAsSeries(plusDI, true);
   ArraySetAsSeries(minusDI, true);
   if(CopyBuffer(adxHandle, 0, 0, 3, adx)     < 3) return;
   if(CopyBuffer(adxHandle, 1, 0, 3, plusDI)  < 3) return;
   if(CopyBuffer(adxHandle, 2, 0, 3, minusDI) < 3) return;

   bool buySignal = (plusDI[2] <= minusDI[2] && plusDI[1] > minusDI[1] && adx[1] >= 25.0);
   bool exitLong  = (minusDI[1] > plusDI[1]);                    // 向きが下に反転したら決済

   if(buySignal && PositionsTotal() == 0)
      trade.Buy(InpLot, _Symbol);

   if(exitLong)
   {
      for(int i = PositionsTotal() - 1; i >= 0; i--)
      {
         ulong ticket = PositionGetTicket(i);
         if(PositionSelectByTicket(ticket) &&
            PositionGetString(POSITION_SYMBOL) == _Symbol)
            trade.PositionClose(ticket);
      }
   }
}

void OnDeinit(const int reason)
{
   IndicatorRelease(adxHandle);
}
これは学習用の最小サンプルです
損切り(SL)・利確(TP)・スプレッド確認・資金管理は入っていません。実運用にはこれらの安全装置が必須です。まずはデモ口座で動きを確認してください。

iADXを使うときの注意・落とし穴

① ADXは「方向」を示さない
ADXが高くても、それが上昇なのか下降なのかは分かりません。強さはADX・方向は+DI/-DIと役割を分けて読みます。「ADXが上がった=買い」は誤りです。
② ADXは遅れて反応する
ADXはトレンドが進んでから上がってくる遅行系です。レンジからトレンドへ変わる初動は取りにくく、ADXが上がりきった頃には終盤、ということもあります。エントリーの号砲ではなく順張りの「やってよい/ダメ」フィルターとして使うのが無難です。
③ お決まりの3点 + バッファ番号
ハンドルは OnInit() で1回だけ/CopyBuffer() の戻り値を必ずチェック/ArraySetAsSeries(配列, true) を忘れない。iADX特有として、0=ADX・1=+DI・2=-DI を取り違えないこと。

まとめ

  • iADX() はADXのハンドルを返す。値は CopyBuffer() で取り出す
  • バッファは 0=ADX(強さ) / 1=+DI / 2=-DI(方向) の3つ
  • 一般に ADX25以上でトレンド・20以下でレンジ確定足で・新バー時のみ判定する
  • 方向は +DIと-DIのクロスで取り、ADXが強いときだけ有効にするとダマシが減る(サンプル③)
  • ADXは遅行する。号砲ではなく順張りのフィルターとして使うのが無難
タイトルとURLをコピーしました