MQL5で一定時間ごとに処理する方法|タイマーは1つだけ

MQL5で一定時間ごとに処理を動かすには、OnInit で EventSetTimer を呼び、OnTimer に処理を書きます。単位は秒です。

ここで知っておくべき制約が2つあります。①1つのプログラムで動かせるタイマーは1つだけ ②前回の処理が終わっていないと、次のタイマーイベントはキューに入らない。どちらもMQL5公式リファレンスに明記されています。

(確認環境:MetaTrader 5 / Windows 11)

最小の構成

int OnInit()
  {
   EventSetTimer(60);          // 60秒ごと
   return(INIT_SUCCEEDED);
  }

void OnTimer()
  {
   Print("60秒経過 ", TimeToString(TimeTradeServer(), TIME_SECONDS));
  }

void OnDeinit(const int reason)
  {
   EventKillTimer();
  }

EventSetTimer の引数は秒です。1秒より細かくしたい場合は EventSetMillisecondTimer を使います。

🔴 なぜ OnTick ではだめなのか

「一定時間ごと」を OnTick の中で時刻を見て判定する書き方をよく見かけます。これは動く時と動かない時があります。

理由は単純です。OnTick は価格が更新された時にしか呼ばれません。

  • 値動きが止まっている時間帯 — 呼ばれない
  • 取引時間外 — 呼ばれない
  • 薄商いの早朝 — 間隔が空く

つまり「22時になったら閉じる」という処理を OnTick に書くと、22時に値が動かなければ実行されません。時刻で何かをする処理は OnTimer に置くのが正しい形です。

🔴 タイマーは1つしか持てない

公式リファレンスには「1つのプログラムにつき、動かせるタイマーは1つを超えない」と書かれています。

「5秒ごとの監視」と「60秒ごとの記録」を両方やりたい場合、タイマーを2つ作ることはできません。短い方の間隔でタイマーを回し、OnTimer の中で回数を数えます。

int count = 0;

void OnTimer()
  {
   count++;
   // 5秒ごとの処理
   if(count % 12 == 0)
     {
      // 60秒ごとの処理
     }
  }

🔴 処理が重いと間隔どおりに来ない

もう1つの制約です。公式リファレンスによると、Timerイベントが既にキューにある、または処理中の場合、新しいTimerイベントはキューに入りません。

つまり1秒タイマーにしても、1回の処理に3秒かかっていれば1秒ごとには来ません。取りこぼした分は後からまとめて来るわけでもありません。

対策は2つです。

  1. 間隔を処理時間より十分長くする
  2. OnTimer の中で重い処理をしない — 判定だけ行い、実処理は条件を満たした時だけにする

「タイマーを短くすれば精度が上がる」とは限らないということです。

🔴 時刻の取り方を間違えると発火しない

OnTimer の中で現在時刻を見る時、どの関数を使うかで結果が変わります。

関数 返すもの
TimeCurrent() 最後にクォートを受信した時刻
TimeTradeServer() 取引サーバーの現在時刻
TimeLocal() PCの時刻

問題になるのは1つ目です。TimeCurrent() は相場が動かないと進みません。

タイマー自体は1秒ごとに回っていても、TimeCurrent() で「22時を過ぎたか」を判定していると、22時前に最後のクォートが止まった場合、いつまでも22時になりません。

時刻で区切る処理では TimeTradeServer() を使ってください。この3つの違いはMT5の時刻がずれる理由で詳しく扱っています。

EventKillTimer は書いておく

公式リファレンスによると、プログラムが停止すればタイマーは自動で破棄されます。EventKillTimer を書き忘れても残り続けるわけではありません。

それでも OnDeinit に書いておくべき理由は、途中でタイマーを止めたり、間隔を変えたりする場合に必要になるからです。間隔を変えるには一度止めてから設定し直します。

何に使えるか

  • 指定時刻での決済 — 値動きに依存せず実行できる
  • 定期的な記録 — 一定間隔で値をファイルに書き出す(MQL5でCSVを出力する方法)
  • 保有時間の監視 — 一定時間を超えたポジションを探す

1つ目が実用上いちばん効きます。エントリーは自分で判断し、閉じる方だけを時間で機械的に行う使い方です。考え方はMT5で決済だけを自動化する方法に、実際に閉じるコードはMQL5でポジションを決済する方法にまとめています。

まとめ

  1. OnInit で EventSetTimer(秒)、処理は OnTimer
  2. 🔴 時刻で動かす処理を OnTick に書かない。値が動かないと呼ばれない
  3. 🔴 タイマーは1プログラムに1つだけ。複数間隔は回数で分ける
  4. 🔴 処理中は次のイベントがキューに入らない。短くすれば精度が上がるわけではない
  5. 🔴 判定に TimeCurrent() を使わない。相場が止まると時刻も止まる

ストラテジーテスターの中では、OnTimer はモデルに関係なく呼ばれます。テスターでの時刻の進み方とモデルの違いはMT5ストラテジーテスターのモデルの選び方にあります。

本記事はMQL5の仕様と実装方法を説明したものであり、特定の売買を推奨するものではありません。仕様はビルドによって変わる可能性があります。投資判断はご自身の責任で行ってください。