【MQL4】iCustom関数の使い方を徹底解説!カスタムインジケーターをEAから呼び出す方法とサンプルコード

【中級編】MQLプログラムの読み方・書き方

「お気に入りのインジケーターを使って自動売買したい!」——そんな夢を叶えてくれるのが、MQL4のiCustom関数です。

iCustom関数を使えば、MT4のIndicatorsフォルダにあるカスタムインジケーターの値をEA(エキスパートアドバイザー)から自由に取得できます。つまり、チャート上で矢印やラインを表示するインジケーターのシグナルを、そのまま自動売買のロジックに組み込めるのです。

この記事では、iCustom関数の基本的な構文から、実践的なサンプルコードまで、初心者にもわかりやすく解説していきます。

iCustom関数とは?

iCustom関数は、指定したカスタムインジケーターの計算結果(バッファの値)を取得するMQL4の組み込み関数です。

MT4にはiMA(移動平均線)やiRSI(RSI)など、標準インジケーター用の関数が用意されていますが、自作のインジケーターやネットで配布されているインジケーターにはこうした専用関数がありません。そこで活躍するのがiCustom関数です。

iCustom関数を利用すると、Indicatorsフォルダに保存されているあらゆるカスタムインジケーターの値を取得できます。これにより、インジケーターのシグナルをEAのエントリー条件・決済条件として使うことが可能になります。

iCustom関数の構文(シンタックス)

iCustom関数の基本構文は以下の通りです。

double iCustom(
    string symbol,      // 通貨ペア(NULLで現在のチャート)
    int    timeframe,    // 時間足(0で現在の時間足)
    string name,         // カスタムインジケーター名
    ...                  // インジケーターの入力パラメーター(可変)
    int    mode,         // バッファ番号(0〜7)
    int    shift         // 取得するバーの位置(0が最新)
);

各パラメーターの意味を詳しく見ていきましょう。

① symbol(通貨ペア)

値を取得したい通貨ペアを文字列で指定します。現在のチャートの通貨ペアを指定する場合は NULL または _Symbol を使います。別の通貨ペアを指定したい場合は "USDJPY" のように気配値表示ウィンドウの表記通りに記述します。

② timeframe(時間足)

時間軸の種類を指定します。現在のチャートの時間足を使う場合は 0 または PERIOD_CURRENT を指定します。別の時間足を指定する場合は、以下の定数を使います。

定数 意味
PERIOD_M1 1 1分足
PERIOD_M5 5 5分足
PERIOD_M15 15 15分足
PERIOD_M30 30 30分足
PERIOD_H1 60 1時間足
PERIOD_H4 240 4時間足
PERIOD_D1 1440 日足
PERIOD_W1 10080 週足
PERIOD_MN1 43200 月足

③ name(インジケーター名)

カスタムインジケーター名を文字列で指定します。指定するカスタムインジケーターの.ex4ファイルが、MQL4\Indicatorsフォルダまたはそのサブフォルダに保存されている必要があります。

サブディレクトリに配置されている場合は、”サブディレクトリ名\\カスタムインジケータ名”で指定します。

// Indicatorsフォルダ直下の場合
iCustom(NULL, 0, "MyIndicator", ...);

// サブフォルダ「Examples」内の場合
iCustom(NULL, 0, "Examples\\MyIndicator", ...);

④ …(インジケーターの入力パラメーター)

カスタムインジケータの入力パラメータです。渡された入力パラメータの順序は、カスタムインジケータの宣言順に対応する必要があります。ここが一番混乱しやすいポイントです。

パラメーターを省略した場合は、インジケーター側のデフォルト値が使用されます。ただし、途中のパラメーターだけを省略することはできません。変更したいパラメーターより前のパラメーターは、すべてデフォルト値であっても記述する必要があります。

⑤ mode(バッファ番号)

取得したいインジケーターバッファのインデックス番号(0〜7)を指定します。最初のバッファはmode=0です。

例えば、ボリンジャーバンドのようなインジケーターなら:

  • バッファ0:ミドルバンド
  • バッファ1:アッパーバンド
  • バッファ2:ロワーバンド

のように対応します。バッファ番号の確認方法は後述します。

⑥ shift(バーの位置)

カスタムインジケーターの値を取得したいバーの位置を指定します。現在のバーであれば「0」、1本前のバーであれば「1」、2本前のバーであれば「2」と記述します。

EA内では、確定した値を使うため shift=1(1本前の確定バー)を指定するのが一般的です。

バッファ番号の調べ方

iCustom関数を使ううえで最も重要なのが、正しいバッファ番号を知ることです。バッファ番号を間違えると、まったく違う値を取得してしまいます。

方法1:チャート上でマウスカーソルを合わせる

チャート上にセットしたインジケーターのラインや矢印にマウスカーソルをのせて、Value1やValue2などという表示がでれば、iCustomでEA化できます。

方法2:データウィンドウで確認する

MT4の「表示」→「データウィンドウ」を開くと、各インジケーターのバッファ値が一覧で表示されます。上から順に0, 1, 2…のバッファ番号に対応しています。

方法3:ソースコードを確認する

インジケーターの.mq4ファイルがある場合は、SetIndexBuffer()SetIndexLabel() の記述からバッファ番号を確認できます。

// ソースコードの例
SetIndexBuffer(0, UpperBuffer);  // バッファ0 → アッパーライン
SetIndexBuffer(1, LowerBuffer);  // バッファ1 → ロワーライン
SetIndexBuffer(2, BuySignal);    // バッファ2 → 買いシグナル
SetIndexBuffer(3, SellSignal);   // バッファ3 → 売りシグナル

基本的な使い方:サンプルコード

ここからは、実際のサンプルコードを使って使い方を解説します。

サンプル1:移動平均線カスタムインジケーターの値を取得

まずは、最もシンプルな例です。カスタムインジケーター「MyMA」の値を取得してチャートにコメント表示します。

void OnTick()
{
    // MyMAインジケーターの値を取得(期間20、バッファ0、1本前のバー)
    double ma_value = iCustom(NULL, 0, "MyMA", 20, 0, 1);
    
    // チャートにコメント表示
    Comment("MyMA(20)の値: ", DoubleToString(ma_value, Digits));
}

サンプル2:ボリンジャーバンドカスタムインジケーターの複数バッファを取得

iCustom関数でボリンジャーバンドの値を取得する例です。

void OnTick()
{
    // Bandsインジケーターの各バンドを取得
    int period = 20;
    double deviation = 2.0;
    
    double upper = iCustom(NULL, 0, "Bands", period, 0, deviation, 1, 0);  // アッパーバンド(バッファ1)
    double lower = iCustom(NULL, 0, "Bands", period, 0, deviation, 2, 0);  // ロワーバンド(バッファ2)
    
    Comment("Upper: ", upper, "\nLower: ", lower);
}

サンプル3:矢印シグナルインジケーターでEA化する

これが最も実践的な使い方です。買い矢印・売り矢印を表示するインジケーターのシグナルを使って自動売買するEAのサンプルです。

#property strict

// --- 入力パラメーター ---
input double Lots       = 0.01;    // ロット数
input int    MagicNumber = 12345;  // マジックナンバー
input int    StopLoss    = 50;     // ストップロス(pips)
input int    TakeProfit  = 100;    // テイクプロフィット(pips)

void OnTick()
{
    // --- カスタムインジケーターのシグナル取得 ---
    // 買いシグナル(バッファ0)と売りシグナル(バッファ1)を1本前のバーから取得
    double buySignal  = iCustom(NULL, 0, "MySignalIndicator", 0, 1);
    double sellSignal = iCustom(NULL, 0, "MySignalIndicator", 1, 1);
    
    // --- 現在のポジション数をカウント ---
    int buyCount = 0, sellCount = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
        if(OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
        if(OrderType() == OP_BUY)  buyCount++;
        if(OrderType() == OP_SELL) sellCount++;
    }
    
    // --- 買いエントリー ---
    // シグナルが EMPTY_VALUE でなければ矢印が出現している
    if(buySignal != EMPTY_VALUE && buySignal != 0 && buyCount == 0)
    {
        double sl = Ask - StopLoss * Point * 10;
        double tp = Ask + TakeProfit * Point * 10;
        int ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 3, sl, tp,
                               "iCustom Buy", MagicNumber, 0, clrBlue);
        if(ticket < 0)
            Print("買い注文エラー: ", GetLastError());
    }
    
    // --- 売りエントリー ---
    if(sellSignal != EMPTY_VALUE && sellSignal != 0 && sellCount == 0)
    {
        double sl = Bid + StopLoss * Point * 10;
        double tp = Bid - TakeProfit * Point * 10;
        int ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, 3, sl, tp,
                               "iCustom Sell", MagicNumber, 0, clrRed);
        if(ticket < 0)
            Print("売り注文エラー: ", GetLastError());
    }
}

ポイントは、矢印が表示されていないバーでは EMPTY_VALUE(空の値)が返されるという点です。矢印系のシグナルインジケーターをEA化する場合、この EMPTY_VALUE との比較がエントリー判定の基本パターンになります。

iCustom関数を使う際の注意点

1. .ex4ファイルが必要

iCustom関数が参照するのは、コンパイル済みの.ex4ファイルです。ソースコード(.mq4)だけではなく、必ずコンパイルして.ex4ファイルを生成しておきましょう。

2. バッファレスインジケーターには使えない

オシレーター系のインジケーターの場合はバッファが不可欠なので問題ないのですが、メインチャートに表示される矢印系のインジケーターの場合にはバッファで処理していないことがあります。「バッファでシグナルを処理するようにプログラミングしていないこと」、これがiCustomでインジケーターをEA化できない原因です。バッファレスインジケーターはiCustomではEA化できません。

3. パラメーターの順序と型に注意

入力パラメーターはインジケーターのソースコードで宣言された順番通りに指定する必要があります。順番を間違えたり、型が合わないと正しい値が返りません。

4. パフォーマンスを意識する

iCustom関数は呼び出すたびに計算が実行されるため、ティックごとに何度も呼び出すとパフォーマンスが低下します。新しいバーが確定したタイミングでのみ呼び出し、データをキャッシュすると処理速度を改善できます。

// 新しいバーの判定例
static datetime lastBarTime = 0;
if(Time[0] != lastBarTime)
{
    lastBarTime = Time[0];
    // ここでiCustomを呼び出す
    double signal = iCustom(NULL, 0, "MyIndicator", 0, 1);
}

5. バッファ番号は0〜7の範囲

MT4ではインジケーターバッファのインデックスは0〜7の8個までです。バッファが8個を超えるインジケーターの場合、すべての値をiCustomで取得できるとは限りません。

まとめ

iCustom関数は、カスタムインジケーターのシグナルをEAに組み込むための必須関数です。この記事のポイントをまとめます。

  • iCustom関数を使えば、Indicatorsフォルダにあるカスタムインジケーターの値をEAから取得できる
  • パラメーターは「通貨ペア → 時間足 → インジケーター名 → 入力パラメーター → バッファ番号 → バー位置」の順に指定する
  • バッファ番号の確認は、データウィンドウやソースコードから行う
  • 矢印シグナル系のインジケーターは EMPTY_VALUE との比較でシグナル判定する
  • バッファレスインジケーター(バッファを使わずオブジェクトで描画するもの)には使えない
  • パフォーマンスのため、新しいバー確定時にのみ呼び出す工夫をすると良い

まずは簡単なインジケーターから試して、iCustom関数の使い方に慣れていきましょう。シグナルインジケーターをEA化できるようになれば、自動売買の幅が大きく広がりますよ!