https://s3-us-west-2.amazonaws.com/secure.notion-static.com/75a6dbf4-aae5-43b3-8793-89ee83a55175/USDJPY_iDaily.png

上のチャートはモメンタムとそれを単純移動平均で平滑化した指標です。

このように既存のテクニカル指標や、独自のテクニカル指標を平滑化したい場合にもカスタム指標を利用できます。

従来MQL4には、[iMAOnArray()](<https://docs.mql4.com/indicators/imaonarray>)という関数が組み込まれており、適当なテクニカル指標を配列に格納したのち、その配列のデータを移動平均をかけることができました。

ところが、MQL5には同等の関数が用意されていないため、同じ方法が使えません。

そこで、MQL4、MQL5の組み込み関数ではありませんが、MT4、MT5をインストールすると標準でコピーされるMovingAverages.mqhという移動平均のライブラリファイルを使ってみることにします。

カスタム指標全体の設定

//MQL4互換ライブラリ(MQL5のみ)
#include "LibMQL4.mqh"
//移動平均ライブラリ
#include <MovingAverages.mqh>

#property indicator_separate_window    //別ウィンドウに表示
#property indicator_buffers 2          //指標バッファの数
#property indicator_plots 2            //表示させる指標バッファの数
#property indicator_type1 DRAW_LINE    //指標の種類
#property indicator_color1 clrGreen    //ラインの色
#property indicator_width1 2           //ラインの太さ
#property indicator_style2 STYLE_SOLID //ラインの種類
#property indicator_type2 DRAW_LINE    //指標の種類
#property indicator_color2 clrRed      //ラインの色
#property indicator_width2 1           //ラインの太さ
#property indicator_style2 STYLE_SOLID //ラインの種類

//指標バッファ用の配列の宣言
double Buf[], BufSmooth[];

input int MomPeriod = 10; //モメンタムの期間
input int Smooth = 5; //移動平均の期間

まず最初に、共通ライブラリの一部であるLibMQL4.mqhをインクルードします。これはMQL5の場合のみ必要です。#ifdef __MQL5__#endifで囲ってMQL5のみインクルードするようにします。

次にMQL4、MQL5共通でMovingAverages.mqhをインクルードします。このファイルはMT4、MT5のデータフォルダのMQL4\\Include、あるいは、MQL5\\Includeの下にインストールされているので確認しておいてください。

あとは、#properyで指標のプロパティの設定、指標バッファ用の配列の宣言、指標のパラメータの宣言となります。

初期化関数

int OnInit()
{
   //配列を指標バッファに関連付ける
   SetIndexBuffer(0, Buf);
   SetIndexBuffer(1, BufSmooth);
   //時系列配列に設定
   ArraySetAsSeries(Buf, true);
   ArraySetAsSeries(BufSmooth, true);
   //プロット開始位置の設定
   SetIndexDrawBegin(0, MomPeriod);
   SetIndexDrawBegin(1, MomPeriod+Smooth);
   return(INIT_SUCCEEDED);
}

他のカスタム指標と同様に、配列の指標バッファへの関連付け、時系列配列の設定、プロット開始位置の設定となります。

プロット開始位置は、モメンタムの場合、モメンタムの期間であるMomPeroidだけ、さらにそれを平滑化した指標の場合、MomPeriodと移動平均の期間Smoothを足した分だけずらしておきます。

指標計算関数

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 = rates_total - prev_calculated; //プロットするバーの数
   limit = MathMin(limit, rates_total-MomPeriod); //プロットの左端をずらす

   for(int i=0; i<limit; i++)
   {  //モメンタムの計算
      Buf[i] = iMomentum(_Symbol, 0, MomPeriod, PRICE_CLOSE, i);
      if(Buf[i] == EMPTY_VALUE) return 0;
   }
   
   //Buf[]の平滑化→BufSmooth[]
   SimpleMAOnBuffer(rates_total, prev_calculated, MomPeriod, Smooth, Buf, BufSmooth);
   
   return(rates_total-1);
}

この関数では、まず、[iMomentum()](<https://www.notion.so/iMomentum-42c456287b87423b93fd941ae332da4f>)を使ってモメンタムをBuf[]という配列に格納します。

次にSimpleMAOnBuffer()という関数を使ってBuf[]に入っているデータに単純移動平均をかけ、BufSmooth[]という配列に出力します。この関数は次のような書式として定義されています。

int SimpleMAOnBuffer(
   const int rates_total,    // チャート全体のバーの数
   const int prev_calculated,// 計算済みのバーの数
   const int begin,          // 計算を開始する位置
   const int period,         // 移動平均の期間
   const double& price[],    // 入力配列
   double& buffer[]          // 出力配列
);