本ページはプロモーションが含まれています

ホーム › EAプログラミング

EAプログラミング

MQL4のOnTick・OnTimer等イベント関数の使い方

↻

トム

トム

現役エンジニア(本業はJavaバックエンド)。以前はMT4のEAを自作してFX自動売買をしていました(現在は引退)。今はポイ活を「時給」で検証・攻略しています。

MQL4のOnTick・OnInit・OnDeinitなどのイベント関数は、決まったタイミングでMT4から自動的に呼ばれ、EAやインジケーターの動きを決めます。

結論として、EAではOnInit(読み込み時)→OnTick(ティック受信ごと)→OnDeinit(終了時)の順に呼ばれ、売買ロジックはOnTickに書きます。時間足・通貨ペアやパラメータを変えたときは、OnDeinitのあとOnInitがもう一度呼ばれます。スクリプトはOnStart、インジケーターはOnCalculateが中心で、定期処理はOnTimerで行います。

各関数の書き方をコード例で示し、旧形式(init/start/deinit)との対応、つまずきやすい点、MQL5(MT5)での違いもまとめました。

イベント関数とは?

イベント関数とは、特定の事象や状態変化が発生した際にMT4から自動的に呼び出される関数です。自分で呼び出すのではなく、決まった名前で定義しておくとMT4が適切なタイミングで実行してくれます。

EAでイベント関数が呼ばれる流れ

1. OnInit
チャートにロードされたとき(時間足・パラメータの変更後にも再び)
→
2. OnTick
新しい価格(ティック)を受信するたび
→
3. OnDeinit
チャートから削除・ターミナルを閉じるとき(時間足・パラメータの変更前にも)
OnStartはスクリプト専用で、実行時に1回だけ呼ばれる。EAではOnInit → OnTick(繰り返し)→ OnDeinitの順。

MQL4のイベント関数にはどんな種類がある?一覧表

MQL4の主なイベント関数は8つで、プログラムの種類(EA・インジケーター・スクリプト)ごとに使える関数が決まっています。

関数呼ばれるタイミング戻り値使えるプログラム
OnInitロード直後。通貨ペア・時間足・パラメータの変更や再コンパイルのあとにも再び呼ばれるint(INIT_SUCCEEDED等)EA・インジケーター
OnDeinit削除・終了時のほか、通貨ペア・時間足・パラメータの変更前にも呼ばれるなしEA・インジケーター
OnTickティック受信ごとなしEA
OnTimerEventSetTimerで指定した間隔なしEA・インジケーター
OnTesterバックテスト完了時double(評価値)EA
OnChartEventクリック・キー操作などチャートのイベントなしEA・インジケーター
OnCalculateティック受信ごと(インジケーター用)int(計算済みバー数)インジケーター
OnStartスクリプト実行時に1回なしスクリプト

主なイベント関数

ここでは8つのイベント関数それぞれについて、呼ばれるタイミング・書くべき処理・最小限のコード例を順に説明します。EAを作るなら、まずOnInit・OnTick・OnDeinitの3つを押さえれば動かせます。

OnStart

スクリプトの開始時に1回だけ呼び出される関数です。「全ポジションを一括決済する」のような、1回きりの処理を書きます。EAでは使いません。

void OnStart()
  {
// ここに処理を記載
   
  }

OnInit

EAやカスタムインジケーターがチャートにロードされる際に呼び出されます。通貨ペア・時間足や入力パラメータを変えたとき、再コンパイルしたとき(EAは口座を切り替えたときも)にも、OnDeinitのあとで再び呼ばれます。パラメータの検証、タイマーの設定、グローバル変数の初期化など、起動時の処理を書きます。

int OnInit()
  {
// ここに処理を記載
   
// 処理結果
   return(INIT_SUCCEEDED);
  }

戻り値でINIT_FAILEDを返すと初期化失敗として扱われ、EAは動作を始めずに停止します。パラメータが不正なときにEAを止める用途に使えます。ただしMQL4では、ソースに#property strictを書いてコンパイルしたときだけ戻り値が評価されます。

OnDeinit

EAやインジケーターがチャートから削除されるときやターミナルを閉じるときのほか、通貨ペア・時間足・パラメータを変えたときや再コンパイルしたときにも(再初期化の前に)実行されます。どの理由で呼ばれたかは引数reasonで分かります(下の表)。オブジェクトの削除やタイマーの停止など、後片付けを書きます。

void OnDeinit(const int reason)
  {
// ここに処理を記載
   
  }
reasonの値定数意味
0REASON_PROGRAMExpertRemove()で自分で終了
1REASON_REMOVEチャートから削除された
2REASON_RECOMPILE再コンパイルされた
3REASON_CHARTCHANGE通貨ペアまたは時間足が変更された
4REASON_CHARTCLOSEチャートが閉じられた
5REASON_PARAMETERSパラメータが変更された
6REASON_ACCOUNT別の口座に接続した
9REASON_CLOSEターミナルが閉じられた

OnTick

新しい価格データ(ティック)が受信されるたびに呼び出されます。EAの売買ロジックは基本的にこの中に書きます。

void OnTick()
  {
// ここに処理を記載
   
  }

OnTickはティックを受信するたびに呼ばれ、相場が活発な時間帯には1秒間に複数回実行されます。「足が確定したときだけ判定したい」場合は、新しい足ができたかを自分で検出する必要があります(後述)。

OnTimer

EventSetTimer関数で指定した秒数ごとに呼ばれます。「1分ごとにポジションを確認する」「価格が動かない週末でも処理したい」といった定期処理に使います。

int OnInit()
  {
   EventSetTimer(60);
   
   return(INIT_SUCCEEDED);
  }
void OnTimer()
  {
// ここに処理を記載
   
  }

OnInitでEventSetTimerを呼んだら、OnDeinitで必ずEventKillTimerを呼んでタイマーを止めます。MQL4公式ドキュメントでも、EventSetTimerはOnInitで1回、EventKillTimerはOnDeinitで1回呼ぶことが推奨されています。

OnTester

ストラテジーテスターでのテストが完了したときに呼ばれ、戻り値が最適化の評価値(カスタム基準)として使われます。「プロフィットファクター×取引回数」のような独自の評価指標で最適化したいときに使います。

あわせて読むMT4バックテストのやり方【初心者向け】EAの設定と結果の見方MT4でEAをバックテストするやり方を画像付きで解説。ヒストリカルデータの準備、ストラテジーテスターのモデル・スプレッド設定、モデリング品質90%の意味、PF・最大ドローダウンなど結果の見方までわかります。
double OnTester()
  {
   double result = 0.0;
// ここで評価値を計算してresultに入れる
   
   return(result);
  }

OnChartEvent

チャート上のマウスクリックやキーボード操作、オブジェクトの移動などのイベントを処理します(オブジェクトの作成・削除やマウス移動のイベントは、チャートのプロパティCHART_EVENT_OBJECT_CREATE等をtrueにしたときだけ届きます)。チャート上にボタンを置いて手動操作するEAで使います。

void OnChartEvent(
 const int         id, // イベントID
 const long&   lparam, // long型イベント
 const double& dparam, // double型イベント
 const string& sparam) // string型イベント
  {
// ここに処理を記載
   
  }

OnCalculate

カスタムインジケーターの値を計算するための関数です。ティックごとに呼ばれ、prev_calculatedを使うと未計算のバーだけを計算できます。

int OnCalculate(const int      rates_total,     // 入力された時系列のバー数
                const int      prev_calculated, // 計算済み(前回呼び出し時)のバー数
                const datetime &time[],         // 時間
                const double   &open[],         // 始値
                const double   &high[],         // 高値
                const double   &low[],          // 安値
                const double   &close[],        // 終値
                const long     &tick_volume[],  // Tick出来高
                const long     &volume[],       // Real出来高
                const int      &spread[])       // スプレッド
  {
// ここに処理を記載
   
// 戻り値は次回呼び出し時のprev_calculatedになる
   return(rates_total);
  }

旧形式(init / start / deinit)との対応

ビルド600より前のMQL4では、関数名がinit・start・deinitでした。古いEAのソースコードを読むときはこの対応表で読み替えてください。

旧形式新形式違い
int init()int OnInit()戻り値の意味が明確になった(INIT_SUCCEEDED等)
int start()void OnTick()戻り値がなくなった。スクリプトではOnStart、インジケーターではOnCalculate
int deinit()void OnDeinit(const int reason)終了理由reasonを受け取れるようになった

旧形式のままでもコンパイルはできますが、新規に書くなら新形式を使います。

あわせて読むMT4(MQL4)EAソースコード公開サイト11選と動かし方MT4(MQL4)のEAソースコードを無料で公開しているサイト11選。付属のMACD Sample、日本語の学習サイト、MQL5コードベース、GitHubをレベル別に紹介し、コンパイルして動かす手順も解説します。

MQL4のイベント関数の応用例

応用例のポイントは、初期化はOnInit、後片付けはOnDeinit、売買判定はOnTick、時間ベースの処理はOnTimer、手動操作はOnChartEventと役割を分けて書くことです。以下では、それぞれの実践的な使い方をコード付きで紹介します。

EAのライフサイクルとイベント関数の役割

OnInit
チャートにロードされた直後(時間足・パラメータの変更後にも再び)。パラメータ検証・EventSetTimerなど
▼
◆戻り値をチェック
INIT_FAILED → Deinitイベントが発生しEAは停止(reason=REASON_INITFAILED)
▼INIT_SUCCEEDED
稼働中:イベントごとに呼ばれる
OnTick=ティック受信ごと(ティックがないと呼ばれない)
OnTimer=EventSetTimerで指定した間隔(ストラテジーテスターでは処理されない)
OnChartEvent=クリック・キー操作などチャートのイベント
▼
OnDeinit
削除・ターミナル終了時(時間足・パラメータの変更前にも)。EventKillTimerなどの後片付け。実行は2.5秒に制限

売買判定はOnTick、時間ベースの処理はOnTimer、手動操作はOnChartEvent、後片付けはOnDeinitと役割を分けて書く。

OnInit()の活用例

OnInitは初期パラメータの設定やリソースの読み込みに使います。外部のCSVファイルからパラメータを読み込んだり、初期の取引戦略を設定したりします。

int OnInit()
{
   // パラメータの読み込みや初期設定
   return(INIT_SUCCEEDED);
}

OnDeinit()の活用例

OnDeinitではオブジェクトの解放やログの保存など、終了に関連するタスクを実行します。

void OnDeinit(const int reason)
{
   // オブジェクトの解放やログの保存
}

OnTick()の活用例

OnTickには取引の主要な処理を書きます。

void OnTick()
{
   double currentPrice = Close[0];
   // 価格が特定の条件を満たす場合に取引を実行
   if(currentPrice > SOME_THRESHOLD)
   {
      // ロングポジションをオープン
   }
}

足の確定ごとに1回だけ判定したい場合は、次のように新しい足の開始を検出します。EA作成で最もよく使うパターンです。

datetime lastBarTime = 0;

void OnTick()
{
   // 新しい足ができたときだけ処理する
   if(Time[0] == lastBarTime) return;
   lastBarTime = Time[0];

   // ここに足の確定ごとの売買判定を書く(Close[1]など確定足を使う)
}

OnTimer()の活用例

OnTimerは特定の時間間隔で動作します。1時間ごとに何らかのアクションをトリガーしたい場合などに役立ちます。

void OnTimer()
{
   // 1時間ごとに特定のアクションを実行
}

OnChartEvent()の活用例

ユーザーの操作やチャート上のイベントをトリガーとして処理を行いたい場合はOnChartEventを使います。

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   // ユーザーのアクションに応じた処理
}

イベント関数でつまずきやすいポイントは?

イベント関数のトラブルの多くは、関数が「いつ・何回」呼ばれるかの誤解から起きます。代表的な症状と対処を表にまとめました。

症状原因対処
1本の足で何回もエントリーするOnTickがティックごとに呼ばれている新しい足の検出(上記コード)を入れる
週末や相場が止まると処理が動かないOnTickはティックがないと呼ばれないOnTimerを使う
OnTimerが一度も呼ばれないEventSetTimerを呼んでいない、またはOnTimer関数を定義していないOnInitでEventSetTimerを呼び、OnTimerを定義する
バックテストでOnTimerが動かないストラテジーテスターではTimerイベントが処理されないOnTick内で時刻を判定する方式にする
OnInitで失敗してもEAが動く戻り値を返していない、または#property strictなしでコンパイルしている#property strictを書き、不正時はINIT_FAILEDを返す

MQL4の基本から自作EAを作る手順は以下の記事で解説しています。

併せて読むFX EAの自作・作り方|MQL4で始める初心者向けEA開発入門FXのEAはMT4付属のMetaEditorとMQL4で無料で自作できます。必要なもの・難しさ、ひな形作成からコンパイル・バックテストまでの手順と全コード、未経験者向けのノーコードツール・ChatGPT・作成代行も解説します。

MQL5(MT5)のOnTick・OnTimerはMQL4と何が違う?

OnTick・OnTimer・OnInit・OnDeinit・OnCalculate・OnChartEvent・OnTester・OnStartは、MQL5でも同じ名前・同じ役割です。OnTickがEA専用でティックごとに呼ばれる点、OnInitでEventSetTimerを呼びOnDeinitでEventKillTimerを呼ぶ流れも変わりません。違いは主に、ストラテジーテスターでのOnTimerの扱い、MQL5にしかないイベント関数、価格・時刻の取り方の3点です。

項目MQL4(MT4)MQL5(MT5)
OnTickティック受信ごと(EA専用)同じ(EA専用)。処理中に届いたティックはキューに追加されない
OnTimer・EventSetTimerEventSetTimer(秒)/EventSetMillisecondTimer(ミリ秒)で設定同じ。1つのプログラムにつきタイマーは1つ。実運用では10〜16ミリ秒より短い間隔では呼ばれない
テスターでのOnTimer呼ばれない呼ばれる(タイマー間隔が短いほどテスト時間が延びる)
OnInitの戻り値int型(INIT_SUCCEEDED/INIT_FAILED/INIT_PARAMETERS_INCORRECT)。void型も書けるが常に初期化成功の扱い。戻り値が評価されるのは#property strictでコンパイルしたときだけ同じ値を使う(int型が推奨)。void型は常に初期化成功の扱いで非推奨
取引・板情報のイベントなしOnTrade・OnTradeTransaction・OnBookEvent
最適化のイベントOnTesterのみOnTesterに加えてOnTesterInit・OnTesterPass・OnTesterDeinit
価格・時刻の取得定義済み配列Time[0]・Close[0]などが使える定義済み配列がないため、iTime・iClose・CopyRates・SymbolInfoTickなどで取得する

表のMQL5側は、MQL5公式リファレンス(イベント処理・OnTimer・OnInit・取引ストラテジーのテスト)の記載に基づいています。MQL5ではテスターでもOnTimerが呼ばれるため、MQL4で必要だった「OnTick内で時刻を判定する」回避策は必須ではありません。

MQL5だけにあるイベント関数

MQL5には、取引サーバーからの通知や最適化の進行を受け取るためのイベント関数が追加されています。

  • OnTrade:注文・ポジション・取引履歴が変わったときに呼ばれる(EA専用)
  • OnTradeTransaction:取引リクエストの実行結果を1件ずつ受け取る。引数のtrans・request・resultで約定や注文変更の中身を確認できる(EA専用)
  • OnBookEvent:板情報が変わったときに呼ばれる。事前にMarketBookAddで銘柄の購読を始めておく必要がある
  • OnTesterInit・OnTesterPass・OnTesterDeinit:ストラテジーテスターでの最適化の開始前・各パスの結果受信時・終了後に呼ばれる

OnTradeとOnTradeTransactionの呼び出し回数は1対1に対応しません。約定ごとに処理したい場合は、OnTradeTransactionで取引の種類(trans.type)を見て分岐させます。

MQL5で新しい足を検出するOnTick

MQL5にはTime[0]のような定義済み配列がないため、MQL4の「新しい足の検出」コードはそのままでは動きません。iTime()で現在の足の開始時刻を取って比較します。iTimeはエラー時に0を返すので、0のときは処理しないようにしています。

datetime lastBarTime = 0;

void OnTick()
{
   // MQL5にはTime[]がないため、iTimeで現在の足の開始時刻を取る
   datetime barTime = iTime(_Symbol, PERIOD_CURRENT, 0);
   if(barTime == 0 || barTime == lastBarTime) return;  // 取得失敗(0)か同じ足なら何もしない
   lastBarTime = barTime;

   // ここに足の確定ごとの売買判定を書く(確定足はiClose(_Symbol, PERIOD_CURRENT, 1)など)
}

よくある質問

Q1. OnTickとOnStartの違いは何ですか?

A1. OnTickはEA専用で、新しいティックを受信するたびに呼ばれます。OnStartはスクリプト専用で、起動時に1回だけ呼ばれます。MQL4公式ドキュメントでも、StartイベントはEAやカスタムインジケーターには送られないと明記されています。

Q2. OnTickの処理中に次のティックが届いたらどうなりますか?

A2. そのティックは無視されます。MQL4では、OnTickの処理中に届いた新しいティックはイベントキューに積まれないためです。OnTickに重い処理を書くとティックを取りこぼすので、処理は軽く保ちます。

Q3. OnInitでINIT_FAILEDを返すとどうなりますか?

A3. 初期化失敗として扱われ、Deinitイベントが発生してEAは停止します。このときOnDeinitの引数reasonにはREASON_INITFAILED(値は8)が渡されます。パラメータ不正時にEAを動かさない用途に使えます。MQL4では#property strictを付けてコンパイルしたときだけ戻り値が評価されます。

Q4. OnDeinitに時間のかかる処理を書いてもよいですか?

A4. 避けるべきです。公式ドキュメントでは、OnDeinitの実行は2.5秒に制限され、時間内に終わらなければ強制終了されると定められています。ファイル保存などは短時間で終わる処理にとどめます。

Q5. OnTimerの呼び出し間隔はどう指定しますか?

A5. OnInitでEventSetTimer(秒数)を呼んで指定します。タイマーは1つのプログラムにつき1つまでです。1秒未満の間隔が必要ならEventSetMillisecondTimer()を使い、OnDeinitでEventKillTimer()を呼んで止めます。

Q6. カスタムインジケーターでOnTickは使えますか?

A6. 使えません。OnTickはEA専用のイベント関数です。インジケーターではOnCalculateがティックごとの計算を担い、定期処理にはOnTimerを使えます。

Q7. OnTickで足の確定ごとに1回だけ処理するにはどうしますか?

A7. 現在の足の開始時刻Time[0]を変数に保存し、値が変わったときだけ処理します。判定には確定済みのClose[1]などを使うと、1本の足で何度もエントリーする問題を防げます。

Q8. MQL5でもOnTickやOnTimerの書き方は同じですか?

A8. 関数名と役割は同じです。OnTickはEA専用でティックごとに呼ばれ、OnTimerはOnInitでEventSetTimer()を呼んで動かし、OnDeinitでEventKillTimer()で止めます。違うのは、MQL5ではストラテジーテスターでもOnTimerが呼ばれること、Time[0]などの定義済み配列がなくiTime()等で価格・時刻を取ること、OnTradeTransactionなどMQL5固有のイベント関数があることです。

まとめ

  • EAはOnInit(読み込み時)→ OnTick(ティックごと)→ OnDeinit(終了時)の順に呼ばれる。時間足やパラメータを変えるとOnDeinit→OnInitが再び呼ばれる
  • 売買ロジックはOnTickに書く。足の確定ごとに判定するなら新しい足の検出が必要
  • 定期処理はOnTimer、終了時の後片付けはOnDeinit、独自の最適化基準はOnTester
  • 旧形式のinit/start/deinitは新形式のOnInit/OnTick/OnDeinitに対応
  • MQL5でも主要なイベント関数は同名。テスターでOnTimerが呼ばれる点、Time[]がない点、OnTradeTransaction等の固有関数に注意
※本記事は情報提供を目的としたもので、特定のEA・金融商品の売買を推奨するものではありません。FX(外国為替証拠金取引)は元本が保証されておらず、レバレッジにより預けた証拠金を上回る損失が発生する可能性があります。記事内の成績・数値は過去の実績であり、将来の利益を保証するものではありません。投資の最終判断はご自身の責任でお願いします。

QUEST CLEAR!

最後まで読んでくれて、ありがとうございます。
つぎのクエストは、この下から選べます。

トム

この記事を書いた人トム

・現役エンジニア(本業はJavaバックエンド)
・以前はMT4のEAを自作してFX自動売買をしていました(現在は引退)
・今はポイ活を「時給」で検証・攻略しています