MT4で便利にFXのトレンド判定ができるADXとDMIのコーディング

ADX

MT4で順張りでトレンドに載るEAを作成していますが、その際にDMIとADXを重要インジケータとして使用しています。

他にもトレンド判定できるインジケータはいろいろありますが、DMIとADXはその中でも有名で、「トレンドの強さの度合」を判定しやすいため、使いやすいかと思います。

DMIとADX

さて、DMIとADXの使い方はこちらのサイトが詳しいです。

MQLで、iADX()関数は下記の値を取得できます。

  • ADX(Average Directional Movement Index)
  • +DI(Plus Directional Indicator)
  • -DI(Minus Directional Indicator)

+DIは上昇する力、-DIは下降する力のイメージですね。

ADXは、トレンドの強さを表します。上昇であろうが下降であろうが、トレンドが強ければ数値が大きくなります。

+DIと-DIのゴールデンクロスで買い、デッドクロスで売りという判断もあるようですが、レンジ相場ではこの2つは頻繁に交差します。ですのでフィルタとしてある程度ADXが大きくないと売買しない、というようにすればよいかと思います。

double iADX(
  string symbol, //通貨ペア
  int timeframe, //PERIOD_CURRENTとかPERIOD_M1など
  int period, //ADXの値を計算する期間、通常は14?
  int applied_price, //PRICE_CLOSE、PRICE_MEDIANなど
  int mode, //どの値を取得するか?ADX:0、+DI:1、-DI:2
  int shift //取得したいバーの位置
);

//例:ADXの傾き
iADX(Symbol(),0,14,PRICE_CLOSE,0,0)-iADX(Symbol(),0,14,PRICE_CLOSE,0,1)

//具体例 ゴールデンクロス、かつADXが25以上で買い
//http://mt4-traders.com/reference/iadx/ より
double Plus_DI_1  = iADX(NULL,0,14,0,1,1);
double Plus_DI_2  = iADX(NULL,0,14,0,1,2);
double Minus_DI_1 = iADX(NULL,0,14,0,2,1);
double Minus_DI_2 = iADX(NULL,0,14,0,2,2);
double ADX_1      = iADX(NULL,0,14,0,0,1);

if(Plus_DI_2 <= Minus_DI_2 && Plus_DI_1 > Minus_DI_1 && ADX_1 >= 25){
   int Ticket = OrderSend(Symbol(),OP_BUY,0.1,Ask,10,0,0,NULL,1359,0,Magenta);
}

参考プログラム1

参考までに、デッドクロス・ゴールデンクロスかつADXが30以上でオープン

ADXが30以下になったら決済を行うプログラムを書いてみました。

※当然、ADXとDMIだけで勝負できるわけもなく、バックテスト結果は惨憺たるものです。

//+------------------------------------------------------------------+
//|                                                      ADXTest.mq4 |
//|                                                                  |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright ""
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
  }
void OnTick()
  {
   static int magic=12345678;
   double pDI0 = iADX(Symbol(),PERIOD_CURRENT,14,PRICE_CLOSE,1,0);
   double pDI1 = iADX(Symbol(),PERIOD_CURRENT,14,PRICE_CLOSE,1,1);
   double mDI0 = iADX(Symbol(),PERIOD_CURRENT,14,PRICE_CLOSE,2,0);
   double mDI1 = iADX(Symbol(),PERIOD_CURRENT,14,PRICE_CLOSE,2,1);
   double ADX0 = iADX(Symbol(),PERIOD_CURRENT,14,PRICE_CLOSE,0,0);

   if(pDI1<mDI1 && pDI0>mDI0 && ADX0>30 && CalculateCurrentOrders(magic,true)==0)
     {
      OrderSend(Symbol(),OP_BUY,0.01,Ask,3,0,0,"ADX_Test",magic);
     } else if(pDI1>mDI1 && pDI0<mDI0 && ADX0>30 && CalculateCurrentOrders(magic,false)==0){
      OrderSend(Symbol(),OP_SELL,0.01,Bid,3,0,0,"ADX_Test",magic);
     }
   for(int i=0; i<OrdersTotal(); i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)
        {
         Alert("Error!");
         break;
        }
      if(OrderMagicNumber()==magic)
        {
         if(ADX0<30)
           {
            RefreshRates();
            if(OrderType()==OP_BUY) OrderClose(OrderTicket(),OrderLots(),Bid,3);
            if(OrderType()==OP_SELL) OrderClose(OrderTicket(),OrderLots(),Ask,3);
           }
        }
     }
  }
int CalculateCurrentOrders(int magic, bool isBuy)
  {
   int buys=0,sells=0;
   for(int i=0;i<OrdersTotal();i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()== magic){
         if(OrderType()==OP_BUY)  buys++;
         if(OrderType()==OP_SELL) sells++;
        }
     }
   return isBuy?buys:sells;
}