English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Indicador para Construção do Gráfico "Ruptura de Três Linhas"

Indicador para Construção do Gráfico "Ruptura de Três Linhas"

MetaTrader 5Exemplos | 18 setembro 2014, 07:55
5 434 1
Dmitriy Zabudskiy
Dmitriy Zabudskiy

Introdução

Nos artigos anteriores estudamos os gráficos de Ponto e Figura, Kagi e Renko. Continuando a série de artigos sobre gráficos do século 20, desta vez vamos falar sobre o gráfico "Ruptura de Três Linhas" (Three Line Break) e, para ser mais preciso, sobre a sua execução através de um código de programa. Há pouca informação sobre a origem deste gráfico. Eu suponho que ela começou no Japão. Nos EUA eles foram introduzidos a este assunto após a publicação do livro "Beyond Candlesticks" por Steve Nison , em 1994.

Como mencionado nos gráficos acima, o intervalo de tempo não é levado em consideração na construção do gráfico "Ruptura de Três Linhas". Ele se baseia nos preços de fechamento recém-formados de um determinado período de tempo, o que permite filtrar pequenas flutuações de preço em relação ao movimento anterior.

Steve Nison em seu livro "Beyond Candlesticks" descreveu onze regras para plotagem deste gráfico (p. 185). Eu vou consolidá-los em apenas três regras.

  • Regra №1: Para a construção selecione um preço inicial e, em seguida, dependendo do movimento do mercado, para cima ou para baixo, desenhe uma linha ascendente ou descendente. Ela irá marcar uma nova mínima ou máxima.
  • Regra №2: Quando um novo preço for inferior a mínima ou superior a máxima, traçamos uma linha descendente ou ascendente.
  • Regra №3: Para desenhar uma linha na direção oposta do movimento anterior, é necessário superar a mínima ou a máxima. Ao mesmo tempo, se houver mais do que uma linha idêntica, então a máxima ou mínima é calculada a partir das duas (se existirem duas linhas idênticas consecutivas) ou três (em caso de três ou mais linhas idênticas consecutivas).

Vamos dar uma olhada mais de perto no exemplo clássico de um gráfico construído com base nos dados históricos (fig. 1).

Fig.1 Exemplo de construção do gráfico "Ruptura de Três Linhas" (EURUSD H1 2014/06/27)

Fig.1 Exemplo de construção do gráfico "Ruptura de Três Linhas" (EURUSD H1 2014/06/27)

A Fig. 1, a esquerda temos o gráfico de "Velas Japonesas" e no lado direito, o gráfico "Ruptura de Três Linhas". Este é o gráfico do par EURUSD, periodicidade H1. A data de inicial do gráfico é de 27/06/2014 com preço de 1,3613 (a hora de fechamento da vela é 00:00), então a vela (01:00) fecha-se em 1,3614, formando a primeira linha ascendente do gráfico "Ruptura de Três Linhas". A vela seguinte com direção de baixa (02:00) forma uma linha descendente, fechando a 1,3612 (preço de fechamento é menor do que a mínima anterior).

Então, uma vela de alta (03:00) se move em direção ao preço de 1,3619, formando uma nova máxima e uma linha. A vela das 04:00 não caiu abaixo da mínima, não afetando a representação. A vela das 05:00 fecha em 1,3623, marcando uma nova máxima (nova linha ascendente).

Agora, para representar a tendência de baixa, é necessário superar duas mínimas (1,3613), mas os "touros" não vão desistir de sua posição e acabam formando um nova máxima 1,3626 (06:00). Em seguida, os "ursos" tentam reverter a tendência de alta por duas horas, mas a mesma tendência continua com um nova máxima alcançado os 1,3634 (09:00). Os "touros" estão liderando novamente. Agora, para desenhar uma linha descendente, três mínimas devem ser superadas (1,3626; 1,3623 e 1,3619).

As seguintes três horas podemos observar como os "ursos" estão dominando o mercado, derrubando-o até a marca dos 1,3612 (12:00). Ela é refletida em uma nova linha descendente. No entanto, as cinco horas seguintes mostram que os "touros" estão retomando a sua posição e trazendo o mercado de volta ao ponto de 1,3641, passando a máxima anterior de 1,3626 e formando uma nova linha ascendente às 17:00. Os "ursos" não conseguem passar a mínima anterior às 18:00 e para as cinco horas seguintes, os "touros" elevam o mercado até a marca dos 1,3649, formando uma nova linha ascendente a cada hora.


Fundamentos da construção gráfica

Antes de chegarmos ao código, vamos falar sobre o próprio indicador e descobrir o que o torna diferente dos outros e como. É óbvio que o gráfico "Ruptura de Três Linhas", assim como outros indicadores, foi projetado para facilitar a análise do mercado de forma eficiente e para buscar novas estratégias. Tenho certeza que você quer saber se existem novidades. Na verdade, existem algumas delas. O indicador permite alterar o tipo de preço para o cálculo. Ele abrange todos os quatro preços que são padrões naa barras. O tipo clássico foi projetado para a construção de gráficos apenas para um tipo de preço enquanto o modernizado serve para usar todos os quatro tipos de preços (abertura, alta, baixa e fechamento). Ele modifica a aparência da construção gráfica clássica, adicionando "sombras" para as linhas e deixando elas com um visual de velas japoneses, o que aumenta a percepção visual do gráfico.

Na versão modernizada existem ajustes com respeito a sincronização dos dados de preços pelo tempo, que substituem os preços ausentes por aqueles que são majoritários.

O tipo modernizado de construção do gráfico é apresentado na fig. 2:

Fig.2 Gráfico modificado com base nos quatro tipos de preços

Fig.2 Gráfico modificado com base nos quatro tipos de preços

Como a construção modernizado combina quatro "Ruptura de Três Linhas" de diferentes tipos de preços, é natural encontrar discrepâncias entre os preços. Para evitar isso, é necessário uma sincronização de dados com o tempo. A sincronização de preço foi realizado em duas variações: completa (. Figura 2, à direita) e parcial (figura 2, à esquerda.). A sincronização completa representa uma sincronização parcial filtrada, onde todos os dados são desenhados no gráfico e os dados ausentes são substituídos pelos preços prioritários especificados nas configurações. No modo de sincronização completa, os dados ausentes simplesmente são omitidos e são desenhadas apenas as velas que possuem um conjunto completo de dados.

Outra inovação é o separador por período, que apresenta uma maior comodidade ao separar os sinais. Como você bem sabe, o separador por período pode ser ativado nas configurações do gráfico. No indicador eles mudam de acordo com o período de tempo, especificado nas configurações. Ao contrário dos gráficos no MetaTrader 5, em que os períodos são separados por uma linha tracejada vertical, neste indicador, um novo período é representado pela mudança de cor da linha (velas, fig 3.):

Fig.3 separadores por período no indicador

Fig.3 separadores por período no indicador

Outra adição é a implementação de um indicador técnico IMA, que é construído com base nos preços do gráfico principal, mas é sincronizado com os dados do indicador de tempo. Assim, os dados são filtrados pela média móvel (fig. 4):

Fig.4 Média móvel interna

Fig.4 Média móvel interna

O indicador também possui um recurso para definir um movimento mínimo em pontos ao desenhar uma linha e o número de linhas necessárias para uma reversão. Ele também possui um papel de filtro.


Código do indicador

O algoritmo do indicador é bem simples, contendo três estágios: a cópia dos dados, o cálculo com base nos dados copiados e o preenchimento dos buffers do indicador (construção de um gráfico com base nos dados recebidos). O código está dividido em funções que são interligadas entre si ou com os dados de entrada. Vamos analisar o códiogo de forma mais detalhada.

1. Parâmetros de entrada do indicador

O preâmbulo do indicador contém uma declaração de construções gráficas. Há dois deles no indicador: o gráfico "ABCTB" (DRAW_COLOR_CANDLES) e a média móvel adicional "LINE_TLB" (DRAW_LINE). Assim, temos 6 buffers. Em seguida, temos os dados do tipo enum para melhorar as configurações de interface e as próprias definições:

  • magic_numb - Número mágico do tipo long. Ele é um número único para denotar o indicador. Se for necessário, com uma pequena alteração é possível converter para o tipo string;
  • time_frame - Intervalo de tempo para o cálculo, do tipo ENUM_TIMEFRAMES, ele é o principal parâmetro (o período de tempo do indicador);
  • time_redraw - Período de atualizações do gráfico, do tipo ENUM_TIMEFRAMES. É o período de tempo em que ocorre um novo recálculo do gráfico. Para um redesenho rápido do gráfico pressione a tecla "R" do teclado - um controle integrado do indicador;
  • first_date_start - Data de início, do tipo datetime. Ele é um parâmetro necessário para definir o ponto de partida da cópia de dados e do desenho do gráfico;
  • chart_price - Tipos de preços para o cálculo (0-Fechamento, 1-Abertura, 2-Máxima, 3-Mínima). Para a construção clássica do gráfico, apenas um tipo de preço deve ser selecionado. Como já mencionado, este parâmetro é ignorado quando a construção modificada está habilitada;
  • step_min_f - Passo mínimo para uma nova coluna (>0, tipo int) ou um salto necessário em pontos para desenhar uma linha;;
  • line_to_back_f - Número de linhas para exibir uma reversão (>0, tipo int). O tipo clássico sugere três linhas para exibir uma reversão;
  • chart_type - Tipo de construção do gráfico (0-clássico, 1-modificado), do tipo lista de seleção. Ele é um interruptor entre os tipos de construção;
  • chart_color_period - Mudar a cor quando se inicia um novo período (tipo boolean). Utilizado para mudar a cor da linha no início de um novo período;
  • chart_synchronization - Construção do gráfico apenas quando sua sincronização estiver completa (tipo boolean, se for true, a sincronização completa ocorre quando todos os valores ausentes foram ignorados, antes de construir um gráfico);
  • chart_priority_close - É o nível de prioridade do preço de fechamento (do tipo lista de seleção, possuindo quatro variações. Ele indica a prioridade do preço de fechamento na sincronização parcial, enquanto que na completa ela é ignorada;
  • chart_priority_open - É o nível de prioridade do preço de abertura. O mesmo aplica-se aqui;
  • chart_priority_high - É o nível de prioridade do preço máximo. O mesmo aplica-se aqui;
  • chart_priority_low - É o nível de prioridade do preço mínimo. O mesmo aplica-se aqui;
  • ma_draw - Desenha a média (do tipo boolean , se for true, então desenha a média móvel);
  • ma_price - Tipo de preço para a construção da média, pode ser uma das ENUM_APPLIED_PRICE;
  • ma_method - Tipo de construção, pode ser uma das ENUM_MA_METHOD;
  • ma_period - Período para o cálculo da média móvel;

Em seguida, declaramos os arrays dos buffers e as variáveis ​​e estruturas necessárias para o cálculo.

//+------------------------------------------------------------------+
//|                                                        ABCTB.mq5 |
//|                                 "Azotskiy Aktiniy ICQ:695710750" |
//|                        "" |
//+------------------------------------------------------------------+
// ABCTB - Auto Build Chart Three Line Break
#property copyright "Azotskiy Aktiniy ICQ:695710750"
#property link      ""
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 6
#property indicator_plots   2
//--- plota ABCTB
#property indicator_label1  "ABCTB"
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrBlue,clrRed,clrGreenYellow
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plota LINE_TLB
#property indicator_label2  "LINE_TLB"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- Tipo do preço para o cálculo
enum type_price
  {
   close=0, // Close
   open=1,  // Open
   high=2,  // Hight
   low=3,   // Low
  };
//--- tipo de construção do gráfico
enum type_build
  {
   classic=0,  // Clássica
   modified=1, // Modificada
  };
//--- nível de prioridade
enum priority
  {
   highest_t=4, // Máximo
   high_t=3,    // Alto
   medium_t=2,  // Médio
   low_t=1,     // Baixo
  };
//--- parametros de entrada
input long               magic_numb=65758473787389;                // Número Mágico
input ENUM_TIMEFRAMES    time_frame=PERIOD_CURRENT;                // Período de cálculo
input ENUM_TIMEFRAMES    time_redraw=PERIOD_M1;                    // Período de atualizações do gráfico
input datetime           first_date_start=D'2013.03.13 00:00:00';  // Data de início
input type_price         chart_price=close;                        // Tipo de preço para o cálculo (0-Close, 1-Open, 2-High, 3-Low)
input int                step_min_f=4;                             // Passo mínimo para a coluna nova (>0)
input int                line_to_back_f=3;                         // Número de linhas para exibir a reversão(>0)
input type_build         chart_type=classic;                       // Tipo da construção do gráfico (0-clássica, 1-modificada)
input bool               chart_color_period=true;                  // Mudança de cor para o novo período
input bool               chart_synchronization=true;               // Construção do gráfico apenas com sincronização completa
input priority           chart_priority_close=highest_t;           // Prioridade do preço de fechamento
input priority           chart_priority_open=highest_t;            // Prioridade do preço de abertura
input priority           chart_priority_high=highest_t;            // Prioridade do preço máximo
input priority           chart_priority_low=highest_t;             // Prioridade do preço mínimo
input bool               ma_draw=true;                             // Desenha a média
input ENUM_APPLIED_PRICE ma_price=PRICE_CLOSE;                     // Tipo do preço para construção da média
input ENUM_MA_METHOD     ma_method=MODE_EMA;                       // Tipo da construção
input int                ma_period=14;                             // Período da média
//--- buffers do indicador
//--- buffer do gráfico
double         ABCTBBuffer1[];
double         ABCTBBuffer2[];
double         ABCTBBuffer3[];
double         ABCTBBuffer4[];
double         ABCTBColors[];
//--- buffer da média
double         LINE_TLBBuffer[];
//--- variáveis
MqlRates rates_array[];// array de dados das barras para análise
datetime date_stop;    // datdo atual
datetime date_start;   // variável de início do cálculo
//+------------------------------------------------------------------+
//| Struct Line Price                                                |
//+------------------------------------------------------------------+
struct line_price// estrutura para armazenar informações sobre as listas passadas
  {
   double            up;  // valor do preço máximo
   double            down;// valor do preço mínimo
  };
//+------------------------------------------------------------------+
//| Struct Line Information                                          |
//+------------------------------------------------------------------+
struct line_info// estrutura para armazenar informações sobre as linhas em comum
  {
   double            up;
   double            down;
   char              type;
   datetime          time;
  };
line_info line_main_open[];  // dados do gráfico sobre os preços de abertura
line_info line_main_high[];  // dados do grafico sobre os preços máximos
line_info line_main_low[];   // dados do grafico sobre os preços mínimos
line_info line_main_close[]; // dados do grafico sobre os preços de fechamento
//+------------------------------------------------------------------+
//| Struct Buffer Info                                               |
//+------------------------------------------------------------------+
struct buffer_info// estrutura para armazenar dados para o preenchimento dos buffer
  {
   double            open;
   double            high;
   double            low;
   double            close;
   char              type;
   datetime          time;
  };
buffer_info data_for_buffer[];// dados para preencher o buffer da construção modificada
datetime array_datetime[];    // array para armazenar informações de hora para cada linha
int time_array[3];            // array para a função func_date_color
datetime time_variable;       // variável para a função func_date_color
bool latch=false;             // variável ativadora para a função func_date_color
int handle;                   // manipulador do indicador iMA
int step_min;                 // variável para o passo mínimo
int line_to_back;             // variável para a quantidade de linhas para exibir reversão

2. Função OnInit 

Todos os buffers de indicador são declarados na função OnInit e o array do indicador é definido em séries temporais.

Em seguida, definimos os valores do indicador que não serão desenhados no gráfico, definimos o nome, especificamos a precisão e removemos os valores atuais pois eles sobrecarregam o gráfico. Definimos aqui também o manipulador do indicador IMA e verificamos a exatidão dos dados introduzidos. No caso de erro, uma mensagem apropriada é impressa e o valor é alterado para o mínimo.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Mapeamento dos buffers de indicador
//--- buffers para o gráfico
   SetIndexBuffer(0,ABCTBBuffer1,INDICATOR_DATA);
   ArraySetAsSeries(ABCTBBuffer1,true);
   SetIndexBuffer(1,ABCTBBuffer2,INDICATOR_DATA);
   ArraySetAsSeries(ABCTBBuffer2,true);
   SetIndexBuffer(2,ABCTBBuffer3,INDICATOR_DATA);
   ArraySetAsSeries(ABCTBBuffer3,true);
   SetIndexBuffer(3,ABCTBBuffer4,INDICATOR_DATA);
   ArraySetAsSeries(ABCTBBuffer4,true);
   SetIndexBuffer(4,ABCTBColors,INDICATOR_COLOR_INDEX);
   ArraySetAsSeries(ABCTBColors,true);
//--- buffer para construção da média
   SetIndexBuffer(5,LINE_TLBBuffer,INDICATOR_DATA);
   ArraySetAsSeries(LINE_TLBBuffer,true);
//--- definição de valores que não serão desenhados no gráfico
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0); // para o gráfico
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0); // para a média
//--- definição da aparência dos indicadores
   IndicatorSetString(INDICATOR_SHORTNAME,"ABCTB "+IntegerToString(magic_numb)); // name of the indicator
//--- precisão de exibição
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//--- proibição de exibir os resultados dos valores atuais para o indicador
   PlotIndexSetInteger(0,PLOT_SHOW_DATA,false);
   PlotIndexSetInteger(1,PLOT_SHOW_DATA,false);
//---
   handle=iMA(_Symbol,time_frame,ma_period,0,ma_method,ma_price);
   if(step_min_f<1)
     {
      step_min=1;
      Alert("O passo mínimo para a nova coluna deve ser superior a zero");
     }
   else step_min=step_min_f;
//---
   if(line_to_back_f<1)
     {
      line_to_back=1;
      Alert("O número de linhas para exibição deve ser superior a zero");
     }
   else line_to_back=line_to_back_f;
//---
   return(INIT_SUCCEEDED);
  }

3. Função que cópia os dados

Como o indicador foi projetado para trabalhar com todos os quatro tipos de preços, é essencial copiar todos os dados, incluindo o tempo. Em MQL5 existe uma estrutura chamada MqlRates. Ele é usada para armazenar informações sobre o tempo de início de uma sessão de negociação, preços, volumes e do spread.

Os parâmetros de entrada da função são: data de início e fim, período de tempo e o array de destino do tipo MqlRates. A função retorna true se a cópia for bem-sucedida. Os dados são copiados em um array intermediário. Os dados ausentes calculados e mais uma sessão são copiados nele, sendo que os dados são contantemente renovados. Se a cópia para o array intermediário for bem sucedida, então os dados são copiados para o array, assegurando o funcionamento correto da função.

//+------------------------------------------------------------------+
//| Func All Copy                                                    |
//+------------------------------------------------------------------+
bool func_all_copy(MqlRates &result_array[],// array de resposta
                   ENUM_TIMEFRAMES period,  // período de tempo
                   datetime data_start,     // data de início
                   datetime data_stop)      // data de término
  {
//--- declaração da variáveis auxiliares
   bool x=false;       // variável para a resposta da função
   int result_copy=-1; // quantidade de dados copiados
//--- adição de variáveis e arrays para o cálculo
   static MqlRates interim_array[]; // arrya dinâmico temporário para o armazenamento de dados copiados
   static int bars_to_copy;         // número de barras para copiar
   static int bars_copied;          // número de barras já copiados desde o início
//--- Descobrir o número atual de barras no intervalo de tempo
   bars_to_copy=Bars(_Symbol,period,data_start,data_stop);
//--- Contar o número de barras a ser copiado
   bars_to_copy-=bars_copied;
//--- e não é a primeira vez que os dados são copiados
   if(bars_copied>0)
     {
      bars_copied--;
      bars_to_copy++;
     }
//--- Alterar o tamanho do array recebido
   ArrayResize(interim_array,bars_to_copy);
//--- Copiar os dados para o array temporário
   result_copy=CopyRates(_Symbol,period,0,bars_to_copy,interim_array);
//--- verifica o resultado da cópia dos dados
   if(result_copy!=-1) // se a cópia do array temporário foi um sucesso
     {
      ArrayCopy(result_array,interim_array,bars_copied,0,WHOLE_ARRAY); // copia os dados do array temporário para o principal
      x=true;                   // atribui resposta positiva para a função
      bars_copied+=result_copy; // aumenta o valor dos dados copiados
     }
//---
   return(x);
  }

4. Função para o cálculo de dados

Esta função é um protótipo do cálculo de dados para uma construção clássica do gráfico "Ruptura de Três Linhas". Como já mencionado, a função apenas calcula os dados e transmite para um array especial do tipo estrutura line_info, declarada no início do código.

Esta função contém duas outras funções: func_regrouping (função de reagrupamento) e func_insert (função de inserção). Vamos dar uma olhada nelas para começar:

4.1. Função de Reagrupamento

Esta função reagrupa informações sobre linhas consecutivas de uma mesma direção. Ele é limitado pelo tamanho do array passado para ele ou, para ser mais preciso, pelo parâmetro line_to_back_f (Número de linhas para exibir uma reversão) a partir das definições do indicador. Então, toda vez que o comando é passado para a função, todos os dados recebidos sobre as linhas idênticas se deslocam em um índice para o fim e o índice 0 é preenchido por um novo valor.

Esta é a forma que as informações sobre as linhas, que são necessárias para haver um rompimento, são armazenadas (no caso da construção clássica o rompimento possui três linhas).

//+------------------------------------------------------------------+
// Func Regrouping                                                   |
//+------------------------------------------------------------------+
void func_regrouping(line_price &input_array[],// array para reagrupamento
                     double new_price,         // novo valor do preço
                     char type)                // tipo do movimento
  {
   int x=ArraySize(input_array);// descobrir o tamanho do array de agrupamento
   for(x--; x>0; x--)           // loop de reagrupamento
     {
      input_array[x].up=input_array[x-1].up;
      input_array[x].down=input_array[x-1].down;
     }
   if(type==1)
     {
      input_array[0].up=new_price;
      input_array[0].down=input_array[1].up;
     }
   if(type==-1)
     {
      input_array[0].down=new_price;
      input_array[0].up=input_array[1].down;
     }
  }

 4.2. Função de Inserção

 A função realiza a inserção dos valores para o array de resposta. O código é simples e não necessita de uma explicação detalhada. 

//+------------------------------------------------------------------+
// Func Insert                                                       |
//+------------------------------------------------------------------+
void func_insert(line_info &line_m[],  // array destino
                 line_price &line_i[], // array fonte
                 int index,            // elemento do array sendo inserido
                 char type,            // tipo da coluna destino
                 datetime time)        // data
  {
   line_m[index].up=line_i[0].up;
   line_m[index].down=line_i[0].down;
   line_m[index].type=type;
   line_m[index].time=time;
  }

A função para o cálculo de dados foi convencionalmente dividida em três partes. A primeira parte copia os dados em análise para um array intermediário com a ajuda do operador switch. Apenas o preço é copiado. A segunda parte faz um teste para calcular o espaço necessário no array de dados. Em seguida, o array de dados line_main_array[], inicialmente passado para a função de resposta, sofre uma alteração. A terceira parte, por sua vez, preenche o array de dados ajustado.

//+------------------------------------------------------------------+
//| Func Build Three Line Break                                      |
//+------------------------------------------------------------------+
void func_build_three_line_break(MqlRates &input_array[],      // array para análise
                                 char price_type,              // tipo do preço em análise (0-Close, 1-Open, 2-High, 3-Low)
                                 int min_step,                 // passo mínimo para desenhar a linha
                                 int line_back,                // número de linhas para uma reversão
                                 line_info &line_main_array[]) // array de retorno (resposta) da função
  {
//--- calcular o tamanho do array para análise
   int array_size=ArraySize(input_array);
//--- extrair os dados necessários para o cálculo do array intermediário
   double interim_array[];// array intermediário
   ArrayResize(interim_array,array_size);// ajustar o array intermediário para o tamanho dos dados
   switch(price_type)
     {
      case 0: // Close
        {
         for(int x=0; x<array_size; x++)
           {
            interim_array[x]=input_array[x].close;
           }
        }
      break;
      case 1: // Open
        {
         for(int x=0; x<array_size; x++)
           {
            interim_array[x]=input_array[x].open;
           }
        }
      break;
      case 2: // High
        {
         for(int x=0; x<array_size; x++)
           {
            interim_array[x]=input_array[x].high;
           }
        }
      break;
      case 3: // Low
        {
         for(int x=0; x<array_size; x++)
           {
            interim_array[x]=input_array[x].low;
           }
        }
      break;
     }
//--- Introduzir as variáveis ​​para armazenar os dados na posição atual
   line_price passed_line[];// array salvos nos preços última linha (estrutura tipo line_price)
   ArrayResize(passed_line,line_back+1);
   int line_calc=0;// número de linhas
   int line_up=0;// número das últimas linhas ascendentes
   int line_down=0;// número das últimas linhas descendentes
   double limit_up=0;// limite superior necessário para passar
   double limit_down=0;// limite inferior necessário para passar
/* Preencher as variáveis informando a situação atual com os primeiros valores */
   passed_line[0].up=interim_array[0];
   passed_line[0].down=interim_array[0];
//--- iniciar o primeiro loop para calcular os dados recebidos para preenchimento do buffer para desenho
   for(int x=0; x<array_size; x++)
     {
      if(line_calc==0)// número de linhas que forma redesenhadas
        {
         limit_up=passed_line[0].up;
         limit_down=passed_line[0].down;
         if(interim_array[x]>=limit_up+min_step*_Point)// o limite superior foi passado
           {
            func_regrouping(passed_line,interim_array[x],1);// reagrupar
            line_calc++;// atualizar o contador da linha
            line_up++;
           }
         if(interim_array[x]<=limit_down-min_step*_Point)// o limite inferior foi passado
           {
            func_regrouping(passed_line,interim_array[x],-1);// reagrupar
            line_calc++;// atualizar o contador da linha
            line_down++;
           }
        }
      if(line_up>line_down)// última linha ascendente(linhas)
        {
         limit_up=passed_line[0].up;
         limit_down=passed_line[(int)MathMin(line_up,line_back-1)].down;
         if(interim_array[x]>=limit_up+min_step*_Point)// o limite superior fo passado
           {
            func_regrouping(passed_line,interim_array[x],1);// reagrupar
            line_calc++;// atualizar o contador da linha
            line_up++;
           }
         if(interim_array[x]<limit_down)// a linha inferior foi passada
           {
            func_regrouping(passed_line,interim_array[x],-1);// reagrupar
            line_calc++;// atualizar o contador de linha
            line_up=0;
            line_down++;
           }
        }
      if(line_down>line_up)// últimas linhas descendentes (linhas)
        {
         limit_up=passed_line[(int)MathMin(line_down,line_back-1)].up;
         limit_down=passed_line[0].down;
         if(interim_array[x]>limit_up)// a linha superior foi passada
           {
            func_regrouping(passed_line,interim_array[x],1);// reagrupar
            line_calc++;// atualizar o contador de linha
            line_down=0;
            line_up++;
           }
         if(interim_array[x]<=limit_down-min_step*_Point)// a linha inferior foi passada
           {
            func_regrouping(passed_line,interim_array[x],-1);// reagrupar
            line_calc++;// atualizar o contador de linha
            line_down++;
           }
        }
     }
   ArrayResize(line_main_array,line_calc);// muda o tamanho do array destino
//--- zera as variáveis e preenche com os dados iniciais
   line_calc=0;
   line_up=0;
   line_down=0;
   passed_line[0].up=interim_array[0];
   passed_line[0].down=interim_array[0];
//--- começa o segundo loop para preencher o buffer de desenho
   for(int x=0; x<array_size; x++)
     {
      if(line_calc==0)// sem linhas para desenhar
        {
         limit_up=passed_line[0].up;
         limit_down=passed_line[0].down;
         if(interim_array[x]>=limit_up+min_step*_Point)// a linha superior foi passada
           {
            func_regrouping(passed_line,interim_array[x],1);// reagrupar
            func_insert(line_main_array,passed_line,line_calc,1,input_array[x].time);
            line_calc++;// atualizar o contador de linha
            line_up++;
           }
         if(interim_array[x]<=limit_down-min_step*_Point)// a linha inferior foi passada
           {
            func_regrouping(passed_line,interim_array[x],-1);// reagrupar
            func_insert(line_main_array,passed_line,line_calc,-1,input_array[x].time);
            line_calc++;// atualizar o contador de linha
            line_down++;
           }
        }
      if(line_up>line_down)// última linha ascendente(linhas)
        {
         limit_up=passed_line[0].up;
         limit_down=passed_line[(int)MathMin(line_up,line_back-1)].down;
         if(interim_array[x]>=limit_up+min_step*_Point)// a linha superior foi passada
           {
            func_regrouping(passed_line,interim_array[x],1);// reagrupar
            func_insert(line_main_array,passed_line,line_calc,1,input_array[x].time);
            line_calc++;// atualizar o contador de linha
            line_up++;
           }
         if(interim_array[x]<limit_down)// a linha inferior foi passada
           {
            func_regrouping(passed_line,interim_array[x],-1);// reagrupar
            func_insert(line_main_array,passed_line,line_calc,-1,input_array[x].time);
            line_calc++;// atualizar o contador de linha
            line_up=0;
            line_down++;
           }
        }
      if(line_down>line_up)// últimas linhas descendentes (linhas)
        {
         limit_up=passed_line[(int)MathMin(line_down,line_back-1)].up;
         limit_down=passed_line[0].down;
         if(interim_array[x]>limit_up)// a linha superior foi passada
           {
            func_regrouping(passed_line,interim_array[x],1);// reagrupar
            func_insert(line_main_array,passed_line,line_calc,1,input_array[x].time);
            line_calc++;// atualizar o contador de linha
            line_down=0;
            line_up++;
           }
         if(interim_array[x]<=limit_down-min_step*_Point)// a linha inferior foi passada
           {
            func_regrouping(passed_line,interim_array[x],-1);// reagrupar
            func_insert(line_main_array,passed_line,line_calc,-1,input_array[x].time);
            line_calc++;// atualizar o contador de linha
            line_down++;
           }
        }
     }
  }

5. Função de construção do gráfico

A finalidade desta função é calcular os dados para um gráfico baseado no parâmetro da construção selecionado (clássico ou modificado) e para preencher o buffer do indicador com os dados de exibição. Bem como a função anterior, a função de construção do gráfico tem três funções adicionais. Eles são a função de cor, a função de sincronização e a função da média móvel. Vamos discuti-las com maiores detalhes.

5.1. Função de Cor

Esta função tem apenas um parâmetro de entrada - o tempo. A resposta da função é uma variável booleana. Se os dados passados esta na fronteira do período, a função retornará true. Como os períodos dependem do tempo gráfico selecionado, a função possui uma separador interno de período pelo operador condicional if. Após o período ser selecionado, ele verifica se um novo período já começou. Ele é feito através da conversão dos dados em uma estrutura MqlDateTime e pela comparação. Para o período de tempo até, e inclusive, H2, as alterações no valor da data indicam o início de um novo período. Períodos de tempo de H12 para D1 indicam mudanças no mês e entre W1 e MN vamos verificar a mudança no ano.

Infelizmente, a estrutura MqlDateTime não possui informações sobre a semana atual. Esse problema foi resolvido com a criação de um ponto inicial representado pela variável time_variable. Mais ao longo da linha, o número de segundos em uma semana fica deduzido a partir desta data.

//+------------------------------------------------------------------+
// Func Date Color                                                   |
//+------------------------------------------------------------------+
bool func_date_color(datetime date_time) // data de entrada
  {
   bool x=false;// variável de resposta
   int seconds=PeriodSeconds(time_frame);// encontrar o intervalo de tempo do cálculo
   MqlDateTime date;
   TimeToStruct(date_time,date);// converter em data
   if(latch==false) // verifica o estado do ativador
     {
      MqlDateTime date_0;
      date_0=date;
      date_0.hour=0;
      date_0.min=0;
      date_0.sec=0;
      int difference=date_0.day_of_week-1;
      datetime date_d=StructToTime(date_0);
      date_d=date_d-86400*difference;
      time_variable=date_d;
      latch=true;// lock the latch
     }
   if(seconds<=7200)// período é igual ou menor a H2
     {
      if(time_array[0]!=date.day)
        {
         x=true;
         time_array[0]=date.day;
        }
     }
   if(seconds>7200 && seconds<=43200)// período é maior que H2, mas é menor ou igual a H12
     {
      if(time_variable>=date_time)
        {
         x=true;
         time_variable=time_variable-604800;
        }
     }
   if(seconds>43200 && seconds<=86400)// período é maior que H12, mas é menor ou igual a D1
     {
      if(time_array[1]!=date.mon)
        {
         x=true;
         time_array[1]=date.mon;
        }
     }
   if(seconds>86400)// período W1 or MN
     {
      if(time_array[2]!=date.year)
        {
         x=true;
         time_array[2]=date.year;
        }
     }
   return(x);
  }

5.2. Função de sincronização

A função de sincronização possui seis parâmetros de entrada: quatro delas são os preços a priori, o parâmetro booleano de sincronização completa ou parcial e o próprio array de análise. A função é dividida em duas partes: uma caixa de sincronização completa e parcial.

A sincronização completa é efetuada em três fases:

  1. Cálculo dos elementos do array, satisfazendo a condição de conter os dados de todos os quatro tipos de preços.
  2. Cópia dos elementos em um array intermediário sob a mesma condição.
  3. Cópia a partir do array intermediário para o que foi passado nos parâmetros.

A sincronização parcial é mais complexa.

Passada o array de estrutura unidimensional, ele é convertido em um array bi-dimensional, onde o primeiro índice indica a ordem e o segundo o tipo do preço. Em seguida, é introduzido um array unidimensional com quatro elementos. Os níveis de prioridade de preço são copiados para esse array e, em seguida, o array é ordenado para identificar a ordem de prioridade. Depois que realizamos a distribuição de acordo com as prioridades usando o loop for e o operador condicional if. Ao mesmo tempo, se as prioridades são iguais, então a sequência de preço é a seguinte: fechamento, abertura, máxima, mínima. Assim que o operador if encontrar o primeiro valor de prioridade, o loop for substituirá todos os dados contendo zero no array bidimensional criado anteriormente para os os que tiverem mais prioridade, etc

//+------------------------------------------------------------------+
// Func Synchronization                                              |
//+------------------------------------------------------------------+
void func_synchronization(buffer_info &info[],
                          bool synchronization,
                          char close,
                          char open,
                          char high,
                          char low)
  {
   if(synchronization==true)// realiza a sincronização completa
     {
      int calc=0;// varioável de contagem
      for(int x=0; x<ArraySize(info); x++)// contagem dos dados completos
        {
         if(info[x].close!=0 && info[x].high!=0 && info[x].low!=0 && info[x].open!=0)calc++;
        }
      buffer_info i_info[];    // introduz um array temporário para copiar
      ArrayResize(i_info,calc);// muda o tamanho do array temporário
      calc=0;
      for(int x=0; x<ArraySize(info); x++)// copia os dados para o array temporário
        {
         if(info[x].close!=0 && info[x].high!=0 && info[x].low!=0 && info[x].open!=0)
           {
            i_info[calc]=info[x];
            calc++;
           }
        }
      ZeroMemory(info);        // esvazia o array de destino
      ArrayResize(info,calc);  // modifica o tamanho do array principal
      for(int x=0; x<calc; x++)// copia os dados do array temporário para o principal
        {
         info[x]=i_info[x];
        }
     }
   if(synchronization==false)  // zera os valores para os prioritários
     {
      int size=ArraySize(info); // mede o tamanho do array
      double buffer[][4];       // cria um array temporário para o cálculo
      ArrayResize(buffer,size); // muda o tamanho do array temporário
      for(int x=0; x<size; x++) // copia os dados para o array temporário
        {
         buffer[x][0]=info[x].close;
         buffer[x][1]=info[x].open;
         buffer[x][2]=info[x].high;
         buffer[x][3]=info[x].low;
        }
      char p[4];// introduz um array para ordenação por ordem
      p[0]=close; p[1]=open; p[2]=high; p[3]=low;// atribui variáveis para posterior ordenação
      ArraySort(p); // ordena
      int z=0,v=0;  // inicializa as variáveis frequentemente usadas
      for(int x=0; x<4; x++)// leva em conta os resultados de ordenação, repassa as variáveis e substituí segundo as prioridades
        {
         if(p[x]==close)// prioridade para os preços de fechamento
           {
            for(z=0; z<size; z++)
              {
               for(v=1; v<4; v++)
                 {
                  if(buffer[z][v]==0)buffer[z][v]=buffer[z][0];
                 }
              }
           }
         if(p[x]==open)// prioridade para os preços de abertura
           {
            for(z=0; z<size; z++)
              {
               for(v=0; v<4; v++)
                 {
                  if(v!=1 && buffer[z][v]==0)buffer[z][v]=buffer[z][1];
                 }
              }
           }
         if(p[x]==high)// prioridade para os preços máximos
           {
            for(z=0; z<size; z++)
              {
               for(v=0; v<4; v++)
                 {
                  if(v!=2 && buffer[z][v]==0)buffer[z][v]=buffer[z][2];
                 }
              }
           }
         if(p[x]==low)// prioridade para os preços mínimos
           {
            for(z=0; z<size; z++)
              {
               for(v=0; v<3; v++)
                 {
                  if(buffer[z][v]==0)buffer[z][v]=buffer[z][3];
                 }
              }
           }
        }
      for(int x=0; x<size; x++)// copia os dados do array temporário de volta
        {
         info[x].close=buffer[x][0];
         info[x].open=buffer[x][1];
         info[x].high=buffer[x][2];
         info[x].low=buffer[x][3];
        }
     }
  }

5.3. Função da média móvel

Ela é a função mais simples. Utilizando o manipulador do indicador, recebido na função OnInit, nós copiamos o valor correspondente à data que foi passada nos parâmetros da função. Então este valor é retornado como uma resposta a esta função.

//+------------------------------------------------------------------+
// Func MA                                                           |
//+------------------------------------------------------------------+
double func_ma(datetime date)
  {
   double x[1];
   CopyBuffer(handle,0,date,1,x);
   return(x[0]);
  }

A função de plotagem do gráfico é convencionalmente dividida em duas partes: plotagem clássica e a plotagem modificada. A função tem dois parâmetros de entrada: Tipo do preço para construção (ignorado durante a construção modificada) e o tipo da construção (clássica e modificada).

No início, os buffers do indicador são esvaziados e depois, dependendo do tipo de construção, dividida em duas partes. A primeira parte (estamos falando da construção modificada) começa com a chamada da função para calcular todos os quatro tipos de preços. Então vamos criar um array de dados comum onde copiamos os dados em uso, recebidos quando acontece a chamada da função de cálculo de dados. Em seguida, o array de dados recebido fica ordenado e é esvaziado a partir dos dados replicados. Depois disso, o array data_for_buffer[], declarado a nível global, é preenchido com base nas datas consecutivas com a seguinte sincronização de dados. O preenchimento dos buffers de indicador é a fase final da construção modificada.

A segunda parte (construção clássico) é muito mais simples. A princípio, a função de cálculo de dados é chamada e, em seguida, os buffers do indicador são preenchidos.

//+------------------------------------------------------------------+
//| Func Chart Build                                                 |
//+------------------------------------------------------------------+
void func_chart_build(char price, // tipo do preço para construção do gráfico
                      char type)  // tipo de construção do gráfico
  {
//--- Zera os buffers
   ZeroMemory(ABCTBBuffer1);
   ZeroMemory(ABCTBBuffer2);
   ZeroMemory(ABCTBBuffer3);
   ZeroMemory(ABCTBBuffer4);
   ZeroMemory(ABCTBColors);
   ZeroMemory(LINE_TLBBuffer);
   if(type==1)// constrói o gráfico modificado (para todos os tipos de preço)
     {
      func_build_three_line_break(rates_array,0,step_min,line_to_back,line_main_close);// dados dos preços de fechamento
      func_build_three_line_break(rates_array,1,step_min,line_to_back,line_main_open);// dados dos preços de abertura
      func_build_three_line_break(rates_array,2,step_min,line_to_back,line_main_high);// dados dos preços máximos
      func_build_three_line_break(rates_array,3,step_min,line_to_back,line_main_low);// dados dos preços mínimos
      //--- calcula os dados do array
      int line_main_calc[4];
      line_main_calc[0]=ArraySize(line_main_close);
      line_main_calc[1]=ArraySize(line_main_open);
      line_main_calc[2]=ArraySize(line_main_high);
      line_main_calc[3]=ArraySize(line_main_low);
      //--- reunimos os dados do array
      int all_elements=line_main_calc[0]+line_main_calc[1]+line_main_calc[2]+line_main_calc[3];// encontra o número de todos os elementos
      datetime datetime_array[];// introduz o array para copiar
      ArrayResize(datetime_array,all_elements);
      int y[4];
      ZeroMemory(y);
      for(int x=0;x<ArraySize(datetime_array);x++)// copia os dados para o array
        {
         if(x<line_main_calc[0])
           {
            datetime_array[x]=line_main_close[y[0]].time;
            y[0]++;
           }
         if(x<line_main_calc[0]+line_main_calc[1] && x>=line_main_calc[0])
           {
            datetime_array[x]=line_main_open[y[1]].time;
            y[1]++;
           }
         if(x<line_main_calc[0]+line_main_calc[1]+line_main_calc[2] && x>=line_main_calc[0]+line_main_calc[1])
           {
            datetime_array[x]=line_main_high[y[2]].time;
            y[2]++;
           }
         if(x>=line_main_calc[0]+line_main_calc[1]+line_main_calc[2])
           {
            datetime_array[x]=line_main_low[y[3]].time;
            y[3]++;
           }
        }
      ArraySort(datetime_array);// ordena o array
      //--- remove dados replicados do array
      int good_info=1;
      for(int x=1;x<ArraySize(datetime_array);x++)// conta informações úteis
        {
         if(datetime_array[x-1]!=datetime_array[x])good_info++;
        }
      ArrayResize(array_datetime,good_info);
      array_datetime[0]=datetime_array[0];// copia o primeiro elemento como um padrão para o começo da comparação
      good_info=1;
      for(int x=1;x<ArraySize(datetime_array);x++)// preenche o array com novos dados
        {
         if(datetime_array[x-1]!=datetime_array[x])
           {
            array_datetime[good_info]=datetime_array[x];
            good_info++;
           }
        }
      //--- preencher o buffer para desenho (velas coloridas)
      int end_of_calc[4];// variáveis para armazenar informações sobre a última comparação 
      ZeroMemory(end_of_calc);
      ZeroMemory(data_for_buffer);
      ArrayResize(data_for_buffer,ArraySize(array_datetime));// altera o tamanho do array declarado globalmente para armazenar os dados antes de passar para o buffer
      for(int x=0; x<ArraySize(array_datetime); x++)
        {
         data_for_buffer[x].time=array_datetime[x];
         for(int s=end_of_calc[0]; s<line_main_calc[0]; s++)
           {
            if(array_datetime[x]==line_main_close[s].time)
              {
               end_of_calc[0]=s;
               if(line_main_close[s].type==1)data_for_buffer[x].close=line_main_close[s].up;
               else data_for_buffer[x].close=line_main_close[s].down;
               break;
              }
           }
         for(int s=end_of_calc[1]; s<line_main_calc[1]; s++)
           {
            if(array_datetime[x]==line_main_open[s].time)
              {
               end_of_calc[1]=s;
               if(line_main_open[s].type==1)data_for_buffer[x].open=line_main_open[s].down;
               else data_for_buffer[x].open=line_main_open[s].up;
               break;
              }
           }
         for(int s=end_of_calc[2]; s<line_main_calc[2]; s++)
           {
            if(array_datetime[x]==line_main_high[s].time)
              {
               end_of_calc[2]=s;
               data_for_buffer[x].high=line_main_high[s].up;
               break;
              }
           }
         for(int s=end_of_calc[3]; s<line_main_calc[3]; s++)
           {
            if(array_datetime[x]==line_main_low[s].time)
              {
               end_of_calc[3]=s;
               data_for_buffer[x].low=line_main_low[s].down;
               break;
              }
           }
        }
      //--- inicia a função de sincronização dos dados
      func_synchronization(data_for_buffer,chart_synchronization,chart_priority_close,chart_priority_open,chart_priority_high,chart_priority_low);
      //--- ações preparatórias antes de iniciar a função func_date_color
      ZeroMemory(time_array);
      time_variable=0;
      latch=false;
      //--- preencher o buffer para desenhar as velas
      for(int x=ArraySize(data_for_buffer)-1,z=0; x>=0; x--)
        {
         ABCTBBuffer1[z]=data_for_buffer[x].open;
         ABCTBBuffer2[z]=data_for_buffer[x].high;
         ABCTBBuffer3[z]=data_for_buffer[x].low;
         ABCTBBuffer4[z]=data_for_buffer[x].close;
         if(ABCTBBuffer1[z]<=ABCTBBuffer4[z])ABCTBColors[z]=0;
         if(ABCTBBuffer1[z]>=ABCTBBuffer4[z])ABCTBColors[z]=1;
         if(func_date_color(data_for_buffer[x].time)==true && chart_color_period==true)ABCTBColors[z]=2;
         if(ma_draw==true)LINE_TLBBuffer[z]=func_ma(data_for_buffer[x].time);
         z++;
        }
     }
   else// constrói um gráfico clássico (baseado no tipo de preço)
     {
      func_build_three_line_break(rates_array,price,step_min,line_to_back,line_main_close);// procura os dados nos preços selecionados
      ArrayResize(array_datetime,ArraySize(line_main_close));
      //--- ações preparatórias antes de iniciar a função func_date_color
      ZeroMemory(time_array);
      time_variable=0;
      latch=false;
      //--- preencher o buffer para desenhar as velas
      for(int x=ArraySize(line_main_close)-1,z=0; x>=0; x--)
        {
         ABCTBBuffer1[z]=line_main_close[x].up;
         ABCTBBuffer2[z]=line_main_close[x].up;
         ABCTBBuffer3[z]=line_main_close[x].down;
         ABCTBBuffer4[z]=line_main_close[x].down;
         if(line_main_close[x].type==1)ABCTBColors[z]=0;
         else ABCTBColors[z]=1;
         if(func_date_color(line_main_close[x].time)==true && chart_color_period==true)ABCTBColors[z]=2;
         if(ma_draw==true)LINE_TLBBuffer[z]=func_ma(line_main_close[x].time);
         z++;
        }
     }
  }

6. Função de consolidação

Esta função reúne todos os elementos de gestão do indicador. No início, a data atual é definida, em seguida, a função de copiar dados e a de construção do gráfico são chamadas.

//+------------------------------------------------------------------+
//| Func Consolidation                                               |
//+------------------------------------------------------------------+
void func_consolidation()
  {
//--- define a data atual
   date_stop=TimeCurrent();
//--- copia os dados para análise
   func_all_copy(rates_array,time_frame,first_date_start,date_stop);
//--- construção básica para o gráfico
   func_chart_build(chart_price,chart_type);
   ChartRedraw();
  }

7. Função de gestão da construção mediante ao teclado e de maneira automática

Estas funções são projetados para redesenhar o indicador, pressionando a tecla "R" (OnChartEvent) do teclado ou fazê-lo automaticamente de acordo com o intervalo de tempo selecionado (OnCalculate). Este último é analisado pela função nova barra (func_new_bar), que é uma versão simplificada da função descrita IsNewBar.

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//---
   if(func_new_bar(time_redraw)==true)
     {
      func_consolidation();
     };
//--- retorna o valor de prev_calculated para a próxima chamada
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- evento para as teclas
   if(id==CHARTEVENT_KEYDOWN)
     {
      if(lparam==82) //--- the key "R" has been pressed
        {
         func_consolidation();
        }
     }
  }
//+------------------------------------------------------------------+
//| Func New Bar                                                     |
//+------------------------------------------------------------------+
bool func_new_bar(ENUM_TIMEFRAMES period_time)
  {
//---
   static datetime old_times; // variável para armazenar valores antigos 
   bool res=false;            // variável para analisar resultados
   datetime new_time[1];      // tempo para uma nova barra
//---
   int copied=CopyTime(_Symbol,period_time,0,1,new_time); // copia o tempo da última barra para a célula new_time
//---
   if(copied>0) // tudo está OK. dados copiados
     {
      if(old_times!=new_time[0]) // se o tempo antigo da barra não for igual ao novo
        {
         if(old_times!=0) res=true; // se não é a primeira vez, entao nova barra = true
         old_times=new_time[0];     // lembra o tempo da barra
        }
     }
//---
   return(res);
  }

Neste ponto, devemos terminar descrevendo o código do indicador e falar sobre as maneiras de usá-lo.


Exemplos de como usar o indicador e uma estratégia de negociação

Vamos começar com as principais estratégias de análise com base na construção do gráfico clássico.

1. Linhas brancas e pretas como sinais de compra e venda

Podemos falar aproximadamente sobre duas regras:

  1. Regra №1: Compre, quando há três linhas ascendentes consecutivas e venda quando há três linhas descendentes consecutivas. Três linhas consecutivas indicam uma tendência aparente.
  2. Regra №2: Venda, quando a linha de reversão cai abaixo das três linhas ascendentes consecutivas, compre quando a linha de reversão é maior do que as três linhas descendentes consecutivas.

Vejamos a fig.6, representando uma construção clássica para o par EURUSD H1 a partir do início de 2013 (o intervalo de tempo analisado é retratado na fig.5).

Fig.5 Intervalo de tempo analisado para o par EURUSD H1

Fig.5 Intervalo de tempo analisado para o par EURUSD H1

Fig.6 Construção clássica do gráfico "Ruptura de Três Linhas" para EURUSD H1, a partir de 2013, preços de fechamento

Fig.6 Construção clássica do gráfico "Ruptura de Três Linhas" para EURUSD H1, a partir de 2013, preços de fechamento

No gráfico (fig. 6), podemos ver claramente o sinal (regra №1) entre os pontos 1 e 2, que é um ponto de partida para a venda. Neste caso, o ganho é de mais de 200 pontos para quatro dígitos decimais. O ponto 4 a seguir indica uma situação favorável para a compra (como na regra №2). No fechamento, no ponto 5, o lucro foi de 40 pontos e estamos no ponto de equilíbrio no fechamento do ponto 6.

No ponto 6, podemos ver um sinal de venda (regra №2). Conseguimos 10 pontos de lucro quando no fechamento do ponto 7 e o ponto de equilíbrio no fechamento do ponto 8. Os pontos 8 e 9 não podem ser considerados como sinais pois eles não satisfazem a regra №1 e nem a regra №2. Nós podemos comprar no ponto 10 (regra №1); podemos também obter lucro de 20 pontos no fechamento do ponto 11 ou um ponto de equilíbrio no ponto 12. Todos os números foram arredondados.

Na melhor das hipóteses, usando essa estratégia poderiamos ter gerado um lucro de 270 pontos, o que é impressionante. Ao mesmo tempo, no intervalo de tempo especificado, há um intenso movimento que afeta os lucros. No pior cenário, a negociação pode resultar em um equilíbrio, o que não é ruim.

Vale ressaltar que, quando uma situação satisfaz qualquer regra ou norma №1 №2, precisamos esperar por uma confirmação de reversão da tendência representada por uma linha no mesmo sentido que a tendência.

2. Canal equidistante, linhas de suporte e resistência

Outra estratégia de negociação é a aplicação da análise técnica para o gráfico "Ruptura de Três Linhas". Vamos dar uma olhada na fig. 7:

Fig. 7 Canal equidistante, linhas de suporte e resistência, GBPUSD H1, intervalo de tempo a partir de 01/03/2014 a 01/05/2014

Fig. 7 Canal equidistante, linhas de suporte e resistência, GBPUSD H1, intervalo de tempo a partir de 01/03/2014 a 01/05/2014

Na Fig. 7 você pode ver que o canal equidistante descendente é desenhado em linhas vermelhas, o canal ascendente é desenhado em azul e as linhas de suporte e resistência são desenhadas em preto. Está claro que a primeira linha de resistência está se tornando uma linha de suporte.

3. Padrão de Velas

Um gráfico modificado (duas linhas de quebra) no prazo M30 para o par USDCAD no início de 2013 parece ser bem interessante.

Podemos distinguir os padrões de velas japonesas que justificaram seus sinais (fig. 8).

Fig. 8 Gráfico modificado "Ruptura de Três Linhas" USDCAD M30, a partir de 2013, duas linhas de quebra

Fig. 8 Gráfico modificado "Ruptura de Três Linhas" USDCAD M30, a partir de 2013, duas linhas de quebra

No início do gráfico, podemos ver um padrão de reversão de "Engolfo" sob №1. Ela consiste por duas velas: uma vermelha e uma precedente em azul. Após a linha de tendência de alta, o mercado vai para baixo para o número 2, que é um padrão de reversão de vela chamado "Martelo". Neste ponto, o mercado muda de direção. O mesmo acontece no padrão №3 ("Spinning Top"). O seguinte padrão de reversão "Kharami" (№4) é mostrado pela vela 4 e pela grande vela ascendente próximo a ele. O padrão №6 também é composto de duas velas (padrão "Engolfo"), mas ao contrário do primeiro modelo, ele ocorre no mercado na direção oposta.

Assim, pode-se concluir que a utilização do indicador neste tipo de análise é aceitável, mas possui desvantagens tais como ocorrência raras de sinais e a possibilidade de um rebaixamento significativo. Essa estratégia, certamente, precisa de mais desenvolvimento.

4. Média móvel

A modificação parcial como a adição de uma média móvel apenas para as linhas desenhadas nos fornece novas oportunidades para análise.

Vejamos a fig. 9:

Fig.9 Análise da média móvel, EURUSD H4, o gráfico "Ruptura de Três Linhas, construção clássica, a partir de 01.01.2014 a 01.07.2014

Fig.9 Análise da média móvel, EURUSD H4, o gráfico "Ruptura de Três Linhas, construção clássica, a partir de 01.01.2014 a 01.07.2014

A parte superior da fig. 9 ilustra uma construção clássica com base nos preços máximos com uma média móvel (período médio é de 90, mínima do preço, média suavizada). A parte inferior mostra uma construção clássica com base nos preços mínimos com uma média móvel (período médio é de 90, máxima do preço, média suavizada).

Assim, na parte superior da fig. 9 a média móvel pode ser considerada uma linha de suporte e, na parte inferior uma linha de resistência. Se o preço de ambos os gráficos cair abaixo da média, então há uma tendência de queda no mercado, sendo melhor fazer uma venda. Quando o preço sobe acima da média, está na hora de comprar. A desvantagem desta estratégia é que elé para negociações de longo prazo.


Conclusão

Em conclusão, podemos dizer que a "Ruptura de Três Linhas" fornece sempre bons sinais ou, no pior dos casos, nos leva a um equilíbrio. Na prática vemos que ele é melhor aplicado em uma tendência de longo prazo e, portanto, eu não recomendo usar este gráfico para uma negociação de curto prazo. Se alguém tiver novas idéias de como usá-lo na negociações, eu ficaria feliz em discutir o assunto.

Como sempre, eu tentei explorar o código em detalhe. Mais uma vez, se há idéias de como estender o assunto, retrabalho ou otimizá-lo, por favor, escreva nos comentários do artigo.


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

Arquivos anexados |
abctb.mq5 (68.78 KB)
Últimos Comentários | Ir para discussão (1)
Marcos Kronhardt
Marcos Kronhardt | 30 set 2014 em 20:39
Muito bom.
Como Preparar Sua Conta de Negociação para Migrar a Hospedagem Virtual Como Preparar Sua Conta de Negociação para Migrar a Hospedagem Virtual
O terminal cliente MetaTrader é perfeito para a automação de estratégias de negociação. Ele possui todas as ferramentas que os desenvolvedores de robôs de negociação necessitam - Uma poderosa linguagem de programação em MQL4 / MQL5, baseada em C++, um conveniente ambiente de desenvolvimento chamado MetaEditor e um testador de estratégia multi segmentado (multi-threaded) que suporta a computação distribuída MQL5 Cloud Network. Neste artigo, você irá descobrir como mover o seu terminal cliente para o ambiente virtual com todos os elementos personalizados.
Construindo uma Startup em Tecnologia Social, Parte II: Programando um cliente REST em MQL5 Construindo uma Startup em Tecnologia Social, Parte II: Programando um cliente REST em MQL5
Vamos agora dar forma a idéia do Twitter baseado em PHP que foi introduzido na primeira parte deste artigo. Nós estamos reunindo as diferentes partes do SDSS. Quanto a arquitetura do sistema pelo lado do cliente, nós estaremos contando com a nova função WebRequest() em MQL5 para o envio de sinais de negociação via HTTP.
Análise de Regressão da Influência dos Dados Macroeconômicos sobre a Flutuação nos Preços da Moeda Análise de Regressão da Influência dos Dados Macroeconômicos sobre a Flutuação nos Preços da Moeda
Este artigo considera a aplicação da análise de regressão múltipla com estatísticas macroeconômicas. Ele também nos dá uma visão sobre a avaliação dos impactos estatísticos sobre a flutuação da taxa de câmbio, utilizando como exemplo o par de moeda EURUSD. Essa avaliação permite automatizar a análise fundamental, tornando-se disponível até mesmo para os traders novatos.
Construindo uma Startup em Tecnologia Social, Parte I: Tuíte seus Sinais do MetaTrader 5 Construindo uma Startup em Tecnologia Social, Parte I: Tuíte seus Sinais do MetaTrader 5
Hoje vamos aprender a ligar um terminal MetaTrader 5 com o Twitter para que você possa "tuitar" os sinais de negociação de seus EAs. Estaremos desenvolvendo um Sistema de Apoio à Decisão Social em PHP com base no serviço web RESTful. Essa idéia vem de um conceito específico da negociação automatizada chamada de negociação assistida por computador. Nós queremos as habilidades cognitivas dos traders humanos para filtrar os sinais de negociação, que de outra maneira eles seriam colocadas automaticamente no mercado pelos Expert Advisors.