【MQL5】iMA関数の使い方|移動平均をEAで取得する方法とサンプルコード

【MQL5】iMA関数の使い方|移動平均をEAで取得する方法とサンプルコード MQL5リファレンス

iMA関数は、移動平均線(MA)の値をMQL5プログラムから取得するための関数です。EAのトレンド判定やエントリー条件づくりで、もっとも使われる指標のひとつ。この記事では、iMAの構文から「ハンドルとCopyBufferの2段階」という MQL5 特有の作法、そしてコピーしてすぐ動く4つのサンプルコード(現在値の取得・ゴールデンクロス検出・上位足フィルター・売買する最小EA)まで、順番に解説します。

iMA関数とは

移動平均線は、一定期間の価格を平均してなめらかにした線で、トレンドの方向を見るのに使います。MQL5では iMA() を使うことで、この移動平均の値をプログラムから取得し、「価格がMAより上なら買い目線」「短期MAが長期MAを上抜けたら買い」といった判断をEAに組み込めます。

MT4の感覚で使うと必ずつまずくポイントがあります。それが、次に説明する「2段階」の考え方です。

iMA() の構文と引数

int  iMA(
   string              symbol,          // 通貨ペア(_Symbol で現在のペア)
   ENUM_TIMEFRAMES     period,          // 時間足(PERIOD_CURRENT 等)
   int                 ma_period,       // 期間(例:20)
   int                 ma_shift,        // 表示ずらし(通常 0)
   ENUM_MA_METHOD      ma_method,       // 平均の種類(MODE_SMA 等)
   ENUM_APPLIED_PRICE  applied_price    // 価格の種類(PRICE_CLOSE 等)
);

戻り値は「インジケーターのハンドル」(整数のID)です。MAの値そのものではない点に注意してください。値の取り出しは、後述の CopyBuffer() で行います。

ma_method(平均の種類)

定数 意味
MODE_SMA 単純移動平均
MODE_EMA 指数移動平均(直近を重視)
MODE_SMMA 平滑移動平均
MODE_LWMA 線形加重移動平均

applied_price(価格の種類)

定数 意味
PRICE_CLOSE 終値(最もよく使う)
PRICE_OPEN 始値
PRICE_HIGH / PRICE_LOW 高値 / 安値
PRICE_MEDIAN (高値+安値)/2
PRICE_TYPICAL (高値+安値+終値)/3
PRICE_WEIGHTED (高値+安値+終値×2)/4

 

【MQL5】iMA関数の使い方|移動平均をEAで取得する方法とサンプルコード

MQL5の基本:iMAは「2段階」で使う

MQL5では、インジケーターの値を次の2ステップで取り出します。ここがMT4と大きく違うところです。

  • ① ハンドルを作るiMA())… OnInit()1回だけ行う
  • ② 値を取り出すCopyBuffer())… OnTick() で必要なときに行う
いちばんの落とし穴
ハンドルを OnTick() の中で毎回作ってはいけません。毎ティック作るとメモリを食いつぶし、やがて取得に失敗します。ハンドル作成は OnInit() で1回だけが鉄則です。

サンプル①:現在の移動平均を取得して表示する

まずは最小構成。MA(20) の現在値をチャート左上に表示するだけのコードです。

コピペOK

int maHandle = INVALID_HANDLE;          // ハンドルを保管する変数

int OnInit()
{
   // ① ハンドルを1回だけ作る(SMA・期間20・終値)
   maHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
   if(maHandle == INVALID_HANDLE)
   {
      Print("iMAハンドルの作成に失敗: ", GetLastError());
      return(INIT_FAILED);
   }
   return(INIT_SUCCEEDED);
}

void OnTick()
{
   double ma[];                          // 値を受け取る配列
   ArraySetAsSeries(ma, true);           // [0]を最新足にそろえる

   // ② 最新2本ぶんの値を取り出す。取得できなければ何もしない
   if(CopyBuffer(maHandle, 0, 0, 2, ma) < 2) return;

   double maNow = ma[0];                 // 現在の移動平均
   Comment("MA(20) = ", DoubleToString(maNow, _Digits));
}

void OnDeinit(const int reason)
{
   IndicatorRelease(maHandle);           // 後始末(ハンドルの解放)
}

CopyBuffer() の引数は「ハンドル・バッファ番号・開始位置・本数・受け取る配列」です。MAのバッファ番号は 0。起動直後はデータが未準備で失敗することがあるため、戻り値のチェックは必須です。

サンプル②:ゴールデンクロス/デッドクロスを検出する

短期MAと長期MAの2本を使い、クロスを判定します。だましを避けるため、形成中の足ではなく確定した足で判定し、さらに新しい足ができた時だけチェックします。

コピペOK

int      fastHandle, slowHandle;
datetime lastBar = 0;                    // 新バー判定用

int OnInit()
{
   fastHandle = iMA(_Symbol, PERIOD_CURRENT, 5,  0, MODE_SMA, PRICE_CLOSE);
   slowHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
   if(fastHandle == INVALID_HANDLE || slowHandle == INVALID_HANDLE)
      return(INIT_FAILED);
   return(INIT_SUCCEEDED);
}

void OnTick()
{
   // 新しい足ができた瞬間だけ判定(毎ティック実行しない)
   datetime t = iTime(_Symbol, PERIOD_CURRENT, 0);
   if(t == lastBar) return;
   lastBar = t;

   double fast[], slow[];
   ArraySetAsSeries(fast, true);
   ArraySetAsSeries(slow, true);

   // [1]=直近の確定足、[2]=その1本前。確定足で見るのでリペイントしない
   if(CopyBuffer(fastHandle, 0, 0, 3, fast) < 3) return;
   if(CopyBuffer(slowHandle, 0, 0, 3, slow) < 3) return;

   bool goldenCross = (fast[2] <= slow[2] && fast[1] > slow[1]); // 下→上
   bool deadCross   = (fast[2] >= slow[2] && fast[1] < slow[1]); // 上→下

   if(goldenCross) Print("ゴールデンクロス発生!");
   if(deadCross)   Print("デッドクロス発生!");
}
ポイント
「直近の確定足 [1]」と「その1本前 [2]」を比べて、位置関係が入れ替わった瞬間をクロスと判定します。形成中の足 [0] は値が動き続けるため、判定に使うとサインが点いたり消えたり(リペイント)します。

サンプル③:上位足の移動平均でトレンドフィルター(MTF)

実行中の時間足とは別に、上位足(例:H1)のMAを参照できます。「H1のMAより上のときだけ買う」といった、大きな流れに沿わせるフィルターに便利です。

コピペOK

int h1Handle;

int OnInit()
{
   // 実行足がM5でも、H1のMAを直接参照できる
   h1Handle = iMA(_Symbol, PERIOD_H1, 50, 0, MODE_EMA, PRICE_CLOSE);
   if(h1Handle == INVALID_HANDLE) return(INIT_FAILED);
   return(INIT_SUCCEEDED);
}

void OnTick()
{
   double h1ma[];
   ArraySetAsSeries(h1ma, true);
   if(CopyBuffer(h1Handle, 0, 0, 2, h1ma) < 2) return;

   double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   bool upTrend = (price > h1ma[0]);     // 上位足MAより上=上目線

   if(upTrend) Comment("H1は上目線:買いのみ狙う");
   else        Comment("H1は下目線:買いは見送り");
}

サンプル④:移動平均クロスで売買する最小EA

サンプル②のクロス判定に、CTrade を使った発注を加えた、動く最小EAです。ゴールデンクロスで買い、デッドクロスで決済します。

コピペOK(デモ口座で動作確認用)

#include <Trade\Trade.mqh>               // 取引クラスを読み込む
CTrade   trade;
int      fastHandle, slowHandle;
datetime lastBar = 0;
input double InpLot = 0.10;              // ロット(外から変更可)

int OnInit()
{
   fastHandle = iMA(_Symbol, PERIOD_CURRENT, 5,  0, MODE_SMA, PRICE_CLOSE);
   slowHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
   if(fastHandle == INVALID_HANDLE || slowHandle == INVALID_HANDLE)
      return(INIT_FAILED);
   trade.SetExpertMagicNumber(20260618); // 自分のEAを見分ける番号
   return(INIT_SUCCEEDED);
}

void OnTick()
{
   datetime t = iTime(_Symbol, PERIOD_CURRENT, 0);
   if(t == lastBar) return;              // 新バー時のみ
   lastBar = t;

   double fast[], slow[];
   ArraySetAsSeries(fast, true);
   ArraySetAsSeries(slow, true);
   if(CopyBuffer(fastHandle, 0, 0, 3, fast) < 3) return;
   if(CopyBuffer(slowHandle, 0, 0, 3, slow) < 3) return;

   bool golden = (fast[2] <= slow[2] && fast[1] > slow[1]);
   bool dead   = (fast[2] >= slow[2] && fast[1] < slow[1]);

   // ゴールデンクロス:ノーポジなら買う
   if(golden && PositionsTotal() == 0)
      trade.Buy(InpLot, _Symbol);

   // デッドクロス:自分のポジションを決済
   if(dead)
   {
      for(int i = PositionsTotal() - 1; i >= 0; i--)
      {
         ulong ticket = PositionGetTicket(i);
         if(PositionSelectByTicket(ticket) &&
            PositionGetString(POSITION_SYMBOL) == _Symbol)
            trade.PositionClose(ticket);
      }
   }
}

void OnDeinit(const int reason)
{
   IndicatorRelease(fastHandle);
   IndicatorRelease(slowHandle);
}
これは学習用の最小サンプルです
損切り(SL)・利確(TP)・スプレッド確認・資金管理は入っていません。そのまま実弾で使うものではなく、必ずデモ口座で動作を確認してください。実運用には、これらの安全装置を必ず足してください。

よくあるエラー・つまずき

① ハンドルを OnTick で毎回作っている
取得が失敗し続けたり、動作が重くなります。iMA()OnInit() で1回だけ。
② CopyBuffer の戻り値を確認していない
起動直後はデータ未準備で取得に失敗します。if(CopyBuffer(...) < 本数) return; で必ずガードを。
③ ArraySetAsSeries を忘れる
付け忘れると [0] が最新ではなく最古の足になり、判定が逆になります。値を取る配列には必ず ArraySetAsSeries(配列, true) を。

まとめ

  • iMA() は移動平均のハンドルを返す。値は CopyBuffer() で取り出す(2段階)
  • ハンドル作成は OnInit() で1回、値取得は OnTick() で。終了時は IndicatorRelease()
  • クロス判定は確定足 [1] と [2]で、新バー時のみ。リペイントを防げる
  • 上位足のMAも直接参照でき、トレンドフィルターに使える
  • 戻り値チェックと ArraySetAsSeries を忘れない
タイトルとURLをコピーしました