MQL4でインジケーターの値を取得するときは、`iMA()`のような関数を呼ぶだけで値そのものが返ってきました。
ところがMQL5で同じことをしようとすると、`iMA()`が返すのは値ではなく「ハンドル」
という見慣れない数値で、そこから戸惑う人が多いポイントです。
この記事では、MQL5でインジケーターの値を取得する基本の流れ(ハンドル取得→CopyBuffer)を、
MQL4との違いを踏まえて解説します。
MQL4とMQL5でインジケーターの値の取り方が違う
MQL4では、以下のように1行でその場の移動平均線の値が取得できました。
double ma = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 0);//MQL4の書き方
MQL5では、`iMA()`は値そのものではなく「インジケーターハンドル」
という整数を返すだけです。
実際の値を取り出すには、別の関数`CopyBuffer()`を使ってハンドルからバッファの中身をコピーする、
という2段階の手順が必要になります。
int handle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);//ハンドルを取得(MQL5) double ma[]; CopyBuffer(handle, 0, 0, 1, ma);//ハンドルから値をコピー(MQL5)
遠回りに見えますが、この方式には理由があります。
ハンドルは一度取得すれば使い回せるので、毎ティックごとにインジケーターを再計算する必要がなくなり、
MQL4よりも処理が軽くなる設計になっています。
ハンドルを取得する
まず`OnInit()`でハンドルを1回だけ取得します。
OnCalculate()やOnTick()の中で毎回iMA()を呼んではいけません。
呼ぶたびに新しいハンドルが作られてしまい、ハンドルが際限なく増え続けてメモリを圧迫する原因になります。
int maHandle;//ハンドルを保存するグローバル変数
int OnInit()
{
maHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
if(maHandle == INVALID_HANDLE)
{
Print("iMAのハンドル取得に失敗しました。エラーコード=", GetLastError());
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
`iMA()`が失敗すると`INVALID_HANDLE`が返るので、
必ずチェックしてください。
チェックを省略すると、この後の`CopyBuffer()`が無言で失敗し続け、
原因がわからないまま値が取得できない状態になります。
CopyBuffer関数で値をコピーする
取得したハンドルを使って、実際の値を配列にコピーします。
int CopyBuffer( int indicator_handle, //インジケーターハンドル int buffer_num, //バッファ番号(移動平均線は0番のみ) int start_pos, //コピーを開始する位置(0=最新のバー) int count, //コピーする本数 double buffer[] //コピー先の配列 );
戻り値は実際にコピーできた本数です。
データがまだ揃っていない(チャートを開いた直後など)場合や、
ハンドルが無効な場合は-1が返ります。
double maValue[];
ArraySetAsSeries(maValue, true);//配列を時系列順(0=最新)に並べる設定
int copied = CopyBuffer(maHandle, 0, 0, 1, maValue);
if(copied <= 0)
{
Print("CopyBufferに失敗しました。エラーコード=", GetLastError());
return(0);
}
Print("現在の移動平均線の値: ", maValue[0]);
ArraySetAsSeries()を忘れるとどうなるか
`ArraySetAsSeries(maValue, true)`を呼び忘れると、
配列は古いデータから並ぶ通常の並び順(0が一番古い)のままCopyBufferに渡されます。
この状態で`maValue[0]`にアクセスすると、意図した「最新の値」
ではなく「一番古い値」を読んでしまうことがあり、気づきにくいバグの原因になります。
値がおかしいと感じたら、まずこの設定を確認してください。
実際に動くインジケーター全体のコード
ここまでの内容をまとめて、現在の20期間移動平均線の値をチャート左上にコメント表示する、
実際にMetaEditorでコンパイルできるインジケーターです。
//+------------------------------------------------------------------+
//| CopyBufferDemo.mq5 |
//| Copyright 2026, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link "https://creator.fx-ea-system-project.com/"
#property version "1.00"
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots 0
input int MAPeriod = 20;//移動平均線の期間
int maHandle;//移動平均線のハンドル
//このインジケーターはチャートに線を描かず、値をComment()で表示するだけなので、
//バッファ・プロットともに0個で問題ありません(線を描く場合は1以上が必要です)。
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
maHandle = iMA(_Symbol, PERIOD_CURRENT, MAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(maHandle == INVALID_HANDLE)
{
Print("iMAのハンドル取得に失敗しました。エラーコード=", GetLastError());
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
IndicatorRelease(maHandle);//ハンドルを解放する
Comment("");
}
//+------------------------------------------------------------------+
//| 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[])
{
double maValue[];
ArraySetAsSeries(maValue, true);
int copied = CopyBuffer(maHandle, 0, 0, 1, maValue);
if(copied <= 0)
{
Print("CopyBufferに失敗しました。エラーコード=", GetLastError());
return(0);
}
Comment("現在の", MAPeriod, "期間移動平均線の値: ", maValue[0]);
return(rates_total);
}
//+------------------------------------------------------------------+
MetaEditorで実際に動かす手順
- MetaTrader 5の「ツール」→「MetaQuotes Language Editor」でMetaEditorを開く
- 「ファイル」→「新規作成」→「インジケーター」を選び、名前を「CopyBufferDemo」にして作成する(中身は空のテンプレートで構いません)
- テンプレートの中身を全て削除し、上のコードを丸ごと貼り付ける
- F7キー(またはコンパイルボタン)でコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
- MT5の「ナビゲーター」パネルからインジケーターを探し、チャートへドラッグ&ドロップする
- チャート左上に「現在の20期間移動平均線の値: ○○」と表示されれば成功です
コピペしてコンパイルが通らないときに確認すること
- 拡張子が「.mq5」になっているか(.mq4のファイルにこのコードを貼ってもコンパイルできません。MQL4とMQL5は別言語です)
- `OnCalculate()`の引数の数・型が1文字も欠けていないか(MQL5のOnCalculate()は引数が多く、コピペ時に1行欠けるとコンパイルエラーになります)
まとめ
MQL5でインジケーターの値を取得するには、①OnInit()でハンドルを1回だけ取得する、
②OnCalculate()でCopyBuffer()を使って値をコピーする、
という2段階の流れになります。
MQL4のように1回の関数呼び出しで値が返ってこない点に最初は戸惑いますが、
ハンドルを使い回す設計のおかげでMQL4より処理が軽くなるというメリットがあります。
今回のCopyBuffer()は、iRSIやiBands等、
他の標準インジケーターの値を取得する際にも同じ手順で使えます。
コメント