【MQL5解説】MQL4とMQL5の違い!テクニカルインジケータ編【まずはここから】
MQL5記事の第一弾です。今後はMQL5に関しての記事も書いていきたいと思いますので、よろしくお願いします。
DiscordサーバーでもMQL5に対応し、質問は随時受付中です。
それでは本編に行きましょう!
テクニカルインジケータ関数の違い
MQL4でも沢山使用してきたiMA関数やiRSI関数は、MQL5では大きく変更が加えられています。
MQL4ではiMA関数などの戻り値はdouble型でしたが、MQL5ではint型になっています。
つまり、MQL5ではiMA関数などから直接インジケータの計算結果などを取得することができなくなりました。
恐らくこの時点でMQL5への意向を断念してしまった方が多いのではないでしょうか。
一度慣れてしまえばなにも問題ありませんので、是非こちらの記事を参考にしてください。
標準の関数(iMA, iBands)を使用する
テクニカルインジケータ関数は戻り値がdouble→int型に変更されています。またiBands関数などはラインインデックス(MODE_UPPERなど)の引数が消えています。
MQL4
double iMA(
string symbol, // 通貨ペア
int timeframe, // 時間軸
int ma_period, // 平均期間
int ma_shift, // MAのシフト
int ma_method, // MAの平均化メソッド
int applied_price, // 適用価格
int shift //シフト
);
double iBands(
string symbol, // 通貨ペア
int timeframe, // 時間軸
int period, // 平均期間
double deviation, // 標準偏差
int bands_shift, // バンドシフト
int applied_price, // 適用価格
int mode, //ラインインデックス
int shift //シフト
);
MQL5
int iMA(
string symbol, // 通貨ペア
ENUM_TIMEFRAMES timeframe, // 時間軸
int ma_period, // 平均期間
int ma_shift, // MAのシフト
int ma_method, // MAの平均化メソッド
ENUM_APPLIED_PRICE applied_price, // 適用価格
);
int iBands(
string symbol, // 通貨ペア
ENUM_TIMEFRAMES timeframe, // 時間軸
int period, // 平均期間
int bands_shift, // バンドシフト
double deviation, // 標準偏差
ENUM_APPLIED_PRICE applied_price, // 適用価格
);
MQL4ではこのように簡単にテクニカルインジケータの算出値を取得できます。
// 今足のMAの値を取得
double ma = iMA(Symbol(), Period(), 14, 0, MODE_SMA, PRICE_CLOSE, 0);
//今足のボリバン+2σの値取得
double bandsUpper = iBands(Symbol(), Period(), 14, 2, 0, PRICE_CLOSE, MODE_UPPER, 0);
しかし、MQL5で同じ要領でテクニカルインジケータ関数を使用すると謎の整数が取得されます。これを「指標ハンドル」と呼びます。
// MAの指標ハンドルを取得
int maHandle = iMA(Symbol(), Period(), 14, 0, MODE_SMA, PRICE_CLOSE);
// ボリバンの指標ハンドルを取得
double bandsHandle = iBands(Symbol(), Period(), 14, 0, 2, PRICE_CLOSE);
指標ハンドルとはなにか?
凄く簡単に説明すると、「私(EA)はこのパラメータを設定したテクニカルインジケータを使用します!」という宣言のようなものです。
MQL4ではテクニカルインジケータ関数は値を取得するためにOnTick関数等で使用しましたが、MQL5ではあくまでも使用する宣言なのでOnInit関数内に記述します。
int maHandle, bandsHandle;
void OnInit(){
// 期間14のSMAを使用すると宣言
maHandle = iMA(Symbol(), Period(), 14, 0, MODE_SMA, PRICE_CLOSE);
// 期間14で偏差2のボリバンを使用すると宣言
bandsHandle = iBands(Symbol(), Period(), 14, 0, 2, PRICE_CLOSE);
return(INIT_SUCCEEDED);
}
※ここではシフトやラインインデックス(MODE_UPPERなど)は指定しません。後ほど解説します。
次は実際に算出された数値を格納する配列を用意し、CopyBuffer関数を使用して格納していきます。
int maHandle, bandsHandle;
double maBuf[];
double bandsUpperBuf[];
double bandsLowerBuf[];
void OnInit(){
// 指標ハンドル(省略)
}
void OnTick(){
CopyBuffer(maHandle, 0, 0, 10, maBuf);
CopyBuffer(bandsHandle, UPPER_BAND, 0, 10, bandsUpperBuf);
CopyBuffer(bandsHandle, LOWER_BAND, 0, 10, bandsLowerBuf);
}
CopyBuffer関数は3つの使用パターンが用意されています。今回は1番目の方法を採用しています。
以下の3つの例は全て同じ結果になります。
// 1, 最新の足(0)から過去10本分を取得する
CopyBuffer(maHandle, 0, 0, 10, maBuf);
// 2, 指定した日付時刻から過去10本分を取得する
CopyBuffer(maHandle, 0, iTime(Symbol(), Period(), 0), 10, maBuf);
// 3, 日付時刻で範囲を指定して取得
CopyBuffer(maHandle, 0, iTime(Symbol(), Period(), 10), iTime(Symbol(), Period(), 0), maBuf);
また、MQL4でのラインインデックスの指定はMQL5ではCopyBuffer関数内で行います。
ボリンジャーバンドの+σは、MODE_UPPERからUPPER_BANDから名称が変更されているように、全般的にラインインデックスの定数名が変更されているので注意が必要です。詳しくは公式リファレンス参照
ここまで行うことで初めてMAやボリンジャーバンドの数値を使用できるようになりました。配列に過去10本分の値が格納されていますので、いつも通りmaBuf[0], bandsUpperBuf[0]のように使用できると思いきや、、、ここで最後の微調整が必要です。
// MQL4 最新の足の値
double ma = iMA(Symbol(), Period(), 14, 0, MODE_SMA, PRICE_CLOSE, 0);
//MQL5 配列内の一番古い値
double ma = maBuf[0]
上のように、MQL4ではシフトを0に指定することで最新足の情報を取得することができます。
しかし、MQL5でCopyBuffer実行直後の配列は0は一番古いデータになります。今回の場合は10本前の値です。
このままでは紛らわしいので、最後に配列の中身を逆順に入れ替えましょう。
void OnTick(){
CopyBuffer(maHandle, 0, 0, 10, maBuf);
CopyBuffer(bandsHandle, UPPER_BAND, 0, 10, bandsUpperBuf);
CopyBuffer(bandsHandle, LOWER_BAND, 0, 10, bandsLowerBuf);
ArraySetAsSeries(maBuf, true);
ArraySetAsSeries(bandsUpperBuf, true);
ArraySetAsSeries(bandsLowerBuf, true);
Print("現在のMA = " + maBuf[0]);
Print("前足の+σ = " + bandsUpperBuf[1]);
Print("2本前のの-σ = " + bandsLowerBuf[2]);
}
ArraySetAsSeries関数を使用し、0番目が一番最新の値になるように入れ替えました。
これでmaBuf[0]と指定することでMAの最新の値を取得できるようになります。
最後にOnDeinit関数でメモリを解放します。理由は割愛しますが、処理速度低下などの恐れがあるので忘れずに記述します。
void OnDeinit(){
IndicatorRelease(maHandle);
IndicatorRelease(bandsHandle);
}
全体のプログラムはこちら
int maHandle, bandsHandle;
double maBuf[];
double bandsUpperBuf[];
double bandsLowerBuf[];
void OnInit(){
// 期間14のSMAを使用すると宣言
maHandle = iMA(Symbol(), Period(), 14, 0, MODE_SMA, PRICE_CLOSE);
// 期間14で偏差2のボリバンを使用すると宣言
bandsHandle = iBands(Symbol(), Period(), 14, 0, 2, PRICE_CLOSE);
}
void OnTick(){
CopyBuffer(maHandle, 0, 0, 10, maBuf);
CopyBuffer(bandsHandle, UPPER_BAND, 0, 10, bandsUpperBuf);
CopyBuffer(bandsHandle, LOWER_BAND, 0, 10, bandsLowerBuf);
ArraySetAsSeries(maBuf, true);
ArraySetAsSeries(bandsUpperBuf, true);
ArraySetAsSeries(bandsLowerBuf, true);
Print("現在のMA = " + maBuf[0]);
Print("前足の+σ = " + bandsUpperBuf[1]);
Print("2本前のの-σ = " + bandsLowerBuf[2]);
}
void OnDeinit(){
IndicatorRelease(maHandle);
IndicatorRelease(bandsHandle);
}
標準ライブラリ(CiMA, CiBands)を使用する
MQL5に搭載されているCTrade標準ライブラリでは、テクニカルインジケータ関数がよりMQL4ライクにプログラムできる関数が用意されてします。
非常に便利で強力なのですが、MQL5の特徴的な書き方にも慣れていく必要はあるので、まずは前章の標準関数をマスターしてから使用することをお勧めします。
まず初めに標準ライブラリをIncludeします。使用するインジケータのタイプによってファイルが分かれています。
#include <Indicators\Trend.mqh>
#include <Indicators\Oscilators.mqh>
#include <Indicators\Volumes.mqh>
#include <Indicators\BillWilliams.mqh>
CiMA ma;
CiBands bands;
今回はMAとボリンジャーバンドを使用したいので、Trend.mqhのみ読み込めば問題ありません。
その後は使用したいインジケータのクラスを呼び出し、オブジェクトを作成します。
次に、インジケータのパラメータを設定します。設定するタイミングはOnInit関数で一度だけ行います。
int OnInit(){
ma.Create(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE);
bands.Create(Symbol(), Period(), 14, 0, 2, PRICE_CLOSE);
return(INIT_SUCCEEDED);
}
ここまで来ると、後はMQL4のようにバーシフトを指定するだけでテクニカルインジケータの算出値が取得できるようになります。
取得をする前には必ずRefreshメソッドを実行し、数値を最新の情報に更新します。
また、作成したオブジェクトのメソッド(MainやUpperの部分)で取得したいラインを指定します。ボリンジャーバンドであればUpperで+σ, Lowerで-σになります。
void OnTick(){
// 必ずRefreshで最新の情報に更新
ma.Refresh();
bands.Refresh();
Print("現在のMA = " + ma.Main(0));
Print("前足の+σ = " + bands.Upper(1));
Print("2本前の-σ = " + bands.Lower(2));
ラインのメソッドは公式リファレンスを随時確認しながらプログラムを行いましょう。
データアクセスメソッドの部分が指定できるメソッドの一覧です。例としてボリンジャーバンドであればこのように記載されています。
全体のプログラムはこちら
#include <Indicators\Trend.mqh>
CiMA ma;
CiBands bands;
int OnInit(){
ma.Create(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE);
bands.Create(Symbol(), Period(), 14, 0, 2, PRICE_CLOSE);
return(INIT_SUCCEEDED);
}
void OnTick(){
ma.Refresh();
bands.Refresh();
Print("現在のMA = " + ma.Main(0));
Print("前足の+σ = " + bands.Upper(1));
Print("2本前の-σ = " + bands.Lower(2));
}