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は「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)・スプレッド確認・資金管理は入っていません。そのまま実弾で使うものではなく、必ずデモ口座で動作を確認してください。実運用には、これらの安全装置を必ず足してください。
よくあるエラー・つまずき
取得が失敗し続けたり、動作が重くなります。
iMA() は OnInit() で1回だけ。起動直後はデータ未準備で取得に失敗します。
if(CopyBuffer(...) < 本数) return; で必ずガードを。付け忘れると
[0] が最新ではなく最古の足になり、判定が逆になります。値を取る配列には必ず ArraySetAsSeries(配列, true) を。まとめ
iMA()は移動平均のハンドルを返す。値はCopyBuffer()で取り出す(2段階)- ハンドル作成は
OnInit()で1回、値取得はOnTick()で。終了時はIndicatorRelease() - クロス判定は確定足 [1] と [2]で、新バー時のみ。リペイントを防げる
- 上位足のMAも直接参照でき、トレンドフィルターに使える
- 戻り値チェックと
ArraySetAsSeriesを忘れない
