MTFインジケーターのサンプルコードをそのままメタエディタにコピペしたのに、「’Current’ – undeclared identifier」のようなエラーが出てコンパイルできなかった——という人向けの記事です。

原因は、パラメーターのデフォルト値にMQL4には存在しない名前が使われていたことです。この記事では、どこが間違っていたか、正しくはどう書けばよいかを説明しながら、実際にコンパイルできる完全なMTF移動平均線インジケーターのコードを紹介します。

MTF(マルチタイムフレーム)で移動平均線を表示するインジケーター

MTFとはマルチタイムフレームの略語で、

ある時間軸の移動平均線を違う時間軸のチャートに表示できるインジケーターです。

MTFインジケーターを活用することで、

下位足を表示させていても上位足の状況を判断することができるといった優れものです。

今回は、MTFで移動平均線を表示するインジケーターを作成していきます。

メタエディタ(MetaEditor)を立ち上げる

メタエディタ(MetaEditor)を立ち上げましょう。今回は名前を「MTF-Ma」で作成します。

プロパティを記述する

プロパティを記述しましょう。バッファはラインを表示させるだけなので1です。

#property indicator_buffers 1//バッファ1

線に設定します。

#property indicator_type1 DRAW_LINE//線

色を水色に設定します。

#property indicator_color1 clrAqua//色

線の種類を実線にします。

#property indicator_style1 STYLE_SOLID//実線

幅を1にします。

#property indicator_width1 1//幅

これでプロパティの記述は完了です。

#property indicator_buffers 1//バッファ1
#property indicator_type1 DRAW_LINE//線
#property indicator_color1 clrAqua//色
#property indicator_style1 STYLE_SOLID//実線
#property indicator_width1 1//幅
Copy

バッファを定義する

バッファを定義しましょう。

double ma[];//バッファ

これでバッファの定義は完了です。

double ma[];//バッファ
Copy

OnInit()関数を記述する

OnInit()関数を記述しましょう。

インデックス0にmaを格納します。

SetIndexBuffer(0, ma);//インデックス0にmaを格納

ラベルを表示させます。

SetIndexLabel(0, StringFormat("MA(%d) [%s]", MaPeriod, EnumToString(TimeFrame)));//ラベル

これでOnInit()関数の記述は完了です。

SetIndexBuffer(0, ma);//インデックスにmaを格納
SetIndexLabel(0, StringFormat("MA(%d) [%s]", MaPeriod, EnumToString(TimeFrame)));//ラベル
Copy

パラメーターを記述する

パラメーターを記述しましょう。

TimeFrameは対象の時間軸を指定します。今回は現在の時間軸を対象にするのでPERIOD_CURRENTにします。

input ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT;//対象の時間軸

MAの期間を21に指定します。

input int MaPeriod = 21;//期間

シフトは0に指定します。

input int MaShift = 0;//シフト

MAの種類は単純移動平均MODE_SMAに指定します。

input ENUM_MA_METHOD MaMethod = MODE_SMA;//種類

適正価格は終値PRICE_CLOSEに指定します。

input ENUM_APPLIED_PRICE MaAppliedPrice = PRICE_CLOSE;//適正価格

これでパラメーターの記述は完了です。

input ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT;//対象の時間軸
input int MaPeriod = 21;//期間
input int MaShift = 0;//シフト
input ENUM_MA_METHOD MaMethod = MODE_SMA;//種類
input ENUM_APPLIED_PRICE MaAppliedPrice = PRICE_CLOSE;//適正価格
Copy

「Current」「simple」「ClosePrice」は存在しない

このパラメーターは、書き方を間違えるとコンパイルが通らない代表的な箇所です。ENUM_TIMEFRAMES・ENUM_MA_METHOD・ENUM_APPLIED_PRICEは、それぞれMQL4があらかじめ用意した決まった名前の定数しか使えません。

  • 対象の時間軸を「現在の足」にしたい場合はCurrentではなくPERIOD_CURRENT
  • 単純移動平均にしたい場合はsimpleではなくMODE_SMA(他に指数平滑=MODE_EMA、平滑化=MODE_SMMA、線形加重=MODE_LWMA)
  • 終値を使いたい場合はClosePriceではなくPRICE_CLOSE(他に始値=PRICE_OPEN、高値=PRICE_HIGH、安値=PRICE_LOW)

「わかりやすい英語」で書きたくなる気持ちは自然ですが、MQL4では定義されていない単語を使うと、コンパイル時に「’○○’ – undeclared identifier」というエラーになります。エラーが出たら、まずこの3種類の定数名を疑ってみてください。

OnCalculateを記述する

OnCalculateを記述しましょう。

iBarShift()関数は、指定した通貨ペア・時間軸・日時におけるバーの位置を取得するために使用します。

int shift_need_recalculate = iBarShift(NULL, Period(), iTime(NULL, TimeFrame, 0));

rate_totalとはインジケーターが持っている配列の要素数です。

チャートに新しいバーが出るたびに1つずつ増えていきます。最初はチャートのバー本数と一致します。

rate_totalがshift_need_recalculateよりも低ければ、return0で返します。

if (rates_total <= shift_need_recalculate)
{
   return 0;
}

prev_calculatedはrate_totalに対してすでに計算済みの要素数を指定します。

ただし、実際にはOnCalculateを呼び出した際のreturnの値が格納されています。

まだ一度も呼び出されていない場合は0です。

rates_totalからprev_calculatedを引いているので現在の最新のバーが残ります。

int num_uncalculated = rates_total - prev_calculated;

MathMaxで

  • shift_need_recalculate
  • num_uncalculated – 1

の2つの値の最大値を返します。その値を初期値iに代入して、for文で0になるまでループさせます。

for (int i = MathMax(shift_need_recalculate, num_uncalculated - 1); i >= 0; i--)

iBarShiftでtime[i]をshiftに代入します。

shiftをiMA関数のシフトの引数にしてma[i]に代入します。

int shift = iBarShift(NULL, TimeFrame, time[i]);
ma[i] = iMA(NULL, TimeFrame, MaPeriod, MaShift, MaMethod, MaAppliedPrice, shift);

OnCalculateはこれで完了です。

int shift_need_recalculate = iBarShift(NULL, Period(), iTime(NULL, TimeFrame, 0));

if (rates_total <= shift_need_recalculate)
{
   return 0;
}
int num_uncalculated = rates_total - prev_calculated;
for (int i = MathMax(shift_need_recalculate, num_uncalculated - 1); i >= 0; i--)
{
    int shift = iBarShift(NULL, TimeFrame, time[i]);
    ma[i] = iMA(NULL, TimeFrame, MaPeriod, MaShift, MaMethod, MaAppliedPrice, shift);
}
Copy

元記事のこの部分には全角スペースによるインデントが混ざっていましたが、上のコードでは半角スペースに統一しています。MQL4は全角スペース・全角文字を使うとエラーになるため、コピペする際は貼り付け先のエディタで全角文字が紛れ込んでいないか確認してください。

コンパイルする

コンパイルして、移動平均線の上位足を下位足にセットすれば表示されます。

MQL インジケーター MTF 移動平均線を表示

ソースコード全体

MTF-Maのソースコード全体は以下に記載しています。存在しない定数を正しいものに修正し、全角スペースも半角に統一した、そのままコンパイルできる完全版です。

//+------------------------------------------------------------------+
//|                                                       MTF-Ma.mq4 |
//|                     Copyright 2020, FX-EA System Project Creator |
//|                        https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, FX-EA System Project Creator"
#property link      "https://creator.fx-ea-system-project.com/"
#property version   "1.01"
#property strict

/*プロパティ*/
#property indicator_chart_window//メインウィンドウ
#property indicator_buffers 1//バッファ1
#property indicator_type1 DRAW_LINE//線
#property indicator_color1 clrAqua//色
#property indicator_style1 STYLE_SOLID//実線
#property indicator_width1 1//幅

/*バッファ*/
double ma[];//バッファ

/*パラメーター*/
input ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT;//対象の時間軸
input int MaPeriod = 21;//期間
input int MaShift = 0;//シフト
input ENUM_MA_METHOD MaMethod = MODE_SMA;//種類
input ENUM_APPLIED_PRICE MaAppliedPrice = PRICE_CLOSE;//適正価格

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
    SetIndexBuffer(0, ma);//インデックス0にmaを格納
    SetIndexLabel(0, StringFormat("MA(%d) [%s]", MaPeriod, EnumToString(TimeFrame)));//ラベル
//---
   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 shift_need_recalculate = iBarShift(NULL, Period(), iTime(NULL, TimeFrame, 0));

   if(rates_total <= shift_need_recalculate)
     {
      return 0;
     }
   int num_uncalculated = rates_total - prev_calculated;
   for(int i = MathMax(shift_need_recalculate, num_uncalculated - 1); i >= 0; i--)
     {
      int shift = iBarShift(NULL, TimeFrame, time[i]);
      ma[i] = iMA(NULL, TimeFrame, MaPeriod, MaShift, MaMethod, MaAppliedPrice, shift);
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
Copy

まとめ

MTFは独特な考え方が必要で難易度が高くなりますが、

考え方さえわかってしまえば他にもMTFは応用が可能です。

MTFのインジケーターは非常に重要なのでぜひマスターしておきましょう。

関連記事