こんにちは、潤奈です( ゚Д゚)!
これまでの連載で、「自動注文(エントリー)」と「ポジション決済」というEAの基本動作をマスターしてきました。
今回は、EAが売買判断を下すために絶対に欠かせない「インジケーター(移動平均線やRSIなど)の数値をプログラム内で取得する方法」を解説します!
実は、MQL4からMQL5へ移行した人が最も驚き、そして挫折しやすいのが、この「インジケーター値の取得方法」です。
MQL4では非常に手軽に1行で書けた処理が、MQL5では全く異なるアプローチが必要になります。
最初は「ちょっと面倒だな…」と感じるかもしれませんが、仕組みを理解してしまえばテンプレート化できますし、動作スピードも劇的に向上します。今回もコピペで動くサンプルコード付きで、分かりやすく解説しますね!
1. MQL5のインジケーター値取得はなぜ難しい?(MQL4との比較)
まず、MQL4とMQL5でコードがどれくらい違うのかを比較してみましょう。
移動平均線(SMA14)の「1本前の値」を取得したい場合、MQL4では以下のように関数を1回呼び出すだけでその場の数値が直接返ってきました。
|
1 2 |
// MQL4での取得方法(シンプル!) double maValue = iMA(Symbol(), 0, 14, 0, MODE_SMA, PRICE_CLOSE, 1); |
一方、MQL5で同じことをやろうとすると、以下の「3つのステップ」を踏む必要があります。
- インジケーターの登録証(ハンドル)を発行する
- 数値を格納する配列を用意し、時系列順(最新の足が0番目)に並べ替える
- 登録証を使って、配列の中にデータをコピーする
MQL5では、iMA などの関数を実行しても直接数値は返ってこず、代わりに「ハンドル」と呼ばれる整理番号(ID)が返ってきます。このハンドルを使って、後から必要な時だけデータを引っ張ってくる(コピーする)という仕組みになっています。
なぜこんな面倒な仕様になったかというと、「動作を圧倒的に軽くするため」です。
MQL4の書き方は手軽でしたが、毎回のチックでインジケーターを丸ごと計算し直すため動作が重くなりがちでした。MQL5の仕様なら、初期化の段階で登録を済ませておくため、PCやサーバーにかかる負荷を激減させることができます。
2. インジケーター値を取得する「3つのステップ」
それでは、具体的な書き方を3ステップで順に解説します。
ステップ①:インジケーターの「ハンドル」を取得する
まずは、プログラム起動時(OnInit()内)で、使いたいインジケーターのハンドルを作成し、グローバル変数に保存しておきます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
int maHandle; // ハンドルを保存する変数 int OnInit() { // 移動平均線のハンドルを作成(期間14、シフト0、単純移動平均、終値基準) maHandle = iMA(_Symbol, _Period, 14, 0, MODE_SMA, PRICE_CLOSE); // ハンドルの作成に失敗した(INVALID_HANDLEが返ってきた)場合の処理 if(maHandle == INVALID_HANDLE) { Print("インジケーターハンドルの作成に失敗しました。"); return(INIT_FAILED); } return(INIT_SUCCEEDED); } |
ステップ②:格納用の配列を「時系列順」に設定する
次に、取得した値を保存するための double 型の配列を用意します。
EAを動かすチック処理の中で毎回配列の並び順を設定するのは無駄があるため、グローバル領域で配列を宣言し、OnInit() 内で ArraySetAsSeries() を1回だけ設定しておくのが、動作を軽くするためのMQL5のベストプラクティスです。
|
1 2 3 4 5 6 7 8 9 |
double maValues[]; // 値を格納するグローバル配列 int OnInit() { // 配列の並び順を時系列(最新の足がインデックス0)に設定 ArraySetAsSeries(maValues, true); return(INIT_SUCCEEDED); } |
これを設定しておかないと、MQL4で馴染みのあった「[0] が最新の足、[1] が1本前の足」という指定ができなくなり、直感的ではない処理になってしまいます。
ステップ③:CopyBuffer でデータを配列にコピーする
最後に、OnTick() 内などで CopyBuffer() 関数を呼び出し、ハンドルから配列へ数値をコピーします。
|
1 2 3 4 5 6 7 8 9 10 11 |
// コピーの実行(ハンドル、バッファインデックス、開始位置、個数、コピー先配列) int copied = CopyBuffer(maHandle, 0, 0, 3, maValues); if(copied <= 0) { Print("データのコピーに失敗しました。エラーコード: ", GetLastError()); return; } // 1本前のMAの値を取得 double maVal_1 = maValues[1]; |
maHandle: ステップ①で取得したハンドル0(バッファ番号): 通常のインジケーター(MAなど)は0でOKです(MACDのシグナル線など、複数の線を持つインジケーターは1などを指定します)。0(開始位置): コピーを開始するバーの位置。0は最新の足です。3(個数): コピーする本数。最新の足から過去3本分をコピーします。maValues: コピー先の配列。
3. 使い終わったらハンドルを解放する(IndicatorRelease)
MQL5の大切な作法として、EAが停止するとき(OnDeinit()内)に、作成したインジケーターハンドルをメモリから解放してあげる必要があります。
|
1 2 3 4 5 6 |
void OnDeinit(const int reason) { // ハンドルの解放 IndicatorRelease(maHandle); Print("インジケーターハンドルを解放しました。"); } |
これを忘れると、MT5のメモリが徐々に圧迫される原因になるため、必ずセットで書くようにしましょう!
4. コピペで動く!サンプルEAコード
それでは、実際に動かして挙動を確認できるサンプルコードを紹介します。
このコードは、「1本前の移動平均線(SMA14)の値」と、「1本前のRSI(14)の値」を毎チック取得してログ(操作履歴)に出力するEAです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
//+------------------------------------------------------------------+ //| IndicatorSample.mq5 | //| 潤奈FX | //+------------------------------------------------------------------+ #property copyright "潤奈FX" #property link "https://zyunafx.com" #property version "1.00" // インジケーターハンドルの保存用変数 int maHandle; int rsiHandle; // データ格納用の動的配列(グローバル変数として宣言) double maValues[]; double rsiValues[]; //+------------------------------------------------------------------+ //| 初期化関数 | //+------------------------------------------------------------------+ int OnInit() { // ① 移動平均線(SMA 14)のハンドル取得 maHandle = iMA(_Symbol, _Period, 14, 0, MODE_SMA, PRICE_CLOSE); if(maHandle == INVALID_HANDLE) { Print("MAハンドルの作成失敗"); return(INIT_FAILED); } // ① RSI(期間 14)のハンドル取得 rsiHandle = iRSI(_Symbol, _Period, 14, PRICE_CLOSE); if(rsiHandle == INVALID_HANDLE) { Print("RSIハンドルの作成失敗"); return(INIT_FAILED); } // ② 配列を時系列順に並び替え(OnInit内で1回だけ設定すればOK!) ArraySetAsSeries(maValues, true); ArraySetAsSeries(rsiValues, true); Print("インジケーターの初期化完了。"); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| 後片付け関数 | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // ハンドルの解放(メモリリーク対策) IndicatorRelease(maHandle); IndicatorRelease(rsiHandle); Print("ハンドルの解放完了。"); } //+------------------------------------------------------------------+ //| チック毎の処理関数 | //+------------------------------------------------------------------+ void OnTick() { // ③ CopyBufferで値を配列にコピー (最新の0番バーから過去3本分) // `<= 0` で判定することで、エラーとデータ未取得の両方を安全に防げます if(CopyBuffer(maHandle, 0, 0, 3, maValues) <= 0) { Print("MAデータのコピー失敗"); return; } if(CopyBuffer(rsiHandle, 0, 0, 3, rsiValues) <= 0) { Print("RSIデータのコピー失敗"); return; } // 1本前のローソク足(確定足)の値を取り出す double lastMA = maValues[1]; double lastRSI = rsiValues[1]; // ログに出力 PrintFormat("確定足の値 -> MA(14): %.2f | RSI(14): %.2f", lastMA, lastRSI); } //+------------------------------------------------------------------+ |
このコードをコンパイルしてデモ口座などのチャートにセットし、「操作履歴」タブを確認してみてください。以下のように、リアルタイムで現在の通貨ペアのMA値とRSI値が表示されれば成功です!
5. まとめ&次のステップ
今回は、MQL5でのインジケーター値の取得方法を解説しました。
- MQL5では直接値を取得できず、「ハンドル取得」と「データコピー」の2ステップが必要。
OnInit()でハンドルを取得し、OnDeinit()で解放する。OnTick()内でArraySetAsSeries()を使って配列を時系列に設定する。CopyBuffer()を使って必要本数分のデータを配列に引っ張ってくる。
これで、「発注」「決済」「インジケーター取得」という、EA開発に必要な3大要素をすべて手に入れました!
次回は、これまでに学んだ知識をすべてガッチャンコして、「移動平均線のゴールデンクロス・デッドクロスで自動で売買(注文&決済)を繰り返す、初めての実用EA」を作成していきます。ついに本物の自動売買プログラムが完成しますので、楽しみにしていてくださいね!
今回のコードで「エラーが出て値が取れない」「RSIのパラメーター変更方法が分からない」といったことがあれば、YouTubeのコメント欄やXでお気軽にご相談ください!


コメント