外汇EA编写教程:EA遥控方法

内容

  • 总结
  • 1。设置任务
  • 2。分析模板文件
  • 三。定义命令
  • 4。创建主EA
    • 4.1。命令管理器
    • 4.2。EA启动数据
    • 4.3。EA状态更改功能
    • 4.4。订单删除、入库功能
  • 结束语

总结

我们处于数字时代,各种用于金融市场交易的自动化系统已经变得非常普遍。Electronic Intelligent Transaction System(EA)的主要优点是它可以每天24小时完美连续地执行算法。虚拟主机允许EA全天候自动运行。

不幸的是,并非所有EAS在任何市场情况下都同样有效。在这些情况下,交易者通常需要手动激活和禁用它们。当用户可以直接访问终端时,这很容易做到。但是如果你不能快速访问终端来控制EA工作呢?在这种情况下,能够远程控制EA操作是很好的。让我们研究一种在终端中远程控制EA的可能方法。

1。设置任务

乍一看,任务似乎很清楚:您需要创建一个在接收到外部命令后向EA发送指令的程序。但是,在深入研究这个问题之后,我们可以看到,MetaTrader5不能通过编程直接影响第三方EA的工作。每个EA在一个单独的线程中工作,无法检测在打开的图表上运行的EA。用户fxsaber提供了一个解决方案“智能系统-MetaTrader 5专用库”。

在这段代码中,作者建议使用保存模板的功能。乍一看,保存模板不会影响图上运行的程序的操作。的确如此,但是保存图表模板时,应用于图表的所有图形对象以及所有启动的应用程序及其参数都将保存在文件中。然后将保存的模板应用于图表,并将所有图形对象和程序与保存的参数一起还原。

另一方面,在加载模板之前存在的所有对象和程序都将从图表中删除。换句话说,如果ea在图表上启动,那么如果模板不包含ea,它将被删除,反之亦然。因此,作为模板文件进行编辑可以减少从图表中加载和删除EA。

当然,您可以提前准备必要的模板,并在必要时加载它们,而不必编辑它们。然而,在这种情况下,所需模板的数量增长速度是使用EAS数量的两倍。此外,如果对每个品种使用不同的EA设置,则每个添加的操作将导致模板数量的增加。准备模板成为常规,这样在应用模板时不会出现混淆。

编辑模板也有自己的细微差别。默认情况下,模板将被保存到DATAYFalth/Frase/模板/。但是MQL5只允许沙盒文件。Fxsaber再次提出了一个解决方案:他建议在指定模板文件名时添加沙盒路径。因此,可以在不使用第三方函数库的情况下访问模板文件。

我们感谢Fxsaber敏锐的头脑和非凡的思维。

在定义了EA管理方法后,研究了程序与用户之间的通信模型。今天的世界迫使人们保持移动,随时随身携带智能手机。MetaTrader 5平台提供iPhone和Android版本。在将终端连接到其帐户后,用户可以在图表上分析价格变化并手动进行交易。目前,移动终端不允许使用EA和第三方指标。如果您想使用EA,桌面终端和虚拟主机是唯一的选项。

连接到帐户的移动终端允许查看整个帐户,但移动终端和桌面终端之间没有直接连接通道。我们唯一能影响的就是下订单和删除订单。下的订单立即显示在帐户上,并由运行在桌面终端上的EA跟踪。因此,在下订单的同时,我们可以将控制命令传输给我们的主EA。我们只需要定义命令列表和传递它们的代码。这些问题将在下面的章节中讨论。

2。分析模板文件

首先,让我们看看模板文件结构。以下示例提供了欧元兑美元M30图表模板,以及将要用于的expertmacd ea和macd指标。

<chart>
id=130874249669663027
symbol=EURUSD
period_type=0
period_size=30
digits=5
.....
.....
windows_total=2

<expert>
name=ExpertMACD
path=Experts/Advisors/ExpertMACD.ex5
expertmode=0
<inputs>
Inp_Expert_Title=ExpertMACD
Inp_Signal_MACD_PeriodFast=12
Inp_Signal_MACD_PeriodSlow=24
Inp_Signal_MACD_PeriodSignal=9
Inp_Signal_MACD_TakeProfit=50
Inp_Signal_MACD_StopLoss=20
</inputs>
</expert>

<window>
height=162.766545
objects=103

<indicator>
name=Main
........
</indicator>
<object>
.......
</object>

<object>
........
</object>
........
........
<object>
........
</object>

</window>

<window>
height=50.000000
objects=0

<indicator>
name=MACD
path=
apply=1
show_data=1
scale_inherit=0
scale_line=0
scale_line_percent=50
scale_line_value=0.000000
scale_fix_min=0
scale_fix_min_val=-0.001895
scale_fix_max=0
scale_fix_max_val=0.001374
expertmode=0
fixed_height=-1

<graph>
name=
draw=2
style=0
width=1
color=12632256
</graph>

<graph>
name=
draw=1
style=2
width=1
color=255
</graph>
fast_ema=12
slow_ema=24
macd_sma=9
</indicator>
</window>
</chart>

从代码中可以看到,模板文件中的信息由标记组成并划分。文件以包含主图表数据&lt;图表&gt;的标记开头,还包含图表ID、变化和时间范围。我们感兴趣的信息介于&lt;expert&gt;和&lt;/expert&gt;标签之间。

模板块的开头提供了EA数据:图表上显示的缩写和文件路径。接下来是expertmode标志。其状态指示EA是否允许交易。此标志后面是&lt;inputs&gt;&lt;/inputs&gt;标签突出显示的EA参数。然后我们可以在图表子窗口中找到数据。每个子窗口都由标记&lt;window&gt;和&lt;/window&gt;突出显示,其中包含已开始索引的说明(&lt;indicator&gt;…&lt;/indicator&gt;)和应用程序图形对象(&lt;object&gt;…&lt;/object&gt;)。

另外,请记住,如果图表上启动的EA和/或度量创建图形对象,最好将它们从模板中删除。否则,对象将从模板应用到图表,并且当此类EAS和/或度量开始时,它们将重新创建相同的对象。

这可能导致大量相同对象的不受控制地创建、图表混乱和计算资源的过度消耗。在最坏的情况下,必要的程序会显示对象创建错误并从图表中卸载它们。

通过编程创建的对象通常通过为其分配隐藏属性来隐藏列表中的图形对象,以防止用户修改它们。模板中提供了“hidden”标志来设置此属性。等于1:00隐藏对象。

因此,要启用/禁用EA,我们只需要重写模板文件,更改expertmode标志值,并按顺序删除隐藏对象。应用新模板将使用必要的属性重新启动EA。

三。定义命令

在定义了开发EA的主要原则之后,是时候创建一个通信系统了。以前,我们决定使用命令发送命令。但是我们如何在不破坏结算结果的情况下使用订单发送命令呢?为此,我们将使用账单,并在EA收到命令时将其删除。

放置吊带时,应确保其在工作时间内不会被激活。这里的解决方案是显而易见的——我们需要下一个离当前价格足够远的订单。

令我惊讶的是,在使用移动终端时,我发现无法对订单进行注释。同时,用户可以在桌面终端中查看所创建订单的注释。因此,我们可以安排从主EA到用户的单向通信。但是,用户将无法以这种方式发出命令。

因此,我们可以通过EA放置默认的账单,但是我们不能对它们发表评论。在这种情况下,我们可以使用价格和订单种类来交付订单。在这里,我们应该定义编码订单的价格。它应该与当前价格保持足够的距离,以便在任何情况下都不会激活已下订单。

我相信这些价格接近于零。理论上,任何品种的价格接近零的概率都可以忽略。因此,如果我们将订单价格设置为至少1-5个差价,它可能永远不会被激活。当然,在这种情况下,我们只限于销售止损,因为使用销售止损不会影响可用的保证金。

请记住,我们可以在移动应用程序中读取订单注释,也就是说,我们的主EA可以通过这种方式向我们发送数据。

总之,建议使用以下命令代码:

世界环境学会 价格 交易量 命令
1最低投标报价 任意地 请求EA的状态。
主EA通过EA设置挂起列表和品种,而EA名称和交易许可证在订单注释中指定。
2最低投标价 任意地 EA停止交易。
如果订单未被评论,则停止所有EAS。如果由于修改订单而在第一个订单之后发出订单,则停止品种上的EA。
3最低投标价 任意地 开始EA交易。
的工作原理与指令2相同。
4最低投标价 最小的是买
,最小的两个是卖
,最小的三个是所有人。
删除账单。
5最低投标价 最小的是买
,最小的两个是卖
,最小的三个是所有人。
关闭一个位置。

4。创建主EA

既然我们已经对操作方法和通信渠道有了透彻的了解,我们现在就开始开发EA。我们的EA代码将应用于“智能系统-MetaTrader 5特殊功能库”中的方法,并进行细微修改-所有库方法都是公共的,易于使用。

首先,让我们为应用程序的标签分配助记键名称,以便于使用。其中一些已在应用程序库中声明。

#define FILENAME (__FILE__ + ".tpl")
#define PATH "//Files//"
#define STRING_END "/r/n"
#define EXPERT_BEGIN ("<expert>" + STRING_END)
#define EXPERT_END ("</expert>" + STRING_END)
#define EXPERT_INPUT_BEGIN ("<inputs>" + STRING_END)
#define EXPERT_INPUT_END ("</inputs>" + STRING_END)
#define EXPERT_CHART_BEGIN ("<chart>" + STRING_END)
#define EXPERT_NAME "name="
#define EXPERT_PATH "path="
#define EXPERT_STOPLEVEL "stops_color="

其他的在我们的EA代码中声明。

#define OBJECT_BEGIN             ("<object>" + STRING_END)
#define OBJECT_END               ("</object>" + STRING_END)
#define OBJECTS_NUMBER           ("objects=")
#define OBJECT_HIDDEN            ("hidden=1")
#define EXPERT_EXPERTMODE        ("expertmode=")

还应注意的是,fxsaber非常重视其库与其他代码的兼容性,并取消库末尾的助记名称。此方法消除了将相同名称重新分配给另一个宏的错误。尽管在库外不允许这样的声明。为了不在EA代码中重复类似的宏声明,我们对库代码中的undef指令进行了注释。

//#undef EXPERT_STOPLEVEL
//#undef EXPERT_PATH
//#undef EXPERT_NAME
//#undef EXPERT_CHART_BEGIN
//#undef EXPERT_INPUT_END
//#undef EXPERT_INPUT_BEGIN
//#undef EXPERT_END
//#undef EXPERT_BEGIN
//#undef STRING_END
//#undef PATH
//#undef FILENAME

然后我们为我们的主EA声明两个外部变量:以分钟为单位的信令序列的生命周期,以及标识它们的幻数。

sinput int      Expirations =  5;
sinput ulong    Magic       =  88888;

将上述函数库和事务操作hassan farmer库添加到EA代码中。

#include <fxsaber/Expert.mqh>
#include <Trade/Trade.mqh>

在全局变量模块中,声明事务操作类的一个实例,以及用于存储工作图表ID和最后一个订单号的变量。

CTrade   *Trade;
ulong     chart;
ulong     last_command;

在OnInit函数中,初始化全局变量。

int OnInit()
  {
//---
   Trade =  new CTrade();
   if(CheckPointer(Trade)==POINTER_INVALID)
      return INIT_FAILED;
   Trade.SetDeviationInPoints(0);
   Trade.SetExpertMagicNumber(Magic);
   Trade.SetMarginMode();
   Trade.SetTypeFillingBySymbol(_Symbol);
//---
   chart=ChartID();
   last_command=0;
//---
   return(INIT_SUCCEEDED);
  }

不要忘记删除ondeinit函数中的事务操作类实例。

void OnDeinit(const int reason)
  {
//---
   if(CheckPointer(Trade)!=POINTER_INVALID)
      delete Trade;
  }

4.1。命令管理器

从OnTradeTransaction事务执行启动主EA的功能。请记住,可以多次调用此函数来处理订单。因此,在运行程序代码之前,我们将进行一系列检查。

我们将检查处理事件的订单号的可用性。我们还将检查订单状态,以便不处理订单的删除。此外,我们还应该检查订单的神奇数量,避免处理非EA订单并验证订单类型,因为我们的订单仅通过一个销售停止下来实现。此外,我们应该检查事务操作的类型,因为我们需要添加或修改订单。

在成功完成所有检查之后,启动在Cuffice命令函数中安排的命令管理器。

void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result)
  {
//---
   if(trans.order>0 && trans.order_state!=ORDER_STATE_REQUEST_CANCEL && request.magic==0 && 
      trans.order_type==ORDER_TYPE_SELL_STOP && 
      (trans.type==TRADE_TRANSACTION_ORDER_ADD || trans.type==TRADE_TRANSACTION_ORDER_UPDATE))
      CheckCommand(trans,request);
  }

当启动Cuffice命令函数时,它在其参数中接收事务操作和请求结构。首先,我们检查请求是否已经被处理过。如果命令已被处理,则退出该函数。

void CheckCommand(const MqlTradeTransaction &trans,
                  const MqlTradeRequest &request)
  {
   if(last_command==trans.order)
      return;

否则,将订单价格解码为订单。

   double tick=SymbolInfoDouble(trans.symbol,SYMBOL_TRADE_TICK_SIZE);
   uint command=(uint)NormalizeDouble(trans.price/tick,0);

然后,使用switch操作符调用与传入命令对应的函数。

   switch(command)
     {
      case 1:
        if(StringLen(request.comment)>0 || trans.type==TRADE_TRANSACTION_ORDER_UPDATE)
           return;
        if(trans.order<=0 || (OrderSelect(trans.order) && StringLen(OrderGetString(ORDER_COMMENT))>0))
           return;
        GetExpertsInfo();
        break;
      case 2:
        ChangeExpertsMode(trans,request,false);
        break;
      case 3:
        ChangeExpertsMode(trans,request,true);
        break;
      case 4:
        DeleteOrders(trans);
        break;
      case 5:
        ClosePosition(trans);
        break;
      default:
        return;
     }

简而言之,保存最后一个命令的编号并从帐户中删除该命令。

   last_command=trans.order;
   Trade.OrderDelete(last_command);
  }

附录中提供了所有功能的完整代码。

4.2。EA启动数据

getexpertsinfo函数负责获取终端中所有已启动ea的数据。如前所述,此函数根据启动ea的图形上显示的变化放置信令账单,ea名称及其状态将显示在order annotation中。

在函数的开头,通过调用deleteOrdersByMagic函数删除先前设置的顺序。

void GetExpertsInfo(void)
  {
   DeleteOrdersByMagic(Magic);

此外,循环被安排为迭代终端中的所有活动图表。在循环的开始,检查分析的图表是否是我们的主EA的工作图表。如果是,请转到下一个图表。

   long i_chart=ChartFirst();
   while(i_chart>=0 && !IsStopped())
     {
      if(i_chart==0 || i_chart==chart)
        {
         i_chart=ChartNext(i_chart);
         continue;
        }

在下一阶段,加载图表模板并初步检查图表上的EA状态。如果EA不存在或未加载模板,请转到下一个图表。

      string temp=EXPERT::TemplateToString(i_chart,true);
      if(temp==NULL)
        {
         i_chart=ChartNext(i_chart);
         continue;
        }

接下来,在模板中找到EA块。如果找不到块,请转到下一个图表。

      temp=EXPERT::StringBetween(temp,EXPERT_BEGIN,EXPERT_END);
      if(temp==NULL)
        {
         i_chart=ChartNext(i_chart);
         continue;
        }

之后,将恢复EA名称及其状态。它们被用来为将来的信令指令形成注释。如果EA允许交易,在其名称前加上字母“T”,否则使用字母“S”。

      string name =  EXPERT::StringBetween(temp,EXPERT_NAME,STRING_END);
      bool state  =  (bool)StringToInteger(EXPERT::StringBetween(temp,EXPERT_EXPERTMODE,STRING_END));
      string comment =  (state ? "T " : "S ")+name;

在周期结束时,确定图表类型和信令有效期。发送订单并转到下一个图表。

      string symbol=ChartSymbol(i_chart);
      ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC;
      datetime expir=0;
      if(Expirations>0)
        {
         expir=TimeCurrent()+Expirations*60;
         type=ORDER_TIME_SPECIFIED;
        }
      Trade.SellStop(SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN),SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE),symbol,0,0,type,expir,comment);
      i_chart=ChartNext(i_chart);
     }
  }

在上面提到的函数中,我们使用fxsaber库中的方法将图表模板转换为字符串变量,并获取指定标记之间的子字符串。

如有必要,请检查图表上是否存在EA,以获取指定图表字符串变量的模板。然后保存指定图表的模板,并将获得的模板作为二进制数组读取。将数字数组转换为字符串并返回调用函数。如果在任何验证阶段发生错误,函数将返回空值。

  static string TemplateToString( const long Chart_ID = 0, const bool CheckExpert = false )
  {
    short Data[];
    return(((!CheckExpert || EXPERT::Is(Chart_ID)) && ::ChartSaveTemplate((ulong)Chart_ID, PATH + FILENAME) && (::FileLoad(FILENAME, Data) > 0)) ?
           ::ShortArrayToString(Data) : NULL);
  }

要获取指定标签之间的子字符串,首先要定义子字符串开始和结束处的位置。

  static string StringBetween( string &Str, const string StrBegin, const string StrEnd = NULL )
  {
    int PosBegin = ::StringFind(Str, StrBegin);
    PosBegin = (PosBegin >= 0) ? PosBegin + ::StringLen(StrBegin) : 0;

    const int PosEnd = ::StringFind(Str, StrEnd, PosBegin);

然后剪切子字符串以返回并将原始字符串减少到原始余数。

    const string Res = ::StringSubstr(Str, PosBegin, (PosEnd >= 0) ? PosEnd - PosBegin : -1);
    Str = (PosEnd >= 0) ? ::StringSubstr(Str, PosEnd + ::StringLen(StrEnd)) : NULL;

    if (Str == "")
      Str = NULL;

    return(Res);
  }

所有函数和类的完整代码可以在附件中找到。

4.3。EA状态更改功能

在ChangeExpertsMode函数中更改EA状态。在其参数中,指定的函数捕获事务操作和请求结构,并放置EA的新状态。

void ChangeExpertsMode(const MqlTradeTransaction &trans,
                       const MqlTradeRequest &request,
                       bool  ExpertMode)
  {
   string comment=request.comment;
   if(StringLen(comment)<=0 && OrderSelect(trans.order))
      comment=OrderGetString(ORDER_COMMENT);      
   string exp_name=(StringLen(comment)>2 ? StringSubstr(comment,2) : NULL);

然后,如上所述,安排一个循环来遍历所有图表并加载模板。

   long i_chart=ChartFirst();
   while(i_chart>=0 && !IsStopped())
     {
      if(i_chart==0 || i_chart==chart || (StringLen(exp_name)>0 && ChartSymbol()!=trans.symbol))
        {
         i_chart=ChartNext(i_chart);
         continue;
        }
      string temp=EXPERT::TemplateToString(i_chart,true);
      if(temp==NULL)
        {
         i_chart=ChartNext(i_chart);
         continue;
        }

在下一阶段,如有必要,检查图表上必要的EA的可用性。如果图表上启动的EA与请求不对应,请转到下一个图表。此外,检查当前的EA状态。如果它对应于所放置的组,则转到下一个图表。

      string NewTemplate   =  NULL;
      if(exp_name!=NULL)
        {
         NewTemplate=EXPERT::StringBetween2(temp,NULL,EXPERT_NAME);
         string name=EXPERT::StringBetween(temp,NULL,STRING_END);
         if(name!=exp_name)
           {
            i_chart=ChartNext(i_chart);
            continue;
           }
         NewTemplate+=name+STRING_END;
        }
//---
      NewTemplate+=EXPERT::StringBetween2(temp,NULL,EXPERT_EXPERTMODE);
      bool state  =  (bool)StringToInteger(EXPERT::StringBetween(temp,NULL,STRING_END));
      if(state==ExpertMode)
        {
         i_chart=ChartNext(i_chart);
         continue;
        }

在通过所有必要的检查之后,创建一个指定EA状态的新模板。从模板中删除隐藏对象并将新模板应用于图表。执行完所有操作后,转到下一个图表。

      NewTemplate+=IntegerToString(ExpertMode)+STRING_END+temp;
      NewTemplate=DeleteHiddenObjects(NewTemplate);
      EXPERT::TemplateApply(i_chart,NewTemplate,true);
//---
      i_chart=ChartNext(i_chart);
     }

完成图表迭代周期后,启动活动的EA数据收集功能,向用户指示EA的新状态。

   GetExpertsInfo();
  }

附录中提供了所有功能的完整代码。

4.4。订单删除、入库功能

普通订单和仓库的功能基于相同的算法,但仅在目标对象上有所不同。因此,本文只研究其中一个问题。调用DeleteOrders函数时,事务操作结构将在参数中传递给它。此结构用于在平面方向(根据第3节中的命令表)解码订单卷。

void DeleteOrders(const MqlTradeTransaction &trans)
  {
   int direct=(int)NormalizeDouble(trans.volume/SymbolInfoDouble(trans.symbol,SYMBOL_VOLUME_MIN),0);

然后安排一个循环来迭代帐户上的所有订单。在这个循环中,检查订单类型是否符合传入命令。如果匹配,则发送订单删除请求。

   for(int i=total-1;i>=0;i--)
     {
      ulong ticket=OrderGetTicket((uint)i);
      if(ticket<=0)
         continue;
//---
      switch((ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE))
        {
         case ORDER_TYPE_BUY_LIMIT:
         case ORDER_TYPE_BUY_STOP:
         case ORDER_TYPE_BUY_STOP_LIMIT:
           if(direct==2)
              continue;
           Trade.OrderDelete(ticket);
           break;
         case ORDER_TYPE_SELL_LIMIT:
         case ORDER_TYPE_SELL_STOP:
         case ORDER_TYPE_SELL_STOP_LIMIT:
           if(direct==1)
              continue;
           Trade.OrderDelete(ticket);
           break;
        }
     }
  }

附件中提供了所有功能的完整代码。

结语

本文提出了一种在MetaTrader 5平台上实现远程EA控制的方法。这种解决方案提高了交易员在活动中使用交易机器人的灵活性。使用非标准方法使用标准函数可以解决更广泛的问题,而无需使用各种DLL。

参考资源

智能系统-MetaTrader 5特殊功能库

本文中使用的程序

姓名 解释
专业硕士 类库 智能系统- Meta AutoRead 5特殊功能库
MQ5 智能交易系统 精通EA管理终端中已经启动的其他EAS
MQPROJ 项目文件 主控EA项目

这篇文章是由俄罗斯原始
由Meta卫星软件公司在HTTPS://www. MQL5.COM/RU/TUNESL/5166中翻译而成。

附加文件下载zip mql5.zip(88.19 kb)

 

 


MyFxtop迈投(www.myfxtop.com)-靠谱的外汇跟单社区,免费跟随高手做交易!

 

免责声明:本文系转载自网络,如有侵犯,请联系我们立即删除,另:本文仅代表作者个人观点,与迈投财经(www.myfxtop.cn)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。

風險提示

MyFxtops邁投所列信息僅供參考,不構成投資建議,也不代表任何形式的推薦或者誘導行為。MyFxtops邁投非外匯經紀商,不接觸妳的任何資金。 MYFXTOPS不保證客戶盈利,不承擔任何責任。從事外彙和差價合約等金融產品的槓桿交易具有高風險,損失有可能超過本金,請量力而行,入市前需充分了解潛在的風險。過去的交易成績並不代表以後的交易成績。依據各地區法律法規,MyFxtops邁投不向中國大陸、美國、加拿大、朝鮮居民提供服務。

邁投公眾號

聯繫我們

客服QQ:981617007
Email: service@myfxtop.com

MyFxtops 邁投