- 1 1. iMAとは何か
- 2 2. iMAの基本構文
- 3 3. iMAの正しい使い方(ハンドル取得と管理)
- 4 4. CopyBufferで移動平均値を取得する方法
- 5 5. よくあるエラーと対策(iMA / CopyBufferで詰まる点)
- 6 6. 実運用での注意点(パフォーマンス設計と安全設計)
- 7 7. EAへの組み込み例(ゴールデンクロス判定と落とし穴)
- 8 8. 関連トピック(今後拡張予定)
- 9 9. よくある質問(FAQ)
1. iMAとは何か
1.1 iMAの役割と基本概念
iMA(Moving Average) は、MQL5で移動平均線(MA:価格の平均値を一定期間で平滑化した指標)を取得するための標準関数です。
移動平均は、相場の方向性(トレンド)を判断する最も基本的なテクニカル指標の一つであり、以下の用途で広く使われます。
- トレンド判定(上昇/下降)
- ゴールデンクロス・デッドクロス検出
- 押し目・戻りの判断補助
- フィルター条件(トレンド方向のみエントリー)
MQL5では、移動平均を計算する処理そのものを自作する必要はありません。
iMA関数を使えば、内部で計算された移動平均インディケータを取得できます。
ただし重要な点として、MQL5のiMAは「値を直接返す関数」ではありません。
MQL4では iMA() を呼ぶと即座に値を取得できましたが、MQL5では“インディケータハンドル方式” に変更されています。
1.2 MQL5におけるiMAの仕組み(ハンドル方式)
MQL5では、iMAを呼び出すと以下の流れになります。
- iMAで「インディケータハンドル(識別番号)」を作成する
- CopyBufferで実際の移動平均値を取得する
つまり、iMAは「移動平均の値」ではなく、移動平均インディケータの参照ID(ハンドル) を返します。
この構造を理解していないと、次のような誤解が発生します。
❌ よくある誤解
- iMAを呼べば値が返ると思っている
- OnTick内で毎回iMAを作成してしまう
- CopyBufferを使わずに比較処理を書いてしまう
これらはすべて典型的な初学者エラーです。
1.3 移動平均の種類(ENUM_MA_METHOD)
iMAでは複数の移動平均タイプを指定できます。
| 種類 | 内容 |
|---|---|
| MODE_SMA | 単純移動平均(Simple Moving Average) |
| MODE_EMA | 指数平滑移動平均(Exponential Moving Average) |
| MODE_SMMA | 平滑移動平均 |
| MODE_LWMA | 加重移動平均 |
一般的なトレンドフォローではEMAが多く使われますが、戦略によって適切な選択は異なります。
1.4 iMAを使うべき場面
iMAは次のようなケースで使用します。
- EAでトレンド方向を判定したい
- 価格が移動平均より上か下かを条件にしたい
- マルチタイムフレーム(例:H1のMAをM5で参照)を行いたい
特にEA開発では、トレンドフィルターとしての使用頻度が非常に高い関数です。
1.5 つまずきやすいポイント
⚠ MQL4との違いを理解していない
MQL5では値を直接取得できません。
必ず「ハンドル → CopyBuffer」という流れになります。
⚠ インディケータの生成位置を誤る
- OnTickで毎回iMAを生成すると負荷が増大
- 正しくはOnInitで生成する
⚠ データ不足
バー数が不足していると、CopyBufferが正しく動作しないことがあります。
特にテスター開始直後は注意が必要です。
iMAを正しく使うには、まず「構文」と「引数の意味」を正確に理解する必要があります。
2. iMAの基本構文
2.1 iMAの関数定義
MQL5におけるiMAの基本構文は以下の通りです。
int iMA(
string symbol, // 通貨ペア
ENUM_TIMEFRAMES period, // 時間足
int ma_period, // 移動平均期間
int ma_shift, // 表示シフト
ENUM_MA_METHOD ma_method, // MAの種類
ENUM_APPLIED_PRICE applied_price // 適用価格
);
この関数は、移動平均インディケータのハンドル(識別番号)を返します。
戻り値が INVALID_HANDLE の場合、インディケータ生成に失敗しています。
2.2 各引数の詳細解説
① symbol(通貨ペア)
_Symbolを使うのが一般的- 例:
"EURUSD"などの明示指定も可能
_Symbol
⚠ マルチ通貨EAでは明示指定が必要になる場合があります。
② period(時間足)
時間足を指定します。
例:
PERIOD_M1PERIOD_M5PERIOD_H1PERIOD_D1PERIOD_CURRENT(現在のチャート時間足)
PERIOD_CURRENT
⚠ マルチタイムフレーム分析では、ここを誤るとロジックが破綻します。
③ ma_period(移動平均期間)
移動平均の計算期間です。
例:
- 20(短期)
- 50(中期)
- 200(長期)
20
⚠ バー数が不足していると計算できません。
テスター開始直後は特に注意。
④ ma_shift(表示シフト)
移動平均を右方向にずらす値です。
通常は 0 を使用します。
0
⚠ これは「計算のシフト」ではなく「表示位置のシフト」です。
ロジック判定用では基本0固定で問題ありません。
⑤ ma_method(移動平均の種類)
列挙型(ENUM_MA_METHOD)を指定します。
MODE_EMA
主な種類:
- MODE_SMA(単純移動平均)
- MODE_EMA(指数)
- MODE_SMMA(平滑)
- MODE_LWMA(加重)
戦略ごとに使い分けが必要です。
⑥ applied_price(適用価格)
どの価格を元に計算するかを指定します。
主な指定値:
- PRICE_CLOSE(終値)
- PRICE_OPEN(始値)
- PRICE_HIGH(高値)
- PRICE_LOW(安値)
- PRICE_MEDIAN(中央値)
- PRICE_TYPICAL(典型価格)
通常は PRICE_CLOSE を使用します。
PRICE_CLOSE
2.3 最小構成のiMA例
int maHandle;
int OnInit()
{
maHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
if(maHandle == INVALID_HANDLE)
{
Print("iMA handle creation failed");
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
ここで重要なのは:
- OnInitで生成すること
- INVALID_HANDLEチェックを必ず入れること
2.4 よくある失敗
❌ OnTick内でiMAを呼ぶ
毎Tick生成するとメモリ消費・パフォーマンス低下の原因になります。
❌ ハンドルの解放忘れ
EA終了時に IndicatorRelease() を呼ばないとメモリが残る可能性があります。
❌ ENUMの型を誤る
intで無理やり指定するとコンパイルは通っても可読性が悪化します。
iMAの構文を理解しただけでは、まだ移動平均値は取得できません。
3. iMAの正しい使い方(ハンドル取得と管理)
3.1 ハンドル生成の正しいタイミング
MQL5では、iMAは値を取得する関数ではなく、インディケータハンドルを生成する関数です。
そのため、生成タイミングを誤るとパフォーマンスや安定性に問題が発生します。
正しい基本構造は以下です。
int maHandle;
int OnInit()
{
maHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
if(maHandle == INVALID_HANDLE)
{
Print("iMA handle creation failed");
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
なぜOnInitで生成するのか?
- インディケータは一度生成すれば使い回せる
- 毎Tick生成は無駄な処理になる
- テスター速度に大きく影響する
❌ よくある間違い
void OnTick()
{
int handle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
}
これは毎Tick新しいインディケータを生成している状態です。
バックテストが遅くなる原因になります。
3.2 ハンドルの有効性チェック
ハンドル生成直後には必ず INVALID_HANDLE チェックを入れます。
if(maHandle == INVALID_HANDLE)
{
Print("Error creating iMA handle");
return(INIT_FAILED);
}
失敗する主な原因:
- 不正な時間足指定
- シンボルが利用不可
- ヒストリーデータ不足(環境依存)
3.3 インディケータの解放(重要)
MQL5では、生成したインディケータは明示的に解放するのが安全設計です。
void OnDeinit(const int reason)
{
if(maHandle != INVALID_HANDLE)
IndicatorRelease(maHandle);
}
解放しないとどうなる?
- メモリ使用量が増加する可能性
- 長時間稼働EAで不安定化の原因になる場合あり
特にVPS運用では、メモリ管理は軽視できません。
3.4 マルチタイムフレーム使用時の注意
例:M5チャート上でH1の移動平均を取得する場合
maHandle = iMA(_Symbol, PERIOD_H1, 50, 0, MODE_EMA, PRICE_CLOSE);
注意点:
- 上位足のデータがロードされている必要がある
- 初回実行時はデータ不足でCopyBufferが失敗することがある
対策:
if(Bars(_Symbol, PERIOD_H1) < 100)
{
Print("Not enough bars for H1");
return;
}
3.5 実運用視点での設計ポイント
✔ ハンドルはグローバル変数で管理する
→ スコープ外になると再生成が必要になる
✔ 複数MAを使う場合は明確に命名
int maFastHandle;
int maSlowHandle;
✔ 再初期化時の挙動を考慮する
パラメータ変更時はOnDeinit → OnInitが再実行されます。
ハンドル管理が適切でないと異常動作の原因になります。
4. CopyBufferで移動平均値を取得する方法
4.1 CopyBufferとは何か
CopyBuffer() は、インディケータハンドルから実際の計算値を取得するための関数です。
iMAは「ハンドル」を返すだけであり、移動平均の値そのものはCopyBufferで取得します。
基本構文は以下です。
int CopyBuffer(
int indicator_handle, // インディケータハンドル
int buffer_num, // バッファ番号
int start_pos, // 取得開始位置
int count, // 取得本数
double buffer[] // 取得先配列
);
戻り値は「コピーできた要素数」です。
0以下の場合は失敗と判断します。
4.2 基本的な取得例(最新値を取得)
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
if(CopyBuffer(maHandle, 0, 0, 3, maBuffer) <= 0)
{
Print("CopyBuffer failed");
return;
}
各引数の意味
maHandle:iMAで取得したハンドル0:バッファ番号(iMAは基本0)0:現在バーから取得3:3本分取得maBuffer:取得結果格納用配列
4.3 start_posとインデックスの関係(重要)
start_pos = 0 は「現在の未確定バー」を指します。
インデックスの意味:
maBuffer[0]→ 現在バー(未確定)maBuffer[1]→ 1本前(確定済み)maBuffer[2]→ 2本前
実運用での注意
未確定バー(index 0)は価格変動により変化します。
EAロジックでは通常:
double currentMA = maBuffer[1]; // 確定足を使う
未確定バーを使うと、バックテストとリアルが一致しない原因になります。
4.4 ArraySetAsSeriesの意味
ArraySetAsSeries(maBuffer, true);
これを指定すると、
- インデックス0が最新データ
- インデックスが大きいほど過去データ
という扱いになります。
指定しない場合は逆順になるため、ロジックが混乱します。
❌ よくある失敗
- ArraySetAsSeriesを忘れる
- インデックス方向を誤解する
- 取得本数より大きいインデックスを参照する(array out of range)
4.5 取得前に確認すべきこと
① バー数が足りているか
if(Bars(_Symbol, PERIOD_CURRENT) < 50)
{
Print("Not enough bars");
return;
}
期間20のMAなら最低20本以上必要です。
② CopyBufferの戻り値チェック
int copied = CopyBuffer(maHandle, 0, 0, 3, maBuffer);
if(copied <= 0)
{
Print("CopyBuffer failed. Error: ", GetLastError());
return;
}
エラー原因は環境依存の場合があります。
4.6 パフォーマンス設計上の注意
- 毎Tick大量本数を取得しない
- 必要最小限の本数だけ取得する
- ループ内でCopyBufferを多重呼び出ししない
例:
// 不適切
for(int i=0; i<100; i++)
{
CopyBuffer(maHandle, 0, i, 1, maBuffer);
}
これは非常に非効率です。
4.7 最小構成まとめ例
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
int copied = CopyBuffer(maHandle, 0, 0, 2, maBuffer);
if(copied > 0)
{
double prevMA = maBuffer[1]; // 確定足
}
この構造が、MQL5での移動平均取得の基本形です。
5. よくあるエラーと対策(iMA / CopyBufferで詰まる点)
5.1 エラーを切り分ける基本方針
iMAまわりの不具合は、原因が「ロジックの誤り」ではなく、次のどれかであるケースが多いです。
- ハンドル生成に失敗している(iMA側)
- CopyBufferが失敗している(取得側)
- 配列の扱いが間違っている(典型)
- ヒストリーデータ不足(環境依存)
- 未確定足を使って判定が揺れている(実運用で差が出る)
まずは、必ずチェックログを入れて「どこで失敗したか」を確定させます。
int copied = CopyBuffer(maHandle, 0, 0, 3, maBuffer);
if(copied <= 0)
{
int err = GetLastError();
Print("CopyBuffer failed. err=", err);
}
5.2 array out of range(配列範囲外参照)
症状
- 実行時エラーで停止する
- ログに
array out of rangeが出る - 条件判定行で落ちることが多い
主な原因
CopyBufferで取得した本数より大きいインデックスを参照している- 配列サイズが確保されていない(動的配列の初期化不足)
ArraySetAsSeries()の有無でインデックス方向を誤解している
典型例(失敗)
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
CopyBuffer(maHandle, 0, 0, 2, maBuffer);
// 2本しか取得していないのに maBuffer[2] を参照している
double x = maBuffer[2];
対策
- 参照する最大インデックス+1 本を必ず取得する
- CopyBufferの戻り値をチェックしてから参照する
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
int need = 3;
int copied = CopyBuffer(maHandle, 0, 0, need, maBuffer);
if(copied < need)
{
Print("Not enough data copied: ", copied);
return;
}
double prevMA = maBuffer[1];
double prev2MA = maBuffer[2];
5.3 INVALID_HANDLE(ハンドル生成失敗)
症状
iMA handle creation failedなどのログ- CopyBufferが常に失敗する
- EAが初期化失敗(INIT_FAILED)になる
主な原因(環境により異なる)
symbolが利用不可(気配値がない、または指定ミス)periodの指定ミス(例:カスタム足など特殊環境)- 初期起動時にヒストリーが揃っていない
- テスター環境でデータが不足している
対策
- ハンドル生成直後にINVALID_HANDLEを必ず判定
Bars()で最低バー数を確認する(特に上位足)
int OnInit()
{
if(Bars(_Symbol, PERIOD_CURRENT) < 100)
{
Print("Not enough bars yet");
return(INIT_FAILED);
}
maHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
if(maHandle == INVALID_HANDLE)
{
Print("iMA handle creation failed. err=", GetLastError());
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
5.4 CopyBuffer failed(値が取れない/0以下が返る)
症状
- CopyBufferの戻り値が
0または-1など - バッファが常に空、または値が更新されない
主な原因
- まだ計算できるだけのデータがない(最頻出)
- start_pos / count の指定が過剰
- ハンドルが無効(INVALID_HANDLEのまま)
- 未確定足を前提にしてロジックが壊れている
対策
- 取得本数を最小限にする(2〜3本で十分なことが多い)
- バー数不足なら待機する設計にする
- 必ず確定足([1])を使う
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
if(Bars(_Symbol, PERIOD_CURRENT) < 30) return;
int copied = CopyBuffer(maHandle, 0, 0, 2, maBuffer);
if(copied < 2)
{
Print("CopyBuffer not ready. copied=", copied, " err=", GetLastError());
return;
}
double maConfirmed = maBuffer[1];
5.5 値が0になる/あり得ない値になる
症状
- MAが0付近のまま
- 価格とかけ離れた値になる
- テスター開始直後だけ変
主な原因
- そもそもデータが揃っていない(開始直後)
- series配列の方向を誤解(ArraySetAsSeries忘れ)
- 「現在バー(未確定)」を参照して揺れる
対策
- 初回は一定バーが溜まるまで計算しない
maBuffer[1]を使う(確定足)
5.6 実運用で差が出る“危険ポイント”
⚠ 未確定足(index 0)を使う
バックテストとリアルで結果が一致しない原因になります。
EAの判定は基本「確定足」を前提にします。
⚠ 毎TickでCopyBuffer大量取得
VPS運用や複数通貨EAでは、重くなる原因になります。
必要最小限の本数を取得する設計が安全です。
6. 実運用での注意点(パフォーマンス設計と安全設計)
6.1 毎Tickでの無駄な処理を避ける
iMA/CopyBufferを使ったEAで最も多い設計ミスは、毎Tickで不要な計算を繰り返すことです。
❌ よくある非効率な例
void OnTick()
{
double maBuffer[];
ArraySetAsSeries(maBuffer, true);
CopyBuffer(maHandle, 0, 0, 100, maBuffer);
}
問題点:
- 毎Tick100本取得している
- 必要以上にメモリ確保が発生
- 複数通貨EAでは負荷が急増
✔ 改善方針
- 必要最小限(通常2〜3本)だけ取得
- 「新しいバーが確定したときのみ」更新
6.2 新バー判定を入れる(実戦設計)
移動平均を使ったロジックの多くは「確定足ベース」です。
そのため、新しいバーができたタイミングだけ処理すれば十分なケースが多いです。
datetime lastBarTime = 0;
void OnTick()
{
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
if(currentBarTime == lastBarTime)
return;
lastBarTime = currentBarTime;
// ここにMA取得処理を書く
}
これにより:
- Tickごとの無駄なCopyBufferを防げる
- テスター速度が向上する
- ロジックが安定する
6.3 マルチシンボルEAでの注意
複数通貨でiMAを使う場合、以下に注意が必要です。
✔ 各シンボルごとにハンドルを管理する
int maHandle_EURUSD;
int maHandle_USDJPY;
✔ 各通貨のバー更新タイミングは異なる
iTime() 判定もシンボルごとに必要になります。
⚠ よくある失敗
- 1つの配列を使い回す
- シンボルが異なるのに
_Symbol固定で処理する
6.4 IndicatorReleaseを忘れない
EAが停止・再初期化されるたびにハンドルは再生成されます。
解放処理を入れないと、長時間稼働で不安定化する可能性があります。
void OnDeinit(const int reason)
{
if(maHandle != INVALID_HANDLE)
IndicatorRelease(maHandle);
}
特にVPS常時運用では重要です。
6.5 未確定足を使わない(バックテスト差異の原因)
❌ 危険な例
double currentMA = maBuffer[0];
maBuffer[0] は現在形成中の足です。
リアルでは値が変動しますが、バックテストでは条件次第で確定値扱いになることがあります。
✔ 推奨
double confirmedMA = maBuffer[1];
確定足のみでロジックを組むと、再現性が高くなります。
6.6 フォワード検証を前提にした設計思想
実運用では次を意識します。
- MA期間変更時の再初期化挙動
- データ不足時の待機設計
- CopyBuffer失敗時に即エントリーしない
- エラー発生時のログ出力
例:
if(copied < 2)
{
Print("MA data not ready. Skip trading.");
return;
}
「値が取れなければ取引しない」設計が安全です。
6.7 設計まとめ(実戦基準)
安全なiMA設計の基本原則:
- ハンドルはOnInitで生成
- 新バー確定時のみ更新
- CopyBufferは最小本数
- 確定足のみ使用
- 必ずエラーチェック
- OnDeinitで解放
これらを守るだけで、EAの安定性は大きく向上します。
7. EAへの組み込み例(ゴールデンクロス判定と落とし穴)
7.1 ゴールデンクロス判定の基本
移動平均をEAに組み込む代表例が、短期MAと長期MAのクロス判定です。
- 短期MAが長期MAを下から上へ抜ける → ゴールデンクロス(買いシグナル)
- 短期MAが長期MAを上から下へ抜ける → デッドクロス(売りシグナル)
重要なのは「今の位置」ではなく、直前(確定足)との比較でクロスを検出することです。
7.2 2本のMAハンドルを作成する(OnInit)
int maFastHandle;
int maSlowHandle;
int OnInit()
{
maFastHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
if(maFastHandle == INVALID_HANDLE)
{
Print("Fast MA handle failed. err=", GetLastError());
return(INIT_FAILED);
}
maSlowHandle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE);
if(maSlowHandle == INVALID_HANDLE)
{
Print("Slow MA handle failed. err=", GetLastError());
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
7.3 CopyBufferで確定足2本を取得する(新バーでのみ)
クロス判定には最低でも「確定足2本分」が必要です。
(1本前と2本前を比較するため)
bool GetMAValues(int handle, double &v1, double &v2)
{
double buf[];
ArraySetAsSeries(buf, true);
int copied = CopyBuffer(handle, 0, 1, 2, buf); // 1=確定足から2本
if(copied < 2)
return false;
v1 = buf[0]; // 1本前(確定足)
v2 = buf[1]; // 2本前(確定足)
return true;
}
ここでのポイント:
start_pos = 1(未確定足を避ける)count = 2(クロス判定に必要な最低本数)
7.4 クロス判定ロジック(確定足ベース)
void OnTick()
{
static datetime lastBarTime = 0;
datetime t = iTime(_Symbol, PERIOD_CURRENT, 0);
if(t == lastBarTime) return;
lastBarTime = t;
double fast1, fast2, slow1, slow2;
if(!GetMAValues(maFastHandle, fast1, fast2))
{
Print("Fast MA not ready");
return;
}
if(!GetMAValues(maSlowHandle, slow1, slow2))
{
Print("Slow MA not ready");
return;
}
bool goldenCross = (fast2 <= slow2) && (fast1 > slow1);
bool deadCross = (fast2 >= slow2) && (fast1 < slow1);
if(goldenCross)
Print("Golden Cross detected (confirmed bar)");
if(deadCross)
Print("Dead Cross detected (confirmed bar)");
}
この判定は「クロスした瞬間」を確定足で捉えます。
バックテストとリアルの差が出にくい、実運用向けの書き方です。
7.5 よくある落とし穴(ここで詰まる)
❌ 位置判定だけでクロスと誤認する
例:短期が上なら買い、下なら売り、のような単純判定。
問題点:
- 「すでに上にいる状態」を毎回シグナル扱いしてしまう
- 連続エントリーの原因になる
クロスは前の状態→現在の状態の変化で判断します。
❌ 未確定足(0番)でクロス判定する
未確定足で判定すると、次のような問題が起きます。
- Tickごとにクロス判定が揺れる
- 「クロスした→戻った→またクロス」のような誤検出
- バックテストとリアルで結果が変わりやすい
対策は start_pos=1 を徹底することです。
❌ CopyBufferの取得開始位置を誤る
例:CopyBuffer(handle, 0, 0, 2, buf) とすると、
- buf[0] は未確定足
- buf[1] は確定足
になり、比較が混乱しやすいです。
クロス判定は「確定足だけ」で完結させるのが安全です。
7.6 実戦向けの追加安全策
クロス判定は単体だとノイズが多い戦略になりやすいです。
実運用ではフィルターを組み合わせるのが一般的です。
例:
- スプレッドが広いときは取引しない
- 一定時間は再エントリー禁止
- 上位足のMA方向と一致したときのみ有効
8. 関連トピック(今後拡張予定)
本記事では、MQL5におけるiMAの基本構文から、CopyBufferによる値取得、EAへの組み込み方法までを解説しました。
ただし、iMAを実戦レベルで使いこなすためには、以下の周辺トピックの理解が不可欠です。
8.1 CopyBufferの完全理解
iMAはハンドルを返すだけであり、実際の値取得はCopyBufferに依存します。
今後解説予定の内容:
- バッファ番号の仕組み
- start_posとcountの正確な意味
- ArraySetAsSeriesの内部挙動
- パフォーマンスを落とさない取得設計
- 複数バッファを持つインジケータの扱い方
iMAだけ理解しても、CopyBufferを誤るとほぼ確実にバグの温床になります。
8.2 array out of range完全対策
MQL5初心者が最も頻繁に遭遇する実行時エラーです。
今後解説予定:
- 発生メカニズムの詳細
- CopyBufferと配列サイズの関係
- series配列方向ミスの検出方法
- 再発防止テンプレートコード
- 実戦EAでの防御設計
エラー対策を体系化することで、EAの安定性は大きく向上します。
8.3 iCustomとの違い
iMAは標準インジケータですが、カスタムインジケータを扱う場合は iCustom を使用します。
予定解説内容:
- iCustomの基本構文
- パラメータの渡し方
- バッファ番号の特定方法
- マルチバッファインジケータの管理
- ハンドル管理の共通設計
iMAを理解した段階で、iCustomへ進むのが自然な流れです。
8.4 移動平均を用いたEA設計思想
単純なクロス戦略はノイズが多く、実運用ではそのままでは通用しません。
今後扱うテーマ:
- フィルター設計(上位足方向一致)
- エントリー頻度制御
- ロット自動計算との連携
- 最大ドローダウン制御との統合
- フォワード検証前提の構造設計
本サイトでは、単なるコード紹介ではなく、安全設計と再現性を重視したEA構造を扱います。
8.5 本記事の位置付け
本記事は、MQL5におけるインディケータ取得の「最初の基礎」です。
ここを正しく理解していない場合:
- バックテストとリアルが一致しない
- CopyBufferエラーで停止する
- 配列エラーで実行時停止する
- パフォーマンスが著しく低下する
といった問題が発生します。
iMAは単純に見えて、MQL5のハンドル構造・バッファ構造・系列配列の理解を要求する関数です。
この理解を土台として、次はCopyBufferの詳細設計へ進みます。
9. よくある質問(FAQ)
9.1 MQL5でiMAの値が0になるのはなぜですか?
主な原因は次のいずれかです。
- ヒストリーデータが不足している(バー数不足)
- CopyBufferが正常に値を取得できていない
- 取得開始位置(start_pos)や取得本数(count)が不適切
- テスター開始直後でまだ十分なデータが形成されていない
対策:
Bars()で必要本数以上あるか確認する- CopyBufferの戻り値を必ずチェックする
- 確定足(index 1以降)を使用する
値が0だからといってロジックをそのまま進めると、誤エントリーの原因になります。
9.2 MQL4のiMAとの違いは何ですか?
最大の違いは「ハンドル方式」です。
- MQL4:
iMA()が直接値を返す - MQL5:
iMA()はハンドルを返し、値取得はCopyBufferで行う
そのため、MQL4のコードをそのまま移植すると動きません。
特に初心者が混乱しやすいのは、「iMAが値を返さない」点です。
MQL5では必ず「ハンドル生成 → CopyBuffer取得」の流れになります。
9.3 CopyBufferで何本取得すればよいですか?
用途により異なります。
- 単純な値参照:2本(確定足とその前)
- クロス判定:最低2本(前状態との比較が必要)
- 傾き判定:3本以上
重要なのは、参照する最大インデックス以上の本数を必ず取得することです。
不足すると array out of range エラーになります。
9.4 iMAを毎Tickで呼ぶと問題になりますか?
推奨されません。
理由:
- 毎Tickインディケータを生成すると無駄な負荷が発生する
- バックテスト速度が低下する
- 複数通貨EAではパフォーマンス問題が顕在化する
安全な設計:
- OnInitでハンドル生成
- 新バー確定時のみCopyBuffer実行
9.5 未確定足(index 0)を使ってもよいですか?
技術的には可能ですが、実運用では推奨されません。
理由:
- 未確定足は価格変動により値が変化する
- バックテストとリアルの結果が一致しにくくなる
- クロス判定が揺れやすい
再現性を重視する場合は、確定足(index 1以降)を使用します。