MQL5 OnTimerの使い方|外部連携・通知・定期処理を分ける設計
MQL5でEAを作る時、すべての処理をOnTickに入れると、処理が重くなったり、ログが増えすぎたり、外部連携の失敗原因を追いにくくなったりします。
OnTimerは、一定間隔で処理を実行するためのイベント関数です。EAの売買判定や注文処理はOnTick側に残し、通知、外部連携、状態監視、ログ抑制、定期チェックをOnTimerへ分けることで、EA全体の責務を整理しやすくなります。
特に、Discord通知、Google Sheets連携、WebRequest、CSV出力、稼働状態ログ、外部制御の取得などは、tickごとに実行するよりも、OnTimerで周期を決めて処理する方が扱いやすい場合があります。
このページでは、MQL5のOnTimerの使い方を、EventSetTimer、EventKillTimer、外部連携、通知、ログ抑制、バックテスト負荷対策の観点から整理します。
なお、このページはMQL5開発における技術確認を目的とした内容です。売買判断、推奨エントリー、推奨ロット、利益保証、損失回避保証を行うものではありません。
- OnTimerとは何か
- OnTickとOnTimerの役割を分ける
- OnTimerに向いている処理
- OnTimerに入れすぎない方がよい処理
- EventSetTimerの基本
- EventKillTimerの基本
- ミリ秒タイマーの扱い
- 外部連携処理をOnTimerへ分ける
- WebRequestをOnTimerで扱う時の注意点
- Discord通知をOnTimerで送る考え方
- Google Sheets連携をOnTimerで扱う考え方
- 状態スナップショットをOnTimerで出す
- バックテストでOnTimerを使う時の注意点
- OnTimerログの設計
- ログ出力例
- よくある失敗パターン
- OnTimer処理とあわせて確認したいイベント・時刻管理
- 関連ページ
- イベント処理と外部連携全体を確認する場合
- 開発依頼前に整理したい情報
- まとめ
OnTimerとは何か
OnTimerは、Timerイベントが発生した時に呼ばれるイベント関数です。
EAやインジケーターでタイマー処理を使う場合、通常はOnInitでEventSetTimerを呼び、指定した秒数ごとにOnTimerを実行します。
int OnInit()
{
if(!EventSetTimer(10))
{
PrintFormat("[TIMER_SET_NG] seconds=10 last_error=%d", GetLastError());
return INIT_FAILED;
}
Print("[TIMER_SET_OK] seconds=10");
return INIT_SUCCEEDED;
}
void OnTimer()
{
Print("[TIMER_TICK] periodic task");
}
void OnDeinit(const int reason)
{
EventKillTimer();
PrintFormat("[TIMER_KILL] reason=%d", reason);
}OnTimerを使う場合は、開始、実行、終了をログで確認できるようにしてください。
OnTickとOnTimerの役割を分ける
EA開発では、OnTickとOnTimerの責務を混同しないことが重要です。
OnTickは価格変動に応じた売買判定や注文処理に向いています。一方、OnTimerは、一定間隔でよい処理、外部連携、状態監視、ログ抑制、通知再送などに向いています。
| イベント | 主な役割 | 入れやすい処理 |
|---|---|---|
| OnTick | 価格変動に応じた処理 | signal判定、entry gate、発注前チェック、注文処理、決済判定 |
| OnTimer | 一定間隔の処理 | 外部制御取得、通知送信、CSV出力、稼働監視、ログ抑制、状態同期 |
| OnInit | 初期化処理 | input確認、timer設定、handle生成、初期ログ |
| OnDeinit | 終了処理 | timer停止、handle解放、終了ログ |
外部連携や通知処理をOnTickに直接入れると、tickが多い時間帯に処理回数が増えすぎる場合があります。定期処理でよいものはOnTimerへ分離してください。
OnTimerに向いている処理
OnTimerは、毎tickで実行する必要がない処理に向いています。
特に、外部連携、通知、状態監視、ログ抑制、定期スナップショットは、OnTimerへ分けると構造が分かりやすくなります。
| 処理 | OnTimerに向く理由 | 確認ログ |
|---|---|---|
| Discord通知 | tickごとに送る必要がなく、送信間隔を制御しやすい | NOTIFY_SEND / NOTIFY_SKIP |
| Google Sheets連携 | 定期的な状態送信や集計送信に向いている | SHEET_WRITE / SHEET_THROTTLE |
| 外部制御取得 | 外部シートやAPIから一定間隔で設定を読む場合に向いている | EXTERNAL_FETCH / EXTERNAL_APPLY |
| CSV出力 | tickごとではなく、一定間隔やイベント後の記録に向いている | CSV_WRITE / CSV_SKIP |
| 状態監視 | 口座状態、ポジション状態、稼働状態を周期的に確認できる | RUNTIME_SNAPSHOT |
| ログ抑制 | 同じ状態を毎tick出さず、一定間隔で要約できる | LOG_THROTTLE / TIMER_SUMMARY |
ただし、OnTimerに重い処理を入れすぎると、タイマーイベントの処理自体が詰まる場合があります。処理時間、通信失敗時の戻り、再送制御を設計してください。
OnTimerに入れすぎない方がよい処理
OnTimerは便利ですが、すべての処理を移す場所ではありません。
価格変動に即応する処理や、発注・決済の中心処理は、OnTickや専用のexecution処理へ分けた方が確認しやすくなります。
| OnTimerに入れすぎない処理 | 理由 | 推奨する分離 |
|---|---|---|
| 毎tick必要なentry判定 | Timer間隔中の価格変化を見落とす場合がある | OnTick / signal層 |
| 発注処理そのもの | 外部連携や通知と注文責務が混ざる | execution層へ分離 |
| 重いWebRequestの連続実行 | 通信失敗時に処理が詰まりやすい | throttle、timeout、queue管理 |
| 大量CSV出力 | ファイルI/Oが増え、BTや長時間稼働で重くなる | イベント時出力、要約出力 |
| 毎秒大量ログ | Expertsログが膨らみ、確認しづらくなる | ログ間隔、状態変化時のみ出力 |
OnTimerは、EA本体の売買ロジックを置き換えるものではありません。定期処理、外部処理、補助処理を整理するために使います。
EventSetTimerの基本
EventSetTimerは、Timerイベントの発生間隔を秒単位で設定します。
通常はOnInitで一度だけ呼び出し、失敗した場合はGetLastErrorをログに残します。
input int InpTimerSeconds = 10;
bool SetupTimer()
{
if(InpTimerSeconds <= 0)
{
PrintFormat("[TIMER_CONFIG_NG] seconds=%d reason=must_be_positive", InpTimerSeconds);
return false;
}
ResetLastError();
if(!EventSetTimer(InpTimerSeconds))
{
PrintFormat("[TIMER_SET_NG] seconds=%d last_error=%d",
InpTimerSeconds,
GetLastError());
return false;
}
PrintFormat("[TIMER_SET_OK] seconds=%d", InpTimerSeconds);
return true;
}
int OnInit()
{
if(!SetupTimer())
return INIT_FAILED;
return INIT_SUCCEEDED;
}タイマー間隔は短くしすぎないようにしてください。外部連携や通知では、5秒、10秒、30秒、60秒など、用途に応じて十分な間隔を取る方が扱いやすくなります。
EventKillTimerの基本
OnInitでEventSetTimerを使った場合は、OnDeinitでEventKillTimerを呼びます。
EA削除、時間足変更、再コンパイル、チャート終了などの場面で、終了ログとあわせてTimerを停止しておくと確認しやすくなります。
void OnDeinit(const int reason)
{
EventKillTimer();
PrintFormat("[DEINIT_TIMER_KILL] reason=%d", reason);
}OnDeinitでは、Timer停止、handle解放、必要最小限の終了ログに留める設計が安全です。広範囲のObject削除や重い通信処理を終了時に詰め込みすぎないようにしてください。
ミリ秒タイマーの扱い
EventSetMillisecondTimerを使うと、1秒未満の間隔でTimerイベントを発生させることができます。
ただし、短い間隔でOnTimerを呼び出すほど、処理回数が増え、バックテスト時間や端末負荷に影響します。通常の通知、外部連携、状態監視では、秒単位のEventSetTimerで十分な場合が多いです。
| 方式 | 用途 | 注意点 |
|---|---|---|
| EventSetTimer | 秒単位の定期処理 | 通常の通知、外部連携、状態監視に向く |
| EventSetMillisecondTimer | 1秒未満の高頻度処理 | 処理負荷やBT時間が増えやすい |
高頻度タイマーは、必要性が明確な場合だけ使ってください。ログ確認や外部連携目的で安易に短い周期を設定すると、検証しづらくなる場合があります。
外部連携処理をOnTimerへ分ける
WebRequest、Discord通知、Google Sheets連携などは、OnTimerで周期管理すると整理しやすくなります。
OnTick側では、売買判定や内部状態の更新だけを行い、外部へ送る必要がある情報をキューや状態変数として保持します。OnTimer側で、送信間隔、失敗回数、再送可否を確認してから外部連携を実行します。
datetime g_last_external_sync = 0;
input int InpExternalSyncSeconds = 60;
bool CanRunExternalSync()
{
datetime now = TimeCurrent();
if(g_last_external_sync > 0 && (now - g_last_external_sync) < InpExternalSyncSeconds)
{
PrintFormat("[EXTERNAL_SYNC_SKIP] reason=throttle wait_sec=%d",
InpExternalSyncSeconds - (int)(now - g_last_external_sync));
return false;
}
g_last_external_sync = now;
return true;
}
void OnTimer()
{
if(!CanRunExternalSync())
return;
RunExternalSync();
}外部連携は、失敗しても売買ロジックを直接止めない設計にすることが多くあります。ただし、外部シートによる売買停止など、取引制御に関係する場合は、影響範囲を明確にしてください。
WebRequestをOnTimerで扱う時の注意点
WebRequestを使う場合は、URL許可、timeout、HTTPステータス、戻り値、レスポンス内容、失敗時の扱いを分けて確認します。
WebRequestが失敗した時に、EAの注文処理まで止めるのか、外部連携だけ停止するのか、次回OnTimerで再試行するのかを仕様として決めてください。
| 確認項目 | 内容 | ログ例 |
|---|---|---|
| URL許可 | MT5のオプションでWebRequest許可URLに入っているか | WEBREQUEST_URL_CHECK |
| timeout | 通信待ち時間を長くしすぎていないか | WEBREQUEST_TIMEOUT |
| HTTPステータス | 200、400、403、500などを確認する | WEBREQUEST_STATUS |
| レスポンス | JSON、CSV、テキストなどを解析できるか | WEBREQUEST_PARSE |
| 再試行 | 失敗時にすぐ連続送信しないか | WEBREQUEST_RETRY_SKIP |
| 売買への影響 | 外部連携失敗時にentryを止めるかどうか | EXTERNAL_CONTROL_STATE |
外部連携失敗をすべて注文失敗として扱うと原因が分かりにくくなります。通信失敗、解析失敗、外部制御による停止、EA内部のentry gateは分けてログ化してください。
Discord通知をOnTimerで送る考え方
Discord通知は、状態変化やイベント発生時に送ることが多い処理です。
ただし、同じ状態を毎tick送ると通知が多くなりすぎます。OnTimer側で送信間隔や重複通知を制御すると、運用しやすくなります。
datetime g_last_notify_time = 0;
string g_last_notify_key = "";
bool CanNotify(const string notify_key, const int min_interval_sec)
{
datetime now = TimeCurrent();
if(g_last_notify_key == notify_key && (now - g_last_notify_time) < min_interval_sec)
{
PrintFormat("[NOTIFY_SKIP] key=%s reason=duplicate_interval", notify_key);
return false;
}
g_last_notify_key = notify_key;
g_last_notify_time = now;
return true;
}
void SendTimerNotification()
{
string key = "runtime_alive";
if(!CanNotify(key, 300))
return;
Print("[NOTIFY_SEND] key=runtime_alive");
}通知処理では、通知対象、送信間隔、失敗時の再送、Webhook URLの管理、ログの出し方を分けて設計してください。
Google Sheets連携をOnTimerで扱う考え方
Google Sheets連携では、EAの状態、ポジション数、外部制御、稼働状態、検証メモなどを一定間隔で読み書きすることがあります。
このような処理は、tickごとではなく、OnTimerで間隔を決めて実行する方が扱いやすくなります。
| 処理 | OnTimerで確認すること | ログ例 |
|---|---|---|
| 外部制御取得 | 停止フラグ、BUY/SELL許可、稼働時間など | SHEET_FETCH_CONTROL |
| 状態送信 | EA稼働状態、ポジション数、最終更新時刻 | SHEET_WRITE_STATUS |
| エラー記録 | 通信失敗、解析失敗、認証失敗 | SHEET_ERROR |
| 送信間隔制御 | 短時間で連続送信しない | SHEET_THROTTLE |
| 取引への影響 | 外部制御がentry gateに影響するか | EXTERNAL_GATE_STATE |
外部シートを使ってEAの動作制御を行う場合は、OnTimerで取得した制御値をruntime状態へ反映し、OnTick側ではその状態を参照する設計にすると責務を分けやすくなります。
状態スナップショットをOnTimerで出す
OnTimerは、EAの稼働状態を一定間隔でログ化する用途にも向いています。
毎tickログを出すと確認しづらくなるため、状態が変わった時、または一定間隔ごとに要約ログを出す設計が有効です。
void PrintRuntimeSnapshot()
{
int positions = PositionsTotal();
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double margin = AccountInfoDouble(ACCOUNT_MARGIN);
double margin_free = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
PrintFormat("[RUNTIME_SNAPSHOT] symbol=%s positions=%d equity=%.2f margin=%.2f margin_free=%.2f",
_Symbol,
positions,
equity,
margin,
margin_free);
}
void OnTimer()
{
PrintRuntimeSnapshot();
}実際のEAでは、毎回すべての情報を出すのではなく、ログプロファイルやdebug設定に応じて出力範囲を切り替えると運用しやすくなります。
バックテストでOnTimerを使う時の注意点
バックテストでOnTimerを使う場合、Timerイベントの回数が多くなるとテスト時間が伸びることがあります。
特に、1秒タイマーやミリ秒タイマーで詳細ログ、WebRequest相当の処理、CSV出力、状態スナップショットを多く出すと、検証が重くなります。
| 注意点 | 問題 | 対策 |
|---|---|---|
| 短いTimer周期 | OnTimer実行回数が増える | BT用は周期を長めにする |
| 詳細ログ過多 | Expertsログが膨らむ | NG時だけ詳細、通常時は要約にする |
| CSV出力過多 | ファイルI/Oが増える | イベント時だけ記録する |
| 外部連携相当処理 | 検証速度や再現性に影響する | BT時は外部連携をOFFまたはモック化する |
| ミリ秒タイマー | 実行回数が非常に多くなる | 必要な場合だけ使う |
Strategy Testerでの検証では、OnTimer用のログ設定、外部連携ON/OFF、Timer周期を別inputにしておくと、速度と確認しやすさを調整できます。
OnTimerログの設計
OnTimerのログは、定期処理の開始、スキップ、成功、失敗、次回実行予定を分けると確認しやすくなります。
| ログ名 | 意味 | 確認内容 |
|---|---|---|
| TIMER_SET_OK | Timer設定成功 | interval、mode、EA version |
| TIMER_SET_NG | Timer設定失敗 | interval、GetLastError |
| TIMER_TICK | OnTimer開始 | 現在時刻、処理対象 |
| TIMER_SKIP | 処理見送り | throttle、外部連携OFF、BTモードなど |
| EXTERNAL_SYNC_OK | 外部同期成功 | HTTP status、更新件数、反映状態 |
| EXTERNAL_SYNC_NG | 外部同期失敗 | last_error、HTTP status、理由 |
| TIMER_SUMMARY | 定期要約ログ | positions、state、last_sync、last_notify |
| TIMER_KILL | Timer停止 | deinit reason |
OnTimerログは、毎回同じ量を出すのではなく、通常時は要約、異常時は詳細に切り替えると確認しやすくなります。
ログ出力例
[TIMER_SET_OK] seconds=30 mode=external_sync
[TIMER_TICK] server_time=2026.05.26 10:15:00 task=external_sync
[EXTERNAL_SYNC_SKIP] reason=throttle wait_sec=18
[SHEET_FETCH_CONTROL] status=200 result=ok entry_control=ALLOW
[NOTIFY_SKIP] key=runtime_alive reason=duplicate_interval
[RUNTIME_SNAPSHOT] symbol=GOLD positions=2 equity=10000.50 margin=250.00 margin_free=9750.50
[TIMER_SUMMARY] last_sync=2026.05.26 10:15:00 last_notify=2026.05.26 10:10:00
[TIMER_KILL] reason=1
ログ例の時刻、数値、HTTP status、状態名は確認用です。実際のEAでは、外部連携先やログプロファイルに合わせて調整してください。
よくある失敗パターン
| 失敗パターン | 問題点 | 確認方法 |
|---|---|---|
| EventSetTimerを呼んでいない | OnTimerが実行されない | OnInitでTIMER_SET_OKが出ているか確認する |
| EventKillTimerを忘れる | 終了処理の見通しが悪くなる | OnDeinitでTIMER_KILLを出す |
| Timer周期が短すぎる | ログ過多やBT低速化につながる | BT用・実運用用で周期を分ける |
| WebRequestを毎tick実行する | 通信回数が多くなり、処理が重くなる | OnTimerへ分けてthrottleする |
| 外部連携失敗で売買処理まで止める | 影響範囲が不明確になる | 外部連携失敗とentry gateを分ける |
| 通知を重複送信する | Discordやメール通知が多すぎる | notify keyと最小間隔で制御する |
| BTで外部連携ログを出しすぎる | 検証ログが膨らみ、速度が落ちる | BT時は簡易ログまたはOFFにする |
OnTimer処理とあわせて確認したいイベント・時刻管理
OnTimerで外部連携、通知、定期監視を分ける場合は、サーバー時間の扱い、OnTradeTransactionとの責務分離、長時間稼働時の処理負荷もあわせて確認します。
| 確認したい内容 | 関連ページ | 確認ポイント |
|---|---|---|
| サーバー時間の確認 | MQL5 TimeCurrentの使い方 | TimeCurrent、OnTick、OnTimer、サーバー時間、EA稼働時間判定の違いを確認します。 |
| 約定イベントの追跡 | MQL5 OnTradeTransactionで約定を追跡する方法 | 約定、決済、履歴追加、コピーEA同期、重複記録防止をイベント単位で整理します。 |
| 長時間稼働EAの実務 | MQL5長時間稼働EA実務ノート | OnTick負荷、OnTimer分離、ログ過多、Object残存、フリーズ対策を確認します。 |
関連ページ
OnTimerは、イベント処理、WebRequest、長時間稼働、ログファースト開発、CSV出力、外部連携の確認と合わせて整理すると理解しやすくなります。
| 関連ページ | 確認できること |
|---|---|
| MQL5長時間稼働・安定化完全ガイド | メモリ、handle、ログ、Object管理、長時間稼働の確認 |
| MQL5デバッグ・ログファースト開発完全ガイド | Expertsログ、再現条件、ログ設計の確認 |
| MQL5ファイル操作関数辞典 | FileOpen、FileWrite、CSV出力、Commonフォルダの確認 |
| EAに外部シート連携を追加したい時に整理すること | Google Sheets、CSV、WebRequest連携の依頼前確認 |
| EAに通知機能を追加したい時に整理すること | Discord、メール、通知ログ、送信条件の整理 |
イベント処理と外部連携全体を確認する場合
OnTimerは、一定間隔で処理を行うためのイベント関数です。外部連携、通知、状態監視、CSV出力、ログ抑制などをOnTickから分けたい場合に使います。イベント処理全体やWebRequestを使った外部連携の設計を確認したい場合は、関連する親記事もあわせて確認してください。
| 確認したいこと | 確認するページ | 主な確認内容 |
|---|---|---|
| MQL5イベント処理の全体を確認したい | MQL5イベント処理完全ガイド | OnInit、OnTick、OnTimer、OnTradeTransaction、OnChartEventの使い分け |
| WebRequestや外部API連携を確認したい | MQL5 WebRequest・JSON・外部API実装完全ガイド | WebRequest、JSON、Discord通知、Google Sheets連携、外部API処理 |
OnTimerで外部連携を扱う場合は、Timer周期、WebRequestのtimeout、通知間隔、再送制御、失敗時の扱い、売買処理への影響を分けて確認してください。
開発依頼前に整理したい情報
OnTimerを使った外部連携、通知、CSV出力、状態監視を相談する場合は、次の情報を整理してください。
| 整理する情報 | 確認内容 |
|---|---|
| 対象EA | 新規EA、既存EA改修、通知ツール、外部連携ツールのどれか |
| Timer周期 | 何秒ごとに処理したいか、BT用と実運用用を分けるか |
| 処理内容 | 通知、外部制御取得、Google Sheets書き込み、CSV出力、状態監視など |
| 外部連携先 | Discord、Google Sheets、GAS、外部API、CSVファイルなど |
| 売買への影響 | 外部連携失敗時にentryを止めるか、通知だけ止めるか |
| ログ方針 | 通常時は要約、失敗時は詳細、BT時は軽量化など |
| 再送制御 | 通知やWebRequestを連続送信しない条件 |
| バックテスト対応 | 外部連携をOFFにするか、モック化するか、ログだけ出すか |
| 機密情報 | Webhook URL、GAS URL、APIキー、認証情報を公開ログに出さない設計 |
外部連携や通知の不具合を相談する場合は、Timer設定ログ、WebRequest結果、HTTP status、送信間隔、通知スキップ理由、Expertsログ、Journalログを合わせて確認してください。
まとめ
OnTimerは、MQL5 EAで一定間隔の処理を行うためのイベント関数です。
売買判定や注文処理はOnTickやexecution層に残し、外部連携、通知、CSV出力、状態監視、ログ抑制はOnTimerへ分けると、EAの責務を整理しやすくなります。
EventSetTimerは通常OnInitで設定し、EventKillTimerはOnDeinitで呼びます。Timer周期は短くしすぎず、バックテスト時の負荷やログ量も考慮してください。
WebRequest、Discord通知、Google Sheets連携をOnTimerで扱う場合は、送信間隔、失敗時の扱い、再送制御、売買への影響、機密情報の扱いを分けて設計することが重要です。
