MT4 (Metatrader 4)上で動くEA (Expert Advisor) は通常MQL4と呼ばれる言語で記述されます。機械学習を用いたアプローチでEAを作成する場合、既存の機械学習のライブラリやコードを用いるためにも、ロジックをPythonで記述できれば便利です。
MT5では公式にPythonとの連携機能が用意されているのですが、残念ながら国内業者での採用が多いMT4では用意されていません。そこで今回は、MT4/MQL4とPythonの連携方法について解説します。
MT4/MQL4とPythonの連携方法
MT4/MQL4からPythonのコードを実行、またはMT4/MQL4とPythonの間で情報を受け渡すにはさまざまな方法が考えられます。
- ソケット (この記事で解説)
- 名前付きパイプ
- ファイル
- 共有メモリ
- Pythonの埋め込み機能
第1回として本記事ではソケットを用いた方法を解説します。ソケットのメリットとしては比較的難易度が低いことと、MT4/MQL4とPythonをそれぞれ別のコンピュータ上で動作可能であることなどがあります。
全体構成
MT4でレートの取得と売買を行い、Python側では売買の判定のみを行うという構成にする場合、MT4とPythonの間で最低でも以下の3種類のデータをやりとりする必要があります。
- レート(MT4→Python)
- 売買や情報取得命令(Python→MT4)
- 売買や情報取得命令の結果を返す(MT4→Python)
今回は簡単のため、Python側でソケットサーバーを作成して接続を待ち受け、MT4のOnTick()のタイミングごとにPythonのソケットサーバーに接続し、データを送受信する構成をとります。
MT4の準備
まず、MT4のオプション→エキスパートアドバイザで、「WebRequestを許可するURLリスト」に「http://localhost」を追加しておきます。
Pythonの準備
Pythonのセットアップは完了しているものとします。Flask をインストールしておきます。pipの場合次のようにします。
pip install Flask
Flaskの動作確認のため、Pythonで次のコードを実行します。
# -*- coding: utf-8 -*-
from flask import Flask, request
app = Flask(__name__)
@app.route("/")
def root():
return 'OK'
if __name__ == '__main__':
app.run(debug=False, host='127.0.0.1', port=8080)
Webブラウザで http://localhost:8080 にアクセスし、OKと表示されたら、Flaskは正常に動いています。
MT4とPythonで通信する
Pythonで次のコードを実行します。
# -*- coding: utf-8 -*-
from flask import Flask, request
app = Flask(__name__)
prev_close = -1
@app.route("/")
def root():
return 'OK'
@app.route("/reset")
def reset():
global prev_close
prev_close = -1
return ""
@app.route("/ontick")
def ontick():
open = float(request.args.get('open'))
high = float(request.args.get('high'))
low = float(request.args.get('low'))
close = float(request.args.get('close'))
global prev_close
if prev_close == -1:
prev_close = close
print(open, high, low, close, prev_close)
prev_close = close
return 'OK'
if __name__ == '__main__':
app.run(debug=False, host='127.0.0.1', port=8080)
次に、MetaEditorで次の内容のEAを作成し、実行します。
void OnTick()
{
static datetime prev_time = Time[0];
// 新しい足ができていないときはなにもせずに抜ける
if(Time[0] == prev_time) {
return;
}
prev_time = Time[0];
string cookie=NULL, headers;
char post[], result[];
string format = "http://localhost:8080/ontick?symbol=%s&time=%s&open=%f&high=%f&low=%f&close=%f";
string request = StringFormat(format, Symbol(), TimeToStr(Time[0] , TIME_DATE | TIME_SECONDS), Open[0], High[0], Low[0], Close[0]);
int response = WebRequest("GET", request, cookie, NULL, 500, post, 0, result, headers);
if (response == -1) {
Print("Error in WebRequest. Error code =",GetLastError());
} else {
if (response == 200) {
// サーバーから返ってきた値を表示する
Print("Return from python: " + CharArrayToString(result));
} else {
PrintFormat("Request '%s' failed, error code %d", url, response);
}
}
}
上記のプログラムは、MT4からPythonに時刻と四本値を送信し、PythonからMT4には”OK”という文字列を返しています。こうして、MT4とPythonの間で情報をやりとりすることができます。注意点としては、実際に上記のプログラムを動かしてみるとわかるのですが、ときどきエラーで止まってしまいます。このため、実運用する際には、エラー処理なども作り込む必要があります。
次回は、名前付きパイプを利用してPythonとMT4を連携する方法を紹介します。
コメント
大変参考になりました。ありがとうございます。
ただ、MetaEditorのEAの内容についてコピペではうまくいかなかった箇所があったので
コメントに残させていただきます。
・14行目
string format = “http://localhost:8080/tick?symbol=%s&time=%s&open=%f&high=%f&low=%f&close=%f”;
URL部について、sample2.pyでは、ポートを「port=80」と定義しているため、
http://localhost:8080ではなくhttp://localhost:80だと思われます。
また、route以降を「tick」としていますが、sample2.pyでは、
routeを「/ontick」と定義しているため、http://localhost:80/ontick
だと思われます。
pythonを使ってEAやインジケータを作るにあたり大変参考にさせていただきましたので
差し出がましいようであれば、申し訳ございません。
ありがとうございました。
間違いの指摘ありがとうございました。
今後ともよろしくお願いいたします。