Você está na página 1de 46

01/01/2021 O poder do ZigZag (parte II).

Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Novo artigo
METATRADER 5 — EXEMPLOS

O PODER DO ZIGZAG (PARTE II). EXEMPLOS DE


RECEBIMENTO, PROCESSAMENTO E EXIBIÇÃO DE
DADOS
2 abril 2019, 10:55

0 2 095
ANATOLI KAZHARSKI

Conteúdo
Introdução
Indicadores definindo o comportamento de preços
Indicador FrequencyChangeZZ
Indicador SumSegmentsZZ
Indicador PercentageSegmentsZZ
Indicador MultiPercentageSegmentsZZ
EA para coleta e exibição de estatísticas
Contagem do número de segmentos por tamanho
Contagem do número de segmentos por duração
Alguns detalhes de como trabalhar com a interface gráfica
Conclusão

Introdução
Na primeira parte do artigo eu descrevi um indicador ZigZag modificado e uma classe para receber os dados desses
tipos de indicadores. Aqui, eu mostrarei como desenvolver indicadores baseados nessas ferramentas e escrever um EA

https://www.mql5.com/pt/articles/5544 1/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

para testes que apresentem operações de acordo com os sinais formados pelo indicador ZigZag.

Como complemento, o artigo introduzirá uma nova versão da biblioteca EasyAndFast para desenvolvimento de
interfaces gráficas do usuário. 
Principais tópicos do artigo:

indicadores que definem o comportamento do preço;


EA com uma interface gráfica para coletar as estatísticas de comportamento do preço;
EA para calcular o número de segmentos do indicador ZigZag em intervalos especificados.

Indicadores definindo o comportamento de preços


Vamos considerar três indicadores que definem o comportamento do preço. 

FrequencyChangeZZ calcula a frequência de formação de segmentos do indicador ZigZag direcionados de forma


oposta.
SumSegmentsZZ calcula a soma dos segmentos do conjunto obtido e seu o valor médio.
PercentageSegmentsZZ define a razão percentual das somas do segmento e a diferença entre elas.
MultiPercentageSegmentsZZ define a natureza da formação de vários segmentos a partir de um período de
tempo maior, com base nos valores do indicador PercentageSegmentsZZ .

A estrutura de código de cada um desses indicadores é a mesma do indicador ZigZag descrito na primeira parte do
artigo. Portanto, nós vamos nos deter apenas na função principal (FillIndicatorBuffers) onde os dados são recebidos e
os buffers dos indicadores são preenchidos.

Indicador FrequencyChangeZZ
Para o indicador FrequencyChangeZZ , o código da função principal é o mesmo do código exibido abaixo. O índice das
barras e o array de tempo são passados para a função. Em seguida, são copiados da hora da barra atual um número
necessário do indicador ZigZag e os elementos do array de tempo (dados de origem). Se os dados de origem forem
recebidos, os dados finais são solicitados. Depois disso, resta apenas chamar um método que retorne o número de
barras no conjunto de segmentos. O resultado é salvo no elemento atual do buffer do indicador.

//+------------------------------------------------------------------+
//| Preenche os buffers do indicador |
//+------------------------------------------------------------------+
void FillIndicatorBuffers(const int i,const datetime &time[])
{
int copy_total=1000;
for(int t=0; t<10; t++)
{
if(::CopyBuffer(zz_handle,2,time[i],copy_total,h_zz_buffer_temp)==copy_total &&
::CopyBuffer(zz_handle,3,time[i],copy_total,l_zz_buffer_temp)==copy_total &&
https://www.mql5.com/pt/articles/5544 2/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
::CopyTime(_Symbol,_Period,time[i],copy_total,t_zz_buffer_temp)==copy_total)
{
//--- Obtém os dados ZZ
zz.GetZigZagData(h_zz_buffer_temp,l_zz_buffer_temp,t_zz_buffer_temp);
//--- Salva o número de barras no segmento definido no buffer do indicador
segments_bars_total_buffer[i]=zz.SegmentsTotalBars();
break;
}
}
}

Nos parâmetros de entrada do indicador, nós especificaremos o seguinte:

(1) os valores devem ser calculados com base em todos os dados disponíveis,
(2) o desvio mínimo para a formação do novo segmento do indicador ZigZag e
(3) o número de extremos para obtenção dos dados finais.

Todos os indicadores neste artigo terão os mesmos parâmetros.

Fig. 1. Parâmetros de entrada do indicador

O FrequencyChangeZZ indicador exibe o gráfico em uma subjanela conforme é exibido abaixo. O indicador ZigZag é
carregado no gráfico principal para maior visibilidade. O indicador mostra claramente quando o preço diminui na
escolha da direção.  

https://www.mql5.com/pt/articles/5544 3/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Fig. 2. Indicador FrequencyChangeZZ

Indicador SumSegmentsZZ
No indicador SumSegmentsZZ, a função principal para obter os dados se parece conforme exibido no trecho de código
a seguir. Todo código é o mesmo que no exemplo anterior. A única diferença é que três buffers do indicador são
preenchidos aqui para segmentos ascendentes e descendentes separadamente. Mais um buffer é usado para calcular a
média desses parâmetros nos valores atuais.

//+------------------------------------------------------------------+
//| Preenche os buffers do indicador |
//+------------------------------------------------------------------+
void FillIndicatorBuffers(const int i,const datetime &time[])
{
https://www.mql5.com/pt/articles/5544 4/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
{
int copy_total=1000;
for(int t=0; t<10; t++)
{
if(CopyBuffer(zz_handle,2,time[i],copy_total,h_zz_buffer_temp)==copy_total &&
CopyBuffer(zz_handle,3,time[i],copy_total,l_zz_buffer_temp)==copy_total &&
CopyTime(_Symbol,_Period,time[i],copy_total,t_zz_buffer_temp)==copy_total)
{
//--- Obtém os dados ZZ
zz.GetZigZagData(h_zz_buffer_temp,l_zz_buffer_temp,t_zz_buffer_temp);
//--- Obtém os dados por segmentos
segments_up_total_buffer[i] =zz.SumSegmentsUp();
segments_dw_total_buffer[i] =zz.SumSegmentsDown();
segments_average_buffer[i] =(segments_up_total_buffer[i]+segments_dw_total_buffer[i]
break;
}
}
}

Após anexar o indicador SumSegmentsZZ no gráfico, você verá o resultado como na imagem abaixo. Aqui nós podemos
ver que depois que a linha azul excede a linha vermelha, a soma dos segmentos ascendentes é maior que a soma dos
descendentes. A situação é invertida se a linha vermelha exceder a linha azul. Somente os experimentos no testador de
estratégia podem nos informar se essa é uma fonte confiável de informação sobre a direção futura do preço. À primeira
vista, quanto maior a soma dos segmentos unidirecionais exceder a soma dos segmentos opostos, maior a probabilidade
de reversão. 

https://www.mql5.com/pt/articles/5544 5/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Fig. 3. Indicador SumSegmentsZZ

Indicador PercentageSegmentsZZ
Agora, vamos dar uma olhada no indicador PercentageSegmentsZZ. Como no caso anterior, três buffers do indicador
devem ser preenchidos na função principal do indicador: um buffer para cada uma das taxas percentuais da soma dos
segmentos direcionadas (1) para cima e (2) para baixo, bem como um buffer (3) pela diferença entre esses valores. 

//+------------------------------------------------------------------+
//| Preenche os buffers do indicador |
//+------------------------------------------------------------------+
void FillIndicatorBuffers(const int i,const datetime &time[])
{
int copy total 1000;
https://www.mql5.com/pt/articles/5544 6/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
int copy_total=1000;
for(int t=0; t<10; t++)
{
if(CopyBuffer(zz_handle,2,time[i],copy_total,h_zz_buffer_temp)==copy_total &&
CopyBuffer(zz_handle,3,time[i],copy_total,l_zz_buffer_temp)==copy_total &&
CopyTime(_Symbol,_Period,time[i],copy_total,t_zz_buffer_temp)==copy_total)
{
//--- Obtém os dados ZZ
zz.GetZigZagData(h_zz_buffer_temp,l_zz_buffer_temp,t_zz_buffer_temp);
//--- Obtém os dados sobre os segmentos
double sum_up =zz.SumSegmentsUp();
double sum_dw =zz.SumSegmentsDown();
double sum =sum_up+sum_dw;
//--- Taxa percentual e diferença
if(sum>0)
{
segments_up_total_buffer[i] =zz.PercentSumSegmentsUp();
segments_dw_total_buffer[i] =zz.PercentSumSegmentsDown();
segments_difference_buffer[i] =fabs(segments_up_total_buffer[i]-segments_dw_total_b
break;
}
}
}
}

O resultado é exibido abaixo. Vamos tentar interpretar isso. Quando a diferença nas taxas percentuais entre as
quantidades de segmentos multidirecionais é menor que um determinado limite, isso pode ser considerado como
lateralizado. Nesse caso, nós devemos também ter em mente que as taxas devem ser alteradas frequentemente, uma
vez que o preço pode mudar em uma direção por um longo tempo, enquanto a diferença é menor do que o nível
selecionado pelo otimizador. Nestes casos, nós devemos aplicar os modelos considerando a formação dos padrões em
uma determinada sequência.

https://www.mql5.com/pt/articles/5544 7/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Fig. 4. Indicador PercentageSegmentsZZ

Indicador MultiPercentageSegmentsZZ
No artigo anterior, nós demonstramos o EA analisando os dados do indicador ZigZag a partir de períodos de tempo
maiores e menores, simultaneamente. Assim, foi possível analisar com mais detalhes como o preço se comportou
dentro dos segmentos a partir do período de tempo maior. Em outras palavras, nós definimos como os segmentos de
período de tempo maiores se formaram em um período de tempo menor. Vamos ver como esse grupo de parâmetros se
parecerá na forma de um indicador separado exibindo esses valores no histórico de preços.

Como no EA do artigo anterior, nós receberemos quatro valores da diferença entre as taxas percentuais das somas do
segmento de direção oposta: um valor é para o período de tempo maior e três valores são para o período menor. Os
valores são calculados pelos três últimos segmentos do indicador ZigZag no período de tempo maior. As cores dos

https://www.mql5.com/pt/articles/5544 8/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

buffers do indicador serão as mesmas que no EA da parte anterior. Depois disso, nós desenvolveremos um EA para testar
o indicador, de modo que seja muito mais fácil entendermos quais dados e para qual período de tempo nós observamos
no gráfico.

//--- Número de buffers


#property indicator_buffers 4
#property indicator_plots 4
//--- Cores dos buffers de cor
#property indicator_color1 clrSilver
#property indicator_color2 clrRed
#property indicator_color3 clrLimeGreen
#property indicator_color4 clrMediumPurple

Declaração de quatro instâncias da classe CZigZagModule:

#include <Addons\Indicators\ZigZag\ZigZagModule.mqh>
CZigZagModule zz_higher_tf;
CZigZagModule zz_current0;
CZigZagModule zz_current1;
CZigZagModule zz_current2;

Vamos adicionar a capacidade de definir um período de tempo maior para o indicador nos parâmetros de entrada:

input int NumberOfBars =0; // Número de barras para calcular o ZZ


input int MinImpulseSize =0; // Pontos mínimos em um raio
input int CopyExtremum =5; // Copiar os extremos
input ENUM_TIMEFRAMES HigherTimeframe =PERIOD_H1; // Período de tempo maior

A principal função para preencher os buffers do indicador é implementada da seguinte forma. Primeiro, obtenha os
dados de origem do maior período de tempo especificado nos parâmetros de entrada. Então obtenha os dados finais e
salve o valor do parâmetro. Em seguida, nós obtemos consistentemente os dados sobre os três segmentos do indicador
do maior período de tempo. Depois disso, preencha todos os buffers do indicador. Eu tive que desenvolver dois blocos
de código separados, para que o indicador pudesse ser calculado corretamente no histórico e na última barra em tempo
real/testador. 

//+------------------------------------------------------------------+
//| Preenche os buffers do indicador |
//+------------------------------------------------------------------+
void FillIndicatorBuffers(const int i,const int total,const datetime &time[])
{
int index=total-i-1;
int copy_total=1000;
int h_buff=2,l_buff=3;
datetime start_time_in =NULL;
i i i
https://www.mql5.com/pt/articles/5544 9/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
datetime stop_time_in =NULL;
//--- Obtém os dados de origem do maior período de tempo
datetime stop_time=time[i]-(PeriodSeconds(HigherTimeframe)*copy_total);
CopyBuffer(zz_handle_htf,2,time[i],stop_time,h_zz_buffer_temp);
CopyBuffer(zz_handle_htf,3,time[i],stop_time,l_zz_buffer_temp);
CopyTime(_Symbol,HigherTimeframe,time[i],stop_time,t_zz_buffer_temp);
//--- Obtém os dados finais do maior período de tempo
zz_higher_tf.GetZigZagData(h_zz_buffer_temp,l_zz_buffer_temp,t_zz_buffer_temp);
double htf_value=zz_higher_tf.PercentSumSegmentsDifference();
//--- Dado do primeiro segmento
zz_higher_tf.SegmentTimes(zz_handle_current,h_buff,l_buff,_Symbol,HigherTimeframe,_Period,0
zz_current0.GetZigZagData(zz_handle_current,_Symbol,_Period,start_time_in,stop_time_in);
//--- Dado do segundo segmento
zz_higher_tf.SegmentTimes(zz_handle_current,h_buff,l_buff,_Symbol,HigherTimeframe,_Period,1
zz_current1.GetZigZagData(zz_handle_current,_Symbol,_Period,start_time_in,stop_time_in);
//--- Dado do terceiro segmento
zz_higher_tf.SegmentTimes(zz_handle_current,h_buff,l_buff,_Symbol,HigherTimeframe,_Period,2
zz_current2.GetZigZagData(zz_handle_current,_Symbol,_Period,start_time_in,stop_time_in);
//--- Na última barra
if(i<total-1)
{
buffer_zz_higher_tf[i] =htf_value;
buffer_segment_0[i] =zz_current0.PercentSumSegmentsDifference();
buffer_segment_1[i] =zz_current1.PercentSumSegmentsDifference();
buffer_segment_2[i] =zz_current2.PercentSumSegmentsDifference();
}
//--- No histórico
else
{
//--- Caso de haver uma nova barra do maior período de tempo
if(new_bar_time!=t_zz_buffer_temp[0])
{
new_bar_time=t_zz_buffer_temp[0];
//---
if(i>2)
{
int f=1,s=2;
buffer_zz_higher_tf[i-f] =buffer_zz_higher_tf[i-s];
buffer_segment_0[i-f] =buffer_segment_0[i-s];
buffer_segment_1[i-f] =buffer_segment_1[i-s];
buffer_segment_2[i-f] =buffer_segment_2[i-s];
}
}
else
{
buffer_zz_higher_tf[i] =htf_value;
buffer_segment_0[i] =zz_current0.PercentSumSegmentsDifference();
b ff t 1[i] t1 P tS S t Diff ()
https://www.mql5.com/pt/articles/5544 10/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
buffer_segment_1[i] =zz_current1.PercentSumSegmentsDifference();
buffer_segment_2[i] =zz_current2.PercentSumSegmentsDifference();
}
}
}

Vamos fazer uma cópia do EA do artigo anterior e adicionar algumas linhas para testar o indicador
MultiPercentageSegmentsZZ. Adiciona o parâmetro de entrada para definir um período de tempo maior. Para que o
indicador seja exibido durante o teste do EA no modo de visualização do testador, é suficiente para obter o seu
manipulador. 

//--- Parâmetros de entrada


input uint CopyExtremum =3; // Copia os extremos
input int MinImpulseSize =0; // Tamanho do impulso mínimo
input ENUM_TIMEFRAMES HigherTimeframe =PERIOD_H1; // Período de tempo maior

...

//+------------------------------------------------------------------+
//| Função de inicialização do Expert |
//+------------------------------------------------------------------+
int OnInit(void)
{

...

//--- Caminho para o indicador ZZ


string zz_path1="Custom\\ZigZag\\ExactZZ_Plus.ex5";
string zz_path2="Custom\\ZigZag\\MultiPercentageSegmentsZZ.ex5";
//--- Obtemos os manipuladores do indicador
zz_handle_current =::iCustom(_Symbol,_Period,zz_path1,0,MinImpulseSize,false,false);
zz_handle_higher_tf =::iCustom(_Symbol,HigherTimeframe,zz_path1,0,MinImpulseSize,false,false
zz_handle =::iCustom(_Symbol,_Period,zz_path2,0,MinImpulseSize,CopyExtremum,Higher

...

return(INIT_SUCCEEDED);
}

É assim que fica no testador:

https://www.mql5.com/pt/articles/5544 11/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Fig. 5. Indicador MultiPercentageSegmentsZZ

Todos os indicadores descritos acima podem ser usados em várias combinações e ao mesmo tempo em diferentes
períodos de tempo. Agora, vamos usar as ferramentas descritas para coletar algumas estatísticas sobre o conjunto de
símbolos para entender quais delas são mais adequadas para a negociação no canal de preço.

EA para coleta e exibição de estatísticas

https://www.mql5.com/pt/articles/5544 12/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Como complemento, o artigo apresenta uma nova versão da biblioteca EasyAndFast para desenvolvimento de interfaces
gráficas do usuário. Aqui nós vamos listar apenas os novos recursos da biblioteca:

Alterar a cor de fundo de cada célula da tabela (classe CTable).


Direção da ordenação.
Se o modo apropriado estiver ativado, uma linha não será destacada ao clicar em uma caixa de seleção na célula
da tabela.
Adicionado o suporte para o teclado numérico na classe CKeys.
Adicionado a classe CFrame para combinar os elementos em grupos:

Fig. 6. Combinando elementos em grupos

Rolagem vertical em tabelas e listas.

https://www.mql5.com/pt/articles/5544 13/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Adicionado a classe CWndCreate, que inclui os métodos de modelos básicos para a criação rápida da maioria dos
elementos. Ele deve ser usado como base para a classe personalizada. O uso dessa classe permite que você não
repita a declaração e a implementação dos mesmos métodos de criação de elementos em diferentes projetos, o
que acelera bastante o desenvolvimento. 
Adicionada a verificação da sequência correta de criação de elementos para a classe CElement.
Na classe CWndEvents, o ID é sempre redefinido após a remoção de um elemento.
Adicionado o método GetActiveWindowIndex() para o CWndEvents para receber o índice da janela ativada.
Corrigido a classe CListView. Alguns campos auxiliares devem ser redefinidos no método Clear() para evitar
arrays fora de alcance em outros métodos da classe CListView.

A nova versão da biblioteca pode ser baixada na CodeBase. 

Em seguida, vamos criar um EA de teste para reunir algumas estatísticas usando a nova versão da biblioteca
EasyAndFast. Nós vamos começar desenvolvendo a interface gráfica do usuário (GUI) do aplicativo e, em seguida,
procederemos aos métodos para coletar e exibir as estatísticas.

Vamos definir quais controles da GUI nós precisamos:

Formulário de controles.
Barra de estado.
Campo de entrada para a ordenação de moedas que devem ser coletadas na lista da janela do Observador do
Mercado.
Calendários suspensos para indicar as datas de início e término da coleta das estatísticas.
Campo de entrada para definir o nível do indicador.
Botão de solicitação de dados.
Tabela para exibir os dados coletados.
Barra de progresso.

Como mencionado anteriormente, a classe CWndCreate deve ser incluída na classe personalizada como base para
desenvolver uma GUI mais rápida e mais conveniente. A conexão completa é a seguinte: CWndContainer ->
CWndEvents -> CWndCreate -> CProgram. A presença da classe CWndCreate permite criar elementos da GUI em uma
única linha, sem criar métodos separados em uma classe personalizada. A classe contém modelos diferentes para quase
todos os elementos da biblioteca. Você pode adicionar novos modelos, se necessário. 

Para criar uma GUI, declare os elementos contidos na lista acima, conforme mostrado no código a seguir. A versão atual
da classe CWndCreate não tem nenhum modelo de criação de tabela rápida, portanto vamos desenvolver nossa próprio
método. 

//+------------------------------------------------------------------+
//| Program.mqh |
//| Copyright 2018, MetaQuotes Software Corp.
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include <EasyAndFastGUI\WndCreate.mqh>
//+------------------------------------------------------------------+
//| Classe para o desenvolvimento da aplicação |
https://www.mql5.com/pt/articles/5544 14/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
//+------------------------------------------------------------------+
class CProgram : public CWndCreate
{
private:
//--- Janela
CWindow m_window;
//--- Barra de status
CStatusBar m_status_bar;
//--- Calendários suspensos
CDropCalendar m_from_date;
CDropCalendar m_to_date;
//--- Botões
CButton m_request;
//--- Campos de entrada
CTextEdit m_filter;
CTextEdit m_level;
//--- Caixas de combinação
CComboBox m_data_type;
//--- Tabelas
CTable m_table;
//--- Barra de progresso
CProgressBar m_progress_bar;
//---
public:
//--- Cria uma GUI
bool CreateGUI(void);
//---
private:
//--- Tabelas
bool CreateTable(const int x_gap,const int y_gap);
};

Para criar uma interface gráfica com tal conteúdo, basta chamar os métodos necessários da classe CWndCreate
especificando os valores das propriedades como argumentos, conforme mostrado no bloco de código abaixo. Para
definir uma propriedade com a qual um parâmetro do método está relacionado, defina o cursor de texto nele e clique
em Ctrl + Shift + Espaço:

Fig. 7. Visualizando os parâmetros do método

Se você precisar definir propriedades adicionais, poderá fazer isso da mesma maneira mostrada no exemplo que
envolve o campo de entrada do filtro de moeda. Aqui, é indicado que a caixa de seleção deve ser ativada por padrão
https://www.mql5.com/pt/articles/5544 15/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

logo após a criação do elemento.

//+------------------------------------------------------------------+
//| Cria a GUI |
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
{
//--- Cria os formulários de controle
if(!CWndCreate::CreateWindow(m_window,"ZZ Market Scanner",1,1,640,480,true,true,true,true))
return(false);
//--- Barra de status
string text_items[1];
text_items[0]="For Help, press F1";
int width_items[]={0};
if(!CWndCreate::CreateStatusBar(m_status_bar,m_window,1,23,22,text_items,width_items))
return(false);
//--- Campo de entrada do filtro de moeda
if(!CWndCreate::CreateTextEdit(m_filter,"Symbols filter:",m_window,0,true,7,25,627,535,"USD"
return(false);
else
m_filter.IsPressed(true);
//--- Calendário suspenso
if(!CWndCreate::CreateDropCalendar(m_from_date,"From:",m_window,0,7,50,130,D'2018.01.01'))
return(false);
if(!CWndCreate::CreateDropCalendar(m_to_date,"To:",m_window,0,150,50,117,::TimeCurrent()))
return(false);
//--- Campo de entrada para especificar o nível
if(!CWndCreate::CreateTextEdit(m_level,"Level:",m_window,0,false,280,50,85,50,100,0,1,0,30)
return(false);
//--- Botão
if(!CWndCreate::CreateButton(m_request,"Request",m_window,0,375,50,70))
return(false);
//--- Tabela
if(!CreateTable(2,75))
return(false);
//--- Barra de progresso
if(!CWndCreate::CreateProgressBar(m_progress_bar,"Processing:",m_status_bar,0,2,3))
return(false);
//--- Fim do desenvolvimento da GUI
CWndEvents::CompletedGUI();
return(true);
}

No caso de uma tabela, crie um método personalizado, já que é um elemento complexo com um grande número de
propriedades que devem ser especificadas antes de criar um elemento. É para apresentar quatro colunas. A primeira
https://www.mql5.com/pt/articles/5544 16/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

mostrará os pares de moedas. Os restantes mostrarão dados estatísticos em três períodos de tempo: M5, H1 e H8.

//+------------------------------------------------------------------+
//| Cria a tabela |
//+------------------------------------------------------------------+
bool CProgram::CreateTable(const int x_gap,const int y_gap)
{
#define COLUMNS1_TOTAL 4
#define ROWS1_TOTAL 1
//--- Salva um ponteiro para o elemento principal
m_table.MainPointer(m_window);
//--- Array de largura da coluna
int width[COLUMNS1_TOTAL];
::ArrayInitialize(width,50);
width[0]=80;
//--- Array de deslocamento de texto em colunas pelo eixo X
int text_x_offset[COLUMNS1_TOTAL];
::ArrayInitialize(text_x_offset,7);
//--- Array do alinhamento de texto em colunas
ENUM_ALIGN_MODE align[COLUMNS1_TOTAL];
::ArrayInitialize(align,ALIGN_CENTER);
align[0]=ALIGN_LEFT;
//--- Propriedades
m_table.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
m_table.TextAlign(align);
m_table.ColumnsWidth(width);
m_table.TextXOffset(text_x_offset);
m_table.ShowHeaders(true);
m_table.IsSortMode(true);
m_table.IsZebraFormatRows(clrWhiteSmoke);
m_table.AutoXResizeMode(true);
m_table.AutoYResizeMode(true);
m_table.AutoXResizeRightOffset(2);
m_table.AutoYResizeBottomOffset(24);
//--- Cria um controle
if(!m_table.CreateTable(x_gap,y_gap))
return(false);
//--- Cabeçalhos
string headers[]={"Symbols","M5","H1","H8"};
for(uint i=0; i<m_table.ColumnsTotal(); i++)
m_table.SetHeaderText(i,headers[i]);
//--- Adiciona um objeto ao array comum de grupos de objetos
CWndContainer::AddToElementsArray(0,m_table);
return(true);
}

https://www.mql5.com/pt/articles/5544 17/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Agora vamos considerar os métodos para a obtenção dos dados. Primeiro, nós precisamos obter os símbolos com os
quais nós devemos trabalhar. Nesta versão do EA, nós receberemos os dados de símbolos de Forex. Ao mesmo tempo,
nós vamos excluir os símbolos, para os quais a negociação está desativada. Aqui, nós também precisaremos do método
auxiliar CheckFilterText() para verificar o símbolo pelo filtro. No campo de entrada, os usuários podem inserir os
valores de texto separados por vírgulas que devem estar presentes nos nomes dos símbolos. Se a caixa de seleção de
campo estiver desativada ou o texto não for digitado, a verificação não é executada. Se as verificações forem passadas
e uma correspondência for encontrada, o texto inserido será dividido em substrings e a pesquisa por uma string
necessária será executada. 

class CProgram : public CWndCreate


{
private:
//--- Verifica um símbolo por filtro
bool CheckFilterText(const string symbol_name);
};
//+------------------------------------------------------------------+
//| Verifica um símbolo por filtro |
//+------------------------------------------------------------------+
bool CProgram::CheckFilterText(const string symbol_name)
{
bool check=false;
//--- Se o filtro com o nome do símbolo estiver ativado
if(!m_filter.IsPressed())
return(true);
//--- Se um texto for digitado
string text=m_filter.GetValue();
if(text=="")
return(true);
//--- Divide em substrings
string elements[];
ushort sep=::StringGetCharacter(",",0);
::StringSplit(text,sep,elements);
//--- Verifique se há correspondência
int elements_total=::ArraySize(elements);
for(int e=0; e<elements_total; e++)
{
//--- Exclui espaços externos
::StringTrimLeft(elements[e]);
::StringTrimRight(elements[e]);
//--- Se uma correspondência for detectada
if(::StringFind(symbol_name,elements[e])>-1)
{
check=true;
break;
}
}

https://www.mql5.com/pt/articles/5544 18/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
//--- Resultado
return(check);
}

No método CProgram::GetSymbols(), ele repassa todos os símbolos presentes no servidor em um loop e coleta os que
se encaixam nos critérios especificados no array. No loop geral, todos os símbolos são excluídos da janela da
Observação do Mercado. Apenas os contidos no array são adicionados à janela depois. 

class CProgram : public CWndCreate


{
private:
//--- array de símbolos
string m_symbols[];
//---
private:
//--- Obtém os símbolos
void GetSymbols(void);
};
//+------------------------------------------------------------------+
//| Obtém os símbolos |
//+------------------------------------------------------------------+
void CProgram::GetSymbols(void)
{
//--- Progresso
m_progress_bar.LabelText("Get symbols...");
m_progress_bar.Update(0,1);
//--- Limpa um array de símbolos
::ArrayFree(m_symbols);
//--- Coleta o array de símbolos de Forex
int symbols_total=::SymbolsTotal(false);
for(int i=0; i<symbols_total; i++)
{
//--- Obtém um nome do símbolo
string symbol_name=::SymbolName(i,false);
//--- Oculta na janela de Observação do Mercado
::SymbolSelect(symbol_name,false);
//--- Se este não for um símbolo de Forex, vá para o próximo
if(::SymbolInfoInteger(symbol_name,SYMBOL_TRADE_CALC_MODE)!=SYMBOL_CALC_MODE_FOREX)
continue;
//--- Se a negociação estiver desativada, vá para a próximo
if(::SymbolInfoInteger(symbol_name,SYMBOL_TRADE_MODE)==SYMBOL_TRADE_MODE_DISABLED)
continue;
//--- Verifica um símbolo por filtro
if(!CheckFilterText(symbol_name))
continue;
//--- Salve um símbolo no array

https://www.mql5.com/pt/articles/5544 19/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
int array_size=::ArraySize(m_symbols);
::ArrayResize(m_symbols,array_size+1,1000);
m_symbols[array_size]=symbol_name;
}
//--- Se um array estiver vazio, define o símbolo atual como padrão
int array_size=::ArraySize(m_symbols);
if(array_size<1)
{
::ArrayResize(m_symbols,array_size+1);
m_symbols[array_size]=_Symbol;
}
//--- Exibe na janela de Observação do Mercado
int selected_symbols_total=::ArraySize(m_symbols);
for(int i=0; i<selected_symbols_total; i++)
::SymbolSelect(m_symbols[i],true);
}

Para obter os dados sobre os símbolos coletados, nós devemos primeiro obter os manipuladores do indicador neles.
Toda vez que nós obtemos o manipulador do indicador, nós precisamos esperar até o final do cálculo antes de copiar os
dados para análise posterior. Depois que todos os dados são recebidos, os cálculos necessários são realizados. 
O método CProgram::GetSymbolsData() é usado para isso. Ele aceita dois parâmetros: símbolo e período de tempo.
Depois de receber o manipulador do indicador, descubra quantas barras estão presentes no intervalo de tempo
especificado. O intervalo de datas pode ser especificado usando os controles da GUI do aplicativo. Em seguida, nós
tentamos obter a quantidade de dados do indicador calculado. O cálculo do indicador pode não ser concluído
imediatamente após o recebimento do manipulador. Portanto, se a função BarsCalculated() retorna -1, nós fazemos
novas tentativas para obter um valor válido até que seja igual ou exceda o número total de barras no intervalo de
tempo especificado.
Depois que os dados do indicador são calculados, nós podemos tentar colocá-los no array. Ele pode levar a várias
tentativas até que a quantidade seja também maior ou igual ao número total de barras. 

Se os indicadores forem copiados com sucesso para o array, resta apenas fazer os cálculos necessários. Neste caso, nós
calculamos a porcentagem da quantidade total de dados para o valor, em que o valor do indicador está acima do nível
especificado. Esse nível também pode ser especificado na GUI do aplicativo. 

No final do método, remova o manipulador do indicador liberando sua parte de cálculo. O método
CProgram::GetSymbolsData() é chamado várias vezes para uma lista selecionada de símbolos e vários períodos de
tempo. O cálculo para cada um deles deve ser executado apenas uma vez e o valor resultante é exibido na tabela da
GUI, portanto, os manipuladores não são mais necessárias e podem ser removidos. 

class CProgram : public CWndCreate


{
private:
//--- Obtém os dados do símbolo
double GetSymbolsData(const string symbol,const ENUM_TIMEFRAMES period);

https://www.mql5.com/pt/articles/5544 20/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
};
//+------------------------------------------------------------------+
//| Obtém os dados do símbolo |
//+------------------------------------------------------------------+
double CProgram::GetSymbolsData(const string symbol,const ENUM_TIMEFRAMES period)
{
double result =0.0;
int buffer_index =2;
//--- Obtém o manipulador do indicador
string path ="::Indicators\\Custom\\ZigZag\\PercentageSegmentsZZ.ex5";
int handle =::iCustom(symbol,period,path,0,0,5);
if(handle!=INVALID_HANDLE)
{
//--- Copia os dados dentro de um intervalo especificado
double data[];
datetime start_time =m_from_date.SelectedDate();
datetime end_time =m_to_date.SelectedDate();
//--- Número de barras em um intervalo especificado
int bars_total=::Bars(symbol,period,start_time,end_time);
//--- Número de barras em um intervalo especificado
int bars_calculated=::BarsCalculated(handle);
if(bars_calculated<bars_total)
{
while(true)
{
::Sleep(100);
bars_calculated=::BarsCalculated(handle);
if(bars_calculated>=bars_total)
break;
}
}
//--- Obtém os dados
int copied=::CopyBuffer(handle,buffer_index,start_time,end_time,data);
if(copied<1)
{
while(true)
{
::Sleep(100);
copied=::CopyBuffer(handle,buffer_index,start_time,end_time,data);
if(copied>=bars_total)
break;
}

}
//--- Encerra se nenhum dado for recebido
int total=::ArraySize(data);
if(total<1)

https://www.mql5.com/pt/articles/5544 21/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
return(result);
//--- Conta o número de repetições
int counter=0;
for(int k=0; k<total; k++)
{
if(data[k]>(double)m_level.GetValue())
counter++;
}
//--- Razão percentual
result=((double)counter/(double)total)*100;
}
//--- Libera o indicador
::IndicatorRelease(handle);
//--- Retorna o valor
return(result);
}

Toda vez que uma nova lista de símbolos é formada, a tabela precisa ser reconstruída. Para fazer isso, basta excluir
todas as linhas e adicionar o valor necessário.

class CProgram : public CWndCreate


{
private:
//--- Re-constrói a tabela
void RebuildingTables(void);
};
//+------------------------------------------------------------------+
//| Re-constrói a tabela |
//+------------------------------------------------------------------+
void CProgram::RebuildingTables(void)
{
//--- Remove todas as linhas
m_table.DeleteAllRows();
//--- Adiciona os dados
int symbols_total=::ArraySize(m_symbols);
for(int i=1; i<symbols_total; i++)
m_table.AddRow(i);
}

O método CProgram::SetData() é usado para preencher as colunas da tabela com os dados. Dois parâmetros (índice da
coluna e período de tempo) são passados para ele. Aqui, nós movemos pelas células de uma coluna especificada e
preenchemos elas com os valores calculados em um loop. A barra de progresso exibe um símbolo e um período de
tempo, cujos dados acabam de ser recebidos, para que os usuários entendam o que está acontecendo no momento.

class CProgram : public CWndCreate


{
https://www.mql5.com/pt/articles/5544 22/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
{
private:
//--- Define os valores para uma coluna especificada
void SetData(const int column_index,const ENUM_TIMEFRAMES period);
//--- Período de tempo para uma string
string GetPeriodName(const ENUM_TIMEFRAMES period);
};
//+------------------------------------------------------------------+
//| Define os valores para uma coluna especificada |
//+------------------------------------------------------------------+
void CProgram::SetData(const int column_index,const ENUM_TIMEFRAMES period)
{
for(uint r=0; r<(uint)m_table.RowsTotal(); r++)
{
double value=GetSymbolsData(m_symbols[r],period);
m_table.SetValue(column_index,r,string(value),2,true);
m_table.Update();
//--- Progresso
m_progress_bar.LabelText("Data preparation ["+m_symbols[r]+","+GetPeriodName(period)+"].
m_progress_bar.Update(r,m_table.RowsTotal());
}
}
//+------------------------------------------------------------------+
//| Retorna o valor da string do período |
//+------------------------------------------------------------------+
string CProgram::GetPeriodName(const ENUM_TIMEFRAMES period)
{

return(::StringSubstr(::EnumToString(period),7));
}

O principal método para preencher a tabela com os dados é CProgram::SetDataToTable() A tabela é reconstruída aqui
primeiro. Em seguida, nós precisamos definir os cabeçalhos e tipo de dados nele (TYPE_DOUBLE). Definir os símbolos
coletados para a primeira coluna. Re-desenhar a tabela para ver as alterações imediatamente.
Agora nós podemos começar a receber os dados do indicador em todos os símbolos e períodos de tempo especificados.
Para fazer isso, basta chamar o método CProgram::SetData() passando o índice de coluna e o período de tempo como
parâmetros. 

class CProgram : public CWndCreate


{
private:
//--- Preenche a tabela com os dados
void SetDataToTable(void);
};
//+------------------------------------------------------------------+

https://www.mql5.com/pt/articles/5544 23/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
//| Preenche a tabela com os dados |
//+------------------------------------------------------------------+
void CProgram::SetDataToTable(void)
{
//--- Progresso
m_progress_bar.LabelText("Data preparation...");
m_progress_bar.Update(0,1);
//--- Re-constrói a tabela
RebuildingTable();
//--- Cabeçalhos
string headers[]={"Symbols","M5","H1","H8"};
for(uint i=0; i<m_table.ColumnsTotal(); i++)
m_table.SetHeaderText(i,headers[i]);
for(uint i=1; i<m_table.ColumnsTotal(); i++)
m_table.DataType(i,TYPE_DOUBLE);
//--- Define os valores para a primeira coluna
for(uint r=0; r<(uint)m_table.RowsTotal(); r++)
m_table.SetValue(0,r,m_symbols[r],0,true);
//--- Mostrar a tabela
m_table.Update(true);
//--- Preenche as colunas restantes com os dados
SetData(1,PERIOD_M5);
SetData(2,PERIOD_H1);
SetData(3,PERIOD_H8);
}

Antes de receber os novos dados usando o CProgram::GetData(), nós devemos tornar a barra de progresso visível com a
ajuda do método CProgram::StartProgress(). Após novos dados serem recebidos, oculte a barra de progresso e remova
o foco do botão pressionado. Para fazer isso, chame o método CProgram::EndProgress(). 

class CProgram : public CWndCreate


{
private:
//--- Obtém os dados
void GetData(void);

//--- Progresso (1) início e (2) fim


void StartProgress(void);
void EndProgress(void);
};
//+------------------------------------------------------------------+
//| Obtém os dados |
//+------------------------------------------------------------------+
void CProgram::GetData(void)
{
//--- Início do progresso

https://www.mql5.com/pt/articles/5544 24/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
StartProgress();
//--- Obtém a lista de símbolos
GetSymbols();
//--- Preenche a tabela com os dados
SetDataToTable();
//--- Fim do progresso
EndProgress();
}
//+------------------------------------------------------------------+
//| Início do progresso |
//+------------------------------------------------------------------+
void CProgram::StartProgress(void)
{
m_progress_bar.LabelText("Please wait...");
m_progress_bar.Update(0,1);
m_progress_bar.Show();
m_chart.Redraw();
}
//+------------------------------------------------------------------+
//| Fim do progresso |
//+------------------------------------------------------------------+
void CProgram::EndProgress(void)
{
//--- Oculta a barra de progresso
m_progress_bar.Hide();
//--- Atualiza o botão
m_request.MouseFocus(false);
m_request.Update(true);
m_chart.Redraw();
}

Quando um usuário clica em Request, o evento personalizado ON_CLICK_BUTTON é gerado e nós podemos definir um
botão pressionado pelo ID do elemento. Se este é o botão Request, é iniciado o processo de obtenção dos dados. 

No método de criação de tabelas, nós incluímos a capacidade de ordenar a tabela clicando nos cabeçalhos. O evento
personalizado ON_SORT_DATA é gerado toda vez que nós fazemos isso. Quando o evento é recebido, a tabela deve ser
atualizada para exibir as alterações. 

//+------------------------------------------------------------------+
//| Manipulador de eventos |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &spara
{
//--- Botão pressionando eventos
if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
{
if(lparam==m request.Id())
https://www.mql5.com/pt/articles/5544 25/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
( p _ q ())
{
//--- Obtém os dados
GetData();
return;
}
//---
return;
}
//--- Eventos da tabela ordenada
if(id==CHARTEVENT_CUSTOM+ON_SORT_DATA)
{
if(lparam==m_table.Id())
{
m_table.Update(true);
return;
}
//---
return;
}
}

Agora vamos ver os resultados. Se nós compilarmos o programa e o carregarmos no gráfico, o resultado será como na
imagem abaixo. Os seguintes parâmetros são definidos por padrão:

O campo de entrada Symbols filter está ativado. Ele indica que é necessário obter os dados apenas para os
símbolos contendo USD em seus nomes.
Os dados devem ser obtidos dentro do intervalo de 01.01.2018 - 21.12.2018.
O valor Level usado como ponto de referência para os cálculos é definido como 30.
Nesta versão, os períodos de tempo nos quais os cálculos são executados são rigidamente definidos no código:
M5, H1 e H8.

https://www.mql5.com/pt/articles/5544 26/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Fig. 8. GUI da aplicação em MQL

Pressionando Request inicia a aquisição de dados:

https://www.mql5.com/pt/articles/5544 27/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Fig. 9. Recebendo os dados

Depois de receber todos os dados, você pode ordená-los:

https://www.mql5.com/pt/articles/5544 28/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Fig. 10. Ordenação dos dados da tabela

Você pode modificar e usar este aplicativo para resolver algumas das suas tarefas. A tabela pode ser preenchida com
outros parâmetros.
Abaixo, eu fornecerei outro exemplo demonstrando como melhorar ainda mais a visibilidade dos dados da tabela. Como
eu já mencionei no começo desta seção, a versão mais recente da biblioteca EasyAndFast apresenta a capacidade de
definir a cor de fundo das células da tabela. Isso permite que você formate a tabela como você vê ajustada da mesma
maneira que é feita em vários editores de tabela. A captura de tela abaixo mostra dados de formatação em planilhas
do Excel. Cada célula tem sua própria cor de plano de fundo restante no mesmo valor, mesmo ao ordenar os arrays.

https://www.mql5.com/pt/articles/5544 29/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Fig. 11. Escalas de cores em Excel

https://www.mql5.com/pt/articles/5544 30/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Tal formatação possibilita a rápida execução de análise visual dos dados. 

Vamos fazer pequenas alterações e adições ao aplicativo MQL considerado acima. Para definir uma cor exclusiva para
cada célula da tabela, desabilite a formatação no estilo zebra. Comente esta linha de código.

// m_table.IsZebraFormatRows(clrWhiteSmoke);

Agora vamos criar o método CProgram::SetColorsToTable() para a formatação da tabela. A classe CColors deve ser
usada para trabalhar com cores. Ela já está presente na biblioteca para criar as GUIs, portanto, não há necessidade de
incluir o arquivo no projeto. Declare dois arrays para o trabalho: (1) array para obter as cores do gradiente e (2) o array
de cores da qual o gradiente deve ser formado. Nós vamos criar o gradiente de três cores. Quanto menor o valor, mais
vermelha fica a cor (clrTomato). Quanto maior o valor, mais azul ele se torna (clrCornflowerBlue). Vamos adicionar a
cor branca para separar essas duas zonas de cor. 
Defina o tamanho dos intervalos de valores do mínimo ao máximo. Este será o tamanho do array de gradientes. O
método CColors::Gradient() é usado para definir o tamanho do array e preenchê-lo. As cores das células da tabela são
definidas no loop final. Para não sair do alcance do array, o índice é calculado como o valor da célula menos o valor
mínimo do intervalo. No final do método, a tabela é atualizada para exibir as alterações implementadas.

class CProgram : public CWndCreate


{
private:
//--- Preenchendo a tabela com cor de fundo para células
void SetColorsToTable(void);
};
//+------------------------------------------------------------------+
//| Formatando a tabela |
//+------------------------------------------------------------------+
void CProgram::SetColorsToTable(void)
{
//--- Para trabalhar com cores
CColors clr;
//--- Array para receber o gradiente
color out_colors[];
//--- Gradiente de três cores
color colors[3]={clrTomato,clrWhite,clrCornflowerBlue};
//--- Encontra os maiores e menores valores da tabela
double max =0;
double min =100;
for(uint c=1; c<(uint)m_table.ColumnsTotal(); c++)
{
for(uint r=0; r<(uint)m_table.RowsTotal(); r++)
{
max =::fmax(max,(double)m_table.GetValue(c,r));
min =::fmin(min,(double)m_table.GetValue(c,r));
}
https://www.mql5.com/pt/articles/5544 31/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
}
//--- Corrige para o inteiro mais próximo abaixo
max =::floor(max);
min =::floor(min);
//--- Obtém o intervalo
int range =int(max-min)+1;
//--- Obtém o array do gradiente de cores
clr.Gradient(colors,out_colors,range);
//--- Define a cor de fundo das células
for(uint c=1; c<(uint)m_table.ColumnsTotal(); c++)
{
for(uint r=0; r<(uint)m_table.RowsTotal(); r++)
{
int index=(int)m_table.GetValue(c,r)-(int)min;
m_table.BackColor(c,r,out_colors[index],true);
}
}
//--- Atualiza a tabela
m_table.Update();
}

Abaixo você pode ver como isso fica na GUI. Nesse caso, os resultados mostram que quanto menor o valor, menor o
número de tendências na área considerada. Seria sensato definir um intervalo de datas tão amplo quanto possível para
obter informações usando o máximo de dados possível. 

https://www.mql5.com/pt/articles/5544 32/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Fig. 12. Escala de cores para visualizar os dados da tabela

Quanto maior o intervalo de datas, mais dados são usados e, consequentemente, mais tempo será necessário para gerar
os dados e calcular os parâmetros. Se não houver dados suficientes, será feito uma tentativa de baixá-los do servidor. 

Contagem do número de segmentos por tamanho


Agora, vamos desenvolver um programa para contar o número de segmentos pelo tamanho deles. Copia o EA da seção
anterior e faz as alterações necessárias e adições a ele. Haverá duas tabelas aqui. O primeiro é usar apenas uma coluna
com a lista de símbolos analisados. O segundo usa duas colunas de dados: (1) o aumento de intervalos em pontos e (2) o
número de segmentos por intervalos na primeira coluna. Abaixo, você pode ver como a GUI aparece logo após o upload
do aplicativo no gráfico.

https://www.mql5.com/pt/articles/5544 33/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Fig. 13. Programa para calcular o número de segmentos por tamanho

O botão Request solicita a lista de símbolos por um filtro especificado. Ao clicar Calculate, os dados do intervalo de
tempo especificado são coletados e distribuídos na segunda tabela. 

Basicamente, todos os métodos permaneceram os mesmos que no EA anterior, então vamos considerar apenas as coisas
relacionadas à segunda tabela. Primeiro, nós precisamos receber os dados do indicador. Isso é feito no método
CProgram::GetIndicatorData(). Inicialmente, nós conectamos ao indicador ZigZag e depois obtemos os seus dados no
intervalo de tempo especificado. O símbolo, período de tempo e o número de segmentos de indicadores obtidos são
exibidos na barra de status. 

class CProgram : public CWndCreate


{
private:
//--- Obtém os dados do indicador
https://www.mql5.com/pt/articles/5544 34/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
void GetIndicatorData(const string symbol,const ENUM_TIMEFRAMES period);
};
//+------------------------------------------------------------------+
//| Recebe os dados do indicador |
//+------------------------------------------------------------------+
void CProgram::GetIndicatorData(const string symbol,const ENUM_TIMEFRAMES period)
{
//--- Obtém o manipulador do indicador
string path ="::Indicators\\Custom\\ZigZag\\ExactZZ_Plus.ex5";
int handle =::iCustom(symbol,period,path,0,0);
if(handle!=INVALID_HANDLE)
{
//--- Copia os dados no intervalo especificado
datetime start_time =m_from_date.SelectedDate();
datetime end_time =m_to_date.SelectedDate();
m_zz.GetZigZagData(handle,2,3,symbol,period,start_time,end_time);
//--- Exibe os dados na barra de status
string text="["+symbol+","+(string)GetPeriodName(period)+"] - Segments total: "+(string)m
m_status_bar.SetValue(0,text);
m_status_bar.GetItemPointer(0).Update(true);
}
//--- Libera o indicador
::IndicatorRelease(handle);
}

As faixas de preço com uma etapa especificada devem ser calculadas para a primeira coluna. O método
CProgram::GetLevels() é usado para isso. Para definir o número de intervalos, nós devemos primeiro obter o tamanho
máximo do segmento no conjunto de dados obtidos. Em seguida, preencha o array com os níveis usando uma etapa
especificada em um loop até que o valor máximo seja atingido. 

class CProgram : public CWndCreate


{
private:
//--- array de intervalo
int m_levels_array[];
//---
private:
//--- Obtém os níveis
void GetLevels(void);
};
//+------------------------------------------------------------------+
//| Obtém os níveis |
//+------------------------------------------------------------------+
void CProgram::GetLevels(void)
{

https://www.mql5.com/pt/articles/5544 35/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
//--- Libera o array
::ArrayFree(m_levels_array);
//--- Obtém o tamanho máximo do segmento
int max_value=int(m_zz.LargestSegment()/m_symbol.Point());
//--- Preenche o array com níveis
int counter_levels=0;
while(true)
{
int size=::ArraySize(m_levels_array);
::ArrayResize(m_levels_array,size+1);
m_levels_array[size]=counter_levels;
//---
if(counter_levels>max_value)
break;
//---
counter_levels+=(int)m_step.GetValue();
}
}

O método CProgram::SetDataToTable2() é usado para preencher a segunda tabela com os dados. No início, a
verificação é executada se o símbolo é realçado na primeira lista da tabela. Se não estiver, o programa sai do método
enviando a mensagem para o log da guia experts Se uma linha na primeira tabela estiver realçada, defina o símbolo e
obtenha os dados nele. Depois disso, os métodos descritos acima são chamados para receber os dados do indicador e
calcular os níveis. Nós recebemos os dados do indicador com o mesmo período de tempo em que o EA é lançado.

Quando nós sabemos o número de níveis, nós podemos construir uma tabela com o tamanho necessário e preenchê-la
com os valores. Primeiro, preencha a primeira coluna com os valores de intervalo. Depois disso, preencha a segunda
coluna. Ao mover sequencialmente por todos os intervalos, há o aumento do contador nas células para os segmentos
que se enquadram nessa faixa.

class CProgram : public CWndCreate


{
private:
//--- Preenche a tabela 2 com dados
void SetDataToTable2(void);
};
//+------------------------------------------------------------------+
//| Preenche a tabela 2 com dados |
//+------------------------------------------------------------------+
void CProgram::SetDataToTable2(void)
{
//--- Encerra se a linha não estiver destacada
if(m_table1.SelectedItem()==WRONG_VALUE)
{
::Print(__FUNCTION__," > Select a symbol in the table on the left!");
return;

https://www.mql5.com/pt/articles/5544 36/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
}
//--- Início do progresso
StartProgress();
//--- Oculta a mesa
m_table2.Hide();
//--- Obtém o símbolo da primeira tabela
string symbol=m_table1.GetValue(0,m_table1.SelectedItem());
m_symbol.Name(symbol);
//--- Obtém os dados do indicador
GetIndicatorData(symbol,_Period);
//--- Obtém os níveis
GetLevels();
//--- Re-constrói a tabela
RebuildingTable2();
//--- Define os intervalos na primeira coluna
for(uint r=0; r<(uint)m_table2.RowsTotal(); r++)
m_table2.SetValue(0,r,(string)m_levels_array[r],0);
//--- Obtém os valores para a segunda coluna
int items_total=::ArraySize(m_levels_array);
int segments_total=m_zz.SegmentsTotal();
for(int i=0; i<items_total-1; i++)
{
//--- Progresso
m_progress_bar.LabelText("Get data ["+(string)m_levels_array[i]+"]...");
m_progress_bar.Update(i,m_table2.RowsTotal());
//---
for(int s=0; s<segments_total; s++)
{
int size=int(m_zz.SegmentSize(s)/m_symbol.Point());
if(size>m_levels_array[i] && size<m_levels_array[i+1])
{
int value=(int)m_table2.GetValue(1,i)+1;
m_table2.SetValue(1,i,(string)value,0);
}
}
}
//--- Mostrar a tabela
m_table2.Update(true);
//--- Fim do progresso
EndProgress();
}

Como exemplo, vamos receber os segmentos para o EURUSD desde 2010 até o presente no gráfico M5. Defina os
intervalos com o passo de 100 pontos de cinco dígitos. O resultado é mostrado na imagem abaixo.

O número total de segmentos é 302145. Como nós podemos ver, o número máximo de segmentos está dentro do
intervalo de zero a 100. Mais adiante, o número de segmentos é reduzido de nível para nível. Dentro do período de
https://www.mql5.com/pt/articles/5544 37/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

tempo especificado, o tamanho máximo do segmento atingido foi de 2400 pontos de cinco dígitos. 

https://www.mql5.com/pt/articles/5544 38/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Fig. 14. Resultado do cálculo do número de segmentos por tamanho

Contagem do número de segmentos por duração


Também seria bom saber a duração dos segmentos nos grupos formados. Para encontrar padrões, nós precisamos ter
todas as estatísticas dos dados analisados. Vamos desenvolver outra versão do EA. Basta copiar o programa da seção
anterior e adicionar outra tabela para a GUI. A tabela deve apresentar duas colunas: (1) número de barras e (2) número
de segmentos com esse número de barras. Abaixo, você pode ver como a GUI aparece logo após o upload do aplicativo
no gráfico.

Fig. 15. Programa para calcular o número de segmentos por duração

A sequência de ações para receber os dados em todas as tabelas é a seguinte:

https://www.mql5.com/pt/articles/5544 39/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Clique em Request para receber a lista de símbolos.


Selecione um símbolo que destaque uma linha na primeira tabela.
Clique em Calculate para receber os dados para a segunda tabela.
Para receber os dados para a terceira, selecione o intervalo necessário, destacando uma linha na segunda tabela.

A lista abaixo fornece o código do método CProgram::SetDataToTable3() para receber os dados e preencher a terceira
tabela. A linha destacada aqui é usada para receber o intervalo, dentro do qual o número de segmentos deve ser
calculado por sua duração. O número de linhas na tabela é definido pelo segmento mais longo (em barras) do conjunto
de dados obtido. Ao preencher a segunda coluna da tabela, percorra todas as linhas e conte os segmentos que se
encaixam o intervalo selecionado e o número de barras por tamanho.

class CProgram : public CWndCreate


{
private:
//--- Preenche a tabela 3 com dados
void SetDataToTable3(void);
};
//+------------------------------------------------------------------+
//| Preenche a tabela 3 com dados |
//+------------------------------------------------------------------+
void CProgram::SetDataToTable3(void)
{
//--- Encerra se a linha não estiver destacada
if(m_table2.SelectedItem()==WRONG_VALUE)
{
::Print(__FUNCTION__," > Select a range in the table on the left!");
return;
}
//--- Início do progresso
StartProgress();
//--- Oculta a mesa
m_table3.Hide();
//--- Obtém a linha destacada
int selected_row_index=m_table2.SelectedItem();
//--- Intervalo
int selected_range=(int)m_table2.GetValue(0,selected_row_index);
//--- Re-constrói a tabela
RebuildingTable3();
//--- Define os valores para a primeira coluna
for(uint r=0; r<(uint)m_table3.RowsTotal(); r++)
m_table3.SetValue(0,r,(string)(r+1),0);
//--- Obtém os valores da segunda coluna
int segments_total=m_zz.SegmentsTotal();
for(uint r=0; r<(uint)m_table3.RowsTotal(); r++)
{
//--- Progresso

https://www.mql5.com/pt/articles/5544 40/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
m_progress_bar.LabelText("Get data ["+(string)r+"]...");
m_progress_bar.Update(r,m_table3.RowsTotal());
//---
for(int s=0; s<segments_total; s++)
{
int size =int(m_zz.SegmentSize(s)/m_symbol.Point());
int bars =m_zz.SegmentBars(s);
//---
if(size>selected_range &&
size<selected_range+(int)m_step.GetValue() &&
bars==r+1)
{
int value=(int)m_table3.GetValue(1,r)+1;
m_table3.SetValue(1,r,(string)value,0);
}
}
}
//--- Exibe a tabela
m_table3.Update(true);
//--- Fim do progresso
EndProgress();
}

Ao destacar as linhas da tabela e da lista, o evento personalizado ON_CLICK_LIST_ITEM é gerado. Neste caso, nós
rastreamos a chegada do evento com o ID da segunda tabela.

//+------------------------------------------------------------------+
//| Manipulador de eventos |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &spara
{
...
//--- Eventos de clique nas linhas
if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM)
{
//--- Linha da tabela clicada
if(lparam==m_table2.Id())
{
//--- Obtém os dados para a terceira tabela
SetDataToTable3();
return;
}
//---
return;
}
...
}
https://www.mql5.com/pt/articles/5544 41/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
}

Ao receber uma nova lista de símbolos ou calcular os dados no novo símbolo realçado na primeira tabela, dados
irrelevantes de cálculos anteriores devem ser apagados das tabelas para evitar confusão sobre quais dados são exibidos
atualmente.

//+------------------------------------------------------------------+
//| Manipulador de eventos |
//+------------------------------------------------------------------+
void CProgram::OnEvent(const int id,const long &lparam,const double &dparam,const string &spara
{
//--- Evento de clique nos botões
if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
{
//--- Botão de solicitação clicado
if(lparam==m_request.Id())
{
//--- Obtém os dados para a primeira tabela
SetDataToTable1();
//--- Exclui os dados irrelevantes das tabelas
m_table2.DeleteAllRows(true);
m_table3.DeleteAllRows(true);
return;
}
//--- Calcula o botão clicado
if(lparam==m_calculate.Id())
{
//--- Obtém os dados para a segunda tabela
SetDataToTable2();
//--- Exclui os dados irrelevantes das tabelas
m_table3.DeleteAllRows(true);
}
//---
return;
}
...
}

Depois de lançar o EA no gráfico, nós obtemos o resultado conforme mostrado abaixo. Neste caso, nós formamos a lista
de pares de moedas com USD. Os dados sobre GBPUSD do início de 2018 foram recebidos posteriormente e a lista de
intervalos (segunda tabela) foi formada com o passo de 100 e os segmentos calculados para cada um deles. Como
exemplo, a linha com o intervalo de 200 e o número de segmentos de 1922 (de 200 a 300) é destacado na segunda
tabela. A terceira tabela exibe a duração de todos os segmentos do intervalo realçado na segunda tabela. Por exemplo,

https://www.mql5.com/pt/articles/5544 42/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

nós podemos ver que apenas 11 segmentos com a duração de 10 barras do intervalo especificado estavam presentes no
GBPUSD durante este período.

Fig. 16. Resultado do cálculo do número de segmentos por duração

Alguns detalhes de como trabalhar com a interface gráfica


Como um suplemento, eu gostaria de mostrar como lidar adequadamente com o evento de alterar um símbolo do
gráfico e um período de tempo quando uma GUI é usada em um programa MQL. Como as GUIs podem conter vários
controles, pode levar algum tempo para carregar e inicializar todo o conjunto. Às vezes, esse tempo pode ser salvo, o
que é exatamente o caso de alterar um símbolo de gráfico e um período de tempo. Aqui, não há necessidade de
remover e criar constantemente uma GUI repetidamente.

Isso pode ser conseguido da seguinte maneira:


https://www.mql5.com/pt/articles/5544 43/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

Crie um campo para armazenar o último motivo da desinicialização do programa na classe principal do programa:

class CProgram : public CWndCreate


{
private:
//--- Último motivo para a desinicialização
int m_last_deinit_reason;
};
//+------------------------------------------------------------------+
//| Construtor |
//+------------------------------------------------------------------+
CProgram::CProgram(void) : m_last_deinit_reason(WRONG_VALUE)
{
}

Durante a desinicialização, a GUI é removida em todos os casos, exceto aqueles em que a razão é
REASON_CHARTCHANGE.

//+------------------------------------------------------------------+
//| Desinicialização |
//+------------------------------------------------------------------+
void CProgram::OnDeinitEvent(const int reason)
{
//--- Lembre-se do último motivo de desinicialização
m_last_deinit_reason=reason;
//--- Remove a GUI se o motivo não estiver relacionado a alterar um símbolo e um ponto
if(reason!=REASON_CHARTCHANGE)
{
CWndEvents::Destroy();
}
}

Como a GUI é criada ao inicializar o programa chamando o método CProgram::CreateGUI(), agora é suficiente para
verificar a última causa de desinicialização. Se a razão for que um símbolo ou período de tempo foi alterado, não há
necessidade de criar uma GUI. Em vez disso, simplesmente saia do método notificando que tudo está bem.

//+------------------------------------------------------------------+
//| Cria a GUI |
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
{
//--- Encerra se um gráfico ou período de tempo tiver sido alterado
if(m_last_deinit_reason==REASON_CHARTCHANGE)
return(true);
...
https://www.mql5.com/pt/articles/5544 44/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5
return(true);
}

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.
Na próxima parte, eu vou mostrar que outros dados podem ser obtidos usando as ferramentas desenvolvidas nesses
artigos.

Nome do arquivo Comentário


Indicador para calcular a frequência de formação de
MQL5\Indicators\Custom\ZigZag\FrequencyChangeZZ.mq5
segmentos do indicador ZigZag de direção oposta
Indicador para calcular a soma dos segmentos do
MQL5\Indicators\Custom\ZigZag\SumSegmentsZZ.mq5
conjunto obtido e seu valor médio
Indicador da relação percentual das somas do
MQL5\Indicators\Custom\ZigZag\PercentageSegmentsZZ.mq5
segmento e da diferença entre elas
Indicador para definir a natureza da formação de
vários segmentos a partir de um período de tempo
MQL5\Indicators\Custom\ZigZag\MultiPercentageSegmentsZZ.mq5
maior, usando a diferença entre as taxas percentuais
das somas dos segmentos com direção oposta
EA para testar o indicador
MQL5\Experts\ZigZag\TestZZ_05.mq5
MultiPercentageSegmentsZZ
EA para a coleta de estatísticas sobre o indicador
MQL5\Experts\ZigZag\ZZ_Scanner_01.mq5
PercentageSegmentsZZ
EA para calcular os segmentos em diferentes faixas
MQL5\Experts\ZigZag\ZZ_Scanner_02.mq5
de preço
EA para calcular os segmentos localizados em
MQL5\Experts\ZigZag\ZZ_Scanner_03.mq5 
diferentes faixas de preço e com duração diferente

Traduzido do russo pela MetaQuotes Software Corp.


Artigo original: https://www.mql5.com/ru/articles/5544

Arquivos anexados | Download ZIP


Files.zip (45.43 KB)

https://www.mql5.com/pt/articles/5544 45/46
01/01/2021 O poder do ZigZag (parte II). Exemplos de recebimento, processamento e exibição de dados - Artigos MQL5

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.

Negociação on-line / Terminal Plataforma de negociação Sobre o projeto Windows


web MetaTrader 5
Histórico do site iPhone/iPad
Indicadores e experts gratuitos Últimas atualizações do
Termos de uso Mac OS
MetaTrader 5
Artigos sobre programação e
Contrato de pagamento Android
negociação Notícias, implementações e
recorrente
tecnologia Huawei
Encomendar experts ou
Política de privacidade e
indicadores de negociação Guia do usuário para Linux
proteção de dados
MetaTrader 5
Comprar robôs de negociação e Calendário Econômico Tradays
Política de Cookies
indicadores Linguagem de estratégias de
negociação MQL5 Contatos Não é uma corretora, não tem contas de
Sinais de negociação Forex
MQL5 Cloud Network negociação reais
Forex VPS para negociação
13 Anastasi Sioukri, 3105, Limassol,
Análise de ponta a ponta
Fórum de traders Cyprus
Baixar a MetaTrader 5
Blogs de traders Copyright 2000-2021, MetaQuotes Ltd.
Instalação da plataforma
Gráficos
Desinstalação do programa

https://www.mql5.com/pt/articles/5544 46/46

Você também pode gostar