EA - indicator

661 阅读3分钟

第一个indicator - ADX

公式

目前看来比较严谨的公式链接 百度经验公式链接

但是仍然要注意的是,实际上mql4/5里使用的公式是略有区别的

  • 平均函数的选择,一般公式都是使用的 SMMA ,但是mql4/5选择的是EMA
  • DI的计算,一般公式是先求的ATR,APlusDM,AMinusDM。但是mql4/5是定义了一个tmpDI = 100 * DM / TR, DI = EMA(tmpDI, Period)

模板

发现最新版的mql4的模板文件和mql5一样了,每次的回调函数为

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[]){
                    
                }

这里需要注意的是,每次开始计算的位置

  • 如果是首次,prev_calculated为0,此时开始计算位置就是数组的最后一个元素,rates_total - 1
  • 如果是非首次,prev_calculated不为0,那么开始计算位置应该是上一次的位置,即rates_total - prev_calculated。也就是说上一次的位置是要重新计算的。因为周期的原因,举个例子,周期为1min,但是每次tick到来的时间间隔假设是1s,也就是说,1分钟内都没有新bar产生,但是当前bar的high,low,close会被更新。

indicator结构

buffers

indicator上的每个线,对应一个buffer,buffer大小就是和Bars的大小一样,在OnInit里初始化buffer,定义线条,颜色等信息。

  • 指定buffer数目
#property indicator_buffers 3  //要显示的buffer
IndicatorBuffers(16); //总buffer数目,除了显示的外,其他为辅助buffer
  • 画额外的东西

使用 ObjectCreate来在窗口上创建元素

int drawHLine(double value){
   static int cnt = 0;
   string name = "ADX("+IntegerToString(ADXPeriod)+")";
   IndicatorShortName(name);
   windowIndex=WindowFind(name);
   
   if(windowIndex<0)
   {
      // if the subwindow number is -1, there is an error
      Print("Can\'t find window");
      return(0);
   }  
   if(cnt == 0)
      ObjectCreate(name,OBJ_HLINE,windowIndex,0,value);
   else{
      ObjectSet(name,OBJPROP_PRICE1, value);
   }  
   cnt++; 
   // drawing a line in the indicator subwindow
            
   ObjectSet(name,OBJPROP_COLOR,GreenYellow);

   WindowRedraw();    
   return(1);  
}

CODE

#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property indicator_separate_window
#property indicator_buffers 3      // Number of buffers
#property indicator_color1 Blue     // Color of the 1st line
#property indicator_color2 Red
#property indicator_color3 Green

input int ADXPeriod = 14;

//buffers
double bufTr[], bufPDM[], bufMDM[], bufADX[],bufPDI[], bufMDI[];
double bufTr14[], bufPDM14[], bufMDM14[], bufDX[];
double bufTmpPDM[], bufTmpMDM[];
double bufDX2[], bufADX2[], bufPDI2[], bufMDI2[];
int windowIndex = 0;
int OnInit()
  {
   IndicatorBuffers(16);
   SetIndexBuffer(0, bufADX);
   SetIndexStyle(0,DRAW_LINE,STYLE_SOLID,1);
   SetIndexBuffer(1, bufPDI);
   SetIndexStyle(1, DRAW_LINE,STYLE_DOT,1);
   SetIndexBuffer(2, bufMDI);
   SetIndexStyle(2, DRAW_LINE,STYLE_DOT,1);
   
   SetIndexBuffer(3, bufADX2);
   //...
   return(INIT_SUCCEEDED);
  }
  
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   int i = 0;
   int p = prev_calculated;
   int limit = rates_total - p;
   int n = ADXPeriod;
   
   int lastIndex = limit ;//the last one should re-calculate
   if(p == 0){
      lastIndex = limit - 2;
   }
   
   for(i=lastIndex;i>=0;i--){
      double up = high[i] - high[i+1];
      double down = low[i+1] - low[i];
      
      if( (up < 0 && down < 0) || (up == down)){
         bufPDM[i] = 0;
         bufMDM[i] = 0;
      }
      else if(up > down){
         bufPDM[i] = up;
         bufMDM[i] = 0;
      }
      else if(down > up){
         bufMDM[i] = down;
         bufPDM[i] = 0;
      }
      
      double tr1 = high[i] - low[i];
      double tr2 = MathAbs(high[i] - close[i+1]);
      double tr3 = MathAbs(low[i] - close[i+1]);
      
      bufTr[i] = MathMax(MathMax(tr1,tr2),tr3);
      if(bufTr[i] == 0){
         bufPDI2[i] = 0;
         bufMDI2[i] = 0;
      }
      else{
         bufPDI2[i] = 100.0 * (bufPDM[i] / bufTr[i]);
         bufMDI2[i] = 100.0 * (bufMDM[i] / bufTr[i]);
      }
   }
   ema(bufPDI, bufPDI2, lastIndex, n, p == 0);
   ema(bufMDI, bufMDI2, lastIndex, n, p == 0);
   
   for(i=0;i<=lastIndex;i++){
      //the last one maybe zero
      if( bufTr14[i] == 0 ){
          bufTr14[i] = 1;
      }
      
      double sumPM = bufPDI[i] + bufMDI[i];
      if(sumPM == 0){
         sumPM = 1;
      }
      bufDX[i] = 100 * ( MathAbs(bufPDI[i] - bufMDI[i]) / (sumPM) );
   }
   
   ema(bufADX, bufDX, lastIndex, n, p == 0);
   return(rates_total);
   
  }
void ema(double &target[], const double &source[], int indexLast, int n, bool first){
   double sum = 0.0;
   int cnt = 0;
   double a = 2.0/(n+1);
   for(int i=indexLast;i>=0;i--){
      if(first && cnt < n){
         sum += source[i];
         target[i] = 0;
         if(cnt == n - 1){
            target[i] =  nd(sum / n);
         }
      }
      else{
         target[i] = nd (target[i+1] * (1-a) + source[i] * a );
      }
      cnt++;
   }
}

参考链接

mql5官方链接

ADX wiki链接

ADX百度经验链接