简介
很多交易者面临编写自己的 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。