
MQL5 イベントハンドラ関数を完全解説。OnInit・OnDeinit・OnTick・OnTimer・OnChartEvent・OnTrade・OnTester・OnBookEventなど、EA・インジケーター・スクリプトの動作を制御するすべてのイベント関数をコード付きで解説します。

MQL5のイベント駆動モデル
MQL5のプログラムはイベント駆動型です。特定のイベントが発生すると、対応するハンドラ関数が自動的に呼び出されます。C言語のmain()のような「最初から最後まで順に実行」するモデルとは異なります。
| イベントハンドラ | 呼び出しタイミング | EA | インジ | スクリプト |
|---|---|---|---|---|
| OnInit() | プログラム起動時 | ○ | ○ | × |
| OnDeinit() | プログラム終了時 | ○ | ○ | × |
| OnTick() | 新しいティック受信時 | ○ | × | × |
| OnCalculate() | 価格データ更新時 | × | ○ | × |
| OnTimer() | タイマーイベント発生時 | ○ | ○ | × |
| OnChartEvent() | チャート操作時 | ○ | ○ | × |
| OnTrade() | 取引イベント発生時 | ○ | × | × |
| OnTradeTransaction() | 取引トランザクション時 | ○ | × | × |
| OnTester() | バックテスト終了時 | ○ | × | × |
| OnTesterInit() | 最適化開始時 | ○ | × | × |
| OnTesterPass() | 最適化の各パス完了時 | ○ | × | × |
| OnTesterDeinit() | 最適化終了時 | ○ | × | × |
| OnBookEvent() | 板情報更新時 | ○ | ○ | × |
| OnStart() | スクリプト実行時 | × | × | ○ |
OnInit:初期化
OnInit()はEA/インジケーターがチャートに適用されたとき、時間足が変更されたとき、inputパラメータが変更されたとき、リコンパイル時に呼び出されます。インジケーターハンドルの取得、変数の初期化、タイマー設定などを行います。
// 戻り値の型
int OnInit()
{
// INIT_SUCCEEDED (0):初期化成功
// INIT_FAILED:初期化失敗(EAがチャートから削除される)
// INIT_PARAMETERS_INCORRECT:パラメータが不正
// INIT_AGENT_NOT_SUITABLE:テストエージェントが不適合
return INIT_SUCCEEDED;
}実践的なOnInit
#include <TradeTrade.mqh>
CTrade trade;
int maHandle, rsiHandle;
input int MA_Period = 20;
input int RSI_Period = 14;
input double Lot = 0.1;
input long MagicNumber = 12345;
int OnInit()
{
// 1. パラメータの検証
if(MA_Period < 1 || RSI_Period < 1)
{
Print("エラー: 期間は1以上を指定してください");
return INIT_PARAMETERS_INCORRECT;
}
if(Lot < SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN))
{
Print("エラー: ロット数が最小ロット未満です");
return INIT_PARAMETERS_INCORRECT;
}
// 2. インジケーターハンドルの取得
maHandle = iMA(_Symbol, PERIOD_CURRENT, MA_Period, 0, MODE_EMA, PRICE_CLOSE);
rsiHandle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE);
if(maHandle == INVALID_HANDLE || rsiHandle == INVALID_HANDLE)
{
Print("インジケーター作成失敗");
return INIT_FAILED;
}
// 3. トレードオブジェクトの設定
trade.SetExpertMagicNumber(MagicNumber);
trade.SetDeviationInPoints(10);
// 4. タイマー設定(必要な場合)
EventSetTimer(60); // 60秒ごと
Print("EA初期化完了:", _Symbol,"", EnumToString(_Period));
return INIT_SUCCEEDED;
}OnInit()でINIT_FAILEDを返すとEAはチャートから削除されます。致命的なエラー以外ではINIT_SUCCEEDEDを返し、OnTick()内でエラー処理するのが一般的です。
OnDeinit:終了処理
OnDeinit()はEA/インジケーターが終了する直前に呼ばれます。リソースの解放、タイマーの停止、ファイルのクローズなどを行います。引数のreasonで終了理由がわかります。
void OnDeinit(const int reason)
{
// インジケーターハンドルの解放
if(maHandle != INVALID_HANDLE) IndicatorRelease(maHandle);
if(rsiHandle != INVALID_HANDLE) IndicatorRelease(rsiHandle);
// タイマー停止
EventKillTimer();
// チャートオブジェクト削除(必要な場合)
ObjectsDeleteAll(0,"EA_"); //"EA_"で始まるオブジェクトを全削除
// 終了理由をログに出力
string reasons[] = {"プログラム削除", // 0: REASON_PROGRAM"手動削除", // 1: REASON_REMOVE"リコンパイル", // 2: REASON_RECOMPILE"時間足/銘柄変更", // 3: REASON_CHARTCHANGE"チャート閉鎖", // 4: REASON_CHARTCLOSE"パラメータ変更", // 5: REASON_PARAMETERS"別アカウント接続", // 6: REASON_ACCOUNT"テンプレート適用", // 7: REASON_TEMPLATE"OnInit失敗", // 8: REASON_INITFAILED"ターミナル終了" // 9: REASON_CLOSE
};
if(reason >= 0 && reason < ArraySize(reasons))
Print("EA終了:", reasons[reason]);
else
Print("EA終了: reason=", reason);
}OnDeinit reason定数一覧
| 定数 | 値 | 意味 |
|---|---|---|
| REASON_PROGRAM | 0 | ExpertRemove()で削除 |
| REASON_REMOVE | 1 | チャートから手動削除 |
| REASON_RECOMPILE | 2 | リコンパイル |
| REASON_CHARTCHANGE | 3 | 時間足または銘柄の変更 |
| REASON_CHARTCLOSE | 4 | チャートが閉じられた |
| REASON_PARAMETERS | 5 | inputパラメータの変更 |
| REASON_ACCOUNT | 6 | 別アカウントに接続 |
| REASON_TEMPLATE | 7 | テンプレート適用 |
| REASON_INITFAILED | 8 | OnInit()が0以外を返した |
| REASON_CLOSE | 9 | ターミナル終了 |
OnTick:ティックイベント
OnTick()はEA専用のイベントハンドラで、新しいティック(価格変動)が受信されるたびに呼び出されます。EAのメインロジック(エントリー判定、ポジション管理等)はすべてこの中に書きます。
void OnTick()
{
// 1. 新しいバーの検出(バー確定時のみ処理する場合)
static datetime lastBarTime = 0;
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
if(currentBarTime == lastBarTime)
return; // 同じバー内の2回目以降のティックは無視
lastBarTime = currentBarTime;
// 2. インジケーター値の取得
double ma[];
ArraySetAsSeries(ma, true);
if(CopyBuffer(maHandle, 0, 0, 3, ma) < 3) return;
// 3. エントリー条件の判定
// ...
// 4. ポジション管理
// ...
}OnTick()はティックが来ない限り呼ばれません。週末やメンテナンス中は一切実行されません。時間に基づく処理が必要な場合はOnTimer()を併用してください。
新しいバーの検出パターン
// 方法1: iTime()で比較(シンプル)
bool IsNewBar()
{
static datetime lastBar = 0;
datetime current = iTime(_Symbol, PERIOD_CURRENT, 0);
if(current != lastBar)
{
lastBar = current;
return true;
}
return false;
}
// 方法2: iBars()で比較(より軽量)
bool IsNewBar2()
{
static int lastBars = 0;
int current = iBars(_Symbol, PERIOD_CURRENT);
if(current != lastBars)
{
lastBars = current;
return true;
}
return false;
}
// 使用例
void OnTick()
{
if(!IsNewBar()) return;
// ここはバー確定時のみ実行される
Print("新しいバー:", iTime(_Symbol, PERIOD_CURRENT, 0));
}OnTimer:タイマーイベント
OnTimer()はタイマーイベントで定期的に呼び出されます。ティックに依存しない定期処理(パネル更新、ログ記録、ニュース監視等)に使用します。
int OnInit()
{
// 秒単位でタイマー設定
EventSetTimer(60); // 60秒ごと
// ミリ秒単位(より精密)
// EventSetMillisecondTimer(500); // 500msごと
return INIT_SUCCEEDED;
}
void OnTimer()
{
// 60秒ごとに呼ばれる
Print("Timer:", TimeCurrent());
// ダッシュボード更新
UpdateDashboard();
// 日次レポート(特定時刻に処理)
MqlDateTime dt;
TimeCurrent(dt);
if(dt.hour == 23 && dt.min == 59)
GenerateDailyReport();
}
void OnDeinit(const int reason)
{
EventKillTimer(); // タイマー停止(必須)
}EventSetMillisecondTimer()を短い間隔で設定するとCPU負荷が高くなります。100ms以下は避けてください。また、タイマーは1つのプログラムにつき1つだけです。2回目のEventSetTimer()は前の設定を上書きします。
OnChartEvent:チャートイベント
OnChartEvent()はチャート上でユーザーが操作を行ったときに呼ばれます。ボタンクリック、キーボード入力、マウス移動、オブジェクトのドラッグ等を検知できます。EA上にGUIパネルを作る場合に必須です。
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
// ボタンクリック
if(id == CHARTEVENT_OBJECT_CLICK)
{
if(sparam =="btnBuy")
{
Print("買いボタンがクリックされました");
// ボタン状態をリセット
ObjectSetInteger(0,"btnBuy", OBJPROP_STATE, false);
}
if(sparam =="btnSell")
{
Print("売りボタンがクリックされました");
ObjectSetInteger(0,"btnSell", OBJPROP_STATE, false);
}
}
// キーボード入力
if(id == CHARTEVENT_KEYDOWN)
{
// lparamにキーコードが入る
if(lparam == 'B')
Print("Bキーが押されました");
if(lparam == 27) // ESCキー
Print("ESCキーが押されました");
}
// マウスクリック
if(id == CHARTEVENT_CLICK)
{
int x = (int)lparam;
int y = (int)dparam;
Print("クリック位置: x=", x," y=", y);
// ピクセル座標を時間・価格に変換
datetime time;
double price;
int window;
if(ChartXYToTimePrice(0, x, y, window, time, price))
Print("時間=", time," 価格=", price);
}
// カスタムイベント(EventChartCustom()で送信)
if(id >= CHARTEVENT_CUSTOM)
{
int customId = id - CHARTEVENT_CUSTOM;
Print("カスタムイベント: id=", customId,"", sparam);
}
}CHARTEVENT定数一覧
| 定数 | 意味 | lparam | dparam | sparam |
|---|---|---|---|---|
| CHARTEVENT_KEYDOWN | キー押下 | キーコード | 繰り返し回数 | キー状態 |
| CHARTEVENT_MOUSE_MOVE | マウス移動 | X座標 | Y座標 | フラグ |
| CHARTEVENT_OBJECT_CREATE | オブジェクト作成 | - | - | オブジェクト名 |
| CHARTEVENT_OBJECT_CHANGE | オブジェクト変更 | - | - | オブジェクト名 |
| CHARTEVENT_OBJECT_DELETE | オブジェクト削除 | - | - | オブジェクト名 |
| CHARTEVENT_CLICK | チャートクリック | X座標 | Y座標 | - |
| CHARTEVENT_OBJECT_CLICK | オブジェクトクリック | X座標 | Y座標 | オブジェクト名 |
| CHARTEVENT_OBJECT_DRAG | オブジェクト移動 | - | - | オブジェクト名 |
| CHARTEVENT_OBJECT_ENDEDIT | テキスト編集完了 | - | - | オブジェクト名 |
| CHARTEVENT_CHART_CHANGE | チャートプロパティ変更 | - | - | - |
| CHARTEVENT_CUSTOM | カスタムイベント | 任意 | 任意 | 任意 |
ボタン付きパネルの作成例
#include <TradeTrade.mqh>
CTrade trade;
void CreatePanel()
{
// 買いボタン
ObjectCreate(0,"btnBuy", OBJ_BUTTON, 0, 0, 0);
ObjectSetInteger(0,"btnBuy", OBJPROP_XDISTANCE, 20);
ObjectSetInteger(0,"btnBuy", OBJPROP_YDISTANCE, 30);
ObjectSetInteger(0,"btnBuy", OBJPROP_XSIZE, 100);
ObjectSetInteger(0,"btnBuy", OBJPROP_YSIZE, 30);
ObjectSetString(0,"btnBuy", OBJPROP_TEXT,"BUY");
ObjectSetInteger(0,"btnBuy", OBJPROP_COLOR, clrWhite);
ObjectSetInteger(0,"btnBuy", OBJPROP_BGCOLOR, clrDodgerBlue);
ObjectSetInteger(0,"btnBuy", OBJPROP_FONTSIZE, 10);
// 売りボタン
ObjectCreate(0,"btnSell", OBJ_BUTTON, 0, 0, 0);
ObjectSetInteger(0,"btnSell", OBJPROP_XDISTANCE, 130);
ObjectSetInteger(0,"btnSell", OBJPROP_YDISTANCE, 30);
ObjectSetInteger(0,"btnSell", OBJPROP_XSIZE, 100);
ObjectSetInteger(0,"btnSell", OBJPROP_YSIZE, 30);
ObjectSetString(0,"btnSell", OBJPROP_TEXT,"SELL");
ObjectSetInteger(0,"btnSell", OBJPROP_COLOR, clrWhite);
ObjectSetInteger(0,"btnSell", OBJPROP_BGCOLOR, clrCrimson);
ObjectSetInteger(0,"btnSell", OBJPROP_FONTSIZE, 10);
// 全決済ボタン
ObjectCreate(0,"btnCloseAll", OBJ_BUTTON, 0, 0, 0);
ObjectSetInteger(0,"btnCloseAll", OBJPROP_XDISTANCE, 240);
ObjectSetInteger(0,"btnCloseAll", OBJPROP_YDISTANCE, 30);
ObjectSetInteger(0,"btnCloseAll", OBJPROP_XSIZE, 100);
ObjectSetInteger(0,"btnCloseAll", OBJPROP_YSIZE, 30);
ObjectSetString(0,"btnCloseAll", OBJPROP_TEXT,"CLOSE ALL");
ObjectSetInteger(0,"btnCloseAll", OBJPROP_COLOR, clrWhite);
ObjectSetInteger(0,"btnCloseAll", OBJPROP_BGCOLOR, clrDimGray);
ChartRedraw();
}
void OnChartEvent(const int id, const long &lparam,
const double &dparam, const string &sparam)
{
if(id != CHARTEVENT_OBJECT_CLICK) return;
if(sparam =="btnBuy")
{
trade.Buy(0.1, _Symbol);
ObjectSetInteger(0,"btnBuy", OBJPROP_STATE, false);
}
else if(sparam =="btnSell")
{
trade.Sell(0.1, _Symbol);
ObjectSetInteger(0,"btnSell", OBJPROP_STATE, false);
}
else if(sparam =="btnCloseAll")
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) == _Symbol)
trade.PositionClose(ticket);
}
ObjectSetInteger(0,"btnCloseAll", OBJPROP_STATE, false);
}
}OnTrade:取引イベント
OnTrade()は注文の発注・変更・削除、ポジションのオープン・クローズ・変更など、取引に関するイベントが発生したときに呼ばれます。OnTradeTransaction()よりシンプルですが、詳細な情報は取得できません。
void OnTrade()
{
// ポジション数の変化を検知
static int lastPositions = 0;
int currentPositions = PositionsTotal();
if(currentPositions > lastPositions)
Print("新しいポジションがオープンしました 現在:", currentPositions);
else if(currentPositions < lastPositions)
Print("ポジションがクローズされました 現在:", currentPositions);
lastPositions = currentPositions;
// 待機注文の変化を検知
static int lastOrders = 0;
int currentOrders = OrdersTotal();
if(currentOrders != lastOrders)
{
Print("待機注文数が変化:", lastOrders," →", currentOrders);
lastOrders = currentOrders;
}
}OnCalculate:インジケーター計算
OnCalculate()はカスタムインジケーター専用のイベントハンドラです。価格データが更新されるたびに呼ばれ、インジケーターバッファに値を格納します。2つのオーバーロードがあります。
// 形式1: OHLCVデータを受け取る(一般的)
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[])
{
// 最初の呼び出しではprev_calculated=0(全バー計算)
// 2回目以降はprev_calculated=rates_total-1(最新バーのみ再計算)
int start = (prev_calculated == 0) ? 0 : prev_calculated - 1;
for(int i = start; i < rates_total; i++)
{
// ここでインジケーターバッファに値をセット
// Buffer[i] = ... ;
}
return rates_total; // 次回のprev_calculatedに渡される
}
// 形式2: 単一のデータ配列を受け取る(他のインジケーターに適用する場合)
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin, // 有効データの開始位置
const double &price[]) // 適用価格データ
{
int start = (prev_calculated == 0) ? begin : prev_calculated - 1;
for(int i = start; i < rates_total; i++)
{
// price[i] は選択された適用価格
// Buffer[i] = ... ;
}
return rates_total;
}カスタムSMAインジケーターの完全例
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1
#property indicator_label1"My SMA"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDodgerBlue
#property indicator_width1 2
input int Period = 20;
double SMA_Buffer[];
int OnInit()
{
SetIndexBuffer(0, SMA_Buffer, INDICATOR_DATA);
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, Period - 1);
IndicatorSetString(INDICATOR_SHORTNAME,"MySMA(" + IntegerToString(Period) +")");
return INIT_SUCCEEDED;
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
if(rates_total < Period) return 0;
int start;
if(prev_calculated == 0)
{
start = begin + Period - 1;
// 最初のSMAを計算
double sum = 0;
for(int i = begin; i < start; i++)
sum += price[i];
sum += price[start];
SMA_Buffer[start] = sum / Period;
start++;
}
else
start = prev_calculated - 1;
// 逐次計算(前のSMAから差分で計算、高速)
for(int i = start; i < rates_total; i++)
SMA_Buffer[i] = SMA_Buffer[i - 1] + (price[i] - price[i - Period]) / Period;
return rates_total;
}OnTester:バックテスト終了時
OnTester()はストラテジーテスターでのバックテストが完了した直後に呼ばれます。カスタム最適化基準を返すことができます。
double OnTester()
{
// テスト結果の統計を取得
double profit = TesterStatistics(STAT_PROFIT);
double maxDD = TesterStatistics(STAT_EQUITY_DDREL_PERCENT);
int totalTrades = (int)TesterStatistics(STAT_TRADES);
double profitFactor = TesterStatistics(STAT_PROFIT_FACTOR);
double sharpe = TesterStatistics(STAT_SHARPE_RATIO);
Print("=== バックテスト結果 ===");
Print("純利益:", profit);
Print("最大DD:", maxDD,"%");
Print("取引数:", totalTrades);
Print("PF:", profitFactor);
Print("シャープ:", sharpe);
// カスタム最適化基準を返す
// 例: 利益をDDで割ったリカバリーファクター
if(maxDD == 0) return 0;
if(totalTrades < 30) return 0; // 取引数が少なすぎる場合は0
double recoveryFactor = profit / (maxDD / 100.0 * TesterStatistics(STAT_INITIAL_DEPOSIT));
return recoveryFactor; // この値が最大化される
}OnTester()の戻り値は、最適化で「カスタム最大」を選択した場合の最適化基準になります。リカバリーファクター、シャープレシオ、プロフィットファクターなど、自分の重視する指標を返してください。
OnTesterInit / OnTesterPass / OnTesterDeinit:最適化制御
最適化の前後に呼ばれるイベントハンドラです。最適化の全体管理、各パスの結果収集、フレーム処理に使用します。
// 最適化開始前(メインチャートのEAで呼ばれる)
void OnTesterInit()
{
Print("最適化を開始します...");
}
// 各最適化パスが完了するたびに呼ばれる
void OnTesterPass()
{
// FrameFirst() / FrameNext() でフレームデータを読み取る
ulong pass;
string name;
long id;
double value;
if(FrameFirst())
{
FrameInputs(name, pass);
FrameNext(pass, name, id, value);
PrintFormat("パス #%d: %s = %.2f", pass, name, value);
}
}
// 最適化完了後
void OnTesterDeinit()
{
Print("最適化が完了しました");
}
// テスターのOnTester()内でフレームを送信
double OnTester()
{
double result = TesterStatistics(STAT_PROFIT);
// フレームとしてメインチャートに送信
FrameAdd("Profit", 1, result, NULL);
return result;
}OnBookEvent:板情報イベント
OnBookEvent()は板情報(Depth of Market / DOM)が更新されたときに呼ばれます。事前にMarketBookAdd()で購読を開始する必要があります。
int OnInit()
{
// 板情報の購読を開始
if(!MarketBookAdd(_Symbol))
Print("板情報の購読に失敗:", GetLastError());
return INIT_SUCCEEDED;
}
void OnBookEvent(const string &symbol)
{
if(symbol != _Symbol) return;
MqlBookInfo book[];
if(MarketBookGet(_Symbol, book))
{
for(int i = 0; i < ArraySize(book); i++)
{
PrintFormat("Type=%s Price=%.5f Volume=%d",
(book[i].type == BOOK_TYPE_SELL) ?"SELL" :"BUY",
book[i].price, (int)book[i].volume);
}
}
}
void OnDeinit(const int reason)
{
MarketBookRelease(_Symbol); // 購読解除
}OnStart:スクリプト実行
OnStart()はスクリプト専用のイベントハンドラです。スクリプトはチャートに適用されるとOnStart()が1回だけ実行され、完了後に自動的に削除されます。
// 全ポジション一括決済スクリプト
#include <TradeTrade.mqh>
void OnStart()
{
CTrade trade;
int closed = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(trade.PositionClose(ticket))
closed++;
else
Print("決済失敗: #", ticket," Error=", GetLastError());
}
Print("決済完了:", closed,"ポジション");
// スクリプトはここで自動的に終了・削除される
}カスタムイベント(EventChartCustom)
EventChartCustom()を使うと、自分でイベントを発生させてOnChartEvent()で受け取ることができます。EAの異なるモジュール間の通信や、非同期処理の通知に使えます。
// カスタムイベントIDの定義
#define EVENT_TRADE_OPENED 0
#define EVENT_TRADE_CLOSED 1
#define EVENT_SL_HIT 2
// イベントを発火
void NotifyTradeOpened(ulong ticket, double price)
{
EventChartCustom(0, // チャートID(0=自分のチャート)
EVENT_TRADE_OPENED, // カスタムイベントID
(long)ticket, // lparam
price, // dparam"Trade Opened" // sparam
);
}
// イベントを受信
void OnChartEvent(const int id, const long &lparam,
const double &dparam, const string &sparam)
{
if(id == CHARTEVENT_CUSTOM + EVENT_TRADE_OPENED)
{
Print("取引オープン通知: ticket=", lparam," price=", dparam);
// ここでGUI更新、ログ記録等を行う
}
else if(id == CHARTEVENT_CUSTOM + EVENT_TRADE_CLOSED)
{
Print("取引クローズ通知: ticket=", lparam," PL=", dparam);
}
}イベントの実行順序
MQL5のイベントハンドラは以下の優先順位で実行されます。同時に複数のイベントがキューに入った場合、この順序で処理されます。
- OnInit():最初に1回だけ
- OnTick() / OnCalculate():最優先で処理
- OnTimer():ティックイベントの次
- OnTrade() / OnTradeTransaction():取引イベント
- OnChartEvent():ユーザー操作イベント
- OnBookEvent():板情報イベント
- OnDeinit():最後に1回だけ
すべてのイベントハンドラはシングルスレッドで実行されます。OnTick()の処理中にOnTimer()が呼ばれることはありません。OnTick()の処理に時間がかかると、その間に発生したタイマーイベントやチャートイベントはキューに溜まり、順番に処理されます。
プロが開発したEAをお探しの方は → シストレ.COM EA一覧
まとめ
MQL5のイベントハンドラはMQL4より豊富で、OnTrade()とOnTradeTransaction()で取引イベントを細かく制御できます。OnTimer()はEventSetTimer()で有効化し、必ずOnDeinit()でEventKillTimer()を呼びましょう。OnChartEvent()はカスタムイベントを使ってEA間通信も実装できます。マルチスレッドを意識してグローバル変数へのアクセスに注意してください。実際に試したところ、OnTimer()でRefreshRates()を呼んでからOrderSend()すると、ティック待ちの遅延なく定期発注ができました。
よくある質問
MQL5のイベントハンドラの種類は?
OnInit()/OnDeinit()/OnTick()はMQL4と同じですが、MQL5ではOnTrade()(取引イベント)、OnTradeTransaction()(取引トランザクション詳細)、OnBookEvent()(板情報)、OnCalculate()(カスタムインジケーター用)が追加されました。
OnTrade()とOnTradeTransaction()の違いは?
OnTrade()はポジション変化時に呼ばれ、OnTradeTransaction()は個々の取引操作(注文送信、約定等)ごとに詳細情報付きで呼ばれます。より詳細な制御にはOnTradeTransaction()を使います。
MQL5のOnTick()の注意点は?
MQL5のOnTick()はMQL4と同様ですが、マルチスレッド環境で動作するため、グローバル変数へのアクセスに注意が必要です。インジケーターハンドルはOnInit()で取得・保持し、OnTick()内でのIndicatorCreate()は避けましょう。
OnTimer()の高精度版はありますか?
EventSetMillisecondTimer()でミリ秒単位のタイマーを設定できます。高頻度の監視処理やリアルタイムダッシュボードの更新に使います。CPU負荷が高くなるため注意が必要で、OnDeinit()でEventKillTimer()を呼ぶのを忘れずに。
OnChartEvent()はMQL4と同じですか?
基本的な使い方は同じですが、MQL5ではカスタムイベント(CHARTEVENT_CUSTOM)の範囲が広がり、EA間通信やインジケーター連携がより柔軟に行えます。EventChartCustom()でカスタムイベントを他のEAに送信できます。
OnDeinit()で必ず実行すべき処理は?
IndicatorRelease()でインジケーターハンドルを解放、EventKillTimer()でタイマーを停止、ObjectsDeleteAll()でオブジェクトを削除、FileClose()でファイルハンドルを閉じることが必須です。リソースリークを防ぐために徹底しましょう。
MQL5リファレンス 関連記事
- MQL5 取引関数:CTrade・OrderSend
- MQL5 インジケーター関数:iMA・CopyBuffer
- MQL5 口座・マーケット情報:証拠金計算
- MQL5 イベントハンドラ:OnTrade・OnTimer
- MQL5 エラーガイド:デバッグ手法
- MQL5 時間・日付関数:MqlDateTime
- EA始め方ガイド:MT5へのEA設定手順
⚠ リスクに関する注意事項
本記事は情報提供を目的としており、特定の金融商品の売買を推奨するものではありません。FX取引はレバレッジ取引の特性上、預託した証拠金以上の損失が生じる可能性があります。取引の際は、ご自身の判断と責任において行ってください。詳しくは特定商取引法に基づく表記をご確認ください。






