是否可以从另一台 PC 远程控制一台 PC 上的 EA?
Is it possible to remotely control an EA on a PC from another PC?
我有一个 EA(即机器人),我希望人们在他们的 PC 上安装它。是否可以根据他们的订阅条件从我的 PC 激活或停用它?说明:如果 A 先生订阅了这个月,我将是从我的 PC 上激活它的人。这意味着,即使 EA 在他们的系统上,他们也无法激活或停用它。
您可以使用您的 PC(需要确保您拥有静态 IP 地址,然后启动 Web 应用程序)。更简单的是租一个VPS。然后,创建一个简单的网络应用程序,可能使用 Django (Python) 或 PHP,带有 REST 网络服务和管理面板。
EA端:编译每个机器人,EX4文件提供给客户端。您的客户将 http://yourwebsite.org/ 添加到 MT4 中允许的 url 列表中,然后使用 EA。当 EA 附加到图表时,调用 OnInit()
函数,在该块内使用 WebRequest()
函数让您的 EA 联系您的网站并询问它是否可以工作(可能客户端可能会传递登录名和密码,或者帐号和经纪人名称(如果您愿意,可以使用客户名称)。网络服务器接收该数据并进行验证。
另一个问题是如何让你的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);
}
};
我有一个 EA(即机器人),我希望人们在他们的 PC 上安装它。是否可以根据他们的订阅条件从我的 PC 激活或停用它?说明:如果 A 先生订阅了这个月,我将是从我的 PC 上激活它的人。这意味着,即使 EA 在他们的系统上,他们也无法激活或停用它。
您可以使用您的 PC(需要确保您拥有静态 IP 地址,然后启动 Web 应用程序)。更简单的是租一个VPS。然后,创建一个简单的网络应用程序,可能使用 Django (Python) 或 PHP,带有 REST 网络服务和管理面板。
EA端:编译每个机器人,EX4文件提供给客户端。您的客户将 http://yourwebsite.org/ 添加到 MT4 中允许的 url 列表中,然后使用 EA。当 EA 附加到图表时,调用 OnInit()
函数,在该块内使用 WebRequest()
函数让您的 EA 联系您的网站并询问它是否可以工作(可能客户端可能会传递登录名和密码,或者帐号和经纪人名称(如果您愿意,可以使用客户名称)。网络服务器接收该数据并进行验证。
另一个问题是如何让你的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);
}
};