はじめに
MT4で自動売買や裁量トレードを行う際、「どのタイミングでエントリー・決済したのか」をリアルタイムで把握できない…という悩みは多いです。
EA運用中は常にチャートを開けないため、トレードチャンスを逃すこともしばしば。
そこで今回は、MQL4で作るLINE通知インジケーターを紹介します。
設定すれば、EAや裁量トレードの売買タイミングを LINEアプリに即通知!
スマホひとつでポジション状況を確認できるようになります。
💡チャート画像も自動送信する上位版(画像付き通知)は以下noteで公開中👇
なぜLINE通知インジケーターを作ったのか
MT4標準の「アラート機能」や「メール通知」は便利ですが、
- 通知が遅れる
- 設定が複雑
- メールアプリを開く手間
といった課題がありました。
筆者自身もEA運用中にチャンスを逃した経験があり、
「トレード発生をスマホに即知らせたい」という目的で、Messaging APIを利用したLINE通知機能を開発しました。
⚙️ インジケーターの概要と機能
このインジケーターは、MT4で新しいポジションが発生・決済されたタイミングで、自動的に通知を送ります。ポジションの有無で判定しているので、市販EAにも適用可能です。
通知内容は以下の通りです👇
- 通貨ペア名
- ロット数
- 売買区分(買い/売り)
- 価格
- マジックナンバー
- コメント
- 損益(決済時)
通知方法はパラメータで選択可能です:
パラメータ | 内容 |
---|---|
通知方法 | トレード通知方法(LINE/メール/通知なし) |
(LINE)チャネルアクセストークン | Messaging APIのチャネルアクセストークン |
(LINE)ユーザーID | Messaging API設定時に発行されるID |
マジックナンバー | 監視するEAのマジックナンバー(空白で全て対象) |
💬 通知イメージ(実際のLINEメッセージ)

エントリー通知例:
【OANDA JAPAN】 2025.10.05 18:34
Lot:0.10 ▲買い注文 USDJPY 149.230
MN:12345 TestEA
決済通知例:
【OANDA JAPAN】 2025.10.05 22:15
Lot:0.10 ▽売り決済 USDJPY 149.320
損益:+900
EAが自動売買を行うたびに、このような通知がLINEに届きます。
スマホ通知がONなら、外出中でも即時に把握可能です。
📩 ダウンロードと設定方法
今回は合計2ファイルが必要となります。
📂 フォルダ構成(LINE_CALLzip)
├─ README.txt
└─ Files/
└─ S_LINE_API_TXT.bat
└─ Indicators/
└─ LINE_Send_TradeAlert_Harf.mq4 // ソースコード(学習・改造用)
└─ LINE_Send_TradeAlert_Harf.ex4 // コンパイル済み実行ファイル
以下のファイルをダウンロードして各フォルダに追加してください。
(ファイル名:LINE_CALL.zip)
設置手順
- MT4を開く
- 「ファイル」→「データフォルダを開く」
- MQL4 → Indicators フォルダに「LINE_Send_TradeAlert_Harf.ex4 」をコピー
- MQL4 → Files フォルダに「S_LINE_API_TXT.bat」ファイルをコピー
- MT4を再起動し、ナビゲーターからチャートに適用
- パラメータ設定を行う。
通知方法・・・任意
(LINE)チャネルアクセストークン・・・登録したアクセストークンを設定してください
(LINE)ユーザーID・・・ユーザーIDを設定してくださいマジックナンバー
・・・任意
🧩 ソースコード解説
LINE_Send_TradeAlert_Harf.mq4
//+------------------------------------------------------------------+
//| LINE_Send_TradeAlert_Harf.mq4 |
//| Copyright © 2020-2025 ぷろぐらむFX |
//| https://fx-prog.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2020-2025 ぷろぐらむFX"
#property link "https://fx-prog.com/"
#property version "1.00"
#property strict
#property indicator_chart_window
#import "shell32.dll"
int ShellExecuteW(int hWnd,string lpVerb,string lpFile,string lpParameters,string lpDirectory,int nCmdShow);
#import
enum EnumAreart
{
mail, // メール
line, // LINE
sinai, // 通知しない
};
input EnumAreart AreartFlg = line; //通知方法
input string LineToken = "c+・・・"; //(LINE)チャネルアクセストークン
input string ID = "U3・・・0"; //(LINE)ユーザーID
input string MagicNo = ""; //マジックナンバー(空白で全て対象)
int Save_ticket[10]; //ポジションのチケット番号保有用(2だと3ポジまで) 5ポジ持たせたい場合は4にすること
string objectName = "LINE_C";
string str_Ticket ="";
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
//ラベルオブジェクトの作成
if(!ObjectCreate(0, objectName, OBJ_LABEL, 0, 0, 0))
{
//return(INIT_FAILED);
}
// 座標位置
ObjectSetInteger(0,objectName, OBJPROP_CORNER, CORNER_LEFT_LOWER);
ObjectSetInteger(0,objectName, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
ObjectSetInteger(0, objectName, OBJPROP_XDISTANCE, 5);
ObjectSetInteger(0, objectName, OBJPROP_YDISTANCE, 5);
// 色
ObjectSetInteger(0, objectName, OBJPROP_COLOR, clrBlue);
// 読み取り専用
ObjectSetInteger(0, objectName, OBJPROP_READONLY, true);
// 選択不可
ObjectSetInteger(0, objectName, OBJPROP_SELECTABLE, false);
// フォント名
ObjectSetString(0, objectName, OBJPROP_FONT, "MS ゴシック");
// フォントサイズ
ObjectSetInteger(0, objectName, OBJPROP_FONTSIZE, 12);
//---
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason){
//---
ObjectDelete(0,objectName);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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[])
{
//---
string Posision_ticket[10]; //ポジションのチケット番号保有用(10だと11ポジまで)
bool mochiFlg =false;
string dataBuff[10]; //マジックナンバー保管用
int spc = StringSplit(MagicNo, ',', dataBuff);
for(int cnt = 0; cnt < OrdersTotal(); cnt++){
if(OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES) == true){
//既に通知済みかチェック
int searchCnt = StringSplit(str_Ticket,',',Posision_ticket);
for(int c = 0;c < searchCnt;c++){
if(OrderTicket() == StringToInteger(Posision_ticket[c])){
mochiFlg =true;
}
}
if(mochiFlg==false){
string OP_BUF = "";
if(OrderType()==OP_BUY){
OP_BUF =" ▲買い";
}else{
OP_BUF =" ▲売り";
}
string mes = "【" + AccountCompany() + "】" + TimeToStr(ChangeJPtime(TimeHour(OrderOpenTime())), TIME_SECONDS) + " Lot:" + DoubleToStr(OrderLots(),2) + OP_BUF + "注文 " + OrderSymbol() + " " + DoubleToString(OrderOpenPrice(), 5) + " MN:" + IntegerToString(OrderMagicNumber()) + " " + OrderComment();
if(spc==0){
if(AreartFlg==line){
SendTextToLine(mes);
}else if(AreartFlg==mail){
SendMail("MT4-トレード通知",mes);
}
}else{
for(int mg = 0; mg < spc; mg++){
if(IntegerToString(OrderMagicNumber()) == dataBuff[mg]){
if(AreartFlg==line){
SendTextToLine(mes);
}else if(AreartFlg==mail){
SendMail("MT4-トレード通知",mes);
}
}
}
}
Print(mes);
str_Ticket= str_Ticket + IntegerToString(OrderTicket()) + ",";
}
mochiFlg =false;
}
}
//既に通知済みかチェック
int searchCnt = StringSplit(str_Ticket,',',Posision_ticket);
for(int c = 0;c < searchCnt;c++){
for(int cnt = OrdersHistoryTotal(); cnt > 0; cnt--){
if(OrderSelect(cnt-1,SELECT_BY_POS,MODE_HISTORY) == true){
if(IntegerToString(OrderTicket()) == Posision_ticket[c]){
string OP_BUF = "";
if(OrderType()==OP_BUY){
OP_BUF =" ▽買い";
}else{
OP_BUF =" ▽売り";
}
string mes = "【" + AccountCompany() + "】" + TimeToStr(ChangeJPtime(TimeHour(OrderCloseTime())), TIME_SECONDS) + " Lot:" + DoubleToStr(OrderLots(),2) + OP_BUF + "決済 " + OrderSymbol() + " " + DoubleToString(OrderClosePrice(), 5) + " MN:" + IntegerToString(OrderMagicNumber()) + " " + OrderComment() + " 損益:" + DoubleToString(OrderProfit(), 2);
if(spc==0){
if(AreartFlg==line){
SendTextToLine(mes);
}else if(AreartFlg==mail){
SendMail("MT4-トレード通知",mes);
}
}else{
for(int mge = 0; mge < spc; mge++){
if(IntegerToString(OrderMagicNumber()) == dataBuff[mge]){
if(AreartFlg==line){
SendTextToLine(mes);
}else if(AreartFlg==mail){
SendMail("MT4-トレード通知",mes);
}
}
}
}
Print(mes);
StringReplace(str_Ticket,Posision_ticket[c]+",","");
break;
}
}
}
}
if(AreartFlg==line){
ObjectSetString(0, objectName, OBJPROP_TEXT, "LINE-CALL(LINE)");
}else if(AreartFlg==mail){
ObjectSetString(0, objectName, OBJPROP_TEXT, "LINE-CALL(MAIL)");
}else{
ObjectSetString(0, objectName, OBJPROP_TEXT, "LINE-CALL(OFF)");
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
//メッセージバッチ立ち上げ
void SendTextToLine(string message) {
string batPath = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL4\\Files\\S_LINE_API_TXT.bat";
// バッチにパラメータを全て渡す(順番注意)
string params =
"\"" + LineToken + "\" " +
"\"" + ID + "\" " +
"\"" + message + "\"";
int res = ShellExecuteW(0, "open", batPath, params, "", 1);
Print("SendTextToLine result:", res);
}
//+------------------------------------------------------------------+
//|【関数】日本時間(JST)をGMTに変換 |
//| |
//|【引数】START_HOUR: JSTの0-23 |
//|【戻値】cTime: GMT 0-23 |
//+------------------------------------------------------------------+
int ChangeJPtime(int START_HOUR)
{
int diff = IsSummerTime() ? -9 : -9; // 日本はサマータイムないので実質いつも-9
// ただし夏時間のGMT基準の考えがある場合はここで変える
int cTime = (START_HOUR + diff + 24) % 24; // マイナスを防ぐため+24
return cTime;
}
//+------------------------------------------------------------------+
//| 【関数】サマータイム判定(米国ルール) |
//| 3月第2日曜~11月第1日曜までをサマータイムとする |
//+------------------------------------------------------------------+
bool IsSummerTime()
{
int year = TimeYear(TimeCurrent());
// 3月第2日曜
datetime marchFirst = StringToTime(StringFormat("%04d.%02d.01 00:00", year, 3));
int marchWeekday = TimeDayOfWeek(marchFirst); // 0=日曜
int marchDaysToFirstSunday = (7 - marchWeekday) % 7;
datetime summerStart = marchFirst + (marchDaysToFirstSunday + (2 - 1) * 7) * 86400;
// 11月第1日曜
datetime novFirst = StringToTime(StringFormat("%04d.%02d.01 00:00", year, 11));
int novWeekday = TimeDayOfWeek(novFirst);
int novDaysToFirstSunday = (7 - novWeekday) % 7;
datetime summerEnd = novFirst + (novDaysToFirstSunday + (1 - 1) * 7) * 86400;
return (TimeCurrent() >= summerStart && TimeCurrent() < summerEnd);
}
MQL4のOnCalculate
内で、
- 現在のポジションを走査
- 新規チケット番号を検出
- LINE API用バッチファイルへ送信
という流れで通知を実現しています。
SendTextToLine()関数に、LINE通知するメッセージを渡してそこからバッチファイルを呼び出しています。
S_LINE_API_TXT.bat
@echo off
setlocal
set "TOKEN=%1"
set "GROUP_ID=%2"
set "MESSAGE=%~3"
set "JSON_DATA={\"to\":\"%GROUP_ID%\",\"messages\":[{\"type\":\"text\",\"text\":\"%MESSAGE%\"}]}"
curl -X POST -H "Authorization: Bearer %TOKEN%" -H "Content-Type: application/json" -d "%JSON_DATA%" https://api.line.me/v2/bot/message/push
endlocal
MT4側から呼び出されるので、アクセストークン・ユーザーID・メッセージを受け取りMessaging API側で利用する形です。
【最新版】LINE公式アカウント経由でMessaging APIチャネルを作成する手順・実装
※2024年9月以降、LINE Developersから直接チャネルを作成する仕様は廃止されました。
現在は「LINE公式アカウント」を作成し、その管理画面からMessaging APIを有効化する手順に変更されています。
STEP①:LINE公式アカウントを作成
- LINEビジネスIDに登録
- アカウント情報を入力し、公式アカウントを作成
- 作成後は「LINE Official Account Manager」で管理可能になります。
STEP②:Official Account ManagerでMessaging APIを有効化
- 公式アカウントの設定画面を開く
- 左メニューから「Messaging API」を選択
- 「Messaging APIを利用する」ボタンをクリックし、規約に同意して有効化
💡この操作により、裏側でMessaging APIチャネルが自動的に作成されます。
STEP③:アクセストークンなどの取得
有効化後に以下の情報を取得します👇
- チャネルアクセストークン(長期版)
- ユーザーID(自分側)
これらをMT4側の設定画面に入力することで、通知機能が連携されます。
例)以下の情報が必要になります。


💬 ここまででMessaging APIの設定が完了しました。
💡補足:LINEのMessaging APIの無料プランについて
- 1チャネルあたり 月200通まで無料送信可能
※上限を超えると送信エラーになります - **ライトプラン(月5,000円)**では、最大5,000通まで送信可能です
⚠️ LINEにメッセージを送る時にハマった事
LINEにメッセージを送る際、唯一ハマったことがあります。
それは、CRYPT_E_NO_REVOCATION_CHECK (0x80092012)「失効の関数は証明書の失効を確認できませんでした。」というエラーが出てLINEにメッセージを送信できなかったことです。
検索しても、証明書関連の解決策が出てきて『自分は証明書とか特に発行してないしなー』という感じでしたが、原因がわかりました。

原因は、ウィルス対策ソフトでした。例外のWEBサイトに『https://api.line.me/*』を追加する事で解決できました。
✅ まとめ
- EAや裁量トレードをリアルタイム監視できる
- MagicNo指定で特定EAのみ監視可能
- 改造次第で、シグナル通知にも使える
- さらにバッチ経由で画像送信も拡張可能
LINE通知によって、EAの挙動を見逃すことがなくなります。
「EAを動かしてるけど、どのタイミングで注文されたか分からない」
──そんな悩みを、このインジケータで一気に解消しましょう!
💡 チャート画像も自動送信する上位版は、こちらのnoteで配布中です👇
コメント