コンテンツにスキップ

【移植#49】DLL共有メモリをやめて共通ファイルへ — 2つのMT5価格を鮮度付きで比較する

共通ファイルで読んだEURUSD価格とローカル価格の差、鮮度、送信元、検証結果を表示したMT5画面

この記事の3行まとめ

  • 共有メモリDLLを使わず、同じPC上のMT5同士でBidとAsk、更新時刻を受け渡します
  • 一時ファイルからの置換、送信元・銘柄・価格・未来時刻・鮮度の検査で書きかけや取り違えを拒否します
  • 実機では正常データ15バッファに加え、期限切れ・未来時刻・送信元違い・銘柄違いの拒否を独立検証しました

今回の原典は「共有メモリで他業者の価格を読む」

投稿日順で次に当たる2010年2月7日の記事は、あるMT4で受け取ったGBPJPY価格を、別業者のMT4から参照する実験でした。

元記事「MT4他業者の価格を表示させる。/共有メモリの活用。」を読む

原典では、書込側と読取側がMemMap.dllを読み込み、同じタグ名で文字列を受け渡していました。ファイルを毎回読み書きする代わりに、Windowsの共有メモリを「メモリ上のファイル」のように使う発想です。

ただし、記事自身も用途には慎重でした。

  • 業者間裁定が成立するかは分からない
  • 複数価格からシステム異常を検出できるかも分からない
  • まずは再利用できる道具として試した

今回も、この距離感を引き継ぎます。

作るのは、2つの価格を観測して差を表示する道具です。価格差が見えたことを、約定可能な利益や売買シグナルとは扱いません。


MT5標準の共通フォルダーへ置き換える

MQL5のFileOpen()FILE_COMMONを指定すると、同じPC上のMT5端末が共通で使うファイル領域を読み書きできます。

MQL
FileOpen(
   file_name,
   FILE_READ | FILE_CSV | FILE_ANSI |
   FILE_COMMON | FILE_SHARE_READ | FILE_SHARE_WRITE,
   ';',
   CP_UTF8
);

通常のMQL5\Filesは端末ごとに分かれています。一方、FILE_COMMONはそのPC上の端末で共有されるため、ジャンクションや任意パスへのWindows API呼出しを用意しなくても、端末間連携を試せます。

今回の配布インジケーターは、次の2モードを持ちます。

モード 役割
PUBLISH 現在のチャート銘柄のBid・Ask・時刻を共通ファイルへ書く
COMPARE 共通ファイルを読み、現在のチャート価格との差を表示する

書込側と比較側へ同じインジケーターを入れ、モードだけを変えます。

DLLインポート、注文、ポジション変更、任意の絶対パスへの書込みはありません。


1つのチャンネルには1つの書込側だけを置く

初期チャンネル名は次のとおりです。

Text Only
EURUSD_FEED_A

書込側は、この名前に対応する1個のCSVを更新します。比較側は同じチャンネル名を指定して読みます。

チャンネル名と送信元別名には、半角英数字、_-だけを使えます。区切り文字やパス記号を入力できないようにし、意図しない別フォルダーや別形式を指さないようにしました。

1つのチャンネルへ複数の書込側を置くと、最後に置換した価格だけが残ります。複数の価格元を比べる場合は、価格元ごとにチャンネル名を分けてください。


書きかけのCSVを読ませない

書込側が最終ファイルを直接開いている途中に比較側が読むと、項目の一部しかない状態を拾う可能性があります。

そこで、書込側は次の順に更新します。

  1. 送信元別名を含む一時ファイルへ全項目を書く
  2. FileFlush()して閉じる
  3. FileMove()で最終ファイルへ置換する
MQL
FileMove(
   temp_name,
   FILE_COMMON,
   feed_name,
   FILE_COMMON | FILE_REWRITE
);

比較側に見せる名前へ移すのは、書込みが終わってからです。

これはOSや端末が落ちないことを保証する仕組みではありません。途中状態を見せにくくする更新手順です。移動に失敗した場合は成功扱いにせず、画面へREPLACE FAILEDを表示します。


11項目をひとかたまりで渡す

共通ファイルの1行には、次の項目をセミコロン区切りで保存します。

# 項目 役割
1 マジック文字列 このインジケーターの形式か確認
2 形式バージョン 将来の項目変更を区別
3 送信元別名 想定した端末か確認
4 実際の銘柄名 画面表示と監査用
5 正規化した銘柄キー 接頭辞・接尾辞が異なるFX銘柄を照合
6 小数桁 送信元価格の表示精度
7 送信元の1 point 送信元スプレッドの単位
8 Bid 送信元の売値
9 Ask 送信元の買値
10 Tick時刻(ミリ秒) 価格自体の更新時刻
11 公開時刻(GMT秒) ファイルの鮮度判定

SymbolInfoTick()でBid、Ask、Tick時刻を1回にまとめて取得します。BidとAskを別々のタイミングで読む構成にはしていません。


期限切れと未来時刻を拒否する

ファイルが読めても、新しい価格とは限りません。

端末が異常終了すると、最後のファイルが残る場合があります。古い価格を現在値として扱わないよう、比較側は公開時刻と現在のGMT時刻を照合します。

初期設定の有効期限は5秒です。

状態 判定
現在より2秒を超えて未来 FUTURE TIMESTAMP
現在より5秒を超えて古い STALE
範囲内 次の検査へ進む

2秒の未来許容は、同じPC上でもイベント処理の境界で1秒程度ずれる可能性を考えたものです。20秒先のような値は受理しません。

書込側を正常に外したときは、初期設定で自分のチャンネルを削除します。ただし、端末やPCの強制終了では削除処理が走らないことがあります。その場合も鮮度検査が防波堤になります。


送信元と銘柄が違えば価格を表示しない

チャンネル名が合っているだけでは、取り違えを防ぎきれません。

比較側は、次の一致も確認します。

  • ファイル内の送信元別名がInpExpectedPeerAliasと一致する
  • ファイル内の銘柄キーが現在のチャート銘柄と一致する
  • ファイル内の銘柄名を正規化し直しても同じキーになる

主要FX通貨では、EURUSDの前後にブローカー固有の文字が付いていても、通貨ペア部分を探してEURUSDへそろえます。これにより、たとえばEURUSDEURUSD.aのような違いを吸収できます。

一方、送信元別名は暗号学的な認証ではありません。共通ファイル領域を読み書きできる別プログラムからの改変を防ぐ仕組みではなく、設定ミスによる取り違えを検出するための印です。

口座番号、口座名、サーバー名、認証情報はファイルへ書きません。


価格差は比較側のpoint単位で表示する

中央価格は、BidとAskの平均です。

Text Only
送信元の中央価格 = (送信元Bid + 送信元Ask) / 2
比較側の中央価格 = (比較側Bid + 比較側Ask) / 2

画面のMID DIFFは、次の式で表示します。

Text Only
(送信元の中央価格 - 比較側の中央価格) / 比較側の1 point

正なら送信元の中央価格が高く、負なら低い状態です。

5桁表示のFX通貨で+25.0 local pointsなら、価格差は2.5 pipsに相当します。

ただし、これは表示時点の気配値差です。次の要素は含みません。

  • 実際に約定できる数量
  • 約定遅延とスリッページ
  • 手数料とスワップ
  • 入出金や資金移動の制約
  • 注文拒否、最小距離、取引時間
  • 同時に両側を約定できる保証

この数値だけから業者間裁定の収益性は判断できません。


15バッファと4つの拒否ケースを独立検証した

画面が見えるだけでなく、配布インジケーターは15本の診断バッファを公開します。

  1. データが全検査に合格したか
  2. 実行モード
  3. 更新回数
  4. 公開からの経過秒数
  5. 送信元Bid
  6. 送信元Ask
  7. 比較側Bid
  8. 比較側Ask
  9. 中央価格差
  10. 送信元スプレッド
  11. 比較側スプレッド
  12. 状態コード
  13. 表示オブジェクト数
  14. 送信元Tick時刻
  15. 比較側Tick時刻

専用の検証EAは、配布インジケーターが読むものと同じ11項目形式を独立に書き、ファイルを読み戻してから各バッファと照合しました。

さらに正常データを表示する前に、次の4ケースを順番に投入しました。

異常データ 期待する状態 結果
公開から20秒経過 STALE 拒否
公開時刻が20秒先 FUTURE TIMESTAMP 拒否
送信元別名が不一致 SOURCE MISMATCH 拒否
銘柄キーが不一致 SYMBOL MISMATCH 拒否

最後に正常データへ戻し、価格、経過秒数、価格差、スプレッド、Tick時刻、状態コード、12個の表示部品を照合してから画面を保存しています。

実行条件

項目
MT5 Build 5836
通貨・時間足 EURUSD・H1
モード COMPARE
チャンネル EURUSD_FEED_A
期待する送信元 PEER-A
有効期限 5秒
検証用価格差 比較側より25 points高い

検証結果

確認項目 結果
配布インジケーターのコンパイル 0エラー・0警告
独立検証EAのコンパイル 0エラー・0警告
正常データの形式・価格・時刻 一致
期限切れ 拒否
未来時刻 拒否
送信元違い 拒否
銘柄違い 拒否
診断バッファ 15本一致
パネルオブジェクト 12
実画面キャプチャー 成功
注文・DLL呼出し なし

この実機検証は、1台の専用MT5で検証EAが価格ファイルを作り、配布インジケーターが比較側として読む方式です。2つの実ブローカーへ同時接続して、価格差や約定を検証したものではありません。


ダウンロードと使い方

49_Common_Quote_Bridge_v1_00.mq5 をダウンロード

同じPC上にある2つのMT5へ、このインジケーターを入れて使います。

書込側

  1. 価格を配信したい銘柄のチャートへ適用します
  2. InpModePUBLISHにします
  3. InpChannelへ専用のチャンネル名を設定します
  4. InpSourceAliasへ個人情報を含まない別名を設定します

比較側

  1. 比較したい銘柄のチャートへ適用します
  2. InpModeCOMPAREにします
  3. 書込側と同じInpChannelを設定します
  4. InpExpectedPeerAliasへ書込側の別名を設定します

主な入力値は次のとおりです。

パラメーター 初期値 役割
InpMode COMPARE 書込または比較
InpChannel EURUSD_FEED_A 価格を分けるチャンネル
InpSourceAlias LOCAL-A 書込側の別名
InpExpectedPeerAlias PEER-A 比較側が受理する送信元
InpMaxAgeSeconds 5 価格ファイルの有効期限
InpDeleteOwnFeedOnRemove true 書込側を正常に外したとき自分の価格を削除
InpShowPanel true 比較パネルを表示

書込側と比較側でチャンネル名や送信元別名が一致しない場合は、価格差を有効値として表示しません。


使えないこと・注意点

  • 同じPCの共通ファイル領域を使います。別PC間やインターネット越しの配信機能ではありません。
  • 共通ファイルは暗号化・署名されません。秘密情報や口座情報をチャンネル名、別名、ファイルへ入れないでください。
  • 1チャンネルにつき書込側は1つにしてください。
  • 端末の強制終了後はファイルが残ることがありますが、有効期限を超えた価格は拒否します。
  • PC時刻や端末時刻が異常なら、鮮度判定も影響を受けます。
  • 主要FX通貨の接頭辞・接尾辞は通貨ペア部分で照合しますが、独自銘柄名やCFDの別名対応を保証しません。
  • 価格差はTick到着と1秒タイマーの時点差を含みます。完全な同時刻比較ではありません。
  • MID DIFFは比較側のpoint単位です。pipsへ読むときは小数桁を確認してください。
  • スプレッドは送信元と比較側で、それぞれ自分のpoint単位です。
  • 表示値は注文可能性、約定価格、利益、異常検出を保証しません。
  • このインジケーターは注文、変更、取消、ポジション管理を行いません。
  • DLL、Windows API、名前付きパイプ、外部ネットワーク通信は使いません。

ロジック評価の結論

原典の共有メモリ実験は、「別々のMT4が持つ価格を、同じプログラムから見られるようにする」という発想を、少ない関数で形にしていました。メモリを使うため、作成元のDLLが外れれば内容も消えるという管理上の分かりやすさもありました。

今回の移植では、速度を最優先して共有メモリDLLを再現する代わりに、MT5標準の共通ファイル領域へ置き換えました。ファイルは残る可能性がありますが、公開時刻と有効期限を持たせることで、残った価格を現在値として扱わないようにしています。

また、「ファイルが読めた」と「比較に使ってよい」を分けました。形式、送信元、銘柄、価格、未来時刻、期限をすべて通ったときだけ、価格差を有効にします。

それでも、見えているのは気配値です。別業者との価格差が25 pointsあっても、その差を同時に約定できるとは限りません。

まず観測する。古い値や別銘柄を混ぜない。観測結果から、いきなり収益性を言い切らない。

共有メモリの実験から今も引き継げるのは、通信方式そのものより、この慎重な道具の作り方だと思います。


前後の記事

前: 【移植#48】アイコン改造をやめて端末識別バッジへ — 複数MT5を色と別名で見分ける

— SPONSORED —