AIトレードシステムのＭＴ４埋め込み

https://qiita.com/EasyCording/items/6db3d63975156653d9fe

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

# MT4

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

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

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

まずは、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でもいいのであるが・・・）
もちろん、カリパクである。

http://www.programmingtheworld.com/index.php/2020/03/16/mql-webrequest-json/

```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

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

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

https://scrapbox.io/nishio/FastAPI%E3%81%A7%E9%9B%91%E3%81%ABJSON%E3%82%92%E5%8F%97%E3%81%91%E5%8F%96%E3%82%8B

```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の練習もできるし・・・