https://s3-us-west-2.amazonaws.com/secure.notion-static.com/dc99299e-2d30-4b96-b243-6e74f029266f/USDJPY_iM15.png

通常、チャートにテクニカル指標を挿入すると、チャートと同じタイムフレームのテクニカル指標が表示されます。別のタイムフレームのテクニカル指標を表示させたい場合、どうすればいいでしょうか?

例えば、上のチャートのように15分足のチャートに1時間足のRSIを表示させる場合などです。

このようにチャートのタイムフレームと異なるタイムフレームのテクニカル指標(マルチタイムフレーム指標)を表示させたい場合も、カスタム指標を利用することができます。

カスタム指標全体の設定

//MQL4互換ライブラリ(MQL5のみ)
#include "LibMQL4.mqh"

#property indicator_separate_window    //サブウィンドウに表示
#property indicator_buffers 1          //指標バッファの数
#property indicator_plots 1            //表示する指標バッファの数
#property indicator_type1 DRAW_LINE    //指標の種類
#property indicator_color1 clrRed      //ラインの色
#property indicator_width1 2           //ラインの太さ
#property indicator_style1 STYLE_SOLID //ラインの種類

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

MQL5の場合のみ、共通ライブラリの一部であるLibMQL4.mqhをインクルードします。

#properyでの指標のプロパティの設定、指標バッファ用の配列の宣言は、他のカスタム指標と同じです。

初期化関数

input int RSIPeriod = 10; //RSIの期間
input ENUM_TIMEFRAMES TF = 0; //タイムフレーム

//TF1本のバーの数
int TFBars = 1;

//初期化関数
int OnInit()
{
   //配列を指標バッファに関連付ける
   SetIndexBuffer(0, Buf);
   //時系列配列に設定
   ArraySetAsSeries(Buf, true);
   //プロット開始位置の設定
   TFBars = PeriodSeconds(TF)/PeriodSeconds()+1;
   SetIndexDrawBegin(0, TFBars*RSIPeriod);
   return(INIT_SUCCEEDED);
}

ここでは、RSIをマルチタイムフレームに対応させるので、RSIのパラメータRSIPeriodと、RSIを適応させるタイムフレームTFを宣言します。

もう一つTFBarsという変数を宣言していますが、これはTFのタイムフレームの1本分のバーがチャートのタイムフレームの何本分のバーに相当するかを表したものです。指標のプロット位置の計算などで利用します。

OnInit()で、配列への指標バッファの関連付け、時系列配列の設定は、他のカスタム指標と同様です。

プロット開始位置は、通常、RSIの期間RSIPeriodだけずらしますが、ここでは、TFBarsを掛けた期間だけずらします。

例えば、TFが1時間足、チャートが15分足の場合、PeriodSeconds()より、TFBarsは60/15+1=5となります。RSIPeriod10の場合、5*10=50バーだけずらした位置から指標がプロットされることになります。

指標計算関数

//指標計算関数
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[])
{
   //時系列配列に設定
   ArraySetAsSeries(time, true);

   int limit = rates_total - prev_calculated; //プロットするバーの数
   limit = MathMin(MathMax(limit, TFBars), rates_total-TFBars*RSIPeriod); //プロットの左端をずらす
   
   for(int i=0; i<limit; i++)
   {
      Buf[i] = iRSI(_Symbol, TF, RSIPeriod, PRICE_CLOSE, iBarShift(_Symbol, TF, time[i]));
      if(Buf[i] == EMPTY_VALUE) return 0;
   }
   return(rates_total-1);
}

OnCalculate()では、基本的にBuf[]という配列に、表示させたいマルチタイムフレームRSIの値を格納します。

RSIの算出には、[iRSI()](<https://www.notion.so/iRSI-RSI-bc693f49d32f47428e65b762a2593cc7>)という関数を使います。従来と異なるのが、2番目の引数にタイムフレームを表す変数TFを代入する点と、最後のshiftの引数に[iBarShift()](<https://www.mql5.com/ja/docs/series/ibarshift>)という関数を使う点です。

[iBarShift()](<https://www.mql5.com/ja/docs/series/ibarshift>)は、3番目の引数に指定した時刻が、別のシンボル(最初の引数)、タイムフレーム(2番目の引数)のチャート上でどの位置に対応するかを表した関数です。つまり、指標を表示させるのはこのチャートなので、チャート上の時刻はtime[i]で変化していきますが、実際にRSIを計算するのはタイムフレームがTFのチャートなので、[iRSI()](<https://www.notion.so/iRSI-RSI-bc693f49d32f47428e65b762a2593cc7>)のパラメータをそちらのチャートに合わせる必要があるのです。