
O indicador ZigZag: nova abordagem e novas soluções
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.
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.
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.
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:
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:
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.
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) }
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:
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:
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.
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:
- 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.
- 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!
- 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.
- 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





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso
Prezados,
Compilei os arquivos e está com a seguinte mensagem de erro, como poderia solucionar ?
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.