Escolar Documentos
Profissional Documentos
Cultura Documentos
Novo artigo
METATRADER 5 — EXEMPLOS
0 3 944
ANATOLI KAZHARSKI
Conteúdo
Introdução
Versão estendida do indicador ZigZag
Classe para obter os dados do indicador ZigZag
Visualização do conjunto de dados obtidos
EA para testar os resultados obtidos
Retomando o desenvolvimento da classe CZigZagModule
Conclusão
Introdução
Em um dos artigos anteriores, eu mostrei como um indicador como o Índice de Força Relativa (RSI) pode ser
apresentado. Em uma de suas versões, o resultado obtido pode ser usado para receber simultaneamente os sinais para
as condições de tendência e lateralizada. O indicador provavelmente carece de apenas uma coisa — a capacidade de
definir o comportamento dos preços, o que também pode ser muito importante para decidir quando negociar e quando
parar de negociar.
Muitos pesquisadores simplesmente ignoram ou não prestam atenção o suficiente para determinar o comportamento do
preço. Ao mesmo tempo, são usados métodos complexos, que muitas vezes são “caixas pretas”, como aprendizado de
máquina ou redes neurais. A questão mais importante que surge nesse caso é quais dados enviar para o treinamento de
https://www.mql5.com/pt/articles/5543 1/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
um determinado modelo. Neste artigo, nós vamos expandir as ferramentas para esses estudos. Você descobrirá como
selecionar os símbolos mais apropriados para negociação antes de procurar os parâmetros ideais. Para conseguir isso,
nós usaremos uma versão modificada do indicador ZigZag e o código da classe que simplifica significativamente a
obtenção e o trabalho com dados de indicadores pertencentes a esse tipo.
Nesta série de artigos, nós vamos implementar:
Preço de Ask mínimo. Os valores mínimos do ZigZag devem ser baseados neles
Preço de Bid máximo. Os valores máximos do ZigZag devem ser baseados neles
Máximas
Mínimas
Todos as máximas detectadas de um segmento ascendente
Todas as mínimas detectadas de um segmento descendente
https://www.mql5.com/pt/articles/5543 2/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots 5
//---
#property indicator_color1 clrRed
#property indicator_color2 clrCornflowerBlue
#property indicator_color3 clrGold
#property indicator_color4 clrOrangeRed
#property indicator_color5 clrSkyBlue
Vamos adicionar a capacidade de definir o número de barras (NumberOfBars) nos parâmetros de entrada, a fim de
construir as linhas do indicador. Zero significa que todos os dados presentes no gráfico devem ser usados. O parâmetro
MinImpulseSize define o número de pontos, pelo qual o preço deve desviar do último valor extremo para começar a
construir um segmento direcionado de forma oposta. Além disso, vamos adicionar a capacidade de definir quais buffers
do indicador devem ser exibidos no gráfico, bem como a cor dos segmentos do ZigZag, como parâmetros adicionais.
No nível global, declare as variáveis auxiliares necessárias para calcular os valores extremos. Nós precisamos salvar os
índices dos pontos extremos calculados anteriormente, rastrear a direção do segmento atual, bem como salvar os
preços mínimos de compra (ask) e o máximo de venda (bid).
//--- Variáveis ZZ
int last_zz_max =0;
int last_zz_min =0;
int direction_zz =0;
double min_low_ask =0;
double max_high_bid =0;
A função FillAskBidBuffers() é usada para preencher os buffers do indicador para a mínima do preço de ask e a máxima
do preço de bid. Para o buffer de bid, salve os valores do array High, enquanto que para o buffer de ask, salve os
https://www.mql5.com/pt/articles/5543 3/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
//+-------------------------------------------------------------------+
//| Preencher os buffers da Máxima de Bid e mínima de Ask do indicador|
//+-------------------------------------------------------------------+
void FillAskBidBuffers(const int i,const datetime &time[],const double &high[],const double &lo
{
//--- Sai se a data inicial não for atingida
if(time[i]<first_date)
return;
//---
high_bid_buffer[i] =high[i];
low_ask_buffer[i] =low[i]+(spread[i]*_Point);
}
A função FillIndicatorBuffers() serve para definir os pontos extremos do ZigZag. Os cálculos são realizados somente a
partir da data especificada dependendo do número de barras definidas no parâmetro de entrada MinImpulseSize. O
programa insere o bloco de código apropriado de acordo com a direção do segmento definida durante a chamada de
função anterior.
Se essas condições forem atendidas, (1) lembre-se do índice atual do array de dados,
(2) salve a nova direção do segmento (ascendente) na variável e (3) atribua o valor
atual de Bid máximo aos elementos atuais dos buffers do indicador.
//+------------------------------------------------------------------+
//| Preenche os buffers do indicador ZZ |
//+------------------------------------------------------------------+
void FillIndicatorBuffers(const int i,const datetime &time[])
{
if(time[i]<first_date)
return;
//--- Se ZZ se move para cima
if(direction_zz>0)
{
//--- No caso de uma nova alta
if(high_bid_buffer[i]>=max_high_bid)
{
zz_H_buffer[last_zz_max] =0;
last_zz_max =i;
max_high_bid =high_bid_buffer[i];
zz_H_buffer[i] =high_bid_buffer[i];
total_zz_h_buffer[i] =high_bid_buffer[i];
}
//--- Se a direção mudou (para baixo)
else
{
if(low_ask_buffer[i]<max_high_bid &&
fabs(low_ask_buffer[i]-zz_H_buffer[last_zz_max])>MinImpulseSize*_Point)
{
last_zz_min =i;
direction_zz =-1;
min_low_ask =low_ask_buffer[i];
zz_L_buffer[i] =low_ask_buffer[i];
total_zz_l_buffer[i] =low_ask_buffer[i];
}
}
}
//--- Se ZZ se move para baixo
else
{
//--- No caso de uma nova baixa
if(low_ask_buffer[i]<=min_low_ask)
{
zz_L_buffer[last_zz_min] =0;
last_zz_min =i;
https://www.mql5.com/pt/articles/5543 5/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
min_low_ask =low_ask_buffer[i];
zz_L_buffer[i] =low_ask_buffer[i];
total_zz_l_buffer[i] =low_ask_buffer[i];
}
//--- Se a direção mudou (para cima)
else
{
if(high_bid_buffer[i]>min_low_ask &&
fabs(high_bid_buffer[i]-zz_L_buffer[last_zz_min])>MinImpulseSize*_Point)
{
last_zz_max =i;
direction_zz =1;
max_high_bid =high_bid_buffer[i];
zz_H_buffer[i] =high_bid_buffer[i];
total_zz_h_buffer[i] =high_bid_buffer[i];
}
}
}
}
O código da função principal do indicador é exibido abaixo. O indicador é calculado apenas pelas barras formadas.
Depois disso, são definidos (1) os arrays e as variáveis como zero, (2) o número de barras para cálculo e o índice inicial.
Inicialmente, os dados de todos os elementos dos buffers do indicador são calculados e, após isso, são calculados
somente os dados da última barra. Depois de realizar os cálculos e verificações preliminares, os buffers do indicador
são calculados e preenchidos.
//+------------------------------------------------------------------+
//| Função de iteração do indicador personalizado |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,const int prev_calculated,const datetime &time[],
const double &open[],const double &high[],const double &low[],const double &clo
const long &tick_volume[],const long &volume[],const int &spread[])
{
//--- Evitar o cálculo a cada tick
if(prev_calculated==rates_total)
return(rates_total);
//--- Se este é o primeiro cálculo
if(prev_calculated==0)
{
//--- Define os buffers do indicador para zero
ZeroIndicatorBuffers();
//--- Define as variáveis para zero
ZeroIndicatorData();
//--- Verifica a quantidade de dados disponíveis
if(!CheckDataAvailable())
return(0);
https://www.mql5.com/pt/articles/5543 6/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
//--- Se forem especificados mais dados para copiar, o valor atual é usado
DetermineNumberData();
//--- Define a plotagem de barras para cada símbolo a partir de
DetermineBeginForCalculate(rates_total);
}
else
{
//--- Calcula o último valor apenas
start=prev_calculated-1;
}
//--- Preenche os buffers do indicador High Bid e Low Ask
for(int i=start; i<rates_total; i++)
FillAskBidBuffers(i,time,high,low,spread);
//--- Preenche os buffers do indicador com dados
for(int i=start; i<rates_total-1; i++)
FillIndicatorBuffers(i,time);
//--- Retorna o tamanho do array de dados
return(rates_total);
}
https://www.mql5.com/pt/articles/5543 7/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
A próxima captura de tela exibe o indicador no EURMXN M5. Aqui nós podemos ver o spread crescendo
significativamente à noite. No entanto, o indicador é calculado considerando o spread.
https://www.mql5.com/pt/articles/5543 8/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Na próxima seção, nós consideraremos um código da classe com métodos que nos ajudam a obter todos os dados
necessários para definir o comportamento atual do preço.
https://www.mql5.com/pt/articles/5543 9/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Como nós podemos trabalhar com várias instâncias da classe simultaneamente, por exemplo, com dados do ZigZag de
diferentes períodos de tempo, talvez seja necessário visualizar os segmentos obtidos usando as linhas de tendência de
cores diferentes. Portanto, nós incluímos o arquivo ChartObjectsLines.mqh da biblioteca padrão para o arquivo da
classe CZigZagModule. A partir deste arquivo, nós vamos precisar da classe CChartObjectTrend para trabalhar com as
linhas de tendência. A cor das linhas de tendência pode ser especificada pelo método público
CZigZagModule::LinesColor(). A cor cinza (clrGray) é definida por padrão.
//+------------------------------------------------------------------+
//| ZigZagModule.mqh |
//| Copyright 2018, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#include <ChartObjects\ChartObjectsLines.mqh>
//+------------------------------------------------------------------+
//| Classe para a obtenção de dados do indicador ZigZag |
//+------------------------------------------------------------------+
class CZigZagModule
{
protected:
//--- linhas de segmento
CChartObjectTrend m_trend_lines[];
https://www.mql5.com/pt/articles/5543 10/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Antes de obter os dados do indicador ZigZag, nós precisamos definir o número de valores extremos necessários para o
trabalho. Para conseguir isso, nós devemos chamar o método CZigZagModule::CopyExtremums(). Os arrays dinâmicos
separados foram declarados para armazenar (1) as extremidades do preços, (2) índices das barras extremas, (3) o
tempo de suas barras e o (4) número de segmentos para construção das linhas de tendência em um gráfico. O tamanho
dos arrays é definido no mesmo método.
O número de segmentos é calculado automaticamente a partir do número de extremos especificados. Por exemplo, se
nós passarmos 1 para o método CZigZagModule::CopyExtremums(), nós recebemos os dados em uma máxima e
mínima. Neste caso, ele é apenas um segmento do indicador ZigZag. Se um valor maior que 1 for passado, o número de
segmentos é sempre igual ao número de extremos copiados multiplicado por 2 menos 1. Em outras palavras, o número
de segmentos sempre será ímpar:
Um extremo - 1 segmento
Dois extremos - 3 segmentos
Três extremos - 5 segmentos, etc.
class CZigZagModule
{
protected:
int m_copy_extremums; // Número de máximas/mínimas salvas
int m_segments_total; // Número de segmentos
//--- Preços extremos
double m_zz_low[];
double m_zz_high[];
//--- Índices das barras extremas
int m_zz_low_bar[];
int m_zz_high_bar[];
//--- Horário das barras extremas
datetime m_zz_low_time[];
datetime m_zz_high_time[];
//---
};
//+------------------------------------------------------------------+
//| Construtor |
//+------------------------------------------------------------------+
CZigZagModule::CZigZagModule(void) : m_copy_extremums(1),
m_segments_total(1)
{
CopyExtremums(m_copy_extremums);
}
//+------------------------------------------------------------------+
//| Número de extremos para trabalhar |
//+------------------------------------------------------------------+
void CZigZagModule::CopyExtremums(const int total)
{
https://www.mql5.com/pt/articles/5543 11/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
if(total<1)
return;
//---
m_copy_extremums =total;
m_segments_total =total*2-1;
//---
::ArrayResize(m_zz_low,total);
::ArrayResize(m_zz_high,total);
::ArrayResize(m_zz_low_bar,total);
::ArrayResize(m_zz_high_bar,total);
::ArrayResize(m_zz_low_time,total);
::ArrayResize(m_zz_high_time,total);
::ArrayResize(m_trend_lines,m_segments_total);
}
Antes de nós começarmos a trabalhar com os dados do indicador ZigZag, coloque-os nos arrays da classe descrita acima
para um uso mais conveniente. Nós vamos precisar de campos auxiliares para serem usados como contadores de
extremos.
Para obter os dados, nós precisamos do método CZigZagModule::GetZigZagData(). É necessário passar ele o array
contendo os dados iniciais do indicador ZigZag junto com o array de tempo. Estes dados de origem podem ser obtidos
usando as funções CopyBuffer() e CopyTime(). Antes de obter os valores necessários dos dados de origem, todos os
campos e arrays devem ser redefinidos. Em seguida, obtenha o número especificado dos extremos (1) dos preços, (2)
dos índices das barras e (3) do horário.
A direção do segmento atual é definida no final do método. Aqui, se o horário do segmento da máxima atual exceder o
da mínima, a direção é para cima. Caso contrário, é para baixo.
class CZigZagModule
{
protected:
int m_direction; // Direção
int m_counter_lows; // Contador da Mínima
int m_counter_highs; // Contado da Máxima
//---
public:
//--- Obtém os dados
void GetZigZagData(const double &zz_h[],const double &zz_l[],const datetime &ti
//--- Redefine a estrutura
void ZeroZigZagData(void);
};
//+------------------------------------------------------------------+
//| Obtém os dados do ZigZag |
//+------------------------------------------------------------------+
void CZigZagModule::GetZigZagData(const double &zz_h[],const double &zz_l[],const datetime &tim
{
https://www.mql5.com/pt/articles/5543 12/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Agora que os dados foram recebidos, nós podemos considerar outros métodos dessa classe. Para obter os preços
extremos, índices da barra extrema e o horário das barras em que esses extremos foram formados, basta chamar o
método apropriado (veja o código abaixo) especificando um índice extremo. Apenas o código do método
CZigZagModule::LowPrice() é fornecido aqui como exemplo, uma vez que são quase idênticos.
class CZigZagModule
{
public:
https://www.mql5.com/pt/articles/5543 13/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
//--- Preço dos extremos por um índice especificado
double LowPrice(const int index);
double HighPrice(const int index);
//--- Índice de uma barra extrema por um índice especificado
int LowBar(const int index);
int HighBar(const int index);
//--- Horário de uma barra extrema por um índice especificado
datetime LowTime(const int index);
datetime HighTime(const int index);
};
//+------------------------------------------------------------------+
//| Valor da mínima pelo índice especificado |
//+------------------------------------------------------------------+
double CZigZagModule::LowPrice(const int index)
{
if(index>=::ArraySize(m_zz_low))
return(0.0);
//---
return(m_zz_low[index]);
}
class CZigZagModule
{
public:
//--- Tamanho do segmento por um índice especificado
double SegmentSize(const int index);
};
//+------------------------------------------------------------------+
//| Retorna o tamanho do segmento pelo índice |
//+------------------------------------------------------------------+
double CZigZagModule::SegmentSize(const int index)
{
if(index>=m_segments_total)
return(-1);
//---
double size=0;
//--- Se o valor for par
if(index%2==0)
{
int i=index/2;
size=::fabs(m_zz_high[i]-m_zz_low[i]);
https://www.mql5.com/pt/articles/5543 14/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
}
//--- Se o valor for ímpar
else
{
int l=0,h=0;
//---
if(Direction()>0)
{
h=(index-1)/2+1;
l=(index-1)/2;
}
else
{
h=(index-1)/2;
l=(index-1)/2+1;
}
//---
size=::fabs(m_zz_high[h]-m_zz_low[l]);
}
//---
return(size);
}
O método CZigZagModule::SegmentsSum() é usado para obter a soma de todos os segmentos. Tudo aqui é simples, já
que o método CZigZagModule::SegmentSize() descrito acima é chamado quando ele passa ao longo de todos os
segmentos em um loop.
class CZigZagModule
{
public:
//--- Soma de todos os segmentos
double SegmentsSum(void);
};
//+------------------------------------------------------------------+
//| Tamanho total de todos os segmentos |
//+------------------------------------------------------------------+
double CZigZagModule::SegmentsSum(void)
{
double sum=0.0;
//---
for(int i=0; i<m_segments_total; i++)
sum+=SegmentSize(i);
//---
return(sum);
}
https://www.mql5.com/pt/articles/5543 15/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Além disso, talvez seja necessário obter a soma de todos os segmentos direcionados apenas para cima ou para baixo. O
código para segmentos ascendentes é exibido abaixo como um exemplo. Tudo depende da direção do segmento atual.
Se for direcionado para cima, os índices atuais são usados em um loop para os cálculos. Se a direção atual for para
baixo, o cálculos devem ser iniciados a partir do primeiro índice com um deslocamento de um elemento para trás para
as máximas. Se você quiser obter a soma de todos os segmentos direcionados para baixo, use o mesmo método, tendo
uma única diferença se a direção atual for para cima, na qual o deslocamento acontece para as mínimas.
class CZigZagModule
{
public:
//--- Soma dos segmentos direcionados (1) para cima e (2) para baixo
double SumSegmentsUp(void);
double SumSegmentsDown(void);
};
//+------------------------------------------------------------------+
//| Retorna o tamanho de todos os segmentos ascendentes |
//+------------------------------------------------------------------+
double CZigZagModule::SumSegmentsUp(void)
{
double sum=0.0;
//---
for(int i=0; i<m_copy_extremums; i++)
{
if(Direction()>0)
sum+=::fabs(m_zz_high[i]-m_zz_low[i]);
else
{
if(i>0)
sum+=::fabs(m_zz_high[i-1]-m_zz_low[i]);
}
}
//---
return(sum);
}
Pode ser útil obter uma taxa percentual das somas de segmentos unidirecionais para o número total de segmentos no
conjunto. Para conseguir isso, use os métodos CZigZagModule::PercentSumSegmentsUp() e
CZigZagModule::PercentSumSegmentsDown(). Eles permitem obter a diferença percentual destas taxas — o método
CZigZagModule::PercentSumSegmentsDifference(), que por sua vez pode nos mostrar a direção do preço atual
(tendência). Se a diferença é insignificante, então o preço flutua uniformemente em ambas as direções (lateralizado).
class CZigZagModule
{
public:
//--- Taxa percentual dos segmentos somados ao número total de todos os segmentos no conjunt
double PercentSumSegmentsUp(void);
https://www.mql5.com/pt/articles/5543 16/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
g p( );
double PercentSumSegmentsDown(void);
//--- Diferença entre as somas dos segmentos
double PercentSumSegmentsDifference(void);
};
//+------------------------------------------------------------------+
//| Retorna o percentual da soma de todos os segmentos de alta |
//+------------------------------------------------------------------+
double CZigZagModule::PercentSumSegmentsUp(void)
{
double sum=SegmentsSum();
if(sum<=0)
return(0);
//---
return(SumSegmentsDown()/sum*100);
}
//+------------------------------------------------------------------+
//| Retorna o percentual da soma de todos os segmentos de baixa |
//+------------------------------------------------------------------+
double CZigZagModule::PercentSumSegmentsDown(void)
{
double sum=SegmentsSum();
if(sum<=0)
return(0);
//---
return(SumSegmentsUp()/sum*100);
}
//+------------------------------------------------------------------+
//| Retorna a diferença da soma de todos os segmentos em percentual |
//+------------------------------------------------------------------+
double CZigZagModule::PercentSumSegmentsDifference(void)
{
return(::fabs(PercentSumSegmentsUp()-PercentSumSegmentsDown()));
}
Para definir o comportamento do preço, nós precisamos de métodos para obter a duração dos segmentos separados e
todo o conjunto resultante. O método CZigZagModule::SegmentBars() serve para obter o número de barras no
segmento especificado. A lógica do código do método é a mesma que a do método CZigZagModule::SegmentSize() para
obter o tamanho do segmento. Portanto, não faz sentido fornecer o seu código aqui.
Para obter o número total de barras no conjunto de dados obtidos, use o método
CZigZagModule::SegmentsTotalBars(). Aqui, são definidos os índices da barra inicial e final no conjunto e retornado a
diferença. O método CZigZagModule::SegmentsTotalSeconds() segue o mesmo princípio. A única diferença é que ele
retorna o número de segundos no conjunto.
https://www.mql5.com/pt/articles/5543 17/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
class CZigZagModule
{
public:
//--- Número de barras em um segmento especificado
int SegmentBars(const int index);
//--- (1) Número de barras e (2) segundos no conjunto de segmentos
int SegmentsTotalBars(void);
long SegmentsTotalSeconds(void);
};
//+------------------------------------------------------------------+
//| Número de barras de todos os segmentos |
//+------------------------------------------------------------------+
int CZigZagModule::SegmentsTotalBars(void)
{
int begin =0;
int end =0;
int l =m_copy_extremums-1;
//---
begin =(m_zz_high_bar[l]>m_zz_low_bar[l])? m_zz_high_bar[l] : m_zz_low_bar[l];
end =(m_zz_high_bar[0]>m_zz_low_bar[0])? m_zz_low_bar[0] : m_zz_high_bar[0];
//---
return(begin-end);
}
//+------------------------------------------------------------------+
//| Número de segundos de todos os segmentos |
//+------------------------------------------------------------------+
long CZigZagModule::SegmentsTotalSeconds(void)
{
datetime begin =NULL;
datetime end =NULL;
int l=m_copy_extremums-1;
//---
begin =(m_zz_high_time[l]<m_zz_low_time[l])? m_zz_high_time[l] : m_zz_low_time[l];
end =(m_zz_high_time[0]<m_zz_low_time[0])? m_zz_low_time[0] : m_zz_high_time[0];
//---
return(long(end-begin));
}
Muitas vezes, pode ser necessário descobrir a faixa de preços dentro do conjunto de dados observado. Para essa
finalidade, a classe apresenta métodos para obter os extremos mínimo e máximo, bem como a diferença entre eles
(faixa de preço).
class CZigZagModule
{
public:
//--- Valores da (1) mínima e (2) máxima do conjunto
https://www.mql5.com/pt/articles/5543 18/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
double LowMinimum(void);
double HighMaximum(void);
//--- Faixa de preço
double PriceRange(void);
};
//+------------------------------------------------------------------+
//| Valor mínimo do conjunto |
//+------------------------------------------------------------------+
double CZigZagModule::LowMinimum(void)
{
return(m_zz_low[::ArrayMinimum(m_zz_low)]);
}
//+------------------------------------------------------------------+
//| Valor máximo do conjunto |
//+------------------------------------------------------------------+
double CZigZagModule::HighMaximum(void)
{
return(m_zz_high[::ArrayMaximum(m_zz_high)]);
}
//+------------------------------------------------------------------+
//| Faixa de preço |
//+------------------------------------------------------------------+
double CZigZagModule::PriceRange(void)
{
return(HighMaximum()-LowMinimum());
}
Ainda há outro conjunto de métodos da classe CZigZagModule que permite receber valores como:
A classe já possui os métodos para obtenção do tamanho dos segmentos e o número de barras do segmento pelo índice
especificado. Portanto, será fácil entender o código dos métodos da lista acima. Todos eles são diferentes apenas nos
métodos chamados dentro deles, portanto, eu vou fornecer os códigos de apenas dois deles —
CZigZagModule::SmallestSegmen() e CZigZagModule::MostNumberOfSegmentBars().
class CZigZagModule
{
public:
//--- O menor segmento do conjunto
double SmallestSegment(void);
//--- O maior segmento do conjunto
double LargestSegment(void);
https://www.mql5.com/pt/articles/5543 19/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
//--- O menor número de barras de um segmento no conjunto
int LeastNumberOfSegmentBars(void);
//--- O maior número de barras de um segmento no conjunto
int MostNumberOfSegmentBars(void);
};
//+------------------------------------------------------------------+
//| O menor segmento do conjunto |
//+------------------------------------------------------------------+
double CZigZagModule::SmallestSegment(void)
{
double min_size=0;
for(int i=0; i<m_segments_total; i++)
{
if(i==0)
{
min_size=SegmentSize(0);
continue;
}
//---
double size=SegmentSize(i);
min_size=(size<min_size)? size : min_size;
}
//---
return(min_size);
}
//+------------------------------------------------------------------+
//| O maior número de barras de um segmento no conjunto |
//+------------------------------------------------------------------+
int CZigZagModule::MostNumberOfSegmentBars(void)
{
int max_bars=0;
for(int i=0; i<m_segments_total; i++)
{
if(i==0)
{
max_bars=SegmentBars(0);
continue;
}
//---
int bars=SegmentBars(i);
max_bars=(bars>max_bars)? bars : max_bars;
}
//---
return(max_bars);
}
https://www.mql5.com/pt/articles/5543 20/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Ao buscar por padrões, nós podemos precisar definir quanto um segmento específico difere em tamanho (em %) do
anterior. Para resolver essas tarefas, use o método CZigZagModule::PercentDeviation().
class CZigZagModule
{
public:
//--- Desvio em porcentagem
double PercentDeviation(const int index);
};
//+------------------------------------------------------------------+
//| Desvio em percentagem |
//+------------------------------------------------------------------+
double CZigZagModule::PercentDeviation(const int index)
{
return(SegmentSize(index)/SegmentSize(index+1)*100);
}
Agora vamos ver como visualizar os dados obtidos e usar a classe CZigZagModule nos projetos personalizados.
class CZigZagModule
{
public:
//--- (1) Exibe e (2) exclui os objetos
void ShowSegments(const string suffix="");
void DeleteSegments(void);
//---
private:
//--- Cria objetos
void CreateSegment(const int segment_index,const string suffix="");
};
//+------------------------------------------------------------------+
//| Exibe os segmentos ZZ em um gráfico |
https://www.mql5.com/pt/articles/5543 21/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
//+------------------------------------------------------------------+
void CZigZagModule::ShowSegments(const string suffix="")
{
for(int i=0; i<m_segments_total; i++)
CreateSegment(i,suffix);
}
//+------------------------------------------------------------------+
//| Remove os segmentos |
//+------------------------------------------------------------------+
void CZigZagModule::DeleteSegments(void)
{
for(int i=0; i<m_segments_total; i++)
{
string name="zz_"+string(::ChartID())+"_"+string(i);
::ObjectDelete(::ChartID(),name);
}
}
Os métodos para exibir os comentários em um gráfico foram adicionados à classe para obter rapidamente as
informações básicas sobre os dados dos indicadores obtidos. O código do método que mostra brevemente os dados do
indicador calculado é exibido abaixo.
class CZigZagModule
{
public:
//--- Comentário no gráfico
void CommentZigZagData();
void CommentShortZigZagData();
};
//+------------------------------------------------------------------+
//| Exibe os dados do ZigZag como um comentário no gráfico |
//+------------------------------------------------------------------+
void CZigZagModule::CommentShortZigZagData(void)
{
string comment="Current direction : "+string(m_direction)+"\n"+
"Copy extremums: "+string(m_copy_extremums)+
"\n---\n"+
"SegmentsTotalBars(): "+string(SegmentsTotalBars())+"\n"+
"SegmentsTotalSeconds(): "+string(SegmentsTotalSeconds())+"\n"+
"SegmentsTotalMinutes(): "+string(SegmentsTotalSeconds()/60)+"\n"+
"SegmentsTotalHours(): "+string(SegmentsTotalSeconds()/60/60)+"\n"+
"SegmentsTotalDays(): "+string(SegmentsTotalSeconds()/60/60/24)+
"\n---\n"+
"PercentSumUp(): "+::DoubleToString(SumSegmentsUp()/SegmentsSum()*100,2)+"\n"
"PercentSumDown(): "+::DoubleToString(SumSegmentsDown()/SegmentsSum()*100,2)+
"PercentDifference(): "+::DoubleToString(PercentSumSegmentsDifference(),2)+
https://www.mql5.com/pt/articles/5543 22/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
"\n---\n"+
"SmallestSegment(): "+::DoubleToString(SmallestSegment()/_Point,0)+"\n"+
"LargestSegment(): "+::DoubleToString(LargestSegment()/_Point,0)+"\n"+
"LeastNumberOfSegmentBars(): "+string(LeastNumberOfSegmentBars())+"\n"+
"MostNumberOfSegmentBars(): "+string(MostNumberOfSegmentBars());
//---
::Comment(comment);
}
Inclua o arquivo que contém a classe CZigZagModule para o arquivo do EA e declare sua instância. Existem dois
parâmetros externos que permitem especificar o número de extremos a serem copiados e a distância mínima para
formar um novo segmento do indicador ZigZag. No nível global, nós também declaramos os arrays dinâmicos para obter
os dados de origem e uma variável para o manipulador do indicador.
//+------------------------------------------------------------------+
//| TestZZ_01.mq5 |
//| Copyright 2018, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#include <ZigZagModule.mqh>
CZigZagModule zz_current;
https://www.mql5.com/pt/articles/5543 23/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Na função OnInit(), nós (1) recebemos o manipulador do indicador, (2) definimos o número de extremos para formar os
dados finais e a cor das linhas de segmento do conjunto obtido, bem como (3) definimos a ordem de indexação reversa
para os arrays de dados de origem.
//+------------------------------------------------------------------+
//| Função de inicialização do Expert |
//+------------------------------------------------------------------+
int OnInit(void)
{
//--- Caminho para o indicador ZZ
string zz_path="Custom\\ZigZag\\ExactZZ_Plus.ex5";
//--- Obtém o manipulador do indicador
zz_handle_current=::iCustom(_Symbol,_Period,zz_path,10000,MinImpulseSize,true,true);
//--- Define a cor para os segmentos e o número de extremos para obtê-lo
zz_current.LinesColor(clrRed);
zz_current.CopyExtremums(CopyExtremum);
//--- Define a ordem de indexação reversa (... 3 2 1 0)
::ArraySetAsSeries(l_zz,true);
::ArraySetAsSeries(h_zz,true);
::ArraySetAsSeries(t_zz,true);
return(INIT_SUCCEEDED);
}
Na função OnTick(), nós obtemos os dados do indicador pelo seu manipulador e o horário de abertura das barras. Então,
preparamos os dados finais chamando o método CZigZagModule::GetZigZagData(). Finalmente, nós visualizamos os
segmentos dos dados obtidos do indicador ZigZag e exibimos esses dados no gráfico como um comentário.
//+------------------------------------------------------------------+
//| Função Tick do Expert |
//+------------------------------------------------------------------+
void OnTick(void)
{
//--- Obtém os dados de origem
int copy_total=1000;
::CopyTime(_Symbol,_Period,0,copy_total,t_zz);
::CopyBuffer(zz_handle_current,2,0,copy_total,h_zz);
::CopyBuffer(zz_handle_current,3,0,copy_total,l_zz);
//--- Obtém os dados finais
zz_current.GetZigZagData(h_zz,l_zz,t_zz);
//--- Visualiza os segmentos em um gráfico
zz_current.ShowSegments();
//--- Exibe os valores dos dados no gráfico como um comentário
zz_current.CommentZigZagData();
}
https://www.mql5.com/pt/articles/5543 24/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Se nós executarmos o EA no testador de estratégia no modo de visualização, nós veremos o seguinte. 5 extremos de
alta e baixa foram obtidos nesse caso. Como resultado, 9 segmentos foram destacados em vermelho no gráfico.
Se nós precisarmos obter os dados do indicador ZigZag de diferentes períodos de tempo ao mesmo tempo, o código do
EA de teste deverá ser um pouco aprimorado. Vamos considerar um exemplo quando você precisa obter os dados de
três períodos gráficos. Neste caso, você precisa declarar três instâncias da classe CZigZagModule. O primeiro período
gráfico é retirado do gráfico atual no qual o EA foi iniciado. Deixe dois outros ser, por exemplo, M15 e H1.
#include <Addons\Indicators\ZigZag\ZigZagModule.mqh>
CZigZagModule zz_current;
https://www.mql5.com/pt/articles/5543 25/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
CZigZagModule zz_m15;
CZigZagModule zz_h1;
Em seguida, na função OnInit(), nós recebemos os manipuladores de forma separada para cada indicador, definindo
cores e o número de extremos:
//+------------------------------------------------------------------+
//| Função de inicialização do Expert |
//+------------------------------------------------------------------+
int OnInit(void)
{
//--- Caminho para o indicador ZZ
string zz_path="Custom\\ZigZag\\ExactZZ_Plus.ex5";
//--- Obtemos os manipuladores do indicador
zz_handle_current =::iCustom(_Symbol,_Period,zz_path,10000,MinImpulseSize,false,false);
zz_handle_m15 =::iCustom(_Symbol,PERIOD_M15,zz_path,10000,MinImpulseSize,false,false);
zz_handle_h1 =::iCustom(_Symbol,PERIOD_H1,zz_path,10000,MinImpulseSize,false,false);
//--- Define a cor dos segmentos
zz_current.LinesColor(clrRed);
zz_m15.LinesColor(clrCornflowerBlue);
zz_h1.LinesColor(clrGreen);
//--- Define o número de extremos para receber
zz_current.CopyExtremums(CopyExtremum);
zz_m15.CopyExtremums(CopyExtremum);
zz_h1.CopyExtremums(CopyExtremum);
//--- Define a ordem de indexação invertida (... 3 2 1 0)
::ArraySetAsSeries(l_zz,true);
::ArraySetAsSeries(h_zz,true);
::ArraySetAsSeries(t_zz,true);
return(INIT_SUCCEEDED);
}
Os dados são recebidos na função OnTick() como é exibido acima para cada instância do indicador ZigZag de forma
separada. Os comentários de apenas um indicador podem ser exibidos no gráfico. Nesse caso, nós olhamos os dados
brevemente para o período gráfico atual do indicador.
https://www.mql5.com/pt/articles/5543 26/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
//+------------------------------------------------------------------+
//| Função Tick do Expert |
//+------------------------------------------------------------------+
void OnTick(void)
{
int copy_total=1000;
::CopyTime(_Symbol,_Period,0,copy_total,t_zz);
::CopyBuffer(zz_handle_current,2,0,copy_total,h_zz);
::CopyBuffer(zz_handle_current,3,0,copy_total,l_zz);
zz_current.GetZigZagData(h_zz,l_zz,t_zz);
zz_current.ShowSegments("_current");
zz_current.CommentShortZigZagData();
//---
::CopyTime(_Symbol,PERIOD_M15,0,copy_total,t_zz);
::CopyBuffer(zz_handle_m15,2,0,copy_total,h_zz);
::CopyBuffer(zz_handle_m15,3,0,copy_total,l_zz);
zz_m15.GetZigZagData(h_zz,l_zz,t_zz);
zz_m15.ShowSegments("_m15");
//---
::CopyTime(_Symbol,PERIOD_H1,0,copy_total,t_zz);
::CopyBuffer(zz_handle_h1,2,0,copy_total,h_zz);
::CopyBuffer(zz_handle_h1,3,0,copy_total,l_zz);
zz_h1.GetZigZagData(h_zz,l_zz,t_zz);
zz_h1.ShowSegments("_h1");
}
https://www.mql5.com/pt/articles/5543 27/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Nós podemos ver que os extremos dos indicadores a partir de períodos gráficos maiores são deslocados ligeiramente
para a esquerda. A razão é que os topos e fundos são definidos pelo tempo de abertura das barras do período em que o
manipulador foi recebido.
https://www.mql5.com/pt/articles/5543 28/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Até agora, nós obtivemos os dados do indicador ZigZag a partir da barra mais recente e se aprofundando nos dados
históricos. No entanto, talvez seja necessário nós obtermos também os dados em uma faixa de tempo específica. Para
conseguir isso, vamos escrever outro método CZigZagModule::GetZigZagData() com um conjunto diferente de
parâmetros. Nesta versão, nós receberemos os dados iniciais dentro do método, portanto, nós precisaremos do
manipulador do indicador, símbolo, período gráfico e o intervalo de tempo (datas de início e término) como
parâmetros.
Mais adiante, nós precisamos contar o número de máximas e mínimas nos dados obtidos de forma separada. Nesse caso,
o número de extremos para o trabalho futuro deve ser definido pela quantidade mínima entre esses contadores.
O método de mesmo nome CZigZagModule::GetZigZagData() com outro conjunto de parâmetros é chamado aqui no
final. Nós consideramos esse conjunto acima, enquanto descrevemos como os arrays contendo os dados de origem
devem ser passados como parâmetros para a obtenção dos dados finais.
class CZigZagModule
{
private:
//--- Arrays para a obtenção dos dados de origem
double m_zz_lows_temp[];
double m_zz_highs_temp[];
datetime m_zz_time_temp[];
//---
public:
//--- Obtém os dados
void GetZigZagData(const int handle,const string symbol,const ENUM_TIMEFRAMES p
};
//+------------------------------------------------------------------+
//| Obtém os dados de ZZ do manipulador passado |
//+------------------------------------------------------------------+
void CZigZagModule::GetZigZagData(const int handle,const string symbol,const ENUM_TIMEFRAMES pe
{
//--- Obtém os dados de origem
::CopyTime(symbol,period,start_time,stop_time,m_zz_time_temp);
::CopyBuffer(handle,2,start_time,stop_time,m_zz_highs_temp);
::CopyBuffer(handle,3,start_time,stop_time,m_zz_lows_temp);
//--- Contadores
int lows_counter =0;
int highs_counter =0;
//--- Contagem das máximas
int h_total=::ArraySize(m_zz_highs_temp);
for(int i=0; i<h_total; i++)
{
if(m_zz_highs_temp[i]>0)
highs_counter++;
}
//--- Contagem das mínimas
int l_total=::ArraySize(m_zz_lows_temp);
https://www.mql5.com/pt/articles/5543 29/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
for(int i=0; i<l_total; i++)
{
if(m_zz_lows_temp[i]>0)
lows_counter++;
}
//--- Obtém o número de extremos
int copy_extremums=(int)::fmin((double)highs_counter,(double)lows_counter);
CopyExtremums(copy_extremums);
//--- Mover ao longo dos valores copiados de ZZ em um loop
GetZigZagData(m_zz_highs_temp,m_zz_lows_temp,m_zz_time_temp);
}
class CZigZagModule
{
public:
//--- Horário da menor mínima
datetime SmallestMinimumTime(void);
//--- Horário da maior máxima
datetime LargestMaximumTime(void);
};
//+------------------------------------------------------------------+
//| Horário da menor mínima |
//+------------------------------------------------------------------+
datetime CZigZagModule::SmallestMinimumTime(void)
{
return(m_zz_low_time[::ArrayMinimum(m_zz_low)]);
}
//+------------------------------------------------------------------+
//| Horário da maior máxima |
//+------------------------------------------------------------------+
datetime CZigZagModule::LargestMaximumTime(void)
{
return(m_zz_high_time[::ArrayMaximum(m_zz_high)]);
}
Além disso, vamos expandir a lista de métodos para trabalhar com os segmentos do ZigZag. Pode ser conveniente obter
vários valores em variáveis passadas por referência de uma só vez. A classe apresenta três desses métodos:
Uma estrutura semelhante está presente em outros métodos considerados anteriormente, portanto, apenas um código
de exemplo é fornecido abaixo.
class CZigZagModule
{
public:
//--- Retorna as barras inicial e final de um segmento especificado
bool SegmentBars(const int index,int &start_bar,int &stop_bar);
//--- Retorna os preços inicial e final de um segmento especificado
bool SegmentPrices(const int index,double &start_price,double &stop_price);
//--- Retorna as horas de início e término de um segmento especificado
bool SegmentTimes(const int index,datetime &start_time,datetime &stop_time);
};
//+------------------------------------------------------------------+
//| Retorna as barras inicial e final de um segmento especificado |
//+------------------------------------------------------------------+
bool CZigZagModule::SegmentBars(const int index,int &start_bar,int &stop_bar)
{
if(index>=m_segments_total)
return(false);
//--- No caso de um número par
if(index%2==0)
{
int i=index/2;
//---
start_bar =(Direction()>0)? m_zz_low_bar[i] : m_zz_high_bar[i];
stop_bar =(Direction()>0)? m_zz_high_bar[i] : m_zz_low_bar[i];
}
//--- No caso de um número ímpar
else
{
int l=0,h=0;
//---
if(Direction()>0)
{
h=(index-1)/2+1;
l=(index-1)/2;
//---
start_bar =m_zz_high_bar[h];
stop_bar =m_zz_low_bar[l];
}
else
{
h=(index-1)/2;
l=(index-1)/2+1;
//---
start_bar =m_zz_low_bar[l];
https://www.mql5.com/pt/articles/5543 31/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
stop_bar =m_zz_high_bar[h];
}
}
//---
return(true);
}
Suponha que nós temos um gráfico em M5 e recebemos os dados de H1. Nós buscamos por padrões a partir do período
gráfico H1 e precisamos definir o comportamento do preço de um determinado segmento do ZigZag a partir do período
H1 sob o atual. Em outras palavras, nós queremos saber como o segmento especificado foi formado em um período
gráfico menor.
Como mostrado na seção anterior, os extremos dos segmentos de períodos gráficos maiores são exibidos no período
atual pelo horário de abertura dos períodos gráficos maiores. Nós já temos o método CZigZagModule::SegmentTimes()
retornando a hora inicial e final de um segmento especificado. Se nós usarmos esse intervalo de tempo para obter os
dados do ZigZag a partir de um período gráfico menor, na maioria dos casos nós teremos muitos segmentos redundantes
realmente pertencentes a outros segmentos de um período gráfico maior. Vamos escrever mais um método
CZigZagModule::SegmentTimes() com outro conjunto de parâmetros no caso de ser necessária uma maior precisão.
Além disso, nós precisaremos de vários métodos auxiliares privados para receber os (1) dados de origem e os (2) índices
dos valores mínimos e máximos nos arrays passados.
class CZigZagModule
{
private:
//--- Copia os dados de origem para os arrays passados
void CopyData(const int handle,const int buffer_index,const string symbol,
const ENUM_TIMEFRAMES period,datetime start_time,datetime stop_ti
double &zz_array[],datetime &time_array[]);
//--- Retorna o índice dos valores (1) mínimo e (2) máximo do array passado
int GetMinValueIndex(double &zz_lows[]);
int GetMaxValueIndex(double &zz_highs[]);
};
//+------------------------------------------------------------------+
//| Copia os dados de origem para os arrays passados |
//+------------------------------------------------------------------+
void CZigZagModule::CopyData(const int handle,const int buffer_index,const string symbol,
const ENUM_TIMEFRAMES period,datetime start_time,datetime stop_tim
double &zz_array[],datetime &time_array[])
{
::CopyBuffer(handle,buffer_index,start_time,stop_time,zz_array);
::CopyTime(symbol,period,start_time,stop_time,time_array);
}
//+------------------------------------------------------------------+
//| Retorna o índice do valor máximo do array passado |
//+------------------------------------------------------------------+
int CZigZagModule::GetMaxValueIndex(double &zz_highs[])
{
https://www.mql5.com/pt/articles/5543 32/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
{
int max_index =0;
double max_value =0;
int total=::ArraySize(zz_highs);
for(int i=0; i<total; i++)
{
if(zz_highs[i]>0)
{
if(zz_highs[i]>max_value)
{
max_index =i;
max_value =zz_highs[i];
}
}
}
//---
return(max_index);
}
//+------------------------------------------------------------------+
//| Retorna o índice do valor mínimo do array passado |
//+------------------------------------------------------------------+
int CZigZagModule::GetMinValueIndex(double &zz_lows[])
{
int min_index =0;
double min_value =INT_MAX;
int total=::ArraySize(zz_lows);
for(int i=0; i<total; i++)
{
if(zz_lows[i]>0)
{
if(zz_lows[i]<min_value)
{
min_index =i;
min_value =zz_lows[i];
}
}
}
//---
return(min_index);
}
Primeiro, nós precisamos obter o horário de abertura da primeira e da última barras de um segmento especificado. Para
fazer isso, chame o primeiro método CZigZagModule::SegmentTimes() descrito acima.
Em seguida, use o método CZigZagModule::CopyData() para receber os dados sobre o horário das barras e extremos.
Dependendo da direção do segmento, nós obtemos os dados em uma determinada sequência. No caso da direção
ascendente, nós primeiro obtemos os dados sobre as mínimas do ZigZag de período gráfico menor que fazem parte do
segmento da primeira barra em um período gráfico maior. Depois disso, nós obtemos os dados sobre as máximas do
ZigZag de período gráfico menor que fazem parte do último segmento da barra em um período gráfico maior. No caso
da direção descendente, a sequência de ações é invertida. Primeiro, nós precisamos obter os dados sobre as máximas
seguidas de informações sobre as mínimas.
Depois de receber os dados de origem, encontre o índices de valores máximos e mínimos. Usando esses índices, você
pode descobrir o horário de início e término do segmento analisado em um período gráfico menor.
class CZigZagModule
{
public:
//--- Retorna o horário de início e término de um segmento especificado considerando um perí
bool SegmentTimes(const int handle,const int highs_buffer_index,const int lows_
const string symbol,const ENUM_TIMEFRAMES period,const ENUM_T
const int index,datetime &start_time,datetime &stop_time);
};
//+------------------------------------------------------------------+
//| Retorna o horário de início e término de um segmento especificado|
//| considerando o período gráfico menor |
//+------------------------------------------------------------------+
bool CZigZagModule::SegmentTimes(const int handle,const int highs_buffer_index,const int lows_b
const string symbol,const ENUM_TIMEFRAMES period,const ENUM_TI
const int index,datetime &start_time,datetime &stop_time)
{
//--- Obtém o horário sem considerar o período gráfico atual
datetime l_start_time =NULL;
datetime l_stop_time =NULL;
if(!SegmentTimes(index,l_start_time,l_stop_time))
https://www.mql5.com/pt/articles/5543 34/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
return(false);
//---
double zz_lows[];
double zz_highs[];
datetime zz_lows_time[];
datetime zz_highs_time[];
datetime start =NULL;
datetime stop =NULL;
int period_seconds=::PeriodSeconds(period);
//--- Obtém os dados de origem no caso da direção ascendente
if(SegmentDirection(index)>0)
{
//--- Dados na primeira barra do período gráfico maior
start =l_start_time;
stop =l_start_time+period_seconds;
CopyData(handle,lows_buffer_index,symbol,in_period,start,stop,zz_lows,zz_lows_time);
//--- Dados na última barra do período gráfico maior
start =l_stop_time;
stop =l_stop_time+period_seconds;
CopyData(handle,highs_buffer_index,symbol,in_period,start,stop,zz_highs,zz_highs_time);
}
//--- Obtém os dados de origem no caso da direção descendente
else
{
//--- Dados na primeira barra do período gráfico maior
start =l_start_time;
stop =l_start_time+period_seconds;
CopyData(handle,highs_buffer_index,symbol,in_period,start,stop,zz_highs,zz_highs_time);
//--- Dados na última barra do período gráfico maior
start =l_stop_time;
stop =l_stop_time+period_seconds;
CopyData(handle,lows_buffer_index,symbol,in_period,start,stop,zz_lows,zz_lows_time);
}
//--- Busca o índice do valor máximo
int max_index =GetMaxValueIndex(zz_highs);
//--- Busca pelo índice do valor mínimo
int min_index =GetMinValueIndex(zz_lows);
//--- Obtém o horário de início e término do segmento
start_time =(SegmentDirection(index)>0)? zz_lows_time[min_index] : zz_highs_time[max_index]
stop_time =(SegmentDirection(index)>0)? zz_highs_time[max_index] : zz_lows_time[min_index]
//--- Bem sucedido
return(true);
}
Agora vamos escrever um EA para testes. O período atual é M5. Use-o para iniciar o EA no modo de visualização do
testador de estratégia. Nós vamos receber os dados a partir de H1, assim como do período gráfico atual. O código do EA
https://www.mql5.com/pt/articles/5543 35/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Primeiro, nós obteremos os dados de H1 usando o primeiro método e exibiremos os segmentos no gráfico para maior
clareza. Em seguida, obtenha os dados do ZigZag do período gráfico atual (M5) no intervalo de tempo do terceiro
(índice 2) segmento do ZigZag em H1. Para fazer isso, obtenha o início e o fim do segmento considerando o período
gráfico atual.
Então, obtenha os dados para o período gráfico atual usando o segundo método e também exiba os segmentos no
gráfico para garantir que tudo esteja bem.
//+------------------------------------------------------------------+
//| Função Tick do Expert |
//+------------------------------------------------------------------+
void OnTick(void)
{
int copy_total=1000;
int h_buff=2,l_buff=3;
//--- Primeiro método para obtenção dos dados
::CopyTime(_Symbol,PERIOD_H1,0,copy_total,t_zz);
::CopyBuffer(zz_handle_h1,h_buff,0,copy_total,h_zz);
::CopyBuffer(zz_handle_h1,l_buff,0,copy_total,l_zz);
zz_h1.GetZigZagData(h_zz,l_zz,t_zz);
zz_h1.ShowSegments("_h1");
//---
int segment_index =2;
int start_bar =0;
int stop_bar =0;
double start_price =0.0;
double stop_price =0.0;
datetime start_time =NULL;
datetime stop_time =NULL;
datetime start_time_in =NULL;
datetime stop_time_in =NULL;
//---
zz_h1.SegmentBars(segment_index,start_bar,stop_bar);
zz_h1.SegmentPrices(segment_index,start_price,stop_price);
zz_h1.SegmentTimes(segment_index,start_time,stop_time);
zz_h1.SegmentTimes(zz_handle_current,h_buff,l_buff,_Symbol,PERIOD_H1,_Period,segment_index,s
https://www.mql5.com/pt/articles/5543 36/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
"\n---\n"+
"Direction > segment["+string(segment_index)+"]: "+string(zz_h1.SegmentDirect
"\n---\n"+
"Start bar > segment["+string(segment_index)+"]: "+string(start_bar)+"\n"+
"Stop bar > segment["+string(segment_index)+"]: "+string(stop_bar)+
"\n---\n"+
"Start price > segment["+string(segment_index)+"]: "+::DoubleToString(start_p
"Stop price > segment["+string(segment_index)+"]: "+::DoubleToString(stop_pri
"\n---\n"+
"Start time > segment["+string(segment_index)+"]: "+::TimeToString(start_time
"Stop time > segment["+string(segment_index)+"]: "+::TimeToString(stop_time,T
"\n---\n"+
"Start time (in tf) > segment["+string(segment_index)+"]: "+::TimeToString(st
"Stop time (in tf) > segment["+string(segment_index)+"]: "+::TimeToString(sto
"\n---\n"+
"Extremums copy: "+string(zz_current.CopyExtremums())+"\n"+
"SmallestMinimumTime(): "+string(zz_current.SmallestMinimumTime())+"\n"+
"LargestMaximumTime(): "+string(zz_current.LargestMaximumTime());
//---
::Comment(comment);
}
https://www.mql5.com/pt/articles/5543 37/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Em seguida, desenvolva mais um EA para receber os dados dos três segmentos de um período gráfico maior.
Nós agora devemos declarar quatro instâncias da classe CZigZagModule no início do arquivo. Um deles é destinado ao
período gráfico maior (H1), enquanto os três restantes destinam-se ao período atual. Neste caso, nós realizamos os
testes no M5.
CZigZagModule zz_h1;
CZigZagModule zz_current0;
CZigZagModule zz_current1;
CZigZagModule zz_current2;
https://www.mql5.com/pt/articles/5543 38/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
Para maior clareza, os segmentos do menor período gráfico dentro dos segmentos do maior serão exibidos em cores
diferentes:
Na função OnTick(), nós recebemos primeiro os dados do período gráfico em H1 e, em seguida, obtemos os dados do
período gráfico menor para o primeiro, segundo e terceiro segmentos em sequência. Exibe os dados em cada grupo dos
segmentos obtidos de período gráfico menor e no período gráfico maior de forma separada nos comentário do gráfico.
Nesse caso, essa é a diferença entre as taxas percentuais das somas do segmento. Ele pode ser obtido usando o método
CZigZagModule::PercentSumSegmentsDifference().
//+------------------------------------------------------------------+
//| Função Tick do Expert |
//+------------------------------------------------------------------+
void OnTick(void)
{
int copy_total=1000;
int h_buff=2,l_buff=3;
//--- Primeiro método para obtenção dos dados
::CopyTime(_Symbol,PERIOD_H1,0,copy_total,t_zz);
::CopyBuffer(zz_handle_h1,h_buff,0,copy_total,h_zz);
::CopyBuffer(zz_handle_h1,l_buff,0,copy_total,l_zz);
zz_h1.GetZigZagData(h_zz,l_zz,t_zz);
zz_h1.ShowSegments("_h1");
//---
datetime start_time_in =NULL;
datetime stop_time_in =NULL;
//--- Dado do primeiro segmento
zz_h1.SegmentTimes(zz_handle_current,h_buff,l_buff,_Symbol,PERIOD_H1,_Period,0,start_time_in
zz_current0.GetZigZagData(zz_handle_current,_Symbol,_Period,start_time_in,stop_time_in);
zz_current0.ShowSegments("_current0");
//--- Dado do segundo segmento
zz_h1.SegmentTimes(zz_handle_current,h_buff,l_buff,_Symbol,PERIOD_H1,_Period,1,start_time_in
zz_current1.GetZigZagData(zz_handle_current,_Symbol,_Period,start_time_in,stop_time_in);
zz_current1.ShowSegments("_current1");
//--- Dado do terceiro segmento
zz_h1.SegmentTimes(zz_handle_current,h_buff,l_buff,_Symbol,PERIOD_H1,_Period,2,start_time_in
zz_current2.GetZigZagData(zz_handle_current,_Symbol,_Period,start_time_in,stop_time_in);
zz_current2.ShowSegments("_current2");
//--- Exibe os dados nos comentários do gráfico
string comment="H1: "+::DoubleToString(zz_h1.PercentSumSegmentsDifference(),2)+"\n"+
"segment[0]: "+::DoubleToString(zz_current0.PercentSumSegmentsDifference(),2
https://www.mql5.com/pt/articles/5543 39/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
"segment[1]: "+::DoubleToString(zz_current1.PercentSumSegmentsDifference(),2
"segment[2]: "+::DoubleToString(zz_current2.PercentSumSegmentsDifference(),2
//---
::Comment(comment);
}
Essa abordagem fornece oportunidades adicionais para analisar a natureza do comportamento do preço dentro dos
padrões. Suponha que nós definimos o padrão em H1 e analisamos como o preço se comportou dentro de cada
https://www.mql5.com/pt/articles/5543 40/42
01/01/2021 O poder do ZigZag (parte I). Desenvolvimento da classe base do indicador - Artigos MQL5
segmento. Os métodos da classe CZigZagModule permitem obter todas as propriedades dos extremos e segmentos, tais
como:
Esse conjunto básico pode ser usado como ponto de partida para o desenvolvimento de vários parâmetros
personalizados para a criação de indicadores. Os testes mostrarão quais benefícios podem ser derivados disso. Este site
contém vários artigos que podem ser úteis na condução de sua própria pesquisa sobre o assunto.
Conclusão
A ideia de que o ZigZag não é adequado para gerar sinais de negociação é amplamente difundida em fóruns de
negociação. Este é um grande equívoco. De fato, nenhum outro indicador fornece tanta informação para determinar a
natureza do comportamento do preço. Agora você tem uma ferramenta que lhe permite obter facilmente todos os
dados necessários do indicador ZigZag para uma análise mais detalhada.
Nos próximos artigos da série, eu mostrarei quais indicadores podem ser desenvolvidos usando a classe CZigZagModule,
bem como os EAs para obter estatísticas sobre diferentes símbolos do indicador ZigZag e a verificação de algumas
estratégias de negociação baseadas no ZigZag que podem ser desenvolvidas.
Aviso: Todos os direitos a estes materiais são reservados a MetaQuotes Ltd. A cópia ou reprodução destes materiais total ou parcial é proibida.
https://www.mql5.com/pt/articles/5543 42/42