A Configuração
Para começarmos, vamos precisar de:
- 1 gráfico zigzag
- 2 buffers de dados para os altos e baixos
- parâmetros de entrada
- um conjunto contínuo de variáveis do sistema que se reiniciam sempre que o indicador é recalculado
O array upWaves armazenará os altos e o array dwWaves armazenará os baixos.
Variáveis do sistema:
Precisamos saber o último tipo de onda, onde começou, onde terminou, a distância em barras do início ao fim.
Em seguida, precisamos de uma variável de alto local e uma de baixo local, assim como as distâncias em barras de cada ponto.
//--- mantendo o controle do zigzag int wave_type=0; //--- preço da onda (preço de início) double wave_start_price=0.0; //--- preço da onda (preço de fim) double wave_end_price=0.0; //--- distância em barras do preço de início int wave_start_distance=0; //--- distância em barras do preço de fim int wave_end_distance=0; //--- acompanhamento do preço alto double high_mem=0.0; int distance_from_high=0; //--- acompanhamento do preço baixo double low_mem=0.0; int distance_from_low=0; //--- cálculo do atr double rollingAtr=0.0; int rollingAtrs=0;
Por fim, o cálculo do atr em andamento e quantos já foram calculados.
Agora vamos criar uma função de reinício do sistema:
void resetSystem(){
ArrayFill(upWaves,0,ArraySize(upWaves),0.0);
ArrayFill(dwWaves,0,ArraySize(dwWaves),0.0);
wave_type=0;
wave_start_price=0.0;
wave_end_price=0.0;
wave_start_distance=0;
wake_end_distance=0;
high_mem=0.0;
low_mem=0.0;
distance_from_high=0;
distance_from_low=0;
rollingAtr=0.0;
rollingAtrs=0;
}
Com isso, reiniciamos as variáveis do sistema.
No método OnInit, configuramos os buffers, o gráfico e chamamos o reset pela primeira vez:
SetIndexBuffer(0,upWaves,INDICATOR_DATA); SetIndexBuffer(1,dwWaves,INDICATOR_DATA); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_ZIGZAG); PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,Color); PlotIndexSetInteger(0,PLOT_LINE_WIDTH,Width); PlotIndexSetInteger(0,PLOT_LINE_STYLE,Style); resetSystem();
Agora vamos para o cálculo.
A primeira coisa que precisamos cuidar é do cálculo do atr.
Até que tenhamos coletado mais barras do que o período do atr, não faremos mais nada.
A parte que gerencia o atr é a seguinte:
- se não temos coletado mais do que o período, continuamos adicionando a faixa das barras a uma soma
- uma vez que chegamos ao período, fazemos a primeira divisão (média)
- depois, cortamos uma parte do atr em andamento, que é atr/período, e adicionamos uma nova parte que é a faixa da barra / período
//--- gerenciando o atr
rollingAtrs++;
if(rollingAtrs>rollingAtrPeriod){
double new_portion=((high[i]-low[i])/_Point)/((double)rollingAtrPeriod);
//--- removemos uma parte antiga e adicionamos uma nova
rollingAtr=(rollingAtr)-(rollingAtr/((double)rollingAtrPeriod))+new_portion;
}
else if(rollingAtrs<=rollingAtrPeriod){
rollingAtr+=(high[i]-low[i])/_Point;
if(rollingAtrs==rollingAtrPeriod){
rollingAtr/=((double)rollingAtrs);
//--- inicializa a memória para altos e baixos e o sistema
high_mem=high[i];
low_mem=low[i];
distance_from_high=0;
distance_from_low=0;
}
}
Ótimo! Agora, existe outro problema.
A base desse zigzag é o retrocesso.
Mas para um retrocesso ocorrer, deve haver pelo menos uma onda.
Mas qual será a primeira onda a retroceder? 😄
Por isso, faremos o seguinte:
- assim que o atr se preencher (atr coletado = período), pegamos o alto e o baixo nas variáveis do sistema
- o lado que formar uma onda com um tamanho válido em unidades de atr, e formar um novo alto (onda de alta) ou um novo baixo (onda de baixa), vence
Dessa forma, não temos um retrocesso como uma onda inicial, mas precisamos iniciar a sequência de alguma forma.
Isso é o que fazemos enquanto não temos uma onda:
//--- se não temos um tipo de onda ainda
else{
//--- se rompemos o alto e não o baixo
if(high[i]>high_mem&&low[i]>=low_mem){
double new_wave_size_in_atr_units=((high[i]-low_mem)/_Point)/rollingAtr;
//--- se o novo tamanho da onda é válido
if(new_wave_size_in_atr_units>=minSizeInAtrUnits){
//--- inicia uma nova onda de alta
wave_type=1;
//--- preço de início é o baixo mem
wave_start_price=low_mem;
wave_start_distance=distance_from_low;
//--- o preço de fim é o novo alto
wave_end_price=high[i];
wave_end_distance=0;
//--- desenha a onda
dwWaves[i-wave_start_distance]=low_mem;
upWaves[i]=high[i];
//--- atualiza o alto
high_mem=high[i];
distance_from_high=0;
//--- atualiza o baixo
low_mem=low[i];
distance_from_low=0;
}
}
//--- se rompemos o baixo e não o alto
else if(low[i]=minSizeInAtrUnits){
//--- inicia uma nova onda de baixa
wave_type=-1;
//--- preço de início é o alto mem
wave_start_price=high_mem;
wave_start_distance=distance_from_high;
//--- o preço de fim é o novo baixo
wave_end_price=low[i];
wave_end_distance=0;
//--- desenha a onda
upWaves[i-wave_start_distance]=high_mem;
dwWaves[i]=low[i];
//--- atualiza o alto
high_mem=high[i];
distance_from_high=0;
//--- atualiza o baixo
low_mem=low[i];
distance_from_low=0;
}
}
//--- se rompemos ambos
else if(low[i]high_mem){
//--- atualizamos
high_mem=high[i];
low_mem=low[i];
distance_from_high=0;
distance_from_low=0;
}
}
Ótimo! Agora, a peça final.
- Se temos uma onda de alta:
- se um novo alto é feito, movemos o zigzag da posição do alto anterior para a nova posição que podemos fazer, uma vez que mantemos as distâncias das barras. Também atualizamos o baixo e a distância do baixo. Fazemos isso para capturar o menor baixo desde o pico e verificar se ele retrocede o suficiente para iniciar um novo baixo.
- se um novo baixo é feito, ou, um novo baixo é definido, calculamos a distância do pico até o baixo e dividimos pelo tamanho da onda. E também multiplicamos por 100 para corresponder à escala do parâmetro de entrada. Então, se o tamanho da nova "onda" que retrocede a anterior também for válido em relação às unidades de atr, iniciamos uma nova onda de baixa, definimos os novos altos e baixos locais e definimos as distâncias das barras.
Aqui está o código relevante para o que foi mencionado acima:
//--- se temos uma onda de alta
if(wave_type==1){
//--- se a onda se expande para cima
if(high[i]>wave_end_price){
//--- remove o preço de fim anterior de sua posição no array (0.0= vazio)
upWaves[i-wave_end_distance]=0.0;
//--- coloca na nova posição
upWaves[i]=high[i];
wave_end_price=high[i];
wave_end_distance=0;
//--- atualiza o alto
high_mem=high[i];
distance_from_high=0;
//--- atualiza o baixo
low_mem=low[i];
distance_from_low=0;
}
//--- verifica o retrocesso
if(low[i]0.0){
double retraced=(size_of_retracement/size_of_wave)*100.0;
double new_wave_size_in_atr_units=((wave_end_price-low_mem)/_Point)/rollingAtr;
//--- se o novo tamanho da onda é válido
if(new_wave_size_in_atr_units>=minSizeInAtrUnits){
//--- se o retrocesso é significativo, inicia uma onda de baixa
if(retraced>=retracement){
//--- inicia uma nova onda de baixa
wave_type=-1;
//--- preço de início é o alto mem
wave_start_price=high[i-distance_from_high];
wave_start_distance=distance_from_high;
//--- o preço de fim é o novo baixo
wave_end_price=low[i];
wave_end_distance=0;
//--- desenha a onda
upWaves[i-wave_start_distance]=high_mem;
dwWaves[i]=low[i];
//--- atualiza o alto
high_mem=high[i];
distance_from_high=0;
//--- atualiza o baixo
low_mem=low[i];
distance_from_low=0;
}
}
}
}
}
Fazemos o oposto quando temos uma onda de baixa.
E estamos prontos! Nosso zigzag de retrocesso está finalizado.
Aqui está o zigzag com 23.6% de retrocesso e 0.0 min tamanho das ondas em unidades de atr.

E aqui está o mesmo zigzag com 3 min tamanho das ondas em unidades de atr.

Publicações relacionadas
- Calendário Econômico: Monitoramento e Cache para Testes de Estratégia no MetaTrader 5
- Buffers Horários para Coleta de Dados no MetaTrader 5
- Índice de Preferência do Investidor: Um Guia Prático para Traders
- Utilitário de Informações de Séries e Taxas para MetaTrader 5: Maximize Seu Trading
- Divergência no Awesome Oscillator: O Guia Completo para Traders