【移植#46】DDEをやめて共有ファイルへ — Excel→MT5の文字列受信を安全にする¶

この記事の3行まとめ
- 古いDDEクライアントを再現せず、Excel等が出力したUTF-8ファイルをMT5が読み取る方式へ変更しました
- 更新時刻、必須ヘッダー、空欄、未来時刻、期限切れを検査し、異常なメッセージは受理しません
- 実機では日本語を含む90バイトのファイルを6回以上連続で読み、9バッファを独立照合しました
今回の原典は「MT4をDDEクライアントにする」¶
投稿日順で次に当たる2010年2月4日の記事は、ExcelのセルをMT4側から読むDDE連携を試していました。
元記事「MetaTrader4をDDEクライアントにする。」を読む
DDEはDynamic Data Exchangeの略で、Windows上のアプリケーション間でデータを交換する仕組みです。原典ではExcelをDDEサーバー、MT4をクライアントとして、指定したシートのセルをティックごとに読み取っていました。
ただし、記事の時点ですでに次の注意点が書かれています。
- Excelで対象セルを編集中だと値を取得できない
- 対象ファイルを開いていないとエラーになる
- 日本語や半角スペースを含む指定は動かない可能性がある
- 返された文字列に
errorが含まれる場合は、必ずエラー処理が必要
そして原典の結論も、「Excelからファイル出力してEAが読む方が単純で分かりやすい」というものでした。
今回は、その最後の提案を現在のMT5向けに実装します。
DDEのセル参照を「1件の受信箱」へ置き換える¶
配布インジケーターは、MT5の共有ファイル領域に置かれたCSVを1秒ごとに確認します。初期設定のファイル名は次のとおりです。
内容は、ヘッダー1行とデータ1行です。
| 列 | 役割 |
|---|---|
updated_at | メッセージを作成したローカル時刻 |
source | 出力元を区別する短い名前 |
message | MT5へ渡す文字列 |
Excel、VBA、Pythonなどの出力側は、この3列をUTF-8で書き出します。MT5側は読み取り専用で、ファイルの内容を書き換えません。
文字列は表示するだけです。BUYやSELLと書かれていても注文へ変換しないため、このインジケーター単体で売買が発生することはありません。
MT5のファイルサンドボックス内だけを読む¶
MQL5のFileOpen()は、セキュリティのため読み書きできる場所をファイルサンドボックス内へ制限しています。
今回はFILE_COMMONを指定し、同じPC上のMT5端末が共有できるTerminal\Common\Files領域を使います。端末固有のMQL5\Filesではないため、Excel等の出力先を1か所へ固定しやすくなります。
FileOpen(file_name,
FILE_READ | FILE_CSV | FILE_ANSI |
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_COMMON,
';', CP_UTF8);
各フラグには次の役割があります。
| フラグ | 目的 |
|---|---|
FILE_READ | MT5側は読み取りだけ行う |
FILE_CSV | セミコロン区切りの列として読む |
FILE_ANSI + CP_UTF8 | UTF-8バイト列をMQL5文字列へ変換 |
FILE_SHARE_READ | 他の読取処理と共有する |
FILE_SHARE_WRITE | 出力側が更新中でもファイルを開けるようにする |
FILE_COMMON | MT5共通ファイル領域を使う |
共有書込みを許可していても、書込み途中の行を受理してよいわけではありません。そのため、MT5側でもファイルサイズ、ヘッダー、列、時刻、空欄を確認します。初期設定では4,096バイトを超えるファイルを開かず、INVALIDとして拒否します。
出力側は完成した一時ファイルを書いてから、対象名へ置き換える方式が安全です。対象ファイルを開いたまま1文字ずつ更新すると、読み取りの瞬間に不完全な内容が見える可能性があります。
ティックではなくタイマーで確認する¶
原典はティック更新ごとにExcelのセルを見に行く構成でした。しかし、ティックが来ない時間帯には確認処理も止まります。
今回はOnTimer()を使い、初期設定では1秒ごとにファイルを確認します。
終了時にはEventKillTimer()を呼びます。
これにより、相場のティック頻度と外部メッセージの確認頻度を分離できます。ただし1秒ポーリングは低遅延取引向けではありません。人がExcel等で更新した情報を、監視・補助表示する用途を想定しています。
文字列ではなく状態でエラーを分ける¶
原典では、失敗時にerrorを含む文字列が返るため、通常のセル値と区別する必要がありました。
今回はメッセージ本文へエラーを混ぜず、状態コードを分けています。
| 状態 | 意味 | メッセージの扱い |
|---|---|---|
READY | 必須項目と鮮度が正常 | 受理して表示 |
MISSING | ファイルがない | 受理しない |
STALE | 更新時刻が期限を超過 | 受理しない |
INVALID | ヘッダー、時刻、空欄などが不正 | 受理しない |
I/O ERROR | ファイルを開けない、属性を読めない | 受理しない |
FUTURE TIME | 許容範囲を超える未来時刻 | 受理しない |
初期設定では、updated_atが現在時刻より60秒以上古ければSTALEです。PC間やアプリ間で時計が少しずれる場合に備え、未来方向には5秒の許容幅を設けています。
エラー状態へ変わると、以前のメッセージをそのまま有効扱いせず、送信元と本文を空にします。最後に成功した指示が残り続ける事故を避けるためです。
ファイルの更新時刻も別に確認する¶
CSV内のupdated_atだけでは、出力側が古い時刻を誤って書いたのか、ファイル自体が更新されていないのかを区別しにくくなります。
そこでFileGetInteger()から、次の属性も取得します。
FILE_EXISTSFILE_SIZEFILE_MODIFY_DATE
パネルには、メッセージ内の時刻から計算した年齢と、ファイル更新時刻から計算した年齢を別々に表示します。
両方が近ければ、出力処理が現在時刻を書いて保存したと考えられます。大きくずれていれば、時刻の生成、保存、コピーのどこで遅れたかを調べる手掛かりになります。
9バッファを別経路で照合した¶
画面表示だけを合格条件にせず、配布インジケーターは9本の診断バッファを公開します。
READYか- 状態コード
- メッセージの経過秒数
- 読取試行回数
- 正常読取回数
- ファイルサイズ
- ファイル更新からの経過秒数
- 受理したメッセージの文字数
- 最後のI/Oエラーコード
検証EAは、日本語を含むUTF-8のCSVを共有ファイル領域へ作成しました。インジケーターとは別に同じファイルを開き、ヘッダー、送信元、本文、時刻を読み直してから、9バッファと照合しています。
実行条件¶
| 項目 | 値 |
|---|---|
| MT5 Build | 5836 |
| 通貨・時間足 | EURUSD・H1 |
| 区切り文字 | セミコロン |
| 文字コード | UTF-8 |
| 送信元 | CAPTURE_FIXTURE |
| メッセージ | EURUSD HOLD / 日本語OK |
| 期限 | 60秒 |
検証結果¶
| 確認項目 | 結果 |
|---|---|
| 配布インジケーターのコンパイル | 0エラー・0警告 |
| 独立検証EAのコンパイル | 0エラー・0警告 |
| 状態 | READY |
| ファイルサイズ | 90バイト |
| メッセージ文字数 | 19 |
| 正常読取 | 6回以上連続成功 |
| パネルオブジェクト | 11 |
| 診断バッファ | 9本一致 |
| 実画面キャプチャー | 成功 |
| 検証用ファイルの後片付け | 成功 |
| 売買注文 | なし |
画面では読取回数がさらに進んでいますが、検証EAが合格判定に使った時点では6回連続で正常でした。スクリーンショット取得後、検証用CSVを削除し、共有領域へテスト値を残していません。
ダウンロードと使い方¶
46_Common_File_Message_Inbox_v1_00.mq5 をダウンロード
MT5のIndicatorsへ保存してコンパイルし、任意のチャートへ適用してください。
初期設定では、MT5の共通ファイル領域に次のファイルを用意します。
UTF-8、セミコロン区切りで、ヘッダー名を変更せずに保存してください。
入力パラメーターは次のとおりです。
| パラメーター | 初期値 | 役割 |
|---|---|---|
InpFileName | MQL46\message_inbox.csv | 共通領域内の相対ファイル名 |
InpPollSeconds | 1 | 読取間隔 |
InpMaxAgeSeconds | 60 | 受理する最大経過秒数 |
InpFutureToleranceSec | 5 | 未来時刻の許容秒数 |
InpMaxFileBytes | 4096 | 読み始めるファイルサイズの上限 |
InpShowPanel | true | 診断パネルを表示 |
Excel等の出力側とMT5側で、区切り文字、文字コード、時刻形式を揃えてください。
使えないこと・注意点¶
- このインジケーターはDDEクライアントではなく、DDEのセルを直接読みません。
- CSVの1件目だけを受信箱として扱い、複数メッセージのキュー処理は行いません。
- ファイルの確認間隔は最短でも設定した秒単位で、低遅延通信には向きません。
- 出力側が書込み途中のファイルを見せないよう、一時ファイルからの置換を推奨します。
updated_atはMT5を動かすPCのローカル時刻と比較します。別PCから書く場合は時計を同期してください。- UTF-8以外で保存したファイルは、日本語が文字化けする可能性があります。
- 初期値では4,096バイトを超えるファイルを拒否します。長文用途へ広げる場合も必要最小限にしてください。
- 状態が
READYであっても、メッセージ内容の業務上の正しさまでは検証できません。 - このインジケーターは表示専用で、注文、変更、取消、ポジション管理を行いません。
- 外部文字列を自動売買へ接続する場合は、許可値、署名、連番、再送防止など別の安全設計が必要です。
ロジック評価の結論¶
原典のDDE実験は、ExcelのセルをMT4へ渡せる一方、セル編集中やファイル未起動を文字列エラーとして処理する必要がありました。そして記事自身が、ファイル連携の方が単純だと結論づけています。
今回はその提案を、MT5のファイルサンドボックス、共有領域、UTF-8、更新時刻、状態コードで具体化しました。
DDEのリアルタイム性は失いますが、受け渡した内容をファイルとして確認でき、期限切れや形式不正を明示的に拒否できます。人が管理する表計算とMT5をつなぐ用途では、「速さ」より「何を受け取ったか追えること」の方が大切な場面があります。
外部から届いた文字列を、成功値かエラー文字列かだけで判断しないこと。形式、鮮度、送信元、失敗状態を別々に持つこと。それが、古いDDE連携から今も引き継げる一番大切な教訓です。
前後の記事¶
前: 【移植#45】MTF補間を確定足だけで再設計 — 30分足バンドを5分足へ滑らかに投影する
次: 【移植#47】生のHSTを読まずに履歴を一括CSV化 — 3通貨×500本をCopyRatesで書き出す