MQLプログラミング言語でマルチタイムフレームを表示する方法
別の時間足の移動平均線を表示
この記事では、マルチタイムフレームについて説明していきます。マルチタイムフレームとは、チャートに表示されている時間足とは別の時間足の情報で計算した結果を表示する機能です。
改修の元とするファイルは、「MQLプログラミング言語でチャートに移動平均線を表示する方法」という記事で作り、「MQLプログラミング言語で移動平均線を作成する方法」で機能を追加した「MA_demo_step2-1」です。単純に移動平均線を表示するだけのものですが、こちらに変更を加えていきます。
参考記事:MQLプログラミング言語で移動平均線を作成する方法
まずファイル名を「MTF_MA_demo」に変更して保存したあと、時間足を指定するためにパラメーターを追加します。今回は列挙型の「ENUM_TIMEFRAMES」を使います。ここでは1時間足を初期設定で指定します。
input ENUM_TIMEFRAMES TIMEFRAME = PERIOD_H1; // 時間足
次に、作ったパラメーターをOnCalculate関数配下の時間足を指定するところに貼り付けます。
MABuffer[i] = iMA(NULL, TIMEFRAME, PERIOD, SHIFT, METHOD, PRICE, i );
これで一旦コンパイルして15分足にセットします。そのチャートと、改修前の「MA_demo_step2-1」を1時間足にセットしたものを比べてみます。次の画像は、上が1時間足と改修前のMA、下が15分足と改修後のMAです。時間軸が異なるものの、移動平均線の形が同じで、1時間足の情報を利用していることが分かります。
時間情報等を補正
上記手順で、表示する移動平均線の時間足を変えることができました。しかし、このままでは時間情報等がずれていて正しく表示されないので、補正を行う必要があります。そこで利用するのが、ローソク足の位置の補正をするための関数として用意されている「iBarShift」です。これをOnCalculate関数配下のfor文の下に組み込み、iMA関数のカッコ内の「i」のところをiBarShiftで計算される「bar」に書き換えます。
for (int i = limit; i >= 0; i--) {
int bar = iBarShift(NULL, TIMEFRAME, Time[i]);
MABuffer[i] = iMA(NULL, TIMEFRAME, PERIOD, SHIFT, METHOD, PRICE, bar );
}
iBarShift関数の設定項目 | |
---|---|
symbol | 通貨ペア名を指定 |
timeframe | 時間足を指定 |
time | 検索する時間の値を指定 |
exact | 指定されたバーが見つからない場合の戻り値を指定 |
iBarShift関数のパラメーター設定に関しては、通貨ペアは表示しているものを使うので「NULL」、時間足は「TIMEFRAME」、時間は表示中のチャートのローソク足の時間を使いたいのでTime配列の「i」とします。もう一つ、バーが存在しなかった場合の戻り値に関するパラメーターがありますが、こちらは初期設定の「false」のままで問題ありません。初期設定の値を利用する場合は省略することも可能です。
このパラメーターを「false」とした場合は、指定した時間のバーが存在しなければ一番近いバーのシフト数が返されます。一方「true」とした場合、指定した時間のバーが存在しなければ「-1」という値が返されるようになります。
以上の設定でコンパイルすれば、15分足のチャートに1時間足の移動平均線を再現できます。
最低限計算するバーの本数を修正
移動平均線のマルチタイムフレーム表示の見た目は完成しました。しかし、1回目の計算ではチャート全体のバーを計算するのに対し、それ以降は最小限のバーの本数だけしか計算しないようになっているので、上位足の情報を使っている場合に計算が不足する場合があります。例えば、15分足で1時間足の情報を使っていると4本分のバーが未確定になる可能性があるということです。そこで、不足することなく再計算が行われるように改修していきます。
まずOnCalculate関数配下のif文の上に整数型で「min」を一つ定義し、1本の足の秒数を示す「PeriodSeconds」のカッコ内で時間足を指定します。そして、その指定した時間足の秒数を現在表示中の足の時間で割って求めた値を、if文内で最小限計算するバーの本数として指定します。最低1番から0番の足まで計算するように「1」としていたところを、「min」に変更すれば完了です。
int min = PeriodSeconds(TIMEFRAME) / PeriodSeconds();
if (limit < min) limit = min;
そしてもう一つ改修を加えます。指定した時間足が下位足の場合、あまり意味のない計算になるので、その場合は計算をしないようにif文を設定します。
if (_Period > TIMEFRAME && TIMEFRAME != PERIOD_CURRENT) return -1;
int limit = Bars - IndicatorCounted() - 1;
int min = PeriodSeconds(TIMEFRAME) / PeriodSeconds();
if (limit < min) limit = min;
「_Period」とは現在の時間足を示し、それがTIMEFRAMEより大きいときは、そこで計算を終わりにするということを表します。また、「PERIOD_CURRENT」は現在表示中の足のことで、値は0です。この場合も条件が成立して動かなくなってしまうので除きます。これで完成です。
ソースコード
今回、作成したソースコードは下記の通りです。
//+------------------------------------------------------------------+
//| MTF_MA_demo.mq4 |
//| Copyright 2020, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1
//--- parameters
input ENUM_TIMEFRAMES TIMEFRAME = PERIOD_H1; // 時間足
input int PERIOD = 20; // 期間
input int SHIFT = 0; // シフト
input ENUM_MA_METHOD METHOD = MODE_SMA; // MA種別
input ENUM_APPLIED_PRICE PRICE = PRICE_CLOSE; // 適用価格
input color CLR = clrWhite; // 色
input ENUM_LINE_STYLE STYLE = STYLE_SOLID; // 線種
input int WIDTH = 1; // 太さ
//--- indicator buffers
double MABuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
SetIndexBuffer(0, MABuffer);
SetIndexStyle (0, DRAW_LINE, STYLE, WIDTH, CLR);
SetIndexLabel(0, "MA");
//---
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[])
{
//---
if (_Period > TIMEFRAME && TIMEFRAME != PERIOD_CURRENT) return -1;
int limit = Bars - IndicatorCounted() - 1;
int min = PeriodSeconds(TIMEFRAME) / PeriodSeconds();
if (limit < min) limit = min;
for (int i = limit; i >= 0; i--) {
int bar = iBarShift(NULL, TIMEFRAME, Time[i]);
MABuffer[i] = iMA(NULL, TIMEFRAME, PERIOD, SHIFT, METHOD, PRICE, bar );
}
//--- return value of prev_calculated for next call
return rates_total;
}
//+------------------------------------------------------------------+
本記事の監修者・HT FX
2013年にFXを開始し、その後専業トレーダーへ。2014年からMT4/MT5のカスタムインジケーターの開発に取り組む。ブログでは100本を超えるインジケーターを無料公開。投資スタイルは自作の秒足インジケーターを利用したスキャルピング。
本ホームページに掲載されている事項は、投資判断の参考となる情報の提供を目的としたものであり、投資の勧誘を目的としたものではありません。投資方針、投資タイミング等は、ご自身の責任において判断してください。本サービスの情報に基づいて行った取引のいかなる損失についても、当社は一切の責を負いかねますのでご了承ください。また、当社は、当該情報の正確性および完全性を保証または約束するものでなく、今後、予告なしに内容を変更または廃止する場合があります。なお、当該情報の欠落・誤謬等につきましてもその責を負いかねますのでご了承ください。