
Indicador para representação de gráfico Kagi
Introdução
O artigo "Indicador para traçar ponto e figura" descreveu uma da formas de programação de criação de Gráfico de ponto e figura. Este gráfico é conhecido desde o século 19. No entanto, este não é o único gráfico do passado distante. Outro representante notável dos primeiros tipos de representação do mercado financeiro é o Gráfico Kagi. Este gráfico será discutido no presente artigo.
A bolsa de valores - instituição financeira desconhecida para o século 19 no Japão - foi fundada em maio de 1878. É conhecida como a Bolsa de valores de Tokyo hoje em dia. Este evento teve um papel vital na criação e no posterior desenvolvimento de gráficos Kagi. A Europa e os EUA foram saber de gráficos Kagi após a publicação de Steve Nison "Beyond Candlesticks: New Japanese Charting Techniques Revealed" em 1994.
As palavras japonesas "Kagi" significam uma chave em forma de L que estava em uso no momento do desenvolvimento do gráfico. Além disso, há uma versão modificada do nome - "gráfico chave". Na publicação de Steve Nison de "Beyond Candlesticks", você também pode encontrar os nomes alternativos do gráfico: gráfico faixa de preço, gráfico gancho, gráfico delta ou cadeia.
O que é tão especial sobre este gráfico? Sua principal característica é que ele ignora a escala de tempo, deixando apenas a escala de preço (ao contrário dos gráficos de castiçais japoneses, barras e linhas). Assim, o gráfico esconde flutuações de preços insignificantes, deixando apenas os mais significativos.
O gráfico representa um conjunto de linhas espessas Yan e linhas finas Yin substituindo umas as outras, dependendo da situação do mercado. No caso do mercado se mover na mesma direção, a linha é estendida atingindo uma nova faixa de preço. No entanto, se o mercado girar para trás e atingir uma quantia predefinida, a linha Kagi é desenhada na direção oposta na coluna nova. A quantia predefinida é estabelecida tanto em pontos (geralmente usados para pares de moedas), ou em valor percentual do preço atual (normalmente usado para ações). A espessura da linha varia dependendo do avanço mais próximo de alta ou de baixa.
1. Exemplo de gráfico
Vamos usar dados do histórico no EURUSD, H1 de 8 a 11 de outubro.
Um exemplo de imagens padrão com limiar inversa de 15 pontos é exibida na fig. 1:
Fig. 1. Gráfico Kagi, EURUSD H1
Como podemos ver, o preço começou a cair as 17:00 horas. O movimento de queda continuou até as 21:00 horas. As 22:00 horas, o preço subiu de 1.3566 e é fechado em 1.3574. Em outras palavras, o preço passa de 11 pontos. Isso não é suficiente para uma inversão, mas a nova baixa não foi atingida também. As próximas duas horas, o preço vai ficar invariável e finalmente, a 01:00 hora (09 de outubro), vemos um forte movimento ascendente, que se fechou em 1.3591 englobando 25 pontos (1.3591-1.3566). Isto significa que o preço inverteu-se.
A tendência de alta continua na hora seguinte. O preço chega a 1.3599 reforçando a linha espessa Yang. As 03:00 horas, o preço cai drasticamente fechando em 1.3578, que é 21 pontos da alta anterior (1.3599-1.3578). Isso é mais do que suficiente para a inversão. A linha se move para baixo, mas mantém a sua forma (linha espessa Yang).
Até as 16:00 horas, o preço cai e, finalmente, rompe o mínimo mais próximo e muda da linha espessa de Yang para a linha fina de Yin. O baixo valor mencionado anteriormente de 1.3566 serviu como um preço imbatível aqui. O preço continua movendo-se como uma linha de Yin e é alterado para Yang as 14:00 horas em 10 de outubro, rompendo a alta mais próxima de 1.3524 formada as 23:00 horas (9 de outubro). Este pequeno exemplo mostra como o gráfico Kagi é formado.
2. Princípio de gráfico indicador Kagi
A fim de tornar o indicador independente do período de tempo atual, foi decidido copiar os dados do período de tempo, em que o indicador foi supostamente formado de forma separada e depois criar o indicador usando os dados obtidos.
Isso permite examinar vários prazos de tempo simultaneamente em um único gráfico expandindo os limites da análise técnica sobre gráficos Kagi. O indicador em si está localizado numa janela separada, mas também é possível visualizar os dados do gráfico principal. Em outras palavras, a formação de base (padrão ou modificado) é realizada na janela indicadora. O indicador é copiado para o gráfico principal, assim como os preços e as marcas de tempo (dependendo das configurações) são desenhados.
Como mencionado anteriormente, o indicador desenha o gráfico tanto na versão padrão como na modificada. A versão padrão foi descrita acima. Agora, vamos considerar a versão modificada.
Eu não sei se é uma ideia nova, mas eu não ouvi falar de tal versão. A ideia do filtro adicional é que não só reverte pontos, mas cada movimento do gráfico é agora filtrado. Em outras palavras, o preço deve mover uma certa distância especificada para que a nova alta ou baixa (não confundir com o ombro/cintura) seja formada. Em geral, sempre que o preço se move, ele deve primeiro cobrir uma distância especificada. Depois disso, ele é definido como se fosse uma continuação de tendência ou uma inversão.
A fig. 2 mostra como os princípios funcionam. O visual do gráfico modificado é mostrado em azul, enquanto o padrão - em vermelho. Como podemos ver, o visual modificado responde às alterações do movimento de preço, filtrando lentamente a maioria dos sinais menores.
Fig. 2. As versões modificada (linha azul) e padrão (linha vermelha) de criação de gráfico Kagi
Além do gráfico Kagi, o indicador fornece alguns elementos adicionais, tanto na janela do indicador como no gráfico principal.
Dependendo das configurações, as marcas podem ser definidas na janela do indicador. Estas marcas fornecem dados sobre preços de inversão. A mesma função é realizada através de níveis de preços, o que (dependendo das configurações) pode distribuir uniformemente ao longo da janela em toda a faixa de preço utilizado para a formação do indicador ou a cada inversão do gráfico. As cores podem ser definidas em três versões: de acordo com o tipo de inversão (para cima - para baixo), tipo de linha (Yin - Yang) ou sem mudança de cor.
As marcas de preço de inversão, incluindo as temporárias, são fornecidas no gráfico principal. Estas marcas (dependendo das configurações) podem ser de uma única cor ou mudar a cor de acordo com as cores das linhas de Yin ou Yang.
O código indicador inteiro é implementado usando as funções de comunicação umas com as outras através de variáveis globais.
O código pode ser dividido em três funções principais e outras onze adicionais. A principal dificuldade dos cálculos e preenchimentos de buffer de construções gráficas básicas e de matrizes adicionais é apoiar-se na função da formação do gráfico Kagi na janela indicadora. As outras duas funções são responsáveis por fornecer os dados: a primeira copia os dados de tempo, enquanto a outra - os dados sobre os preços de cada barra do período de tempo selecionado.
As funções auxiliares restantes são responsáveis por executar todas as construções, excluir os objetos, descarregar o indicador acompanhado pela exclusão de todos os objetos do indicador, cálculo de parâmetros de inversão, desenhar marcas no gráfico principal e na janela indicadora, criar objetos gráficos do tipo "linha de tendência", desenhar Kagi no gráfico principal, bem como definir a chegada da nova barra para iniciar a formação do indicador.
3. Código e algoritmo indicador
Agora, vamos examinar o código e o algoritmo indicador da sua formação em detalhes. O código é muito grande e pode ser bem difícil para programadores iniciantes compreendê-lo. As funções se comunicam umas com as outras através de variáveis globais tornando o código um pouco confuso. Nesta parte do artigo, explicarei cada função e parte do código separadamente. Primeiro, descreverei as configurações do indicador e, em seguida, haverá esclarecimentos sobre funções iniciais de cópia de dados, cálculo de parâmetros de inversão, função principal da formação e cálculo de gráfico Kagi e outras funções auxiliares.
3.1. Parâmetros de entrada do indicador
O código começa com a declaração do indicador em uma janela separada, bem como de 12 buffers e de 8 construções gráficas de indicador. Primeiro de tudo, vamos definir o porquê de construções gráficas, incluindo dois "histogramas" e seis "linhas", terem sido usadas. Cada "histograma" constrói sua própria linha vertical. Uma das linhas é responsável pela linha Yin, enquanto que a outra para linha Yang.
O caso é um pouco mais complicado com as "linhas", uma vez que existem três delas para cada linha. Isto é feito devido ao fato de que a linha é desenhada caso haja um outro ponto desenhado perto do primeiro. Em outras palavras, precisamos de apenas duas construções de gráfico do tipo "linha"a serem rodados para desenhar duas linhas adjacentes umas às outras. No entanto, se vamos precisar omitir pontos necessários, temos a terceira construção a ser rodada com mais outras duas.
Isso é explicado na Figura 3, onde você pode ver o que acontece, se apenas duas construções de gráfico do tipo "linha" forem usadas:
Fig. 3. Exemplo do uso de duas construções de gráfico do tipo "linha"para exibir linhas de ombro e cintura.
Em seguida, o menu de configurações é criado. Há cinco enumerações aqui (vamos examiná-las nos parâmetros de entrada).
A primeira entrada de parâmetro "período" é um período em que a construção é realizada, ela é seguida por "period_to_redraw" - período de atualização da construção de gráfico e o último parâmetro é "start_data" - o início da construção do tempo.
Esses parâmetros são seguidos por construção de gráfico e por parâmetros de etiquetagem adicional:
- kagi_type - tipo de construção de gráfico definido pelo usuário, padrão ou modificado;
- price_type - tipo do preço usado para a construção: Fechado, aberto, alta e baixa;
- type_doorstep - tipo inversão usado: ponto e porcentagem;
- doorstep - valor de inversão (especificado em pontos ou valor em porcentagem, dependendo do parâmetro acima);
- color_yin - cor da linha Yin na janela indicadora;
- color_yang - cor da linha Yang na janela indicadora;
- width_yin - largura da linha Yin na janela indicadora;
- width_yang - largura da linha Yang na janela indicadora;
- levels_on_off - caso níveis de preço devam ser desenhados na janela indicadora;
- levels_type - tipos de níveis de preços na janela indicadora. Existem dois valores para escolher: a cada inversão ou através da taxa de preço de forma uniforme;
- levels_number - número de níveis de preço na janela indicadora;
- levels_change_color - permite alterar a cor das linhas do nível de preços, as opções são reversões superiores e inferiores, linhas Yin e Yang ou nenhuma alteração;
- levels_first_color - a primeira cor de um nível de preço;
- levels_second_color - a segunda cor de um nível de preço;
- label_1 - etiquetas de preço de inversão de gráfico de desenho na janela indicadora;
- label_1_number - número de etiquetas exibido na janela indicadora;
- label_1_color – cor das etiquetas de preço na janela indicadora;
- label_2 - etiquetas de preço de desenho no gráfico principal;
- label_2_color - cor da etiqueta no gráfico principal;
- time_line_draw - linhas de tempo de inversão de desenho no gráfico principal;
- time_separate_windows - continuação de desenho de linhas de tempo de inversão a partir do gráfico principal;
- time_line_change_color - mudança de cor da linha do tempo de acordo com a etiqueta de inversão na linha Yin ou Yang;
- time_first_color - a primeira cor da linha do tempo no gráfico principal;
- time_second_color - a segunda cor da linha do tempo no gráfico principal;
- kagi_main_chart - se Kagi deve ser desenhado no gráfico principal;
- color_yin_main - cor da linha Yin no gráfico principal;
- color_yang_main - cor da linha Yang no gráfico principal;
- width_yin_main - largura da linha Yin no gráfico principal;
- width_yang_main - largura da linha Yang no gráfico principal;
- magic_numb - número mágico utilizado para a construção de objetos e sua exclusão, bem como no nome indicador, a fim de iniciar vários indicadores em um único gráfico.
Estes parâmetros são, por sua vez seguidos por declarações dos buffers indicadores, buffers auxiliares para armazenar preços e valores de tempo, variáveis auxiliares (stop_data, bars_copied, bars_copied_time, copy_history, copy_time), matrizes de armazenamento de dados nas quais as linha Yin ou Yang marcam a mudança do movimento de gráfico que ocorreu, o tempo e o preço dessa mudança, o preço central (se Yin é substituído por Yang na barra ou vice- versa). Finalmente, uma das variáveis globais mais utilizadas que contenham dados sobre o número de alterações de movimento do gráfico "а" é declarada.
//+------------------------------------------------------------------+ //| BKCV.mq5 | //| Azotskiy Aktiniy ICQ:695710750 | //| https://www.mql5.com/pt/users/Aktiniy | //+------------------------------------------------------------------+ //--- Build Kagi Chart Variable #property copyright "Azotskiy Aktiniy ICQ:695710750" #property link "https://www.mql5.com/pt/users/Aktiniy" #property version "1.00" #property description "Build Kagi Chart Variable" #property description " " #property description "This indicator makes drawing a chart Kagi as a matter of indicator window, and in the main chart window" #property indicator_separate_window #property indicator_buffers 12 #property indicator_plots 8 //--- plot Yin #property indicator_label1 "Yin" #property indicator_type1 DRAW_HISTOGRAM2 #property indicator_color1 clrRed #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot Yin1 #property indicator_label2 "Yin1" #property indicator_type2 DRAW_LINE #property indicator_color2 clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- plot Yin2 #property indicator_label3 "Yin2" #property indicator_type3 DRAW_LINE #property indicator_color3 clrRed #property indicator_style3 STYLE_SOLID #property indicator_width3 1 //--- plot Yin3 #property indicator_label4 "Yin3" #property indicator_type4 DRAW_LINE #property indicator_color4 clrRed #property indicator_style4 STYLE_SOLID #property indicator_width4 1 //--- plot Yang #property indicator_label5 "Yang" #property indicator_type5 DRAW_HISTOGRAM2 #property indicator_color5 clrRed #property indicator_style5 STYLE_SOLID #property indicator_width5 2 //--- plot Yang1 #property indicator_label6 "Yang1" #property indicator_type6 DRAW_LINE #property indicator_color6 clrRed #property indicator_style6 STYLE_SOLID #property indicator_width6 2 //--- plot Yang2 #property indicator_label7 "Yang2" #property indicator_type7 DRAW_LINE #property indicator_color7 clrRed #property indicator_style7 STYLE_SOLID #property indicator_width7 2 //--- plot Yang3 #property indicator_label8 "Yang3" #property indicator_type8 DRAW_LINE #property indicator_color8 clrRed #property indicator_style8 STYLE_SOLID #property indicator_width8 2 //--- Enumerations as input data (for more attractive setting) //--- Kagi charting type enum kagi_type_enum { classic=0, // Classic modified=1, // Modified }; //--- Type of the price used for construction enum price_type_enum { c=0, // Close o=1, // Open h=2, // High l=3, // Low }; //--- Type of the used reversal enum type_doorstep_enum { point=0, // Point procent=1, // Percent }; //--- Type of levels location enum levels_type_enum { cor=0, // Cornering equ=1, // Equal distance }; //--- Level colors change type (works when "Type of levels location"="Cornering") enum levels_change_color_enum { up_down=0, // Up & Down yin_yang=1, // Yin & Yang no=2, // Don't change }; //--- input parameters input ENUM_TIMEFRAMES period=PERIOD_CURRENT; // Calculation period to build the chart input ENUM_TIMEFRAMES period_to_redraw=PERIOD_M1; // Refresh period chart input datetime start_data=D'2013.07.10 00:00:00'; // Start time to build the chart input kagi_type_enum kagi_type=classic; // The type to build Kagi chart input price_type_enum price_type=c; // Price used to build chart input type_doorstep_enum type_doorstep=point; // Type calculate doorstep input double doorstep=25; // Doorstep reversal input color color_yin=clrRed; // Color Yin line (indicator window) input color color_yang=clrRed; // Color Yang line (indicator window) input char width_yin=1; // Width Yin line (indicator window) input char width_yang=2; // Width Yang line (indicator window) input bool levels_on_off=false; // Draw level (indicator window) input levels_type_enum levels_type=cor; // Type of drawing levels (indicator window) input uint levels_number=6; // Number of levels (indicator window) input levels_change_color_enum levels_change_color=up_down; // Type change color of levels (indicator window) input color levels_first_color=clrBeige; // The first color of level (indicator window) input color levels_second_color=clrCoral; // The second color of level (indicator window) input bool label_1=true; // Draw price label on (indicator window) input uint label_1_number=10; // The number of labels (indicator window) input color label_1_color=clrGreenYellow; // The color of labels (indicator window) input bool label_2=true; // Draw price label on (main chart) input color label_2_color=clrGreenYellow; // The color of labels (main chart) input bool time_line_draw=true; // Draw a timeline reversal (main chart) input bool time_separate_windows=false; // Draw a timeline reversal on indicator window input bool time_line_change_color=true; // Different color timeline on the Yin and Yang lines (main chart) input color time_first_color=clrRed; // The first color of timeline (main chart) input color time_second_color=clrGreenYellow; // The second color of timeline (main chart) input bool kagi_main_chart=true; // Draw Kagi on main chart (main chart) input color color_yin_main=clrRed; // Color Yin line (main chart) input color color_yang_main=clrRed; // Color Yang line (main chart) input char width_yin_main=1; // Width Yin line (main chart) input char width_yang_main=2; // Width Yang line (main chart) input long magic_numb=65758473787389; // The magic number for drawing objects //--- indicator buffers double YinBuffer1[]; double YinBuffer2[]; double Yin1Buffer[]; double Yin2Buffer[]; double Yin3Buffer[]; double YangBuffer1[]; double YangBuffer2[]; double Yang1Buffer[]; double Yang2Buffer[]; double Yang3Buffer[]; //--- additional variables double Price[]; // Buffer for storing the copied price data double Time[]; // Buffer for storing the copied time data //--- datetime stop_data; // Current time int bars_copied=0; // Number of the already copied bars from the initial date int bars_copied_time; // Number of the already copied bars having the initial date bool copy_history=false; // Price history copying result bool copy_time=false; // Time history copying result //--- datetime time_change[]; // Array for writing the time when the chart movement started changing (up or down) char time_line[]; // Array for storing the data on what line (Yin=0 or Yang=1) direction has changed double time_change_price[]; // Array for writing the chart movement change price double time_central_price[]; // Array for writing the average price during the chart movement change uint a=0; // Variable for building the chart, number of chart reversals is fixed
3.2. Função de inicialização do indicador
A próxima é a função de inicialização do indicador. Os buffers indicadores e a sua correção de índice (principalmente como períodos de tempo, pois o gráfico Kagi é menor do que a principal, é melhor desenhá-lo de trás para frente) são especificados lá. Além disso, os valores que não devem ser exibidos na tela são definidos (EMPTY_VALUE=-1).
Agora, atribuímos o nome de indicador e precisão da tela. Como mencionado anteriormente, o número mágico é adicionado ao nome. Isto é feito para proporcionar a correta operação da função ChartWindowFind(). Caso contrário, o objeto gráfico desenhado na janela indicadora é exibido apenas no primeiro indicador iniciado (se vários indicadores em um único gráfico são usados).
Em seguida, atribuímos nomes às linhas de construção, proibimos a exibição dos valores numéricos atuais na janela indicadora, definimos a cor e a largura das linhas Yin e Yang, definimos o número de níveis de preço exibidos na janela do indicador.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,YinBuffer1,INDICATOR_DATA); ArraySetAsSeries(YinBuffer1,true); SetIndexBuffer(1,YinBuffer2,INDICATOR_DATA); ArraySetAsSeries(YinBuffer2,true); SetIndexBuffer(2,Yin1Buffer,INDICATOR_DATA); ArraySetAsSeries(Yin1Buffer,true); SetIndexBuffer(3,Yin2Buffer,INDICATOR_DATA); ArraySetAsSeries(Yin2Buffer,true); SetIndexBuffer(4,Yin3Buffer,INDICATOR_DATA); ArraySetAsSeries(Yin3Buffer,true); //--- SetIndexBuffer(5,YangBuffer1,INDICATOR_DATA); ArraySetAsSeries(YangBuffer1,true); SetIndexBuffer(6,YangBuffer2,INDICATOR_DATA); ArraySetAsSeries(YangBuffer2,true); SetIndexBuffer(7,Yang1Buffer,INDICATOR_DATA); ArraySetAsSeries(Yang1Buffer,true); SetIndexBuffer(8,Yang2Buffer,INDICATOR_DATA); ArraySetAsSeries(Yang2Buffer,true); SetIndexBuffer(9,Yang3Buffer,INDICATOR_DATA); ArraySetAsSeries(Yang3Buffer,true); //--- add the buffer for copying data on prices for calculation SetIndexBuffer(10,Price,INDICATOR_CALCULATIONS); //--- add the buffer for copying data on bar open time for construction SetIndexBuffer(11,Time,INDICATOR_CALCULATIONS); //--- set what values are not to be drawn for(char x=0; x<8; x++) { PlotIndexSetDouble(x,PLOT_EMPTY_VALUE,-1); } //--- set the indicator's look IndicatorSetString(INDICATOR_SHORTNAME,"BKCV "+IntegerToString(magic_numb)); // Indicator name IndicatorSetInteger(INDICATOR_DIGITS,_Digits); // Display accuracy //--- assign names to graphical constructions PlotIndexSetString(0,PLOT_LABEL,"Yin"); PlotIndexSetString(1,PLOT_LABEL,"Yin"); PlotIndexSetString(2,PLOT_LABEL,"Yin"); PlotIndexSetString(3,PLOT_LABEL,"Yin"); PlotIndexSetString(4,PLOT_LABEL,"Yang"); PlotIndexSetString(5,PLOT_LABEL,"Yang"); PlotIndexSetString(6,PLOT_LABEL,"Yang"); PlotIndexSetString(7,PLOT_LABEL,"Yang"); //--- prohibit display of the results of the current values for graphical constructions PlotIndexSetInteger(0,PLOT_SHOW_DATA,false); PlotIndexSetInteger(1,PLOT_SHOW_DATA,false); PlotIndexSetInteger(2,PLOT_SHOW_DATA,false); PlotIndexSetInteger(3,PLOT_SHOW_DATA,false); PlotIndexSetInteger(4,PLOT_SHOW_DATA,false); PlotIndexSetInteger(5,PLOT_SHOW_DATA,false); PlotIndexSetInteger(6,PLOT_SHOW_DATA,false); PlotIndexSetInteger(7,PLOT_SHOW_DATA,false); //--- set color for Yin line PlotIndexSetInteger(0,PLOT_LINE_COLOR,color_yin); PlotIndexSetInteger(1,PLOT_LINE_COLOR,color_yin); PlotIndexSetInteger(2,PLOT_LINE_COLOR,color_yin); PlotIndexSetInteger(3,PLOT_LINE_COLOR,color_yin); //--- set color for Yang line PlotIndexSetInteger(4,PLOT_LINE_COLOR,color_yang); PlotIndexSetInteger(5,PLOT_LINE_COLOR,color_yang); PlotIndexSetInteger(6,PLOT_LINE_COLOR,color_yang); PlotIndexSetInteger(7,PLOT_LINE_COLOR,color_yang); //--- set Yin line width PlotIndexSetInteger(0,PLOT_LINE_WIDTH,width_yin); PlotIndexSetInteger(1,PLOT_LINE_WIDTH,width_yin); PlotIndexSetInteger(2,PLOT_LINE_WIDTH,width_yin); PlotIndexSetInteger(3,PLOT_LINE_WIDTH,width_yin); //--- set Yang line width PlotIndexSetInteger(4,PLOT_LINE_WIDTH,width_yang); PlotIndexSetInteger(5,PLOT_LINE_WIDTH,width_yang); PlotIndexSetInteger(6,PLOT_LINE_WIDTH,width_yang); PlotIndexSetInteger(7,PLOT_LINE_WIDTH,width_yang); //--- set the number of levels in the indicator window IndicatorSetInteger(INDICATOR_LEVELS,levels_number); //--- return(INIT_SUCCEEDED); }
3.3. Função de cópia de dados
Agora vamos examinar as funções de cópia de dados.
Há duas delas aqui. A primeira é para copiar os preços, enquanto que a segunda é para copiar tempo aberto de cada barra. Ambas as funções mantêm seus valores em buffers de cálculo do indicador previamente declarado.
Primeiro, vamos considerar a função de cópia de preço. Parâmetros de entrada de função: a matriz para armazenamento de dados, início de término da cópia de dados (tempo atual). O corpo da função contém as variáveis de resposta para a função, o número de dados (barras) copiados à matriz intermediária, a própria matriz dinâmica intermediária e o número de barras que devem ser copiadas à matriz intermediária. O número de barras é calculado com base no número total de barras no período de tempo determinado e no número de barras (variável global) copiadas na chamada da função anterior.
Se não for a primeira vez que os dados foram copiados, os dados sobre a última barra copiada devem ser atualizados. Para fazer isso, reduzimos o número de barras copiadas por um e aumentamos o número de barras recém copiadas por um. Mudamos também o tamanho da matriz intermediária preparando-a para copiar as barras.
Dependendo das configurações, copiamos os preços para a matriz intermediária. Se a cópia for bem sucedida, os dados são copiados da matriz intermediária para o fim da matriz de buffer (matriz de resposta da função), atribuímos a resposta positiva à função e atualizamos a variável global armazenando os dados sobre o número de barras copiadas. Este tipo de cópia permite copiar apenas algumas últimas barras reduzindo o tempo de cópia.
//+------------------------------------------------------------------+ //| Func Copy History | //+------------------------------------------------------------------+ bool func_copy_history(double &result_array[], datetime data_start, datetime data_stop) { //--- int x=false; // Variable for answer int result_copy=-1; // Number of copied data static double price_interim[]; // Temporary dynamic array for storing copied data static int bars_to_copy; // Number of bars for copying bars_to_copy=Bars(_Symbol,period,data_start,data_stop); // Find out the current number of bars on the time interval bars_to_copy-=bars_copied; // Calculate the number of bars to be copied if(bars_copied!=0) // If it is not the first time the data has been copied { bars_copied--; bars_to_copy++; } ArrayResize(price_interim,bars_to_copy); // Change the size of the receiving array switch(price_type) { case 0: result_copy=CopyClose(_Symbol,period,0,bars_to_copy,price_interim); break; case 1: result_copy=CopyOpen(_Symbol,period,0,bars_to_copy,price_interim); break; case 2: result_copy=CopyHigh(_Symbol,period,0,bars_to_copy,price_interim); break; case 3: result_copy=CopyLow(_Symbol,period,0,bars_to_copy,price_interim); break; } if(result_copy!=-1) // If copying to the intermediate array is successful { ArrayCopy(result_array,price_interim,bars_copied,0,WHOLE_ARRAY); // Copy the data from the temporary array to the main one x=true; // assign the positive answer to the function bars_copied+=result_copy; // Increase the value of the processed data } //--- return(x); }
A próxima função é que é a correta para copiar os dados de tempo. É diferente da anterior em que se trata de um outro tipo de variável - datetime (que é convertida ao dobro quando copiadas para matriz de buffer de tempo - matriz de resposta de função). Uma outra diferença é que a declaração switch() não é utilizada, como não há necessidade alguma de selecionar os dados copiados.
//+------------------------------------------------------------------+ //| Func Copy Time | //+------------------------------------------------------------------+ bool func_copy_time(double &result_array[], datetime data_start, datetime data_stop) { //--- int x=false; // Variable for answer int result_copy=-1; // Number of copied data static datetime time_interim[]; // Temporary dynamic array for storing copied data static int bars_to_copy_time; // Number of bars for copying bars_to_copy_time=Bars(_Symbol,period,data_start,data_stop); // Find out the current number of bars on the time interval bars_to_copy_time-=bars_copied_time; // Calculate the number of bars to be copied if(bars_copied_time!=0) // If it is not the first time the data has been copied { bars_copied_time--; bars_to_copy_time++; } ArrayResize(time_interim,bars_to_copy_time); // Change the size of the receiving array result_copy=CopyTime(_Symbol,period,0,bars_to_copy_time,time_interim); if(result_copy!=-1) // If copying to the intermediate array is successful { ArrayCopy(result_array,time_interim,bars_copied_time,0,WHOLE_ARRAY); // Copy the data from the temporary array to the main one x=true; // assign the positive answer to the function bars_copied_time+=result_copy; // Increase the value of the processed data } //--- return(x); }
3.4. Função de cálculo de parâmetro de inversão
Uma vez que o parâmetro de inversão pode ser um ponto ou uma porcentagem um, precisamos da função que calculará o parâmetro de inversão, dependendo das definições de indicadores. A função tem apenas um parâmetro - o preço para o cálculo do percentual de inversão A variável para a resposta é primeiro inicializada pelo tipo duplo e após os cálculos, é convertida indiretamente para o tipo int para resposta.
Isso é feito porque os números de ponto flutuante são usados nos cálculos, enquanto a resposta deve ser apresentada como números inteiros. A seleção é implementada na função pela declaração condicional if-else. A comparação é desempenhada diretamente com a variável externa input (parâmetros indicadores). O cálculo dos pontos é realizado usando uma equação simples. Em primeiro lugar, é definido o número total de pontos que o preço passou. Em seguida, a porcentagem indicada é calculada com base nesse número e atribuída à variável devolvida.
//+------------------------------------------------------------------+ //| Func Calculate Doorstep | //+------------------------------------------------------------------+ int func_calc_dorstep(double price) { double x=0; // Variable for answer if(type_doorstep==0) // If the calculation is to be performed in points { x=doorstep; } if(type_doorstep==1) // If the calculation is to be performed in percentage { x=price/_Point*doorstep/100; } return((int)x); }
3.5. A função principal - Desenho de gráfico Kagi
Já examinamos todas as funções que são necessárias para a operação da função principal - desenho de gráfico Kagi na janela indicadora (ou seja, o preenchimento dos buffers indicadores). Os parâmetros de entrada da função consistem de matrizes de dados. Duas delas são os buffers de cálculo descritos acima (preço e tempo previamente copiados), todo o resto são as matrizes dos buffers de construção gráfica de indicador.
As variáveis necessárias para armazenar os dados sobre a construção do gráfico são declaradas dentro da função. Uma vez que o gráfico é construído utilizando a declaração for loop, devemos ter os dados no estágio que terminou a etapa anterior. Isto pode ser conseguido por seis variáveis: line_move - onde o preço moveu-se na etapa anterior, line_gauge - line calibre (espessura da linha) - Yin ou Yang, price_1 e price_2 - preço anterior e atual que está sendo considerado, price_down e price_up - preço anterior de um ombro e cintura. Como podemos ver, price_1 é imediatamente equiparado ao primeiro elemento da matriz de preços copiados devido ao fato de que esta variável está envolvida em cálculos antes de comparação desde o início do ciclo.
Uma vez que matrizes de buffers da construção gráfica do indicador tenham a bandeira de correção de índice AS_SERIES elas devem ser preenchidas na ordem inversa. Para conseguir isso, as matrizes que têm o tempo e o tamanho apropriados são implementadas. As variáveis globais para armazenar os dados em tempo, tipos de linhas, "ombro" e "cintura", bem como os preços de inversão são então convertidas da mesma maneira.
Em seguida, todas as matrizes devem ser preenchidas com valores "vazios" (-1). Isso é feito utilizando dois ciclos pequenos. É possível juntar tudo em um único ciclo. Mas o uso de dois torna todas as ações executadas muito mais claras, enquanto que o tempo de execução não é muito alterado. Em outras palavras, as matrizes de tempo de cálculo e buffers gráficos são preenchidos separadamente.
Agora, todas as variáveis são declaradas, convertidas e preenchidas, para que o ciclo principal possa ser iniciado. É muito grande (apesar de que o cálculo é realizado com bastante rapidez) e inclui digitalização de todas as barras previamente copiadas.
O ciclo passa por todas as barras copiadas e preenche as matrizes previamente declaradas necessárias para trabalhar com elas ainda mais. Primeiro, vamos definir todas as matrizes usadas no ciclo:
- yin_int_1 - valor principal de preço da linha Yin vertical (se linha Yin vertical é desenhada e o gráfico se move para baixo, este é o valor superior do preço, se o gráfico se move para cima, temos o caso oposto);
- yin_int_2 - valor secundário de preço de linha Yin vertical, (se a linha ascendente é desenhada, este é o valor superior, se a linha for para baixo, temos o caso oposto);
- yang_int_1 - valor principal do preço da linha Yang vertical;
- yang_int_2 - valor secundário de preço de linha Yang vertical;
- lin_yin - valor de linha Yin horizontal (preço de inversão na linha Yin);
- lin_yang - valor da linha Yang horizontal (preço de inversão na linha Yang);
- time_change - tempo de inversão do gráfico (construção de um ombro ou uma cintura);
- time_line - a linha durante inversão Yin = 0 ou Yang = 1;
- time_central_price - o valor do preço central, o preço no momento em que a linha Yin torna-se Yang, ou vice-versa;
- time_change_price - o valor de preço de inversão (ombro ou cintura), a variável é a comum não dependendo de tipos de linha Yin ou Yang.
O valor do preço atual analisado atuala partir do buffer de preço é atribuído à variável price_2 antes de cada passagem de ciclo para posterior comparação em declarações condicionais if-else. Depois disso, a matriz de buffer de dados copiados será analisada passo a passo e as matrizes acima referidas são preenchidas. Cada declaração condicional if-else executa certas ações, dependendo das condições: direção anterior de linhas de gráfico (para cima ou para baixo) e visual anterior das linhas (Yin ou Yang). Em seguida, as condições de movimento (se o preço passou um certo número de pontos) são verificadas em função do tipo de construção (padrão ou modificada).
Se tudo estiver bem, as novas variáveis (elementos da matriz) são reinstaladas ou definidas. O tipo de linha (Yin ou Yang) é definida no início. Dependendo do movimento e das ações anteriores, a distribuição posterior é realizada.
Há dois possíveis movimentos de preço:
- Preço sobe;
- Preço cai.
Há também quatro tipos de ações anteriores em cada direção:
- A linha anterior era Yin e subiu;
- A linha anterior era Yan e subiu;
- A linha anterior era Yin e caiu;
- A linha anterior era Yan e caiu.
Assim, temos oito casos além das duas primeiras definições de movimento inicial do gráfico (aparência primeira linha).
Depois disso, o ciclo principal termina. A reinstalação (inversa) e o preenchimento dos buffers são realizados para construir o gráfico em um pequeno ciclo consiste no número de inversões de gráfico Kagi previamente definidas no ciclo principal e escritas em variável "a". Quanto à distribuição dos valores de preços superiores e inferiores e linhas verticais, é tudo muito simples: uma inversão simples é executada. Em outras palavras, os valores primários obtidos anteriormente (matrizes tendo índices 0,1,2,3...) são atribuídos aos valores finais dos buffers (elemento com índice "а", por exemplo, а, а-1, а-2, а-3 ... é utilizado como um valor final). Para prevenir linhas (horizontais) de inversão de grudarem umas nas outras, o giro usando a declaração switch é executado como mencionado acima.
Fora isso, o trabalho da função principal da construção do gráfico Kagi está completo.
//+------------------------------------------------------------------+ //| Func Draw Kagi | //+------------------------------------------------------------------+ void func_draw_kagi(double &array_input[], double &arr_yin_1[], double &arr_yin_2[], double &arr_yin_lin1[], double &arr_yin_lin2[], double &arr_yin_lin3[], double &arr_yang_1[], double &arr_yang_2[], double &arr_yang_lin1[], double &arr_yang_lin2[], double &arr_yang_lin3[], double &arr_time[]) { //--- a=0; // Variable for the chart construction fixing the number of chart reversals char line_move=0; // Previous price direction 1-up, -1-down char line_gauge=0; // Previous look of the line 1-thick yang, -1-thin yin double price_1=0,price_2=0; // Auxiliary variables for defining the price movement double price_down=-99999,price_up=99999; // Auxiliary variables for storing the reversal price values price_1=array_input[0]; //--- auxiliary arrays for the initial data storing before the reversal (transferring to the buffers) double yin_int_1[]; double yin_int_2[]; double lin_yin[]; double yang_int_1[]; double yang_int_2[]; double lin_yang[]; //--- change the sizes of dynamic arrays ArrayResize(yin_int_1,bars_copied); ArrayResize(yin_int_2,bars_copied); ArrayResize(yang_int_1,bars_copied); ArrayResize(yang_int_2,bars_copied); ArrayResize(lin_yin,bars_copied); ArrayResize(lin_yang,bars_copied); //--- time data storing arrays ArrayResize(time_change,bars_copied_time); ArrayResize(time_line,bars_copied_time); // Look of the line Yin = 0 or Yang = 1 ArrayResize(time_change_price,bars_copied_time); ArrayResize(time_central_price,bars_copied_time); //--- assign -1 (not displayed) value to the transferred buffers for(int z=0; z<bars_copied; z++) { arr_yin_1[z]=-1; arr_yin_2[z]=-1; arr_yin_lin1[z]=-1; arr_yin_lin2[z]=-1; arr_yin_lin3[z]=-1; arr_yang_1[z]=-1; arr_yang_2[z]=-1; arr_yang_lin1[z]=-1; arr_yang_lin2[z]=-1; arr_yang_lin3[z]=-1; } //--- equate -1 (not displayed) value to the arrays for(int z=0; z<bars_copied; z++) { yin_int_1[z]=-1; yin_int_2[z]=-1; lin_yin[z]=-1; yang_int_1[z]=-1; yang_int_2[z]=-1; lin_yang[z]=-1; time_change[z]=-1; time_line[z]=-1; time_change_price[z]=-1; time_central_price[z]=-1; } //--- function's main loop for(int z=0; z<bars_copied; z++) { price_2=array_input[z]; //--- first, let's define the initial market direction //--- first THIN DESCENDING line if(((price_1-price_2)/_Point>func_calc_dorstep(price_2)) && line_move==0) { yin_int_1[a]=price_1; yin_int_2[a]=price_2; line_move=-1; line_gauge=-1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=0; } //--- first THICK ASCENDING line if(((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) && line_move==0) { yang_int_1[a]=price_1; yang_int_2[a]=price_2; line_move=1; line_gauge=1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=1; } //--- price moves DOWN //--- if the price moved DOWN before that, the line is THIN if(line_move==-1 && line_gauge==-1) { if(((price_1-price_2)/_Point>func_calc_dorstep(price_2)) || (kagi_type==0 && (price_1-price_2)/_Point>0)) { yin_int_2[a]=price_2; line_move=-1; line_gauge=-1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=0; } } //--- if the price moved DOWN before that, the line is THICK if(line_move==-1 && line_gauge==1) { if(((price_1-price_2)/_Point>func_calc_dorstep(price_2)) || (kagi_type==0 && (price_1-price_2)/_Point>0)) { if(price_2<price_down) // If the thick line crossed the lower shoulder when moving downwards { yin_int_1[a]=price_down; yin_int_2[a]=price_2; yang_int_2[a]=price_down; line_move=-1; line_gauge=-1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_central_price[a]=price_down; time_line[a]=0; } else //if(price_2>=price_down) // If the thick line has not crossed the lower shoulder when moving downwards { yang_int_2[a]=price_2; line_move=-1; line_gauge=1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=1; } } } //--- if the price has moved UPWARDS before that, the line is THIN if(line_move==1 && line_gauge==-1) { if((price_1-price_2)/_Point>func_calc_dorstep(price_2)) { a++; yin_int_1[a]=price_1; yin_int_2[a]=price_2; lin_yin[a]=price_1; line_move=-1; line_gauge=-1; price_up=price_1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=0; time_change_price[a]=lin_yin[a]; } } //--- if the price has moved UPWARDS before that, the line is THICK if(line_move==1 && line_gauge==1) { if((price_1-price_2)/_Point>func_calc_dorstep(price_2)) { a++; if(price_2<price_down) // If the thick line has crossed the lower shoulder when moving downwards { yin_int_1[a]=price_down; yin_int_2[a]=price_2; yang_int_1[a]=price_1; yang_int_2[a]=price_down; lin_yang[a]=price_1; line_move=-1; line_gauge=-1; price_up=price_1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=0; time_change_price[a]=lin_yang[a]; time_central_price[a]=price_down; } else//if(price_2>=price_down) // If the thick line has not crossed the lower shoulder when moving downwards { yang_int_1[a]=price_1; yang_int_2[a]=price_2; lin_yang[a]=price_1; line_move=-1; line_gauge=1; price_up=price_1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=1; time_change_price[a]=lin_yang[a]; } } } //--- the price moves UP //--- if the price has moved UPWARDS before that, the line is THICK if(line_move==1 && line_gauge==1) { if(((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) || (kagi_type==0 && (price_1-price_2)/_Point<0)) { yang_int_2[a]=price_2; line_move=1; line_gauge=1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=1; } } //--- if the price has moved UPWARDS before that, the line is THIN if(line_move==1 && line_gauge==-1) { if(((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) || (kagi_type==0 && (price_1-price_2)/_Point<0)) { if(price_2>price_up) // If the thin line has not crossed the upper shoulder when moving upwards { yin_int_2[a]=price_up; yang_int_1[a]=price_up; yang_int_2[a]=price_2; line_move=1; line_gauge=1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_central_price[a]=price_up; time_line[a]=1; } else//if(price_2<=price_up) // If the thin line has not crossed the upper shoulder when moving upwards { yin_int_2[a]=price_2; line_move=1; line_gauge=-1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=0; } } } //--- if the price has moved DOWNWARDS before that, the line is THICK if(line_move==-1 && line_gauge==1) { if((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) { a++; yang_int_1[a]=price_1; yang_int_2[a]=price_2; lin_yang[a]=price_1; line_move=1; line_gauge=1; price_down=price_1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=1; time_change_price[a]=lin_yang[a]; } } //--- if the price has moved DOWNWARDS before that, the line is THIN if(line_move==-1 && line_gauge==-1) { if((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) { a++; if(price_2>price_up) // If the thin line has crossed the upper shoulder when moving upwards { yin_int_1[a]=price_1; yin_int_2[a]=price_up; yang_int_1[a]=price_up; yang_int_2[a]=price_2; lin_yin[a]=price_1; line_move=1; line_gauge=1; price_down=price_1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=1; time_change_price[a]=lin_yin[a]; time_central_price[a]=price_up; } else //if(price_2<=price_up) // If the thin line has not crossed the upper shoulder when moving upwards { yin_int_1[a]=price_1; yin_int_2[a]=price_2; lin_yin[a]=price_1; line_move=1; line_gauge=-1; price_down=price_1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=0; time_change_price[a]=lin_yin[a]; } } } } //--- function's main loop //--- assign actual values to drawing buffers uint y=a; //--- auxiliary variables for storing data on filling the current buffer char yin=1; char yang=1; for(uint z=0; z<=a; z++) { arr_yin_1[z]=yin_int_1[y]; arr_yin_2[z]=yin_int_2[y]; switch(yin) { case 1: { arr_yin_lin1[z]=lin_yin[y]; arr_yin_lin1[z+1]=lin_yin[y]; yin++; } break; case 2: { arr_yin_lin2[z]=lin_yin[y]; arr_yin_lin2[z+1]=lin_yin[y]; yin++; } break; case 3: { arr_yin_lin3[z]=lin_yin[y]; arr_yin_lin3[z+1]=lin_yin[y]; yin=1; } break; } arr_yang_1[z]=yang_int_1[y]; arr_yang_2[z]=yang_int_2[y]; switch(yang) { case 1: { arr_yang_lin1[z]=lin_yang[y]; arr_yang_lin1[z+1]=lin_yang[y]; yang++; } break; case 2: { arr_yang_lin2[z]=lin_yang[y]; arr_yang_lin2[z+1]=lin_yang[y]; yang++; } break; case 3: { arr_yang_lin3[z]=lin_yang[y]; arr_yang_lin3[z+1]=lin_yang[y]; yang=1; } break; } y--; } //--- }
3.6. Função para criação do objeto gráfico da "Linha de tendência"
Agora, vamos examinar a função para a criação de "linha de tendência" do objeto gráfico. Esta função é necessária, a fim de chamar no gráfico Kagi principal.
A função é muito simples. Ela contém os parâmetros de entrada necessários para a criação de objeto gráfico "linha de tendência": nome do objeto, preços e horários primeiro e segundo preços e pontos de tempo, assim como a largura da linha e a cor. O corpo da função contém a função de criação do objeto gráfico e seis funções de mudar as propriedades do objeto gráfico.
//+------------------------------------------------------------------+ //| Func Object Create Trend Line | //+------------------------------------------------------------------+ void func_create_trend_line(string name, double price1, double price2, datetime time1, datetime time2, int width, color color_line) { ObjectCreate(0,name,OBJ_TREND,0,time1,price1,time2,price2); //--- set the line color ObjectSetInteger(0,name,OBJPROP_COLOR,color_line); //--- set the line display style ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID); //--- set the line width ObjectSetInteger(0,name,OBJPROP_WIDTH,width); //--- display in the foreground (false) or background (true) ObjectSetInteger(0,name,OBJPROP_BACK,false); //--- enable (true) or disable (false) the mode of continuing the line display to the left ObjectSetInteger(0,name,OBJPROP_RAY_LEFT,false); //--- enable (true) or disable (false) the mode of continuing the line display to the right ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,false); }
3.7. Desenho no gráfico Kagi principal
A próxima função que se aplica, várias vezes, é a função Kagi em construção anteriores ao gráfico. As variáveis globais preenchidas na função principal previamente examinada da construção do gráfico Kagi são utilizadas como variáveis de entrada: a matriz de preços de inversão ("ombros" e "cinturas"), a matriz de mudança e preços centrais (o preço, em que a linha Yin transforma-se em Yang, ou vice-versa), a matriz de tempo de inversão (localizada em tempo real, [z-1] índice de matriz é usada para marcar o início de inversão), a matriz do tipo de linha, em que a inversão ocorreu (é também um elemento para a frente, como a matriz de tempo).
O corpo da função consiste em um ciclo. O ciclo é dividido em duas partes: desenhar linhas verticais e horizontais. O primeiro também é dividido em dois: desenhar as verticais, considerando a mudança de linha (preço central de mudança) e ausência de mudança. Observe os parâmetros da "linha de tendência" transferidos da função de criação do objeto.
A nomenclatura é executada repetidamente. O nome do objeto começa com um número mágico (necessário para a exclusão de objetos de um determinado indicador), em seguida, o seu tipo é fixo e, finalmente, o índice é atribuído. O índice é atualizado a cada passagem do ciclo.
//+------------------------------------------------------------------+ //| Func Kagi Main Chart | //+------------------------------------------------------------------+ void func_kagi_main_chart(double &price[], // Shoulder prices array double ¢ral_price[], // Array of the prices of passing through the shoulders datetime &time[], // Current location time array ([-1] - start of shoulder) char &type_line_end[]) // Line type by the start of shoulder formation { //--- start of the loop for(uint z=1; z<=a; z++) { //--- check for the pass conditions (no pass) if(central_price[z]==-1) { if(type_line_end[z-1]==0 && price[z+1]!=-1) { func_create_trend_line(IntegerToString(magic_numb)+"_trend_yin_v"+IntegerToString(z), price[z],price[z+1],time[z],time[z],width_yin_main,color_yin_main); } if(type_line_end[z-1]==1 && price[z+1]!=-1) { func_create_trend_line(IntegerToString(magic_numb)+"_trend_yang_v"+IntegerToString(z), price[z],price[z+1],time[z],time[z],width_yang_main,color_yang_main); } } else //--- check for the pass conditions (pass is present) { if(type_line_end[z-1]==0 && price[z+1]!=-1) { func_create_trend_line(IntegerToString(magic_numb)+"_trend_yin_v"+IntegerToString(z), central_price[z],price[z],time[z],time[z],width_yin_main,color_yin_main); func_create_trend_line(IntegerToString(magic_numb)+"_trend_yang_v"+IntegerToString(z), central_price[z],price[z+1],time[z],time[z],width_yang_main,color_yang_main); } if(type_line_end[z-1]==1 && price[z+1]!=-1) { func_create_trend_line(IntegerToString(magic_numb)+"_trend_yin_v"+IntegerToString(z), central_price[z],price[z+1],time[z],time[z],width_yin_main,color_yin_main); func_create_trend_line(IntegerToString(magic_numb)+"_trend_yang_v"+IntegerToString(z), central_price[z],price[z],time[z],time[z],width_yang_main,color_yang_main); } } //--- check for the pass conditions (pass is present) //--- draw the horizontals if(type_line_end[z-1]==0) { func_create_trend_line(IntegerToString(magic_numb)+"_trend_h"+IntegerToString(z), price[z],price[z],time[z-1],time[z],width_yin_main,color_yin_main); } if(type_line_end[z-1]==1) { func_create_trend_line(IntegerToString(magic_numb)+"_trend_h"+IntegerToString(z), price[z],price[z],time[z-1],time[z],width_yang_main,color_yang_main); } //--- draw the horizontals } }
3.8. Implementação de etiquetas adicionais
Como já mencionado acima, o indicador implementa etiquetas adicionais. Vamos examinar a função de fornecer essas etiquetas no gráfico principal. Existem apenas dois tipos de etiquetas de preços aqui: etiquetas de inversão e etiquetas de tempo mostradas via "etiqueta de preço" e "etiqueta vertical". Os seguintes parâmetros são passados como os de entrada: atributo do desenho da etiqueta de preço de inversão e cor da etiqueta, atributos do desenho de etiqueta de tempo de inversão e de mudança de cor da etiqueta, a primeira e a segunda cor do tempo de inversão.
A função inteira é dividida em duas partes: a primeira parte é responsável por etiquetas de tempo, enquanto que a segunda - para etiquetas de preços. Ambas as partes da função consistem em ciclos limitados pelo número de gráficos de inversões (variável "a"). A declaração condicional é definida antes do cicloif-else. A declaração verifica a necessidade de seu desenho de acordo com as definições do indicador.
O primeiro ciclo cria etiquetas de tempo, a definição de nome do objeto é executada no início do ciclo (princípio de geração de nome foi descrito acima). Em seguida, a cor é selecionada, dependendo da linha do tipo a partir da matriz de tipo de linha globalmente declarada (se o parâmetro é definido) e outros parâmetros são aplicados para à linha.
O segundo ciclo é responsável pela criação de etiquetas de preços de inversão. Em primeiro lugar, o nome do objeto é gerado. Em seguida, a seleção do índice da matriz de tempo é definida dependendo se Kagi está sendo construído no gráfico principal ou não. Se isso não for feito, as etiquetas serão localizadas "no ar" e não ficará suficientemente claro do lugar que ocorreu a inversão. Em seguida, o objeto tipo "etiqueta de preço" é criado e configurado.
//+------------------------------------------------------------------+ //| Func Label Main Chart | //+------------------------------------------------------------------+ void func_label_main_chart(bool label_print, color label_color, bool time_change_print, bool time_change_color, color time_color_first, color time_color_second) { if(time_change_print==true) { for(uint z=1; z<=a; z++) { string name=IntegerToString(magic_numb)+"_time_2_"+IntegerToString(z); //--- create an object of a vertical line type ObjectCreate(0,name,OBJ_VLINE,0,time_change[z],0); //--- set the line color color color_line=clrBlack; if(time_change_color==true) { if(time_line[z]==0)color_line=time_color_first; if(time_line[z]==1)color_line=time_color_second; } else color_line=time_color_first; ObjectSetInteger(0,name,OBJPROP_COLOR,color_line); //--- set the line display style ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID); //--- set the line width ObjectSetInteger(0,name,OBJPROP_WIDTH,1); //--- display on the foreground (false) or background (true) ObjectSetInteger(0,name,OBJPROP_BACK,false); //--- enable (true) or disable (false) the line display mode in the chart subwindows ObjectSetInteger(0,name,OBJPROP_RAY,time_separate_windows); } } if(label_print==true) { for(uint z=1; z<=a; z++) { string name=IntegerToString(magic_numb)+"_label_2_"+IntegerToString(z); uint numb_time; if(kagi_main_chart==true)numb_time=z; else numb_time=z-1; //--- create a label type object ObjectCreate(0,name,OBJ_ARROW_RIGHT_PRICE,0,time_change[numb_time],time_change_price[z]); //--- set the label color ObjectSetInteger(0,name,OBJPROP_COLOR,label_color); //--- set the edging line style ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID); //--- set the label size ObjectSetInteger(0,name,OBJPROP_WIDTH,1); //--- display on the foreground (false) or background (true) ObjectSetInteger(0,name,OBJPROP_BACK,false); } } }
Agora, vamos ver como podemos definir as etiquetas na janela do indicador.
Todas as etiquetas na janela do indicador são principalmente de preços e só há dois tipos delas: etiquetas de preços de inversão e níveis de preços. Existem dois tipos de desenhos dos níveis de preço: nas inversões de gráfico e em uma distância igual de toda a faixa de preço gráfico. O primeiro tipo pode mudar a cor dos níveis de duas maneiras: dependendo do tipo de linha (Yin Yang ou) e de acordo com reversão (para cima ou para baixo).
Assim, a própria função é dividida em dois ciclos: o primeiro é responsável pela criação de etiquetas de preços de inversão, o segundo trata da designação dos níveis de preços. Este último é dividido em dois tipos: de etiquetas em cada inversão ou etiquetas em todo o intervalo de preços em um nível igual.
Esta função é diferente da anterior na medida em que ela tem limitações sobre o número de etiquetas de preço e níveis, devido ao fato de que, em grandes números elas sobrecarregam o gráfico, que complica a sua compreensão.
Devido a esta característica, ambos os ciclos são limitados pelo número de passagens especificadas nas configurações do indicador (número de etiquetas de preço e níveis). Tal abordagem é perigosa, pois o número de inversões pode vir a ser muito menor do que o número de etiquetas de preços fixadas nas configurações. Devido a esta razão, a presença de inversão durante cada passagem do ciclo é verificada para desenhar uma etiqueta de preço ou nível.
A única exceção é o desenho de níveis de preço ao longo de toda a faixa de preço em uma distância igual. A geração de objetos gráficos do tipo "Etiqueta de preço" é realizada nas coordenadas em ordem inversa, ou seja, as etiquetas são colocadas a partir da data atual para o passado. O mesmo se aplica aos níveis de preços: os níveis de preços atuais são gerados primeiro, seguido por anteriores. As exceções são os níveis de preços que não dependam das inversões de gráfico.
Mudanças de cor do nível de preços são realizadas usando declarações condicionais if-else de acordo com as configurações.
//+------------------------------------------------------------------+ //| Func Label Indicator Window | //+------------------------------------------------------------------+ void func_label_indicator_window(bool label_print, // Draw price labels bool levels_print, // Draw levels char levels_type_draw, // Type of drawing the levels by reversals or at an equal distance of the entire price range char levels_color_change) // Change line color { uint number=a; if(label_print==true) { for(uint z=0; z<=label_1_number; z++) { if(z<number) { string name=IntegerToString(magic_numb)+"_label_1_"+IntegerToString(z); //--- create label type object ObjectCreate(0,name,OBJ_ARROW_RIGHT_PRICE,ChartWindowFind(),(datetime)Time[(bars_copied_time-z-2)],time_change_price[number-z]); //--- set the label color ObjectSetInteger(0,name,OBJPROP_COLOR,label_1_color); //--- set the style of the edging line ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID); //--- set the label size ObjectSetInteger(0,name,OBJPROP_WIDTH,1); //--- display on the foreground (false) or background (true) ObjectSetInteger(0,name,OBJPROP_BACK,false); } } } if(levels_print==true) { if(levels_type_draw==0) { for(uint z=0; z<=levels_number; z++) { if(z<number) { IndicatorSetDouble(INDICATOR_LEVELVALUE,z,time_change_price[number-z]); if(levels_change_color==0) { double numb_even=z; if(MathMod(numb_even,2)==0) { IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,levels_first_color); } if(MathMod(numb_even,2)!=0) { IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,levels_second_color); } } if(levels_change_color==1) { if(time_line[number-z]==0)IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,levels_first_color); if(time_line[number-z]==1)IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,levels_second_color); } if(levels_change_color==2) { IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,levels_first_color); } } } } if(levels_type_draw==1) { double max_price=Price[ArrayMaximum(Price)]; double min_price=Price[ArrayMinimum(Price,1,ArrayMinimum(Price)-1)]; double number_difference=(max_price-min_price)/levels_number; NormalizeDouble(number_difference,_Digits); for(uint z=0; z<=levels_number; z++) { IndicatorSetDouble(INDICATOR_LEVELVALUE,z,(min_price+(z*number_difference))); IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,levels_first_color); } } } }
3.9. Exclusão de objetos gráficos criados anteriormente
Nós já sabemos que este indicador é rico em objetos gráficos. É hora de pensar em como podemos excluí-los de forma rápida e eficiente.
Esta tarefa é executada pela função, para excluir os objetos gráficos. O nome e o número inicial de objetos, são utilizados como parâmetros de função. Como durante a criação, o nome do objeto deve conter o número mágico e o nome de um tipo de objeto. A chamada de função no programa é limitada pelo número de objetos que excedam à sua possível existência. No entanto, isto não afeta a funcionalidade do indicador.
//+------------------------------------------------------------------+ //| Func Delete Objects | //+------------------------------------------------------------------+ void func_delete_objects(string name, int number) { string name_del; for(int x=0; x<=number; x++) { name_del=name+IntegerToString(x); ObjectDelete(0,name_del); } }
3.10. Função para o início da construção do gráfico
Agora, depois de ter examinado todas as funções para cálculo e construção do gráfico Kagi, bem como para criação e exclusão de objetos, devemos considerar uma outra pequena função para verificação do recebimento da nova barra. A função é bastante simples e tem um parâmetro de entrada - período analisado. A resposta da função também é muito simples. Ela tem tipo bool e contém a resposta sobre se uma nova barra está presente ou não. A base do corpo da função é mudar a declaração que passa o controle para suas declarações diferentes dependendo do período.
No exemplo, a função cobre toda a faixa do período, embora apenas um período possa também ser usado.
O algoritmo de função foi pego do código IsNewBar: o tempo de abertura da última barra é comparado com o valor de tempo anteriormente definido. Se os valores forem diferentes, há uma nova barra. O novo valor é designado como o definido anteriormente e uma resposta da função é considerada positiva. Se o tempo de abertura da última barra coincide com o valor de tempo anteriormente determinado, então a nova barra ainda não apareceu e a resposta da função é negativa.
//+------------------------------------------------------------------+ //| Func New Bar | //+------------------------------------------------------------------+ bool func_new_bar(ENUM_TIMEFRAMES period_time) { //---- static datetime old_Times[22];// array for storing old values bool res=false; // analysis result variable int i=0; // old_Times[] array cell index datetime new_Time[1]; // new bar time switch(period_time) { case PERIOD_M1: i= 0; break; case PERIOD_M2: i= 1; break; case PERIOD_M3: i= 2; break; case PERIOD_M4: i= 3; break; case PERIOD_M5: i= 4; break; case PERIOD_M6: i= 5; break; case PERIOD_M10: i= 6; break; case PERIOD_M12: i= 7; break; case PERIOD_M15: i= 8; break; case PERIOD_M20: i= 9; break; case PERIOD_M30: i=10; break; case PERIOD_H1: i=11; break; case PERIOD_H2: i=12; break; case PERIOD_H3: i=13; break; case PERIOD_H4: i=14; break; case PERIOD_H6: i=15; break; case PERIOD_H8: i=16; break; case PERIOD_H12: i=17; break; case PERIOD_D1: i=18; break; case PERIOD_W1: i=19; break; case PERIOD_MN1: i=20; break; case PERIOD_CURRENT: i=21; break; } // copy the time of the last bar to new_Time[0] cell int copied=CopyTime(_Symbol,period_time,0,1,new_Time); if(copied>0) // all is well. Data has been copied { if(old_Times[i]!=new_Time[0]) // if the bar's old time is not equal to new one { if(old_Times[i]!=0) res=true; // if it is not the first launch, true = new bar old_Times[i]=new_Time[0]; // store the bar's time } } //---- return(res); }
3.11. Funções OnCalculate() e OnChartEvent()
Todas as funções descritas acima são consolidadas na função que levam o mesmo nome - Func Consolidation. Esta função é iniciada cada vez que uma nova barra aparece na função OnCalculate() e quando a tecla "R" é pressionada a partir função OnChartEvent().
Antes que o gráfico seja gerado ou atualizado, a função de exclusão de todos os objetos gráficos é chamado na função de consolidação (Func Consolidation). Uma vez que existem vários objetos e eles são divididos em etiquetas de preço da janela indicadora e do gráfico principal, as linhas verticais indicando o tempo de inversão, bem como linhas de tendência vertical e horizontal Yin e Yang, o número geral de chamadas da função será 7.
Em seguida, os dados históricos são copiados por preço e tempo. A função principal para a construção do gráfico Kagi é, então, iniciada. Depois disso, a função de colocar todas as etiquetas de preço no gráfico principal e na janela indicadora é chamada. Finalmente, o Kagi é gerado no gráfico principal e a função para redesenhar os objetos é iniciada.
//+------------------------------------------------------------------+ //| Func Consolidation | //+------------------------------------------------------------------+ void func_consolidation() { //--- date of construction end stop_data=TimeCurrent(); //--- deleting all graphical objects belonging to the indicator func_delete_objects(IntegerToString(magic_numb)+"_label_2_",ObjectsTotal(0,-1,-1)); func_delete_objects(IntegerToString(magic_numb)+"_label_1_",ObjectsTotal(0,-1,-1)); func_delete_objects(IntegerToString(magic_numb)+"_time_2_",ObjectsTotal(0,-1,-1)); func_delete_objects(IntegerToString(magic_numb)+"_trend_yin_v",ObjectsTotal(0,-1,-1)); func_delete_objects(IntegerToString(magic_numb)+"_trend_yang_v",ObjectsTotal(0,-1,-1)); func_delete_objects(IntegerToString(magic_numb)+"_trend_h",ObjectsTotal(0,-1,-1)); func_delete_objects(IntegerToString(magic_numb)+"_trend_h",ObjectsTotal(0,-1,-1)); //--- copy price data to the main buffer copy_history=func_copy_history(Price,start_data,stop_data); //--- display information about the error when copying price data if(copy_history==false)Alert("Error of copy history Price"); //--- copy time data to the main buffer copy_time=func_copy_time(Time,start_data,stop_data); //--- display a notification of the error occurred while copying time data if(copy_time==false)Alert("Error of copy history Time"); //--- construct Kagi chart in the indicator window func_draw_kagi(Price,YinBuffer1,YinBuffer2,Yin1Buffer,Yin2Buffer,Yin3Buffer, YangBuffer1,YangBuffer2,Yang1Buffer,Yang2Buffer,Yang3Buffer,Time); //--- draw labels on the main chart func_label_main_chart(label_2,label_2_color,time_line_draw,time_line_change_color,time_first_color,time_second_color); //--- draw labels on the indicator chart func_label_indicator_window(label_1,levels_on_off,levels_type,levels_change_color); //--- construct Kagi chart in the main window if(kagi_main_chart==true)func_kagi_main_chart(time_change_price,time_central_price,time_change,time_line); //--- redraw the chart ChartRedraw(0); //--- } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- if(func_new_bar(period_to_redraw)==true) { func_consolidation(); } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| OnChartEvent | //+------------------------------------------------------------------+ void OnChartEvent(const int id, // event ID const long& lparam, // long type event parameter const double& dparam, // double type event parameter const string& sparam) // string type event parameter { if(id==CHARTEVENT_KEYDOWN) // Keyboard button pressing event { if(lparam==82) // "R" key has been pressed { func_consolidation(); } } }
3.12. Função OnDeinit()
A exclusão de todos os objetos é realizada na função de deinicialização do indicador.
//+------------------------------------------------------------------+ //| OnDeinit | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- delete all graphical objects belonging to the indicator func_delete_objects(IntegerToString(magic_numb)+"_label_2_",ObjectsTotal(0,-1,-1)); func_delete_objects(IntegerToString(magic_numb)+"_label_1_",ObjectsTotal(0,-1,-1)); func_delete_objects(IntegerToString(magic_numb)+"_time_2_",ObjectsTotal(0,-1,-1)); func_delete_objects(IntegerToString(magic_numb)+"_trend_yin_v",ObjectsTotal(0,-1,-1)); func_delete_objects(IntegerToString(magic_numb)+"_trend_yang_v",ObjectsTotal(0,-1,-1)); func_delete_objects(IntegerToString(magic_numb)+"_trend_h",ObjectsTotal(0,-1,-1)); func_delete_objects(IntegerToString(magic_numb)+"_trend_h",ObjectsTotal(0,-1,-1)); //--- redraw the chart ChartRedraw(0); }
Agora, vamos passar a usar o indicador na prática.
4. Uso do gráfico Kagi na prática
Há muitas estratégias de negociação baseadas no gráfico Kagi. Vamos examinar algumas delas.
Vamos começar com a estratégia mais popular: vender quando Yang muda para Yin e comprar, no caso oposto. Isto é mostrado na fig. 4:
Fig. 4. Vender quando Yang muda para Yin e comprar no caso contrário
Como pode ser visto na fig. 4 (EURUSD M30, 5 pontos), esta estratégia mostra bons resultados. A figura mostra 8 pontos para 4 sinais, o primeiro (1) mostra que a posição longa deve ser aberta em 1.3518, o que parece ser correto, pois o preço, em seguida, atinge cerca de 1.3560, que abrange 42 pontos por dia. Este é um bom resultado.
O próximo ponto (2) recomenda vender a 1.3519. Como podemos ver, o preço realmente se move para baixo cruzando o nível de 1.3485 (e cobrindo 34 pontos), aproximadamente por duas horas.
Vamos ao ponto (3). A posição longa é aberta em 1.3538 e o preço sobe atingindo 1.3695. Assim, o lucro abrange 157 pontos já por um dia e meio. Claro, estes são os maiores lucros possíveis, mas o resultado ainda é bom o suficiente.
A próxima estratégia de negociação está rolando para trás da linha de tendência mostrada na fig. 5 (EURUSD M30, 5 pontos), de 07 a 18 de outubro:
Fig. 5. Redução a partir da linha de tendência
Podemos seguir em frente e negociar seguindo os canais. Um exemplo de busca de um canal pode ser analisado na figura 6 (EURUSD H1, 5 pontos), aproximadamente o mesmo período:
Fig. 6. Negociação por canais
A estratégia menos popular baseada no fato de que, depois de 7-10 "ombros" de aumento sucessivo ou de "cinturas" de diminuição, certamente haverá uma inversão (ascensão e queda).
Isto é apresentado na Figura 7 (GBPUSD H4, 25 pontos), de 10 de julho - 18 outubro:
Fig. 7. 7-10 sucessivos "ombros" de aumento ou "cinturas" de diminuição
Como pode ser visto na imagem, sete ombros ascendentes são seguidos por uma queda bastante considerável igual a aproximadamente metade da elevação anterior (cerca de 300 pontos).
Vamos examinar a estratégia de "Negociação por meio de uma etiqueta de preço" para mostrar a necessidade do uso de parâmetros indicadores adicionais. A ideia é entrar no mercado quando o preço exceder (compra) ou mover para abaixo (vender) a etiqueta de preço anterior.
A estratégia é mostrada na fig. 8 (GBPUSD H4, 30 pontos, construção modificada):
Fig. 8. Negociação através de uma etiqueta de preço
Setas de exibição vermelhas na figura 8 ao comprar ou vender. As setas estão se movendo a partir da etiqueta de preço anterior, exibindo os locais das etiquetas de preços anteriores que foram quebradas completamente.
Etiquetas de tempo servem principalmente como indicadoras de direção e tendência. Visto que a cor das etiquetas de tempo podem ser alteradas em relação ao tipo de linha, e o tipo de linha Yin ou Yang mostra a direção de tendência ou inversão, a cor pode nos ajudar a definir a atmosfera do mercado atual.
Por exemplo, vamos pegar o gráfico de ações de #IBM (H4, 1%, construção padrão) mostrado na figura 9:
Fig. 9. Definição de direção de tendência utilizando etiquetas de tempo
O gráfico mostra que as linhas azuis estão localizadas principalmente nos topos do gráfico, enquanto as vermelhas - nas partes inferiores.
Conclusão
O gráfico Kagi pode ser usado com sucesso para negociação no mercado como base de estratégia ou como uma ferramenta auxiliar para a análise mais precisa.
Neste artigo, examinei o código em si e algumas especificações da construção do indicador. O objetivo principal foi a criação do indicador multi-funcional que contém todos os elementos necessários com alguns recursos extras que podem ser desativados.
Terei todo o prazer de considerar novas ideias e melhorias para o indicador e, talvez, implementá-las no futuro. Além disso, por favor, me forneça o seu feedback. Ficarei feliz em responder suas perguntas sobre o indicador.
Este artigo continua a série dedicada ao desenvolvimento de indicadores para a construção dos gráficos do passado. O artigo anterior pode ser encontrado aqui. A série deve ser continuada e espero encontrá-lo novamente em breve. Obrigado pelo seu interesse! Desejo-lhe negociações de sucesso, assim como códigos estáveis e otimizados.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/772





- 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