MQL5 CopyBufferとインジケーターハンドル管理を実コードで解説|安全取得helperとIndicatorRelease

EAファンクラブ

MQL5でEAからインジケーター値を読む場合、よく使う関数がCopyBufferです。

しかし、CopyBufferは単体で使えばよい関数ではありません。実際には、インジケーターハンドルの作成、buffer番号の指定、shiftの指定、取得失敗時の確認、不要になったhandleの解放まで含めて設計する必要があります。

EAがエントリーしない、インジケーター値が0になる、バックテストでは動くのにリアルでは値が取れない、時間足変更後に値取得が不安定になる。こうした問題は、CopyBufferだけでなく、handle lifecycleやログ設計まで含めて確認すると切り分けやすくなります。

この記事では、MQL5のCopyBufferとインジケーターハンドル管理を、学習用に一般化したコード断片で解説します。完成EAソース全文、外部シート制御、認証、endpoint、token、URL、実運用set値、中核エントリー条件は公開しません。

この記事で扱う範囲

項目この記事で扱う内容扱わない内容
目的EAからインジケーター値を安全に取得する構造利益を狙う売買ロジック、具体的なエントリー条件
主な関数CopyBuffer、IndicatorRelease、iMAなどのhandle作成例独自インジケーターの中核判定式
設計対象handle作成、安全取得helper、失敗ログ、解放処理外部制御、認証、実運用set値
コード例学習用に簡略化した短いコード断片完成EAソース全文、実運用コード全文
確認対象INVALID_HANDLE、CopyBuffer失敗、取得本数、GetLastError売買判断、推奨ロット、推奨銘柄

CopyBufferとは

CopyBufferは、MQL5でインジケーターのバッファ値を取得するための関数です。

EA側で移動平均、RSI、MACD、独自インジケーターなどの値を参照する場合、まず対象インジケーターのhandleを作成し、そのhandleに対してCopyBufferを呼び出します。

つまり、CopyBufferは単独で完結する処理ではなく、次の流れの中で使います。

  1. インジケーターハンドルを作成する
  2. handleが有効か確認する
  3. CopyBufferで必要なbuffer値を取得する
  4. 取得本数とエラーを確認する
  5. 値が有効か確認する
  6. 不要になったhandleをIndicatorReleaseで解放する

この流れを分けずにOnTick内へ直接書くと、取得失敗時の理由が追いにくくなります。EA開発では、handle作成、値取得、ログ確認、解放処理を別責務として扱う方が安全です。

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

インジケーターハンドルとは、MQL5が内部で管理しているインジケーター計算資源を参照するための識別子です。

たとえば、iMAで移動平均のhandleを作成すると、以後はそのhandleを使ってCopyBufferで値を取得します。

処理役割
iMA / iRSI / iCustomなどインジケーターhandleを作成する
INVALID_HANDLE確認handle作成に失敗していないか確認する
CopyBufferhandleからbuffer値を取得する
IndicatorRelease不要になったhandleを解放する

handleは毎tick作り直すものではありません。通常はOnInitで作成し、OnTickでは値取得だけを行い、OnDeinitで解放します。

buffer番号とshiftの考え方

CopyBufferでは、どのbufferのどの位置の値を取得するかを指定します。

項目意味注意点
handle対象インジケーターのhandleINVALID_HANDLEでないことを確認する
buffer番号インジケーター内の出力バッファ番号MAなど単一線なら0が多いが、複数線インジでは異なる
shift取得するバー位置0は現在足、1は確定済みの1本前として扱うことが多い
count取得する本数必要最小限にする
配列取得値の格納先ArraySetAsSeriesの向きに注意する

特にEAでは、現在足の値を使うのか、確定足の値を使うのかを曖昧にしないことが重要です。

バー確定型EAであれば、shift=1のように確定済みバーを使う設計が多くなります。一方、リアルタイム反応型EAではshift=0を使う場合もあります。ただし、その場合は値が足の途中で変化する前提を明示する必要があります。

CopyBuffer失敗時に確認すること

CopyBufferが失敗した場合、単に「値が取れない」と判断するだけでは原因を切り分けられません。

最低限、次の項目を確認します。

確認項目見る理由
handleINVALID_HANDLEのままCopyBufferしていないか
buffer番号存在しないbufferを指定していないか
shift必要なバーがまだ計算されていない位置を指定していないか
取得本数CopyBufferの戻り値が期待本数と一致しているか
GetLastErrorMQL5側のエラーを確認できるか
値の妥当性EMPTY_VALUE、0固定、非数値などになっていないか

取得失敗時は、Expertsログにhandle、buffer、shift、copied、errorを残すと確認しやすくなります。

handleを使い回す理由

インジケーターハンドルは、毎tick作り直すのではなく、基本的にはOnInitで作成して使い回します。

毎tick作成すると、次の問題が起きやすくなります。

  • 処理が重くなる
  • handle解放漏れが起きやすい
  • 値取得失敗の原因が追いにくくなる
  • 時間足変更や再セット時の管理が複雑になる
  • 長時間稼働時に不要な負荷が増える

EAの構造としては、次のように分けると分かりやすくなります。

場所主な責務
OnInithandle作成、初期化確認、失敗時ログ
OnTickCopyBufferで値取得、判定に渡す、失敗時は安全側に見送る
OnDeinitIndicatorReleaseでhandle解放

この分離により、EAが「起動できていない」のか、「値取得に失敗している」のか、「判定条件が成立していない」のかをログで分けやすくなります。

IndicatorReleaseが必要になる場面

IndicatorReleaseは、作成したインジケーターハンドルを解放するために使います。

特に次の場面では、handle解放を意識します。

  • EAを削除する時
  • 時間足変更や再セットでEAが再初期化される時
  • 設定変更でhandleを作り直す時
  • 複数インジケーターを使うEAで不要handleを整理する時

handle解放後は、変数をINVALID_HANDLEへ戻しておくと、誤って古いhandleを使い続ける事故を防ぎやすくなります。

実コード断片1:handle初期化

以下は、実際のEAで使う考え方を学習用に簡略化したコード例です。完成EAのソース全文ではなく、構造を理解するための抜粋です。

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

int g_maHandle = INVALID_HANDLE;

bool CreateMaHandle()
{
   if(g_maHandle != INVALID_HANDLE)
      return true;

   ResetLastError();

   g_maHandle = iMA(_Symbol,
                    PERIOD_CURRENT,
                    20,
                    0,
                    MODE_EMA,
                    PRICE_CLOSE);

   if(g_maHandle == INVALID_HANDLE)
   {
      Print("DIAG/INDICATOR: event=HANDLE_CREATE_FAIL",
            " reason=INVALID_HANDLE",
            " error=", GetLastError());
      return false;
   }

   Print("DIAG/INDICATOR: event=HANDLE_CREATE_OK",
         " kind=MA",
         " symbol=", _Symbol);

   return true;
}

実際のEAでは、認証、外部制御、口座条件、エラー処理、ログ出力などを分けて設計します。この記事では、公開できる範囲の構造だけを取り上げています。

このコードの役割

処理役割
g_maHandle移動平均インジケーターのhandleを保持する
INVALID_HANDLE確認すでに作成済みなら再作成しない
ResetLastError作成前にエラー状態を整理する
iMA学習用の移動平均handleを作成する
HANDLE_CREATE_FAILhandle作成失敗をExpertsログへ残す
HANDLE_CREATE_OKhandle作成成功を確認できるようにする

ここでは学習用にiMAを例にしています。実際のEAでは、使うインジケーターの種類、期間、適用価格、時間足、設定値を仕様に合わせて設計します。

実コード断片2:CopyBuffer安全取得helper

以下は、CopyBufferで1つの値を安全に取得するための学習用helper例です。完成EAのソース全文ではなく、失敗時に理由を追いやすくする構造だけを取り上げています。

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

bool CopyOneBufferValue(int handle,
                        int bufferIndex,
                        int shift,
                        double &outValue)
{
   outValue = 0.0;

   if(handle == INVALID_HANDLE)
   {
      Print("DIAG/COPYBUFFER: event=SKIP",
            " reason=INVALID_HANDLE");
      return false;
   }

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

   ResetLastError();

   int copied = CopyBuffer(handle,
                           bufferIndex,
                           shift,
                           1,
                           values);

   if(copied != 1)
   {
      Print("DIAG/COPYBUFFER: event=FAIL",
            " reason=COPY_COUNT_MISMATCH",
            " buffer=", bufferIndex,
            " shift=", shift,
            " copied=", copied,
            " error=", GetLastError());
      return false;
   }

   if(!MathIsValidNumber(values[0]))
   {
      Print("DIAG/COPYBUFFER: event=FAIL",
            " reason=INVALID_VALUE");
      return false;
   }

   outValue = values[0];
   return true;
}

実際のEAでは、認証、外部制御、口座条件、エラー処理、ログ出力などを分けて設計します。この記事では、公開できる範囲の構造だけを取り上げています。

このコードの役割

処理役割
handle確認INVALID_HANDLEのまま値取得しない
ArraySetAsSeries配列の向きを時系列参照に合わせる
CopyBuffer指定buffer、指定shiftの値を1本取得する
copied確認期待した本数が取れたか確認する
GetLastError取得失敗時のエラーを残す
MathIsValidNumber取得値が数値として有効か確認する
outValue呼び出し元へ取得値を返す

CopyBufferの戻り値を確認せず、values[0]だけを使う設計は危険です。取得失敗時には配列に期待値が入っていない可能性があるため、必ずcopiedを確認します。

実コード断片3:取得値を判定層へ渡す

以下は、CopyBufferで取得した値を、そのまま発注処理へ直結せず、確認用のsnapshotとして扱う考え方を示した例です。中核エントリー条件は含めていません。

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

struct IndicatorSnapshot
{
   bool   ready;
   double maValue;
   string reason;
};

IndicatorSnapshot BuildIndicatorSnapshot()
{
   IndicatorSnapshot snap;
   snap.ready = false;
   snap.maValue = 0.0;
   snap.reason = "INIT";

   if(!CreateMaHandle())
   {
      snap.reason = "HANDLE_NOT_READY";
      return snap;
   }

   double value = 0.0;

   if(!CopyOneBufferValue(g_maHandle, 0, 1, value))
   {
      snap.reason = "COPYBUFFER_FAIL";
      return snap;
   }

   snap.ready = true;
   snap.maValue = value;
   snap.reason = "OK";

   Print("DIAG/INDICATOR: event=SNAPSHOT",
         " ready=", snap.ready,
         " reason=", snap.reason);

   return snap;
}

実際のEAでは、認証、外部制御、口座条件、エラー処理、ログ出力などを分けて設計します。この記事では、公開できる範囲の構造だけを取り上げています。

このコードの役割

処理役割
IndicatorSnapshotインジケーター取得状態をまとめる構造体
ready値取得が正常にできたかを示す
reason取得できなかった理由を記録する
BuildIndicatorSnapshothandle作成とCopyBuffer取得をまとめ、判定層へ渡す
発注へ直結しない値取得と売買実行を分離する

EA設計では、インジケーター値を取った瞬間に発注へ進むのではなく、まずsnapshotとして整理し、その後のsignal層やexecution層へ渡す方が保守しやすくなります。

実コード断片4:handle解放とIndicatorRelease

以下は、OnDeinitや再初期化時にhandleを安全に解放する学習用コード例です。

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

void ReleaseMaHandle()
{
   if(g_maHandle == INVALID_HANDLE)
      return;

   IndicatorRelease(g_maHandle);

   Print("DIAG/INDICATOR: event=HANDLE_RELEASE",
         " kind=MA");

   g_maHandle = INVALID_HANDLE;
}

void OnDeinit(const int reason)
{
   ReleaseMaHandle();

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

実際のEAでは、認証、外部制御、口座条件、エラー処理、ログ出力などを分けて設計します。この記事では、公開できる範囲の構造だけを取り上げています。

このコードの役割

処理役割
INVALID_HANDLE確認未作成handleに対して解放処理を行わない
IndicatorRelease作成済みhandleを解放する
HANDLE_RELEASE解放処理をログで確認する
INVALID_HANDLEへ戻す古いhandleを誤って再利用しない
OnDeinitEA終了時にhandle解放を行う

handle解放は、Object cleanupとは別の責務です。IndicatorReleaseは軽量な終了処理としてOnDeinitで扱いやすい一方、チャートObjectの広範囲cleanupは慎重に設計する必要があります。

よくある失敗例

失敗1:毎tickでhandleを作成している

OnTickのたびにiMAやiCustomを呼び出してhandleを作成すると、処理が重くなり、handle解放漏れや取得不安定の原因になります。handleは原則としてOnInitで作成し、OnTickではCopyBufferで値を読むだけにします。

失敗2:CopyBufferの戻り値を確認していない

CopyBufferの戻り値を見ずに配列の値だけを使うと、取得失敗時に古い値や未初期化値を使う可能性があります。copiedが期待本数と一致しているか確認してください。

失敗3:buffer番号を勘違いしている

複数線を持つインジケーターでは、buffer番号が0だけとは限りません。iCustomを使う場合は、対象インジケーター側のバッファ構造を確認する必要があります。

失敗4:shift=0とshift=1を混同している

shift=0は現在足、shift=1は1本前の確定足として使われることが多いです。バー確定型EAなのか、リアルタイム反応型EAなのかによって使い分ける必要があります。

失敗5:IndicatorRelease後にhandleをINVALID_HANDLEへ戻していない

解放後も変数に古いhandle値が残っていると、後続処理で誤って使う可能性があります。解放後はINVALID_HANDLEへ戻す方が安全です。

失敗6:値取得失敗とシグナル不成立を混同している

CopyBufferに失敗した状態と、インジケーター値は取得できたがシグナル条件が成立しない状態は別です。ログでも、COPYBUFFER_FAILとNO_SIGNALを分けて記録します。

ログで確認するポイント

CopyBufferやhandle管理の問題を確認する時は、Expertsログで次の情報を見ます。

ログ見るポイント
HANDLE_CREATE_OKhandle作成が成功しているか
HANDLE_CREATE_FAILhandle作成失敗のerrorが出ているか
COPYBUFFER FAILcopied、buffer、shift、errorが確認できるか
SNAPSHOT値取得結果がreadyになっているか
HANDLE_RELEASEEA終了時にhandle解放が行われているか
DEINIT終了時に余計な処理が走っていないか

ログ確認の基本は、次のページも参考にしてください。

MT5のログ確認方法|Experts・Journalの見方

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

EA開発を依頼する場合、インジケーター値の取得方法を最初に整理しておくと、仕様のすれ違いを減らせます。

  • どのインジケーター値を使うか
  • 標準インジケーターか、iCustomを使う独自インジケーターか
  • buffer番号はいくつか
  • shift=0を使うのか、shift=1を使うのか
  • バー確定型か、リアルタイム反応型か
  • 値取得失敗時は見送りにするか
  • CopyBuffer失敗時にログを出すか
  • handle作成・解放のタイミングをどうするか
  • 時間足変更や再セット時に再初期化を許容するか

仕様書、setファイル、ログ、スクリーンショットを整理する場合は、次のページも確認してください。

MT5開発依頼前に用意する資料まとめ|仕様書・setファイル・ログ・スクリーンショット

公開しない情報

この記事では、MQL5のCopyBufferとインジケーターハンドル管理を学ぶために、公開可能な範囲だけを一般化して解説しています。以下は公開しません。

  • 完成EAソース全文
  • 外部シート参照による動作制御ロジック
  • 外部シートCSV取得、解析、時間枠、方向制御ロジック
  • 認証、口座許可判定、購入者管理ロジック
  • endpoint、token、URL、Google Sheet ID、Webhook URL、GAS URL
  • APIキー、認証トークン、口座番号、サーバー名
  • 実運用set値
  • 中核エントリー条件
  • 独自優位性のある売買判定式
  • 利益保証、勝率保証、推奨ロット、推奨銘柄、推奨エントリー

本記事は、投資判断や売買指示ではなく、MQL5開発におけるCopyBuffer、handle管理、IndicatorReleaseの実装構造を理解するための技術解説です。

FAQ

CopyBufferとは何ですか?

CopyBufferは、MQL5でインジケーターのbuffer値をEAやスクリプト側へ取得するための関数です。対象インジケーターのhandleを作成したうえで、そのhandleから必要なbufferとshiftの値を取得します。

handleは毎tick作成してよいですか?

基本的には避けた方がよいです。handleはOnInitで作成し、OnTickではCopyBufferで値を取得し、OnDeinitでIndicatorReleaseする構成が分かりやすく安定しやすいです。

CopyBufferが失敗した時は何を見ればよいですか?

handleがINVALID_HANDLEではないか、buffer番号が正しいか、shiftが適切か、戻り値copiedが期待本数と一致しているか、GetLastErrorの値が何かを確認します。

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

EAの設計によります。バー確定型ではshift=1のように確定済みバーを使うことが多く、リアルタイム反応型ではshift=0を使う場合があります。ただし、shift=0は現在足の途中で値が変わる点に注意が必要です。

IndicatorReleaseは必ず必要ですか?

作成したインジケーターハンドルを不要になった時に解放するため、OnDeinitやhandle再作成時にIndicatorReleaseを使う設計が一般的です。解放後はINVALID_HANDLEへ戻しておくと安全です。

iCustomを使う場合も考え方は同じですか?

基本的な流れは同じです。ただし、iCustomでは対象インジケーター側のbuffer番号、パラメータ順、値の出力仕様を確認する必要があります。

このコードは完成EAとして使えますか?

いいえ。この記事のコード例は、CopyBufferとhandle管理の考え方を理解するために簡略化した学習用コードです。完成EAとしてそのまま使うことは想定していません。

実際のEAソース全文は公開されていますか?

公開していません。完成EAソース全文、外部シート制御、認証、endpoint、token、URL、実運用set値、中核エントリー条件は公開対象外です。

関連ページ

ページ確認できること
MQL5ログファースト設計を実コードで解説CopyBuffer失敗時のログ設計、event・reason管理
MQL5 EAのObject lifecycleを実コードで解説OnDeinit、IndicatorRelease、Object cleanupの責務分離
MT5のログ確認方法|Experts・Journalの見方ExpertsログとJournalログの基本確認
MT5開発依頼前に用意する資料まとめ|仕様書・setファイル・ログ・スクリーンショット開発相談前に整理する資料
不具合報告・調査依頼について不具合相談前に送る情報
開発・改修の相談ページを見るEA・インジケーター開発や既存改修の相談導線
よくある質問導入、確認、相談前のFAQ
免責事項投資判断、損益、利用上の注意に関する確認
投資助言を行わない方針売買助言ではなく技術支援として扱う方針

まとめ

MQL5でEAからインジケーター値を読む時は、CopyBufferだけでなく、handle作成、取得失敗時の確認、snapshot化、IndicatorReleaseまで含めて設計する必要があります。

特に、次の4点を分けておくと、原因調査と保守がしやすくなります。

  • handle作成:OnInitで作成し、INVALID_HANDLEを確認する
  • CopyBuffer安全取得:戻り値、buffer、shift、GetLastErrorを確認する
  • snapshot化:取得値とready状態、reasonをまとめて判定層へ渡す
  • IndicatorRelease:OnDeinitや再初期化時にhandleを解放し、INVALID_HANDLEへ戻す

値取得失敗とシグナル不成立を混同すると、EAが動かない原因を切り分けにくくなります。CopyBufferに失敗しているのか、値は取れているが判定条件が成立していないのかを、Expertsログで分けて確認できる設計が重要です。

CopyBufferとhandle管理をログファーストで設計しておくと、インジケーターEA化、独自インジケーター連携、長時間稼働、販売後サポートのいずれでも、問題発生時の確認がしやすくなります。

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