MQL5外部連携EA実務ノート|WebRequest・JSON・Webhookを安全に扱う設計
MQL5 EAでは、WebRequest、JSON、Webhookなどを使って、外部サービスと連携する場面があります。
たとえば、外部通知、稼働状態の送信、設定確認、運用メモの取得、Discord通知、検証ログの送信などです。外部連携を使うと便利ですが、設計を間違えると、通信失敗でEA本体が止まる、tokenやURLがログへ出る、通知失敗を売買失敗と誤解する、外部応答遅延でOnTickが重くなる、といった問題が起きます。
外部連携EAで重要なのは、通信処理を売買ロジックへ直接混ぜないことです。signal、execution、risk、exit、auth、external control、notificationを分け、通信失敗時にどの処理を止めるのか、どの処理を継続するのかを明確にします。
この記事では、MQL5 EAでWebRequest、JSON、Webhookを安全に扱うための設計判断を、開発実務ノートとして整理します。完成EAソース全文、外部シート制御ロジック、認証ロジック、endpoint、token、URL実値、実運用set値、中核Entry条件は公開しません。
本記事は、投資判断や売買指示ではなく、外部連携を含むMQL5 EAを安全に設計・検証・サポートするための技術記事です。
- この記事で扱う実務課題
- なぜ外部連携EAでは責務分離が重要なのか
- 外部連携で分けるべき責務
- WebRequestを使う時に決めること
- JSON応答を扱う時の注意点
- Webhook通知を売買処理と分ける理由
- 通信失敗時は安全側で扱う
- 実コード例1:外部通信結果を構造体で扱う
- 実コード例2:外部通信ログは機密情報をマスクする
- 実コード例3:外部状態を新規Entryと既存管理へ分けて扱う
- 実コード例4:通知失敗を売買失敗と分ける
- 外部連携でログに残すべき情報
- 外部通信をOnTickへ直接詰め込まない
- 外部制御と認証を混同しない
- よくある失敗例
- 導入前・開発依頼前に整理する情報
- 関連する技術講座・確認ページ
- FAQ
- 関連する開発実務ノート
- まとめ
この記事で扱う実務課題
| 項目 | この記事で扱う内容 | 扱わない内容 |
|---|---|---|
| 目的 | WebRequest、JSON、WebhookをEAで安全に扱う設計 | 利益を狙う売買ロジック、具体的なEntry条件 |
| 主な対象 | 外部通信、通知、レスポンス確認、通信失敗時の安全側処理 | 完成EAソース全文、実運用コード全文 |
| 設計観点 | 責務分離、ログ設計、タイムアウト、通信抑制、機密情報マスク | 認証ロジック、外部シート制御、実運用set値 |
| コード例 | 一般化した通信結果構造、ログ例、通知分離、通信失敗時の扱い | 実endpoint、token、URL、GAS URL、Webhook URL |
| 読者 | MQL5開発者、外部通知EAを作りたい人、検証担当者、販売前チェック担当者 | 売買判断や推奨設定を知りたい人 |
なぜ外部連携EAでは責務分離が重要なのか
外部連携をEAへ追加すると、EA本体の処理に通信という不安定要素が入ります。
通信は、EA内部だけでは完結しません。回線、MT5のWebRequest許可設定、外部サーバーの応答、タイムアウト、証明書、payload形式、HTTPステータス、サービス側の制限など、多くの要因に影響されます。
| 問題 | 起きる原因 | 分けるべき責務 |
|---|---|---|
| EAが重くなる | OnTick内で毎回通信している | external communication / runtime |
| 通知が届かない | Webhook設定不備、通信失敗、送信抑制 | notification |
| 売買まで止まる | 通知失敗と売買処理を同じ失敗として扱っている | execution / notification |
| ログに機密情報が出る | endpointやtokenをそのままPrintしている | log / secret management |
| 外部停止の範囲が曖昧 | 新規Entry停止と既存ポジション管理を混同している | external control / exit |
| 問い合わせ時に確認できない | HTTP結果、reason、detailがログにない | log design |
外部連携は便利ですが、EA本体の売買判定や決済処理と密結合にすると、通信失敗がそのまま売買不具合のように見えてしまいます。
外部連携で分けるべき責務
外部連携EAでは、少なくとも次の責務を分けて設計します。
| 責務 | 役割 | 混同すると起きる問題 |
|---|---|---|
| signal | Entry候補を作る | 外部通信失敗をシグナル不成立と誤解する |
| execution | OrderSend、決済、modifyを実行する | 通知失敗と注文失敗を混同する |
| risk | ロット、保有上限、損失制御を扱う | 外部状態と内部リスクを混同する |
| exit | 既存ポジション管理を行う | 新規Entry停止時に保護決済まで止めてしまう |
| auth | 利用許可や認証状態を扱う | 認証NG時の停止範囲が曖昧になる |
| external control | 外部状態による動作制御を扱う | 通信失敗時に売買全体の扱いが不明になる |
| notification | Discord通知や外部通知を扱う | 通知失敗が売買失敗に見える |
| log | 通信結果、reason、detailを記録する | 問い合わせ時に原因を追えない |
特に重要なのは、notificationとexecutionを分けることです。通知が失敗しても、注文自体は成功している場合があります。逆に、注文が失敗しても通知だけ成功している場合もあります。
WebRequestを使う時に決めること
MQL5でWebRequestを使う場合、実装前に次の方針を決めておく必要があります。
| 確認項目 | 設計判断 |
|---|---|
| 通信タイミング | OnTickごとか、OnTimerか、状態変化時か |
| 通信頻度 | 秒単位で抑制するか、イベント発生時だけにするか |
| 失敗時の扱い | 新規Entryを止めるか、通知だけ失敗扱いにするか |
| タイムアウト | 応答遅延時にEA本体を止めないか |
| ログ粒度 | HTTP status、reason、masked detailをどこまで出すか |
| 機密情報 | endpoint、token、URLをログや画面に出さないか |
| 外部依存範囲 | 外部通信が失敗しても既存ポジション管理を続けるか |
外部通信は、OnTick内で無制限に呼ばない方が安全です。状態変化時、OnTimer、または一定間隔のsummary処理へ分けることで、EA本体の安定性を保ちやすくなります。
JSON応答を扱う時の注意点
外部サービスからJSON形式の応答を受け取る場合、文字列が返ってきたことと、EAが使える状態であることは別です。
JSON応答では、次のような確認が必要です。
| 確認項目 | 確認する理由 |
|---|---|
| 空応答ではないか | 通信は成功しても中身が空の場合がある |
| 期待するキーがあるか | 形式変更やエラー応答を検出するため |
| 値の型が想定どおりか | true / false、数値、文字列の誤解釈を防ぐため |
| 時刻や有効期限があるか | 古い応答を使わないため |
| 機密情報を含めていないか | ログへ出す前にマスクするため |
| 失敗応答を成功扱いしていないか | HTTP成功でも業務上NGの可能性があるため |
JSONを受け取ったら、そのまま売買判断へ使うのではなく、通信結果、形式確認、値の妥当性、外部状態の適用範囲を分けて扱います。
Webhook通知を売買処理と分ける理由
Webhook通知は、EAの状態や注文結果を外部へ知らせるために便利です。
ただし、通知は売買処理そのものではありません。通知処理と売買処理を混同すると、次のような問題が起きます。
| 混同例 | 起きる問題 |
|---|---|
| 通知成功を注文成功として扱う | 実際のOrderSend結果とずれる |
| 通知失敗でEA全体を止める | 注文や保護決済まで止まる可能性がある |
| Webhook URLをログへ出す | 通知先が漏れる |
| 毎tick通知する | 通知過多、外部サービス制限、ログ過多になる |
| 通知payloadに口座情報を入れる | 個人情報や機密情報の漏えいにつながる |
Webhook通知は、notification層として分け、送信成功・失敗をログで追えるようにします。通知失敗時に売買処理を止めるかどうかは、仕様として明確にします。
通信失敗時は安全側で扱う
外部連携EAでは、通信失敗時の扱いを最初に決めておく必要があります。
安全側の基本方針は、外部状態が不明な場合、無理に新規Entryへ進まないことです。一方で、既存ポジション管理まで止めるかどうかは慎重に判断します。
| 状態 | 新規Entry | 既存ポジション管理 | 理由 |
|---|---|---|---|
| 外部通信OK | 外部状態に従う | 通常どおり継続 | 外部状態が確認できるため |
| 外部通信失敗 | 停止または前回状態の扱いを仕様化 | 原則として保護処理は継続検討 | 新規Entryと保護処理は責務が違うため |
| 外部応答が不正 | 停止候補 | 必要な保護処理は継続検討 | 不正な外部値を使わないため |
| 通知だけ失敗 | 売買可否とは分ける | 売買可否とは分ける | 通知と注文実行は別責務のため |
「通信できないからEA全体を止める」のか、「新規Entryだけ止める」のか、「一定時間だけ前回状態を使う」のかは、EAの目的とリスク方針によって異なります。重要なのは、仕様として曖昧にしないことです。
実コード例1:外部通信結果を構造体で扱う
以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。実endpoint、token、URLは含めていません。
// 学習用に一般化した外部通信結果の例です。
// 実運用EAの完成ソースではありません。
enum ExternalStatus
{
EXT_STATUS_UNKNOWN = 0,
EXT_STATUS_OK,
EXT_STATUS_FAIL,
EXT_STATUS_TIMEOUT,
EXT_STATUS_INVALID_RESPONSE
};
struct ExternalFetchResult
{
ExternalStatus status;
int httpStatus;
string reason;
string maskedDetail;
datetime checkedAt;
};
ExternalFetchResult MakeExternalFail(string reason, string detail)
{
ExternalFetchResult result;
result.status = EXT_STATUS_FAIL;
result.httpStatus = 0;
result.reason = reason;
result.maskedDetail = detail;
result.checkedAt = TimeCurrent();
return result;
}外部通信の結果は、true / falseだけで扱うより、status、httpStatus、reason、maskedDetail、checkedAtを分けると確認しやすくなります。
特に、通信失敗、タイムアウト、形式不正、外部応答NGは別のreasonとして扱うべきです。
実コード例2:外部通信ログは機密情報をマスクする
以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。
// 学習用に一般化した外部通信ログ例です。
// 実運用EAの完成ソースではありません。
string MaskExternalText(string value)
{
string lower = StringToLower(value);
if(StringFind(lower, "token") >= 0)
return "masked";
if(StringFind(lower, "endpoint") >= 0)
return "masked";
if(StringFind(lower, "webhook") >= 0)
return "masked";
return value;
}
void WriteExternalLog(string eventName,
string reason,
const ExternalFetchResult &result)
{
Print("DIAG/EXTERNAL: event=", eventName,
" reason=", reason,
" status=", (int)result.status,
" http=", result.httpStatus,
" detail=", MaskExternalText(result.maskedDetail));
}外部連携ログでは、endpoint、token、Webhook URL、GAS URL、APIキー、口座番号、顧客情報を出さないことが重要です。
ログに必要なのは、実値ではなく、原因調査に使える分類です。たとえば、FETCH_FAIL、TIMEOUT、INVALID_RESPONSE、HTTP_STATUS_NGのように、reasonで整理します。
実コード例3:外部状態を新規Entryと既存管理へ分けて扱う
以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。外部シート制御や認証処理は含めていません。
// 学習用に一般化した外部状態の適用例です。
// 実運用EAの完成ソースではありません。
struct ExternalRuntimeState
{
bool externalReady;
bool allowNewEntry;
bool allowNotification;
string reason;
};
ExternalRuntimeState BuildExternalRuntimeState(const ExternalFetchResult &fetch)
{
ExternalRuntimeState state;
state.externalReady = false;
state.allowNewEntry = false;
state.allowNotification = false;
state.reason = "INIT";
if(fetch.status != EXT_STATUS_OK)
{
state.reason = "EXTERNAL_NOT_READY";
return state;
}
state.externalReady = true;
state.allowNewEntry = true;
state.allowNotification = true;
state.reason = "EXTERNAL_OK";
return state;
}
void ApplyExternalStateToEntry(const ExternalRuntimeState &state)
{
if(!state.allowNewEntry)
{
Print("DIAG/ENTRY: event=SKIP",
" reason=", state.reason,
" scope=NEW_ENTRY_ONLY");
return;
}
Print("DIAG/ENTRY: event=EXTERNAL_GATE_PASS",
" reason=", state.reason);
}この例では、外部状態を新規Entryの許可判断へ反映する考え方を示しています。ただし、既存ポジション管理や保護決済まで同時に止めるとは限りません。
新規Entry停止と既存ポジション管理は、必ず分けて設計します。
実コード例4:通知失敗を売買失敗と分ける
以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。実Webhook URLやpayloadは含めていません。
// 学習用に一般化した通知結果の扱い例です。
// 実運用EAの完成ソースではありません。
struct NotifyResult
{
bool sent;
string reason;
datetime sentAt;
};
NotifyResult SendNotificationSafe(string eventName, string messageSummary)
{
NotifyResult result;
result.sent = false;
result.reason = "NOT_SENT";
result.sentAt = TimeCurrent();
if(eventName == "")
{
result.reason = "EMPTY_EVENT";
return result;
}
// 実際のEAでは、ここで通知送信処理を別責務として扱います。
// 実Webhook URL、token、payload詳細はこの記事では扱いません。
result.sent = true;
result.reason = "NOTIFY_SEND_OK";
return result;
}
void TraceNotifyResult(const NotifyResult &result)
{
if(result.sent)
{
Print("DIAG/NOTIFY: event=SEND_OK",
" reason=", result.reason);
}
else
{
Print("DIAG/NOTIFY: event=SEND_FAIL",
" reason=", result.reason);
}
}通知処理は、notification層として分けます。通知失敗は、通知失敗としてログに残し、注文実行や決済結果と混同しないようにします。
外部連携でログに残すべき情報
外部連携の不具合調査では、実値ではなく、分類された状態が重要です。
| ログ項目 | 残す内容 | 出してはいけない内容 |
|---|---|---|
| event | FETCH_START、FETCH_OK、FETCH_FAIL、SEND_OK、SEND_FAIL | 実endpoint、実Webhook URL |
| reason | TIMEOUT、HTTP_STATUS_NG、INVALID_RESPONSE | token、APIキー |
| httpStatus | HTTPステータス番号 | 認証ヘッダー実値 |
| scope | NEW_ENTRY_ONLY、NOTIFICATION_ONLY、LOG_ONLY | 口座番号、顧客情報 |
| maskedDetail | マスク済みの要約 | GAS URL、Google Sheet ID、Webhook URL |
| checkedAt | 確認時刻 | 個人情報、購入者情報 |
外部連携では、ログが詳しすぎても危険です。問い合わせ時に共有される可能性を前提に、実値ではなく、分類・状態・reasonを残します。
外部通信をOnTickへ直接詰め込まない
外部通信は、OnTickへ直接詰め込まない方が安全です。
OnTickは価格更新ごとに呼ばれます。ここで毎回WebRequestを実行すると、EA全体が重くなり、バックテストやリアル運用でも不安定になりやすくなります。
| 避けたい設計 | 推奨する設計 |
|---|---|
| OnTickごとにWebRequestする | OnTimer、状態変化時、一定間隔へ分離する |
| 通信結果を即OrderSendへ直結する | ExternalRuntimeStateとして整理してからGATEへ渡す |
| 通信失敗でEA全体を停止する | 新規Entry、既存管理、通知の停止範囲を分ける |
| 通知成功を売買成功として扱う | ORDER_RESULTとNOTIFY_RESULTを分ける |
| 外部応答をそのままログへ出す | 必要項目だけマスクして出す |
外部通信は、EAの補助機能または外部状態取得として設計し、売買判定や注文実行と直接混ぜないことが重要です。
外部制御と認証を混同しない
外部連携EAでは、外部制御と認証を混同しないことも重要です。
外部制御は、外部状態に応じて動作を変える仕組みです。たとえば、新規Entryを止める、通知だけ止める、特定機能を一時停止するなどです。
一方、認証は、EAの利用許可や利用者権限を確認する仕組みです。
| 区分 | 役割 | 公開記事での扱い |
|---|---|---|
| 外部制御 | 外部状態に応じて動作を変える | 概念のみ扱う。詳細ロジックは公開しない |
| 認証 | 利用許可や購入者状態を確認する | 詳細ロジック、判定条件、tokenは公開しない |
| 通知 | 状態や結果を外部へ送る | 通知成功・失敗の扱いを説明する |
| ログ | 状態を追跡する | 機密情報をマスクしてreason中心にする |
認証NG、外部制御NG、通信失敗、通知失敗は、それぞれ意味が違います。ログ上もAUTH、EXTERNAL、NOTIFY、ORDERを分けて確認できるようにします。
よくある失敗例
失敗1:WebRequest失敗で売買処理全体を止める
通信失敗時に何を止めるかは仕様で分ける必要があります。新規Entryを止めるのか、通知だけ止めるのか、既存ポジション管理まで止めるのかを曖昧にすると危険です。
失敗2:Webhook URLやtokenをログへ出している
endpoint、token、Webhook URL、GAS URL、Google Sheet ID、APIキーをログへ出してはいけません。問い合わせ時にログが共有される前提で、必ずマスクします。
失敗3:通知失敗を注文失敗として扱う
通知と注文は別責務です。通知が失敗してもOrderSendが成功している場合があります。ORDER_RESULTとNOTIFY_RESULTを分ける必要があります。
失敗4:OnTickで毎回外部通信する
OnTickで毎回WebRequestを実行すると、EAが重くなり、通信制限やタイムアウトの原因になります。OnTimerや状態変化時に分ける方が安全です。
失敗5:JSON応答をそのまま信じる
JSON文字列が返っただけでは、EAが使える状態とは限りません。形式、必須項目、値の型、有効期限、失敗応答を確認する必要があります。
失敗6:外部制御と認証を混同する
外部制御は運用状態の制御、認証は利用許可の確認です。意味が違うため、ログも停止範囲も分ける必要があります。
失敗7:通信失敗時のログがない
外部連携の問題は、ログがないと原因を追えません。HTTPステータス、reason、scope、checkedAtをマスク済みで残す設計が必要です。
導入前・開発依頼前に整理する情報
外部連携EAを開発・改修する場合、次の情報を整理しておくと仕様確認がスムーズになります。
- 外部連携の目的
- 通知だけなのか、外部状態取得も行うのか
- WebRequestを使うタイミング
- 通信頻度
- 通信失敗時に止める範囲
- 新規Entryと既存ポジション管理の扱い
- 通知失敗時に売買へ影響させるか
- JSON応答の必須項目
- 外部応答の有効期限
- ログに残す項目
- ログに出してはいけない機密情報
- 開発版と配布版で見せる設定項目の違い
- 問い合わせ時に送るログとマスク方法
外部連携は、便利な機能である一方、通信失敗、機密情報、サポート対応の設計が必要です。最初に責務分離と失敗時の扱いを決めておくことが重要です。
関連する技術講座・確認ページ
| ページ | 確認できること |
|---|---|
| 技術講座ハブ | MQL5やMT5開発に関する講座一覧 |
| MQL5デバッグ・ログファースト開発完全ガイド | ログ確認、デバッグ、原因調査の基本 |
| MQL5ファイル操作・CSVログ出力完全ガイド | ログ保存、CSV出力、検証記録の基本 |
| MT5開発依頼前に用意する資料まとめ | 仕様書、setファイル、ログ、スクリーンショットの整理 |
| 不具合報告・調査依頼について | 不具合相談前に送る情報 |
| よくある質問 | 導入、確認、相談前のFAQ |
| 免責事項・リスク説明 | 投資判断、損益、利用上の注意に関する確認 |
FAQ
WebRequestを使えばEAは外部サービスと自由に連携できますか?
WebRequestを使うことで外部通信は可能になりますが、MT5側の許可設定、通信先の応答、タイムアウト、payload形式、サービス側の制限などを考慮する必要があります。EA本体の売買処理とは責務を分けるべきです。
通信失敗時はEAを止めるべきですか?
目的によります。新規Entryを止めるのか、通知だけ失敗扱いにするのか、既存ポジション管理まで止めるのかを仕様として決める必要があります。一般には、新規Entryと既存ポジション管理は分けて扱う方が安全です。
Webhook通知が失敗した場合、注文も失敗したという意味ですか?
違います。Webhook通知とOrderSendは別責務です。通知が失敗しても注文が成功している場合があります。ORDER_RESULTとNOTIFY_RESULTを分けて確認します。
JSON応答はそのまま売買判断に使ってよいですか?
避けるべきです。空応答、形式不正、必須項目不足、古い応答、失敗応答を確認し、外部状態として整理したうえでGATEやexternal controlへ渡します。
外部連携ログには何を出すべきですか?
event、reason、HTTP status、scope、checkedAt、マスク済みdetailなどを出します。endpoint、token、Webhook URL、GAS URL、APIキー、口座番号、顧客情報は出してはいけません。
OnTickで毎回WebRequestしてもよいですか?
避けた方が安全です。OnTickは呼び出し頻度が高いため、通信処理はOnTimer、状態変化時、一定間隔などへ分離する方が安定しやすくなります。
外部制御と認証は同じですか?
違います。外部制御は外部状態に応じた動作制御、認証は利用許可や権限の確認です。ログも停止範囲も分けて設計する必要があります。
実装コードがなくても外部連携設計の相談はできますか?
可能です。連携目的、通信タイミング、失敗時の扱い、通知内容、ログに出す項目、マスクすべき情報が整理されていれば、外部連携設計の相談は進めやすくなります。
関連する開発実務ノート
外部連携を含むEAでは、通信処理だけでなく、EA本体の責務分離、ログ設計、バックテストとの差分、配布前の機密情報管理も重要です。
- MQL5 EA設計実務ノート|signal・execution・risk・exitを分ける理由
- MQL5ログファースト開発実務ノート|不具合調査しやすいEA・インジの作り方
- MQL5バックテスト実務ノート|検証条件・最適化・リアル差分を記録する考え方
- MQL5商品化・配布前チェック実務ノート|Inputs・HELP・Snapshot・manual・UserLive化の基本
まとめ
MQL5 EAでWebRequest、JSON、Webhookを扱う場合、外部連携を売買ロジックへ直接混ぜないことが重要です。
特に、次の4点を分けておくと、通信失敗や通知失敗が起きた時に原因を切り分けやすくなります。
- external communication:外部通信の成功・失敗・タイムアウトを扱う
- external control:外部状態をEAの動作制御へどう反映するかを扱う
- notification:Webhook通知や外部通知の送信結果を扱う
- execution / exit:注文実行や既存ポジション管理を外部通信と混同しない
外部通信が失敗した時に、新規Entryを止めるのか、既存ポジション管理を継続するのか、通知だけ失敗扱いにするのかは、仕様として明確にする必要があります。
また、endpoint、token、Webhook URL、GAS URL、Google Sheet ID、APIキー、口座番号、顧客情報は、本文・コード例・ログ例・スクリーンショットのいずれにも出してはいけません。
完成EAの外部制御ロジックや認証処理を公開しなくても、外部連携の責務分離、通信失敗時の安全側処理、ログ設計を理解しておくことで、開発依頼、既存EA改修、検証、不具合調査、販売後サポートの品質を上げやすくなります。

