インジケーター作成04

指数平滑移動平均線(EMA)を追加して2本のラインを表示させてみよう!

ここでは、前回完成した単純移動平均線を表示させるインジケーターに指数平滑移動平均線(EMA)を追加して2本のラインを表示させるようにカスタマイズする方法を解説します。

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

前回記事のおさらい

前回記事では、単純移動平均線を表示させるインジケーターを作成しました。

Dr.EADr.EA

前回記事 インジケーター作成3【単純移動平均線】で完成したファイルのコードがこちら

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

extern int  SMA_Period  = 10;          // SMAの期間

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

//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0, buf);             // 配列 buf[]をインジケーター用に割り当てる
   SetIndexStyle(0, 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本前から現在のローソク足を処理
   {
      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;
      }
   }
   
//--- return value of prev_calculated for next call
   return(rates_total);
}

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

EMAを追加する

インジケーター用配列を追加

「#property」で始まる部分で、表示用インジケーターバッファを2つに変更します。

#property indicator_buffers 2

2本目のライン(EMAライン)の色と太さの初期設定を指定するため、次のコード追加します。

#property indicator_color2 clrYellow   // 2つ目の色 黄色
#property indicator_width2 2           // 2つ目の太さ 2

そして、前回記事でのSMA用のパラメーターと配列の宣言と同じように、EMA用の期間を指定するパラメーター「EMA_Period」とインジケーター用配列にする配列 ema[]を次のように追加します。

extern int  EMA_Period  = 20;
double ema[];

OnInit()関数内に次のコードを追加して、インジケーターバッファ1番に配列 ema[]を割り当て、描画タイプの設定をします。

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

EMAの計算式

指数平滑移動平均線(EMA)は、はじまりを単純移動平均で計算して、その後からは次の式で算出します。

EMA = (前回EMA × (期間-1) + 今回終値 × 2) ÷ (期間+1)

「前回EMA少なめ、終値増しで。」って感じですね。

EMAの計算式をコード化する

OnCalculate()関数内のfor()文内で算出開始のシフト数にも気を付けて、EMAの計算式を次のようにコード化します。

   if (i + EMA_Period - 1 <= Bars - 1)
   {
      if (i + EMA_Period - 1 == Bars - 1) // 最初はSMAで算出
      {
         ema[i] = 0;
         for (j=0; j<EMA_Period; j++) ema[i] += Close[i+j];
         ema[i] /= EMA_Period;
      }
      else // その後は前回EMAと終値で算出
      {
         ema[i] = ema[i+1] * (EMA_Period - 1) + Close[i] * 2;
         ema[i] /= EMA_Period + 1;
      }
   }

MT4のEMAと同じにする

MetaTrader4のインジケーター「Moving Average」でEMAを表示させると、ラインの始まり方が先ほど計算したEMAのライン表示と異なります。

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;
   }

意外とシンプルになりましたね。

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;
      }
      
      /*
      // 一般的なEMA
      if (i + EMA_Period - 1 <= Bars - 1)
      {
         if(i + EMA_Period - 1 == Bars - 1) // 最初はSMAで算出
         {
            ema[i] = 0;
            for (j=0; j<EMA_Period; j++) ema[i] += Close[i+j];
            ema[i] /= EMA_Period;
         }
         else // その後は前回EMAと終値で算出
         {
            ema[i] = ema[i+1] * (EMA_Period - 1) + Close[i] * 2;
            ema[i] /= EMA_Period + 1;
         }
      }
      */
      
      // 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】をダウンロード

あとがき

追加した指数平滑移動平均線EMAは正常に表示されましたか?
今回と同様の手順で3本目のラインやさらに多くのラインを追加していけるのでぜひ挑戦してみてください。

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