MQL4の`iRSI()`は関数を呼ぶだけでRSIの値がそのまま返ってきました。

ところがMQL5で同じように書くと、返ってくるのは値ではなく「ハンドル」

という整数だけで、そこから戸惑う人が多いポイントです。

ここまでは前回の記事(CopyBuffer関数)で解説したiMAと同じ流れですが、

今回はもう一歩踏み込んで、上限線・中心線・下限線という3本の値を同時に持つ「ボリンジャーバンド(iBands)」

を例に、複数バッファを持つインジケーターの読み方まで解説します。

この記事では、MQL5で`iRSI()`を使ってRSIを取得する基本の流れと、

`iBands()`で複数バッファを読み分ける方法を、MQL4との違いを踏まえて解説します。

iRSI関数でRSIのハンドルを取得する

MQL5の`iRSI()`は、MQL4版と引数の並びは似ていますが、

戻り値がハンドルである点が異なります。

int iRSI(
   string              symbol,          //通貨ペア(_Symbolで現在のチャート)
   ENUM_TIMEFRAMES     period,          //時間足(PERIOD_CURRENTで現在の時間足)
   int                 ma_period,       //RSIの計算期間
   ENUM_APPLIED_PRICE  applied_price    //価格の種類(PRICE_CLOSE等)
   );

MQL4版のようにshift引数はありません。

「何本前の足の値か」は、この後のCopyBuffer()側の引数で指定します。

int rsiHandle;//RSIのハンドルを保存するグローバル変数

int OnInit()
  {
   rsiHandle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
   if(rsiHandle == INVALID_HANDLE)
     {
      Print("iRSIのハンドル取得に失敗しました。エラーコード=", GetLastError());
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }

CopyBuffer()を使ってRSIの値を取り出す部分は、

前回のiMAの例と全く同じ書き方です。

double rsiValue[];
ArraySetAsSeries(rsiValue, true);
int copied = CopyBuffer(rsiHandle, 0, 0, 1, rsiValue);
if(copied <= 0)
  {
   Print("CopyBufferに失敗しました。エラーコード=", GetLastError());
   return;
  }
Print("現在のRSI: ", rsiValue[0]);

RSIはバッファが1本しかないインジケーターなので、CopyBuffer()の第2引数(バッファ番号)は常に0で問題ありません。

ここまでは前回のiMAと同じ流れです。

複数バッファを持つインジケーターの場合(iBandsで解説)

移動平均線やRSIはバッファが1本だけでしたが、インジケーターの中には複数のバッファを同時に持つものがあります。

代表例がボリンジャーバンド(`iBands()`)で、「中心線」

「上限線」

「下限線」という3本の値を1つのハンドルから取得します。

int iBands(
   string              symbol,          //通貨ペア
   ENUM_TIMEFRAMES     period,          //時間足
   int                 bands_period,    //移動平均の期間
   int                 bands_shift,     //線を水平方向にずらす本数(通常は0)
   double              deviation,       //標準偏差の倍率(通常は2.0)
   ENUM_APPLIED_PRICE  applied_price    //価格の種類
   );

ハンドルの取得自体はiRSIと同じ考え方です。

int bandsHandle;

bandsHandle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE);
if(bandsHandle == INVALID_HANDLE)
  {
   Print("iBandsのハンドル取得に失敗しました。エラーコード=", GetLastError());
   return(INIT_FAILED);
  }

buffer_num引数で読む線を切り替える

問題はここからで、`iBands()`のハンドルは1つでも、

中身には3本分の値が入っています。

どの線を読むかは、CopyBuffer()の第2引数(buffer_num)で指定します。

MQL5の公式リファレンスでは、iBandsのバッファ番号は以下のように決まっています。

  • 0 = BASE_LINE(中心線、単純移動平均線)
  • 1 = UPPER_BAND(上限線)
  • 2 = LOWER_BAND(下限線)
double baseLine[], upperBand[], lowerBand[];
ArraySetAsSeries(baseLine, true);
ArraySetAsSeries(upperBand, true);
ArraySetAsSeries(lowerBand, true);

CopyBuffer(bandsHandle, 0, 0, 1, baseLine);  //中心線
CopyBuffer(bandsHandle, 1, 0, 1, upperBand); //上限線
CopyBuffer(bandsHandle, 2, 0, 1, lowerBand); //下限線

CopyBuffer()を3回呼んでいるように見えますが、WebRequestのように毎回サーバーへ通信しているわけではなく、

1つのハンドルが持つ内部バッファから配列へ値をコピーしているだけなので、

負荷を心配する必要はありません。

ここでバッファ番号を間違える(例: 上限線のつもりで0番を読んでしまう)と、

エラーは出ないまま違う線の値を参照し続けるバグになるので注意してください。

実際に動くコード全体(RSIとボリンジャーバンドを同時に表示)

ここまでの内容をまとめて、現在のRSIとボリンジャーバンド(中心・上限・下限)の値をチャート左上にコメント表示する、

実際にMetaEditorでコンパイルできるインジケーターです。

//+------------------------------------------------------------------+
//|                                                RsiBandsDemo.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    RSIPeriod   = 14;//RSIの計算期間
input int    BandsPeriod = 20;//ボリンジャーバンドの計算期間
input double BandsDeviation = 2.0;//標準偏差の倍率
//このインジケーターはチャートに線を描かず、値をComment()で表示するだけなので、
//バッファ・プロットともに0個で問題ありません(線を描く場合は1以上が必要です)。

int rsiHandle;   //RSIのハンドル
int bandsHandle; //ボリンジャーバンドのハンドル

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   rsiHandle = iRSI(_Symbol, PERIOD_CURRENT, RSIPeriod, PRICE_CLOSE);
   if(rsiHandle == INVALID_HANDLE)
     {
      Print("iRSIのハンドル取得に失敗しました。エラーコード=", GetLastError());
      return(INIT_FAILED);
     }

   bandsHandle = iBands(_Symbol, PERIOD_CURRENT, BandsPeriod, 0, BandsDeviation, PRICE_CLOSE);
   if(bandsHandle == INVALID_HANDLE)
     {
      Print("iBandsのハンドル取得に失敗しました。エラーコード=", GetLastError());
      return(INIT_FAILED);
     }

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   IndicatorRelease(rsiHandle);
   IndicatorRelease(bandsHandle);
   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 rsiValue[];
   ArraySetAsSeries(rsiValue, true);
   if(CopyBuffer(rsiHandle, 0, 0, 1, rsiValue) <= 0)
     {
      Print("iRSIのCopyBufferに失敗しました。エラーコード=", GetLastError());
      return(0);
     }

   double baseLine[], upperBand[], lowerBand[];
   ArraySetAsSeries(baseLine, true);
   ArraySetAsSeries(upperBand, true);
   ArraySetAsSeries(lowerBand, true);
   if(CopyBuffer(bandsHandle, 0, 0, 1, baseLine) <= 0 ||
      CopyBuffer(bandsHandle, 1, 0, 1, upperBand) <= 0 ||
      CopyBuffer(bandsHandle, 2, 0, 1, lowerBand) <= 0)
     {
      Print("iBandsのCopyBufferに失敗しました。エラーコード=", GetLastError());
      return(0);
     }

   Comment(
      "RSI(", RSIPeriod, ")= ", DoubleToString(rsiValue[0], 2), "\n",
      "ボリンジャーバンド上限= ", DoubleToString(upperBand[0], _Digits), "\n",
      "ボリンジャーバンド中心= ", DoubleToString(baseLine[0], _Digits), "\n",
      "ボリンジャーバンド下限= ", DoubleToString(lowerBand[0], _Digits)
     );

   return(rates_total);
  }
//+------------------------------------------------------------------+
Copy

MetaEditorで実際に動かす手順

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

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

  • 拡張子が「.mq5」になっているか
  • `iBands()`のCopyBuffer()を3回呼んでいる箇所で、buffer_num(第2引数)を0/1/2で書き分けているか(コピペ時に3行のうち1行だけ番号を直し忘れるミスが起きやすい)
  • 値がすべて0のまま変化しない場合、チャートを開いた直後でBandsPeriod分の過去データがまだ読み込まれていない可能性があります。しばらく待つか、通貨ペアの履歴データをダウンロードし直してください

まとめ

MQL5のiRSI()もiMAと同じく、ハンドル取得→CopyBufferという2段階の手順で値を取得します。

バッファが1本のインジケーター(iRSI・iMA)ではCopyBuffer()のbuffer_numは常に0で構いませんが、

ボリンジャーバンドのように複数の線を持つインジケーターでは、

buffer_num(0=中心線、1=上限線、2=下限線)を正しく指定しないと、

意図しない線の値を読んでしまいます。

他の複数バッファ系インジケーター(iStochastic、iMACD等)を扱う際も、

この考え方がそのまま使えます。

関連記事