
Indicador para Construção do Gráfico "Ruptura de Três Linhas"
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)
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
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
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
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:
- Cálculo dos elementos do array, satisfazendo a condição de conter os dados de todos os quatro tipos de preços.
- Cópia dos elementos em um array intermediário sob a mesma condição.
- 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:
- 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.
- 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.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
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
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
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





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso