首页 技术指标 帖子

理想的ZigZag指标 - MetaTrader 5中的高效工具

附件
925.zip (3.53 KB, 下载 0次)

大家好!今天我要和大家分享一个非常实用的指标——理想的ZigZag。这是一个简单而快速的ZigZag指标,能有效帮助我们识别市场的高低点。

此指标没有悬挂或错误的峰值,峰值的获取过程经过了时间优化。

理想的ZigZag

优点:

  • 计算中最耗时的功能是iBarShift。它完全替代了获取峰值所需的所有循环,使用ArrayBSearch替代,因此这个指标的效率比MQL4版本更高。
  • 每个K线所需的数据不仅可以实时访问,还可以供EA在历史数据中随时调用。
  • 没有悬挂的峰值。
  • 高效的方法找到峰值,无需搜索指标值。
  • 运行非常快速。
  • 在历史数据插入和切换时间框架时均能正确工作。
  • 非常适合在EA中使用。

缺点:

  • 内存需求较高。ZigZag需要两个缓冲区(一个不足以绘制正确的图形),而这里使用了五个缓冲区。在我看来,这个缺点完全被第六个优点所掩盖,因为没有快速ZigZag能够在两个缓冲区上正确处理历史插入。
  • 额外的线条是可用的。这是为了使数据能够被EA可见,但这些线条不应该被显示。

原理:

ZigZag是通过通道原理绘制的,通道的宽度可以用点(IdealZZ)或百分比(IdealZZP)来定义。

峰值获取:

input int ChannelWidth=100;

#property indicator_chart_window

datetime LastTime;
int ZZHandle;
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                         |
//+------------------------------------------------------------------+
void OnInit()
  {
   LastTime = 0;
   ZZHandle = iCustom(_Symbol, Period(), "IdealZZ", ChannelWidth);
  }
//+------------------------------------------------------------------+
//| 获取值                                                         |
//+------------------------------------------------------------------+
bool GetValue(double dir,int bar,int prevBar,double &peak,
             int &peakBar,datetime &peakTime,const datetime &T[])
  {
   if(dir<0)
     {
      double t[1];
      if(0>=CopyBuffer(ZZHandle,2,bar,1,t)) return false;
      int i= ArrayBsearch(T, (datetime)t[0]);

      if(i==prevBar)
        {
         if(0>=CopyBuffer(ZZHandle,2,bar+1,1,t)) return false;
         i=ArrayBsearch(T,(datetime)t[0]);
        }

      double v[1];
      if(0>=CopyBuffer(ZZHandle,1,i,1,v)) return false;

      if(v[0]==EMPTY_VALUE)
        {
         if(0>=CopyBuffer(ZZHandle,2,bar+1,1,t)) return false;
         i=ArrayBsearch(T,(datetime)t[0]);
         if(0>=CopyBuffer(ZZHandle,1,i,1,v)) return false;
        }

      peak=v[0];
      peakBar=i;
      peakTime=(datetime)t[0];
   }
   else if(dir>0)
     {
      double t[1];
      if(0>=CopyBuffer(ZZHandle,3,bar,1,t)) return false;
      int i= ArrayBsearch(T, (datetime)t[0]);

      if(i==prevBar)
        {
         if(0>=CopyBuffer(ZZHandle,3,bar+1,1,t)) return false;
         i=ArrayBsearch(T,(datetime)t[0]);
        }

      double v[1];
      if(0>=CopyBuffer(ZZHandle,0,i,1,v)) return false;

      if(v[0]==EMPTY_VALUE)
        {
         if(0>=CopyBuffer(ZZHandle,3,bar+1,1,t)) return false;
         i=ArrayBsearch(T,(datetime)t[0]);
         if(0>=CopyBuffer(ZZHandle,0,i,1,v)) return false;
        }

      peak=v[0];
      peakBar=i;
      peakTime=(datetime)t[0];
     }
   else
     {
      return(false);
     }

   return(true);
  }
//+------------------------------------------------------------------+
//| 设置点                                                         |
//+------------------------------------------------------------------+
void SetPt(string name,double price,datetime time)
  {
   ObjectCreate(0,name,OBJ_ARROW,0,time,price);
   ObjectSetInteger(0,name,OBJPROP_ARROWCODE,108);
   ObjectSetDouble(0,name,OBJPROP_PRICE,price);
   ObjectSetInteger(0,name,OBJPROP_TIME,time);
  }
//+------------------------------------------------------------------+
//| 自定义指标迭代函数                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &T[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   if(LastTime==T[0]) return(rates_total);
   LastTime=T[0];

   ArraySetAsSeries(T,true);

   double dir_[1];
   if(0>=CopyBuffer(ZZHandle,4,1,1,dir_)) return rates_total;
   double dir=dir_[0];
   double rdir=-dir;

   if(dir==EMPTY_VALUE) return(rates_total);

   double v1,v2,v3,v4,v5;
   int    i1,i2,i3,i4,i5;
   datetime t1,t2,t3,t4,t5;

   if(
      GetValue(dir,1,0,v1,i1,t1,T) && 
      GetValue(rdir,i1,0,v2,i2,t2,T) && 
      GetValue(dir,i2,i1,v3,i3,t3,T) && 
      GetValue(rdir,i3,i2,v4,i4,t4,T) && 
      GetValue(dir,i4,i3,v5,i5,t5,T)
      )
     {
      SetPt("1",v1,t1);
      SetPt("2",v2,t2);
      SetPt("3",v3,t3);
      SetPt("4",v4,t4);
      SetPt("5",v5,t5);
      Print(v1,"   ",v2,"  ",v3,"  ",v4," ",v5," ",i1,"  ",i2,"  ",i3," ",i4," ",i5);
     }
     else
     {
      Print("似乎出现了错误...");
     }

   return(rates_total);
  }
//+------------------------------------------------------------------+

这个例子是一个指标,每次K线形成时会标记前五个峰值(包括当前正在形成的峰值)。

注意!如果启用了零K线模式,代码可能会出现不正确的情况。

零K线模式:

该模式可以在DrawZeroBar变量代码中启用,默认情况下是禁用的。特别是在使用EA时,不建议启用此模式。

希望大家能愉快地使用这个指标!如果遇到任何问题,请告诉我!

相关帖子

评论 (0)