自作のカスタムインジケーターが「そろそろ買いのタイミングだ」と検知したとします。
でも、その情報をEAにどう伝えればいいのでしょうか。
インジケーターとEAは、同じチャートに乗っていても別々のプログラムです。
変数をそのまま共有することはできません。
これまでは、GlobalVariableSetでグローバル変数を経由させるか、
ファイルに書き出して読み込ませるという、間接的な方法が主流でした。
この記事では、もっと直接的にメッセージを送れる`EventChartCustom`関数と、
受け取り側の`OnChartEvent`イベントハンドラの使い方を解説します。
EventChartCustomとOnChartEventの基本
この2つはセットで使います。
送信側が`EventChartCustom`を呼び、
受信側の`OnChartEvent`がそれを検知する、という関係です。
EventChartCustomの引数
bool EventChartCustom( long chart_id, //送信先のチャートID(0で現在のチャート) ushort custom_event_id, //カスタムイベントの番号 long lparam, //long型の値 double dparam, //double型の値 string sparam //文字列(最大63文字) );
`lparam`・`dparam`・`sparam`の3つに、
伝えたい情報を自由に詰め込めます。
数値だけでなく、”BUY_SIGNAL”のような文字列も一緒に送れる点が便利です。
OnChartEventでCHARTEVENT_CUSTOMを判定する
void OnChartEvent( const int id, //イベントID const long &lparam, const double &dparam, const string &sparam );
カスタムイベントは`id > CHARTEVENT_CUSTOM`で判定します。
自分で定義した番号Nのイベントは、
`CHARTEVENT_CUSTOM+N`という値になります。
補足: OnChartEventはマウス操作やオブジェクトのドラッグなど、
他の種類のイベントも同じ関数で受け取ります。
`id`の値を見て、どの種類のイベントかを判定する必要があります。
インジケーターからEAへシグナルを送る設計
移動平均線のクロスをインジケーターが検知したら、
`EventChartCustom`でEA側に、
BUY・SELLのシグナルを送る設計を作ります。
sparamにシグナル種別、dparamに補足の数値を載せる
シグナルの種類は`sparam`に文字列で入れます。
判断の根拠になった数値(移動平均線の差など)は`dparam`に入れておくと、
EA側でログを見て後から検証しやすくなります。
カスタムイベント番号を#defineで管理する
インジケーター側とEA側で番号がずれると、判定に失敗します。
`#define SIGNAL_EVENT (CHARTEVENT_CUSTOM+1)`
のように、
同じ定義を両方のファイルに書いておくと管理しやすくなります。
実際に動くコード全体(インジケーター側)
移動平均線のゴールデンクロス・デッドクロスを検知して、
カスタムイベントでシグナルを送るインジケーターです。
//+------------------------------------------------------------------+
//| SignalSenderIndicator.mq4 |
//| Copyright 2026, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link "https://creator.fx-ea-system-project.com/"
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 0
#define SIGNAL_EVENT (CHARTEVENT_CUSTOM+1)
int g_lastDirection = 0; //0=未確定 1=ゴールデンクロス済み -1=デッドクロス済み
int OnInit()
{
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[])
{
double maFast = iMA(_Symbol, 0, 5, 0, MODE_SMA, PRICE_CLOSE, 0);
double maSlow = iMA(_Symbol, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 0);
double diff = maFast - maSlow;
if(diff > 0 && g_lastDirection != 1)
{
EventChartCustom(0, SIGNAL_EVENT, 0, diff, "BUY_SIGNAL");
g_lastDirection = 1;
}
else if(diff < 0 && g_lastDirection != -1)
{
EventChartCustom(0, SIGNAL_EVENT, 0, diff, "SELL_SIGNAL");
g_lastDirection = -1;
}
return(rates_total);
}
実際に動くコード全体(EA側)
インジケーターから送られたシグナルを受け取り、ログに出力するEAです。
実運用では、この`OnChartEvent`の中に発注処理を追加していきます。
//+------------------------------------------------------------------+
//| SignalReceiverEA.mq4 |
//| Copyright 2026, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link "https://creator.fx-ea-system-project.com/"
#property version "1.00"
#property strict
#define SIGNAL_EVENT (CHARTEVENT_CUSTOM+1)
int OnInit()
{
return(INIT_SUCCEEDED);
}
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if(id != SIGNAL_EVENT)
return;
if(sparam == "BUY_SIGNAL")
Print("インジケーターからBUYシグナル受信。MA差=", dparam);
else if(sparam == "SELL_SIGNAL")
Print("インジケーターからSELLシグナル受信。MA差=", dparam);
//ここに実際の発注処理(OrderSend等)を追加する
}
void OnTick()
{
//通常のティック処理はここに書く(シグナル受信とは独立)
}
MetaEditorで実際に動かす手順
- MetaEditorでインジケーター「SignalSenderIndicator」とEA「SignalReceiverEA」を、それぞれ新規作成し上のコードを貼り付ける
- 両方ともF7キーでコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
- 同じ通貨ペアの同じチャートに、インジケーターとEAの両方を適用する
- 「エキスパート」タブに、移動平均線がクロスするたびにシグナル受信のログが出るか確認する
よくあるエラーと注意点
コンパイルは通るのに、シグナルが届かないというケースで確認すべき点をまとめます。
OnChartEventが呼ばれない
インジケーターとEAが、別々のチャートに適用されていないか確認してください。
`EventChartCustom`の第1引数を0にした場合、
送信先は「インジケーター自身が乗っているチャート」になります。
EAが同じチャートに乗っていなければ、シグナルは届きません。
複数のカスタムイベントIDを見分ける
将来イベントの種類を増やす場合は、
`CHARTEVENT_CUSTOM+1`、
`CHARTEVENT_CUSTOM+2`のように番号を分け、
`OnChartEvent`内の`id`で分岐させます。
注意: このVaultにはMT4の実行環境がなく、
実際のコンパイル確認はできていません。
MetaEditorでコンパイルする際は、
必ず「0 error(s), 0 warning(s)」を確認してから使ってください。
グローバル変数・ファイル経由との使い分け
すべてをEventChartCustomに置き換える必要はありません。
| 方法 | 向いている用途 |
|---|---|
| EventChartCustom | その場で即座に伝えたいシグナル・イベント |
| GlobalVariableSet/Get | 端末を再起動しても残したい値、複数チャート間の共有 |
| FileWrite/FileOpen | 後から集計・分析したい記録、ログとして残す情報 |
要点: 「今すぐ伝える」ならEventChartCustom、
「後で参照する・残す」ならグローバル変数かファイル、という使い分けが基本です。
よくある質問
EventChartCustomの実装でよく検索されている疑問を、
3つにまとめて回答します。
MQL5でも同じ書き方ができますか?
はい。`EventChartCustom`・`OnChartEvent`ともに、
MQL4とMQL5で同じ引数構成です。
この記事のコードは、拡張子とプロパティ行を変えるだけでMQL5にも移植できます。
複数のインジケーターから同じEAにシグナルを送れますか?
送れます。`sparam`にインジケーター名や種別を含めておけば、
EA側の`OnChartEvent`で送信元を区別できます。
EAからインジケーターへ、逆方向に送ることもできますか?
できます。
`EventChartCustom`は送信元がEAでもインジケーターでも動作は同じです。
インジケーター側にも`OnChartEvent`を実装すれば受信できます。
【MQL4】インジケーターからEAへ合図を送りたい?EventChartCustom/OnChartEventでカスタムイベント通信する方法:まとめ
`EventChartCustom`と`OnChartEvent`を組み合わせれば、
インジケーターが検知した情報を、グローバル変数やファイルを経由せず直接EAに伝えられます。
`sparam`に文字列、`dparam`に数値を載せる設計にしておけば、
シグナルの種類と根拠を同時に送れます。
「今すぐ伝える」用途はEventChartCustom、
「後で参照する」用途はグローバル変数・ファイル、という使い分けを覚えておいてください。
コメント