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);
  }
//+------------------------------------------------------------------+
Copy

MetaEditorで実際に動かす手順

  1. MetaTrader 5の「ツール」→「MetaQuotes Language Editor」でMetaEditorを開く
  2. 「ファイル」→「新規作成」→「インジケーター」を選び、名前を「CopyBufferDemo」にして作成する(中身は空のテンプレートで構いません)
  3. テンプレートの中身を全て削除し、上のコードを丸ごと貼り付ける
  4. F7キー(またはコンパイルボタン)でコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
  5. MT5の「ナビゲーター」パネルからインジケーターを探し、チャートへドラッグ&ドロップする
  6. チャート左上に「現在の20期間移動平均線の値: ○○」と表示されれば成功です

コピペしてコンパイルが通らないときに確認すること

  • 拡張子が「.mq5」になっているか(.mq4のファイルにこのコードを貼ってもコンパイルできません。MQL4とMQL5は別言語です)
  • `OnCalculate()`の引数の数・型が1文字も欠けていないか(MQL5のOnCalculate()は引数が多く、コピペ時に1行欠けるとコンパイルエラーになります)

まとめ

MQL5でインジケーターの値を取得するには、①OnInit()でハンドルを1回だけ取得する、

②OnCalculate()でCopyBuffer()を使って値をコピーする、

という2段階の流れになります。

MQL4のように1回の関数呼び出しで値が返ってこない点に最初は戸惑いますが、

ハンドルを使い回す設計のおかげでMQL4より処理が軽くなるというメリットがあります。

今回のCopyBuffer()は、iRSIやiBands等、

他の標準インジケーターの値を取得する際にも同じ手順で使えます。

関連記事