MQL4 イベントハンドラリファレンス|OnInit・OnTick・OnTimer・OnChartEvent完全ガイド

MQL4のイベントハンドラを体系的にまとめました。旧形式のinit()/deinit()/start()とビルド600+で導入されたOnInit()/OnDeinit()/OnTick()の違い、OnTimer()による定期処理、OnChartEvent()によるチャートイベント処理、EA・インジケーター・スクリプトの実行モデルの違い、新バー検出パターン、UninitializeReasonまで、MT4プログラム開発に必要なイベント処理のすべてをコード付きで解説します。

目次

MQL4とMQL5のイベントハンドラの違い

機能MQL4(ビルド600+)MQL5
初期化OnInit() / init()OnInit()
終了処理OnDeinit() / deinit()OnDeinit()
ティック処理OnTick() / start()OnTick()
タイマーOnTimer()OnTimer()
チャートイベントOnChartEvent()OnChartEvent()
計算イベントOnCalculate()(インジケーター)OnCalculate()
取引イベントなしOnTrade() / OnTradeTransaction()
テスターイベントOnTester()OnTester() / OnTesterInit() / OnTesterDeinit()

MQL4ビルド600以降は、MQL5と同じイベントハンドラ名(OnInit/OnDeinit/OnTick)が使えます。旧形式のinit/deinit/startも互換性のために動作しますが、新規開発ではOnXxx形式を推奨します。

旧形式 vs 新形式

ビルド600(2014年)以降のMT4では、MQL5互換のOnInit() / OnDeinit() / OnTick()形式が使えます。旧形式のinit/deinit/startも動作しますが、新形式ではOnDeinitのreason引数OnInitの定数戻り値など、より細かい制御が可能です。新規開発では必ず新形式を使いましょう。

ビルド600(2014年)以降のMT4では、MQL5互換のOnInit() / OnDeinit() / OnTick()形式が使えます。旧形式のinit/deinit/startも動作しますが、新形式ではOnDeinitのreason引数OnInitの定数戻り値など、より細かい制御が可能です。新規開発では必ず新形式を使いましょう。

// 旧形式 — 戻り値の型が異なる
int init()
  {
   // 初期化処理
   Print("EA初期化(旧形式)");
   return(0);  // 0=成功
  }

int deinit()
  {
   // 終了処理
   Print("EA終了(旧形式)");
   return(0);
  }

int start()
  {
   // ティックごとに実行
   Print("ティック受信(旧形式)");
   return(0);
  }
// 新形式 — MQL5と同じ書式
int OnInit()
  {
   // 初期化処理
   Print("EA初期化");
   return(INIT_SUCCEEDED);  // 定数を使用
  }

void OnDeinit(const int reason)
  {
   // 終了処理(理由コードを受け取れる)
   Print("EA終了: reason=", reason);
  }

void OnTick()
  {
   // ティックごとに実行
   // 戻り値なし(void)
  }

OnInit — 初期化

EAがチャートにアタッチされた時、時間軸の変更時、再コンパイル時に1回だけ実行されます。

// グローバル変数
int    PipMultiplier;
double PipSize;
string EAName = "MyEA v1.0";

int OnInit()
  {
   // 口座チェック
   if(!IsTradeAllowed())
     {
      Alert(EAName, ": 自動売買が許可されていません");
      return(INIT_FAILED);
     }

   // 通貨ペアチェック
   if(Symbol() != "USDJPY" && Symbol() != "GBPJPY")
     {
      Alert(EAName, ": 対応通貨ペアではありません");
      return(INIT_PARAMETERS_INCORRECT);
     }

   // 5桁ブローカー判定
   if(Digits == 3 || Digits == 5)
     {
      PipMultiplier = 10;
      PipSize = Point * 10;
     }
   else
     {
      PipMultiplier = 1;
      PipSize = Point;
     }

   // タイマー開始(1秒間隔)
   EventSetTimer(1);

   // チャートコメント
   Comment(EAName, " - 稼働中");

   Print(EAName, " 初期化完了");
   return(INIT_SUCCEEDED);
  }

OnInitの戻り値

定数説明
INIT_SUCCEEDED0初期化成功
INIT_FAILED1初期化失敗(EA停止)
INIT_PARAMETERS_INCORRECTパラメータエラー
INIT_AGENT_NOT_SUITABLEテスターエージェント不適合

OnDeinit — 終了処理

void OnDeinit(const int reason)
  {
   // タイマー停止
   EventKillTimer();

   // チャート上のオブジェクトを削除
   ObjectsDeleteAll(0, "MyEA_");

   // チャートコメントをクリア
   Comment("");

   // 終了理由をログ出力
   string reasonText;
   switch(reason)
     {
      case REASON_PROGRAM:     reasonText = "プログラムから終了"; break;
      case REASON_REMOVE:      reasonText = "チャートから削除"; break;
      case REASON_RECOMPILE:   reasonText = "再コンパイル"; break;
      case REASON_CHARTCHANGE: reasonText = "通貨ペアまたは時間軸変更"; break;
      case REASON_CHARTCLOSE:  reasonText = "チャートを閉じた"; break;
      case REASON_PARAMETERS:  reasonText = "パラメータ変更"; break;
      case REASON_ACCOUNT:     reasonText = "口座変更"; break;
      case REASON_TEMPLATE:    reasonText = "テンプレート適用"; break;
      case REASON_INITFAILED:  reasonText = "OnInit失敗"; break;
      case REASON_CLOSE:       reasonText = "ターミナル終了"; break;
      default:                 reasonText = "不明(" + IntegerToString(reason) + ")";
     }

   Print(EAName, " 終了: ", reasonText);
  }

UninitializeReason定数

定数説明
REASON_PROGRAM0ExpertRemove()で終了
REASON_REMOVE1チャートから手動削除
REASON_RECOMPILE2プログラムを再コンパイル
REASON_CHARTCHANGE3通貨ペアまたは時間軸を変更
REASON_CHARTCLOSE4チャートを閉じた
REASON_PARAMETERS5入力パラメータを変更
REASON_ACCOUNT6別の口座に切り替え
REASON_TEMPLATE7テンプレートを適用
REASON_INITFAILED8OnInit()が失敗
REASON_CLOSE9ターミナルを閉じた

OnTick — ティック処理

void OnTick()
  {
   // 新バー検出(ティックごとの重複処理を防ぐ)
   static datetime lastBar = 0;
   if(Time[0] == lastBar)
      return;  // 同じバー内では何もしない
   lastBar = Time[0];

   // ここから新バーの処理
   // 1. ポジションチェック
   int posCount = CountMyPositions();

   // 2. 決済判定
   CheckExitConditions();

   // 3. エントリー判定
   if(posCount < MaxPositions)
      CheckEntrySignal();

   // 4. トレーリングストップ
   UpdateTrailingStop();
  }
OnTick内でやってはいけないこと
  • Sleep()の使用: ティック処理がブロックされ、後続のティックが失われる
  • 長時間のループ処理: 他のEAのティック処理にも影響する(MT4はシングルスレッド)
  • 毎ティック同じ計算を繰り返す: 新バー検出で制御し、不要な計算を省く
  • Alert()の多用: ダイアログが表示されるたびに処理が停止する
OnTick内でやってはいけないこと
  • Sleep()の使用: ティック処理がブロックされ、後続のティックが失われる
  • 長時間のループ処理: 他のEAのティック処理にも影響する(MT4はシングルスレッド)
  • 毎ティック同じ計算を繰り返す: 新バー検出で制御し、不要な計算を省く
  • Alert()の多用: ダイアログが表示されるたびに処理が停止する

OnTimer — タイマーイベント

int OnInit()
  {
   // 60秒間隔でタイマーイベントを発生
   EventSetTimer(60);
   return(INIT_SUCCEEDED);
  }

void OnTimer()
  {
   // 定期的な処理
   // - チャートコメントの更新
   // - 損益の定期集計
   // - 外部データの取得

   double equity = AccountEquity();
   double balance = AccountBalance();
   double drawdown = (balance - equity) / balance * 100;

   string info = "";
   info += "残高: " + DoubleToStr(balance, 0) + "\n";
   info += "有効証拠金: " + DoubleToStr(equity, 0) + "\n";
   info += "DD: " + DoubleToStr(drawdown, 1) + "%\n";
   info += "更新: " + TimeToStr(TimeCurrent(), TIME_MINUTES);

   Comment(info);
  }

void OnDeinit(const int reason)
  {
   EventKillTimer();  // タイマー停止を忘れずに
   Comment("");
  }

OnChartEvent — チャートイベント

void OnChartEvent(
   const int     id,       // イベントID
   const long    &lparam,  // long型パラメータ
   const double  &dparam,  // double型パラメータ
   const string  &sparam   // string型パラメータ
);

主要なイベントID

定数説明lparamdparamsparam
CHARTEVENT_KEYDOWNキー押下キーコード
CHARTEVENT_MOUSE_MOVEマウス移動X座標Y座標マウスフラグ
CHARTEVENT_OBJECT_CLICKオブジェクトクリックX座標Y座標オブジェクト名
CHARTEVENT_OBJECT_CREATEオブジェクト作成オブジェクト名
CHARTEVENT_OBJECT_DELETEオブジェクト削除オブジェクト名
CHARTEVENT_CHART_CHANGEチャートサイズ変更
CHARTEVENT_CUSTOMカスタムイベント任意任意任意
int OnInit()
  {
   // ボタンオブジェクトを作成
   ObjectCreate(0, "BuyButton", OBJ_BUTTON, 0, 0, 0);
   ObjectSetInteger(0, "BuyButton", OBJPROP_XDISTANCE, 10);
   ObjectSetInteger(0, "BuyButton", OBJPROP_YDISTANCE, 30);
   ObjectSetInteger(0, "BuyButton", OBJPROP_XSIZE, 100);
   ObjectSetInteger(0, "BuyButton", OBJPROP_YSIZE, 30);
   ObjectSetString(0, "BuyButton", OBJPROP_TEXT, "BUY");
   ObjectSetInteger(0, "BuyButton", OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(0, "BuyButton", OBJPROP_BGCOLOR, clrBlue);

   ObjectCreate(0, "SellButton", OBJ_BUTTON, 0, 0, 0);
   ObjectSetInteger(0, "SellButton", OBJPROP_XDISTANCE, 120);
   ObjectSetInteger(0, "SellButton", OBJPROP_YDISTANCE, 30);
   ObjectSetInteger(0, "SellButton", OBJPROP_XSIZE, 100);
   ObjectSetInteger(0, "SellButton", OBJPROP_YSIZE, 30);
   ObjectSetString(0, "SellButton", OBJPROP_TEXT, "SELL");
   ObjectSetInteger(0, "SellButton", OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(0, "SellButton", OBJPROP_BGCOLOR, clrRed);

   return(INIT_SUCCEEDED);
  }

void OnChartEvent(const int id, const long &lparam,
                   const double &dparam, const string &sparam)
  {
   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      if(sparam == "BuyButton")
        {
         Print("BUYボタンがクリックされました");
         OrderSend(Symbol(), OP_BUY, 0.01, Ask, 3, 0, 0, "Manual Buy", 0, 0, clrBlue);
         ObjectSetInteger(0, "BuyButton", OBJPROP_STATE, false);  // ボタンをリセット
        }
      else if(sparam == "SellButton")
        {
         Print("SELLボタンがクリックされました");
         OrderSend(Symbol(), OP_SELL, 0.01, Bid, 3, 0, 0, "Manual Sell", 0, 0, clrRed);
         ObjectSetInteger(0, "SellButton", OBJPROP_STATE, false);
        }
     }
  }

EA・インジケーター・スクリプトの違い

項目EA(Expert Advisor)インジケータースクリプト
メインイベントOnTick()OnCalculate()OnStart()
実行タイミングティックごとティックごと1回だけ
取引可能はいいいえはい
チャートへの描画オブジェクトのみバッファ+オブジェクトオブジェクトのみ
同時実行チャートに1つ複数可チャートに1つ
OnTimer使用可使用可不可
OnChartEvent使用可使用可不可
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 clrRed

double Buffer[];

int OnInit()
  {
   SetIndexBuffer(0, Buffer);
   SetIndexStyle(0, DRAW_LINE);
   SetIndexLabel(0, "MyIndicator");
   return(INIT_SUCCEEDED);
  }

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[],
                const long &volume[],
                const int &spread[])
  {
   int limit = rates_total - prev_calculated;
   if(prev_calculated == 0)
      limit = rates_total - 1;

   for(int i = limit; i >= 0; i--)
     {
      Buffer[i] = (high[i] + low[i] + close[i]) / 3.0;
     }

   return(rates_total);
  }
// スクリプト — 1回だけ実行される
void OnStart()
  {
   // 全ポジションの情報を表示
   Print("=== 保有ポジション一覧 ===");

   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
         continue;

      Print("Ticket=", OrderTicket(),
            " Type=", (OrderType() == OP_BUY ? "BUY" : "SELL"),
            " Lots=", OrderLots(),
            " Profit=", OrderProfit());
     }

   Print("=== 完了 ===");
  }
OnCalculateの最適化
  • prev_calculated引数を活用して、既に計算済みのバーを再計算しない
  • 初回呼び出し時(prev_calculated==0)は全バーを計算、2回目以降は新しいバーだけ計算
  • 戻り値にrates_totalを返すことで、次回呼び出し時のprev_calculatedに反映される
  • インジケーターでは取引関数(OrderSend等)は使用できない
OnCalculateの最適化
  • prev_calculated引数を活用して、既に計算済みのバーを再計算しない
  • 初回呼び出し時(prev_calculated==0)は全バーを計算、2回目以降は新しいバーだけ計算
  • 戻り値にrates_totalを返すことで、次回呼び出し時のprev_calculatedに反映される
  • インジケーターでは取引関数(OrderSend等)は使用できない

イベントハンドラ一覧(MQL5対応表)

MQL4イベントハンドラMQL5対応説明
OnInit() / init()OnInit()初期化
OnDeinit() / deinit()OnDeinit()終了処理
OnTick() / start()OnTick()ティック受信
OnTimer()OnTimer()タイマーイベント
OnChartEvent()OnChartEvent()チャートイベント
OnCalculate()OnCalculate()インジケーター計算
OnTester()OnTester()テスター終了
なしOnTrade()取引イベント
なしOnTradeTransaction()取引トランザクション
なしOnBookEvent()板情報変更

まとめ

MQL4のイベントハンドラはEA、インジケーター、スクリプトそれぞれの実行モデルに合わせて設計されています。重要なポイントは以下の通りです。

  • 新形式(OnInit/OnDeinit/OnTick)を使う — ビルド600+では旧形式より新形式が推奨
  • OnDeinitでは必ずリソースを解放する — タイマー停止、オブジェクト削除、コメントクリア
  • OnTickでは新バー検出を入れる — ティックごとの重複処理を防ぎ、バックテスト精度を向上
  • OnInitの戻り値でエラーを適切に通知する — INIT_FAILEDを返すとEAが自動停止する

次のステップとして、MQLリファレンス総合ガイドでチャート操作やエラーハンドリングと組み合わせたプロ品質のEA開発を学びましょう。

シストレ.COMで実績のあるEAが使い放題!/
無料会員登録はこちら
FX自動売買でEAを探すなら
シストレ.COM
実績あるEAが無料
厳格な審査を乗り越えた実績のあるEAが無料で使えます!
自由な口座選び
有料版を購入し柔軟な口座選びが可能!
フォワードテスト公開
全EAのフォワードテスト結果を公開中!
FX初心者も安心
初心者の方も安心して取引を始められます。
多様なEA選択肢
様々な種別のEAをご用意!自分の手法にあった取引が可能です。
信頼のFX会社と提携
人気のFX会社と提携中!様々なFX会社から選べます。
1分で登録完了!EA探すならシストレ.COM!/
無料会員登録はこちら
【FX自動売買】システムトレード完全ガイド|Forex Guide

この記事が気に入ったら
フォローしてね!

お役立ち情報をシェアする
  • URLをコピーしました!
目次