ホームホーム  更新日: 2020-12-05  [日本語 / English]

MT4(MQL4) と Python の連携 ~名前付きパイプを使ってデータを渡す~ <双方向編>

はじめに

MT4(MQL4) から外部プログラムにデータを渡して処理したくなることがあります。 そんなとき,Windows の名前付きパイプ(NamedPipe)を使うと比較的容易に実現できます。

MT4(MQL4) と Python の連携 ~名前付きパイプを使ってデータを渡す~」では,MT4(MQL4) から Python で作った外部プログラムに一方的にデータを渡していましたが,今回は双方向の通信をやってみます。

MT4(MQL4)と Python の連携(双方向名前付きパイプ)

試した環境

プログラムの流れ

プログラムの動きは以下のような流れになります。

  1. 外部プログラム側で名前付きパイプを作成し,接続されるのを待ちます。
  2. MT4(MQL4) から名前付きパイプに接続します。
  3. MT4(MQL4) から名前付きパイプにデータを書き込みます。
  4. 外部プログラムで名前付きパイプからデータを読み取ります。
  5. 外部プログラムで読み取ったデータを処理します。
  6. 外部プログラムの処理結果を名前付きパイプに書き込みます。
  7. MT4(MQL4) で名前付きパイプからデータを読み取ります。

外部プログラムの作成

今回は Python を使って外部プログラムを作成します。 パイプから送られてきた文字列を数値に変換し,2 倍した結果を文字列に変換して名前付きパイプに書き込むプログラムです。「倍返しだ!」

Python で Windows の名前付きパイプを扱うには,win32pipe モジュールを使います。

import win32pipe
import win32file

# 名前付きパイプの作成
pipe = win32pipe.CreateNamedPipe(
    r'\\.\pipe\TestPipe', 
    win32pipe.PIPE_ACCESS_DUPLEX,
    win32pipe. PIPE_TYPE_BYTE | win32pipe.PIPE_READMODE_BYTE | win32pipe.PIPE_WAIT,
    1, 256, 256, 0, None)

# クライアントの接続を待つ
win32pipe.ConnectNamedPipe(pipe, None)

# バッファの準備
s = b''

# 無限ループ
while True:
    # パイプから 1 文字読み取って
    hr, c = win32file.ReadFile(pipe, 1)

    # バッファに追加
    s += c
    
    # 改行文字を読んだら
    if c == b'\n':
        # 読み取ったデータを数値に変換して 2 倍する
        x = float(s) * 2.0
        
        # 結果を文字列に変換
        res = '{0:.3f}\r\n'.format(x)
        
        # コンソールに表示
        print(res, end='')
        
        # パイプに書き込む
        win32file.WriteFile(pipe, res.encode())
        
        # 次の準備
        s = b''

MT4(MQL4) プログラムの作成

MT4(MQL4) 側は EA(エキスパートアドバイザ)としてプログラムを作成します。 ティックごとに Bid 価格を文字列に変換してパイプに書き込み,外部プログラムの処理結果をパイプから読み取ってターミナルに表示するプログラムです。

MT4(MQL4) から既存のパイプに接続するには FileOpen 関数を使います。

#property strict

const string pipeName = "TestPipe";     // パイプ名。外部プログラムで作成した名前に合わせる。
int pipe = INVALID_HANDLE;

int OnInit()
{
   // 名前付きパイプを開く(接続する)。
   pipe = FileOpen("\\\\.\\pipe\\" + pipeName, FILE_READ | FILE_WRITE | FILE_BIN | FILE_ANSI);

   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
   // パイプを閉じる。
   FileClose(pipe);
}

// ファイルから 1 行読み取る
inline string ReadLine(int file)
{
   string s;
   while (1)
   {
      string c = FileReadString(file, 1);
      s += c;
      if (c == "\n") break;
   } 
   
   return s;
}

void OnTick()
{
   // Bid 価格を文字列に変換
   string s = DoubleToString(Bid);

   // 文字列をパイプに書き込む
   FileWriteString(pipe, s + "\r\n");
   
   // パイプから 1 行読み取って,ターミナルに表示
   Print(ReadLine(pipe));
}

表示例

上記のプログラムを動かすときは,はじめに外部プログラムを起動して待受状態にした後,MT4 側で EA をチャートに適用します。 うまく行けば外部プログラムに以下のように処理結果が表示されます。また,MT4 のターミナルにも同じ結果が表示されます。

209.386
209.388
209.388
209.392
209.388
豊嶋 久道 (著)
豊嶋 久道 (著)
Bill Lubanovic (著), 斎藤 康毅 (監修), 長尾 高弘 (翻訳)