5
6

More than 1 year has passed since last update.

AIトレードシステムのMT4埋め込み

Last updated at Posted at 2022-03-15

とりあえず、アルゴリズムは完成したので、いよいよMT4からのMLシステムを構築することとした。

MT4

Metatrader4からは、API経由でデータの受け渡しをすることにした。

メタトレード側のサーバーでやることは、3つである

  1. Pandasデータフレームから、tailのtimeindex情報を取得する
  2. Pandasデータフレームに対して、各足のチャート情報を送付する
  3. 売買シグナルを取得する

まずは、Oninit関数に、1,2を仕込む

autotrade.c
#property copyright "Copyright 2016, gogojungle"
#property version   "1.00"
#property strict

string URL = "http://127.0.0.1/";


int OnInit(){
   string res,str,filename,sep_str[];
   datetime m1,m5,m15,current;
   
   int pos;
   
   res = GET(URL + "getlasttime/", "");
   
   pos =StringSplit(res,'\"',sep_str);
   if(pos!=0)
        {
         m1 = StringToTime(sep_str[3]);
         m5 = StringToTime(sep_str[7]);
         m15 = StringToTime(sep_str[10]);  
        }
    
   SendValue(PERIOD_M1,m1);
   SendValue(PERIOD_M5,m5);
   SendValue(PERIOD_M15,m15);
      
   return(INIT_SUCCEEDED);
}

void SendValue(string peristr,datetime end){
   for(int i=0; i<100000; i++){
   if (end > iTime(NULL,peristr,i))
   
   break;
     
   string data = TimeToString(iTime(NULL,peristr,i))
   +"_"+peristr + "_" + DoubleToString(iClose(NULL,peristr,i));

   POST(URL + "gettick/", data);
   }
}

Webserver

GET,POSTは以下の通り

今回のPOSTは、Fastapiの練習を兼ねて、JSON-BODY渡しを書いた。(別にGETでもいいのであるが・・・)
もちろん、カリパクである。

autotrade.c

bool POST(string url, string text){
       
string headers;
string data;
char post[],result[];

headers = "Content-Type: application/json\r\n";      

StringReplace(text, "\n", "\\n");
data = "{\"content\":\""+text+"\"}"; 
ArrayResize(post,StringToCharArray(data,post,0,WHOLE_ARRAY,CP_UTF8)-1);

int res=WebRequest("POST",url,headers,5000,post,result,headers);

   if(res == -1){
      Print(__FUNCTION__ + " Error code =",GetLastError(),data);
      return(false);
   }
   
   Print("POST success! ", CharArrayToString(result, 0, -1));
   return(true);
}

リクエストをGETに変えただけ・・・

autotrade.c
string GET(string url, string text){
       
string headers;
string data,str;
char post[],result[];

headers = "Content-Type: application/json\r\n";      

StringReplace(text, "\n", "\\n");
data = "{\"content\":\""+text+"\"}"; 
ArrayResize(post,StringToCharArray(data,post,0,WHOLE_ARRAY,CP_UTF8)-1);

int res=WebRequest("GET",url,headers,5000,post,result,headers);

   if(res == -1){
      Print(__FUNCTION__ + " Error code =",GetLastError(),data);
      return(false);
   }
   
         //--- Receive a link to the image uploaded to the server
   str=CharArrayToString(result);    
   return(str);
}

Fast-API

丸一日かかって、とりあえずAPI連携させるところまで完了した。

苦労したところは、POST側のバリデーションの部分。
何回もエラーになったが、結局、以下のコードを参考にした。

EURUSD-BOP2.py
async def root(body=Body(...)):
        global df1,df2,df3
       
        time,peristr,value = body["content"].split("_")
EURUSD-BOP2.py
import pandas as pd
import datetime as dt
from pandas_datareader import data
import mplfinance as mpf
import torch
from torchvision.datasets import ImageFolder
from torchvision import models, transforms
import torch.nn as nn
import numpy as np

import os
os.environ['KMP_DUPLICATE_LIB_OK']='True'

df1 = pd.read_csv(r'C://Users//User//Desktop//EURUSD.oj5k1.csv', sep=",",names=('date', 'time', 'open', 'high', 'low', 'close', 'volume'))
df1.index = pd.to_datetime(df1['date']+" "+df1['time'])

df2 = pd.read_csv(r'C://Users//User//Desktop//EURUSD.oj5k5.csv', sep=",",names=('date', 'time', 'open', 'high', 'low', 'close', 'volume'))
df2.index = pd.to_datetime(df2['date']+" "+df2['time'])

df3 = pd.read_csv(r'C://Users//User//Desktop//EURUSD.oj5k15.csv', sep=",",names=('date', 'time', 'open', 'high', 'low', 'close', 'volume'))
df3.index = pd.to_datetime(df3['date']+" "+df3['time'])
EURUSD-BOP2.py
from PIL import Image
import matplotlib.pyplot as plt
from tqdm import tqdm
import pdb

def min_max(x, axis=None):
    min = x.min(axis=axis, keepdims=True)
    max = x.max(axis=axis, keepdims=True)
    result = (x-min)/(max-min)
    return result

def imagemake(dfspan1,dfspan2,dfspan3):
    a = min_max(np.array(dfspan1))
    d = min_max(np.array(dfspan2))
    g = min_max(np.array(dfspan3))
    
    m = np.outer(a,a).astype(np.float32)
    n = np.outer(d,d).astype(np.float32)
    o = np.outer(g,g).astype(np.float32)
    
    m1 = min_max(m[0:64,0:64])
    m2 = min_max(m[16:80,16:80])
    n1 = min_max(n[0:64,0:64])
    n2 = min_max(n[16:80,16:80])
    o1 = min_max(o[0:64,0:64])
    o2 = min_max(o[16:80,16:80])

    te1 = np.stack([m1,n1,o1])
    te2 = np.stack([m2,n2,o2])
    te3=np.concatenate([te2,te2], 2)#real = fake = te2で与える
    
    te4=np.kron(te3, np.ones((4,4)))
    tmp = torch.from_numpy(te4).clone()
    return  transforms.ToPILImage(mode='RGB')(tmp)   

当然ながら、送る方も適当なので、受ける方も適当だ。
Jsonリクエストを、splitして適当にパラメータを抜いている。

PandasのTailに、更新データを突っ込む処理がだるい・・・
→ Pandasがますます嫌になった。

調べ物をしていて、チートシートを発見した。→ 外人さんマメやなあ。。。

chrome-extension://dnkjinhmoohpidjdgehjbglmgbngnknl/pdf.js/web/viewer.html?file=https%3A%2F%2Fwww.webpages.uidaho.edu%2F~stevel%2Fcheatsheets%2FPandas%2520DataFrame%2520Notes_12pages.pdf

EURUSD-BOP2.py
from fastapi import Body
from fastapi import FastAPI

app = FastAPI()

@app.post("/gettick/")
async def root(body=Body(...)):
        global df1,df2,df3
       
        time,peristr,value = body["content"].split("_")
        s=pd.DataFrame({"close": [value]}, index=[time])
        s.index = pd.to_datetime(s.index)  
        
        if int(peristr)==1:
            df1 = df1.append(s)
            grouped = df1.groupby(level=0)  
            df1 = grouped.last() 
            df1=df1.sort_index(ascending=True)
        
        elif int(peristr)==2:
            df2 = df2.append(s)
            grouped = df2.groupby(level=0)  
            df2 = grouped.last() 
            df2=df2.sort_index(ascending=True)
            
        elif int(peristr)==3:
            df3 = df3.append(s)
            grouped = df3.groupby(level=0)  
            df3 = grouped.last() 
            df3=df3.sort_index(ascending=True)
            
        return peristr+"ok"
    
@app.get("/getlasttime/")
async def gettime():
    global df1,df2,df3
    return {"m1":df1.tail(1).index.astype(str)[0].replace("-","."),"m5":df2.tail(1).index.astype(str)[0].replace("-","."),"m15":df3.tail(1).index.astype(str)[0].replace("-",".")}

@app.get("/predict/")
async def predict():
        global df1,df2,df3

        df11 = [x for x in df1[-96:]['close']]
        df22 = [x for x in df2[-96:]['close']]
        df33 = [x for x in df3[-96:]['close']]

        img = imagemake( df11, df22, df33)
        fn = df1.tail(1).index.astype(str).values.tolist()
        fname = "datasets/facades2/test/" + fn[0].replace(":","_") + "sk.png"
            
        if len(fn[0])<16:
            fname = fname.replace("sk.png"," 00_00_00sk.png")
                
        img.save(fname)
        
        
        
        return {"image":fname}
            

どうやら、メタトレードはPORT80しか使えないらしい。

EURUSD-BOP2.py
import nest_asyncio
import uvicorn

if __name__ == "__main__":
    nest_asyncio.apply()
    uvicorn.run(app, port=80)

まとめ

機械学習アプリの学習を兼ねて、MT4とFastAPIの連携を書いてみた。
シグナルを取り出すところは、コマンドラインからPIX2PIXを呼び出す必要があり、出来ていない。

Pandasはtimeindexがメンドクサイ → MT4とPANDASで、TIMEDATAのフォーマットが違う

Pandasがめんどくさいので、データベースモデルに突っ込もうかなあ・・・ その方がCRUDの練習もできるし・・・

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6