Warm tip: This article is reproduced from stackoverflow.com, please click
mql4

Is it possible to remotely control an EA on a PC from another PC?

发布于 2020-04-23 12:26:11

I have an EA (i.e Robot) i want people to have it on their PC. is it possible to activate or deactivate it from my PC based on their subscription condition? Explanation: if Mr. A has subscribed for this month, i will be the one to activate it from my PC. Meaning, even though the EA is on their system, they won't be able to activate or deactivate it.

Questioner
Raphael Tunji
Viewed
43
Daniel Kniaz 2020-02-09 20:50

You can use your PC (need to make sure that you have a static IP address and then launch a web application). Simpler is to rent a VPS. Then, create a simple web application, probably using Django (Python) or PHP, with REST webservice and admin panel.

EA side: every robot is compiled, EX4 file is provided to a client. Your client adds http://yourwebsite.org/ into list of allowed urls in MT4 then uses the EA. When EA is attached to the chart, OnInit() function is called, use WebRequest() function inside that block to let your EA contact your website and ask whether it can work (probably client may pass login and password, or account number and broker name (with client name if you wish). The webserver receives that data and makes validation.

Another question is how to let your EA to work till some time. Easiest way is to call the webserver once a day (at random time seems better) with the same validation request. If validation fails - EA stops working.

Finally, think of how you are going to deactivate your EA... It might happen that EA opened plenty of deals and pending orders, and if it kills itself with ExpertRemove(), those deals will remain in MT4. So probably it would be better to notify the client that EA is no longer active, and follow the existing orders, close all at breakeven if possible, or other solutions that depends on your EA logic. The following piece of code worked for some clients without any complaints, you are welcome to use it (with your super admin, password if needed, and domain name).

class CLicenseOnline : public CObject
  {
private:
   string               m_login;
   string               m_password;
   datetime             m_nextCheck;
   int                  m_prevResult;
   string               m_url;
   int                  m_strategyId;
public:
                    CLicenseOnline(const string login,const string password,const int id):
                                m_login(login),m_password(password),m_nextCheck(0),m_strategyId(id),m_prevResult(-1)
 {

  bool isCheckingRequired=false;
  if(CLicenseOnline::isSuperAdmin(login,password))
    {
     printf("%i %s - Hello, SUPER ADMIN!",__LINE__,__FILE__);
     isCheckingRequired=true;
    }
  isCheckingRequired= isCheckingRequired || IsTesting();
  if(isCheckingRequired)
    {
     m_nextCheck=INT_MAX;
     m_prevResult=1;
    }
  else
    {
     m_url=CLicenseOnline::genUrl(login,password);
    }
 }
                   ~CLicenseOnline(){}
   int                  check()
 {
  if(TimeCurrent()>m_nextCheck)
    {
     int result=this.checkMain();
     switch(result)
       {
        case 1: m_nextCheck=this.generateNextDate();    m_prevResult=1;break;
        default:
        case 0: m_nextCheck=TimeCurrent()+PeriodSeconds(PERIOD_M1);  m_prevResult=0;break;
        case-1: m_nextCheck=TimeCurrent()+PeriodSeconds(PERIOD_H1);  m_prevResult=-1;break;
       }
    }
  return(m_prevResult);
 }
    static string           genUrl(const string login,const string password)
 {
  const string http="localhost";
  return(StringFormat("http://%s/verify/?Login=%s&&Password=%s&&Check=%d",http,login,password,2147483647));
 }
    static string           getHttpResponce(const string url)
 {
  char data[],res[];
  string cookies=NULL, headers=NULL,result;
  ResetLastError();
  int answer = WebRequest("GET",url,cookies,NULL,5000,data,0,res,headers);
  if(answer==200)
    {
     result = CharArrayToString(res);
     return(result);        
    }
  //printf("%i - result=%d|%s|size=%d; %d",__LINE__,answer,result,ArraySize(res),GetLastError());      
  return(NULL);
 }

private:
static bool             isSuperAdmin(const string login,const string password)
 {
  static string 
        superAdminLogin="Admin", 
        superAdminPassword="password";
           //ATTENTION! Edit the login and password here!
  return login==superAdminLogin && password==superAdminPassword;
 }
datetime             generateNextDate()const
 {
  return(iTime(_Symbol,PERIOD_D1,0)+PeriodSeconds(PERIOD_D1)+MathRand()%PeriodSeconds(PERIOD_D1));
 }
int                  checkMain()const
 {
  string respond=CLicenseOnline::getHttpResponce(m_url);
  if(respond==NULL)
     return(0);//try later
  CJAVal js(NULL,jtUNDEF);
  if(!js.Deserialize(respond))
    {
     printf("%i %s - failed to deserialize %s",__LINE__,__FUNCTION__,respond);
     return(-1);
    }
  int retCode=(int)js["key"].ToInt();
  switch(retCode)
    {
     case -1: Alert("incorrect password");return(0);
     case -2: Alert("incorrect key!");return(0);
     case -3: Alert("incorrect request method!");return(0);
     case -4: 
     case -5: Alert("no such login");return(0);
     default:
        Alert(StringFormat("%i %s - incorrect login/password/no such user!",__LINE__,__FUNCTION__));
        return(0);
     case 200:
       {
        CJAVal *valueJs=js["value"];
        if(!this.checkStatus(valueJs["Status"].ToStr()))
           return(-1);
        if(!this.checkAccount(
              (int)valueJs["Allow_account_1"].ToInt(),(int)valueJs["Allow_account_2"].ToInt(),(int)valueJs["Allow_account_3"].ToInt()))
           return -1;
        bool strategyX=(bool)valueJs["Allow_strategy_"+(string)m_strategyId].ToBool();
        if(!stategyX)
          {
           return(-1);
          }
        return(1);
       }
    }
  return(-1);
 }
bool                 checkStatus(const string status)const
 {      //printf("%i %s - status = |%s|%d",__LINE__,__FUNCTION__,status,IsDemo());
  if(status=="demo")
    {
     if(!IsDemo())
       {
        string message=StringFormat("your login %s is allowed to trade on Demo accounts only!",m_login);
        Alert(message);
        printf("%i %s - %s",__LINE__,__FILE__,message);
        return(false);
       }
     return(true);
    }
  if(status!="active")
    {
     string message=StringFormat("status of your login [%s] is [%s] so not allowed to trade!",m_login,status);
     Alert(message);
     printf("%i %s - %s",__LINE__,__FILE__,message);
     return(false);
    }
  return(true);
 } 
bool                 checkAccount(const int acc1,const int acc2,const int acc3)const
 {
  if(acc1==0 && acc2==0 && acc3==0)
     return(true);
  int currentAccount=AccountNumber();
  if(acc1==currentAccount || acc2==currentAccount || acc3==currentAccount)
     return(true);
  string message=StringFormat("allowed accounts are only %d, %d and %d, your account %d is not allowed!",acc1,acc2,acc3,currentAccount);
  Alert(message);
  printf("%i %s - %s",__LINE__,__FUNCTION__,message);
  return(false);
 }
};