LoginSignup
2
1

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-03-26

状況

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

苦労したこと

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

結果

  • BOPのバックテストでは5分足エントリで勝率60%
     → 実際のトレードでは、この閾値では、ほとんどサインが出なかった。

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

反省点

  • BOPで勝負をかけるのは、まだ早すぎる → 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;
}

2
1
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
2
1