mt4とPythonの間でのデータのやり取りを実現する(mt4シリーズPART1)

BTCをbotでトレードするマシンについてはあらかた完成したので、次はFX・株価平均先物・商品先物を対象として自動で取引するマシンを作りたいな、と思ったので、ずっと面倒くささ半分怖さ半分で避けてきたmt4を経由して海外口座で取引するやつをやりたいと思います。そこまでの試行錯誤を記録として10パートぐらいに分けてこのブログに書いていこうかなという次第です。

メリットとしては

レバレッジ500倍を掛けることが出来てBTCよりも(ハイリスク)ハイリターン

流動性の高い銘柄が仮想通貨よりも多く分散型の投資戦略を検討しやすい

一方デメリットとしては

①BTCよりも要人発言やニュースによって相場が急変しやすい

②手数料が高い

ことぐらいでしょうか。デメリットの①に関しては、ポジションを持つ時間が短い自分の戦略では大きく響いてこないしかつニュースを見張らなくても値動きの急変をシグナルとして対処可能であると考え、デメリットの②に関してもレバレッジの大きさを考えれば大きな支障にはならない(と今のところは考えている)ので、とりあえず試してみようと思います。

目標としては2月の春休みの暇な期間をガッツリ使って3月1日までには実戦投入できるようにしたいと思っております。


  ~ロードマップ~

・mt4からPythonにデータを渡す環境を整える ←今ここ
Python側でmt4の処理速度に合わせて売買判断ができるシステムを機械学習をベースとして作る
Python側からmt4にデータを渡す環境を整える
・mt4の方で売買するためのプログラムおよびそのためのモジュールを作る
・デモ環境で数日動かして成果を確認する
・少額を投入して成行を見る
・もし問題なさそうであれば実践運用(3/1の予定)
・(VPS契約してmt4を動かす?それともpcを一台用意してずっと回す?)



mt4とPythonの間でデータのやり取りをする方法は、例えば名前付きパイプを用いるなど様々考えられるようですが、今回はPythonモジュールのFlaskを用いることにしました。

ここでは手始めとして、①mt4側のOntick()で新しい足が形成されればそのOHLCデータをPython側に送信し、②それを受信したPythonがもし陽線だったら売りシグナル1(string)を、陰線だったら買いシグナル1(string)を、それ以外であれば0(string)を返し、③その結果に応じてmt4側でPrint()を用いてコンソールに文字を表示させる、ということを実現したいと思います。


まず、Python側で以下のコードを作成し、実行します。

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: ' + str(_open))
    print('High: ' + str(high))
    print('Low: ' + str(low))
    print('Close: ' + str(close))
    print('############################################')
    prev_close = close

    if _open > close:
        return '1' # 陰線の場合、1を返す

    elif _open < close:
        return '2' # 陽線の場合、2を返す

    else:
        return '0' # open==closeの場合、0を返す


if __name__ == '__main__':
    app.run(debug=False, host='127.0.0.1', port=80)

正しく実行された場合、Webブラウザhttp://127.0.0.1:80/にアクセスするとOKと表示される。
次に、mt4の方から、オプション→エキスパートアドバイザーと選択して、「WebRequestを許可するURLリスト」に「http://localhost」を追加し、これが出来たらMetaEditorの方でEAとして次のファイルを作成する。

#property strict

int OnInit()
  {
   
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   
  }

void OnTick()
  {
   //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:80/ontick?symbol=%s&time=%s&open=%f&high=%f&low=%f&close=%f";
   string url = "localhost";
   string request = StringFormat(format, Symbol(), TimeToStr(Time[0] , TIME_DATE | TIME_SECONDS), Open[1], High[1], Low[1], Close[1]);

   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));

         // Resultに応じてPrintする内容を変える
         if (CharArrayToString(result)=="1"){
             Print("You should buy!");
         }
         else if(CharArrayToString(result)=="2"){
             Print("You should sell!");
         }
         else{
             Print("You should wait!");
         }
      } else {
         PrintFormat("Request '%s' failed, error code %d", url, response);
      }
    }
}

これを実行すると例えば日経平均の1分足ではmt4側とPython側でそれぞれ次のような表示になるはず。

Python:
Open: 27232.0
High: 27240.0
Low: 27232.0
Close: 27237.0
############################################
Open: 27242.0
High: 27242.0
Low: 27232.0
Close: 27235.0
############################################
・・・・

mt4:
f:id:UTS1:20220203142150p:plain

Python, mt4側でこのような表示が(一分足なので)一分おきにprintされるかと思う。問題はmt4側でしばしばWebRequestError5203のエラーコードが表示されることだが原因は特定できていない。特に問題はないはずなのに??

今回のmt4側での処理は勿論本質的なものではないが、mt4でデータを得るごとにPythonへ送信→Pythonでデータ処理→結果をmt4へ送信、という骨子だけは確認できたので、あとは食わせたデータから機械学習で予測した値を返してそれをもとに売買すればいい、という感じか。