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

https://qiita.com/EasyCording/items/158c9a09a3f4db1efacc

# 状況

https://github.com/chanmoto/eurusd_pix2pix

昨日は、High-loバイナリーのエントリー部分を完成しました。
適当にGithubから、コードを頂きました。

# 苦労したこと
* セレニウムを全く知らないこと（やばめの金属化合物かと思いました。。。）
* XPATHの取り方が、まったく分かりませんでした。。。

# 結果
* ＢＯＰのバックテストでは５分足エントリで勝率６０％
 　→　実際のトレードでは、この閾値では、ほとんどサインが出なかった。

* サインの閾値範囲を、緩めてエントリーしたら、かなりの勝率で利益が取れた。
　→　調子に乗って、実弾１００００円をエントリーして、夜中に持ち越ししたら、残高が０円になった。

# 反省点
* ＢＯＰで勝負をかけるのは、まだ早すぎる　→　signalと勝率についてのデータ収集を行い、統計的有意差を検証すること
* MT4については、1分足では危険すぎる　→　1分、5分、15分のマルチタイムフレームの戦略を立てる必要がある

# ソース
一応、今回のソースを以下に示します。
（なんやかんや言うて、mlopsぽいことができるスキルがついてきました。）

```main.py
from datetime import datetime
from selenium import webdriver
from selenium.webdriver.chrome import service as fs
import chromedriver_binary
from selenium.webdriver.common.by import By
    
BC_ADRESS = "Mail or Wallet"
PASSWORD = "PASSWORD"
 
def l(str):
    print("%s : %s"%(datetime.now().strftime("%Y/%m/%d %H:%M:%S"),str), flush=True)
 
def s(t = 5):
    import time
    time.sleep(t)
 
def x(str = ""):
    import traceback
    traceback.print_exc()
    if str != "":
        l(str)
 
def start():
    # ドライバー指定でChromeブラウザを開く 
    chrome_service = fs.Service(executable_path='./chromedriver') 
    b = webdriver.Chrome(service=chrome_service)
    b.get('https://app.highlow.com/quick-demo?source=header-quick-demo-cta')
    s()
    return b
 
def login():
    b.find_element_by_css_selector('.login_menu_button a').click()
    i = b.find_element_by_id('login_form_btc_address')
    i.send_keys(BC_ADRESS)
    i = b.find_element_by_id('login_form_password')
    i.send_keys(PASSWORD)
    b.find_element_by_id('login_button').click()
    s()
    
def purchase(driver, high_low_xxx, entry_price):
    if high_low_xxx == "high":
        b.find_element(by=By.XPATH,value = "//div[text()='High']").click()
        s(0.5)
        b.find_element(by=By.XPATH,value = "//div[text()='今すぐ購入']").click()
        s(0.5)
        b.find_element(by=By.XPATH,value = "//div[text()='High']").click()
        
    elif high_low_xxx == "low":
        b.find_element(by=By.XPATH,value = "//div[text()='Low']").click()
        s(0.5)
        b.find_element(by=By.XPATH,value = "//div[text()='今すぐ購入']").click()
        s(0.5)
        b.find_element(by=By.XPATH,value = "//div[text()='Low']").click()

@app.get("/order/")
async def order(signal : float ,db:Session = Depends(get_db)):
    
        if signal>2 and signal<100:
            s(0.5)
            purchase(b,"high",1000)
            s(0.5)
            
        elif signal>0.001 and signal<0.5:
            s(0.5)
            purchase(b,"low",1000)
            s(0.5)
    
        return {"ordered":str(signal)}
```


# MT4
```main.c
#property copyright "Copyright 2016, gogojungle"
#property version   "1.00"
#property strict

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

#define SIGNAL_NONE 0
#define SIGNAL_BUY 1
#define SIGNAL_SELL 2
#define SIGNAL_CLOSEBUY 3
#define SIGNAL_CLOSESELL 4

#property copyright "Expert Advisor Builder"
#property link "http://sufx.core.t3-ism.net/ExpertAdvisorBuilder/"

extern int MagicNumber = 20170302;
extern bool EachTickMode = False;
extern double Lots = 0.1;
extern double LotMultiple = 1.2; //ナンピンロット係数

//ポジション
extern int Slippage = 3;
extern bool Use_limitorder = True;
extern bool Use_stoporder = True;
extern bool UseT_S = True;
extern bool UseT_L = True;
extern bool Use_close = True;
extern bool UseDuration = True; //

extern int expiration = 200;  //エントリー有効時間
extern int maxDuration = 200; //ポジション保有時間
//---- input parameters

extern string param1 = "Current time frame";
extern int nATR = 20;
extern double Coef = 2.0; 
extern double margin = 0.0001;

extern int nLS_MA = 10;
extern int atrLS =1;

extern int space = 100; //ナンピン幅（ピプス）
extern int multi = 1;

//---- input parameters
extern int nPeriod_RSI = 14;
extern int nPeriod_RSI2 = 28;
extern int nPeriod_MA = 25;
extern int MA_Method = 0;
extern int min_gap = 2;
extern int TIMERAG = 3;
extern int TIMERAG2 = 3;
extern double PROF = 500;


int Limit = 200;
int nLine = 2;

int BarCount;
int Current;
bool TickCheck = False;

bool close_mode_buy;
bool close_mode_sell;

datetime entryTime = 0; // エントリー時間
datetime bartime = 0;


int OnInit()
{
   Init();
   return(INIT_SUCCEEDED);
};


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

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

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


//! @brief  ティック毎の処理
void OnTick()
    {

        // 最新の1分足のバーの形成開始時刻を取得。
        datetime current = iTime(NULL, PERIOD_M1, 0);
        
        // 前のティックでの形成開始時刻と比較。
        if (current != mBeforeBarCreationDateTime)
        {
            // 違うならば前のバーが確定し新しいバーになった＝1分毎の更新タイミング。
            On1Minute();

            // バーの形成開始時刻を更新。
            mBeforeBarCreationDateTime = current;
        }
};



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

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



int On1Minute()
{

   int Order = SIGNAL_NONE;
   int total, Ticket;
   bool ret = false;
   double buy_price[100];
   double sell_price[100];
   int i;
   
   
   string res,str,pos,filename,sep_str[];
          

   //+------------------------------------------------------------------+
   //| Variable Begin                                                   |
   //+----
   //------------------------------------------------------------+

   //Check position
   bool IsTrade = False;

   total = OrdersTotal();
   //   if(total>10)
   //   IsTrade = True;


   double signal;

   HideTestIndicators(false);
   
   Print("On1Minute");
        
        Init();
        
   Print("predict", GET(URL + "predict/", ""));
   Print("predict1", GET(URL + "predict1/", ""));
   res = GET(URL + "predict2/", "");
   Print("signal is " + res);

   pos = GET(URL + "order/" + "?signal=" + res,"");
   
   signal = (float)res; 
    
   if (signal>2 && signal<100) {
   Order = SIGNAL_BUY;
   }

   if (signal>0.001 && signal<0.5)  {
   Order = SIGNAL_SELL;
   }
      
   static int BarsBefore = 0;
   int BarsN = Bars;
   int BarsCheck = BarsN - BarsBefore;

   //Buy
   if ( Order == SIGNAL_BUY && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount))))
   {
      if (!IsTrade)
      {
         //Check free margin
         if (AccountFreeMargin() < (1000 * Lots))
         {
            Print("We have no money. Free Margin = ", AccountFreeMargin());
            return (0);
         }

         if (Use_limitorder)
         {
            for (i = 0; i < multi; i++)
            {

               Ticket = OrderSend(Symbol(), OP_SELLLIMIT, (i * LotMultiple + 1) * Lots, NormalizeDouble(Bid - i * space * iStdDev(NULL, 0, nPeriod_MA, 0, MODE_EMA, PRICE_CLOSE, 0) * 0.01, Digits), Slippage, 0, 0, "Buy(#" + Symbol() + Period() + ")", MagicNumber, TimeCurrent() + expiration * Period() * 60, DodgerBlue);
               if (Ticket > 0)
               {
                  if (OrderSelect(Ticket, SELECT_BY_TICKET, MODE_TRADES))
                  {
                     Print("BUY limit order opened : ", OrderOpenPrice());
                  }
                  else
                  {
                     Print("Error opening BUY limit order : ", GetLastError());
                  }
               }
            }

            if (EachTickMode)
               TickCheck = True;
            if (!EachTickMode)
               BarCount = Bars;
            return (0);
         }
      }
   }

   //Sell
   if ( Order == SIGNAL_SELL && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount))))
   {
      if (!IsTrade)
      {
         //Check free margin
         if (AccountFreeMargin() < (1000 * Lots))
         {
            Print("We have no money. Free Margin = ", AccountFreeMargin());
            return (0);
         }

         if (Use_limitorder)
         {
            for (i = 0;i < multi; i++)
            {

               Ticket = OrderSend(Symbol(), OP_BUYLIMIT, (i * LotMultiple + 1) * Lots, NormalizeDouble(Ask + i * space * iStdDev(NULL, 0, nPeriod_MA, 0, MODE_EMA, PRICE_CLOSE, 0) * 0.01, Digits), Slippage, 0, 0, "Sell(#" + Symbol() + Period() + ")", MagicNumber, TimeCurrent() + expiration * Period() * 60, DeepPink);
               if (Ticket > 0)
               {
                  if (OrderSelect(Ticket, SELECT_BY_TICKET, MODE_TRADES))
                  {
                     Print("SELL limit order opened : ", OrderOpenPrice());
                  }
                  else
                  {
                     Print("Error opening SELL limit order : ", GetLastError());
                  }
               }
            }
            if (EachTickMode)
               TickCheck = True;
            if (!EachTickMode)
               BarCount = Bars;
            return (0);
         }
      }
   }

   if (EachTickMode)
               TickCheck = True;
   if (!EachTickMode)
      BarCount = Bars;

   return (0);
   
}
//+------------------------------------------------------------------+

bool CloseAll(int type)
{

   Print("Close All");

   for (int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if (!OrderSelect(i, SELECT_BY_POS))
         continue;
      if (OrderSymbol() != Symbol())
         continue;
      if (OrderMagicNumber() != MagicNumber)
         continue;
      if (OrderType() != type)
         continue;
      if (!OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), Slippage))
      {
         Print("Close Error");
         return (false);
      }
   }
   return (true);
}

bool CloseAll_maxDuration(int type)
{

   for (int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if (!OrderSelect(i, SELECT_BY_POS))
         continue;
      if (OrderSymbol() != Symbol())
         continue;
      if (OrderMagicNumber() != MagicNumber)
         continue;
      if (OrderType() != type)
         continue;
      if (OrderType() != type)
         continue;
      if (int(TimeCurrent() - OrderOpenTime()) < maxDuration * Period() * 60)
         continue;
      if (StringFind(OrderComment(), Period(), 0) == false)
         continue;
      if (!OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), Slippage))
      {
         Print("Close Error");
         return (false);
      }
      else{
   Print("Close All maxDuration");
   return (true);
   }
}
return(true);

}

double AdjustPoint()
{
   //提示レートの小数点桁数を取得する
   int disit = (int)MarketInfo(NULL, MODE_DIGITS);

   //2桁と3桁は2桁に統一する
   if (disit == 2 || disit == 3)
   {
      return 0.01;
   }
   //4桁と5桁は4桁に統一する
   if (disit == 4 || disit == 5)
   {
      return 0.0001;
   }
   //2～5桁以外の桁が発生した場合は、0を返す。
   return 0;
}

```