FX自動売買基礎と応用

ZigZagでヘッド&ショルダーを定義して売買サインを表示する方法【MQLプログラミングの基礎】


1.三つのバラメーターと二つのバッファーを登録


この記事では、ZigZagというインジケーターを利用してヘッド&ショルダーを定義し、ネックラインをブレイクする位置に、矢印の売買サインを表示する方法を解説します。ZigZagはMT4に標準搭載されており、そのソースファイルを改造するやり方もありますが、今回はiCustom関数を用いてZigZagの頂点情報を取得し、その値からヘッド&ショルダーを定義して売買サインを表示させます。

まずはファイルの新規作成で「カスタムインディケータ」を選択し、ファイル名を「ZigZag_H_and_S」とします。パラメーターは標準搭載のZigZagに合わせて三つ設定しましょう。一つ目は名前を「Depth」、初期値を「12」、二つ目は名前を「Deviation」、初期値を「5」、三つ目は名前を「Backstep」、初期値を「3」にして「次へ」をクリックします。

カスタムインディケータの一般プロパティの画面

「カスタムインディケータのイベントハンドラ」の画面では、「OnTimer」「OnChartEvent」のどちらにもチェックを入れずに次へ進み、バッファーを二つ追加します。一つは買いサイン用でラベルを「UP」、タイプを「Arrow」、カラーを「Red」、もう一つは売りサイン用でラベルを「DN」、タイプを「Arrow」、カラーを「DodgerBlue」としましょう。これで「完了」をクリックすれば、ひな形の完成です。

カスタムインディケータの描画プロパティの画面


2.バッファー名を変更し矢印サインのコードを定義


ファイルが開いたら、まず売買サインのサイズを見やすいように大きく変更します。「#property indicator_width1」と「#property indicator_width2」の値を「1」から「5」に変更しましょう。


#property indicator_width1  5
#property indicator_width2  5

また、バッファーの名前が長いので「//— indicator buffers」のバッファー名を「UPBuffer」→「UP」、「DNBuffer」→「DN」という具合に「Buffer」を省いて短くします(短くしなくても問題はありません)。


double UP[];
double DN[];

同様にOnInit関数内の「//— indicator buffers mapping」にあるバッファー名も次のように変更します。


SetIndexBuffer(0,UP);
SetIndexBuffer(1,DN);

そして「//— setting a code from the Wingdings charset as the property of PLOT_ARROW」のところで、矢印サインのコードを定義します。今回は普通の矢印を使うので、次のように変更しましょう。233が上向き矢印、234が下向き矢印のコードです。


SetIndexArrow(0,233);
SetIndexArrow(1,234);


3.過去に遡ってZigZagのポイントを探す


上記では、三つのバラメーターと二つのバッファーを登録し、矢印サインのコードを定義するところまで解説しました。続いて、OnCalculate関数内にメインの回路を作っていきましょう。

メインのループとしては、リミットから最新足までを計算します。そして最低限、毎回計算する足をミニマムとして、リミットがミニマムよりも小さかった場合に、それをミニマムとします。


int limit = Bars - prev_calculated -1;
int min = 1;
if (limit < min) limit = min;
for (int i = limit; i >= 0; i--) {
}

今回はZigZagのパターンを検索するので、最低限三つのポイントまで遡り、そこから先を毎回計算するようにします。そして一周計算が終わってから、iCustom関数でZigZagのポイントを探しに行きます。回数を数えるために「count」を用意し、ZigZagの値が「0」ではなかったとき、そこは頂点ポイントということなので、カウントを一つ進め、それが「3」以上になったところで、そのときの足の値をミニマムに入れます。これで最低限、3ポイント手前から毎回計算を実行するようになります。


if (prev_calculated > 0) {
   int count = 0;
   for (int i = 1; i < Bars - 1; i++) {
      double zz = iCustom(NULL, 0, "ZigZag", Depth, Deviation, Backstep, 0, i);
      if (zz != 0) count++;
      if (count >= 3) {
         min = i;
         break;
      }
   }
}


4.ZigZagの6ポイントの情報を配列に格納


続いて、メインのループでも同じように、iCustom関数でZigZagの情報を取得します。今回はヘッド&ショルダーを判定するのに全部で6ポイント記憶しなければいけないので、バーの番号とZigZagの値をそれぞれ格納できるように定義します。そして「ArrayInitialize」を使って配列をリセットし、最初に見つかったポイントを1点目として記憶します。そこから過去に遡り、残りの5ポイントを検索していきます。一つずつ遡って記憶していき、「n」が6になったらそこで検索は終了です。


if (limit < min) limit = min;
double point[6];
int bar[6];
int n = 0;
for (int i = limit; i >= 0; i--) {
   double zz = iCustom(NULL, 0, "ZigZag", Depth, Deviation, Backstep, 0, i);
   if (zz != 0) {
      ArrayInitialize(point, 0);
      ArrayInitialize(bar, 0);
      point[0] = zz;
      bar[0] = i;
      n = 1;
      for (int j = i + 1; j < Bars - 1; j++) {
         zz = iCustom(NULL, 0, "ZigZag", Depth, Deviation, Backstep, 0, j);
         if (zz != 0) {
            point[n] = zz;
            bar[n] = j;
            n++;
         }
         if (n >= 6) break;
      }
   }
}


5.パターン検索して売買サインを表示


上記では、ZigZagの6ポイントの情報を配列に格納することができました。次に、チャートの形がヘッド&ショルダーかどうかを判定するパターン検索の回路を組みます。このパターン検索は、6ポイントの情報を格納できた場合に限り行います。

まずは売りサインの表示条件です。下画像のように、ポイント0が高値で、かつポイント2はポイント0よりも大きく、かつポイント2はポイント4よりも大きく、かつポイント5はポイント3よりも小さく、かつポイント5はポイント1よりも小さければ、ヘッド&ショルダーのパターンが成立しているとみなします。

ZigZagの線のポイントに数字が割り当てられているチャート

そしてヘッド&ショルダー成立時は、ポイント0の隣から先の値動きを見ていき、ポイント1の安値を下抜いたら、その場所に売りサインとなる下向きの矢印を表示してループ処理を終了、そうでない場合は値を空にします。また、新しいポイントが出てきた場合は、そこでループ処理を終了するようにしましょう。


if (n >= 6) {
   if (point[0] == High[bar[0]] && point[2] > point[0] && point[2] > point[4] && point[5] < point[3] && point[5] < point[1]) {
      for (int k = i - 1; k >= 0; k--) {
         if (Low[k] < point[1]) {
            DN[k] = High[k];
            break;
         } else DN[k] = EMPTY_VALUE;
         zz = iCustom(NULL, 0, "ZigZag", Depth, Deviation, Backstep, 0, k);
         if (zz != 0) break;
      }
   }
}

同様に買いサインの表示条件も加えます。こちらはポイント0が安値で、かつポイント2はポイント0よりも小さく、かつポイント2はポイント4よりも小さく、かつポイント5はポイント3よりも大きく、かつポイント5はポイント1よりも大きければ、逆ヘッド&ショルダーのパターンが成立しているとみなします。

そして逆ヘッド&ショルダー成立時は、ポイント0の隣から先の値動きを見ていき、ポイント1の高値を上抜いたら、その場所に買いサインとなる上向きの矢印を表示してループ処理を終了、そうでない場合は値を空にします。また、新しいポイントが出てきた場合も、そこでループ処理を終了するようにしましょう。


if (point[0] == Low[bar[0]] && point[2] < point[0] && point[2] < point[4] && point[5] > point[3] && point[5] > point[1]) {
   for (int k = i - 1; k >= 0; k--) {
      if (High[k] > point[1]) {
         UP[k] = Low[k];
         break;
      } else UP[k] = EMPTY_VALUE;
      zz = iCustom(NULL, 0, "ZigZag", Depth, Deviation, Backstep, 0, k);
      if (zz != 0) break;
   }
}

これでコンパイルしてチャートにセットすると、指定した条件通りに矢印の売買サインが表示されることが分かります。

矢印の売買サインが表示されているチャート


6.ソースコード


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


//+------------------------------------------------------------------+
//|                                               ZigZag_H_and_S.mq4 |
//|                        Copyright 2022, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2
//--- plot UP
#property indicator_label1  "UP"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  5
//--- plot DN
#property indicator_label2  "DN"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  5
//--- input parameters
input int      Depth = 12;
input int      Deviation = 5;
input int      Backstep = 3;
//--- indicator buffers
double         UP[];
double         DN[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
   SetIndexBuffer(0, UP);
   SetIndexBuffer(1, DN);
//--- setting a code from the Wingdings charset as the property of PLOT_ARROW
   SetIndexArrow(0, 233);
   SetIndexArrow(1, 234);

//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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 limit = Bars - prev_calculated - 1;

   int min = 1;

   if (prev_calculated > 0) {
      int count = 0;
      for (int i = 1; i < Bars - 1; i++) {
         double zz = iCustom(NULL, 0, "ZigZag", Depth, Deviation, Backstep, 0, i);
         if (zz != 0) count++;
         if (count >= 3) {
            min = i;
            break;
         }
      }
   }

   if (limit < min) limit = min;

   double point[6];
   int bar[6];
   int n = 0;

   for (int i = limit; i >= 0; i--) {
      double zz = iCustom(NULL, 0, "ZigZag", Depth, Deviation, Backstep, 0, i);
      if (zz != 0) {
         ArrayInitialize(point, 0);
         ArrayInitialize(bar, 0);
         point[0] = zz;
         bar[0] = i;
         n = 1;
         for (int j = i + 1; j < Bars - 1; j++) {
            zz = iCustom(NULL, 0, "ZigZag", Depth, Deviation, Backstep, 0, j);
            if (zz != 0) {
               point[n] = zz;
               bar[n] = j;
               n++;
            }
            if (n >= 6) break;
         }
         if (n >= 6) {
            if (point[0] == High[bar[0]] && point[2] > point[0] && point[2] > point[4] && point[5] < point[3] && point[5] < point[1]) {
               for (int k = i - 1; k >= 0; k--) {
                  if (Low[k] < point[1]) {
                     DN[k] = High[k];
                     break;
                  } else DN[k] = EMPTY_VALUE;
                  zz = iCustom(NULL, 0, "ZigZag", Depth, Deviation, Backstep, 0, k);
                  if (zz != 0) break;
               }
            }
            if (point[0] == Low[bar[0]] && point[2] < point[0] && point[2] < point[4] && point[5] > point[3] && point[5] > point[1]) {
               for (int k = i - 1; k >= 0; k--) {
                  if (High[k] > point[1]) {
                     UP[k] = Low[k];
                     break;
                  } else UP[k] = EMPTY_VALUE;
                  zz = iCustom(NULL, 0, "ZigZag", Depth, Deviation, Backstep, 0, k);
                  if (zz != 0) break;
               }
            }
         }
      }
   }
//--- return value of prev_calculated for next call
   return(rates_total);
}


本記事の監修者・HT FX


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

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

EA運用の注意点

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


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

この記事をシェアする

ホーム » FX自動売買基礎と応用 » ZigZagでヘッド&ショルダーを定義して売買サインを表示する方法【MQLプログラミングの基礎】