【移植#51】指値注文を通信に使わない — 期限付き停止指令を検証するリモートHALTガード¶

この記事の3行まとめ
- 指値注文を通信メッセージにせず、HTTPSの短い応答から
HALTとRESUMEだけを受け取ります - 期限切れ、未来時刻、別チャンネル、別対象、古い連番は拒否し、異常な応答で停止状態を解除しません
- 専用MT5では6つの状態遷移を自己テストし、注文・ポジションを変えずに最終
HALTを確認しました
今回の原典は「別PCのEAを止めたい」¶
投稿日順で次に当たる2010年2月9日の記事は、同じ口座へ接続した別PCのMT4へ、緊急停止の意思を伝える方法を考えています。
想定されていたのは、VPSへログインできないときでも、自宅PCから停止命令を出したい場面です。
原典では、約定しないほど離れた指値注文へ特定のマジックナンバーを付け、その注文を別PCのEAが見つけたら停止する案が示されています。
発想の中心は今も大切です。
- 管理画面へ入れない経路障害にも備える
- 複数PCへ同じ停止意思を伝える
- 通常の売買条件と緊急停止を分ける
ただし、注文は通信パケットではありません。
相場が大きく動く、価格桁や銘柄仕様を取り違える、注文コメントが変わる、ブローカー側の制限に触れる、といった条件が重なると、「絶対に約定しない」という前提は崩れます。
そこで今回は、注文を使う部分を採用しません。
注文ゼロの「停止指令受信EA」へ置き換えた¶
移植版は、複数PCのMT5が同じHTTPSエンドポイントを定期確認するExpert Advisorです。
受け取る命令は2種類だけです。
| 命令 | 役割 |
|---|---|
HALT | 端末内の停止フラグを1へラッチする |
RESUME | 条件を満たす新しい命令に限り、停止フラグを0へ戻す |
このEA自身は、次の操作を行いません。
- 新規注文
- 注文変更・取消
- ポジション決済
- 自動売買ボタンの切り替え
- MT5やWindowsの終了
役割は、受信内容を検査して、同じ端末のMQL5プログラムから読める停止フラグを更新するところまでです。
実際に新規エントリーを止めるには、稼働中EA側にもフラグ確認を組み込みます。既存ポジションを維持するか、決済するか、損切りを動かすかは戦略ごとに異なるため、この受信EAが勝手に決める設計にはしませんでした。
なぜインジケーターではなくEAなのか¶
外部のHTTPS応答はWebRequest()で取得します。
WebRequest()は同期処理です。応答を待つ間、そのMQL5プログラムの処理は止まります。また、共通スレッドで動くインジケーターからは呼び出せず、EAまたはスクリプトで使う必要があります。
そこで、価格Tickへ依存しないOnTimer()で定期確認するEAにしました。
int OnInit()
{
EventSetTimer(InpPollSeconds);
return INIT_SUCCEEDED;
}
void OnTimer()
{
PollHttps();
}
WebRequest()を使うURLは、利用者がMT5の「ツール」→「オプション」→「エキスパートアドバイザ」で許可リストへ追加する必要があります。プログラムから勝手に許可先を増やすことはできません。
この明示許可は少し手間ですが、ダウンロードしたEAが知らない接続先へ通信しないための大事な境界です。
1行8項目だけを受け取る¶
応答形式は、複雑なJSONではなく、最大512 bytesの1行に固定しました。
時刻はUTCのUnix秒です。
| # | 項目 | 検査 |
|---|---|---|
| 1 | プロトコル | MQLP51と完全一致 |
| 2 | 版 | 1と完全一致 |
| 3 | チャンネル | EAの入力値と完全一致 |
| 4 | 対象 | EAのInpScopeTagと完全一致 |
| 5 | 連番 | 前回受理した値より大きい正整数 |
| 6 | 命令 | HALTまたはRESUME |
| 7 | 発行時刻 | 許容秒数を超えて未来でない |
| 8 | 失効時刻 | 現在より新しく、有効期間上限以内 |
改行を含む応答、項目数違い、数値の後ろに文字が付いた値も拒否します。
「だいたい合っている」応答を善意に補正すると、停止対象を取り違える余地が増えます。そのため、チャンネルや対象名は大文字小文字も含めて完全一致にしました。
停止状態はラッチする¶
通信に失敗したとき、停止中だったEAが勝手に再開するのは危険です。
今回の状態遷移は、次のようにしました。
| 現在 | 受信 | 結果 |
|---|---|---|
RUN | 新しい有効なHALT | HALTへ移る |
HALT | 新しい有効なRESUME | RUNへ移る |
HALT | 期限切れ・形式違い・通信失敗 | HALTを維持 |
HALT | 同じ連番の再送 | HALTを維持 |
RUN | 無効な応答 | RUNを維持 |
初めてHTTPSモードを起動し、保存済み状態がない場合は、初期設定でHALTから始まります。
ネットワークが使えないことを「停止命令なし」と読み替えません。正常なRESUMEを1度受け取ってRUNへ移った後は、その状態を保存しつつ、異常な応答で状態を書き換えない設計です。
停止フラグと最後の連番は、GlobalVariableSet()でクライアント端末のグローバル変数へ保存します。
端末グローバル変数は、MQL5ソース内のグローバル変数とは別物です。同じMT5端末内の別プログラムから読めますが、別PCへ直接同期される機能ではありません。
各PCの受信EAが同じHTTPSエンドポイントを確認し、それぞれ自分の端末内フラグを更新する構成です。
稼働EA側は新規エントリーの直前で確認する¶
たとえば、チャンネル名を固定して使うEAなら、新規注文を組み立てる前に次のように確認できます。
bool RemoteHaltActive()
{
const string key = "MQLP51.mql-port-51.halt";
if(!GlobalVariableCheck(key))
return true; // 受信EA未確認を安全側に倒す例
return GlobalVariableGet(key) >= 0.5;
}
void CheckEntry()
{
if(RemoteHaltActive())
return;
// ここから先で通常の新規エントリー判定を行う
}
この例は「新規エントリーを止める」だけです。
既存ポジションの管理まで止めると、損切りやトレーリングも止まる可能性があります。通常は、停止中も既存ポジションの保護処理を続け、新規発注の直前だけを遮断する方が境界を説明しやすくなります。
複数口座や複数戦略を同じ端末で動かす場合は、チャンネル名を分けてください。端末グローバル変数は口座へ自動的にひも付きません。
Bearer tokenは通信先の認証にだけ使う¶
HTTPSモードでは、次のヘッダーを付けてGETします。
配布ファイルに実トークンは入っていません。画面にもトークンを表示しません。
入力値は次の条件を満たさないと初期化を拒否します。
- URLが
https://で始まる - Bearer tokenが16〜256文字
- URLとtokenに改行がない
- タイムアウトが250〜10,000 ms
- 確認間隔が1〜300秒
- 命令の最大有効期間が10〜3,600秒
ただし、MT5の入力値は秘密保管庫ではありません。設定ファイルや画面共有へtokenを残さず、漏えい時に失効できる専用tokenを使ってください。
また、このEAは証明書ピンニングや応答への電子署名を実装していません。TLSとサーバー側のBearer認証を前提にした最小構成です。より高い保証が必要なら、鍵管理、署名、監査ログ、冗長な停止経路を含む別設計が必要です。
6ケースをローカル自己テストした¶
WebRequest()はストラテジーテスターでは実行されません。さらに、この記事では実在の制御サーバーや認証情報を検証用に用意していません。
そこで配布EAの初期設定をMQLP51_SELF_TESTにし、専用MT5のライブチャート上で、通信を発生させず受信後の検査と状態遷移を確認しました。
実行条件¶
| 項目 | 値 |
|---|---|
| MT5 Build | 6061 |
| チャート | EURUSD・H1 |
| 通信 | なし(ローカル自己テスト) |
| 初期状態 | HALT |
| 注文 / ポジション | 0 / 0 |
テストケース¶
| ケース | 期待 | 結果 |
|---|---|---|
新しい期限内HALT | 受理して停止 | 合格 |
期限切れRESUME | 拒否して停止維持 | 合格 |
別対象RESUME | 拒否して停止維持 | 合格 |
| 同じ連番の再送 | 拒否して停止維持 | 合格 |
新しい期限内RESUME | 受理して再開 | 合格 |
さらに新しいHALT | 受理して再停止 | 合格 |
実測結果¶
| 確認項目 | 結果 |
|---|---|
| 配布EAのコンパイル | 0エラー・0警告 |
| 状態遷移 | 6 / 6合格 |
| 受理 / 拒否 | 3 / 3 |
| 最終連番 | 102 |
| 最終状態 | HALT |
| 注文件数 | 0 → 0 |
| ポジション件数 | 0 → 0 |
| 実画面キャプチャー | 成功 |
画像はこの自己テストの実画面です。SOURCE: LOCAL SELF-TESTと表示しているとおり、HTTPS到達性、サーバー認証、複数PCへ届く時間は未検証です。
コンパイル成功とローカル状態遷移の合格を、外部停止経路全体の動作保証へ広げてはいけません。
ダウンロードと使い方¶
51_Remote_Halt_Guard_v1_00.mq5 をダウンロード
まず、初期設定の自己テストで画面とログを確認してください。
実環境へ接続するときは、デモ口座とテスト用EAから始めます。
- HTTPSで1行の命令を返す認証付きエンドポイントを用意します
- MT5の許可URLへ、その接続先を追加します
- EAの
InpSourceModeをMQLP51_HTTPSへ変更します - URL、専用Bearer token、チャンネル、対象名を設定します
- 稼働EAの新規エントリー直前へ停止フラグ確認を追加します
HALT、通信断、期限切れ、再送、RESUMEをデモ環境で順に確認します
主な入力値は次のとおりです。
| パラメーター | 初期値 | 役割 |
|---|---|---|
InpSourceMode | MQLP51_SELF_TEST | ローカル検証 / HTTPS |
InpEndpointUrl | 空欄 | HTTPSエンドポイント |
InpAuthToken | 空欄 | 専用Bearer token |
InpChannel | mql-port-51 | 指令チャンネル |
InpScopeTag | demo-fleet | 対象グループ |
InpPollSeconds | 5 | 確認間隔 |
InpHttpTimeoutMs | 3000 | 1回の待ち時間上限 |
InpAllowedFutureSkewSec | 30 | 未来時刻の許容 |
InpMaxCommandLifetimeSec | 300 | 指令の有効期間上限 |
InpFailSafeOnStartup | true | 保存状態がない初回を停止から始める |
使えないこと・注意点¶
- 配布EAだけでは、他のEAの新規発注は止まりません。各EA側のフラグ確認が必要です。
- 自動売買ボタン、MT5、Windows、VPSを遠隔終了する機能ではありません。
- 既存ポジションを決済しません。停止時のポジション管理方針は戦略側で決めます。
- HTTPSエンドポイントやサーバー実装は付属しません。
WebRequest()はストラテジーテスターで動きません。- HTTPSは同期処理です。タイムアウトを長くしすぎると受信EAの応答が遅くなります。
- 端末グローバル変数は別PCへ自動同期されません。各PCで受信EAを動かします。
- 端末グローバル変数は口座へ自動的にひも付きません。チャンネル設計が必要です。
- 連番を巻き戻すと命令を拒否します。サーバー側で単調増加を維持してください。
- tokenを公開コード、画像、共有設定へ入れないでください。
- 自己テスト合格は、実際のHTTPS経路や障害時運用の合格を意味しません。
ロジック評価の結論¶
原典の強みは、普段使うログイン経路が壊れたときのために、別の停止経路を考えたことです。
一方、売買注文を通信へ流用すると、「停止したいのに注文リスクを増やす」というねじれが生まれます。
今回の移植では、停止意思の受信と売買処理を分離しました。
- 通信は明示許可したHTTPSだけ
- 命令は短命な
HALT/RESUMEだけ - 対象、時刻、連番をすべて検査
- 無効な応答で停止を解除しない
- 受信EAは注文APIを使わない
- 戦略EAは新規エントリー直前でフラグを見る
これで「別PCから止めたい」という目的を、注文をメッセージにする方法から切り離せます。
ただし、本当に緊急停止へ使うなら、コードだけで終わりではありません。制御サーバーの可用性、token失効、時計ずれ、通信断、端末再起動、監視通知、手動復旧を含めた運用テストが必要です。
止める仕組みほど、正常時より「壊れたときに何を維持するか」を先に決める。
今回のHALTラッチで一番移植したかったのは、その考え方です。
前後の記事¶
前: 【移植#50】12通貨の指標値を1枚へ — 確定足を揃えるトレンド・コンセンサス
次: 【移植#52】HST直書きをやめる — 日足CSVをMT5カスタムシンボルへ安全に取り込む