FX自動売買基礎と応用

移動平均線の色を方向によって変える自動売買の作成方法


三つのバッファーを登録


この記事で解説するのは、方向によって色変化する移動平均線(MA:Moving Average)の作成方法についてです。まずはインジケーターのバッファーを使う一般的な作り方を紹介します。

ファイルの新規作成で「カスタムインディケータ」を選択したあと、ファイル名を「ColorfulMA_Normal」としてパラメーターを追加します。名前は「PERIOD」、初期値は「5」という設定です。ここではMAの色変化が分かりやすいように期間を短めにしています。

パラメーターを追加

「カスタムインディケータのイベントハンドラ」の画面では、「OnTimer」「OnChartEvent」のどちらにもチェックを入れずに次へ進み、「カスタムインディケータの描画プロパティ」画面のプロット欄でMAのデータを格納する三つのバッファーを登録します。

  • 一つ目は計算用のバッファーで表示はしません。ラベルを「MA」、カラーを「None」としましょう。
  • 二つ目は上昇用のバッファーで、ラベルを「UP」、カラーを「Red」に、
  • 三つ目は下降用のバッファーで、ラベルを「DN」、カラーを「DodgerBlue」にして「完了」をクリックすれば、ひな形の完成です。

MAのデータを格納する三つのバッファーを登録


MAを計算して値をバッファーに格納


新規ファイルが開いたら、上部のプロパティを修正します。「MA」に関しては前述の通り表示しないので、タイプ(type)のところを「DRAW_LINE」から「DRAW_NONE」に変えておきます。また、MAを見やすくするため、「UP」と「DN」の太さ(width)のところを「1」から「2」に変更しましょう。


//--- plot MA
#property indicator_label1  "MA"
#property indicator_type1   DRAW_NONE
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot UP
#property indicator_label2  "UP"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2
//--- plot DN
#property indicator_label3  "DN"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrDodgerBlue
#property indicator_style3  STYLE_SOLID
#property indicator_width3  2

そして、OnCalculate関数の配下にMAの計算式を記述します。MAのバッファーを次のように定義しましょう。タイプは単純移動平均線、適用価格は終値とします。


int limit = Bars - prev_calculated - 2;
for (int i = limit; i >= 0; i--) {
   MABuffer[i] = iMA(NULL, 0, PERIOD, 0, MODE_SMA, PRICE_CLOSE, i);

これで計算されたMAの値が、バッファーに格納されます。


格納したデータを用いてMAを表示


続いて、バッファーに格納したデータを利用し、if文で上昇・下降の条件を組みます。

1本前の足と比較して上昇していた場合は、「UPBuffer」に値を入れます。1点だけではラインが引けないので、「i+1」として1本前にも値を入れるのがポイントです。そして、1本前の足と比較して上昇していなかった場合は、「DNBuffer」バッファーに値を入れます。


if (MABuffer[i] > MABuffer[i + 1]) {
   UPBuffer[i] = MABuffer[i];
   UPBuffer[i + 1] = MABuffer[i + 1];
} else {
   DNBuffer[i] = MABuffer[i];
   DNBuffer[i + 1] = MABuffer[i + 1];
}

これでコンパイルしてチャートにセットすると、上向きのときは赤、下向きのときは青のMAが表示されることが分かります。

上向きのときは赤、下向きのときは青のMAが表示


オブジェクトを使って問題を対策


方向によって色変化する移動平均線(MA:Moving Average)を表示することができました。しかし、MAをよく見ると上昇しているにもかかわらず赤の表示となっていない箇所があります。

上昇しているにもかかわらず赤の表示となっていない箇所がある

この現象が起きるのは、前後が下降しているポイントです。実際には上昇していますが、その前後が下がっているので下降用のバッファーに値が格納され、ラインが下降の色で塗られてしまいます。そこで、オブジェクトを使った対策方法を紹介します。

対策版インジケーターを作るために、もう一度ファイルを新規作成しましょう。

ファイルの新規作成で「カスタムインディケータ」を選択し、ファイル名を「ColorfulMA」としてパラメーターを追加します。前回と同じく名前は「PERIOD」、初期値は「5」という設定です。

今度は「OnChartEvent」を使うので、「カスタムインディケータのイベントハンドラ」の画面で「OnChartEvent」にチェックを入れ、次の画面でバッファーを一つだけ登録します。ラベルを「MA」、カラーを「None」としましょう。これで「完了」をクリックすれば、ひな形の完成です。

「カスタムインディケータのイベントハンドラ」の画面で「OnChartEvent」にチェック

まず、新規ファイルの上部に定義されている「MA」のタイプ(type)のところを「DRAW_LINE」から「DRAW_NONE」に変えます。


//--- plot MA
#property indicator_label1  "MA"
#property indicator_type1   DRAW_NONE
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

MAの計算式に関しては、先に作った「ColorfulMA_Normal」のものと同じなので、それをコピーしてOnCalculate関数の配下に貼り付けましょう。


int limit = Bars - prev_calculated - 2;
for (int i = limit; i >= 0; i--) {
   MABuffer[i] = iMA(NULL, 0, PERIOD, 0, MODE_SMA, PRICE_CLOSE, i);
}


「MABuffer」の値を利用して色を決定


「ChartEvent function」の下にトレンドラインを使ってMAを描画するプログラムを組んでいきます。まずはObjectsDeleteAll関数を用いてオブジェクトをリセットするコードを記述します。


void DrawMA()
{
   ObjectsDeleteAll(0, "MA_");
}

そして、バーの検索する範囲を限定するために、チャートに表示されているバーの情報を入手します。「CHART_FIRST_VISIBLE_BAR」はチャートの左端のバーを表し、そこからチャート幅全体の本数を表す「CHART_WIDTH_IN_BARS」を引くと右端の値となります。

もし、その計算結果がマイナスとなってしまった場合は「0」とします。


int barF = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR);
int barR = barF - (int)ChartGetInteger(0, CHART_WIDTH_IN_BARS);
if (barR < 0) barR = 0;

次に、求めたバーを使って計算をさせます。上昇か下降かで色を変えたいので、「MABuffer」の値を利用して色を決めます。今回は三色表示で、上昇でも下降でもなければ「白」、上昇だったら「赤」、下降だったら「青」としましょう。


for (int i = barF; i > barR; i--) {
   color clr = clrWhite;
   if (MABuffer[i] > MABuffer[i + 1]) clr = clrRed;
   else if (MABuffer[i] < MABuffer[i + 1]) clr = clrDodgerBlue; 
}


トレンドラインでMAを描画


続いて、トレンドラインを使ってMAを表示します。

トレンドラインのサンプルコードは、MQL4リファレンスからコピーして使いましょう。

MQL4リファレンスの目次にある「Constants, Enumerations and Structures」→「Objects Constants」→「Object Types」をクリックするとオブジェクトの一覧が表示されるので、その中から「OBJ_TREND」を選択し、あらかじめ用意されている「Create a trend line by the given coordinates」のコードをコピーしてファイル下部に貼り付けます。

「//--- set anchor points' coordinates if they are not set」から「ResetLastError();」までの4行と、「Print(__FUNCTION__,」「": failed to create a trend line! Error code = ", GetLastError());」の2行は不要なので削除してください。

また、ラインを太くしたいので上部の「// line width」のところを「width = 1」から「width = 2」に、セレクションは必要ないので「// highlight to move」のところを「selection = true」から「selection = false」に修正します。


//+------------------------------------------------------------------+
//| Create a trend line by the given coordinates                     |
//+------------------------------------------------------------------+
bool TrendCreate(const long            chart_ID = 0,      // chart's ID
                 const string          name = "TrendLine", // line name
                 const int             sub_window = 0,    // subwindow index
                 datetime              time1 = 0,         // first point time
                 double                price1 = 0,        // first point price
                 datetime              time2 = 0,         // second point time
                 double                price2 = 0,        // second point price
                 const color           clr = clrRed,      // line color
                 const ENUM_LINE_STYLE style = STYLE_SOLID, // line style
                 const int             width = 2,         // line width
                 const bool            back = false,      // in the background
                 const bool            selection = false, // highlight to move
                 const bool            ray_right = false, // line's continuation to the right
                 const bool            hidden = true,     // hidden in the object list
                 const long            z_order = 0)       // priority for mouse click
{
//--- create a trend line by the given coordinates
   if(!ObjectCreate(chart_ID, name, OBJ_TREND, sub_window, time1, price1, time2, price2)) {
      return(false);
   }
//--- set line color
   ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);
//--- set line display style
   ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);
//--- set line width
   ObjectSetInteger(chart_ID, name, OBJPROP_WIDTH, width);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);
//--- enable (true) or disable (false) the mode of moving the line by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot be
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
   ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);
   ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);
//--- enable (true) or disable (false) the mode of continuation of the line's display to the right
   ObjectSetInteger(chart_ID, name, OBJPROP_RAY_RIGHT, ray_right);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(chart_ID, name, OBJPROP_HIDDEN, hidden);
//--- set the priority for receiving the event of a mouse click in the chart
   ObjectSetInteger(chart_ID, name, OBJPROP_ZORDER, z_order);
//--- successful execution
   return(true);
}


最初に作ったMAと対策版MAを比較


設定したTrendCreateは、DrawMA()の「else if (MABuffer[i] < MABuffer[i + 1]) clr = clrDodgerBlue;」の下で呼び出します。1点目の時間は「Time[i]」、価格は「MABuffer[i]」、2点目の時間と価格はそれぞれ1をプラスして「Time[i+1]」、「MABuffer[i +1]」とします。


TrendCreate(0, "MA_" + (string)i, 0, Time[i], MABuffer[i], Time[i + 1], MABuffer[i + 1], clr);

最後に、作ったDrawMA()をOnCalculate関数の配下に入れます。


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 - 2;
   for (int i = limit; i >= 0; i--) {
      MABuffer[i] = iMA(NULL, 0, PERIOD, 0, MODE_SMA, PRICE_CLOSE, i);
   }
   DrawMA();
//--- return value of prev_calculated for next call
   return(rates_total);
}

また、チャートが変化したときに追随して表示されるようにしたいので、OnChartEvent関数のところに次のif文を追記します。


if (id == CHARTEVENT_CHART_CHANGE) DrawMA();

これでコンパイルしてチャートにセットし、最初のMAと比較してみましょう。画像の上が最初に作ったインジケーター「ColorfulMA_Normal」、下が対策版として作ったインジケーター「ColorfulMA」です。ColorfulMAでは、前後が下降している上昇部分もきちんと赤く表示されていることが分かります。

最初のMAと対策版を比較


ソースコード


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


ColorfulMA_Normal



//+------------------------------------------------------------------+
//|                                            ColorfulMA_Normal.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 3
#property indicator_plots   3
//--- plot MA
#property indicator_label1  "MA"
#property indicator_type1   DRAW_NONE
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot UP
#property indicator_label2  "UP"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2
//--- plot DN
#property indicator_label3  "DN"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrDodgerBlue
#property indicator_style3  STYLE_SOLID
#property indicator_width3  2
//--- input parameters
input int      PERIOD = 5;
//--- indicator buffers
double         MABuffer[];
double         UPBuffer[];
double         DNBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
   SetIndexBuffer(0, MABuffer);
   SetIndexBuffer(1, UPBuffer);
   SetIndexBuffer(2, DNBuffer);

//---
   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 - 2;
   for (int i = limit; i >= 0; i--) {
      MABuffer[i] = iMA(NULL, 0, PERIOD, 0, MODE_SMA, PRICE_CLOSE, i);

      if (MABuffer[i] > MABuffer[i + 1]) {
         UPBuffer[i] = MABuffer[i];
         UPBuffer[i + 1] = MABuffer[i + 1];
      } else {
         DNBuffer[i] = MABuffer[i];
         DNBuffer[i + 1] = MABuffer[i + 1];
      }
   }
//--- return value of prev_calculated for next call
   return(rates_total);
}


ColorfulMA



//+------------------------------------------------------------------+
//|                                                   ColorfulMA.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 1
#property indicator_plots   1
//--- plot MA
#property indicator_label1  "MA"
#property indicator_type1   DRAW_NONE
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      PERIOD = 5;
//--- indicator buffers
double         MABuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
   SetIndexBuffer(0, MABuffer);

//---
   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 - 2;
   for (int i = limit; i >= 0; i--) {
      MABuffer[i] = iMA(NULL, 0, PERIOD, 0, MODE_SMA, PRICE_CLOSE, i);
   }
   DrawMA();
//--- return value of prev_calculated for next call
   return(rates_total);
}
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
//---
   if (id == CHARTEVENT_CHART_CHANGE) DrawMA();
}
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void DrawMA()
{
   ObjectsDeleteAll(0, "MA_");
   int barF = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR);
   int barR = barF - (int)ChartGetInteger(0, CHART_WIDTH_IN_BARS);
   if (barR < 0) barR = 0;

   for (int i = barF; i > barR; i--) {
      color clr = clrWhite;
      if (MABuffer[i] > MABuffer[i + 1]) clr = clrRed;
      else if (MABuffer[i] < MABuffer[i + 1]) clr = clrDodgerBlue;
      TrendCreate(0, "MA_" + (string)i, 0, Time[i], MABuffer[i], Time[i + 1], MABuffer[i + 1], clr);
   }
}
//+------------------------------------------------------------------+
//| Create a trend line by the given coordinates                     |
//+------------------------------------------------------------------+
bool TrendCreate(const long            chart_ID = 0,      // chart's ID
                 const string          name = "TrendLine", // line name
                 const int             sub_window = 0,    // subwindow index
                 datetime              time1 = 0,         // first point time
                 double                price1 = 0,        // first point price
                 datetime              time2 = 0,         // second point time
                 double                price2 = 0,        // second point price
                 const color           clr = clrRed,      // line color
                 const ENUM_LINE_STYLE style = STYLE_SOLID, // line style
                 const int             width = 2,         // line width
                 const bool            back = false,      // in the background
                 const bool            selection = false, // highlight to move
                 const bool            ray_right = false, // line's continuation to the right
                 const bool            hidden = true,     // hidden in the object list
                 const long            z_order = 0)       // priority for mouse click
{
//--- create a trend line by the given coordinates
   if(!ObjectCreate(chart_ID, name, OBJ_TREND, sub_window, time1, price1, time2, price2)) {
      return(false);
   }
//--- set line color
   ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);
//--- set line display style
   ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);
//--- set line width
   ObjectSetInteger(chart_ID, name, OBJPROP_WIDTH, width);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);
//--- enable (true) or disable (false) the mode of moving the line by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot be
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
   ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);
   ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);
//--- enable (true) or disable (false) the mode of continuation of the line's display to the right
   ObjectSetInteger(chart_ID, name, OBJPROP_RAY_RIGHT, ray_right);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(chart_ID, name, OBJPROP_HIDDEN, hidden);
//--- set the priority for receiving the event of a mouse click in the chart
   ObjectSetInteger(chart_ID, name, OBJPROP_ZORDER, z_order);
//--- successful execution
   return(true);
}


本記事の監修者・HT FX


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

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

EA運用の注意点

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


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

この記事をシェアする

ホーム » FX自動売買基礎と応用 » 移動平均線の色を方向によって変える自動売買の作成方法