FX自動売買基礎と応用

ZigZagをダウ理論的に色分け表示する方法【MQLプログラミングの基礎】


1.ZigZagのコードを開いて別名保存


この記事では、ZigZagをダウ理論的に色分け表示する方法について解説します。ZigZagはMT4に標準搭載されているインジケーターで、山谷を直線で表示する便利なツールです。今回は、その山の高値、谷の安値が共に切り上がった波を上昇トレンド、共に切り下がった波を下降トレンドとして定義し、色分け表示します。

ここではプログラムを一から作るのではなく、ZigZagを改造して作成します。まずチャートにZigZagをセットしましょう。ZigZagの山と谷を多めに表示したいので、パラメーターのDepthの値を「5」とします。

ZigZagの線が描かれているチャート

ZigZagのプログラムを改造するので、MT4のナビゲーターにある「ZigZag」上で右クリックした後、「修正」をクリックしてファイルを開きます。

MT4のナビゲーター

そして、メタエディターの「ファイル」→「名前を付けて保存」をクリックし、名前を「Colorful_ZigZag」に変更して保存しましょう。

メタエディターのファイルの画面


2.上昇トレンド用と下降トレンド用のバッファーを追加


別名で保存できたら、コードを改造していきます。まずはバッファーを三つに増やします。ファイル上部プロパティの「#property indicator_buffers」のところを「1」から「3」に変えて、その下に「#property indicator_color2」と「#property indicator_color3」を追加します。一つ目は白、二つ目は赤、三つ目は青にしましょう。また、線の太さもここで指定しておきます。一つ目は細線で、二つ目と三つ目は見やすいように太くします。


#property indicator_buffers 3
#property indicator_color1  clrWhite
#property indicator_color2  clrRed
#property indicator_color3  clrDodgerBlue
#property indicator_width1  1
#property indicator_width2  3
#property indicator_width3  3

さらに、「double ExtLowBuffer[];」の下に上昇トレンド用と下降トレンド用のバッファーを足します。


double UP[], DN[];

それに伴い、OnInit関数内にある「//— 2 additional buffers」のバッファー数を「3」から「5」に二つ増やします。


IndicatorBuffers(5);

そして「//—- indicator buffers」の2番目に「UP」を、3番目に「DN」を追加して番号をずらします。


SetIndexBuffer(0,ExtZigzagBuffer);
SetIndexBuffer(1,UP);
SetIndexBuffer(2,DN);
SetIndexBuffer(3,ExtHighBuffer);
SetIndexBuffer(4,ExtLowBuffer);

また、今回は「DRAW_LINE」というものを利用して線を塗りつぶすので、「//—- drawing settings」の「SetIndexStyle(0, DRAW_SECTION);」の下に次の2行を追加しておきます。


SetIndexStyle(1, DRAW_LINE);
SetIndexStyle(2, DRAW_LINE);

これで土台となるファイルが準備できました。その他の部分に関してはそのまま流用し、必要に応じて回路を追加していきます。


3.四つ分の配列を用意してデータを格納


上記ではZigZagのプログラムを流用し、上昇トレンド用と下降トレンド用のバッファーを追加できました。続いて、上昇時のラインと下降時のラインを色分け表示する回路を追加していきます。

まずは計算する範囲の定義として、今回は高値と安値の切り上げ、切り下げのパターンを判定するために、ZigZagの四つのポイントを探すまで再計算するようにします。ZigZagのバッファー「ExtZigzagBuffer」が「0」でない場合にカウントしていき、そのカウントが「4」になったらそこで検索を終了。その足を最低の計算範囲として記憶して、for文を抜けます。


limit = Bars - prev_calculated - 1;
int min = 0;
int count = 0;
for (i = 0; i < Bars - 1; i++) {
   if (ExtZigzagBuffer[i] != 0) count++;
   if (count >= 4) {
      min = i;
      break;
   }
}

次に、その記憶した数まで、最低限計算を繰り返すようにします。ZigZagの四つのポイントの値と、足の番号の値を覚える必要があるので、四つ分の配列を用意。ポイントが見つかったところで、配列の一つ目にその情報を入れ、カウントを「1」としましょう。


if (limit < min) limit = min;
int bar[4];
double zz[4];
for (i = limit; i >= 0; i--) {
   if (ExtZigzagBuffer[i] != 0) {
      bar[0] = i;
      zz[0] = ExtZigzagBuffer[i];
      count = 1;
   }
}

今度は、見つかった「i」の1個前の足から、過去に遡って配列全体を探しに行きます。「j」の足が「0」ではなかった場合、配列の二つ目以降にポイントを格納していき、カウントが4以上になったときに終了とします。これで配列bar[]とzz[]に四つのZigZag頂点情報が格納できます。


for (int j = i + 1; j < Bars - 1; j++) {
   if (ExtZigzagBuffer[j] != 0) {
      bar[count] = j;
      zz[count] = ExtZigzagBuffer[j];
      count++;
      if (count >= 4) break;
   }
}

なお、毎回この四つの配列をリセットするために、配列を指定した値で初期化する「ArrayInitialize」を「for (i = limit; i >= 0; i–) {」の下に入れておきます。


ArrayInitialize(bar, -1);
ArrayInitialize(zz, 0);


4.値動きのパターンを検索してトレンドを判定


続いて、配列を探した後に最後のバーが「-1」だった場合、その後の処理を行わないように「continue」を使います。


if (bar[3] == -1) continue;

その後の処理というのは、高値と安値の切り上げ、切り下げを判定するパターン検索です。下画像のようにポイント0が高値で、かつポイント0がポイント2よりも大きく、かつポイント1がポイント3よりも大きければ、高値と安値が共に切り上がったことになるので、上昇トレンドとみなします。

ZigZagの線の先端に数字が割り当てられているチャート

同様の考え方で、ポイント0が安値で、かつポイント0がポイント2よりも小さく、かつポイント1がポイント3よりも小さければ、高値と安値が共に切り下がったことになるので下降トレンドとみなします。ラインの塗りつぶし処理に関しては、今回は「DrawLine」という名前の関数を別で作り、ここで実行します。


if (zz[0] == High[i] && zz[0] > zz[2] && zz[1] > zz[3]) {
   DrawLine(UP, bar, zz);
} else if (zz[0] == Low[i] && zz[0] < zz[2] && zz[1] < zz[3]) {
   DrawLine(DN, bar, zz);
}


5.値動きのパターンに応じてラインを塗り分ける


上記では、上昇トレンドか下降トレンドか判定するために値動きのパターンを検索し、「DrawLine」という名前の関数を作って、ラインの塗りつぶし処理を実行するところまで解説しました。続いて、そのDrawLineの処理を記述していきます。

ファイルの下部に「Draw line function」を設けて、そこにコードを追加していきましょう。具体的な処理としては、バッファーの配列と足の番号の情報を両方渡して、ラインの塗りつぶしを行います。MT4では「参照渡し」というやり方でしかパラメーターを配列で渡すことができないので、各配列の前に「&」を付ける必要があります。


void DrawLine(double &array[], int &bar[], double &zz[])

今回は「上昇・下降・上昇」もしくは「下降・上昇・下降」の3本のラインをワンセットとして塗りつぶしたいので、for文で3回繰り返すようにします。ここでは一定期間の塗り分けを実現するために、離れた点を指定してその間を一本の直線で表示するタイプの「DRAW_SECTION」というインジケータではなくて、「DRAW_LINE」を利用するのがポイントです。Draw_Lineは、ラインを塗りつぶす場合に1コマ1コマを順番に塗り、それを繋げて1本の直線を作ります。そのため、まずはbar[i+1]からbar[i]を引いて何コマあるのかを求めます。このあと割り算を使うので、コマ数を表すnが「0」の場合はそこで処理をしないようにしておきます。


for (int i = 0; i < 3; i++) {
   int n = bar[i + 1] -  bar[i];
   if (n == 0) continue;

1コマごとの価格の変化を出すためには全体値幅を出して、それをnで割ります。これで「pitch」ができるので、それを利用して0からn番目まで1コマずつラインを書いていきます。「bar[i]」がスタートとなって、「j」ずつ増やしていきます。


double pitch = (zz[i + 1] - zz[i]) / n;
   for (int j = 0; j <= n; j++) {
   array[bar[i] + j] = zz[i] + pitch * j;
   }

これでコンパイルしてチャートにセットすると、上昇トレンドのときは赤色に、下降トレンドのときは青色に、ZigZagが色分けされることが分かります。

ZigZagの線が赤と青に色分けされているチャート


6.ソースコード


今回、作成したソースコードは下記の通りです。


//+------------------------------------------------------------------+
//|                                              Colorful_ZigZag.mq4 |
//|                   Copyright 2006-2014, MetaQuotes Software Corp. |
//|                                              http://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright "2006-2014, MetaQuotes Software Corp."
#property link      "http://www.mql4.com"
#property strict

#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1  clrWhite
#property indicator_color2  clrRed
#property indicator_color3  clrDodgerBlue
#property indicator_width1  1
#property indicator_width2  3
#property indicator_width3  3
//---- indicator parameters
input int InpDepth = 12;   // Depth
input int InpDeviation = 5; // Deviation
input int InpBackstep = 3; // Backstep
//---- indicator buffers
double ExtZigzagBuffer[];
double ExtHighBuffer[];
double ExtLowBuffer[];
double UP[], DN[];
//--- globals
int    ExtLevel = 3; // recounting's depth of extremums
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   if(InpBackstep >= InpDepth) {
      Print("Backstep cannot be greater or equal to Depth");
      return(INIT_FAILED);
   }
//--- 2 additional buffers
   IndicatorBuffers(5);
//---- drawing settings
   SetIndexStyle(0, DRAW_SECTION);
   SetIndexStyle(1, DRAW_LINE);
   SetIndexStyle(2, DRAW_LINE);
//---- indicator buffers
   SetIndexBuffer(0, ExtZigzagBuffer);
   SetIndexBuffer(1, UP);
   SetIndexBuffer(2, DN);
   SetIndexBuffer(3, ExtHighBuffer);
   SetIndexBuffer(4, ExtLowBuffer);
   SetIndexEmptyValue(0, 0.0);
//---- indicator short name
   IndicatorShortName("ZigZag(" + string(InpDepth) + "," + string(InpDeviation) + "," + string(InpBackstep) + ")");
//---- initialization done
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
{
   int    i, limit, counterZ, whatlookfor = 0;
   int    back, pos, lasthighpos = 0, lastlowpos = 0;
   double extremum;
   double curlow = 0.0, curhigh = 0.0, lasthigh = 0.0, lastlow = 0.0;
//--- check for history and inputs
   if(rates_total < InpDepth || InpBackstep >= InpDepth)
      return(0);
//--- first calculations
   if(prev_calculated == 0)
      limit = InitializeAll();
   else {
      //--- find first extremum in the depth ExtLevel or 100 last bars
      i = counterZ = 0;
      while(counterZ < ExtLevel && i < 100) {
         if(ExtZigzagBuffer[i] != 0.0)
            counterZ++;
         i++;
      }
      //--- no extremum found - recounting all from begin
      if(counterZ == 0)
         limit = InitializeAll();
      else {
         //--- set start position to found extremum position
         limit = i - 1;
         //--- what kind of extremum?
         if(ExtLowBuffer[i] != 0.0) {
            //--- low extremum
            curlow = ExtLowBuffer[i];
            //--- will look for the next high extremum
            whatlookfor = 1;
         } else {
            //--- high extremum
            curhigh = ExtHighBuffer[i];
            //--- will look for the next low extremum
            whatlookfor = -1;
         }
         //--- clear the rest data
         for(i = limit - 1; i >= 0; i--) {
            ExtZigzagBuffer[i] = 0.0;
            ExtLowBuffer[i] = 0.0;
            ExtHighBuffer[i] = 0.0;
         }
      }
   }
//--- main loop
   for(i = limit; i >= 0; i--) {
      //--- find lowest low in depth of bars
      extremum = low[iLowest(NULL, 0, MODE_LOW, InpDepth, i)];
      //--- this lowest has been found previously
      if(extremum == lastlow)
         extremum = 0.0;
      else {
         //--- new last low
         lastlow = extremum;
         //--- discard extremum if current low is too high
         if(low[i] - extremum > InpDeviation * Point)
            extremum = 0.0;
         else {
            //--- clear previous extremums in backstep bars
            for(back = 1; back <= InpBackstep; back++) {
               pos = i + back;
               if(ExtLowBuffer[pos] != 0 && ExtLowBuffer[pos] > extremum)
                  ExtLowBuffer[pos] = 0.0;
            }
         }
      }
      //--- found extremum is current low
      if(low[i] == extremum)
         ExtLowBuffer[i] = extremum;
      else
         ExtLowBuffer[i] = 0.0;
      //--- find highest high in depth of bars
      extremum = high[iHighest(NULL, 0, MODE_HIGH, InpDepth, i)];
      //--- this highest has been found previously
      if(extremum == lasthigh)
         extremum = 0.0;
      else {
         //--- new last high
         lasthigh = extremum;
         //--- discard extremum if current high is too low
         if(extremum - high[i] > InpDeviation * Point)
            extremum = 0.0;
         else {
            //--- clear previous extremums in backstep bars
            for(back = 1; back <= InpBackstep; back++) {
               pos = i + back;
               if(ExtHighBuffer[pos] != 0 && ExtHighBuffer[pos] < extremum)
                  ExtHighBuffer[pos] = 0.0;
            }
         }
      }
      //--- found extremum is current high
      if(high[i] == extremum)
         ExtHighBuffer[i] = extremum;
      else
         ExtHighBuffer[i] = 0.0;
   }
//--- final cutting
   if(whatlookfor == 0) {
      lastlow = 0.0;
      lasthigh = 0.0;
   } else {
      lastlow = curlow;
      lasthigh = curhigh;
   }
   for(i = limit; i >= 0; i--) {
      switch(whatlookfor) {
      case 0: // look for peak or lawn
         if(lastlow == 0.0 && lasthigh == 0.0) {
            if(ExtHighBuffer[i] != 0.0) {
               lasthigh = High[i];
               lasthighpos = i;
               whatlookfor = -1;
               ExtZigzagBuffer[i] = lasthigh;
            }
            if(ExtLowBuffer[i] != 0.0) {
               lastlow = Low[i];
               lastlowpos = i;
               whatlookfor = 1;
               ExtZigzagBuffer[i] = lastlow;
            }
         }
         break;
      case 1: // look for peak
         if(ExtLowBuffer[i] != 0.0 && ExtLowBuffer[i] < lastlow && ExtHighBuffer[i] == 0.0) {
            ExtZigzagBuffer[lastlowpos] = 0.0;
            lastlowpos = i;
            lastlow = ExtLowBuffer[i];
            ExtZigzagBuffer[i] = lastlow;
         }
         if(ExtHighBuffer[i] != 0.0 && ExtLowBuffer[i] == 0.0) {
            lasthigh = ExtHighBuffer[i];
            lasthighpos = i;
            ExtZigzagBuffer[i] = lasthigh;
            whatlookfor = -1;
         }
         break;
      case -1: // look for lawn
         if(ExtHighBuffer[i] != 0.0 && ExtHighBuffer[i] > lasthigh && ExtLowBuffer[i] == 0.0) {
            ExtZigzagBuffer[lasthighpos] = 0.0;
            lasthighpos = i;
            lasthigh = ExtHighBuffer[i];
            ExtZigzagBuffer[i] = lasthigh;
         }
         if(ExtLowBuffer[i] != 0.0 && ExtHighBuffer[i] == 0.0) {
            lastlow = ExtLowBuffer[i];
            lastlowpos = i;
            ExtZigzagBuffer[i] = lastlow;
            whatlookfor = 1;
         }
         break;
      }
   }
//--- 色分け
   limit = Bars - prev_calculated - 1;
   int min = 0;
   int count = 0;
   for (i = 0; i < Bars - 1; i++) {
      if (ExtZigzagBuffer[i] != 0) count++;
      if (count >= 4) {
         min = i;
         break;
      }
   }
   if (limit < min) limit = min;

   int bar[4];
   double zz[4];
   for (i = limit; i >= 0; i--) {
      ArrayInitialize(bar, -1);
      ArrayInitialize(zz, 0);
      if (ExtZigzagBuffer[i] != 0) {
         bar[0] = i;
         zz[0] = ExtZigzagBuffer[i];
         count = 1;

         for (int j = i + 1; j < Bars - 1; j++) {
            if (ExtZigzagBuffer[j] != 0) {
               bar[count] = j;
               zz[count] = ExtZigzagBuffer[j];
               count++;
               if (count >= 4) break;
            }
         }
         if (bar[3] == -1) continue;

         if (zz[0] == High[i] && zz[0] > zz[2] && zz[1] > zz[3]) {
            DrawLine(UP, bar, zz);
         } else if (zz[0] == Low[i] && zz[0] < zz[2] && zz[1] < zz[3]) {
            DrawLine(DN, bar, zz);
         }
      }
   }
//--- done
      return(rates_total);
   }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   int InitializeAll() {
      ArrayInitialize(ExtZigzagBuffer, 0.0);
      ArrayInitialize(ExtHighBuffer, 0.0);
      ArrayInitialize(ExtLowBuffer, 0.0);
//--- first counting position
      return(Bars - InpDepth);
   }
//+------------------------------------------------------------------+
//| Draw line function                                               |
//+------------------------------------------------------------------+
void DrawLine(double & array[], int &bar[], double & zz[])
{
   for (int i = 0; i < 3; i++) {
      int n = bar[i + 1] -  bar[i];
      if (n == 0) continue;
      double pitch = (zz[i + 1] - zz[i]) / n;
      for (int j = 0; j <= n; j++) {
         array[bar[i] + j] = zz[i] + pitch * j;
      }
   }
}


本記事の監修者・HT FX


2013年にFXを開始し、その後専業トレーダーへ。2014年からMT4/MT5のカスタムインジケーターの開発に取り組む。ブログでは100本を超えるインジケーターを無料公開。投資スタイルは自作の秒足インジケーターを利用したスキャルピング。

EA(自動売買)を学びたい方へオススメコンテンツ

EA運用の注意点

OANDAではEA(自動売買)を稼働するプラットフォームMT4/MT5の基本的な使い方について、画像や動画付きで詳しく解説しています。MT4/MT5のインストールからEAの設定方法までを詳しく解説しているので、初心者の方でもスムーズにEA運用を始めることが可能です。またOANDAの口座をお持ちであれば、独自開発したオリジナルインジケーターを無料で利用することもできます。EA運用をお考えであれば、ぜひ口座開設をご検討ください。


本ホームページに掲載されている事項は、投資判断の参考となる情報の提供を目的としたものであり、投資の勧誘を目的としたものではありません。投資方針、投資タイミング等は、ご自身の責任において判断してください。本サービスの情報に基づいて行った取引のいかなる損失についても、当社は一切の責を負いかねますのでご了承ください。また、当社は、当該情報の正確性および完全性を保証または約束するものでなく、今後、予告なしに内容を変更または廃止する場合があります。なお、当該情報の欠落・誤謬等につきましてもその責を負いかねますのでご了承ください。

この記事をシェアする

ホーム » FX自動売買基礎と応用 » ZigZagをダウ理論的に色分け表示する方法【MQLプログラミングの基礎】