MQL5イベント処理完全ガイド|OnTimer・OnTradeTransaction・OnChartEventの使い分け
MQL5のEAやインジケーターは、決められたイベントに応じて処理が呼び出されます。代表的なものに、起動時の OnInit、終了時の OnDeinit、新しいティックを受け取る OnTick、一定間隔で処理する OnTimer、取引サーバー側の取引変化を受ける OnTradeTransaction、チャート上のクリックや変更を受ける OnChartEvent があります。
イベント処理を理解すると、EAやインジケーターの処理を整理しやすくなります。特に、すべてを OnTick に詰め込むのではなく、外部制御、認証、通知、UIクリック、取引結果確認、ログ出力、パネル更新などを適切なイベントへ分けると、検証・保守・問い合わせ対応がしやすくなります。
この記事では、MQL5のイベント処理を、EA開発・インジケーター開発・パネルUI・外部連携・ログ確認の実務視点で整理します。売買判断、推奨ロット、特定銘柄、運用成績に関する助言は扱いません。あくまで、MQL5プログラムを安定して設計・確認するための技術講座です。
この記事で扱う範囲
この記事では、MQL5イベント関数の基本的な役割と、実務上の使い分けを扱います。対象は、EA、インジケーター、パネルEA、外部連携EA、通知機能付きツール、長時間稼働する補助ツールです。
主に扱うイベント関数
| イベント関数 | 主な用途 | この記事での重点 |
|---|---|---|
| OnInit | 起動時の初期化 | 初期設定、ハンドル作成、timer開始、self-check |
| OnDeinit | 終了時の後処理 | timer停止、軽量cleanup、終了理由の確認 |
| OnTick | EAで新しいtickを受ける | 価格変化に連動する処理、過負荷回避 |
| OnTimer | 一定間隔の処理 | 外部制御、認証、通知、UIメンテナンス |
| OnTradeTransaction | 取引トランザクションの確認 | 注文結果、約定、決済、履歴確認の入口 |
| OnChartEvent | チャート操作やObjectクリック | ボタン、パネル、表示切替、チャート変更 |
| OnCalculate | インジケーター計算 | EAのOnTickとの違い |
この記事で深く扱わないこと
この記事では、個別の売買ロジック、ロット計算、注文戦略、損益改善手法は扱いません。また、外部API通信そのものの詳細、JSON組み立て、WebRequest許可設定、Google Apps Script側の実装、Discord Webhookの実URLなども扱いません。
イベント関数をどのように分けるか、どのイベントで何を確認するか、どのログを残すか、問い合わせ前にどの情報を整理すべきかに絞って解説します。
MQL5イベント処理の全体像
MQL5では、プログラム側が任意のタイミングで常に動き続けるのではなく、ターミナルから届くイベントに応じて関数が呼び出されます。EAであれば新しいtick、timer、取引イベント、チャートイベントなどを受け取り、インジケーターであれば価格データの再計算やチャートイベントを受け取ります。
重要なのは、イベントごとに向いている処理が違うことです。価格変化に連動する処理は OnTick、一定間隔の監視は OnTimer、取引結果の追跡は OnTradeTransaction、ボタン操作は OnChartEvent、インジケーター計算は OnCalculate というように責務を分けます。
イベント関数比較表
| イベント | 主な対象 | 呼ばれる契機 | 向いている処理 | 注意点 |
|---|---|---|---|---|
| OnInit | EA / インジケーター | プログラム起動時 | 初期化、入力値確認、ハンドル作成 | 失敗時の扱いを明確にする |
| OnDeinit | EA / インジケーター | 終了・再初期化時 | timer停止、handle解放、軽量終了処理 | 重いObject走査や広範囲削除は避ける |
| OnTick | 主にEA | 新しいtick受信時 | 価格変化に依存する評価 | すべての処理を詰め込まない |
| OnTimer | EA / インジケーター | 設定した周期 | 定期監視、外部制御、軽量メンテナンス | timer開始と停止を管理する |
| OnTradeTransaction | EA | 取引トランザクション発生時 | 注文・約定・決済結果の追跡 | 処理を重くしすぎない |
| OnChartEvent | EA / インジケーター | クリック、キー操作、チャート変更 | ボタン、UI、パネル操作 | Object名と表示文字を混同しない |
| OnCalculate | インジケーター | 価格データ計算時 | インジケーター値の計算 | EAのOnTickとは役割が違う |
責務分離で考える
イベント処理では、どのイベントに何を書くかを先に決めます。処理をイベント単位で分けるだけでなく、signal、execution、risk、exit、auth、external control、notification、UI、loggingという責務でも分けます。
| 責務 | 主に使うイベント | 補足 |
|---|---|---|
| 初期化 | OnInit | 入力値確認、ハンドル作成、timer開始 |
| 価格依存処理 | OnTick | 新tickで必要な軽量評価 |
| 定期監視 | OnTimer | 外部制御、認証、UIメンテナンス |
| 取引結果確認 | OnTradeTransaction | 注文結果、約定、決済、履歴更新 |
| UI操作 | OnChartEvent | ボタン、入力欄、表示切替 |
| インジ計算 | OnCalculate | バッファ更新、表示値計算 |
| 終了処理 | OnDeinit | timer停止、軽量cleanup |
OnInitの役割
OnInit は、EAやインジケーターの起動時に呼ばれる初期化関数です。ここでは、入力値の確認、indicator handleの作成、Object prefixの初期化、Timer開始、初期ログ、self-checkなどを行います。
OnInitは「起動できる状態か」を確認する場所です。設定不備がある場合は、静かに動かし続けるのではなく、何が不足しているかをログやステータスで確認できるようにします。
OnInitに向いている処理
| 処理 | 目的 | 確認ログ例 |
|---|---|---|
| input確認 | 無効な設定を早期検出する | INIT/CHECK: input=OK |
| symbol情報取得 | digits、point、volume step等を確認する | INIT/SYMBOL: symbol=… |
| indicator handle作成 | MA、ATR等の参照準備 | INIT/HANDLE: ma=OK |
| EventSetTimer | OnTimerを使う準備 | INIT/TIMER: sec=1 |
| Object prefix初期化 | UIやライン名の衝突回避 | INIT/OBJECT: prefix=… |
| 外部連携準備確認 | URLやtokenを直接出さず準備状態だけ確認 | INIT/EXT: configured=Y/N |
| 初期SNAP | 問い合わせ時の初期状態確認 | INIT/SUMMARY: status=OK |
OnInitの最小例
int OnInit()
{
Print("INIT: version=1.00 status=START");
if(!ValidateInputs())
{
Print("INIT: status=FAILED reason=INVALID_INPUT");
return INIT_FAILED;
}
EventSetTimer(1);
Print("INIT: status=OK timer=1sec");
return INIT_SUCCEEDED;
}この例では、入力値確認に失敗した場合に INIT_FAILED を返します。実務では、どの項目が不正だったか、どの機能だけ停止したかをログで分けると確認しやすくなります。
OnDeinitの役割
OnDeinit は、EAやインジケーターが終了する時、時間足変更や設定変更などで再初期化される時に呼ばれる終了処理です。timer停止、handle解放、Comment解除、必要最小限のObject整理などを行います。
OnDeinitで重要なのは、見た目の完全cleanupよりも、異常終了しないことを優先する点です。大量のObject走査や広範囲削除をOnDeinitに詰め込むと、チャート状態や環境によって不安定化する場合があります。
OnDeinitで行う処理と避けたい処理
| 分類 | 処理例 | 方針 |
|---|---|---|
| 行う | EventKillTimer | OnTimerを使った場合は停止する |
| 行う | IndicatorRelease | 作成したhandleを解放する |
| 行う | Comment(“”) | コメント表示を消す |
| 必要時のみ | 自EAの一時Object削除 | prefixと用途を限定する |
| 避ける | 全Object走査 | 他EAや手動Objectを巻き込む可能性がある |
| 避ける | 大量削除ループ | 終了処理が重くなりやすい |
| 避ける | trade系処理 | 終了時に予期しない操作を避ける |
OnDeinitの最小例
void OnDeinit(const int reason)
{
EventKillTimer();
Comment("");
Print("DEINIT: reason=", reason, " status=OK");
}実際には、reasonの内容に応じてログを分けると確認しやすくなります。ただし、終了時に重い処理を行うより、次回起動時のstartup auditで残存Objectを検出・分類する方が安定する場合があります。
OnTickの役割
OnTick は、EAで新しいtickを受け取った時に呼ばれます。価格変化に連動する処理を行う入口です。EAの中心処理として使われることが多い一方で、すべての処理をOnTickへ集めると重くなりやすくなります。
OnTickに向いているのは、価格変化に依存する軽量な確認、現在価格の取得、必要な評価関数の呼び出し、状態変化の検出などです。外部通信、UI全再構築、重いObject走査、長いログ出力は、OnTimerや別helperへ分けることを検討します。
OnTickに置く処理・置かない処理
| 処理 | OnTick向きか | 理由 | 代替先 |
|---|---|---|---|
| 最新価格の取得 | 向いている | tickごとに変わるため | – |
| 新バー判定 | 向いている | 軽量でEA制御に使いやすい | – |
| signal評価呼び出し | 条件付きで向いている | 軽量化・新バー限定が必要 | Evaluate helper |
| 外部制御取得 | 通常は不向き | 通信遅延や負荷が出る可能性 | OnTimer |
| 認証状態の定期確認 | 通常は不向き | tick頻度に依存させる必要が薄い | OnTimer |
| 通知送信 | 通常は不向き | transport処理を本体評価と分けたい | notification queue / OnTimer |
| UI全再構築 | 不向き | ちらつき・描画負荷の原因になる | OnChartEvent / OnTimer |
| 全Object走査 | 不向き | 長時間稼働で重くなりやすい | OnTimer / startup audit |
| 大量ログ | 不向き | Strategy Testerや実運用でログ過多になる | 状態変化時ログ / summary |
OnTickを軽く保つ基本形
void OnTick()
{
UpdateMarketSnapshot();
if(IsNewBar())
{
EvaluateSignalOnNewBar();
}
ManageRuntimeStateLight();
}OnTickでは、処理本体を長く書かず、役割ごとのhelperを呼び出す形にすると確認しやすくなります。実際のEAでは、signal、execution、risk、exit、external controlを分け、ログ上でもどこで止まったか追えるようにします。
OnTimerの役割
OnTimer は、EventSetTimer などで設定した周期に応じて呼ばれるイベント処理です。tickが少ない時間帯でも一定間隔で処理できるため、外部制御、認証確認、通知キュー処理、UIメンテナンス、Object欠損チェック、定期ログに向いています。
OnTimerを使う場合は、OnInitでtimerを開始し、OnDeinitで必ず停止します。timerを使う目的、周期、処理内容、失敗時の扱いを明確にしておくと、長時間稼働時の確認がしやすくなります。
OnTimer利用例表
| 用途 | OnTimerに向いている理由 | 確認ログ例 |
|---|---|---|
| 外部制御取得 | tick頻度に依存しない | TIMER/EXTCTRL: state=OK |
| 認証状態確認 | 定期確認しやすい | TIMER/AUTH: status=OK |
| 通知キュー処理 | 本体判定とtransportを分けられる | TIMER/NOTIFY: sent=1 fail=0 |
| UIメンテナンス | 毎tick再描画を避けられる | TIMER/UI: update=DIFF |
| Object監査 | 低頻度で十分な場合が多い | TIMER/OBJECT: count=… |
| 状態summary | 一定間隔で現状を記録できる | TIMER/SUMMARY: mode=… |
| 長時間稼働監視 | heartbeat的に状態確認できる | TIMER/HEARTBEAT: alive=Y |
OnTimerの最小例
int OnInit()
{
EventSetTimer(5);
Print("INIT: timer=5sec");
return INIT_SUCCEEDED;
}
void OnTimer()
{
RefreshExternalStateIfNeeded();
ProcessNotificationQueue();
UpdatePanelIfChanged();
}
void OnDeinit(const int reason)
{
EventKillTimer();
}この例では、外部状態確認、通知処理、パネル更新をOnTimer側へ分けています。実務では、それぞれの処理にthrottle、失敗時reason、last-good状態、ログ抑制を持たせると確認しやすくなります。
OnTradeTransactionの役割
OnTradeTransaction は、EAで取引トランザクションが発生した時に呼ばれるイベント処理です。注文リクエストの結果、約定、注文更新、決済、履歴反映など、取引関連の変化を確認する入口になります。
OnTradeTransactionは、取引処理の結果確認やログ追跡に役立ちます。ただし、ここに重い処理を詰め込むのではなく、受け取った内容を分類し、必要な状態更新やログ記録へ渡す設計が扱いやすくなります。
OnTradeTransactionで確認する項目
| 確認対象 | 確認する理由 | ログ例 |
|---|---|---|
| transaction type | どの種類の取引変化かを分類する | TRADE_TX: type=… |
| symbol | 対象銘柄を確認する | symbol=… |
| order | 注文IDを確認する | order=… |
| deal | 約定IDを確認する | deal=… |
| position | ポジションIDを確認する | position=… |
| request | EAが送ったリクエストとの関係を見る | request_action=… |
| result | retcodeや結果を確認する | retcode=… |
| time | 発生時刻を記録する | server_time=… |
OnTradeTransactionの最小例
void OnTradeTransaction(const MqlTradeTransaction &trans,
const MqlTradeRequest &request,
const MqlTradeResult &result)
{
Print("TRADE_TX: type=", trans.type,
" order=", trans.order,
" deal=", trans.deal,
" symbol=", trans.symbol,
" retcode=", result.retcode);
}この例は、取引トランザクションの概要をログに出すだけの最小例です。実務では、必要に応じてorder、deal、position、symbol、magic、reason、retcodeなどを分類し、注文結果、決済結果、履歴更新の確認に使います。
OnTradeTransactionを使う時の注意
OnTradeTransactionは、取引関連の変化を詳細に追いやすい一方で、複数段階のtransactionが発生する場合があります。1回の注文操作に対して、注文追加、約定、履歴追加など複数のイベントが関係することがあります。
そのため、「OnTradeTransactionが呼ばれたら必ず最終状態」と決めつけず、必要に応じて現在のポジション、注文、履歴を再確認します。ログでは、transaction単体の情報と、再取得した現在状態を分けて記録すると追跡しやすくなります。
OnChartEventの役割
OnChartEvent は、チャート上のクリック、オブジェクトクリック、キー入力、チャート変更などを受け取るイベント処理です。パネルUI、ボタン、HELP、SNAP、表示切替、設定編集などで重要です。
ボタンUIでは、CHARTEVENT_OBJECT_CLICK を確認し、sparam に入るObject名を使って、どのボタンが押されたかを判断します。表示文字ではなく、内部Object名で判定することが重要です。
OnChartEventで受ける代表的なイベント
| イベント例 | 主な用途 | 確認ポイント |
|---|---|---|
| CHARTEVENT_OBJECT_CLICK | ボタン押下 | sparamのObject名 |
| CHARTEVENT_CHART_CHANGE | チャートサイズ・時間足変更等 | パネル再配置要求 |
| キー入力系イベント | ショートカット操作 | 誤操作防止、対象限定 |
| Object変更系イベント | Object移動や編集 | 手動変更を許可するか |
| マウス関連イベント | 高度なUI操作 | 必要時のみ有効化 |
OnChartEventの最小例
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if(id == CHARTEVENT_OBJECT_CLICK)
{
if(sparam == "EAF_BTN_HELP")
{
ToggleHelpPanel();
return;
}
if(sparam == "EAF_BTN_SNAP")
{
PrintRuntimeSnapshot();
return;
}
}
if(id == CHARTEVENT_CHART_CHANGE)
{
g_relayout_required = true;
return;
}
}この例では、ボタンを押した時の処理と、チャート変更時の再配置要求を分けています。OnChartEvent内で重い再構築を直接行うのではなく、フラグを立ててOnTimer側で軽く処理する構成にすると安定しやすくなります。
OnCalculateとの違い
OnCalculate は、主にカスタムインジケーターで使う計算イベントです。価格データやインジケーターバッファを更新するための関数であり、EAの OnTick とは役割が異なります。
インジケーターでは、表示値やバッファを計算する処理をOnCalculateに置きます。一方で、ボタン操作やチャート変更はOnChartEvent、定期処理はOnTimerへ分けられます。
EAとインジケーターのイベント差
| 項目 | EA | インジケーター |
|---|---|---|
| 価格変化の主処理 | OnTick | OnCalculate |
| 初期化 | OnInit | OnInit |
| 終了処理 | OnDeinit | OnDeinit |
| 定期処理 | OnTimer | OnTimer |
| チャート操作 | OnChartEvent | OnChartEvent |
| 取引transaction | OnTradeTransaction | 通常は対象外 |
| 注文・決済 | EA側の責務 | 通常は表示・計算中心 |
インジケーターをEAへ流用する場合、OnCalculateに入っていた計算処理をそのままOnTickへ移すのではなく、データ取得、評価、表示、ログを分けて設計し直します。
重い処理をOnTickに置かない理由
OnTickは、相場のtickを受けるたびに呼ばれます。tickが多い環境では、短時間に何度も呼ばれます。ここに外部通信、全Object走査、大量ログ、全パネル再作成、履歴全件走査などを入れると、処理が重くなりやすくなります。
OnTickは「価格変化に関係する軽量処理の入口」と考え、重い処理はOnTimer、OnTradeTransaction、OnChartEvent、helper関数、queue処理へ分けます。
OnTick過負荷の典型例
| 典型例 | 起きやすい問題 | 整理方針 |
|---|---|---|
| 毎tickで外部制御を取得 | 通信遅延、ログ過多 | OnTimerで周期管理 |
| 毎tickで全Object再作成 | ちらつき、描画負荷 | 差分更新、OnTimer再配置 |
| 毎tickで履歴全走査 | 長期間稼働で重くなる | 必要時だけ範囲限定 |
| 毎tickで詳細ログ出力 | ログ確認が困難 | 状態変化時のみ出力 |
| OnTickに長い分岐を直書き | 保守性低下 | 責務別helperへ分離 |
| 通知送信を直接実行 | transport失敗が本体処理に混ざる | 通知queueへ分離 |
状態変化時だけログを出す
OnTickで毎回同じログを出すと、確認したい情報が埋もれます。状態が変わった時だけ出す、一定秒数ごとにsummaryだけ出す、詳細ログはdebug inputで切り替えるといった設計が有効です。
void PrintStateWhenChanged(const string new_state)
{
static string last_state = "";
if(new_state != last_state)
{
Print("STATE_CHANGE: from=", last_state, " to=", new_state);
last_state = new_state;
}
}このような仕組みにすると、OnTickで確認していても、ログ量を抑えながら状態遷移を追えます。
外部制御や認証をOnTimerへ分離する考え方
外部制御、認証、稼働許可、通知先設定、管理用ステータス取得などは、tickごとに確認する必要がない場合が多くあります。これらをOnTimerに分けると、価格変化処理と外部確認処理を分離できます。
外部制御を扱う場合は、実URL、APIキー、認証トークンなどの実値をログや画面に出さないようにします。ログには、取得成否、状態、reason、最終取得時刻、stale判定など、確認に必要な情報だけを出します。
外部制御をOnTimerへ分ける例
| 項目 | OnTimerで確認する内容 | OnTick側で使う内容 |
|---|---|---|
| 認証状態 | 認証OK / NG / stale / fetch error | 新規処理を許可するか |
| 外部稼働制御 | ON / OFF / emergency / invalid | 処理候補を止めるか |
| 時間制御 | 現在時間帯の許可状態 | 新規処理のgate |
| 通知設定 | 通知ON/OFF、送信先種別 | 通知queueへ積むか |
| 設定バージョン | config_version、updated_at | 古い設定を使っていないか |
| 最終成功状態 | last-good snapshot | 取得失敗時の扱いを判断 |
fail-safe理由を分ける
外部制御では、取得失敗、認証NG、設定不正、古い設定、緊急停止などを同じ理由にしないことが重要です。理由を分けると、問い合わせ時にどこで止まったか確認しやすくなります。
enum ExtState
{
EXT_OK,
EXT_FETCH_ERROR,
EXT_INVALID_BODY,
EXT_STALE,
EXT_DISABLED
};この例では、外部状態をenumで分けています。実際のログでは、raw URLやtokenではなく、分類済みの状態だけを出します。
通知処理の分離
通知処理は、signal評価や注文結果確認とは別の責務です。通知が成功したかどうかと、EA内部の判定や取引結果は混同しないようにします。
通知処理をOnTickへ直接書くと、transport失敗、通信遅延、payload生成失敗などが本体処理と混ざりやすくなります。実務では、通知したいイベントをqueueへ積み、OnTimerで送信処理を行う構成が扱いやすい場合があります。
通知処理の責務分離
| 責務 | 内容 | 主な場所 |
|---|---|---|
| 通知イベント生成 | 何を通知対象にするか決める | OnTick / OnTradeTransaction / OnChartEvent |
| payload作成 | 送信用の本文を作る | notification helper |
| 送信実行 | transport処理 | OnTimer / notifier helper |
| 送信結果確認 | 成功・失敗・status code確認 | notification logger |
| 再送制御 | 必要に応じた再試行 | queue manager |
| ログ | 通知成否を記録 | NOTIFY/SEND、NOTIFY/FAIL |
通知ログには、Webhook URL、APIキー、認証トークン、個人情報、口座番号などの実値を入れないようにします。対象種別、イベント種別、送信成否、理由だけを残す方針が安全です。
UIクリック処理の分離
パネルEAや表示付きインジケーターでは、ボタン操作を OnChartEvent で受けます。ただし、クリックイベントの中に重い処理や全再構築を入れると、UIが重くなったり、表示崩れの原因になる場合があります。
クリックイベントでは、どのボタンが押されたかを判定し、runtime stateや要求フラグを更新する程度に留めます。重い処理、再配置、外部通信、通知送信などは、OnTimerや専用helperへ渡します。
UIクリック処理の分離表
| 操作 | OnChartEventで行うこと | 後続処理 |
|---|---|---|
| HELP | HELP表示フラグを切り替える | パネル差分更新 |
| SNAP | SNAP要求を立てる | ログ出力helper |
| APPLY | edit buffer検証要求を立てる | validation、applied value反映 |
| CANCEL | edit bufferを戻す要求 | UI表示更新 |
| RESET | 初期値復帰要求 | 確認ログ、表示更新 |
| 表示切替 | view modeを変更 | OnTimerで再配置 |
| チャート変更 | relayout_requiredを立てる | 軽量再配置 |
Object名で判定する
ボタンの表示文字は後から変わる可能性があります。クリック判定では、表示文字ではなくObject名を使います。Object名にはprefixと役割を含め、他EAや手動Objectと衝突しないようにします。
bool IsPanelButton(const string name)
{
return (StringFind(name, "EAF_PANEL_") == 0);
}このようにprefixで判定すると、自EAのパネルObjectだけを処理対象にしやすくなります。
イベント間で状態を共有する方法
OnTick、OnTimer、OnTradeTransaction、OnChartEventは別々のイベントですが、同じEA内のruntime stateを共有できます。ただし、どのイベントがどの状態を更新するかを決めておかないと、状態の上書きや表示と実状態のズレが起きやすくなります。
状態共有で分けるべきもの
| 状態 | 主に更新するイベント | 確認ポイント |
|---|---|---|
| Market snapshot | OnTick | 価格、spread、bar time |
| External state | OnTimer | 認証、外部制御、stale判定 |
| Trade state | OnTradeTransaction / OnTick | 注文結果、ポジション状態 |
| UI state | OnChartEvent / OnTimer | 表示モード、ボタン、HELP |
| Applied config | OnChartEvent後のvalidation | APPLY済み設定 |
| Edit buffer | UI入力操作 | 未適用値と確定値を分ける |
| Log state | 各イベント | 前回ログとの差分を管理 |
runtime構造体でまとめる例
struct RuntimeState
{
string mode;
string ext_state;
string last_reason;
datetime last_tick_time;
datetime last_timer_time;
bool relayout_required;
};
RuntimeState g_rt;状態を構造体にまとめると、SNAPログやパネル表示でも同じ情報を使いやすくなります。ただし、表示用文字列と判定用enumやboolを混同しないようにします。
ログ設計とデバッグ
イベント処理を分けても、ログが整理されていなければ不具合の切り分けは難しくなります。ログでは、どのイベントで、何を確認し、どの状態に変わったかを短く記録します。
ログを増やすほど確認しやすくなるとは限りません。同じログが大量に出続けると、重要な変化が見えにくくなります。イベント別にログ名を分け、状態変化時ログ、定期summary、詳細debugを分けて設計します。
イベント別ログ表
| イベント | ログ名例 | 記録する内容 |
|---|---|---|
| OnInit | INIT/SUMMARY | version、symbol、timeframe、timer、設定確認 |
| OnDeinit | DEINIT/SUMMARY | reason、timer停止、終了状態 |
| OnTick | TICK/STATE | 新バー、spread、軽量状態変化 |
| OnTimer | TIMER/SUMMARY | 外部制御、認証、通知queue、UI更新 |
| OnTradeTransaction | TRADE_TX | type、order、deal、retcode、symbol |
| OnChartEvent | CHART_EVENT | event id、Object名、操作種別 |
| OnCalculate | CALC/SUMMARY | rates_total、prev_calculated、計算状態 |
| 共通 | SNAP | 現在状態のまとめ |
SNAPログに入れると確認しやすい項目
| 項目 | 理由 | 注意点 |
|---|---|---|
| version | 対象ファイルを確認する | ファイル名と一致させる |
| symbol / timeframe | 再現条件を確認する | ブローカー差も記録する |
| timer状態 | OnTimerが動いているか確認する | 周期も記録する |
| external state | 外部制御の状態を確認する | URLやtokenは出さない |
| last event | 直近のイベントを確認する | OnTick / OnTimer / OnChartEventなど |
| last reason | 停止・見送り理由を確認する | 短いreasonにする |
| object count | UI過多や残存確認に使う | 必要な範囲だけ数える |
| last error | 異常の追跡に使う | 発生時刻も残す |
イベント設計でよくある不具合と確認方法
イベント処理の不具合は、コンパイルエラーだけでは判断できません。動いているように見えても、OnTimerが止まっている、OnChartEventが届いていない、OnTradeTransactionのログが多すぎる、OnTickに処理が集中している、といったケースがあります。
| 症状 | 主な原因 | 確認するログ | 整理方針 |
|---|---|---|---|
| OnTimerが動いていない | EventSetTimer未実行、EventKillTimer後に再開していない | INIT/TIMER、TIMER/SUMMARY | OnInitとOnDeinitを確認 |
| ボタンが反応しない | Object名不一致、背景Objectが前面、イベント未処理 | CHART_EVENT | sparamとZORDERを確認 |
| ログが多すぎる | OnTickで毎回詳細ログ | TICK/STATE | 状態変化時ログにする |
| 通知が本体処理を巻き込む | 通知transportをOnTickに直書き | NOTIFY/FAIL | queueとOnTimerへ分離 |
| 取引結果が追えない | OnTradeTransactionログ不足 | TRADE_TX | order、deal、retcodeを記録 |
| 終了時に不安定 | OnDeinitで重いcleanup | DEINIT/SUMMARY | 軽量終了処理へ寄せる |
| 再セット後に古いObjectが混ざる | prefixやstartup audit不足 | OBJECT_AUDIT | 残存Objectを分類する |
開発依頼前に整理すること
イベント処理が絡むEAやインジケーターの開発を依頼する場合は、どのイベントで何をしたいかを整理しておくと、仕様化が進めやすくなります。特に、外部連携、通知、パネルUI、長時間稼働、取引結果ログを含む場合は、イベント設計が重要です。
依頼前整理表
| 整理項目 | 確認する内容 | 補足 |
|---|---|---|
| 対象種別 | EA / インジケーター / パネルEA / スクリプト | 使えるイベントが変わる |
| 価格依存処理 | tickごとか、新バーごとか | OnTick設計に関係 |
| 定期処理 | 何秒ごとに何を確認するか | OnTimer設計に関係 |
| 取引結果確認 | 注文・約定・決済をどう記録するか | OnTradeTransactionに関係 |
| UI操作 | ボタン、入力欄、HELP、SNAPの有無 | OnChartEventに関係 |
| 外部連携 | 認証、外部制御、通知、記録 | URLやtokenの扱いに注意 |
| ログ | INIT、TIMER、TRADE_TX、SNAPの有無 | 問い合わせ前確認に重要 |
| 終了時処理 | Objectを消すか、残すか | OnDeinit方針に関係 |
| 再現資料 | Expertsログ、Journalログ、スクリーンショット | 発生時刻も記録する |
問い合わせ時は、EA名、バージョン、setファイル、対象銘柄、時間足、発生時刻、Expertsログ、Journalログ、スクリーンショットを整理してください。イベント処理の不具合では、どのイベントのログが出ているか、どのイベントのログが出ていないかも重要な確認材料になります。
次に読む技術講座
この講座とあわせて確認すると、MT5・MQL5開発、検証、不具合調査の流れを整理しやすくなります。
| No | 講座 | 確認できること |
|---|---|---|
| LEARN-019 | MQL5チャートオブジェクト・パネルUI完全ガイド | チャートObject・パネルUIを確認する |
| LEARN-018 | MQL5 WebRequest・JSON・外部API実装完全ガイド | WebRequestや通知をOnTimerへ分ける考え方を確認する |
| LEARN-021 | MQL5マルチシンボル・マルチタイムフレーム完全ガイド | 複数銘柄データ取得のタイミングを確認する |
| LEARN-022 | MQL5長時間稼働・安定化完全ガイド | OnTimer・OnDeinit・長時間稼働を確認する |
| LEARN-014 | MQL5デバッグ・ログファースト開発完全ガイド | イベント別ログ設計を確認する |
次に確認するページ
技術講座を確認した後、導入・商品確認・開発相談・不具合報告へ進む場合は、以下のページも確認してください。
| ページ | 確認できること |
|---|---|
| 技術講座一覧 | MT5・MQL5・EA開発に関する技術講座を順番に確認できます。 |
| 導入ガイド | EA、インジケーター、補助ツールを導入する前の確認事項を整理できます。 |
| 商品一覧 | EAファンクラブで扱う補助ツール、インジケーター、コピーEAなどを確認できます。 |
| 開発代行ページ | EA、インジケーター、補助ツールの新規作成・改修相談を確認できます。 |
| 不具合報告・サポート依頼 | ログ、スクリーンショット、再現手順を整理して相談する場合に確認できます。 |
よくある質問
OnTickだけでEAを作ってもよいですか?
小さなEAであればOnTick中心でも構成できます。ただし、外部制御、認証、通知、パネルUI、取引結果ログ、長時間稼働を含む場合は、OnTimer、OnTradeTransaction、OnChartEventへ責務を分けた方が確認しやすくなります。
OnTimerは何に使いますか?
定期監視、外部制御取得、認証確認、通知queue処理、UIメンテナンス、Object欠損チェック、heartbeatログなどに使います。tickが少ない時間帯でも一定間隔で処理できる点が特徴です。
OnTradeTransactionは必須ですか?
すべてのEAで必須ではありません。ただし、注文結果、約定、決済、履歴反映、retcode、order、dealを詳しく追いたい場合は有効です。取引関連のログを整理したいEAでは検討対象になります。
OnChartEventはインジケーターでも使えますか?
はい。チャート上のボタン、Objectクリック、チャート変更などを受ける用途で、EAでもインジケーターでも使えます。パネルUIや表示切替がある場合に重要です。
外部連携をOnTimerに分ける理由は何ですか?
外部連携は、tickごとに実行する必要がない場合が多く、通信遅延や失敗も起こり得ます。OnTimerへ分けると、価格変化処理と外部状態確認を分離でき、ログや失敗理由も整理しやすくなります。
イベント間で変数を共有してもよいですか?
共有できます。ただし、どのイベントがどの状態を更新するかを決めておく必要があります。Market snapshot、external state、trade state、UI state、edit buffer、applied valueを分けると確認しやすくなります。
OnDeinitで重い処理をしてよいですか?
基本的には避けます。OnDeinitではtimer停止、Comment解除、handle解放などの軽量処理を優先します。Objectの広範囲削除や重いcleanupは、対象を限定するか、次回起動時のstartup auditで確認する方が安定する場合があります。
ログはイベントごとに分けるべきですか?
分けた方が確認しやすくなります。INIT、TIMER、TICK、TRADE_TX、CHART_EVENT、DEINIT、SNAPのように分類すると、どのイベントで問題が起きたか追跡しやすくなります。
OnTimerを使うと重くなりますか?
OnTimer自体が問題というより、OnTimer内で何をどれだけ行うかが重要です。短い周期で重い処理を繰り返すと負荷になります。周期、処理量、ログ量、Object更新量を制御してください。
OnTradeTransactionだけで現在ポジションを完全に判断できますか?
OnTradeTransactionは取引変化を追う入口として有効ですが、必要に応じて現在の注文、ポジション、履歴を再取得して確認します。transaction単体の情報と現在状態を分けてログに残すと確認しやすくなります。
まとめ
MQL5のイベント処理では、OnTickにすべてを詰め込むのではなく、処理の性質に応じてイベントを分けることが重要です。価格変化に依存する処理はOnTick、定期監視はOnTimer、取引結果確認はOnTradeTransaction、UI操作はOnChartEvent、インジケーター計算はOnCalculateへ分けます。
イベントごとの責務を分けると、ログ確認、再現条件整理、長時間稼働確認、パネルUIの安定化、外部制御の切り分けがしやすくなります。特に、外部連携や通知を扱う場合は、実URL、APIキー、認証トークン、口座番号などの実値をログや本文に出さず、状態分類とreasonで追跡できる設計にします。
学習内容を確認しても整理が難しい場合は、EA名、バージョン、setファイル、Expertsログ、Journalログ、発生時刻、スクリーンショットを整理したうえで相談してください。

