English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
O indicador ZigZag: nova abordagem e novas soluções

O indicador ZigZag: nova abordagem e novas soluções

MetaTrader 5Sistemas de negociação | 21 março 2014, 10:16
9 868 3
Sergey Pavlov
Sergey Pavlov

Introdução

Todo investidor conhece certamente o indicador ZigZag destinado à análise dos movimentos de preço de uma dada amplitude ou maior. A linha ZigZag é uma linha quebrada, cujos nós ficam localizados nos altos e baixos do gráfico de preços.

Existem muitas variações desse indicador: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16. Ainda, muitos desenvolvedores de programas do MQL5 são entusiastas na criação de seus próprios ZigZags "ideais". Os principais aspectos negativos do indicador ZigZag são a demora, marcações incorretas de nós questionáveis (barra externa) e desempenho insatisfatório.

Na minha opinião, a implementação mais elegante do ZigZag foi proposta por Yuri Kulikov (Yurich). Além disso, existem alguns artigos do MQL4 muito bons, como o "Notas para os leigos: ZigZag..." e "O show deve continuar, ou Mais uma vez sobre o ZigZag". O assunto parece ter sido explorado substancialmente, com um grande número de publicações disponíveis. E, ainda, existe algo hipnotizante a respeito dele. Agora, também despertou meu interesse, particularmente na possibilidade de criação de um indicador avançado ZigZag.

Esse artigo descreve um método para criar um ZigZag avançado utilizando o indicador Envelopes. Presume-se que podemos encontrar uma certa combinação de parâmetros de entrada para uma série de Envelopes, pelos quais a maioria dos nós dos ZigZags se encontram nos confins das faixas dos Envelopes.

 

Um método para criar um indicador avançado ZigZag

Vamos estabelecer um objetivo: encontrar as coordenadas de dois nós - o nó atual e o nó previsto (Fig. 1). O nó atual é um nó que ainda não está completo e cujas coordenadas ainda estão sendo buscadas ou ajustadas. Além disso, ele está sempre na barra atual (zero). Apesar de estar no futuro, um nó previsto deve mostrar o nível estimado do próximo nó do ZigZag.

Prevendo novos nós do ZigZag

Fig. 1. Prevendo novos nós do ZigZag: o nó atual e o próximo nó

Então o objetivo está estabelecido e temos uma ideia de como utilizar Envelopes de média móvel como uma base para montar um indicador avançado (Fig. 2). Vamos procurar envelopes cujos desvios dos nós do ZigZag sejam mínimos. Parece bastante lógico que os envelopes para os altos e baixos do ZigZag devem ser buscados separadamente.

Indicadores ZigZag e envelopes de médias móveis

Fig. 2. Indicadores ZigZag e envelopes de médias móveis

Para aumentar a significância estatística da previsão, ao invés de utilizar somente um ou até mesmo 10 indicadores de envelopes, devemos utilizar um grupo de 100 ou mais indicadores com diferentes dados de entrada. Eles vão se diferenciar no período de referência na linha do indicador principal e no preço usado (alto para os picos e baixo para os baixos). Vamos apresentar as seguintes notas e fórmulas:

  • ZZ - o indicador ZigZag;
  • ENV - a linha principal do indicador Envelopes (coincide com o indicador iMA);
  • Envelopes(i) - valor da linha principal do indicador Envelopes na barra i'th;
  • ZZ(High) - valor de pico do ZigZag;
  • ZZ(Low) - valor de baixa do ZigZag;
  • ENV(High) - valor da linha principal do indicador Envelopes correspondente a um pico do ZigZag;
  • ENV(Low) - valor da linha principal do indicador Envelopes correspondente a uma baixa do ZigZag;
  • n_high - número de picos do ZigZag;
  • n_low - número de baixas do ZigZag.

Temos dois grupos de indicadores: um para os picos e outro para as baixas (cerca de 100 indicadores em cada um). Vamos calcular o desvio dos nós do ZigZag da linha principal do indicador Envelopes para cada indicador no grupo e encontrar a média aritmética dos desvios para cada indicador de grupo utilizando as fórmulas acima. A figura a seguir demonstra um diagrama de desvios com respeito aos nós identificados ZZ da linha principal ENV para um indicador.

Diagrama de desvios dos nós ZZ do ENV

Fig. 3. Diagrama de desvios dos nós ZZ do ENV

A média aritmética dos desvios será utilizado para determinar o nível para o qual a linha principal do indicador Envelopes deve ser deslocado para plotar as faixas do envelope. Então, precisaremos da média aritmética dos picos do ZigZag para desenharmos a linha superior e a média aritmética dos desvios das baixas para desenharmos a linha inferior do indicador Envelopes.

São as linhas superiores e inferiores dos envelopes que usaremos para localizar pontos característicos e prever os nós do ZigZag. Mais uma vez, estamos interessados no grupo de envelopes que consiste em um conjunto dos indicadores Envelopes. A média aritmética dos desvios dos nós do ZigZag da linha principal de um envelope dado é calculado para cada indicador. Depois de plotar as linhas resultantes (as linhas superior e inferior) do grupo no gráfico, poderemos ver o seguinte:

As linhas de Envelopes no plano

Fig. 4. As linhas de Envelopes no plano

Se presumirmos que cada linha fica em um plano separado, enquanto todas elas juntas criam uma superfície, a figura acima mostra somente a projeção de cada indicador no plano do gráfico de preço. Uma imagem 3D dessas linhas será mais ou menos como a seguir:

As linhas de Envelopes em 3D

Fig. 5. As linhas de Envelopes em 3D

Agora vamos ter uma rápida aula de geometria. Imagine que o grupo de linhas do indicador envelopes seja uma superfície 3D. Tome um plano perpendicular ao gráfico de preço e corte a superfície na barra atual (zero).

Como resultado, obtemos um corte transversal da superfície representando uma curva (as figuras acima demonstram um caso especial onde a curva é uma linha reta). Para fazer a previsão, basta ter as coordenadas de cada ponto da curva que será utilizado nos cálculos mais adiante.

Precisaremos das seguintes características transeccionais: ponto de máximo e mínimo, assim como o centro de gravidade do corte transversal (a média aritmética de todos os valores dos pontos). Os pontos característicos obtidos serão lançados na barra atual (zero), com os dados relevantes sendo armazenados no histórico. Estes pontos característicos servirão como base para os atuais e os próximos ZigZag.

Já que a busca pelos laços do Envelope é realizada separadamente por picos e baixas, como resultado devemos obter dois cortes transversais: um para os picos e outro para as baixas.

Para obter a previsão, utilizaremos o ponto característico mais próximo. Por exemplo, ao buscar por um pico do ZigZag, tomamos os pontos característicos do corte transversal resultantes da interseção da superfície das linhas superiores do indicador Envelopes com um plano de corte. Por outro lado, para encontrar uma baixa tomamos os pontos característicos do corte transversal resultante da intersecção da superfície das linhas inferiores do indicador Envelopes com um plano de corte.

 

Testando um novo indicador

Agora que definimos o método, vamos criar o indicador. Primeiramente encontraremos os últimos nós do indicador ZigZag e desenhá-los no gráfico. Para isso, utilizaremos a classe AdvancedZigZag escrita para a tarefa em questão:

//+------------------------------------------------------------------+
//|                                               AdvancedZigZag.mqh |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                 GetExtremums.mqh |
//+------------------------------------------------------------------+
#include <GetExtremums.mqh>   // author of the code Yurich
#property copyright "Copyright 2012, Yurich"
#property link      "https://www.mql5.com/ru/users/Yurich"
//+------------------------------------------------------------------+
//| ZigZag node structure                                            |
//+------------------------------------------------------------------+
struct MqlZigZag
  {
   double            price;   // Node coordinate
   datetime          t;       // Time
  };
//+------------------------------------------------------------------+
//| The AdvancedZigZag class                                         |
//+------------------------------------------------------------------+
class AdvancedZigZag
  {
private:
   MqlRates          rt[];
   dextremum         zz[];
   int               history;
   double            amplitude;
public:
   dextremum         zHL[];
   MqlZigZag         zzH[],zzL[];
   int               Count(const double range);
   int               Read(const int nodes);
                     AdvancedZigZag(const int bars);
                    ~AdvancedZigZag();
  };
//+------------------------------------------------------------------+
//| Class constructor                                                |
//+------------------------------------------------------------------+
AdvancedZigZag::AdvancedZigZag(const int bars)
  {
   history=bars;
   amplitude=0;
  }
//+------------------------------------------------------------------+
//| The Read method of the class                                     |
//+------------------------------------------------------------------+
int AdvancedZigZag::Read(const int nodes)
  {
   CopyRates(NULL,0,TimeCurrent(),history,rt);
   int cnt=GetExtremums(amplitude,rt,zHL,nodes);
   return(cnt);
  }
//+------------------------------------------------------------------+
//| The Count method of the class                                    |
//+------------------------------------------------------------------+
int AdvancedZigZag::Count(const double range)
  {
   amplitude=range;
   CopyRates(NULL,0,TimeCurrent(),history,rt);
   int cnt=GetExtremums(amplitude,rt,zz);
   ArrayResize(zzH,cnt);
   ArrayResize(zzL,cnt);
   int h=0;
   int l=0;
   for(int i=0; i<cnt; i++)
     {
      if(zz[i].type>0)
        {
         zzH[h]=(MqlZigZag)zz[i];
         h++;
        }
      else
        {
         zzL[l]=(MqlZigZag)zz[i];
         l++;
        }
     }
   ArrayResize(zzH,h);
   ArrayResize(zzL,l);
   return(cnt);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
AdvancedZigZag::~AdvancedZigZag()
  {
  }

Existem dois métodos ao todo:

  • O método Count encontra todos os nós ZigZag em um dado período de tempo (número de barras) e os grava em vários arranjos, separando picos de baixas. Dessa forma será mais fácil realizar a análise e cálculo dos envelopes;
  • O método Read encontra os últimos nós e os grava em um único arranjo. Precisamos desse método para a visualização do indicador ZigZag;

A biblioteca GetExtremums (por Yury Kulikov) também será necessária na busca pelos nós.

Vamos colocar o indicador em análise em um Consultor Especialista. Por que um Consultor Especialista e não um indicador? Certamente é uma questão de gosto, mas me parece ser mais eficiente dessa forma. As características gráficas do Consultor Especialista são, sem sombra de dúvida, mais fracas, porém, ganhamos em desempenho já que os indicadores de mesmo símbolo operam em um único fluxo, enquanto cada CE opera em seu fluxo separado. Vamos dar uma olhada no código:

//+------------------------------------------------------------------+
//|                                                   two_Comets.mq5 |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
#include <AdvancedZigZag.mqh>
//--- Depth of history for the indicator calculation
input int      depth_stories=5000;  // Depth stories for calculating the indicator [bars]
//--- Minimum ZigZag amplitude value
input int      amplitude=100;        // The minimum value of the amplitude of the indicator [points]
//--- Declaring the class
AdvancedZigZag Azz(depth_stories);
//---
#define NUMBER_MA   227
#define START_MA    5
//--- macros
#define SIZE(i)                     (double)i*0.3<1?1:(int)(i*0.25)
#define ObjF1                       ObjectSetString(0,name,OBJPROP_FONT,"Wingdings")
#define ObjF2                       ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER)
#define ObjF3(T)                    ObjectSetInteger(0,name,OBJPROP_TIME,T)
#define ObjF4(P)                    ObjectSetDouble(0,name,OBJPROP_PRICE,P)
#define ObjF5(size)                 ObjectSetInteger(0,name,OBJPROP_FONTSIZE,size)
#define ObjF6(code)                 ObjectSetString(0,name,OBJPROP_TEXT,CharToString(code))
#define ObjF7(clr)                  ObjectSetInteger(0,name,OBJPROP_COLOR,clr)
#define ObjF8                       ObjectSetInteger(0,name,OBJPROP_COLOR,clrMagenta)
#define ObjF9                       ObjectSetInteger(0,name,OBJPROP_WIDTH,3)
#define ObjF10                      ObjectSetInteger(0,name,OBJPROP_BACK,true) 
#define ObjFont                     ObjF1;ObjF2;
#define ObjCoordinates(T,P)         ObjF3(T);ObjF4(P);
#define ObjProperty(size,code,clr)  ObjF5(size);ObjF6(code);ObjF7(clr);
#define ObjZZ                       ObjF8;ObjF9;ObjF10;
//---
double      MA[1],sumHi[NUMBER_MA],sumLo[NUMBER_MA];
int         handle_MA_H[NUMBER_MA],handle_MA_L[NUMBER_MA];
datetime    t[1];
int         H,L;
int         t_min,t_max;
int         err=-1;
double      sumH[2],maxH[2],minH[2];
double      sumL[2],maxL[2],minL[2];
string      name;
int         count;
int         shift;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   shift=PeriodSeconds()/30;
//--- calculation of ZigZag nodes using historical data
   Azz.Count(amplitude*Point());
   H=ArraySize(Azz.zzH);
   L=ArraySize(Azz.zzL);
   if(H<30 || L<30)
     {
      Print("Not enough data to calculate ZigZag nodes: "+
            "increase the depth of history; "+
            "or decrease the amplitude value.");
      return(-1);
     }
//---
   for(int i=0; i<NUMBER_MA; i++)
     {
      handle_MA_H[i]=iMA(NULL,0,i+START_MA,0,MODE_SMA,PRICE_HIGH);
      handle_MA_L[i]=iMA(NULL,0,i+START_MA,0,MODE_SMA,PRICE_LOW);
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0,-1,-1);
   for(int i=0; i<NUMBER_MA; i++)
     {
      IndicatorRelease(handle_MA_H[i]);
      IndicatorRelease(handle_MA_L[i]);
     }
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+

void OnTick()
  {
//--- get the current bar's opening time value
   CopyTime(NULL,0,0,1,t);
//--- ZigZag: last 7 nodes
   count=Azz.Read(7);
   for(int i=1; i<count; i++)
     {
      name="ZZ"+(string)i;
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,clrRed);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,10);
      ObjectSetInteger(0,name,OBJPROP_BACK,true);
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[i-1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[i-1].time);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,Azz.zHL[i].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,Azz.zHL[i].time);
     }
//--- check for integrity of preliminary calculations
   if(err<0)
     {
      //--- calculate the sums of deviations of the nodes from MA for ZigZag peaks
      ArrayInitialize(sumHi,0.0);
      for(int j=H-1; j>=0; j--)
        {
         for(int i=0; i<NUMBER_MA; i++)
           {
            err=CopyBuffer(handle_MA_H[i],0,Azz.zzH[j].t,1,MA);
            if(err<0) return;
            sumHi[i]+=Azz.zzH[j].price-MA[0];
           }
        }
      //--- calculate the sums of deviations of the nodes from MA for ZigZag troughs
      ArrayInitialize(sumLo,0.0);
      for(int j=L-1; j>=0; j--)
        {
         for(int i=0; i<NUMBER_MA; i++)
           {
            err=CopyBuffer(handle_MA_L[i],0,Azz.zzL[j].t,1,MA);
            if(err<0) return;
            sumLo[i]+=MA[0]-Azz.zzL[j].price;
           }
        }
     }
  }
//+------------------------------------------------------------------+

Precisamos esclarecer algumas coisas aqui:

  • O indicador iEnvelopes é substituído pelo indicador iMA. Não há nada falso ou enganoso nele. A questão é que a linha principal do iEnvelopes coincide com a linha do iMA! É, portanto, mais conveniente utilizar o indicador Moving Average.
  • Utilizamos dois grupos de médias móveis, consistindo em 227 linhas cada, assim formando 454 indicadores iMA no total! É muito ou pouco? Basicamente, é um número grande. Mas, em primeiro lugar, podemos alterar o número de indicadores, se necessário, e em segundo lugar, precisamos de estatística. Que sentido faz em buscar envelopes para uma dúzia de nós? Precisamos de, pelo menos, cem.
  • Os valores dos indicadores são carregados no bloco OnTick() ao invés do bloco OnInit(). Se o bloco de carregamento de dados estiver localizado no OnInit(), é muito provável que alguns dados demorem a carregar e os indicadores, consequentemente, não serão calculados precisa e completamente. Após todos os dados para os cálculos sejam obtidos, o valor da variável err se tornará positivo e esse bloco será excluído da operação.

Então, o indicador resultante plota os últimos sete nós do ZigZag e calcula as coordenadas de todos os outros nós em um dado histórico. (Fig. 6). O cálculo somente é realizado uma vez e usamos posteriormente os dados calculados. Você pode, claro, implementá-lo de tal forma a permitir que os dados sejam atualizados regularmente, mas nesse artigo resumiremos a um único passo.

O indicador ZigZag (7 nós)

Fig. 6. O indicador ZigZag (7 nós)

Posteriormente, vamos plotar os cortes transversais das superfícies dos indicadores Envelopes. Para fazê-lo, adicionaremos o seguinte ao método OnTick ():

//--- PEAKS
   sumH[0]=0.0;
   maxH[0]=0.0;
   minH[0]=0.0;
   for(int i=0; i<NUMBER_MA; i++)
     {
      CopyBuffer(handle_MA_H[i],0,t[0],1,MA);
      double envelope=MA[0]+sumHi[i]/H;
      if(i==0 || envelope<minH[0])
        {
         minH[0]=envelope;
         t_min=SIZE(i);
        }
      if(envelope>maxH[0])
        {
         maxH[0]=envelope;
         t_max=SIZE(i);
        }
      sumH[0]+=envelope;
      name="H"+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjFont
      ObjCoordinates(t[0]-(NUMBER_MA-i*2)*shift,envelope)
      ObjProperty(SIZE(i),158,clrBlue)
     }
//--- TROUGHS
   sumL[0]=0.0;
   maxL[0]=0.0;
   minL[0]=0.0;
   for(int i=0; i<NUMBER_MA; i++)
     {
      CopyBuffer(handle_MA_L[i],0,t[0],1,MA);
      double envelope=MA[0]-sumLo[i]/L;
      if(i==0 || envelope<minL[0])
        {
         minL[0]=envelope;
         t_min=SIZE(i);
        }
      if(envelope>maxL[0])
        {
         maxL[0]=envelope;
         t_max=SIZE(i);
        }
      sumL[0]+=envelope;
      name="L"+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjFont
      ObjCoordinates(t[0]+(NUMBER_MA-i*2)*shift,envelope)
      ObjProperty(SIZE(i),158,clrGold)
     }
Uma nota para programadores iniciantes: os operadores ao final do bloco de picos e baixas não têm ';' no fim da cadeia. Não é um erro ou algo similar. São macros (veja a seção de dados onde eles são declarados) - eles são muito úteis! Eu recomendo que você os use em seus programas.

Para identificar os pontos do corte transversal da superfície formada pelas linhas envelopes, os pontos variam de tamanho: quanto maior for o período de média da linha principal dos indicadores Envelopes, maiores serão os pontos (Fig. 7). Além disso, os cortes transversais são rodados ao redor de um eixo vertical passando através da barra atual (zero) em direções diferentes: picos ficam a 90 graus a direita e baixas ficam a 90 graus a esquerda.

Agora eles podem ser vistos no plano do gráfico de preço. Inicialmente, eles estavam no plano de corte (Fig. 5) e não podiam ser observados. Podíamos somente imaginá-los, sem ter qualquer ideia a respeito de seu formato. As linhas transversais acabaram se tornando uma forma bastante peculiar. Isso também é feito para a comodidade da análise gráfica. Visualmente, os cortes transversais lembram dois cometas voadores:

Corte transversal do grupo de indicadores Envelopes

Fig. 7. Corte transversal do grupo de indicadores Envelopes

Vamos dar continuidade com o cálculo das características transeccionais: o máximo e o mínimo, assim como o centro de gravidade (a média aritmética). Os valores resultantes serão exibidos na forma de pontos na barra atual, com o tamanho do ponto correspondendo ao tamanho da característica relevante. Além disso, iremos gravá-los no histórico para análise posterior. Então, adicionaremos o seguinte ao código atual:

//--- PEAKS

...

//--- midi
   string str=(string)t[0];
   name="Hmidi"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],sumH[0]/NUMBER_MA)
   ObjProperty(10,119,clrBlue)
//--- max
   name="Hmax"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],maxH[0])
   ObjProperty(t_max,158,clrBlue)
//--- min
   name="Hmin"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],minH[0])
   ObjProperty(t_min,158,clrBlue)

...

//--- TROUGHS

...

//--- midi
   name="Lmidi"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],sumL[0]/NUMBER_MA)
   ObjProperty(10,119,clrGold)
//--- max
   name="Lmax"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],maxL[0])
   ObjProperty(t_max,158,clrGold)
//--- min
   name="Lmin"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],minL[0])
   ObjProperty(t_min,158,clrGold)

Agora vamos ver como se parece quando representado graficamente:

Características do corte transversal

Fig. 8. Características do corte transversal: o máximo e o mínimo, assim como o centro de gravidade plotado para os picos e baixas separadamente

Precisamos apenas adicionar o último retoque encontrando e plotando os nós do ZigZag. Melhoramos o código adicionando o seguinte:

//--- ZigZag: advanced nodes
   if(Azz.zHL[0].type>0) // peak
     {
      ObjectDelete(0,"MIN");
      ObjectDelete(0,"MINfuture");
      name="MAX";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[1].time);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]);
      double price=minH[0];
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
      if(Azz.zHL[0].value>minH[0])
        {
         price=sumH[0]/NUMBER_MA;
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      if(Azz.zHL[0].value>sumH[0]/NUMBER_MA)
        {
         price=maxH[0];
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      //--- into the future
      name="MAXfuture";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,price);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,t[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,maxL[0]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]+NUMBER_MA*shift);
      if(price<maxL[0])
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,sumL[0]/NUMBER_MA);
      if(price<sumL[0]/NUMBER_MA)
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,minL[0]);
     }
   if(Azz.zHL[0].type<0) // trough
     {
      ObjectDelete(0,"MAX");
      ObjectDelete(0,"MAXfuture");
      name="MIN";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[1].time);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]);
      double price=maxL[0];
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
      if(Azz.zHL[0].value<maxL[0])
        {
         price=sumL[0]/NUMBER_MA;
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      if(Azz.zHL[0].value<sumL[0]/NUMBER_MA)
        {
         price=minL[0];
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      //--- into the future
      name="MINfuture";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,price);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,t[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,minH[0]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]+NUMBER_MA*shift);
      if(price>minH[0])
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,sumH[0]/NUMBER_MA);
      if(price>sumH[0]/NUMBER_MA)
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,maxH[0]);
     }

Então, temos o novo e avançado indicador ZigZag que prevê a posição de novos nós (Fig. 9). Os nós ficam localizados nos pontos transeccionais característicos: o máximo, o mínimo e o centro de gravidade. O título provisório do indicador é "dois cometas".

Deve-se notar que o tempo de conclusão do próximo nó, o qual está no futuro, permaneceu desconhecido. Basicamente, podemos prever somente uma coordenada do nó - o preço.

Nós previstos do ZigZag

Fig. 9. O indicador do ZigZag avançado prevê os nós: o atual e o seguinte

 

Análise dos resultados e recomendações para desenvolvedores

As observações do indicador mostraram que:

  1. Desvios das coordenadas dos nós do ZigZag oriundos do nós previstos estão na margem de tolerância. O vasto número de nós fica na sombra do corte transversal correspondente. Esta é certamente uma simples avaliação qualitativa. Resultados mais precisos serão contemplados em futuros artigos.
  2. Os cortes transversais das linhas dos envelopes demonstram o comportamento do mercado e a conjuntura de preço esperada! Preste atenção à cauda do cometa que é composta de pontos com o menor período de média (o menor em tamanho). Ela é conduzida na direção do preço: A cauda do cometa dobra-se na forma mais complexa e quanto mais é virada para a direção oposta, maior as chances de se ver a tendência mudar. Observe simplesmente o comportamento do indicador em diferentes intervalor de tempo com diferentes amplitudes. Isso é extremamente interessante!
  3. Os pontos característicos dos cortes transversais formam linhas que podem apresentar forte resistência ao movimento de preço. Portanto, eles podem ser considerados como apoio e linhas de resistência.
  4. Quando os pontos do centro de gravidade do corte transversal ficam a frente dele (como os picos na Fig. 9), este é um indicador da presença de uma tendência de crescimento.

Então, o que temos como resultado é um indicador muito interessante que pode ser experimentado em uma estratégia de negócios!

 

Conclusão

  • O método para prever os nós do indicador ZigZag examinados nesse artigo nos permite criar um novo indicador - "dois cometas".
  • O ZigZag avançado mostra possíveis coordenadas de novos nós, mesmo que seja apenas uma previsão.
  • O algoritmo levado em consideração neste artigo pode ser utilizado para plotar indicadores avançados similares, não necessariamente sendo indicadores ZigZag, por exemplo fractais ou indicadores de semáforo.
  • Programadores novatos do MQL5 podem achar interessante ver como podem criar macros em seus programas para reduzir a quantidade de códigos repetidos.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/646

Arquivos anexados |
advancedzigzag.mqh (3.54 KB)
getextremums.mqh (5.24 KB)
two_comets.mq5 (10.16 KB)
Últimos Comentários | Ir para discussão (3)
Eduardo Gonçalves
Eduardo Gonçalves | 29 nov 2018 em 03:09

Prezados, 

Compilei os arquivos e está com a seguinte mensagem de erro, como poderia solucionar ?


Sant Clear Ali Costa
Sant Clear Ali Costa | 23 fev 2019 em 21:02

Olá parkus,

substitua a linha 74 pelo trecho de código marcado em vermelho.

Sei que você não questionou isso, mas os arquivos <advancedzigzag.mqh> e <getextremums.mqh> devem ser copiados para o diretório <...\MQL5\Include\>. Eu recomendo renomear os arquivos advancedzigzag.mqh para AdvancedZigZag.mqh, getextremums.mqh para GetExtremums.mqh e por fim two_comets.mq5 para AdvancedZigZag.mq5. Esse último como é um expert eu copiei para o diretório <...\MQL5\Experts\Advisors\Downloads\ZigZag\> para uma melhor organização dos plugins.


Correção do Erro

Mauricio Ximenez
Mauricio Ximenez | 26 mai 2019 em 21:07
Seria possível este consultor Comets na versão mql4? Obrigado
Guia prático do MQL5: Desenvolvendo uma estrutura para um sistema de negócios baseado na estratégia de tela tripla Guia prático do MQL5: Desenvolvendo uma estrutura para um sistema de negócios baseado na estratégia de tela tripla
Nesse artigo, desenvolveremos uma estrutura para um sistema de negócios baseado na estratégia de tela tripla no MQL5. O Consultor Especialista não será desenvolvido do zero. Ao invés disso, simplesmente modificaremos o programa do artigo anterior "Guia prático do MQL5: Usando indicadores para definir condições de negócios em Consultores Especialistas" que já servem substancialmente ao nosso propósito. Então o artigo também demonstrará como você pode modificar facilmente padrões de programas já prontos.
Guia prático do MQL5: Utilizando indicadores para ajustar condições de negócios no Consultor Especialista Guia prático do MQL5: Utilizando indicadores para ajustar condições de negócios no Consultor Especialista
Neste artigo, continuaremos a a modificar o Consultor Especialista que estamos trabalhando durante os artigos precedentes da série Guia prático do MQL5. Desta vez, o Consultor Especialista será melhorado com indicadores dos quais os valores serão usados para verificar as condições de abertura de posição. Para aprimorá-lo, criaremos uma lista de menu suspenso nos parâmetros externos para ser possível selecionar um de três indicadores de transações.
Guia prático do MQL5: Consultor Especialista multi-moeda - Abordagem simples, organizada e rápida" Guia prático do MQL5: Consultor Especialista multi-moeda - Abordagem simples, organizada e rápida"
Este artigo descreverá uma implementação de uma abordagem simples, adequada para um Consultor Especialista multi-moeda. Isso significa que você será capaz de montar o Consultor Especialista para testes/negócios sob condições idênticas, mas com parâmetros diferentes para cada símbolo. Como um exemplo, criaremos um padrão para dois símbolos, mas de forma a ser capaz de somar símbolos adicionais, se necessário, fazendo pequenas alterações ao código.
Guia prático do MQL5: O Histórico de transações e a biblioteca de função para obter propriedades de posição Guia prático do MQL5: O Histórico de transações e a biblioteca de função para obter propriedades de posição
É hora de brevemente resumir a informação fornecida nos artigos anteriores sobre as propriedades de posição. Neste artigo, criaremos algumas funções adicionais para obter propriedades que podem apenas serem obtidas após acessar o histórico de transações. Também nos familiarizaremos com estruturas de dados que nos permitirá acessar propriedades de posição e símbolo de forma mais conveniente.