MQL5 CopyBufferとインジケーターハンドル管理を実コードで解説|安全取得helperとIndicatorRelease
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は単独で完結する処理ではなく、次の流れの中で使います。
- インジケーターハンドルを作成する
- handleが有効か確認する
- CopyBufferで必要なbuffer値を取得する
- 取得本数とエラーを確認する
- 値が有効か確認する
- 不要になったhandleをIndicatorReleaseで解放する
この流れを分けずにOnTick内へ直接書くと、取得失敗時の理由が追いにくくなります。EA開発では、handle作成、値取得、ログ確認、解放処理を別責務として扱う方が安全です。
インジケーターハンドルとは
インジケーターハンドルとは、MQL5が内部で管理しているインジケーター計算資源を参照するための識別子です。
たとえば、iMAで移動平均のhandleを作成すると、以後はそのhandleを使ってCopyBufferで値を取得します。
| 処理 | 役割 |
|---|---|
| iMA / iRSI / iCustomなど | インジケーターhandleを作成する |
| INVALID_HANDLE確認 | handle作成に失敗していないか確認する |
| CopyBuffer | handleからbuffer値を取得する |
| IndicatorRelease | 不要になったhandleを解放する |
handleは毎tick作り直すものではありません。通常はOnInitで作成し、OnTickでは値取得だけを行い、OnDeinitで解放します。
buffer番号とshiftの考え方
CopyBufferでは、どのbufferのどの位置の値を取得するかを指定します。
| 項目 | 意味 | 注意点 |
|---|---|---|
| handle | 対象インジケーターのhandle | INVALID_HANDLEでないことを確認する |
| buffer番号 | インジケーター内の出力バッファ番号 | MAなど単一線なら0が多いが、複数線インジでは異なる |
| shift | 取得するバー位置 | 0は現在足、1は確定済みの1本前として扱うことが多い |
| count | 取得する本数 | 必要最小限にする |
| 配列 | 取得値の格納先 | ArraySetAsSeriesの向きに注意する |
特にEAでは、現在足の値を使うのか、確定足の値を使うのかを曖昧にしないことが重要です。
バー確定型EAであれば、shift=1のように確定済みバーを使う設計が多くなります。一方、リアルタイム反応型EAではshift=0を使う場合もあります。ただし、その場合は値が足の途中で変化する前提を明示する必要があります。
CopyBuffer失敗時に確認すること
CopyBufferが失敗した場合、単に「値が取れない」と判断するだけでは原因を切り分けられません。
最低限、次の項目を確認します。
| 確認項目 | 見る理由 |
|---|---|
| handle | INVALID_HANDLEのままCopyBufferしていないか |
| buffer番号 | 存在しないbufferを指定していないか |
| shift | 必要なバーがまだ計算されていない位置を指定していないか |
| 取得本数 | CopyBufferの戻り値が期待本数と一致しているか |
| GetLastError | MQL5側のエラーを確認できるか |
| 値の妥当性 | EMPTY_VALUE、0固定、非数値などになっていないか |
取得失敗時は、Expertsログにhandle、buffer、shift、copied、errorを残すと確認しやすくなります。
handleを使い回す理由
インジケーターハンドルは、毎tick作り直すのではなく、基本的にはOnInitで作成して使い回します。
毎tick作成すると、次の問題が起きやすくなります。
- 処理が重くなる
- handle解放漏れが起きやすい
- 値取得失敗の原因が追いにくくなる
- 時間足変更や再セット時の管理が複雑になる
- 長時間稼働時に不要な負荷が増える
EAの構造としては、次のように分けると分かりやすくなります。
| 場所 | 主な責務 |
|---|---|
| OnInit | handle作成、初期化確認、失敗時ログ |
| OnTick | CopyBufferで値取得、判定に渡す、失敗時は安全側に見送る |
| OnDeinit | IndicatorReleaseで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_FAIL | handle作成失敗をExpertsログへ残す |
| HANDLE_CREATE_OK | handle作成成功を確認できるようにする |
ここでは学習用に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 | 取得できなかった理由を記録する |
| BuildIndicatorSnapshot | handle作成と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を誤って再利用しない |
| OnDeinit | EA終了時に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_OK | handle作成が成功しているか |
| HANDLE_CREATE_FAIL | handle作成失敗のerrorが出ているか |
| COPYBUFFER FAIL | copied、buffer、shift、errorが確認できるか |
| SNAPSHOT | 値取得結果がreadyになっているか |
| HANDLE_RELEASE | EA終了時にhandle解放が行われているか |
| DEINIT | 終了時に余計な処理が走っていないか |
ログ確認の基本は、次のページも参考にしてください。
開発依頼前に整理する情報
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化、独自インジケーター連携、長時間稼働、販売後サポートのいずれでも、問題発生時の確認がしやすくなります。

