開発実務ノート

MQL5インジケーターEA化実務ノート|サイン取得・確定足・リペイント確認の考え方

MQL5インジケーターEA化実務ノート|サイン取得・確定足・リペイント確認の考え方の内容を表す、Signal・確定足・repaintの確認用アイキャッチ画像
EAファンクラブ

MQL5でサインインジケーターをEA化する時、単に「矢印が出たらエントリー」と考えると、実装後に問題が出やすくなります。

インジケーターのサインは、表示されている見た目だけで判断できるとは限りません。どのbufferにサイン値が入るのか、shift=0を見るのかshift=1を見るのか、未確定足で値が変わるのか、過去サインがリペイントするのか、CopyBufferが失敗した時にどう扱うのかを整理する必要があります。

インジケーターEA化で重要なのは、表示サイン、取得値、確定足、Signal Snapshot、Entry判断を分けることです。

この記事では、MQL5でインジケーターサインをEA化する時の設計判断を、開発実務ノートとして整理します。完成EAソース全文、独自インジケーターの中核条件、外部シート制御ロジック、認証ロジック、endpoint、token、URL実値、実運用set値、中核Entry条件は公開しません。

本記事は、投資判断や売買指示ではなく、MQL5のインジケーターEA化を設計・検証・サポートしやすくするための技術記事です。

この記事で扱う実務課題

項目この記事で扱う内容扱わない内容
目的インジケーターサインをEA化する時の値取得・確定足・リペイント確認利益を狙う売買ロジック、具体的なEntry条件
主な対象iCustom、CopyBuffer、buffer番号、shift、確定足、Signal Snapshot完成EAソース全文、実運用コード全文
設計観点サイン取得失敗、未確定足変動、リペイント、ログ追跡、検証再現性独自インジケーターの中核ロジック、実運用set値
コード例一般化したhandle管理、CopyBuffer取得、Snapshot化、確定足判定実サイン条件、独自優位性のある判定式
読者MQL5開発者、サインインジをEA化したい人、検証担当者売買判断や推奨設定を知りたい人

なぜインジケーターEA化では設計整理が必要なのか

チャート上で矢印やサインが見えていても、EA側で同じタイミング・同じ値を取得できるとは限りません。

インジケーターEA化でよく起きる問題は次の通りです。

現象原因の例確認すべき責務
サインが見えるのにEAが入らないbuffer番号違い、shift違い、CopyBuffer失敗indicator read / signal snapshot
EAが早すぎる場所で入る未確定足shift=0を使っているconfirmed bar / signal timing
過去検証とリアルが違うリペイント、未確定足変動、計算タイミング差repaint check / validation
サインが消えたのにEntryしている一時的な値をSnapshotとして固定しているsnapshot policy / gate
EAを再起動すると挙動が変わるhandle再作成、初期バー不足、履歴読み込み不足OnInit / handle / bars ready
バックテストとリアルで一致しないtick model、未確定足、インジ内部仕様の差BT condition / realtime validation

インジケーターEA化では、表示されているサインとEAが取得する値を分けて確認して確認する必要があります。

インジケーターEA化で分けるべき責務

サインインジケーターをEA化する時は、次の責務を分けます。

責務役割混同すると起きる問題
indicator handleiCustomなどでインジケーターハンドルを作るhandle不正、再初期化不備、解放漏れが起きる
buffer readCopyBufferで値を取得する取得失敗とサインなしを混同する
signal snapshot取得した値を判定用に固定する未確定足の変動に振り回される
confirmed bar確定足で判定するかを決めるリアルで早すぎるEntryになる
repaint check過去サインが変わるか確認するバックテスト上だけ良く見える可能性がある
entry gateサインがあってもEntryしてよいか確認するriskや重複発注の制御を飛ばす
log取得値、shift、buffer、reasonを記録するサイン不一致の原因を追えない

特に重要なのは、CopyBufferで値が取れなかった状態と、サインがない状態を混同しないことです。

iCustomとインジケーターハンドルの考え方

MQL5でカスタムインジケーターをEAから使う場合、iCustomなどでインジケーターハンドルを作成します。

ハンドルが正しく作成できていない場合、CopyBufferで値を取得できません。また、EA終了時や再初期化時には、必要に応じてIndicatorReleaseで解放する設計も必要です。

確認項目確認する理由
handleがINVALID_HANDLEではないかインジケーターが作成できているか確認するため
インジケーター名が正しいかファイル名、パス、拡張子の扱いを確認するため
input引数が一致しているかチャート表示時とEA呼び出し時の条件差を防ぐため
必要バー数が揃っているか計算前の値を使わないため
OnDeinitで解放するかhandle管理を明確にするため

ハンドル作成失敗は、サインなしではありません。ログ上もHANDLE_FAILやINVALID_HANDLEとして分ける必要があります。

CopyBufferで見るべきポイント

CopyBufferは、インジケーターのbuffer値をEA側で取得するために使います。

CopyBufferで重要なのは、どのbuffer番号から、どのshiftの値を、何本取得するかです。

項目意味確認すること
buffer indexどのbufferを見るかBUYサイン、SELLサイン、補助値がどのbufferか
shiftどの足を見るか0は未確定足、1は直近確定足として扱うことが多い
count何本取得するか1本だけで足りるか、過去比較が必要か
戻り値取得できた本数取得失敗と値なしを分ける
EMPTY_VALUEサインなし表現の候補インジ仕様により0やEMPTY_VALUEの扱いが違う

CopyBufferが失敗した場合は、サインなしではなく、値取得失敗です。ENTRY判定へ進める前に、取得結果を検証します。

ハンドルの生成・取得・解放を確認する

以下のコード例は、個別の処理と確認項目を読むためのものです。複数の例をそのまま一つのEAへ連結する前提ではありません。初期化、値の取得、状態更新、終了処理をそれぞれの例で区別して確認してください。

CopyBufferとhandle管理の関係

CopyBufferは、インジケーターのbuffer値を取得するための関数です。ただし、CopyBufferを使うには、先に対象インジケーターのhandleを作成しておく必要があります。

要素役割確認ポイント
handleインジケーターを参照する識別子INVALID_HANDLEではないか
CopyBufferhandleからbuffer値を取得するbuffer番号、shift、取得本数、戻り値を確認する
BarsCalculatedインジケーター計算済みバー数を確認する必要本数以上あるか
IndicatorRelease不要になったhandleを解放するOnDeinitや再生成時に扱う
ログ取得失敗の原因を追うhandle、copied、last_errorを記録する

CopyBufferが失敗した時は、まずhandleが正しく作られているかを確認します。handleがINVALID_HANDLEであれば、CopyBuffer以前の問題です。

handleはOnInitで作り、OnTickで使う

EAでは、インジケーターハンドルをOnTickで毎回作り直すのではなく、OnInitで作成し、OnTickではそのhandleを使って値を取得する構成が基本です。

場所主な役割注意点
OnInithandle生成、初期チェックINVALID_HANDLEならINIT_FAILEDで止める判断も可能
OnTickCopyBufferで値を取得し、判定へ使う毎tickでhandleを作り直さない
OnDeinitIndicatorReleaseでhandleを解放するhandleが有効な時だけ解放する
再初期化時時間足変更、EA再セットなど古いhandleを使い続けない

handle生成と値取得を分けることで、取得失敗時に「handle生成の問題」なのか「CopyBufferの問題」なのかを原因を確認しやすくなります。

基本のhandle管理コード例

以下は、iMAのhandleをOnInitで作成し、OnTickでCopyBufferを使い、OnDeinitでIndicatorReleaseする基本例です。

int ma_handle = INVALID_HANDLE;

int OnInit()
{
   ResetLastError();

   ma_handle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
   int err = GetLastError();

   Print("HANDLE_CREATE",
         " indicator=iMA",
         " symbol=", _Symbol,
         " timeframe=", PERIOD_CURRENT,
         " handle=", ma_handle,
         " last_error=", err);

   if(ma_handle == INVALID_HANDLE)
      return INIT_FAILED;

   return INIT_SUCCEEDED;
}

void OnTick()
{
   double values[];
   ArraySetAsSeries(values, true);

   ResetLastError();

   int copied = CopyBuffer(ma_handle, 0, 0, 3, values);
   int err = GetLastError();

   Print("COPYBUFFER_TRACE",
         " copied=", copied,
         " last_error=", err);

   if(copied < 2)
      return;

   double ma_closed = values[1];
   Print("MA_CLOSED_VALUE value=", DoubleToString(ma_closed, _Digits));
}

void OnDeinit(const int reason)
{
   if(ma_handle != INVALID_HANDLE)
   {
      IndicatorRelease(ma_handle);
      ma_handle = INVALID_HANDLE;
   }
}

この例では、EA判定に1本前の確定足であるvalues[1]を使っています。現在足を使うのか、確定足を使うのかはEA仕様として明示してください。

OnTickでhandleを作り直さない理由

OnTickで毎回iMAやiCustomを呼び、handleを作り直す実装は避けるべきです。

問題内容影響
処理負荷が増えるtickごとにhandle生成処理が走る複数インジや複数時間足で重くなる
状態が安定しない計算準備前にCopyBufferを呼ぶ可能性がある取得失敗や初期値混入が起きやすい
解放漏れが起きる古いhandleをReleaseしないまま増えるリソース管理が不明瞭になる
原因調査が難しくなるhandle生成とCopyBuffer失敗が混ざるログから原因を追いにくい

handleは、対象symbol、timeframe、period、inputが変わらない限り、基本的には使い回します。パラメータ変更や時間足変更が必要な場合は、古いhandleを解放してから再生成する流れを明示します。

INVALID_HANDLEを確認する

handle生成後は、必ずINVALID_HANDLEかどうかを確認します。

INVALID_HANDLEのままCopyBufferを呼んでも、正しい値は取得できません。特にiCustomでは、ファイル名、サブフォルダ、input順序、input型の不一致が原因でhandle生成に失敗することがあります。

handle生成元主な失敗原因確認ログ
iMA / iRSI / iATRsymbol、timeframe、period不正HANDLE_CREATE
iCustomインジ名、配置パス、input順序不一致ICUSTOM_HANDLE
複数時間足対象時間足のデータ不足HANDLE_CREATE / BARS_CHECK
複数銘柄Market Watch未選択、suffix違いSYMBOL_CHECK

handle生成失敗は、CopyBuffer側ではなく初期化処理の問題として扱います。EA全体を止めるのか、該当インジケーターだけ無効化するのかは仕様として決めてください。

handle生成専用関数を作る

複数のインジケーターを扱うEAでは、handle生成を関数化するとログや失敗時の扱いを統一できます。

int CreateRsiHandle(const string symbol,
                    const ENUM_TIMEFRAMES timeframe,
                    const int period)
{
   ResetLastError();

   int handle = iRSI(symbol, timeframe, period, PRICE_CLOSE);
   int err = GetLastError();

   Print("HANDLE_CREATE",
         " indicator=iRSI",
         " symbol=", symbol,
         " timeframe=", timeframe,
         " period=", period,
         " handle=", handle,
         " last_error=", err);

   if(handle == INVALID_HANDLE)
      return INVALID_HANDLE;

   return handle;
}

このように関数化しておくと、handle生成時のログ形式を統一できます。複数インジケーターを使うEAでは、インジケーター名、symbol、timeframe、period、handle、last_errorを必ず追えるようにします。

BarsCalculatedで計算準備を確認する

handleが作れていても、インジケーターの計算がまだ終わっていない場合は、CopyBufferで期待する本数を取得できないことがあります。

この時に使うのがBarsCalculatedです。BarsCalculatedで計算済みバー数を確認し、必要本数に達していない場合は判定を見送ります。

bool IsHandleReady(const int handle, const int required_bars)
{
   if(handle == INVALID_HANDLE)
   {
      Print("HANDLE_READY status=NG reason=INVALID_HANDLE");
      return false;
   }

   int calculated = BarsCalculated(handle);

   Print("HANDLE_READY",
         " calculated=", calculated,
         " required=", required_bars);

   if(calculated < required_bars)
      return false;

   return true;
}

EA起動直後、バックテスト開始直後、時間足変更直後、重いカスタムインジケーターを呼んだ直後は、BarsCalculatedが不足する場合があります。この状態を異常と断定せず、準備未完了として扱います。

CopyBufferの戻り値を必ず確認する

CopyBufferの戻り値は、実際に取得できたデータ数です。

戻り値意味確認すること
要求本数と同じ取得成功値の中身を確認する
0取得できた本数が0BarsCalculated、対象バー、buffer番号を確認する
-1取得失敗GetLastError、handle、buffer番号を確認する
要求本数未満一部しか取得できていない配列参照前に本数不足を扱う

CopyBufferが失敗しているのに配列を参照すると、古い値や未初期化値を使う可能性があります。必ずcopiedを確認してから配列を参照してください。

安全に値を取得するhelper例

実務では、CopyBufferを直接あちこちに書くより、安全取得helperを作ると確認しやすくなります。

bool CopyOneIndicatorValue(const int handle,
                           const int buffer_index,
                           const int shift,
                           double &out_value)
{
   out_value = EMPTY_VALUE;

   if(handle == INVALID_HANDLE)
   {
      Print("COPY_ONE status=NG reason=INVALID_HANDLE");
      return false;
   }

   int calculated = BarsCalculated(handle);

   if(calculated <= shift)
   {
      Print("COPY_ONE status=WAIT reason=BARS_NOT_READY",
            " calculated=", calculated,
            " shift=", shift);
      return false;
   }

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

   ResetLastError();

   int copied = CopyBuffer(handle, buffer_index, shift, 1, temp);
   int err = GetLastError();

   Print("COPY_ONE",
         " buffer=", buffer_index,
         " shift=", shift,
         " copied=", copied,
         " calculated=", calculated,
         " last_error=", err);

   if(copied != 1)
      return false;

   out_value = temp[0];
   return true;
}

このhelperでは、INVALID_HANDLE、BarsCalculated不足、CopyBuffer戻り値、GetLastErrorをまとめて確認しています。実際のEAでは、ログ出力頻度を制御し、成功ログを毎tick出しすぎないようにします。

EMPTY_VALUEと取得失敗を分ける

CopyBufferが成功していても、取得した値がEMPTY_VALUEの場合があります。

特に、矢印サインや条件成立時だけ値を出すインジケーターでは、サインがないバーにEMPTY_VALUEが入ることがあります。この場合、CopyBufferの失敗ではなく、サインなしとして扱う方が自然です。

状態意味EA側の扱い
CopyBuffer失敗値を取得できていないhandle、BarsCalculated、GetLastErrorを確認
CopyBuffer成功 + EMPTY_VALUEそのバーにサインがないWAITまたはNO_SIGNALとして扱う
CopyBuffer成功 + 有効値判定に使える値があるsignal評価へ進む
0.0有効値か未初期化かはインジ仕様次第インジ側仕様を確認する

取得失敗とサインなしを混同すると、正常なWAIT状態をエラー扱いしてしまいます。EA内部では、値取得の成否とsignal成立を分けて扱ってください。

複数インジケーターのhandle管理

EAで複数のインジケーターを使う場合は、それぞれのhandleを分けて管理します。

たとえば、MA、RSI、ATRを使う場合、それぞれのhandle、buffer番号、必要本数、取得値、ログを分けておくと原因を追いやすくなります。

int ma_handle  = INVALID_HANDLE;
int rsi_handle = INVALID_HANDLE;
int atr_handle = INVALID_HANDLE;

int OnInit()
{
   ma_handle  = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
   rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
   atr_handle = iATR(_Symbol, PERIOD_CURRENT, 14);

   if(ma_handle == INVALID_HANDLE)
      return INIT_FAILED;

   if(rsi_handle == INVALID_HANDLE)
      return INIT_FAILED;

   if(atr_handle == INVALID_HANDLE)
      return INIT_FAILED;

   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
   if(ma_handle != INVALID_HANDLE)
      IndicatorRelease(ma_handle);

   if(rsi_handle != INVALID_HANDLE)
      IndicatorRelease(rsi_handle);

   if(atr_handle != INVALID_HANDLE)
      IndicatorRelease(atr_handle);

   ma_handle  = INVALID_HANDLE;
   rsi_handle = INVALID_HANDLE;
   atr_handle = INVALID_HANDLE;
}

この例では簡略化していますが、実務では各handle作成時にログを出し、どのインジケーターで失敗したか分かるようにします。

複数時間足のhandle管理

複数時間足の値を使う場合は、同じインジケーターでも時間足ごとに別handleを作成します。

例handle注意点
M15のMAma_m15_handleM15のバー数と確定足を確認する
H1のMAma_h1_handleH1のBarsCalculatedを別に確認する
H4のATRatr_h4_handle上位足の履歴不足に注意する
現在チャートPERIOD_CURRENT時間足変更時に再初期化される点を考慮する

複数時間足では、現在チャートのバー数と上位足のバー数が一致しません。CopyBufferで値を取得する前に、対象時間足のバーが十分あるかを確認します。

複数時間足handleのコード例

int ma_m15_handle = INVALID_HANDLE;
int ma_h1_handle  = INVALID_HANDLE;

int OnInit()
{
   ma_m15_handle = iMA(_Symbol, PERIOD_M15, 20, 0, MODE_SMA, PRICE_CLOSE);
   ma_h1_handle  = iMA(_Symbol, PERIOD_H1,  20, 0, MODE_SMA, PRICE_CLOSE);

   if(ma_m15_handle == INVALID_HANDLE)
   {
      Print("INIT_FAILED reason=MA_M15_HANDLE");
      return INIT_FAILED;
   }

   if(ma_h1_handle == INVALID_HANDLE)
   {
      Print("INIT_FAILED reason=MA_H1_HANDLE");
      return INIT_FAILED;
   }

   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
   if(ma_m15_handle != INVALID_HANDLE)
      IndicatorRelease(ma_m15_handle);

   if(ma_h1_handle != INVALID_HANDLE)
      IndicatorRelease(ma_h1_handle);

   ma_m15_handle = INVALID_HANDLE;
   ma_h1_handle  = INVALID_HANDLE;
}

複数時間足では、どのhandleがどの時間足を見ているかログや変数名で分かるようにします。M15の値とH1の値を同じ変数で扱うと、判定ミスやログ確認ミスにつながります。

iCustomのhandle管理

iCustomでカスタムインジケーターを呼ぶ場合も、基本は同じです。OnInitでhandleを作成し、OnTickでCopyBufferを使います。

ただし、iCustomではインジケーター名、サブフォルダ、input順序、input型、buffer番号の確認が追加で必要になります。

int custom_handle = INVALID_HANDLE;

int OnInit()
{
ResetLastError();

custom_handle = iCustom(_Symbol,
PERIOD_CURRENT,
"Custom\u005c\u005cMySignal",
20,
2.0,
true);

int err = GetLastError();

Print("ICUSTOM_HANDLE",
" handle=", custom_handle,
" last_error=", err);

if(custom_handle == INVALID_HANDLE)
return INIT_FAILED;

return INIT_SUCCEEDED;
}

サブフォルダ内のインジケーターを呼ぶ場合、パス指定を間違えるとhandle生成に失敗します。また、インジケーター側inputが変更された場合、EA側のiCustom引数も更新する必要があります。

IndicatorReleaseの考え方

IndicatorReleaseは、不要になったインジケーターハンドルを解放するために使います。

EA終了時、インジケーター再生成時、設定変更により古いhandleが不要になった時などに使います。ただし、使用中のhandleを誤って解放すると、その後のCopyBufferで値が取れなくなります。

場面IndicatorReleaseの扱い注意点
EA終了時OnDeinitで解放するINVALID_HANDLEでない時だけ実行する
handle再生成時古いhandleを先に解放する新旧handleを混同しない
設定変更時必要なら再生成するruntime変更とinput初期値を分ける
OnTick中通常は毎tick解放しない値取得直後に解放し続ける設計は避ける

IndicatorRelease後は、対象handle変数をINVALID_HANDLEへ戻しておくと、古いhandleを誤って使い続けるリスクを下げられます。

安全にhandleを解放するコード例

void ReleaseHandle(int &handle, const string label)
{
   if(handle == INVALID_HANDLE)
   {
      Print("HANDLE_RELEASE_SKIP label=", label,
            " reason=INVALID_HANDLE");
      return;
   }

   bool released = IndicatorRelease(handle);

   Print("HANDLE_RELEASE",
         " label=", label,
         " released=", released ? "Y" : "N");

   handle = INVALID_HANDLE;
}

このように、解放対象のラベルをログに出しておくと、どのhandleを解放したのか確認しやすくなります。

バックテスト開始直後の値取得に注意する

Strategy Testerでは、テスト開始直後にインジケーター計算や履歴データの準備が完了していない場合があります。

この状態でCopyBufferを呼ぶと、戻り値が0や-1になったり、BarsCalculatedが不足していたりすることがあります。

確認項目見る内容対応
テスト開始直後必要本数がそろっているかウォームアップ期間を設ける
BarsCalculated計算済みバー数required未満なら判定しない
複数時間足上位足の履歴があるか対象timeframeごとに確認する
iCustomテスターで読み込めているかICUSTOM_HANDLEログを見る

EAでは、ウォームアップ不足の状態をエラーとして扱うのではなく、判定待ちとして扱う方が自然です。ログ上も、ERRORではなくWAITやNOT_READYとして出すと確認しやすくなります。

値取得とsignal判定を分ける

CopyBufferで取得した値を、そのまま発注処理へつなげるのは避けます。

EA側では、値取得、値の妥当性確認、signal判定、entry gate、executionを分けます。こうすることで、どの段階で止まったのかログから追いやすくなります。

責務内容ログ例
handle管理インジケーターhandleを作成・保持・解放するHANDLE_CREATE / HANDLE_RELEASE
値取得CopyBufferで値を取るCOPYBUFFER_TRACE
妥当性確認EMPTY_VALUEやNaNを確認するVALUE_VALIDATE
signal判定BUY / SELL / WAITへ変換するSIGNAL_EVAL
entry gateスプレッド、時間、ポジション数などを見るENTRY_GATE
executionOrderSendやCTradeを実行するORDER_SEND

この分離がないと、CopyBufferの値取得失敗なのか、シグナル条件不成立なのか、発注前制限で止まったのかが分かりにくくなります。

取得値をsignalへ変換する例

enum ESignalState
{
   SIGNAL_STATE_WAIT = 0,
   SIGNAL_STATE_BUY  = 1,
   SIGNAL_STATE_SELL = 2
};

ESignalState ResolveMaSignal(const double close_price,
                             const double ma_value)
{
   if(ma_value == EMPTY_VALUE)
      return SIGNAL_STATE_WAIT;

   if(!MathIsValidNumber(ma_value))
      return SIGNAL_STATE_WAIT;

   if(close_price > ma_value)
      return SIGNAL_STATE_BUY;

   if(close_price < ma_value)
      return SIGNAL_STATE_SELL;

   return SIGNAL_STATE_WAIT;
}

この例では、CopyBufferで取得したMA値をEA内部のsignal状態へ変換しています。実際のEAでは、この後にスプレッド、時間帯、既存ポジション、Magic Number、証拠金、OrderCheckなどの条件を確認してから発注処理へ進みます。

ログ設計で原因を追えるようにする

CopyBufferとhandle管理では、ログ設計が重要です。

単に「値が取れない」と出すだけでは、handle生成失敗なのか、BarsCalculated不足なのか、buffer番号の誤りなのか、EMPTY_VALUEなのか判断できません。

ログ名出す内容目的
HANDLE_CREATEindicator、symbol、timeframe、handle、last_errorhandle生成の成否を確認する
HANDLE_READYBarsCalculated、required計算準備状態を確認する
COPYBUFFER_TRACEbuffer、shift、count、copied、last_errorCopyBuffer結果を確認する
VALUE_VALIDATEEMPTY_VALUE、NaN、有効値値の妥当性を確認する
HANDLE_RELEASElabel、released解放処理を確認する
SIGNAL_EVAL取得値、basis、判定結果EA内部判定を確認する

成功ログを毎tick大量に出すと、Expertsログが読みにくくなります。検証中は詳細ログ、本番運用では失敗時または状態変化時だけ出すなど、ログレベルを分けると扱いやすくなります。

shift=0とshift=1の違い

CopyBuffer()ではstart_pos=0が現在足です。インジケーターEA化で確定足のサインを使う場合、現在足の変化中値を読むのか、確定済みバーを読むのかを仕様として固定してください。画面上の矢印とbuffer値のタイミングが同じとは限らないため、時刻・buffer番号・shiftをログで照合します。

インジケーターEA化で重要なのが、shiftの扱いです。

一般的に、shift=0は現在形成中の足、shift=1は直近の確定足を意味します。未確定足のサインは、足が確定するまで変わる場合があります。

shift意味注意点
shift=0現在足リアルタイムで値が変わる可能性がある
shift=1直近確定足確定後の値として扱いやすい
shift=2以降過去足リペイント確認や過去比較に使う場合がある

EA化では、サインを早く拾いたいのか、確定後に安定して拾いたいのかを仕様として決める必要があります。

未確定足で動くEAは、早く反応できる一方で、サインが消えたり変わったりする可能性を受け入れる必要があります。確定足で動くEAは、反応は遅くなりますが、検証再現性は高めやすくなります。

標準インジケーターの値をEAへ取り込む

以下のコード例は、個別の処理と確認項目を読むためのものです。複数の例をそのまま一つのEAへ連結する前提ではありません。初期化、値の取得、状態更新、終了処理をそれぞれの例で区別して確認してください。

MQL5でEAにインジケーター値を取り込む基本

MQL5では、EAからインジケーター値を使いたい場合、まずインジケーターハンドルを作成します。ハンドルとは、MT5内部で作成されたインジケーター計算結果へアクセスするための識別子です。

たとえば、移動平均線ならiMA、ATRならiATR、RSIならiRSIでハンドルを作成します。その後、CopyBufferを使って、指定したバッファ番号、開始位置、取得本数に応じた値を配列へコピーします。

MQL4の感覚で「iMAを呼べば値が返る」と考えていると、MQL5では混乱しやすくなります。MQL5では、ハンドル作成と値取得を分けて考えることが重要です。

工程内容確認ポイント
ハンドル作成iMA、iATR、iRSI、iCustomなどでハンドルを作成します。INVALID_HANDLEでないか確認します。
計算状態確認BarsCalculatedで計算済み本数を確認します。必要本数が揃っているか確認します。
値取得CopyBufferで値を配列へ取得します。戻り値が要求本数と一致しているか確認します。
判定利用取得した値をシグナルやフィルターに使います。現在足か確定足かを明確にします。
終了処理IndicatorReleaseでハンドルを解放します。OnDeinitで後処理します。

インジケーターハンドルとは

インジケーターハンドルは、インジケーターの計算結果をEAから参照するための識別子です。MQL5では、標準インジケーターやカスタムインジケーターを使う時に、まずハンドルを作成します。

ハンドル作成に失敗すると、CopyBufferで値を取得することはできません。ハンドルがINVALID_HANDLEでないかをOnInitで確認し、失敗した場合は理由をログに出すことが重要です。

int ma_handle = INVALID_HANDLE;

int OnInit()
{
   ma_handle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);

   if(ma_handle == INVALID_HANDLE)
   {
      PrintFormat("HANDLE_FAIL name=iMA symbol=%s tf=%d last_error=%d",
                  _Symbol,
                  PERIOD_CURRENT,
                  GetLastError());
      return INIT_FAILED;
   }

   PrintFormat("HANDLE_OK name=iMA handle=%d symbol=%s tf=%d",
               ma_handle,
               _Symbol,
               PERIOD_CURRENT);

   return INIT_SUCCEEDED;
}

この例では、iMAで移動平均線のハンドルを作成し、INVALID_HANDLEかどうかを確認しています。ハンドル作成に失敗した状態でOnTickへ進むと、CopyBufferが失敗し続けるため、OnInitで止める設計が安全です。

iMAで移動平均線の値を取得する

iMAは、移動平均線のインジケーターハンドルを作成する関数です。EAでは、移動平均線の傾き、価格との位置関係、短期線と長期線のクロスなどを判定するために使うことがあります。

iMAで作成したハンドルから値を取得するにはCopyBufferを使います。移動平均線は通常バッファ0に値が入ります。現在足を使うか、確定足を使うかは、EAの仕様として明確にしてください。

bool GetMAValue(int handle, int shift, double &ma_value)
{
   if(handle == INVALID_HANDLE)
   {
      Print("MA_VALUE_FAIL reason=INVALID_HANDLE");
      return false;
   }

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

   ResetLastError();

   int copied = CopyBuffer(handle, 0, shift, 1, buffer);

   if(copied != 1)
   {
      PrintFormat("COPYBUFFER_FAIL name=iMA shift=%d copied=%d last_error=%d",
                  shift,
                  copied,
                  GetLastError());
      return false;
   }

   ma_value = buffer[0];

   PrintFormat("COPYBUFFER_OK name=iMA shift=%d value=%.5f",
               shift,
               ma_value);

   return true;
}

この例では、指定shiftの移動平均線値を1本取得しています。shift=0なら現在足、shift=1なら1本前の確定足を参照する考え方になります。シグナル判定の再現性を重視する場合は、確定足を使う設計が一般的です。

iATRでATR値を取得する

iATRは、ATRのインジケーターハンドルを作成する関数です。ATRは、ボラティリティや値幅の確認に使われることがあります。EAでは、SL/TP幅、トレーリング幅、ボラティリティフィルターなどに使う場合があります。

ATRもCopyBufferで値を取得します。ATRが0に見える場合、値が本当に0なのか、CopyBufferに失敗しているのか、計算本数が不足しているのかを分けて確認してください。

int atr_handle = INVALID_HANDLE;

int OnInit()
{
   atr_handle = iATR(_Symbol, PERIOD_CURRENT, 14);

   if(atr_handle == INVALID_HANDLE)
   {
      PrintFormat("HANDLE_FAIL name=iATR last_error=%d", GetLastError());
      return INIT_FAILED;
   }

   PrintFormat("HANDLE_OK name=iATR handle=%d", atr_handle);
   return INIT_SUCCEEDED;
}

bool GetATRValue(int shift, double &atr_value)
{
   double buffer[];
   ArraySetAsSeries(buffer, true);

   ResetLastError();

   int copied = CopyBuffer(atr_handle, 0, shift, 1, buffer);

   if(copied != 1)
   {
      PrintFormat("COPYBUFFER_FAIL name=iATR shift=%d copied=%d last_error=%d",
                  shift,
                  copied,
                  GetLastError());
      return false;
   }

   atr_value = buffer[0];

   PrintFormat("COPYBUFFER_OK name=iATR shift=%d value=%.5f",
               shift,
               atr_value);

   return true;
}

ATRをSL/TPやトレーリング幅に使う場合は、pointやdigits、銘柄仕様もあわせて確認する必要があります。ATR値をそのまま価格距離として使えるかどうかは、銘柄や仕様によって確認が必要です。

iRSIでRSI値を取得する

iRSIは、RSIのインジケーターハンドルを作成する関数です。EAでは、買われすぎ・売られすぎの確認、エントリーフィルター、逆張り条件、トレンド中の過熱確認などに使われることがあります。

RSIも、ハンドル作成後にCopyBufferで値を取得します。RSIは通常0〜100の範囲で表示されますが、値が取れていない場合に初期値や0.0を判定に使ってしまうと、誤判定につながります。

int rsi_handle = INVALID_HANDLE;

bool CreateRSIHandle()
{
   rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);

   if(rsi_handle == INVALID_HANDLE)
   {
      PrintFormat("HANDLE_FAIL name=iRSI last_error=%d", GetLastError());
      return false;
   }

   PrintFormat("HANDLE_OK name=iRSI handle=%d", rsi_handle);
   return true;
}

bool GetRSIValue(int shift, double &rsi_value)
{
   double buffer[];
   ArraySetAsSeries(buffer, true);

   ResetLastError();

   int copied = CopyBuffer(rsi_handle, 0, shift, 1, buffer);

   if(copied != 1)
   {
      PrintFormat("COPYBUFFER_FAIL name=iRSI shift=%d copied=%d last_error=%d",
                  shift,
                  copied,
                  GetLastError());
      return false;
   }

   rsi_value = buffer[0];

   PrintFormat("COPYBUFFER_OK name=iRSI shift=%d value=%.2f",
               shift,
               rsi_value);

   return true;
}

RSIを使う場合も、現在足か確定足かを明確にします。現在足のRSIは価格更新に応じて変化するため、シグナルが出たり消えたりすることがあります。確定足のRSIを使う場合は、shift=1を基準にすることが多くなります。

CopyBufferの基本構造

CopyBufferは、インジケーターハンドルから指定したバッファの値を取得する関数です。主に、ハンドル、バッファ番号、開始位置、取得本数、出力先配列を指定します。

CopyBufferを使う時は、戻り値を必ず確認します。戻り値は実際にコピーできた要素数です。要求本数を満たしていない場合は、値を使わずにログへ出して処理を止める方が安全です。

引数・要素意味確認ポイント
handleインジケーターハンドル。INVALID_HANDLEでないか確認します。
buffer number取得するバッファ番号。標準インジなら0が多いですが、カスタムでは仕様確認が必要です。
start position取得開始位置。shift=0かshift=1かを明確にします。
count取得本数。判定に必要な本数を指定します。
buffer array値を受け取る配列。ArraySetAsSeriesの設定を確認します。
return value実際に取得できた本数。要求本数と一致しているか確認します。
bool CopyIndicatorValues(int handle, int buffer_index, int start_shift, int count, double &values[])
{
   if(handle == INVALID_HANDLE)
   {
      Print("COPYBUFFER_FAIL reason=INVALID_HANDLE");
      return false;
   }

   ArraySetAsSeries(values, true);

   ResetLastError();

   int copied = CopyBuffer(handle, buffer_index, start_shift, count, values);

   if(copied != count)
   {
      PrintFormat("COPYBUFFER_FAIL buffer=%d start=%d count=%d copied=%d last_error=%d",
                  buffer_index,
                  start_shift,
                  count,
                  copied,
                  GetLastError());
      return false;
   }

   PrintFormat("COPYBUFFER_OK buffer=%d start=%d count=%d value0=%.5f",
               buffer_index,
               start_shift,
               count,
               values[0]);

   return true;
}

この例では、CopyBufferの戻り値が要求本数と一致するかを確認しています。取得本数が不足した状態で配列を参照すると、誤判定や配列範囲エラーにつながる可能性があります。

BarsCalculatedで計算済み本数を確認する

BarsCalculatedは、インジケーターの計算済み本数を確認するために使います。ハンドルが作成できても、必要な本数がまだ計算されていない場合、CopyBufferで十分な値を取得できないことがあります。

EA起動直後、バックテスト開始直後、MTF、マルチシンボル、iCustom利用時などは、計算済み本数が不足することがあります。BarsCalculatedで必要本数に達しているか確認してからCopyBufferへ進むと、失敗原因を確認やすくなります。

bool IsIndicatorReady(int handle, int needed_bars)
{
   if(handle == INVALID_HANDLE)
   {
      Print("INDICATOR_READY_FAIL reason=INVALID_HANDLE");
      return false;
   }

   ResetLastError();

   int calculated = BarsCalculated(handle);

   if(calculated < needed_bars)
   {
      PrintFormat("INDICATOR_NOT_READY calculated=%d needed=%d last_error=%d",
                  calculated,
                  needed_bars,
                  GetLastError());
      return false;
   }

   PrintFormat("INDICATOR_READY calculated=%d needed=%d",
               calculated,
               needed_bars);

   return true;
}

この例では、BarsCalculatedの値が必要本数を満たしているかを確認しています。計算済み本数が不足している場合は、シグナル判定へ進まず、ログを出して見送る方が安全です。

現在足と確定足を分けて扱う

インジケーター値をEAに取り込む時は、現在足と確定足を分けて扱う必要があります。現在足は価格更新に応じて値が変化します。確定足はすでに閉じた足なので、判定の再現性が高くなります。

CopyBufferでstart positionに0を指定すると、現在足の値を取得する構成になります。start positionに1を指定すると、1本前の確定足の値を取得する構成になります。どちらを使うかは、EAの仕様として明確にしてください。

指定意味注意点
shift=0現在足の値。価格更新により変化します。
shift=11本前の確定足の値。判定の再現性を高めやすいです。
現在足判定早い反応が可能。シグナルが出たり消えたりする場合があります。
確定足判定値が確定してから判定。反応は遅くなりますが、検証しやすくなります。

バックテストで再現性を重視する場合や、シグナルの出たり消えたりを避けたい場合は、確定足を使う設計が扱いやすいです。一方で、リアルタイム性を重視するEAでは現在足を使う場合もあります。その場合は、ログで値の変化を確認できるようにしてください。

ArraySetAsSeriesと配列方向の注意

CopyBufferで取得した値を配列で扱う時は、ArraySetAsSeriesの設定を確認します。ArraySetAsSeriesをtrueにすると、配列の0番目を最新側として扱いやすくなります。

配列方向を確認せずにbuffer[0]やbuffer[1]を使うと、現在足と確定足を取り違える可能性があります。特にCopyBuffer、CopyRates、CopyCloseを混在させるEAでは、配列方向を統一しておくと確認しやすくなります。

設定意味確認ポイント
ArraySetAsSeries(buffer, true)0番目を最新側として扱います。buffer[0]が取得開始位置の値として扱いやすくなります。
ArraySetAsSeries(buffer, false)通常配列方向で扱います。インデックスの意味をログで確認します。
buffer[0]配列方向とCopyBuffer指定により意味が変わります。時刻やshiftとセットで確認します。
buffer[1]2本以上取得した時に使います。クロス判定や前回値比較で注意します。

EMPTY_VALUEと取得失敗を混同しない

インジケーターによっては、値が存在しない場所にEMPTY_VALUEが入ることがあります。特に矢印系インジケーター、サイン系インジケーター、条件成立時だけ値を出すカスタムインジケーターでは、EMPTY_VALUEの確認が重要です。

CopyBufferの失敗とEMPTY_VALUEは別です。CopyBufferが成功していても、取得した値がEMPTY_VALUEの場合、そのバーではシグナルが出ていない可能性があります。一方で、CopyBuffer自体が失敗している場合は、インジケーター値を判定に使うべきではありません。

bool GetSignalValue(int handle, int buffer_index, int shift, double &signal_value)
{
   double buffer[];
   ArraySetAsSeries(buffer, true);

   ResetLastError();

   int copied = CopyBuffer(handle, buffer_index, shift, 1, buffer);

   if(copied != 1)
   {
      PrintFormat("SIGNAL_COPY_FAIL buffer=%d shift=%d copied=%d last_error=%d",
                  buffer_index,
                  shift,
                  copied,
                  GetLastError());
      return false;
   }

   if(buffer[0] == EMPTY_VALUE)
   {
      PrintFormat("SIGNAL_EMPTY buffer=%d shift=%d", buffer_index, shift);
      return false;
   }

   signal_value = buffer[0];

   PrintFormat("SIGNAL_VALUE buffer=%d shift=%d value=%.5f",
               buffer_index,
               shift,
               signal_value);

   return true;
}

この例では、CopyBuffer失敗とEMPTY_VALUEを分けてログに出しています。サイン系インジケーターをEAへ取り込む場合は、この確認が非常に重要です。

iCustomでカスタムインジケーター値を取得する

iCustomは、カスタムインジケーターのハンドルを作成するために使います。EAから自作インジケーターや外部インジケーターの値を取得したい場合、iCustomでハンドルを作成し、CopyBufferでバッファ値を取得します。

iCustomを使う時は、インジケーターファイル名、input引数の順番、バッファ番号、サブウィンドウ、EMPTY_VALUE、再描画の有無を確認します。カスタムインジケーター側の仕様が分からないままEAへ取り込むと、値の意味を誤解する可能性があります。

int custom_handle = INVALID_HANDLE;

bool CreateCustomIndicatorHandle()
{
   custom_handle = iCustom(_Symbol, PERIOD_CURRENT, "MyCustomIndicator", 14, 2.0);

   if(custom_handle == INVALID_HANDLE)
   {
      PrintFormat("HANDLE_FAIL name=MyCustomIndicator last_error=%d",
                  GetLastError());
      return false;
   }

   PrintFormat("HANDLE_OK name=MyCustomIndicator handle=%d",
               custom_handle);

   return true;
}

この例では、MyCustomIndicatorというカスタムインジケーターをiCustomで呼び出しています。実際には、ファイル名、パス、input引数、バッファ番号が正しいかを確認してください。

カスタムインジケーター連携で確認すること

カスタムインジケーターをEAに取り込む場合は、標準インジケーターよりも確認項目が増えます。特に、どのバッファに何の値が入っているか、サインが出ない時にEMPTY_VALUEになるのか0になるのか、現在足で値が変わるのか、確定足で固定されるのかを確認します。

インジケーター側が描画用に作られている場合、EAから読み取る用途に適していないこともあります。バッファが公開されているか、CopyBufferで取得できるか、描画オブジェクトだけで値を出していないかを確認してください。

確認項目内容注意点
ファイル名iCustomで指定するインジケーター名。拡張子やフォルダ階層の扱いに注意します。
input引数カスタムインジケーターの設定値。順番や型が違うと期待値になりません。
バッファ番号CopyBufferで指定する番号。買いサイン・売りサインなどの対応を確認します。
EMPTY_VALUE値なしの扱い。サインなしを注文条件と混同しないようにします。
現在足更新現在足で値が変わるか。リペイントや再計算の有無を確認します。
確定足確定足で値が固定されるか。バックテスト再現性に影響します。
ログ値、shift、buffer、copied。EA側で取得状態を確認します。

IndicatorReleaseでハンドルを解放する

EA終了時には、作成したインジケーターハンドルをIndicatorReleaseで解放します。OnDeinitで後処理を行うことで、リソース管理が明確になります。

短いサンプルでは省略されることがありますが、複数インジケーター、MTF、マルチシンボル、iCustomを多用するEAでは、ハンドル管理を整理しておくと保守しやすくなります。

void OnDeinit(const int reason)
{
   if(ma_handle != INVALID_HANDLE)
   {
      IndicatorRelease(ma_handle);
      PrintFormat("HANDLE_RELEASE name=iMA handle=%d reason=%d",
                  ma_handle,
                  reason);
      ma_handle = INVALID_HANDLE;
   }

   if(atr_handle != INVALID_HANDLE)
   {
      IndicatorRelease(atr_handle);
      PrintFormat("HANDLE_RELEASE name=iATR handle=%d reason=%d",
                  atr_handle,
                  reason);
      atr_handle = INVALID_HANDLE;
   }

   if(rsi_handle != INVALID_HANDLE)
   {
      IndicatorRelease(rsi_handle);
      PrintFormat("HANDLE_RELEASE name=iRSI handle=%d reason=%d",
                  rsi_handle,
                  reason);
      rsi_handle = INVALID_HANDLE;
   }
}

この例では、各ハンドルが有効な場合だけIndicatorReleaseを呼び出し、その後INVALID_HANDLEへ戻しています。ログにreasonを出しておくと、EA終了理由の確認にも役立ちます。

MTFでインジケーター値を取得する時の注意

MTFでは、現在チャートとは別の時間足のインジケーター値を取得します。たとえば、M5チャート上でEAを動かしながら、H1の移動平均線やRSIをフィルターに使うような構成です。

MTFで注意すべきなのは、現在チャートのバー更新と上位足のバー更新が一致しないことです。上位足のshift=0は形成中であり、値が変わります。上位足をフィルターに使う場合は、shift=1の確定足を使うか、現在足を使うかを仕様として明確にします。

int h1_ma_handle = INVALID_HANDLE;

bool CreateH1MAHandle()
{
   h1_ma_handle = iMA(_Symbol, PERIOD_H1, 20, 0, MODE_SMA, PRICE_CLOSE);

   if(h1_ma_handle == INVALID_HANDLE)
   {
      PrintFormat("HANDLE_FAIL name=H1_MA last_error=%d", GetLastError());
      return false;
   }

   PrintFormat("HANDLE_OK name=H1_MA handle=%d", h1_ma_handle);
   return true;
}

上位足の値が取得できない場合は、時間足データ不足、バックテスト開始直後、BarsCalculated不足を確認します。MTFでは、CopyBuffer失敗をシグナル不成立と混同しないようにしてください。

マルチシンボルでインジケーター値を取得する時の注意

マルチシンボルEAでは、現在チャートとは別の銘柄のインジケーター値を取得することがあります。この場合、対象銘柄がMarket Watchに表示されているか、SymbolSelectで選択できているか、ヒストリーデータがあるかを確認する必要があります。

別銘柄のiMAやiRSIハンドルを作る場合は、_Symbolに固定せず、対象symbolを引数として渡す構成にします。銘柄ごとにハンドルを管理する必要があるため、単一ハンドルのEAよりも管理が複雑になります。

bool PrepareSymbol(string symbol)
{
   ResetLastError();

   if(!SymbolSelect(symbol, true))
   {
      PrintFormat("SYMBOL_SELECT_FAIL symbol=%s last_error=%d",
                  symbol,
                  GetLastError());
      return false;
   }

   PrintFormat("SYMBOL_SELECT_OK symbol=%s", symbol);
   return true;
}

SymbolSelectに失敗した状態でインジケーターハンドルを作成すると、ハンドル作成やCopyBufferに失敗する可能性があります。マルチシンボルEAでは、対象銘柄ごとの準備ログを残してください。

CopyBuffer失敗時に確認すること

CopyBufferが失敗する場合は、ハンドル、バッファ番号、取得開始位置、取得本数、計算済み本数、配列方向、対象銘柄、対象時間足、GetLastErrorを確認します。値が取れない理由を1つに決めつけないことが重要です。

症状確認する場所主な原因候補
copiedが要求本数より少ないCopyBuffer戻り値、BarsCalculated。計算本数不足、ヒストリー不足、起動直後。
INVALID_HANDLEになるiMA、iATR、iRSI、iCustomの戻り値。引数不正、ファイル名違い、銘柄・時間足データ不足。
値が0.0に見えるCopyBuffer成功可否、値の意味。取得失敗、値なし、初期値、実際に0。
EMPTY_VALUEになる取得値、カスタムインジ仕様。サインなし、描画なし、条件不成立。
MTFだけ失敗する上位足ハンドル、BarsCalculated。上位足データ不足、バックテスト開始直後。
別銘柄だけ失敗するSymbolSelect、銘柄名、Market Watch。銘柄未選択、銘柄名違い、ヒストリー不足。
バッファ番号が合わないインジケーター仕様。買いサイン・売りサインのバッファ番号違い。

バックテストでCopyBufferを確認する

バックテストでは、EAの損益結果だけでなく、インジケーター値が正しく取得できているかを確認します。特に、CopyBufferの取得本数、BarsCalculated、shift、現在足と確定足、MTF、iCustomのバッファ番号をログで確認してください。

バックテスト開始直後は、インジケーター計算に必要な本数が揃っていない場合があります。その状態でCopyBuffer結果を使ってしまうと、シグナル不成立や誤判定につながります。

  • EA名とバージョンを記録する
  • 使用したsetファイルを保存する
  • 銘柄、時間足、期間を記録する
  • インジケーターハンドル作成ログを確認する
  • BarsCalculatedの値を確認する
  • CopyBufferの戻り値を確認する
  • 現在足と確定足を混同していないか確認する
  • iCustom利用時はバッファ番号を確認する
  • EMPTY_VALUEをシグナル不成立として扱うか確認する
  • バックテスト結果を将来成績保証として扱わない

EAに取り込んだインジケーター値をどこで使うかを分ける

EAにインジケーター値を取り込む時は、値を取得できたかどうかだけでなく、その値をEA内部のどこで使うかを先に分ける必要があります。

同じMA値やRSI値でも、エントリー方向を決めるために使うのか、エントリーを見送るフィルターとして使うのか、決済条件として使うのか、通知やパネル表示だけに使うのかで、必要な確認内容が変わります。

たとえば、RSIが30未満になったことを通知するだけなら、値取得と通知重複防止が中心です。一方で、自動発注EAとして使う場合は、スプレッド、既存ポジション、Magic Number、証拠金、ロット、OrderCheck、取引時間、外部停止条件まで確認する必要があります。

責務インジケーター値の使い方確認ポイント
signalBUY / SELL / WAITの候補を作る値取得、shift、EMPTY_VALUE、判定方向を確認する
filterエントリー許可・見送り条件に使うトレンド方向、過熱感、ボラティリティ、時間帯と分ける
riskSL幅、トレーリング幅、ロット補助に使うATR値、point、pips、銘柄仕様、証拠金を確認する
exit決済条件や撤退条件に使うエントリー条件と決済条件を混同しない
notification通知だけに使う重複通知、通知対象足、通知タイミングを確認する
UI / panel画面表示や状態確認に使う取得失敗時の表示、更新頻度、表示値の説明を確認する

EA設計では、インジケーター値を取得した時点で発注へ直結させないことが重要です。値取得、値の妥当性確認、signal判定、entry gate、risk確認、executionを分けることで、後からログを見た時にどの段階で止まったのかを確認できます。

この分離がないと、「CopyBufferは成功しているのにEAが入らない」という状態になった時、値が悪いのか、判定条件が悪いのか、発注前条件で止まったのか、注文処理で失敗したのかを確認できません。

標準インジケーター別のEA取り込み方

EAへ取り込む標準インジケーターは、それぞれ値の性質が異なります。すべてを同じ「数値」として扱うのではなく、値の単位、意味、使う責務を分けて確認してください。

インジケーター値の性質EAでの主な使い方注意点
iMA価格に近いライン値方向確認、クロス、価格との位置関係価格とMAのshiftを合わせる
iRSI0〜100のオシレーター値過熱感、押し目、逆張り候補の補助価格やpipsとは単位が違う
iATR価格変動幅ボラティリティ確認、SL幅、トレーリング補助point、pips、価格単位への換算を確認する
iBands上限・中央・下限の価格値価格位置、バンド内外、ボラティリティ確認buffer番号を必ず確認する
iMACDMACD線やシグナル線など複数buffer方向、勢い、クロス補助どのbufferを読むか確認する
iStochastic%K / %Dなどのオシレーター値過熱感、クロス、レンジ補助現在足の変動と確定足を分ける

たとえば、ATRはエントリー方向を直接決めるインジケーターではありません。ATRが大きいからBUY、ATRが小さいからSELLという使い方ではなく、相場の値幅やボラティリティ環境を確認するために使う方が自然です。

一方で、MAは価格と同じような水準の値を返すため、価格との比較や短期線・長期線の比較に使いやすいです。ただし、現在足の終値と確定足のMAを比較するなど、参照足がズレると判定が不自然になります。

RSIやStochasticは、価格そのものではなく指標値です。0〜100の範囲で評価する値を、価格差やpipsと同じ単位で扱わないようにしてください。

CopyBufferで取得できた値を使える値として扱う前の確認

CopyBufferが成功したように見えても、その値をEA判定に使ってよいとは限りません。取得本数が足りているか、値がEMPTY_VALUEではないか、NaNではないか、意図したshiftの値か、buffer番号が正しいかを確認する必要があります。

状態意味EA側の扱い
copiedが要求本数と一致CopyBufferの取得処理は成功次に値の妥当性を確認する
copiedが0取得できた値がないBarsCalculated、履歴、buffer番号を確認する
copiedが-1CopyBuffer失敗GetLastErrorとhandle状態を確認する
EMPTY_VALUEそのバーに値やサインがない可能性サインなしとして扱うか仕様で決める
0.0有効値の場合も初期値の場合もあるインジケーター仕様とログを照合する
異常に大きい値EMPTY_VALUE相当や未初期化の可能性MathIsValidNumberなどで確認する
想定と違う方向の値buffer番号違いの可能性SetIndexBufferやData Windowを確認する

値取得の成功、値の有効性、signal成立は別の段階です。CopyBufferが成功しても、EMPTY_VALUEならサインなしの可能性があります。値が有効でも、EAのsignal条件を満たしていないならWAITです。

この段階を分けずに実装すると、正常なWAIT状態をエラー扱いしたり、取得失敗をシグナル不成立として見逃したりします。ログ上でも、COPYBUFFER_FAIL、VALUE_EMPTY、SIGNAL_WAIT、ENTRY_BLOCKを分けると確認しやすくなります。

リペイント確認が必要な理由

リペイントとは、過去に出ていたサインや値が後から変わることです。

リペイントするインジケーターをEA化する場合、バックテスト上ではきれいに見えても、リアルタイムでは同じように動かない可能性があります。

確認項目理由
過去の矢印が変わるかサイン履歴が後から変わる可能性を確認するため
shift=0だけ変わるのか未確定足だけの変動か確認するため
shift=1以降も変わるのか確定足後も変わるならEA化リスクが高いため
バックテストとリアルで差があるか検証再現性を確認するため
buffer値と表示Objectが一致するか見た目とEA取得値の差を確認するため

リペイント自体が必ず悪いわけではありません。ただし、EA化する場合は、どのタイミングの値を使うのか、過去サインの変化をどう扱うのかを明確にする必要があります。

サイン表示とbuffer値は同じとは限らない

チャート上に矢印が表示されていても、その矢印がEAから直接読めるbuffer値とは限りません。

インジケーターによっては、矢印Objectをチャート上に描画しているだけで、bufferには値を出していない場合があります。また、BUYサインとSELLサインが別bufferで管理されている場合もあります。

確認対象注意点
bufferサインCopyBufferで取得しやすい
ObjectサインObject名や座標から判断する必要があり、EA化では慎重に扱う
コメント表示画面表示であり、判定の真実にしない方が安全
色変化buffer構造やDRAW設定により読み方が変わる
アラートだけのサインEA側で同じ条件を再現できるか確認が必要

EA化前には、サインがbufferで取れるのか、Objectでしか出ていないのか、アラートだけなのかを確認します。

iCustomの入力・バッファ・サインを照合する

以下のコード例は、個別の処理と確認項目を読むためのものです。複数の例をそのまま一つのEAへ連結する前提ではありません。初期化、値の取得、状態更新、終了処理をそれぞれの例で区別して確認してください。

iCustomとは何か

iCustomは、MQL5でカスタムインジケーターをEAや別のプログラムから呼び出すための関数です。

iMAやiRSIのような標準インジケーターは専用関数でhandleを作成できますが、独自インジケーターや配布されたカスタムインジケーターをEAから使う場合は、iCustomでhandleを作成し、CopyBufferで対象bufferの値を取得します。

処理役割確認ポイント
iCustomカスタムインジケーターのhandleを作成するインジ名、パス、input引数、timeframeを確認する
CopyBuffer作成したhandleからbuffer値を取得するbuffer番号、shift、取得本数、戻り値を確認する
SetIndexBufferインジ側でbufferを割り当てるEA側で読むbuffer番号と対応させる
EMPTY_VALUE値なし、サインなし、未描画を表す場合があるエラーとシグナルなしを分ける
確定足リペイントや未確定値を避けるために使うshift 0とshift 1を分けて確認する

iCustomでEA化する時は、インジケーター側の設計とEA側の取得処理をセットで確認します。EA側のコードだけを見ても、buffer番号やinput順序が正しいか判断できない場合があります。

iCustomでEA化する時の基本構成

基本的な流れは、OnInitでiCustomのhandleを作成し、OnTickでCopyBufferを使って値を取得し、OnDeinitでIndicatorReleaseを行う形です。

int custom_handle = INVALID_HANDLE;

int OnInit()
{
   ResetLastError();

   custom_handle = iCustom(_Symbol,
                           PERIOD_CURRENT,
                           "MyCustomIndicator",
                           20,
                           2.0,
                           true);

   int err = GetLastError();

   Print("ICUSTOM_HANDLE",
         " symbol=", _Symbol,
         " timeframe=", PERIOD_CURRENT,
         " handle=", custom_handle,
         " last_error=", err);

   if(custom_handle == INVALID_HANDLE)
      return INIT_FAILED;

   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
   if(custom_handle != INVALID_HANDLE)
   {
      IndicatorRelease(custom_handle);
      custom_handle = INVALID_HANDLE;
   }
}

この例では、iCustomでカスタムインジケーターのhandleを作成しています。実際には、インジケーター名、input引数、引数型、並び順を対象インジケーターに合わせる必要があります。

EA化でよくある失敗は、インジケーター側のinputが増減しているのに、EA側のiCustom引数が古いままになっているケースです。この場合、handleが作れない、値が取れない、想定と違う設定で計算されるといった問題が起きます。

iCustomで最初に確認すること

iCustomで値が取れない時は、CopyBufferより前に、iCustomの指定が正しいかを確認します。

確認項目内容よくあるミス
インジケーター名呼び出すカスタムインジケーター名ファイル名違い、拡張子指定、全角半角、スペース違い
配置パスMQL5/Indicators配下の場所サブフォルダ指定漏れ
input引数インジ側inputの順序と型途中のinput省略、順序ズレ、型違い
symbol対象銘柄_Symbolと別銘柄指定の混同、suffix違い
timeframe対象時間足PERIOD_CURRENTと固定時間足の混同
handleiCustomの戻り値INVALID_HANDLEを確認していない

iCustomのhandle作成に失敗している場合、CopyBuffer側を修正しても値は取れません。まず、handle作成ログを出し、INVALID_HANDLEになっていないか確認してください。

インジケーター名と配置パスの注意点

iCustomで指定するインジケーター名は、MQL5/Indicators配下の配置と一致している必要があります。

配置例iCustom指定例注意点
MQL5/Indicators/MySignal.ex5"MySignal"通常は拡張子なしで指定する
MQL5/Indicators/Custom/MySignal.ex5"Custom\\MySignal"サブフォルダを含める
ファイル名にスペースあり"My Signal"スペース違いに注意する
mq5はあるが未コンパイルhandle作成失敗の可能性ex5が生成されているか確認する

ファイル名やフォルダ名を推測で書くと、EA側ではhandleが作れません。特に配布されたインジケーターをEA化する場合は、実際のファイル名と配置場所を確認してください。

input引数の順序と型を確認する

iCustomでは、カスタムインジケーター側のinput順序に合わせて、EA側から引数を渡します。

たとえば、インジケーター側に以下のinputがあるとします。

input int    InpPeriod = 20;
input double InpThreshold = 2.0;
input bool   InpUseFilter = true;

この場合、EA側のiCustomでも同じ順序で値を渡します。

custom_handle = iCustom(_Symbol,
                        PERIOD_CURRENT,
                        "MyCustomIndicator",
                        20,
                        2.0,
                        true);

途中のinputだけを省略したり、intとdouble、boolとint、enumとintを混同したりすると、handle生成失敗や想定外の値取得につながる場合があります。

buffer番号と表示ラインを対応させる

iCustomでEA化する時に重要なのが、取得したい表示ラインとbuffer番号の対応です。

インジケーター側では、SetIndexBufferで各bufferを割り当てます。EA側では、CopyBufferの第2引数にそのbuffer番号を指定します。

double BuyBuffer[];
double SellBuffer[];

double FilterBuffer[];

int OnInit()
{
   SetIndexBuffer(0, BuyBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, SellBuffer, INDICATOR_DATA);
   SetIndexBuffer(2, FilterBuffer, INDICATOR_CALCULATIONS);

   return INIT_SUCCEEDED;
}

この例では、BuyBufferはbuffer 0、SellBufferはbuffer 1です。FilterBufferは計算用で、EA側のシグナル取得対象ではない可能性があります。

buffer番号例EA側の扱い
0BuyBufferBUYサイン取得用
1SellBufferSELLサイン取得用
2FilterBuffer内部計算用なら直接使わない

チャート上で見えている順番とbuffer番号が必ず一致するとは限りません。ソースコードがある場合は、SetIndexBufferの順序を確認してください。ソースコードがない場合は、Data Windowや開発元の仕様説明を確認します。

CopyBufferでiCustomの値を取得する例

iCustomで作成したhandleから値を取得する時も、標準インジケーターと同じくCopyBufferを使います。

void CheckCustomSignal()
{
   if(custom_handle == INVALID_HANDLE)
   {
      Print("SIGNAL_SKIP reason=INVALID_HANDLE");
      return;
   }

   double buy_values[];
   double sell_values[];

   ArraySetAsSeries(buy_values, true);
   ArraySetAsSeries(sell_values, true);

   ResetLastError();

   int copied_buy = CopyBuffer(custom_handle, 0, 0, 3, buy_values);
   int err_buy = GetLastError();

   ResetLastError();

   int copied_sell = CopyBuffer(custom_handle, 1, 0, 3, sell_values);
   int err_sell = GetLastError();

   Print("ICUSTOM_COPY",
         " copied_buy=", copied_buy,
         " err_buy=", err_buy,
         " copied_sell=", copied_sell,
         " err_sell=", err_sell);
}

CopyBufferの戻り値は、取得できたデータ数です。要求本数分を取得できたか、0や-1になっていないか、GetLastErrorに何が出ているかを確認してください。

現在足と確定足を分けて確認する

EA化では、現在足の値を使うのか、確定足の値を使うのかを決める必要があります。

チャート上のインジケーター表示は現在足で変化していることがあります。一方、EAでは安定した判定のために1本前の確定足を使う設計にすることが多くあります。

参照位置用途注意点
shift 0現在足の値未確定で変動する。リペイント確認が必要
shift 11本前の確定足バー確定型EAで使いやすい
shift 2さらに1本前クロスや変化確認に使う

「チャートではサインが出ているのにEAが入らない」という場合、チャートで見ている値がshift 0、EAが使っている値がshift 1というズレが原因になることがあります。

確定足基準で取得するコード例

bool ReadClosedBarSignal(const int handle,
                         const int buffer_index,
                         double &signal_value)
{
   signal_value = EMPTY_VALUE;

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

   ResetLastError();

   int copied = CopyBuffer(handle, buffer_index, 0, 3, values);
   int err = GetLastError();

   Print("READ_CLOSED_SIGNAL",
         " buffer=", buffer_index,
         " copied=", copied,
         " last_error=", err);

   if(copied < 2)
      return false;

   signal_value = values[1];
   return true;
}

この例では、CopyBufferで0番から3本分を取得し、EA判定にはvalues[1]を使っています。values[0]は現在足、values[1]は1本前の確定足として扱う前提です。

EMPTY_VALUEとサインなしを区別する

カスタムインジケーターのサインバッファでは、サインがないバーにEMPTY_VALUEが入ることがあります。

この場合、CopyBufferは成功していても、そのバーに有効なサインがないだけです。これをエラー扱いすると、EAのログが不要に増えたり、正常なサインなし状態を異常として判断したりする原因になります。

状態意味EA側の扱い
CopyBuffer失敗値を取得できていないhandle、BarsCalculated、GetLastErrorを確認
CopyBuffer成功 + EMPTY_VALUEそのバーにサインがないWAITまたはNO_SIGNALとして扱う
CopyBuffer成功 + 有効値サインまたはライン値があるsignal判定へ進める
0.0有効値か未初期化かはインジ仕様次第インジ側仕様を確認する

EA化では、値取得の成功とシグナル成立を分けます。CopyBufferが成功しても、EMPTY_VALUEなら「値取得は成功、シグナルはなし」と判断する方が自然です。

リペイントするインジケーターをEA化する時の注意点

カスタムインジケーターには、未確定足で値が変わるものがあります。これをリペイントと呼ぶことがあります。

リペイントするインジケーターをEA化する場合、チャート上で一時的に見えていたサインをEAがどう扱うかを明確にする必要があります。

確認項目内容EA化での扱い
現在足のサイン足確定前に出たり消えたりするリアルタイムEA以外では慎重に扱う
確定足のサイン足確定後に残った値バー確定型EAで使いやすい
過去サインの再描画過去バーの値が後から変わるバックテストとの整合に注意する
MTFインジ上位足確定まで値が変わる上位足の確定タイミングを確認する

リペイントするインジケーターを使うこと自体が常に悪いわけではありません。ただし、EA化する場合は、未確定足の変動値を使うのか、確定足だけを使うのかを仕様として明示してください。

リペイント確認用のログ例

void PrintRepaintCheck(const double shift0_value,
                       const double shift1_value)
{
   Print("REPAINT_CHECK",
         " shift0_current=", DoubleToString(shift0_value, _Digits),
         " shift1_closed=", DoubleToString(shift1_value, _Digits));
}

現在足と確定足を同時にログへ出すと、インジケーターが未確定足でどの程度変化しているか確認できます。

EA側では値取得とsignal判定を分ける

iCustomで取得した値をそのまま発注処理へつなげるのは避けます。

実務では、値取得、値の妥当性確認、signal判定、entry gate、executionを分けると、原因を追いやすくなります。

責務内容ログ例
iCustom handleインジケーターを呼び出すICUSTOM_HANDLE
CopyBufferbuffer値を取得するICUSTOM_COPY
value validationEMPTY_VALUEやNaNを確認するVALUE_VALIDATE
signalBUY / SELL / WAITへ変換するSIGNAL_EVAL
entry gateスプレッド、時間、最大ポジション数を見るENTRY_GATE
executionOrderSendやCTradeを実行するORDER_SEND

この分離により、「iCustomで呼べていない」のか、「CopyBufferで値が取れていない」のか、「値は取れているがシグナル条件を満たしていない」のか、「entry gateで止まっている」のかを確認できます。

signal判定へ変換するコード例

enum ESignalSide
{
   SIGNAL_WAIT = 0,
   SIGNAL_BUY  = 1,
   SIGNAL_SELL = 2
};

ESignalSide ResolveSignal(const double buy_value,
                          const double sell_value)
{
   bool has_buy = (buy_value != EMPTY_VALUE && MathIsValidNumber(buy_value));
   bool has_sell = (sell_value != EMPTY_VALUE && MathIsValidNumber(sell_value));

   if(has_buy && !has_sell)
      return SIGNAL_BUY;

   if(has_sell && !has_buy)
      return SIGNAL_SELL;

   return SIGNAL_WAIT;
}

この例では、BUY用bufferとSELL用bufferの値を見て、EA内部のsignalへ変換しています。実際のEAでは、ここからさらにスプレッド、時間帯、既存ポジション、Magic Number、リスク条件などのentry gateを通してから発注処理へ進めます。

バックテストでiCustomが動かない時の確認

Strategy TesterでiCustomを使う場合、カスタムインジケーターがテスター環境で読み込めているか確認します。

実チャートでは動いていても、テスターで対象インジケーターが見つからない、履歴データが不足している、初期化直後にBarsCalculatedが不足している、といった問題が起きることがあります。

確認項目見る内容対応
インジファイルIndicators配下にあるか配置場所とファイル名を確認する
handleINVALID_HANDLEではないかOnInitログを見る
BarsCalculated計算済みバー数が足りているかウォームアップ期間を設ける
ヒストリカルデータ対象時間足のバーがあるかテスト期間と履歴を確認する
複数時間足上位足データがあるかiBarsやCopyTimeを確認する

テスター起動直後の取得失敗は、必ずしも致命的なエラーではありません。必要本数がそろうまで判定を見送る設計にすると、初期バーの誤判定を避けやすくなります。

ログに残すべき項目

iCustomのEA化では、値が取れない原因をログで追えるようにしておくことが重要です。

ログ名出す内容目的
ICUSTOM_HANDLEsymbol、timeframe、indicator、handle、last_errorhandle生成の成否を確認する
ICUSTOM_ARGSinput引数の値EA側の指定値を確認する
BARS_CALCULATEDcalculated、required計算済みバー数を確認する
ICUSTOM_COPYbuffer、shift、copied、last_errorCopyBufferの取得結果を確認する
VALUE_VALIDATEEMPTY_VALUE、NaN、有効値値の有無を確認する
SIGNAL_EVALBUY / SELL / WAIT、basis、shiftEA内部判定を確認する
REPAINT_CHECKshift 0とshift 1の比較未確定足の変動を確認する

ログを出す時は、成功時に毎tick大量出力しないよう注意してください。失敗時、初回のみ、状態変化時、検証モードON時など、目的に応じて出力条件を分けると扱いやすくなります。

現在足を使うEAと確定足を使うEAの違い

インジケーター値をEAへ取り込む時、現在足を使う設計と、確定足を使う設計では挙動が大きく変わります。

現在足は価格更新に応じて変化します。シグナルが早く出る一方で、同じバーの中で条件が成立したり不成立になったりすることがあります。確定足は反応が遅くなりますが、検証結果と実運用の照合がしやすくなります。

方式特徴向いている用途注意点
現在足方式価格更新中の値を使うリアルタイム通知、早い反応を狙う判定サインが出たり消えたりする可能性がある
確定足方式1本前の確定した値を使うバー確定型EA、再現性重視の検証反応は現在足方式より遅くなる
現在足通知+確定足発注通知と発注で基準を分ける半裁量、確認用EAユーザーに基準差を明示する必要がある
複数本確認方式直近数本の値を比較するクロス、傾き、連続条件取得本数不足に注意する

「チャートではサインが出ているのにEAが入らない」という相談では、現在足と確定足の違いが原因になっていることがあります。チャート上で見ているサインが現在足の変動中サインで、EAが確定足を見ている場合、見え方が違って当然です。

そのため、EA仕様書やinput説明では、判定basisを明記してください。たとえば、SignalShift=1なら確定足基準、SignalShift=0なら現在足基準というように、利用者が分かる形にしておくと問い合わせ対応もしやすくなります。

iCustomでサイン系インジケーターをEA化する時の確認順序

サイン系カスタムインジケーターをEA化する場合、標準インジケーターより確認項目が多くなります。

特に、買いサインと売りサインがどのbufferに入っているのか、サインがない時にEMPTY_VALUEを返すのか0を返すのか、現在足でサインが消えるのか、確定足で固定されるのかを確認する必要があります。

順番確認項目確認内容
1インジケーター名iCustomで指定するファイル名と配置場所を確認する
2input引数インジ側inputの順序、型、初期値とEA側指定を照合する
3handle作成INVALID_HANDLEでないか、GetLastErrorを確認する
4buffer番号BUYサイン、SELLサイン、フィルター値のbufferを確認する
5shift現在足で見るか、確定足で見るかを決める
6EMPTY_VALUEサインなしをどの値で表しているか確認する
7リペイント未確定足や過去足の値が変わるか確認する
8EA側signal化値取得をBUY / SELL / WAITへ変換する

カスタムインジケーターのソースコードがある場合は、SetIndexBuffer、OnCalculate、EMPTY_VALUEの入れ方を確認できます。ソースコードがない場合は、Data Window、チャート表示、CopyBufferログを使って推測することになります。

ex5のみのインジケーターをEA化する場合、内部bufferの意味が完全には分からないことがあります。この場合は、すぐに自動発注へつなげず、まず通知やログ出力でサイン検出の再現性を確認する方が安全です。

値取得できているのにEAが動かない時の確認

CopyBufferで値が取れているにもかかわらず、EAがエントリーしない場合があります。この場合、インジケーター値の取得は成功しているため、次にsignal判定、filter、entry gate、risk、executionを確認します。

段階確認内容よくある停止理由
valueCopyBufferで値が取得できているか取得失敗、EMPTY_VALUE、buffer番号違い
signal取得値からBUY / SELL / WAITへ変換できているか条件未達、現在足と確定足の違い
filter追加条件を通過しているかMA方向、RSI範囲、ATR環境、時間帯
entry gate発注前制限を通過しているかスプレッド過大、既存ポジションあり、取引停止
riskロットや証拠金条件が通っているか最小ロット未満、証拠金不足、StopLevel違反
execution注文結果が成功しているかOrderSend失敗、retcode異常、約定拒否

EAが動かない時に「インジケーター値が取れていない」と決めつけるのは危険です。実際には、インジケーター値は正常に取れているが、entry gateやrisk条件で止まっている場合があります。

そのため、ログでは、VALUE_OK、SIGNAL_EVAL、FILTER_BLOCK、ENTRY_BLOCK、RISK_BLOCK、ORDER_RESULT のように段階を分けると原因を追いやすくなります。

ATRをSL幅やトレーリングに使う時の注意点

ATRは、EAでSL幅、トレーリング幅、ボラティリティ判定に使われることがあります。ただし、ATR値をそのままpipsとして扱うと、銘柄や桁数によって誤った距離になる可能性があります。

確認項目内容注意点
Digits銘柄の小数桁5桁、3桁、2桁、XAUUSDなどで感覚が違う
Point最小価格単位pips換算と混同しない
ATR値価格単位の変動幅そのままSL距離に使えるか確認する
StopLevel注文時の最小距離ATR由来のSL幅が近すぎる場合がある
Spread現在スプレッド低ATR環境ではスプレッド比率が大きくなる
銘柄仕様最小ロット、tick value、contract sizerisk計算と組み合わせて確認する

ATRを使う場合は、単に「ATRが大きいから広いSL」「ATRが小さいから狭いSL」とするだけでは不十分です。銘柄仕様、StopLevel、スプレッド、証拠金、ロット計算と合わせて確認する必要があります。

また、ATRは相場環境を示す値であり、売買方向そのものを決める値ではありません。EA内部では、signalではなく、risk補助、volatility filter、exit補助として扱う方が自然な場面が多くあります。

通知・半裁量・完全自動で確認項目を変える

同じインジケーター値取得でも、通知ツール、半裁量EA、完全自動EAでは、必要な確認項目が異なります。

通知ツールでは、値取得と重複通知防止が中心です。半裁量EAでは、サイン表示や手動実行ボタン、誤操作防止が重要です。完全自動EAでは、発注前のentry gate、risk、execution、注文結果確認まで必要になります。

用途インジケーター値の扱い追加確認
通知ツールサイン検出や条件成立を通知する重複通知、通知先、通知文、ログ
情報パネル現在値や状態を表示する更新頻度、取得失敗時の表示、色分け
半裁量EAサインを確認して手動操作するボタン、確認表示、誤操作防止
完全自動EAsignalから注文処理へ進めるentry gate、risk、OrderCheck、retcode確認
検証EA条件成立や値変化を記録するCSVログ、検証期間、再現条件

インジケーター値を取得できるようになったからといって、すぐに完全自動発注へ接続する必要はありません。まず通知やログで検証し、サインの再現性、リペイント有無、確定足での残り方を確認してから、発注処理へ進める方が安全です。

EAファンクラブでは、インジケーター値取得を、通知、表示、判定、発注、決済、リスク管理へ分けて扱います。これにより、後から「通知だけ使う」「発注を止める」「ログ検証だけ行う」といった運用に切り替えやすくなります。

実コード例1:インジケーターハンドルを管理する

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したインジケーターハンドル管理例です。
// 実運用EAの完成ソースではありません。

int g_indicatorHandle = INVALID_HANDLE;

bool CreateIndicatorHandle()
{
   // 実際のEAでは、インジケーター名やinput引数を仕様に合わせて設定します。
   // この記事では実インジケーター名や中核条件は扱いません。

   g_indicatorHandle = iCustom(_Symbol, PERIOD_CURRENT, "SampleIndicator");

   if(g_indicatorHandle == INVALID_HANDLE)
   {
      Print("DIAG/INDICATOR: event=HANDLE_FAIL",
            " reason=INVALID_HANDLE",
            " symbol=", _Symbol);
      return false;
   }

   Print("DIAG/INDICATOR: event=HANDLE_OK",
         " reason=ICUSTOM_CREATED",
         " symbol=", _Symbol);

   return true;
}

void ReleaseIndicatorHandle()
{
   if(g_indicatorHandle == INVALID_HANDLE)
      return;

   IndicatorRelease(g_indicatorHandle);
   g_indicatorHandle = INVALID_HANDLE;

   Print("DIAG/INDICATOR: event=HANDLE_RELEASE",
         " reason=INDICATOR_RELEASE_DONE");
}

この例では、iCustomでインジケーターハンドルを作り、失敗時はHANDLE_FAILとしてログに残します。handle作成失敗は、サインなしとは別の状態です。

実コード例2:CopyBuffer取得結果を分ける

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したCopyBuffer取得例です。
// 実運用EAの完成ソースではありません。

struct BufferReadResult
{
   bool ok;
   double value;
   int copied;
   int bufferIndex;
   int shift;
   string reason;
};

BufferReadResult ReadIndicatorBuffer(int bufferIndex, int shift)
{
   BufferReadResult result;
   result.ok = false;
   result.value = EMPTY_VALUE;
   result.copied = 0;
   result.bufferIndex = bufferIndex;
   result.shift = shift;
   result.reason = "INIT";

   if(g_indicatorHandle == INVALID_HANDLE)
   {
      result.reason = "INVALID_HANDLE";
      return result;
   }

   double values[1];
   ArraySetAsSeries(values, true);

   ResetLastError();

   int copied = CopyBuffer(g_indicatorHandle, bufferIndex, shift, 1, values);
   result.copied = copied;

   if(copied != 1)
   {
      result.reason = "COPYBUFFER_FAIL";
      return result;
   }

   result.ok = true;
   result.value = values[0];
   result.reason = "COPYBUFFER_OK";

   return result;
}

この例では、CopyBufferの取得失敗と、取得できた値を分けています。copiedが1ではない場合は、サインなしではなく、取得失敗として扱います。

実コード例3:Signal Snapshotとして固定する

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したSignal Snapshot例です。
// 実運用EAの完成ソースではありません。

enum IndicatorSignalSide
{
   IND_SIGNAL_NONE = 0,
   IND_SIGNAL_BUY,
   IND_SIGNAL_SELL
};

struct IndicatorSignalSnapshot
{
   bool valid;
   IndicatorSignalSide side;
   int shift;
   datetime barTime;
   double rawValue;
   string reason;
};

IndicatorSignalSnapshot BuildSignalSnapshot(int shift)
{
   IndicatorSignalSnapshot snap;
   snap.valid = false;
   snap.side = IND_SIGNAL_NONE;
   snap.shift = shift;
   snap.barTime = iTime(_Symbol, PERIOD_CURRENT, shift);
   snap.rawValue = EMPTY_VALUE;
   snap.reason = "INIT";

   BufferReadResult buyBuffer = ReadIndicatorBuffer(0, shift);
   BufferReadResult sellBuffer = ReadIndicatorBuffer(1, shift);

   if(!buyBuffer.ok && !sellBuffer.ok)
   {
      snap.reason = "BUFFER_READ_FAIL";
      return snap;
   }

   if(buyBuffer.ok && buyBuffer.value != EMPTY_VALUE)
   {
      snap.valid = true;
      snap.side = IND_SIGNAL_BUY;
      snap.rawValue = buyBuffer.value;
      snap.reason = "BUY_SIGNAL";
      return snap;
   }

   if(sellBuffer.ok && sellBuffer.value != EMPTY_VALUE)
   {
      snap.valid = true;
      snap.side = IND_SIGNAL_SELL;
      snap.rawValue = sellBuffer.value;
      snap.reason = "SELL_SIGNAL";
      return snap;
   }

   snap.reason = "NO_SIGNAL";
   return snap;
}

この例では、取得値をその場で直接Entryへ使わず、IndicatorSignalSnapshotとして固定しています。

実際のEAでは、このSnapshotをGATE、risk、duplicate controlへ渡し、最終的にexecution層へ進むかを判断します。

実コード例4:確定足で判定する

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化した確定足判定例です。
// 実運用EAの完成ソースではありません。

int SignalShiftForConfirmedBar()
{
   return 1;
}

void EvaluateConfirmedBarSignal()
{
   int shift = SignalShiftForConfirmedBar();

   IndicatorSignalSnapshot snap = BuildSignalSnapshot(shift);

   Print("DIAG/INDICATOR_SIGNAL: event=SNAPSHOT",
         " valid=", snap.valid,
         " shift=", snap.shift,
         " bar_time=", TimeToString(snap.barTime, TIME_DATE | TIME_MINUTES),
         " reason=", snap.reason);

   if(!snap.valid)
   {
      Print("DIAG/ENTRY: event=SKIP",
            " reason=", snap.reason);
      return;
   }

   Print("DIAG/ENTRY: event=CANDIDATE",
         " reason=CONFIRMED_BAR_SIGNAL",
         " side=", (int)snap.side);

   // 実際のEAでは、この後にGATE / risk / executionへ分けて渡します。
   // この記事では実Entry条件やOrderSend処理は扱いません。
}

この例では、shift=1を使って確定足のサインを評価しています。未確定足を使う場合は、サイン変動やリペイントの扱いを別途仕様化する必要があります。

ログで確認するポイント

インジケーターEA化では、サインが出たかどうかだけでなく、どのbuffer、どのshift、どのbar timeを見たかが重要です。

ログ区分確認できること例
INDICATORhandle作成・解放HANDLE_OK、HANDLE_FAIL、HANDLE_RELEASE
BUFFER_READCopyBuffer取得結果COPYBUFFER_OK、COPYBUFFER_FAIL
INDICATOR_SIGNALサインSnapshotBUY_SIGNAL、SELL_SIGNAL、NO_SIGNAL
SHIFTどの足を見たかshift=0、shift=1
BAR_TIME対象バー時刻bar_time
REPAINT_CHECK過去サイン変化の確認VALUE_CHANGED、VALUE_STABLE
ENTRYEntry候補へ渡したかCANDIDATE、SKIP

「サインが出ているのにEAが入らない」という相談では、まず表示サインとEA取得値が一致しているかを確認します。

バックテストとリアルで確認すること

インジケーターEA化では、バックテストだけでなく、リアルタイムでの挙動確認も重要です。

確認項目バックテストリアルタイム確認
サイン発生位置履歴上のサイン位置を確認リアルで同じタイミングに出るか確認
shiftshift=0 / shift=1の違いを確認未確定足で変動するか確認
リペイント履歴だけでは見えにくい場合がある発生後にサインが変わるか観察
CopyBuffer値ログで値取得を確認チャート表示とログ値を比較
Entry候補候補発生時刻を確認リアルで候補が固定されるか確認

バックテスト上で見えるサインが、リアルタイムで同じように使えるとは限りません。特に、未確定足サインやリペイント型インジケーターでは、リアルタイム確認が重要です。

よくある失敗例

失敗1:チャート上の矢印だけを見てEA化する

表示されている矢印と、EAがCopyBufferで取得できる値は同じとは限りません。buffer番号、shift、EMPTY_VALUE、Object表示かどうかを確認する必要があります。

失敗2:CopyBuffer失敗をサインなしとして扱う

CopyBufferが失敗した状態と、サインがない状態は違います。COPYBUFFER_FAILとNO_SIGNALはログ上も分けるべきです。

失敗3:shift=0を確定サインとして扱う

shift=0は現在足であり、値が変わる可能性があります。確定足で判断したい場合は、shift=1を使う方針を検討します。

失敗4:リペイント確認をしない

過去サインが変わるインジケーターをそのままEA化すると、バックテストとリアル稼働で差が出る可能性があります。

失敗5:handle作成失敗を見逃す

iCustomでhandleが作成できていない場合、EAは値を取得できません。INVALID_HANDLEを起動時に確認し、ログに残す必要があります。

失敗6:インジケーターinput条件がチャート表示とEA呼び出しで違う

チャートに表示したインジケーターとEAから呼び出したインジケーターでinputが違うと、サイン位置が変わる場合があります。

失敗7:サイン取得とEntry実行を直接つなぐ

サインがあっても、GATE、risk、duplicate control、execution precheckを通す必要があります。サイン取得はEntry候補の一部として扱います。

導入前・開発依頼前に整理する情報

インジケーターEA化を依頼する場合、次の情報を整理しておくと仕様確認がスムーズになります。

  • 対象インジケーター名
  • インジケーターのinput設定
  • BUYサインとSELLサインの見た目
  • BUY / SELLのbuffer番号
  • サインなしの値が0か、EMPTY_VALUEか、別の値か
  • shift=0で使うのか、shift=1で使うのか
  • 確定足でEntryするのか、未確定足でEntryするのか
  • リペイントするかどうか
  • サイン発生後に消えることがあるか
  • チャート表示とCopyBuffer値が一致するか
  • Entryを1回だけにするか、同一方向の再Entryを許可するか
  • サイン取得後に通すGATE / risk条件
  • ログに出すbuffer、shift、bar time、reason
  • バックテストとリアル確認の手順

インジケーターEA化では、見た目のサインだけでなく、EAが取得できる値、確定タイミング、リペイントの有無を整理することが重要です。

値取得・EA化の検証条件を記録する

よくある失敗パターン

失敗パターン起きる問題確認すること
OnTickで毎回handleを作る処理が重くなり不安定になるhandleはOnInitで作る
INVALID_HANDLEを確認しないCopyBuffer失敗の原因が分からないhandle生成直後に確認する
BarsCalculatedを見ない計算前に値を取りに行く必要本数以上か確認する
CopyBuffer戻り値を見ない取得失敗後に配列を参照するcopiedを確認する
IndicatorReleaseしないhandle管理が不明瞭になるOnDeinitで解放する
使用中handleを解放するその後のCopyBufferで失敗する解放タイミングを限定する
複数時間足handleを混同する別時間足の値で判定する変数名とログで区別する
ログが不足している原因調査ができないhandle、buffer、shift、copiedを出す

開発・改修依頼前に整理したい情報

CopyBufferやhandle管理の不具合を相談する場合は、事前に以下を整理しておくと原因確認が進めやすくなります。

整理項目記入例確認理由
対象EASampleEA.mq5どのEAで値取得しているか確認するため
対象インジiMA、iRSI、CustomSignalなどhandle生成元を確認するため
対象銘柄・時間足USDJPY M15、XAUUSD H1などsymbol、timeframe、履歴不足を確認するため
取得bufferbuffer 0、buffer 1などCopyBuffer対象を確認するため
参照shift0、1、確定足基準など現在足と確定足の違いを確認するため
ExpertsログHANDLE_CREATE、COPYBUFFER_TRACEなど失敗箇所を追うため
ソース有無mq5あり / ex5のみSetIndexBufferやinputを確認できるか判断するため
バックテスト条件期間、モデル、時間足、スプレッドテスター特有の履歴不足を確認するため

口座番号、認証情報、Webhook URL、APIキー、個人情報は共有しないでください。ログを共有する場合は、必要な箇所だけを伏せ字にして整理してください。

実務チェックリスト

  • handleをOnInitで作成している
  • OnTickで毎回handleを作り直していない
  • handle生成直後にINVALID_HANDLEを確認している
  • handle生成時にGetLastErrorをログへ出している
  • BarsCalculatedで計算済みバー数を確認している
  • CopyBufferの戻り値copiedを確認している
  • 取得本数が不足している時に配列を参照していない
  • EMPTY_VALUEと取得失敗を分けて扱っている
  • 複数インジケーターのhandleを別変数で管理している
  • 複数時間足のhandleを時間足別に区別している
  • OnDeinitでIndicatorReleaseを行っている
  • IndicatorRelease後にhandleをINVALID_HANDLEへ戻している
  • 値取得、妥当性確認、signal判定、entry gateを分けている
  • ログ名を固定し、Expertsログで検索しやすくしている

検証時に残すべき証跡

EAにインジケーター値を取り込む処理を検証する場合、単にバックテストを実行するだけでは不十分です。どの値を、どの足で、どのbufferから取得し、どの判定に使ったのかを確認できる証跡が必要です。

証跡残す内容目的
setファイルinput設定、使用インジ、shift、期間同じ条件を再現する
Expertsログhandle、BarsCalculated、CopyBuffer、signal値取得から判定まで追跡する
バックテスト条件銘柄、時間足、期間、モデル、スプレッド検証条件を明確にする
チャートスクリーンショットサイン位置、インジ表示、EAログ表示と取得値を照合する
CSVログ時刻、値、signal、block reason大量データを後から分析する
バージョン情報EAバージョン、インジバージョン修正前後の差分を確認する

不具合調査では、「動かない」という説明だけでは原因を特定できません。値取得に失敗しているのか、値は取れているがsignal条件を満たしていないのか、entry gateで止まっているのか、注文処理で失敗しているのかをログで分けてください。

特にCopyBuffer関連では、buffer、shift、copied、last_error、BarsCalculated、取得値、basisを同じ行に残すと、後から原因を確認しやすくなります。

CopyBufferのログ設計

CopyBufferを使うEAでは、ログ設計が重要です。EAが注文しない時、ロジック条件ではなく、インジケーター値が取得できていないことが原因の場合があります。

ログ名は、HANDLE_OK、HANDLE_FAIL、INDICATOR_READY、INDICATOR_NOT_READY、COPYBUFFER_OK、COPYBUFFER_FAIL、SIGNAL_EMPTYのように分けると検索しやすくなります。

ログ名残す内容目的
HANDLE_OKインジケーター名、handle、symbol、timeframe。ハンドル作成成功を確認します。
HANDLE_FAILインジケーター名、GetLastError。ハンドル作成失敗を確認します。
INDICATOR_READYBarsCalculated、必要本数。計算済み本数を確認します。
INDICATOR_NOT_READY計算済み本数不足。起動直後やデータ不足を確認します。
COPYBUFFER_OKbuffer、shift、count、value。値取得成功を確認します。
COPYBUFFER_FAILbuffer、shift、要求本数、取得本数、GetLastError。値取得失敗を確認します。
SIGNAL_EMPTYEMPTY_VALUE、buffer、shift。サインなしと取得失敗を分けます。

開発依頼前に整理する情報

EAにインジケーター値を取り込みたい場合や、CopyBufferが失敗する不具合を相談する場合は、対象EA、対象インジケーター、setファイル、銘柄、時間足、ハンドル作成ログ、CopyBufferログ、バッファ番号、shift指定を整理してください。

特にカスタムインジケーターをEAに取り込む場合は、インジケーター側のバッファ仕様が重要です。買いサイン、売りサイン、ライン、フィルター値がどのバッファに入っているのか、値なしがEMPTY_VALUEなのか0なのかを確認してください。

整理する情報内容理由
EA名・バージョン対象ファイル名、更新日、バージョン。確認対象を特定するため。
インジケーター名iMA、iATR、iRSI、iCustom対象。取得対象を明確にするため。
setファイルinput設定一式。同じ条件を再現するため。
銘柄・時間足_Symbol、参照時間足、MTF。ハンドル作成条件に関係するため。
バッファ番号CopyBufferで指定する番号。取得する値を特定するため。
shift現在足か確定足か。判定再現性に関係するため。
ログHANDLE、BarsCalculated、CopyBuffer。取得失敗の確認に必要です。
送らない情報口座番号、パスワード、APIキー、Webhook URL。機密情報を保護するため。

CopyBuffer実務チェック表

  • OnInitでインジケーターハンドルを作成している
  • INVALID_HANDLEを確認している
  • ハンドル作成失敗時にログを出している
  • BarsCalculatedで計算済み本数を確認している
  • CopyBufferの戻り値を確認している
  • 要求本数に満たない場合は判定へ進んでいない
  • shift=0とshift=1の意味を明確にしている
  • 現在足と確定足を混同していない
  • ArraySetAsSeriesの配列方向を確認している
  • EMPTY_VALUEとCopyBuffer失敗を分けている
  • iCustom利用時にバッファ番号を確認している
  • OnDeinitでIndicatorReleaseを行っている
  • バックテスト条件とsetファイルを保存している
  • 口座情報や認証情報をログへ出していない

よくある失敗パターン

失敗パターン起きる問題確認すること
インジ名を推測で指定するINVALID_HANDLEになる実ファイル名と配置場所を確認する
input引数を省略する順序ズレや設定違いが起きるインジ側input定義と一致させる
buffer番号を見た目で決める別bufferや空bufferを読むSetIndexBufferを確認する
現在足をそのままEA判定に使うサインが出たり消えたりする確定足基準を検討する
EMPTY_VALUEをエラー扱いするサインなしを異常と誤認する取得失敗とサインなしを分ける
リペイントを確認しないチャート表示とEA結果が合わないshift 0とshift 1を比較する
ログが不足している原因が追えないhandle、buffer、shift、copiedを出す

開発・改修依頼前に整理したい情報

iCustomを使ったEA化や値取得不具合を相談する場合は、事前に以下を整理しておくと確認が進めやすくなります。

整理項目記入例確認理由
対象インジ名MyCustomIndicatoriCustomの指定名を確認するため
配置場所MQL5/Indicators/Customサブフォルダ指定の有無を見るため
input一覧period、threshold、modeなどEA側引数の順序を合わせるため
buffer番号Buy=0、Sell=1などCopyBufferの対象を確認するため
ソース有無mq5あり / ex5のみSetIndexBufferを確認できるか判断するため
リペイント有無不明、現在足で変化するなどEA判定basisを決めるため
ExpertsログICUSTOM_HANDLE、ICUSTOM_COPYなどhandleとCopyBuffer結果を確認するため
EA化したい動作サイン確定後に通知、発注前確認などsignalとexecutionの責務を分けるため

実務チェックリスト

  • iCustomで指定するインジケーター名を実ファイル名で確認した
  • サブフォルダにある場合、iCustomのパス指定を確認した
  • インジ側inputの順序とEA側iCustom引数を照合した
  • input型の違いがないか確認した
  • handleがINVALID_HANDLEではないことを確認した
  • GetLastErrorをhandle生成直後にログへ出した
  • SetIndexBufferとCopyBufferのbuffer番号を対応させた
  • CopyBufferの戻り値copiedを確認した
  • EMPTY_VALUEをサインなしとして扱うか決めた
  • shift 0とshift 1の違いを確認した
  • リペイントの有無を現在足と確定足で確認した
  • EA側で値取得、妥当性確認、signal判定、entry gateを分けた

よくある質問

チャートに矢印が出ていればEAからも同じように読めますか?

必ずしもそうではありません。矢印がbufferに出ているのか、Objectとして描画されているのか、アラートだけなのかを確認する必要があります。

CopyBufferで値が取れない場合はサインなしですか?

違います。CopyBuffer失敗とサインなしは別です。取得失敗はCOPYBUFFER_FAIL、サインなしはNO_SIGNALとして分けるべきです。

shift=0とshift=1はどちらを使うべきですか?

仕様によります。早く反応したいならshift=0を使う場合がありますが、値が変わる可能性があります。確定足で安定して判定したい場合はshift=1を使う方針を検討します。

リペイントするインジケーターはEA化できませんか?

EA化自体は可能な場合があります。ただし、過去サインが変わる前提で、どのタイミングの値を使うか、検証とリアルの差をどう扱うかを明確にする必要があります。

インジケーターinputはEA側でも同じにする必要がありますか?

基本的には同じ条件で確認する必要があります。チャート表示時とEA呼び出し時でinputが違うと、サイン位置や値が変わる可能性があります。

サインが出たらすぐOrderSendしてよいですか?

避けた方が安全です。サインはEntry候補の一部です。GATE、risk、duplicate control、execution precheckを通してから実行する設計が必要です。

バックテストで良ければリアルでも同じになりますか?

必ずしも同じにはなりません。未確定足、リペイント、tick model、履歴計算、リアルタイム更新の違いにより差が出る場合があります。

実装コードがなくてもインジケーターEA化の相談はできますか?

可能です。インジケーター名、input設定、サイン表示、buffer番号、shift方針、リペイント有無、ログ確認項目が整理されていれば、相談を進めやすくなります。

handleは毎tick作る必要がありますか?

通常は毎tick作る必要はありません。OnInitで作成し、OnTickでは既存handleを使ってCopyBufferを呼ぶ構成が基本です。毎tick作り直すと処理負荷や管理ミスの原因になります。

CopyBufferが失敗した時は何を最初に確認しますか?

まずhandleがINVALID_HANDLEではないかを確認します。次にBarsCalculated、buffer番号、shift、取得本数、CopyBufferの戻り値、GetLastErrorを順番に確認してください。

BarsCalculatedが不足している場合はエラーですか?

必ずしもエラーではありません。EA起動直後やバックテスト開始直後などは、まだ計算準備が完了していない場合があります。必要本数がそろうまで判定を見送る設計にしてください。

IndicatorReleaseは必ず必要ですか?

不要になったhandleはIndicatorReleaseで解放するのが基本です。OnDeinitや再生成時に解放し、解放後はhandle変数をINVALID_HANDLEへ戻しておくと管理しやすくなります。

複数時間足では同じhandleを使えますか?

同じインジケーターでも、時間足が違う場合は別handleとして管理します。M15用、H1用などを変数名とログで区別し、それぞれBarsCalculatedとCopyBuffer結果を確認してください。

EMPTY_VALUEはCopyBuffer失敗ですか?

CopyBufferが成功していても、取得値がEMPTY_VALUEになる場合があります。サイン系インジケーターでは、そのバーにサインがないことをEMPTY_VALUEで表す場合があるため、CopyBuffer失敗とサインなしは分けて扱ってください。

MQL5でiMAを呼べば移動平均線の値が直接返りますか?

MQL5では、iMAは基本的にインジケーターハンドルを返します。移動平均線の値を取得するには、そのハンドルを使ってCopyBufferでバッファ値を取得します。

CopyBufferの戻り値は何を意味しますか?

CopyBufferの戻り値は、実際にコピーできた要素数です。要求本数と一致していない場合は、取得不足として扱い、ログを出して判定を止める方が安全です。

shift=0とshift=1はどちらを使えばよいですか?

shift=0は現在足、shift=1は1本前の確定足として扱うことが多いです。現在足は値が変化するため、再現性を重視する場合は確定足を使う設計が扱いやすいです。

BarsCalculatedは必ず確認すべきですか?

確認した方が安全です。ハンドルが有効でも、インジケーターの計算本数が不足していると、CopyBufferで必要本数を取得できないことがあります。

iCustomで値が取れない時は何を確認しますか?

インジケーター名、ファイルパス、input引数、バッファ番号、EMPTY_VALUE、ハンドル作成結果、BarsCalculated、CopyBufferの戻り値を確認します。カスタムインジケーター側の仕様確認も必要です。

CopyBufferで0.0が返った場合は取得成功ですか?

0.0が有効な値である場合もありますが、取得失敗や初期値の可能性もあります。CopyBufferの戻り値、GetLastError、BarsCalculated、EMPTY_VALUEを確認し、値の意味を分けて判断してください。

iCustomでINVALID_HANDLEになる原因は何ですか?

インジケーター名、配置パス、input引数の順序、input型、対象symbol、timeframeが合っていない可能性があります。まずOnInitでiCustomの戻り値とGetLastErrorをログへ出してください。

チャートではサインが出ているのにEAで取得できないのはなぜですか?

EA側が見ているbuffer番号やshiftが、チャートで見ているサインと違う可能性があります。表示ライン、SetIndexBuffer、CopyBufferのbuffer番号、shift 0 / shift 1を確認してください。

iCustomのinputは全部指定する必要がありますか?

対象インジケーターの仕様によります。途中のinputだけを省略すると順序がズレる場合があります。EA化では、インジ側input定義を確認し、必要な引数を正しい順序と型で渡してください。

リペイントするインジケーターはEA化できますか?

可能な場合もありますが、未確定足で値が変わることを前提に設計する必要があります。バー確定型EAでは、shift 1の確定足を使うなど、判定basisを明確にしてください。

EMPTY_VALUEはエラーですか?

必ずしもエラーではありません。サイン系インジケーターでは、そのバーにサインがないことをEMPTY_VALUEで表す場合があります。CopyBufferの失敗と、CopyBuffer成功後のサインなしは分けて扱ってください。

EA化する時は現在足と確定足のどちらを使うべきですか?

EAの仕様によります。安定した判定を優先するなら確定足、リアルタイム反応を優先するなら現在足を使う場合があります。ただし、現在足を使う場合は値の変動、リペイント、同一バー重複発注防止を設計してください。

関連する確認ページ

確認したい内容に応じて、次のページを参照してください。本文中ですでに案内したページは、ここでは重ねて掲載していません。

確認分野関連ページ
技術講座MQL5インジケーター開発・EA連携完全ガイド|iCustom・CopyBuffer・OnCalculate・SetIndexBufferの基本
技術講座MQL5時系列データ・価格取得完全ガイド|CopyRates・iClose・SymbolInfoの基本
技術講座MQL5 EA設計パターン完全ガイド|signal・execution・risk・exitの責務分離
技術講座MQL5デバッグ・ログファースト開発完全ガイド|Print・Expertsログ・再現条件の整理
技術辞典MQL5インジケーター関数辞典|iCustom・CopyBuffer・SetIndexBuffer・OnCalculate一覧
開発実務ノートMQL5ログファースト設計を実コードで解説|event・side・reason・detailで追跡するEA開発
開発実務ノートMQL5バックテスト実務ノート|検証条件・最適化・リアル差分を記録する考え方
開発実務ノート自動売買EAを自作する前に確認すること|ロジック・バックテスト・ログ設計
技術辞典MQL5 CopyBufferで値が取れない原因と確認ポイント
技術辞典MQL5 OnInitの役割と初期化失敗の確認
開発実務ノートMQL5 EAサンプルコードの読み方|OnInit・OnTick・OrderSend・CopyBufferの基本構造

あわせて確認したいページ

今回の確認内容に関連する補足ページです。必要な項目だけ確認してください。

確認目的関連ページ
「MQL5 iCustom インジケーター EA化」の読後に「サインインジケータ作成を依頼する前に整理すること」を補足確認サインインジケータ作成を依頼する前に整理すること
「MQL5 iCustom インジケーター EA化」の読後に「MQL5 CopyBufferとインジケーターハンドル管理を実コードで解説」を補足確認MQL5 CopyBufferとインジケーターハンドル管理を実コードで解説
「MQL5 iCustom インジケーター EA化」の読後に「押し目・戻り・トレンドとは」を補足確認押し目・戻り・トレンドとは
「MQL5 iCustom インジケーター EA化」の読後に「サポートライン・レジスタンスラインとは」を補足確認サポートライン・レジスタンスラインとは

まとめ

MQL5でインジケーターサインをEA化する時は、チャート上の見た目だけで判断せず、EAが取得できる値、buffer番号、shift、確定足、リペイントの有無を整理することが重要です。

特に、次の4点を分けると、サイン不一致、早すぎるEntry、バックテストとリアルの差、CopyBuffer失敗の原因を確認やすくなります。

  • indicator handle:iCustomなどでインジケーターを正しく呼び出す
  • buffer read:CopyBufferでどのbuffer・shiftの値を取得したか確認する
  • Signal Snapshot:取得値を判定用に固定し、reason付きで残す
  • confirmed bar / repaint check:確定足で使うか、未確定足やリペイントを許容するか決める

また、CopyBuffer失敗とNO_SIGNALを混同しないこと、サイン取得とOrderSendを直接つなげないことも重要です。

完成EAの中核Entry条件や独自インジケーターの内部ロジックを公開しなくても、iCustom、CopyBuffer、buffer番号、shift、確定足、リペイント確認の考え方を理解しておくことで、開発依頼、既存インジケーターのEA化、検証、不具合調査、販売後サポートの品質を上げやすくなります。

利用条件・相談窓口

確認内容案内ページ
MT4/MT5 技術講座|EA・インジケーター・MQL開発を学ぶ技術講座ハブ
不具合報告の方法不具合報告・調査依頼について
免責事項・リスク説明免責事項・リスク説明

お問い合わせはEAFC公式LINEへ

EAFCサイト内の記事、商品、導入前確認、設定確認、ログ確認、開発依頼前のご相談など、各種お問い合わせはEAFC公式LINEより受け付けています。

※投資助言、売買指示、利益保証、推奨ロット、推奨銘柄の案内は行っておりません。

口座番号、認証情報、Webhook URL、GAS URL、APIキーなどの機密情報は送信しないでください。

ABOUT ME
記事URLをコピーしました