• MT4平台上mql4实现的基于macd指标的智能交易EA


    屌丝命苦,拼爹拼不过,拼后台没有,技术宅一枚,情商有问题,不会见人说人话见鬼说鬼话,所以在国庆熬着混着,工作也没啥大起色,想想就郁闷,难不成一辈子就只能这样了?

    苦思冥想,想得一条路,那就是程序化交易--现在程序化交易正有越来越火的趋势,国外已经程序化了很久,国内各大交易所也正在半掩半遮的开展,卷商、私人公司陆陆续续都在开展,心水啊,想着先研究研究,熟了之后也是碗饭啊,不行就靠着给人写策略也能吃口饭不至于饿死吧,想想还有点小鸡冻啊。

    说干就干啊,原来做过外汇的模拟盘,用过MT4软件,软件自带MQL4语言,程序化已经支持的非常好了,还带有例子,还有高大上的名字叫EA,于是咱也高大上了一把,这年头都得将B格嘛。另外,选择外汇是因为外汇受认为操控的可能性比较小,外汇交易每天几万亿美元,不是个人能左右的了的。外汇里面,EUR/USD又是流通量最大的,所以就选择这个汇对。

    废话了一大堆,直接在例子上改,开始是基于均线的MASample,运行了几个礼拜,不是很好,又在MACDSample上改了改,运行了个把月,基本上盈亏平衡,也算是个好开端吧。下面就是我该的macdSample的代码。

     MQL4是一个类似c的语言,很多都可以按照c的逻辑来写。我定义的一些全局变量

     1 input double TakeProfit    =1000;
     2 input double Lots          =0.1;
     3 input double TrailingStop  =150;
     4 input double MACDOpenLevel =5;
     5 input double MACDCloseLevel=3;
     6 input int    MATrendPeriod =60;
     7 input int    MATrendPeriodFast =26;
     8 input double MaximumRisk   =0.08;
     9 input double DecreaseFactor=3;
    10 input int    CheckPeriod = 36;

    根据历史盈亏状况改变下单数量的函数,思路是:在最大下单数量的基础上*风险系数,如果有损失,损失次数/3,直到最小下单数量。不过最近也没用这个函数,主要是函数总是在几次损失后下最小的数量单子,但是行情总是在几次震荡才启动,所以总是错失良机,现在基本上都是下固定数量。

     1 //+------------------------------------------------------------------+
     2 //| Calculate optimal lot size                                       |
     3 //+------------------------------------------------------------------+
     4 double LotsOptimized()
     5   {
     6    double lot=Lots;
     7    int    orders=HistoryTotal();     // history orders total
     8    int    losses=0;                  // number of losses orders without a break
     9    Print("value of Lots:",lot);
    10 //--- select lot size
    11    lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1);
    12 //--- calcuulate number of losses orders without a break
    13    if(DecreaseFactor>0)
    14      {
    15       for(int i=orders-1;i>=0;i--)
    16         {
    17          if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false)
    18            {
    19             Print("Error in history!");
    20             break;
    21            }
    22          if(OrderSymbol()!=Symbol() || OrderType()>OP_SELL)
    23             continue;
    24          //---
    25          if(OrderProfit()>0) break;
    26          if(OrderProfit()<0) losses++;
    27         }
    28       if(losses>1)
    29          lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
    30      }
    31 //--- return lot size
    32    if(lot<0.1) lot=0.1;
    33    Print("lot:",lot);
    34    return(lot);
    35   }

    下面的函数是判断盘整行情的,主要是因为往往美国收市后,整个市场就波动很小了,等待第二天才会开始新一轮行情。

     1 //判断从第i个行情之前的一段时间内存在盘整行情
     2 //盘整行情的定义:行情波动不大
     3 bool hasConsolidation(int i)
     4 {  double macd;
     5    int count,j;
     6    for(j=0;j<2*CheckPeriod;j++)
     7    {
     8       macd=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,i+j);
     9       if(MathAbs(macd)<=(MACDOpenLevel*Point))
    10       {
    11          count=count+1;
    12          if(count>=CheckPeriod)
    13          {
    14             Print("isConsolidation:",2*CheckPeriod,"个周期内有连续半数以上波动过小");
    15             return true;
    16          }
    17       }else{
    18          count = 0;
    19       }
    20    }
    21    return false; 
    22 }

    MACD的基础理论来了,金叉和死叉的应用(关于MACD以及金叉死叉,这里不解释,请各位自行百度或者知乎),我这里判断一段时间内是否有金叉或者死叉,太长时间也没啥意义,我主要是基于5分钟线做日内交易。

     1 //检查一小时内是否有金叉
     2 bool CheckForGoldInHour()
     3 {
     4    double MacdCurrent,MacdPre,SignalCurrent,SignalPre;
     5    for(int i=0;i<CheckPeriod;i++)
     6    {
     7       MacdCurrent=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,i);
     8       MacdPre=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,i+1);
     9       SignalCurrent=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,i);
    10       SignalPre=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,i+1);
    11       
    12       //在0轴下的金叉
    13      if(CheckForGold(MacdCurrent,MacdPre,SignalCurrent,SignalPre))
    14          return true;
    15    }
    16    
    17    return false;
    18 }
    19 
    20 bool CheckForDeathInHour()
    21 {
    22    double MacdCurrent,MacdPre,SignalCurrent,SignalPre;
    23    for(int i=0;i<CheckPeriod;i++)
    24    {
    25       MacdCurrent=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,i);
    26       MacdPre=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,i+1);
    27       SignalCurrent=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,i);
    28       SignalPre=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,i+1);
    29       
    30       //在0轴上的死叉. 
    31      if(CheckForDeath(MacdCurrent,MacdPre,SignalCurrent,SignalPre))
    32          return true;
    33    }
    34    
    35    return false;
    36 }
    37 
    38 bool CheckForGold(double MacdCurrent,double MacdPrevious,double SignalCurrent,double SignalPrevious)
    39 {
    40     if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && 
    41          MathAbs(MacdCurrent)>(MACDOpenLevel*Point))
    42      {
    43          Print("在0轴下的金叉");
    44          return true;
    45      }
    46      
    47      return false;
    48 }
    49 
    50 bool CheckForDeath(double MacdCurrent,double MacdPrevious,double SignalCurrent,double SignalPrevious)
    51 {
    52     if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && 
    53          MacdCurrent>(MACDOpenLevel*Point))
    54      {
    55          Print("在0轴上的死叉");
    56          return true;
    57      }
    58      
    59      return false;
    60 }

    所有的策略最后都归结到一点,你是看多还是看空,看多,平掉空单,开多单,看空,平掉多单,开空单,简单的逻辑。

     1 double Macd0,Macd1,Macd2;
     2 double Signal0,Signal1,Signal2;
     3 double Ma0,Ma1,Ma2;
     4 double highLevel;
     5 
     6 // 看前三个macd值和signal,都是向上的,并且均线向上
     7 bool CheckForLong()
     8 {
     9    Macd0=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,0);
    10    Macd1=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,1);
    11    Macd2=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,2);
    12    
    13    
    14    Signal0=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,0);
    15    Signal1=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,1);
    16    Signal2=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,2);
    17    
    18   
    19    
    20    if(Macd1>=Macd0 || Macd2>=Macd1 || Signal1>=Signal0 || Signal2>=Signal1)
    21    {
    22       Print("CheckForLong:macd或者signal不是向上");
    23       return false;
    24    }
    25    
    26    highLevel = (Macd0+Macd1+Macd2-Signal0-Signal1-Signal2)/3;
    27    
    28    if(highLevel<MACDOpenLevel*Point)//Macd0<=(Signal0+MACDOpenLevel*Point) || Macd1<=(Signal1+MACDOpenLevel*Point) || Macd2<=(Signal2+MACDOpenLevel*Point))
    29    {
    30       Print("CheckForLong:macd不满足开仓必须高于信号足够的量");
    31       Print("相差",highLevel/Point,"个Point");
    32       return false;
    33    }
    34    
    35    //均线变动比较慢,暂时取两个
    36    Ma0=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
    37    Ma1=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);
    38    //Ma2=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,2);
    39    if(Ma0<Ma1)// || Ma1<Ma2)
    40    {
    41       Print("CheckForLong:均线向下,没有向上");
    42       return false;
    43    }
    44    
    45    if(!CheckForGoldInHour())
    46    {
    47       Print("CheckForLong:有效时间内没有检测到0轴下的金叉");
    48       if(hasConsolidation(0))
    49       {
    50          Print("CheckForLong:检测到盘整行情,现在已经确定走势,可以开仓。");
    51          return true;
    52       }
    53       return false;
    54    }
    55    
    56    //if(Macd0>Macd1 && Macd1>Macd2 && Signal0>Signal1 && Signal1>Signal2 && 
    57    //      Macd0>(Signal0+MACDOpenLevel*Point) && Macd1>(Signal1+MACDOpenLevel*Point) && Macd2>(Signal2+MACDOpenLevel*Point)
    58    //      && Ma0>Ma1)
    59    //{
    60      //检查一小时内有金叉
    61    //  if(CheckForGoldInHour())
    62    //    return true;
    63    //}
    64     
    65    //Print("CheckForLong:long");
    66    return true;
    67 }

    这里面加入了均线的判断,macd本质上就是依据两条不同步调(比如我选择的26日均线和60日均线)的均线,如果快的均线离慢均线越来越近,则代表行情可能结束。但是在实际情况中,经常会是,快均线在超过慢均线快速上涨之后,慢慢回落到慢均线,等于慢均线快接近的时候,又快速拉升,慢均线就像支撑线。但是如果仅仅就macd的理论,行情在两均线靠近时就已经要反转了,而这往往是错误的判断。所以macd往往要配合均线。我这里采用26日均线来判断趋势,对于看涨函数,只有在均线是向上的时候才会开仓。同理,下面的short判断也是要看均线向下才开仓。

    
    


    bool CheckForShort()
    {
    Macd0=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,0);
    Macd1=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,1);
    Macd2=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_MAIN,2);


    Signal0=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,0);
    Signal1=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,1);
    Signal2=iMACD(NULL,0,MATrendPeriodFast,MATrendPeriod,9,PRICE_CLOSE,MODE_SIGNAL,2);


    //Ma2=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);

    if(Macd0>=Macd1 || Macd1>=Macd2 || Signal0>=Signal1 || Signal1>=Signal2)
    {
    Print("CheckForShort:macd或者signal不是向下");
    return false;
    }

    highLevel = (Signal0+Signal1+Signal2-Macd0-Macd1-Macd2)/3;

    if(highLevel<MACDOpenLevel*Point)//Signal0<=(Macd0+MACDOpenLevel*Point) || Signal1<=(Macd1+MACDOpenLevel*Point) || Signal2<=(Macd2+MACDOpenLevel*Point))
    {
    Print("CheckForShort:macd不满足开仓必须低于信号足够的数量");
    Print("相差",highLevel/Point,"个Point");
    return false;
    }

    //均线变动比较慢
    Ma0=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
    Ma1=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);
    //Ma2=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,2);
    if(Ma0>Ma1) //|| Ma1>Ma2)
    {
    Print("CheckForShort:均线向上,没有向下");
    return false;
    }

    if(!CheckForDeathInHour())
    {
    Print("CheckForShort:有效时间内没有检测到0轴上的死叉");
    if(hasConsolidation(0))
    {
    Print("CheckForShort:检测到盘整行情,现在已经确定走势,可以开仓。");
    return true;
    }
    return false;
    }

    //if(Macd0<Macd1 && Macd1<Macd2 && Signal0<Signal1 && Signal1<Signal2 &&
    // Signal0>(Macd0+MACDOpenLevel*Point) && Signal1>(Macd1+MACDOpenLevel*Point) && Signal2>(Macd2+MACDOpenLevel*Point)
    // && Ma0<Ma1)
    //{
    //检查一小时内有金叉
    // if(CheckForDeathInHour())
    // return true;
    //}

    //Print("CheckForShort:not short");
    return true;
    }

    
    

    下面就是ontick函数,相当于c语言的main函数,主要是根据多空的判断来开仓和平仓,还有就是移动止损,有点复杂,但是其实也就是一句话的事,就是采用60日均线来作为移动止损点,默认止损是120点,之后取120点和60日均线的大值(要有足够的行情波动空间)。

      1 //+------------------------------------------------------------------+
      2 //|                                                                  |
      3 //+------------------------------------------------------------------+
      4 void OnTick(void)
      5   {
      6    //double MacdCurrent,MacdPrevious;
      7    //double SignalCurrent,SignalPrevious;
      8    double MaCurrent;
      9    int    cnt,ticket,total;
     10    double stopLost;
     11 //---
     12 // initial data checks
     13 // it is important to make sure that the expert works with a normal
     14 // chart and the user did not make any mistakes setting external 
     15 // variables (Lots, StopLoss, TakeProfit, 
     16 // TrailingStop) in our case, we check TakeProfit
     17 // on a chart of less than 100 bars
     18 //---
     19    if(Bars<100)
     20      {
     21       Print("bars less than 100");
     22       return;
     23      }
     24    if(TakeProfit<10)
     25      {
     26       Print("TakeProfit less than 10");
     27       return;
     28      }
     29 //--- to simplify the coding and speed up access data are put into internal variables
     30    //MacdCurrent=iMACD(NULL,0,26,60,9,PRICE_CLOSE,MODE_MAIN,0);
     31    //MacdPrevious=iMACD(NULL,0,26,60,9,PRICE_CLOSE,MODE_MAIN,1);
     32    //SignalCurrent=iMACD(NULL,0,26,60,9,PRICE_CLOSE,MODE_SIGNAL,0);
     33    //SignalPrevious=iMACD(NULL,0,26,60,9,PRICE_CLOSE,MODE_SIGNAL,1);
     34    MaCurrent=iMA(NULL,0,MATrendPeriod*2,0,MODE_EMA,PRICE_CLOSE,0);
     35    //MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);
     36    
     37    //Print("Ask:",Ask," Bid:",Bid," diff point:",(Bid-Ask)/Point);
     38    
     39    total=OrdersTotal();
     40    if(total<1)
     41      {
     42       //--- no opened orders identified
     43       if(AccountFreeMargin()<(1000*Lots))
     44         {
     45          Print("We have no money. Free Margin = ",AccountFreeMargin());
     46          return;
     47         }
     48       //--- check for long position (BUY) possibility
     49       if(CheckForLong())
     50         {
     51          ticket=OrderSend(Symbol(),OP_BUY,10,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green);
     52          if(ticket>0)
     53            {
     54             if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
     55                Print("BUY order opened : ",OrderOpenPrice());
     56            }
     57          else
     58             Print("Error opening BUY order : ",GetLastError());
     59          return;
     60         }
     61       //--- check for short position (SELL) possibility
     62       if(CheckForShort()) //&& MaCurrent<MaPrevious)
     63         {
     64          ticket=OrderSend(Symbol(),OP_SELL,10,Bid,3,0,Bid-TakeProfit*Point,"macd sample",16384,0,Red);
     65          if(ticket>0)
     66            {
     67             if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
     68                Print("SELL order opened : ",OrderOpenPrice());
     69            }
     70          else
     71             Print("Error opening SELL order : ",GetLastError());
     72         }
     73       //--- exit from the "no opened orders" block
     74       return;
     75      }
     76 //--- it is important to enter the market correctly, but it is more important to exit it correctly...   
     77    for(cnt=0;cnt<total;cnt++)
     78      {
     79       if(!OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES))
     80          continue;
     81       if(OrderType()<=OP_SELL &&   // check for opened position 
     82          OrderSymbol()==Symbol())  // check for symbol
     83         {
     84          //--- long position is opened
     85          if(OrderType()==OP_BUY)
     86            {
     87             //--- should it be closed?
     88             if(CheckForShort())
     89               {
     90                //--- close order and exit
     91                if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet))
     92                   Print("OrderClose error ",GetLastError());
     93                return;
     94               }
     95             //--- check for trailing stop
     96             if(TrailingStop>0)
     97               {
     98                if(Bid-OrderOpenPrice()>Point*TrailingStop)
     99                  {
    100                   if(OrderStopLoss()<Bid-Point*TrailingStop)
    101                     {
    102                      //当前卖价减去TrailingStop作为移动止损线
    103                      stopLost = Bid-Point*TrailingStop;
    104                      //如果移动止损值高于均线,以均线为止损线。
    105                      if(stopLost>MaCurrent)
    106                      {
    107                         stopLost = MaCurrent;
    108                      }
    109                      
    110                      //--- modify order and exit
    111                      if(!OrderModify(OrderTicket(),OrderOpenPrice(),stopLost,OrderTakeProfit(),0,Green))
    112                         Print("OrderModify error ",GetLastError());
    113                      return;
    114                     }
    115                  }
    116                  
    117                 if(Bid<OrderOpenPrice())
    118                   {
    119                      
    120                      if((OrderOpenPrice()-Bid)>Point*TrailingStop)
    121                      {
    122                         if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet))
    123                            Print("OrderClose error ",GetLastError());
    124                         return;
    125                      }
    126                      
    127                     if((OrderStopLoss()<OrderOpenPrice()-Point*TrailingStop)||(OrderStopLoss()==0))
    128                     {
    129                      //--- modify order and exit
    130                      if(!OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-Point*TrailingStop,OrderTakeProfit(),0,Green))
    131                         Print("OrderModify error ",GetLastError());
    132                      return;
    133                     }
    134                   }
    135                  
    136               }
    137            }
    138          else // go to short position
    139            {
    140             //--- should it be closed?
    141             if(CheckForLong())
    142               {
    143                //--- close order and exit
    144                if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet))
    145                   Print("OrderClose error ",GetLastError());
    146                return;
    147               }
    148             //--- check for trailing stop
    149             if(TrailingStop>0)
    150               {
    151                if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
    152                  {
    153                   if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
    154                     {
    155                     
    156                      stopLost = Ask+Point*TrailingStop;
    157                      if(Ask+Point*TrailingStop<MaCurrent)
    158                      {
    159                         stopLost = MaCurrent;
    160                      }
    161                      
    162                      //--- modify order and exit
    163                      if(!OrderModify(OrderTicket(),OrderOpenPrice(),stopLost,OrderTakeProfit(),0,Red))
    164                         Print("OrderModify error ",GetLastError());
    165                      return;
    166                     }
    167                  }
    168                  
    169                if(OrderOpenPrice()<Ask)
    170                   {   
    171                      if((Ask-OrderOpenPrice())>Point*TrailingStop)
    172                      {
    173                         if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet))
    174                         Print("OrderClose error ",GetLastError());
    175                         return;
    176                      }
    177                      if((OrderStopLoss()>(OrderOpenPrice()+Point*TrailingStop)) || (OrderStopLoss()==0))
    178                      {
    179                         //--- modify order and exit
    180                         if(!OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+Point*TrailingStop,OrderTakeProfit(),0,Red))
    181                         Print("OrderModify error ",GetLastError());
    182                      }
    183                      return;
    184                   }
    185               }
    186            }
    187         }
    188      }
    189 //---
    190   }

    昨天采用这套策略,抓到一个大行情,模拟盘赚了1万,实盘做的小,500美金的账号,每次下单0.01手,昨天一笔赚了10刀,把我昨天手动亏损的全赚回来了。

    当时也是看模拟盘,模拟的不错,一激动入了金,结果发现,外汇还真不是好的发财门道。目前电脑做的比我好多了

  • 相关阅读:
    笔记:C/C++字符函数的使用
    学习游戏基础编程3:地图编辑器
    学习游戏基础编程2:Win32分割窗口
    学习游戏基础编程1:Win32自定义控件
    [WebServer] Tomcat 配置访问限制:访问白名单和访问黑名单
    [WebServer] Windows操作系统下 Tomcat 服务器运行 PHP 的环境配置
    XSLT函数集合:数值函数、字符串函、节点集函数和布尔函数
    腾讯的一道JavaScript面试题
    【转】AES 进一步的研究
    MQTT-Client-FrameWork使用整理
  • 原文地址:https://www.cnblogs.com/linbirg/p/4564647.html
Copyright © 2020-2023  润新知