MQL4のiCustom関数は、自作インジケーターの計算結果を、

そのまま数値として返してくれます。

ところがMQL4のコードをそのままMQL5に持ち込んでiCustomを呼ぶと、

返ってくるのは価格でも指標値でもない、意味不明な小さい整数です。

これはバグではなく、MQL5のiCustomが「値」ではなく「ハンドル」

しか返さない仕様に変わったためです。

この記事では、MQL5でiCustomからハンドルを受け取り、

CopyBufferで実際の値を取り出すまでの一連の流れを、

自作インジケーターと呼び出し側スクリプトの両方の完全なコードで解説します。

設計思想: なぜMQL5はハンドル方式に変えたのか

MQL4のiCustomは、呼び出すたびに指定したインジケーターの計算をその場で走らせ、

指定したバッファ・シフトの値を直接返していました。

この方式は書く側は楽ですが、

同じインジケーターを何度も呼び出すたびに、

毎回ゼロから再計算が走るという無駄がありました。

MQL5では、iMAやiRSIなど標準インジケーターの呼び出しが、

すべて「ハンドルを取得してからCopyBufferで値を読む」

という2段階方式に統一されており、iCustomも同じ設計に合わせられています。

ハンドルは一度だけ取得してOnInit()等で保持しておけば、

その後は同じ計算結果をCopyBufferで何度でも安く読み出せるという利点があります。

これはCopyBuffer関数の解説記事で扱った、

標準インジケーターの仕組みと全く同じ考え方です。

iCustom関数の書式(MQL5版)

int iCustom(
   string           symbol,       // 通貨ペア。NULLで現在のチャート
   ENUM_TIMEFRAMES  period,       // 時間足。PERIOD_CURRENTで現在の時間足
   string           name,         // カスタムインジケーター名(拡張子なし)
   ...                            // カスタムインジケーターのinput引数(省略可)
   );

戻り値はintのハンドルで、取得に失敗すると`INVALID_HANDLE`が返ります。

第3引数のnameには、

MQL5\Indicatorsフォルダを基準にしたファイル名(拡張子なし)を渡します。

サブフォルダに入れている場合は、

`”MyFolder\\MyIndicator”`のようにパスごと指定します。

呼び出される側: 自作インジケーターSimpleSMA

まず、iCustomから呼び出す側の、

シンプルな単純移動平均を計算するだけの自作インジケーターを用意します。

このファイルを先にコンパイルし、

MQL5\Indicatorsフォルダに保存しておく必要があります。

//+------------------------------------------------------------------+
//|                                                    SimpleSMA.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 1
#property indicator_plots   1
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue

input int MaPeriod = 20;//移動平均の期間

double SmaBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0, SmaBuffer, INDICATOR_DATA);
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MaPeriod);
   IndicatorSetString(INDICATOR_SHORTNAME, "SimpleSMA(" + IntegerToString(MaPeriod) + ")");
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| 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[])
  {
   if(rates_total < MaPeriod)
      return(0);

   int start = (prev_calculated > 0) ? prev_calculated - 1 : MaPeriod - 1;

   for(int i = start; i < rates_total; i++)
     {
      double sum = 0;
      for(int j = 0; j < MaPeriod; j++)
         sum += close[i - j];
      SmaBuffer[i] = sum / MaPeriod;
     }

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

OnCalculate()の配列は、

MQL5では既定でインデックスが昇順(0が一番古い足)になっている点がMQL4と逆なので、

`close[i - j]`のようにiより過去を指すには添字を引き算します。

呼び出す側: iCustomとCopyBufferでSimpleSMAの値を読む

次に、上のSimpleSMAをiCustomで呼び出し、

CopyBufferで最新3本分の値を取得するスクリプトです。

//+------------------------------------------------------------------+
//|                                              iCustomDemo.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 script_show_inputs

input int MaPeriod = 20;//SimpleSMA側に渡す期間(SimpleSMAのinputと合わせる)

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   int handle = iCustom(_Symbol, _Period, "SimpleSMA", MaPeriod);

   if(handle == INVALID_HANDLE)
     {
      Print("iCustomのハンドル取得に失敗しました。エラーコード=", GetLastError());
      return;
     }

   double buf[];
   ArraySetAsSeries(buf, true);

   int copied = CopyBuffer(handle, 0, 0, 3, buf);
   if(copied <= 0)
     {
      Print("CopyBufferに失敗しました。エラーコード=", GetLastError());
      IndicatorRelease(handle);
      return;
     }

   Print("SimpleSMA 現在値=", buf[0], " 1本前=", buf[1], " 2本前=", buf[2]);

   IndicatorRelease(handle);
  }
//+------------------------------------------------------------------+
Copy

CopyBuffer()に渡す配列は、

`ArraySetAsSeries(buf, true)`で、

「0番目=最新」の並びに変えているため、

SimpleSMA.mq5側の昇順とは向きが逆になります。

同じプログラムの中でも、

OnCalculate内の配列と、

CopyBufferで受け取る配列とで向きが違うという点は、

MQL5を書き始めた人が混乱しやすいポイントです。

MetaEditorで実際に動かす手順

  1. MetaEditorで新規カスタムインジケーターを作成し、名前を「SimpleSMA」にしてテンプレートの中身を上のコードに置き換え、F7でコンパイルする
  2. MT5のナビゲータの「インジケーター」欄にSimpleSMAが表示されることを確認する(チャートに適用しなくてよい)
  3. MetaEditorで新規スクリプトを作成し、名前を「iCustomDemo」にしてテンプレートの中身を上のコードに置き換え、F7でコンパイルする
  4. チャートへiCustomDemoをドラッグ&ドロップして実行し、「エキスパート」タブにSimpleSMAの直近3本の値がPrint出力されることを確認する

コピペして動かないときに確認すること

  • SimpleSMA.mq5を先にコンパイルしてMQL5\Indicatorsフォルダに置いたか。iCustomは実行時にコンパイル済みの.ex5ファイルを名前で探すため、ソースコードが同じフォルダにあるだけでは見つからない
  • iCustomに渡すinput引数の順序・個数が、SimpleSMA側のinput宣言順と一致しているか。ずれていても文法エラーにはならず、意図しない期間で計算されるだけなので気づきにくい
  • handleが有効でもCopyBufferの戻り値がマイナスや0になる場合、履歴データがまだ読み込み中の可能性がある。数ティック待ってから再試行するか、待機用の再試行ループを入れる
  • MQL4の`iCustom(NULL,0,"SimpleSMA",20,0,0)`のように末尾に「バッファ番号,シフト」を書く古い呼び出し方をMQL5にそのまま持ち込むと、余分な引数がinputに渡ってしまい正しく動かない

まとめ

MQL4のiCustomは自作インジケーターの値をその場で直接返しますが、

MQL5のiCustomはハンドルしか返さず、

値を読むにはCopyBufferをもう1段呼ぶ必要があります。

この2段階方式は書く手間が増える代わりに、

同じ計算結果を何度も安く読み出せる利点があります。

ハンドルを使い終えたらIndicatorRelease()で解放する習慣も、

CopyBuffer関数や、

IndicatorCreate/IndicatorRelease関数の記事と合わせて、

身につけておくと安心です。

関連記事