インジケーター作成05

2つのEMAからMACDを算出してサブウィンドウに表示させてみよう!

ここでは、前回完成したインジケーターファイルをカスタマイズして、2本の指数平滑移動平均線(EMA)をサブウィンドウに表示させるようにして、さらにそれをカスタマイズしてMACDとそのシグナルラインを表示させるインジケーターにする方法を解説します。

記事一覧で前回までの記事をチェックしよう!
「MT4インジケーター作成入門」の記事一覧

前回記事のおさらい

前回記事では、単純移動平均線(SMA)と指数平滑移動平均線(EMA)の2本のラインを表示させるようにしました。

Dr.EADr.EA

前回記事で完成したファイルのコードがこちら

#property strict
#property indicator_chart_window
#property indicator_buffers 2          // インジケーターバッファ 2つ
#property indicator_color1 clrRed      // 1つ目の色 赤色
#property indicator_width1 2           // 1つ目の太さ 2
#property indicator_color2 clrYellow   // 2つ目の色 黄色
#property indicator_width2 2           // 2つ目の太さ 2

extern int  SMA_Period  = 10;          // SMAの期間
extern int  EMA_Period  = 20;          // EMAの期間


double buf[];                          // ライン用の配列を宣言
double ema[];                          // EMA用の配列を宣言

//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
   SetIndexBuffer(0, buf);             // 配列 buf[]をインジケーター用に割り当てる
   SetIndexStyle(0, DRAW_LINE);        // 描画タイプをラインと定義
   SetIndexBuffer(1, ema);             // 配列 ema[]をインジケーター用に割り当てる
   SetIndexStyle(1, DRAW_LINE);        // 描画タイプをラインと定義

   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, j;
   int limit;
   if (prev_calculated == 0)              // 最初
      limit = rates_total - 1;               // 左端のローソク足から全部
   else                                   // それ以外
      limit = rates_total - prev_calculated; // ローソク足増加時「1」、通常「0」
   
   for (i=limit; i>=0; i--)               // limit本前から現在のローソク足を処理
   {
      // SMA
      if (i + SMA_Period - 1 <= Bars - 1)
      {
         // buf[i]を0に初期化して
         buf[i] = 0;
         // Close[i+0] ~ Close[i+SMA_Period]の一つ手前までを足していき
         for (j=0; j<SMA_Period; j++) buf[i] += Close[i+j];
         // SMA_Periodで割る
         buf[i] /= SMA_Period;
      }
      
      // MT4のEMA
      if (i == Bars - 1) ema[i] = Close[i];
      else
      {
         ema[i] = ema[i+1] * (EMA_Period - 1) + Close[i] * 2;
         ema[i] /= EMA_Period + 1;
      }
   }
   
//--- return value of prev_calculated for next call
   return(rates_total);
}

前回完成ファイル【Sample_Indicator_04.mq4】をダウンロード

サブウィンドウに表示するように定義する

前回完成ファイルの「#property indicator_chart_window」を次のコードに変更します。

#property indicator_separate_window

この時点でコンパイルして表示させてみるとサブウィンドウに表示されるのがわかります。

にゃんたにゃんた

簡単だにゃ♪

2つのEMAを表示させてみる

短期EMAと長期EMAの2つを表示させるため、次の変更編集をします。

  • パラメーター名変更
    • SMA_Period → FastEMA_Period
    • EMA_Period → SlowEMA_Period
  • 配列名変更
    • buf → fast_ema
    • ema → slow_ema
  • OnCalculate()関数内のfor()文内のコードを変更

パラメーター名変更と配列名変更

パラメーター変数と配列の宣言部分を次のように変更します。

extern int  FastEMA_Period  = 12;      // 短期EMAの期間
extern int  SlowEMA_Period  = 26;      // 長期EMAの期間

double fast_ema[];                     // 短期EMA用配列
double slow_ema[];                     // 長期EMA用配列

それに伴い、OnInit()関数内を次のように変更します。

   SetIndexBuffer(0, fast_ema);
   SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(1, slow_ema);
   SetIndexStyle(1, DRAW_LINE);

OnCalculate()関数内のfor()文内のコードを変更

OnCalculate()関数のfor()文内を次のコードに変更します。

   fast_ema[i] = iMA(NULL, 0, FastEMA_Period, 0, MODE_EMA, PRICE_CLOSE, i);
   slow_ema[i] = iMA(NULL, 0, SlowEMA_Period, 0, MODE_EMA, PRICE_CLOSE, i);

短期EMAと長期EMAの値をそれぞれiMA()関数で取得しています。
※iMA()関数は移動平均を返す関数です。

この時点で、2つのEMAがサブウィンドウに表示されるようになっています。

にゃんたにゃんた

博士、移動平均の計算式が無くなったにゃ!

Dr.EADr.EA

しー!
簡単なコードの方がええじゃろて。(汗)
現段階でのコードがこちら。

#property strict
#property indicator_chart_window
#property indicator_buffers 2          // インジケーターバッファ 2つ
#property indicator_color1 clrRed      // 1つ目の色 赤色
#property indicator_width1 2           // 1つ目の太さ 2
#property indicator_color2 clrYellow   // 2つ目の色 黄色
#property indicator_width2 2           // 2つ目の太さ 2

extern int  FastEMA_Period  = 12;      // 短期EMAの期間
extern int  SlowEMA_Period  = 26;      // 長期EMAの期間

double fast_ema[];                     // 短期EMA用配列
double slow_ema[];                     // 長期EMA用配列

//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0, fast_ema);
   SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(1, slow_ema);
   SetIndexStyle(1, DRAW_LINE);
   
   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, j;
   int limit;
   if (prev_calculated == 0)              // 最初
      limit = rates_total - 1;               // 左端のローソク足から全部
   else                                   // それ以外
      limit = rates_total - prev_calculated; // ローソク足増加時「1」、通常「0」
   
   for (i=limit; i>=0; i--)               // limit本前から現在のローソク足を処理
   {
      fast_ema[i] = iMA(NULL, 0, FastEMA_Period, 0, MODE_EMA, PRICE_CLOSE, i);
      slow_ema[i] = iMA(NULL, 0, SlowEMA_Period, 0, MODE_EMA, PRICE_CLOSE, i);
   }
   
   return(rates_total);
}

現段階でのファイル【Sample_Indicator_05_ema.mq4】をダウンロード
※途中段階なので変数 j が使用されていないという警告が出ます。

にゃんたにゃんた

今まで学んだことが、たった一行で。。

MACDを表示

Dr.EADr.EA

さて本題にいくぞーい (しれ~っと)

MACD表示の準備

MACDとMACDシグナルを表示させるように改変していきます。

パラメーター変数とインジケーター用配列として次のコードを追加します。

extern int  Signal_Period  = 9;        // MACDシグナルライン期間

double macd[];                         // MACD用配列
double macd_sig[];                     // MACDシグナル用配列

次に、OnInit()関数内で配列macd[]と配列macd_sig[]をインジケーターバッファ0番と1番に割り当てます。一方、EMA用の配列fast_ema[]とslow_ema[]は表示はしないがインジケーター用配列のようにローソク足本数分の要素数を自動的に持つようにしたいので、OnInit()関数内を次のようにします。

   IndicatorBuffers(4);                // インジケータ―用配列は4つ

   SetIndexBuffer(0, macd);            // 配列 macd[]をインジ用に割り当て
   SetIndexStyle(0, DRAW_LINE);        // 描画タイプをラインと定義
   SetIndexBuffer(1, macd_sig);        // 配列 macd_sig[]をインジ用に割り当て
   SetIndexStyle(1, DRAW_LINE);        // 描画タイプをラインと定義

   SetIndexBuffer(2, fast_ema);        // 配列 fast_ema[]をインジ用に割り当て
   SetIndexBuffer(3, slow_ema);        // 配列 slow_ema[]をインジ用に割り当て

IndicatorBauffers()関数に4を渡すことで、表示用配列2つに加えてさらに表示をしない2つのインジケーター用配列を割り当てることができるようになります。
インジケーター用配列2番3番にそれぞれ短期EMAと長期EMAの配列を割り当てます。

MACDとMACDシグナルを算出する

MACDは次の計算式で算出されます。

MACD = 短期EMA - 長期EMA

MACDシグナルはそのMACDの単純移動平均線です。
OnCalculate()関数のfor()分内に、次のコードを追加すれば完成です。

   macd[i] = fast_ema[i] - slow_ema[i];   // MACD
   if (i + Signal_Period <= Bars)         // MACDシグナル
   {
      macd_sig[i] = 0;
      for (j=0; j<Signal_Period; j++) macd_sig[i] += macd[i+j];
      macd_sig[i] /= Signal_Period;
   }

にゃんたにゃんた

ここで単純移動平均で学んだコードが出てきたにゃ!

Dr.EADr.EA

そうじゃよ(汗)
今回完成ファイルのコードがこちら

#property strict
#property indicator_separate_window
#property indicator_buffers 2          // 表示用インジケーターバッファ 2つ
#property indicator_color1 clrRed      // 1つ目の色 赤色
#property indicator_width1 2           // 1つ目の太さ 2
#property indicator_color2 clrYellow   // 2つ目の色 黄色
#property indicator_width2 2           // 2つ目の太さ 2

extern int  FastEMA_Period = 12;       // 短期EMAの期間
extern int  SlowEMA_Period = 26;       // 長期EMAの期間
extern int  Signal_Period  = 9;        // MACDシグナルライン期間

double macd[];                         // MACD用配列
double macd_sig[];                     // MACDシグナル用配列
double fast_ema[];                     // 短期EMA用配列
double slow_ema[];                     // 長期EMA用配列

//+------------------------------------------------------------------+
int OnInit()
{
   IndicatorBuffers(4);                // インジケータ―用配列は4つ
   
   SetIndexBuffer(0, macd);            // 配列 macd[]をインジ用に割り当て
   SetIndexStyle(0, DRAW_LINE);        // 描画タイプをラインと定義
   SetIndexBuffer(1, macd_sig);        // 配列 macd_sig[]をインジ用に割り当て
   SetIndexStyle(1, DRAW_LINE);        // 描画タイプをラインと定義
   
   SetIndexBuffer(2, fast_ema);        // 配列 fast_ema[]をインジ用に割り当て
   SetIndexBuffer(3, slow_ema);        // 配列 slow_ema[]をインジ用に割り当て
   
   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, j;
   int limit;
   if (prev_calculated == 0)              // 最初
      limit = rates_total - 1;               // 左端のローソク足から全部
   else                                   // それ以外
      limit = rates_total - prev_calculated; // ローソク足増加時「1」、通常「0」
   
   for (i=limit; i>=0; i--)               // limit本前から現在のローソク足を処理
   {
      fast_ema[i] = iMA(NULL, 0, FastEMA_Period, 0, MODE_EMA, PRICE_CLOSE, i);   // Fast EMA
      slow_ema[i] = iMA(NULL, 0, SlowEMA_Period, 0, MODE_EMA, PRICE_CLOSE, i);   // Slow EMA
      
      macd[i] = fast_ema[i] - slow_ema[i];   // MACD
      
      if (i + Signal_Period <= Bars)         // MACDシグナル
      {
         macd_sig[i] = 0;
         for (j=0; j<Signal_Period; j++) macd_sig[i] += macd[i+j];
         macd_sig[i] /= Signal_Period;
      }
   }
   
   return(rates_total);
}

今回の完成ファイル【Sample_Indicator_05.mq4】をダウンロード

あとがき

MACDとMACDシグナルはラインで正常に表示されましたか?
次回は、今回のMACDインジケーターファイルを編集して、見た目の整え方を解説したいと思います。

ではまた、次回をお楽しみに!