温馨提示:本文翻译自stackoverflow.com,查看原文请点击:mql4 - Is it possible to remotely control an EA on a PC from another PC?
mql4

mql4 - 是否可以从另一台PC远程控制PC上的EA?

发布于 2020-05-02 08:26:36

我有一个EA(即机器人),我希望人们将其安装在PC上。是否可以根据订阅条件从我的PC激活或停用它?说明:如果A先生已订阅本月,我将是从我的PC激活它的人。这意味着,即使EA在其系统上,他们也将无法激活或停用它。

查看更多

提问者
Raphael Tunji
被浏览
69
Daniel Kniaz 2020-02-09 20:50

您可以使用PC(需要确保您具有静态IP地址,然后启动Web应用程序)。租用VPS比较简单。然后,使用REST Web服务和管理面板创建一个简单的Web应用程序(可能使用Django(Python)或PHP)。

EA端:每个机器人都经过编译,并向客户端提供EX4文件。您的客户将http://yourwebsite.org/添加到MT4中允许的URL列表中,然后使用EA。当EA附加到图表上时,OnInit()将调用函数,使用WebRequest()该块内的函数让您的EA联系您的网站,并询问它是否可以工作(客户端可能会通过登录名和密码,或者帐号和经纪人名称(如果使用网络服务器会接收到该数据并进行验证。

另一个问题是如何让您的EA工作一段时间。最简单的方法是每天使用相同的验证请求调用一次Web服务器(随机时间似乎更好)。如果验证失败-EA停止工作。

最后,考虑一下如何停用EA ...可能会发生EA开出大量交易和挂单,并且如果EA杀死了自己ExpertRemove(),这些交易将保留在MT4中。因此,最好通知客户EA不再处于活动状态,并遵循现有订单,在可能的情况下保持收支平衡,或者根据您的EA逻辑选择其他解决方案,这会更好。以下代码对某些客户有效,没有任何投诉,欢迎您使用它(使用超级管理员,密码(如果需要)和域名)。

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