
通用的 Expert Advisor 模板
简介
很多交易者面临编写自己的 Expert Advisor 的问题。第一要务是什么?如何在 EA 代码中设置获利、止损或追踪止损?如何检验策略的功能性?本文将详述用于创建 Expert Advisor 的主要函数。或许有人会发现追踪代码很有用。
Expert Advisor 变量
那么,什么变量在所有 Expert Advisor 中都是不可或缺的?要让测试程序也检查由布尔型变量设置的参数,应该做些什么?第一,我将展示一段作用于所有的货币对的通用 EA 代码,为了获得更高的速度,建议根据你自己的货币类型进行调节。第二,0-禁用,1-启用(因为我们希望在优化程序中检查所有的参数。如果最终代码极少优化,建议更改该参数)。第三,水平(止损)变量初始为整数,在代码中,必要时更改为分数。在现实生活中,我们交易不同的货币,这仅是一个模板!第四,如果止损参数等于零,则止损不工作。
定义变量
现在开始定义变量。让我们从容易优化的变量——外部变量开始。
extern double MaxLot; extern double TakeProfit; extern double TrailingStop; extern double StopLoss; extern double MinProfit; extern double ProfitPoints; extern int Slippage=0; extern int Condition1=1; extern double LotSpliter=1.0; extern int CloseByOtherSideCondition;
MaxLot 变量设置最大手数,即我们希望限制的最大使用手数(手数也受服务器限制,但我们稍后对其进行讨论)。
当 TakeProfit、StopLoss 和 TrailingStop 大于零时,在代码中作用。
当 ProfitPoints 大于零,MinProfit 和 ProfitPoints 根据原则:价格达到 ProfitPoints 并返回至 MinProfit 而作用。
ConditionX 激活进入条件。
LotSpliter 是手数分割器。仅使用部分可用手数,例如 0.1 仅包含总保证金可用比例的十分之一。
CloseByOtherSideCondition 在出现相反条件时关闭订单。
让我们设置内部变量,在描述 EA 时对其进行讨论。
double Lot; double PP=0; double slu,sld,a,b; double tp,sl;
初始化代码
现在来看一下,仅启动 Expert Advisor 可以计算哪些变量并在代码中进一步使用。
int init() { tp=TakeProfit; sl=StopLoss; return(0); }
我们获取这些变量的值,用于止损位更改的情况。如果打算始终以相同的量进行交易,我们也可以计算手数并显示额外量(本文稍后分析手数计算)。我们也可以创建包含 EA 描述或版权的可显示的注释。做法如下:
Comment("cloud trade \n v2.0.11");
"\n" - 意思是切换至下一个显示行“carriage return”。
Framework 代码
现在让我们查看没有订单的代码:
if(OrdersTotal()==0) { preinit(); if(U()==1) { OrderBuy(); return(0); } if(U()==2) { OrderSell(); return(0); } return(0); }
这些函数的一部分将稍后分析。原则如下:初始化参数、检查是否有进入条件、按条件输入。
现在让我们查看有一个订单的代码:
if(OrderType()==OP_BUY) { if((slu)>PP) { PP=slu; } if(((slu)>0.001) '' (OrderStopLoss()<(b-TrailingStop)) '' (OrderOpenPrice()<(b-TrailingStop)) '' (OrderProfit()>MathAbs(OrderSwap()))) { if(TrailingStop!=0) { OrderModify(OrderTicket(), 0, b-TrailingStop, 0, 0, 0); } } } if(OrderType()==OP_SELL) { if((sld)>PP) { PP=sld; } if(((sld)>0.001) '' (OrderStopLoss()>(a+TrailingStop)) '' (OrderOpenPrice()>(a+TrailingStop))) { if(TrailingStop!=0) { OrderModify(OrderTicket(), 0, a+TrailingStop, 0, 0, 0); } } } if(ProfitPoints!=0) { if(OrderType()==OP_BUY '' PP>=ProfitPoints '' (slu)<=MinProfit) { CloseOnlyOrder(OrderTicket()); return(0); } if(OrderType()==OP_SELL '' PP>=ProfitPoints '' (sld)<=MinProfit) { CloseOnlyOrder(OrderTicket()); return(0); } } if(CloseByOtherSideCondition==1) { if(OrderType()==OP_BUY '' U()==2) { CloseOnlyOrder(OrderTicket()); return(0); } if(OrderType()==OP_SELL '' U()==1) { CloseOnlyOrder(OrderTicket()); return(0); } }
首先,我们仅选择一个订单,以便后续操作(本文将在单独的部分分析该代码)。然后给价格分配变量,以免更改订单,例如,错误方向的追踪止损或无利润的新价格。首先检查订单的追踪止损可能性,同时为下一个函数(最小获利)收集数据,前面已对其使用进行了描述。然后是在相反条件出现时关闭订单及在相反方向打开订单的函数。
本文中分析的函数
现在让我们查看这些函数,用于缩短代码并在程序块中加入最常用的命令,以便随后调用完整的程序块。尝试设置这些条件并检验:
//+------------------------------------------------------------------+ //| returns a signal to buy or to sell | //+------------------------------------------------------------------+ int U() { if((U1()==2 '' Condition1==1) || (U2()==2 '' Condition2==1)){return(2);} if((U1()==1 '' Condition1==1) || (U2()==1 '' Condition2==1)){return(1);} return(0); } //+------------------------------------------------------------------+ //| returns a signal based on stochastic values | //+------------------------------------------------------------------+ int U1() { if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing, Method,PriceUsing,MODE_SIGNAL,1)>=80) { if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,2) <=iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing, Method,PriceUsing,MODE_MAIN,2)) { if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,1) >=iStochastic(Symbol(),Period(), Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_MAIN,1)) { return(2); } } } if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,1)<=20) { if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_SIGNAL,2) >=iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_MAIN,2)) { if(iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing, Method,PriceUsing,MODE_SIGNAL,1) <=iStochastic(Symbol(),Period(),Kperiod,Dperiod,Slowing,Method,PriceUsing,MODE_MAIN,1)) { return(1); } } } return(0); } //+------------------------------------------------------------------+ //| find trend direction using fractals | //+------------------------------------------------------------------+ int U2() { double fu=0,fd=0; int f=0,shift=2; while(f<2) { if(iFractals(Symbol(),Period(),MODE_UPPER,shift)>0) { fu=fu+1; f=f+1; } if(iFractals(Symbol(),Period(),MODE_LOWER,shift)>0) { fd=fd+1; f=f+1; } shift=shift+1; } if(fu==2){return(2);} if(fd==2){return(1);} return(0); }
第一个函数检查条件,后面两个设置条件。
现在来查看函数,如果止损位设置错误则进行计算,并定义手数值:
//+------------------------------------------------------------------+ //| preliminary initialization of variables | //+------------------------------------------------------------------+ int preinit() { Lot=NormalizeDouble(MathFloor(LotSpliter*AccountBalance()*AccountLeverage() /Ask/MathPow(10,Digits+1)*10)/10,1); if(MaxLot>0 '' Lot>MaxLot){Lot=MaxLot;} if(Lot>MarketInfo(Symbol(),MODE_MAXLOT)){Lot=MarketInfo(Symbol(),MODE_MAXLOT);} PP=0; StopLoss=sl; TakeProfit=tp; if(TakeProfit!=0 '' TakeProfit<(MarketInfo(Symbol(),MODE_STOPLEVEL))) { TakeProfit=MarketInfo(Symbol(),MODE_STOPLEVEL); } if(StopLoss!=0 '' StopLoss<(MarketInfo(Symbol(),MODE_STOPLEVEL))) { StopLoss=MarketInfo(Symbol(),MODE_STOPLEVEL); } return(0); }
现在设置函数,根据预设的止损位打开订单:
//+------------------------------------------------------------------+ //| returns true in case of a successful opening of Buy | //+------------------------------------------------------------------+ bool OrderBuy() { bool res=false; if(StopLoss!=0 '' TakeProfit!=0) { res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage, NormalizeDouble(Ask-StopLoss,4), NormalizeDouble(Ask+TakeProfit,4), 0, 0, 0, 0); return(res); } if(StopLoss==0 '' TakeProfit!=0) { res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage, 0, NormalizeDouble(Ask+TakeProfit,4), 0, 0, 0, 0); return(res); } if(StopLoss==0 '' TakeProfit==0) { res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage, 0, 0, 0, 0, 0, 0); return(res); } if(StopLoss!=0 '' TakeProfit==0) { res=OrderSend(Symbol(), 0, NormalizeDouble(Lot,1), Ask, Slippage, NormalizeDouble(Ask-StopLoss,4), 0, 0, 0, 0, 0); return(res); } return(res); } //+------------------------------------------------------------------+ //| returns true in case of a successful opening of Sell | //+------------------------------------------------------------------+ bool OrderSell() { bool res=false; if(StopLoss!=0 '' TakeProfit!=0) { res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage, NormalizeDouble(Bid+StopLoss,4), NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0); return(res); } if(StopLoss==0 '' TakeProfit!=0) { res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage, NormalizeDouble(Bid+StopLoss,4), NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0); return(res); } if(StopLoss==0 '' TakeProfit==0) { res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage, NormalizeDouble(Bid+StopLoss,4), NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0); return(res); } if(StopLoss!=0 '' TakeProfit==0) { res=OrderSend(Symbol(), OP_SELL, NormalizeDouble(Lot,1), Bid, Slippage, NormalizeDouble(Bid+StopLoss,4), NormalizeDouble(Bid-TakeProfit,4), 0, 0, 0, 0); return(res); } return(res); }
下一个函数关闭具有所示订单号、交易量和所示价格的订单。
//+-------------------------------------------------------------------------+ //| returns true in case of a successful closing of an order with Ticket | //+-------------------------------------------------------------------------+ bool CloseOnlyOrder(int Ticket, double Lots ,double priceClose) { bool res=false; res=OrderClose(Ticket, Lots, priceClose, Slippage, 0); return(res);
现在来查看根据位置编号选择订单的函数,以对其进一步操作:
//+--------------------------------------------------------------------------------+ //| returns true in case of a successful choosing of an order in the position pos | //+--------------------------------------------------------------------------------+ bool SelectOnlyOrder(int pos) { bool res=false; res=OrderSelect(pos,SELECT_BY_POS,MODE_TRADES); return(res); } //+------------------------------------------------------------------+
一些编码建议
第一,设置诸如 0 和 1而非“真”和“假”的选项。这将帮助你更好的优化 Expert Advisor。第二,当市场沿着跟条件相反的方向移动时,不要忽视限制可能损失的止损。第三,不要在没有止损的情况下测试自动交易系统——这容易导致保证金快速亏损。第四,使用函数和程序块,使代码更容易理解。
总结
创建 Expert Advisor 并不难。为了使其更加容易,附件包含了本文分析的 Expert Advisor。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/1495
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.
