MQL4学习之MACD Sample解读

时间:2023-02-10 07:53:34

  每个用用MT4的人可能都多多少少有听到过"EA“这个东东,那EA是啥呢,如果你百度EA,那么印入你眼帘的可能就会是MQL4学习之MACD Sample解读

对没错这就是出了烂橘子的那个EA(顺便说一下有木有一起打BF1(*^▽^*)),这当然不是我们要找的EA,我们这里所说的EA( Expert Advisors) 指的是MT4自带的智能交易系统,可以实现全自动交易,代替人工24小时执行自己所写的交易策略。EA是以MQL4语言为基础的,官方解释说MQL4语言是基于C语言所开发,所以很多用法都和C语言相同,但是也有一些区别例如:

  • 没有运算地址;

  • 没有 do ... while 语句;

  • 没有 goto ... 语句;

  • 没有 [条件][表达式 1]:[表达式 2] 语句;

  • 没有复合数据类型 (结构);

  • 复合负值是不允许的,例如:val1=val2=0; arr[i++]=val; cond=(cnt=OrdersTotal)>0; 等等;

  • 逻辑表达式的计算完成前不可以提前终止。

所以如果有C语言基础的话,上手是很快的,目前网上关于MQL4的教材很少,很多都是类似于字典一样的,并不解释语法以及用法,仅仅将所有函数解释,如果你通读了MQL4的中文手册,那么你回过头来看自带的MACD Sample可能也会一头雾水,看得懂每一个函数却不知道它要表达什么,在MQL4社区里倒是有一些教程,但很多都是英文版本,仅有的一些中文版本也是机翻,所以我就找了很多关于示例的解读,经过研究后发现很多都是2012年以前的版本,里面会出现类似于:

extern double Lots = 0.1;
extern double TrailingStop = 30;
extern double MACDOpenLevel=3;
extern double MACDCloseLevel=2;
extern double MATrendPeriod=26;
但是回到目前版本的MT4示例:

input double TakeProfit    =30;
input double Lots          =0.1;
input double TrailingStop  =20;
input double MACDOpenLevel =3;
input double MACDCloseLevel=2;
input double MATrendPeriod =26;

一个是extern打头,一个是input打头,似乎有些不太一样。后面经过一番摸索后发现,新版MT5使用的是MQL5语言,老版的MQL4中间进行过一次修改,引入了许多MQL5的语法,所以老版本的解释会和目前版本的MT4有些出入,这也是我写这篇解读的原因,以目前最新的版本进行一次解读。下面我会从从源代码开始以注释的形式来解读

#property copyright   "2005-2014, MetaQuotes Software Corp."
#property link        "http://www.mql4.com"//前面两行为版权信息,如果只是自用的话,完全可以删除
input double TakeProfit    =30;//input代表输入变量,用户可以通过窗口进行修改,而double指的是后面的变量名是浮点数(可以简单理解为小数)TakeProfit为获利点数
input double Lots          =0.1;//前面input和double同上下面不再解释,Lots为每一单交易的手数
input double TrailingStop  =20;//TrailingStop为止损点数
input double MACDOpenLevel =3;//MACDOpenLevel为自己设定的开仓指数,本例为3
input double MACDCloseLevel=2;//MACD平仓指数
input double MATrendPeriod =26;//均线趋势周期=26根K线线

总结一下,input函数主要用于一些需要在优化时方便修改的指标,可以在回测时很方便的直接修改,而double主要用于数值,浮点数都要用到它。

void OnTick(void)//此处的void意思为空值,等待赋值,新版MQL4的模板中取消了int start函数所以就不要在苦苦寻找start函数了。
  {
   double MacdCurrent,MacdPrevious;//给定自定义浮点数类型变量,分别是目前的MACD值和上一次MACD值
   double SignalCurrent,SignalPrevious;//定义目前的信号值和前一次信号值
   double MaCurrent,MaPrevious;//定义自定义函数变量目前MA值和前一次MA值
   int    cnt,ticket,total;//int函数是代表整数,int后面的所赋值的变量均为整数 cnt这个变量在后面会用到 ticket仓位 total总数

if(Bars<100)
     {
      Print("bars less than 100");
      return;//此处为判定若柱子数量少于100,则不执行后续函数直接返回,如果是自用,此处代码也可忽略不写(bars为柱子的意思)
     }
   if(TakeProfit<10)
     {
      Print("TakeProfit less than 10");
      return;//同上获利若小于10,直接返回自用可不写

此处用到了if函数,做了一个简单的循环和判定,如果有C语言基础的话,这句话应该一看就懂,翻译过来就是当柱子数量少于100时,在屏幕下方打出柱子少于100,并且返回开头,当设定获利少于10时,打出获利少于10并返回开头。

   MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);//利用imacd函数对前面的已经自定义的函数进行赋值,括号中的数值是imacd函数所需要的一些设定参数
   MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);//本行和下方代码作用同第一行
   SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);
   SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);
   MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
   MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);
iMACD函数需要以下几个参数
int  iMACD(
   string              symbol,              // 交易品种名称symbol意思为当前交易品种
   ENUM_TIMEFRAMES     period,              // 周期
   int                 fast_ema_period,     // 快速移动平均数周期
   int                 slow_ema_period,     // 慢速移动平均数周期
   int                 signal_period,       // 不同点的平均周期
   ENUM_APPLIED_PRICE  applied_price        // 价格或者处理器的类型
   );

所以imacd里面NULL就代表当前的交易品种,函数中PRICE_CLOSE指的是采用收盘价,0,12,26,9这几个参数一般是固定的,若变量为Macd那么后面的MODE就为MODE_MAIN,如果为signal那么MODE就为MODE_SIGNAL,最后一位数字是指shift也就是0代表
当前1代表前一次。
iMA函数主要是下列几个参数
 
int  iMA(
   string               symbol,            // 交易品种名称
   ENUM_TIMEFRAMES      period,            // 周期
   int                  ma_period,         // 平均周期
   int                  ma_shift,          // 平移
   ENUM_MA_METHOD       ma_method,         // 平滑类型
   ENUM_APPLIED_PRICE   applied_price      // 价格或者处理程序类型
   );

 
iMA函数主要作为一个处理器存在,所参数沿用i'MACD函数的 

 total=OrdersTotal();
   if(total<1)
     {
      //此处给total赋值。OrdersTotal函数的意思为获取当前的仓位数量,所以total变量的意思就是当前的仓位数并与1比较即确认若果当前没有开仓则进行下一步。
      if(AccountFreeMargin()<(1000*Lots))
        {
         Print("We have no money. Free Margin = ",AccountFreeMargin());
         return;//AccountFreeMargin函数是获取当前账户保证金余额,并判断当前的保证金余额是否足够开仓。


 if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && 
         MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious)
 //此处是对多头开仓条件的判定,如果(当前MACD<0 并且  当前MACD>当前的信号值 
                                                         且前次MACD<前次信号,并且取当前MACD绝对值>开仓水平*点 且当前均线>前次均线)                                          MACD处于0轴以下(熊市)+MACD与信号形成金叉+MACD的绝对值>MACD开仓水平值*点数+均线上升(零下金叉+均线上行)
 
        {
         ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green);//OrderSend函数即为开仓函数可利用该函数进行多头或
 空头开仓,当前货币对,多仓,开仓量,卖价,滑点=3,没有设置止损,止盈=卖价+设置的止盈点,“名称”,订单号,限挂单=0,绿色箭头显示
         if(ticket>0)
           {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
               Print("BUY order opened : ",OrderOpenPrice());
           } //如果ticket大于0则说明开仓成功,则输出多头仓位
         else
            Print("Error opening BUY order : ",GetLastError());
         return;
        } //若ticket小于0则说明开仓失败,输出错误原因

  if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && 
         MacdCurrent>(MACDOpenLevel*Point) && MaCurrent<MaPrevious)
 //如果(当前MACD>0 并且 当前MACD<当前信号 并且 前一次MACD>前次信号
 且 当前MACD>MACD水平*点 且当前MAC<前次MA)
 MACD处于0线以上+MACD与信号形成死叉+MACD值>MACD开仓水平值*点数+均线下降--(零上死叉+均线下行)
        {
         ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,"macd sample",16384,0,Red);
  //同上,OP_SELL为卖单,Bid为买价,其余部分同buy单
         if(ticket>0)
           {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
               Print("SELL order opened : ",OrderOpenPrice());
           }
         else
            Print("Error opening SELL order : ",GetLastError());
        }
      return;
 //确认开仓是否成功,解释同上 

 for(cnt=0;cnt<total;cnt++)//执行for循环,验证cnt是否小于total,cnt=cnt+1
     {
      if(!OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES))//OrderSelect函数主要用于验证订单,若cnt存在返回真值则继续下面的函数,若函数没能完成则报错。
         continue;//返回真值,函数继续
      if(OrderType()<=OP_SELL &&   // 验证仓位类型,是否挂仓
         OrderSymbol()==Symbol())  // 验证是货币种类
        {
         if(OrderType()==OP_BUY)//若仓位是多头仓位
           {
            if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && 
               MacdCurrent>(MACDCloseLevel*Point))//自动平仓的条件
              {
               if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet))
                  Print("OrderClose error ",GetLastError());//检测仓位是否关闭成功,!OrderClose表示否定的意思,即若!OrderClose为真,则说明失败
               return;


 if(TrailingStop>0)//TrailingStop在函数一开始就赋值过,表示止损
               {
                if(Bid-OrderOpenPrice()>Point*TrailingStop)//Bid表示买价,OrderOpenPrice表示开仓价,所以是持仓单的开仓价格。
    //意思为买价-订单开仓价>移动止损*点数
                  {
                   if(OrderStopLoss()<Bid-Point*TrailingStop)//如果(订单止损价<买价-移动止损*点数)
                     {
                      if(!OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green))
                                                               //修改订单(订单索引,开仓价格,买价-移动止损*点数,止盈价格,限价单格,使用绿色箭头显示)
                     Print("OrderModify error ",GetLastError());//若!OrderModify为真则输出错误信息
                      return;//返回上一层
                      }
                  }
               }
            }

  else //空头判定
           {
            if(MacdCurrent<0 && MacdCurrent>SignalCurrent && 
               MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*Point))//当前的MACD<0 并且 当前MACD>当前信号值
 并且前一次MACD<前次信号 且 MACD与信号线形成金叉 且取绝对值(当前MACD)>MACD平仓水平*点
              {
               if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet))
                  Print("OrderClose error ",GetLastError());//同多头检查错误
               return;
              }
            if(TrailingStop>0)
              {
               if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
                 {
                  if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
                    {
                     if(!OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red))
                        Print("OrderModify error ",GetLastError());//同多头,检查止损
                     return;
                    }
                 }
              }
           }
        }
     }
//---
  }

以上就是对于整个MACD Sample的解读,如果有什么问题可以一起讨论哈