
O Histograma de preço (Perfil de mercado) e sua implementação no MQL5
"O Perfil de mercado tenta fornecer essa lógica interna, no contexto do mercado.
É um método de análise que começa com a compreensão de que somente o preço
não comunica as informações ao participante, apenas com palavras sem sintaxe
ou o contexto pode não ter nenhum significado. O volume é uma parte integrante da expressão direta
do mercado - compreenda-o e você compreenderá a linguagem do mercado."
Robin Mesh
Introdução
Há muito tempo atrás, examinando uma assinatura de revista, encontrei um artigo "Perfil de mercado e compreensão da linguagem de mercado" (outubro de 2002) no jornal russo "Valutny Spekulant" (atualmente é chamado como "Trader ativo"). O artigo original foi publicado em "New Thinking in Technical Analysis: Trading Models from the Masters".
O Perfil de mercado foi desenvolvido pelo pensador realmente brilhante Peter Steidlmayer. Ele descobriu a expressão natural de (volume) de mercado e organizou-a de uma forma que fosse legível (a curva de Gaussian), de modo que a informação objetiva gerada pelo mercado fosse acessível para participantes do mercado. Steidlmayer sugeriu o uso da representação alternativa de informação sobre movimentos de mercados "horizontais" e "verticais" que levam a um conjunto de modelos completamente diferentes. Ele presumiu que existe um pulso subjacente do mercado ou de um padrão fundamental chamado de ciclo de equilíbrio e desequilíbrio.
O Perfil de mercado mede o movimento do mercado horizontal através de um vertical. Vamos chamar isso de "equilíbrio" através de "desequilíbrio". Esta relação é o princípio organizador fundamental do mercado. Todo estilo do negócio de trading pode mudar dependendo de que parte do ciclo de equilíbrio/desequilíbrio do mercado ele esteja. O Perfil de mercado pode determinar tanto quando o mercado vai mudar de equilíbrio para o desequilíbrio e o quão grande o movimento será.
Os dois conceitos básicos de Perfil de mercado são:
- O mercado é um leilão e move-se na direção da faixa de preço onde a oferta e a demanda são mais ou menos iguais.
- O mercado tem duas fases: atividade horizontal e atividade vertical. O mercado se move verticalmente quando oferta e procura não são iguais ou estão em desequilíbrio e horizontalmente quando estão em equilíbrio ou equilibradas.
O mercado de equilíbrio mostrado utilizando o Perfil de mercado no quadro abaixo, tende a formar uma curva em forma de sino quase perfeita, com rotação de 90 graus, devido à orientação do gráfico:
Fig 1. O Perfil de mercado do mercado de equilíbrio
A tendência, mercado não-equilibrado também forma uma curva em forma de sino, mas o seu centro é deslocado para cima ou para baixo. Outras configurações que formam dois picos de sinos, dependendo do movimento do preço e da confiança dos agentes do mercado, são possíveis.
Fig 2. O Perfil de mercado do mercado (tendência) de desequilíbrio
A utilização das formas perfil diárias para determinar o grau do nível de equilíbrio/desequilíbrio do mercado pode ser útil, porque lhe dá um ponto de partida para a compreensão das mudanças entre os vários participantes do mercado.
A oportunidade de trading com o maior benefício aparece quando a mudança de equilíbrio para o desequilíbrio está prestes a ocorrer. Além disso, se você pode identificar essa oportunidade de trading e estimar com precisão a magnitude potencial dessa mudança, então você pode estimar a qualidade de negócio e a quantidade de tempo que é necessário para isso.
Você pode encontrar o exemplo de metodologia de trabalho com esta ferramenta em http://www.enthios.com/, onde um grupo de traders estuda o Histograma de preço desde 1998. A estratégia Universal Enthios e exemplo do seu uso podem também ser encontradas aqui.
1. Histograma de preço
O Histograma de preço é uma ferramenta muito confiável. É um pouco intuitivo, mas extremamente eficaz. O Histograma de preço simplesmente mostra os "mais convenientes" pontos de negociação do mercado. Este é um indicador líder, porque mostra os pontos onde o mercado pode mudar a sua direção com antecedência. Os indicadores, como médias móveis ou osciladores não podem especificar os pontos exatos de resistência e de apoio, eles podem apenas mostrar o fato caso o mercado esteja sobrecomprado ou sobrevendido.
Normalmente, o Histograma de preço (ou Perfil de mercado) é aplicado a gráficos de preços de 30 min. para estudar a atividade do mercado durante um dia. Eu prefiro usar os gráficos de 5 min. para os mercados de ações e gráficos de 15-30 min. para FOREX.
2. Ponto de controle
Na figura acima você pode ver o nível em que o mercado foi negociado em quantidade máxima de tempo, está descrito com a linha mais longa do histograma. É chamado de Ponto de Controle, ou POC. Por vezes, como visto na figura, o histograma tem dois topos, um deles é um pouco inferior. Nesse caso, vemos que o indicador mostra apenas um POC, mas na verdade existem dois deles, e isso deve ser levado em conta.
Além disso, o nível de percentagem da taxa no histograma também cria níveis adicionais, assim chamados de Níveis de POC secundários:
Fig 3. Pontos de controle
O que mostra o POC? O preço que é lembrado pela maioria dos traders. O mercado mais longo é negociado a este preço, o mercado mais longo, lembre-se.
O POC age psicologicamente como um centro de atração.
O próximo gráfico mostra o que aconteceu poucos dias antes. É uma boa demonstração do poder do Histograma de preço.
Fig 4. O Ponto de controle não é absoluto, mostra a taxa de negócio
O Ponto de controle não é absoluto, indica a taxa de negociação. Assim, o trader deve estar pronto para agir quando o mercado se aproximar ao POC. Auxilia a melhorar ordens, utilizando as observações históricas.
Vamos considerar a fig. 4. O POC em 29.12.2009 está localizado ao preço de 68,87. É claro que, mesmo sem o histograma e a linha de POC, o mercado estava dentro da taxa de 68,82~68,96 quase durante o dia todo. O mercado fechou no final do dia com 5 pontos abaixo do POC. No dia seguinte causou a abertura do mercado com um deslizamento.
É importante entender que não podemos prever se o mercado subirá ou descerá. Podemos apenas supor que o mercado retornará à linha do POC e ao acúmulo máximo das linhas do histograma. Mas o que acontecerá quando o preço encostar no POC? A mesma coisa que acontece com um objeto elástico que cai no chão, saltará para trás. Se isso acontecer rapidamente, como uma bola de tênis que dá golpes em uma raquete, o preço retornará muito rapidamente para o nível inicial.
Após a abertura do mercado em 30.12.2009, vemos que era uma lacuna e, em seguida, o mercado encostou no POC do dia anterior e, então, rapidamente voltou para o preço de abertura e atualizou o mínimo.
Observe que o POC não é absolutamente preciso (traders experientes sabem que não há níveis de resistência claros quando o preço atinge um alcance máximo, mínimo ou taxa de concentração). O que acontece neste momento depende dos agentes de mercado. Se o desejo coletivo (por exemplo, publicação de notícias) coincidir, então o mercado vai passar do POC, mas é raro e pode ser utilizado para desenvolver um sistema de negociação.
Preste atenção que o comportamento do mercado era o mesmo em 31.12.2009. Quando o preço encostou no POC, os compradores renderam-se aos vendedores.
3. Ponto virgem de controle
O POC Virgem (Ponto virgem de controle) é um nível que o preço não atingiu nos próximos dias.
A lógica é simples, como descrito acima, o POC é um ponto de atração para o mercado. Como o preço se afasta do POC, a força de atração aumenta. E quanto mais o preço se afasta do POC Virgem, maior é a possibilidade de que quando retornar a este nível, o salto de retorno ocorrerá e, provavelmente, um preço invertido também ocorrerá.
Fig 5. POC Virgem anterior e atual
Na fig. 5, os POCs Virgens anteriores que eram os níveis de suporte e resistência estão marcados com círculos. Os POCs Virgens em funcionamento estão marcados com valores de preço.
Uma vez que o preço tenha encostado no POC Virgem, ele deixa de ser um "virgem". Psicologicamente, o mercado já não o vê como um nível substancial de suporte ou resistência. Os traders ainda podem ver os níveis de preços, que inicialmente formaram o POC, mas como uma simples acumulação de preços.
4. Implementação de Histograma de preço no MQL5
Minha primeira versão do Histograma de preço apareceu em 2006, foi escrita no MQL4 no MetaTrader 4 para uso pessoal. Durante o desenvolvimento deste indicador, enfrentei alguns problemas, aqui estão alguns deles:
- Pouquíssimo número de barras no histórico para M5, sem falar do M1;
- A necessidade de desenvolver funções especiais para trabalhar com histórico, como voltar para trás por um dia, considerando feriados, verificar o tempo de fechamento do mercado na sexta-feira, verificar o tempo de abertura e fechamento para o mercado de CFD, etc.;
- Recalcular o indicador ao alterar prazos e, como resultado, os atrasos terminais.
Portanto, quando o teste inicial do МetaТrader 5 e MQL5 começou, decidi convertê-lo ao MQL5.
Como as pessoas dizem, "a primeira panqueca é sempre um pouco mais complicada", tentei implementá-lo como um indicador.
Vamos começar com a boa: a presença de um longo histórico de citações de um minuto para todos os símbolos, a possibilidade de obtenção de dados históricos para um determinado período de tempo, em qualquer intervalo de tempo.
Agora vou explicar por que acabou. Não considerei os recursos dos indicadores do MQL5:
- O tempo de execução do indicador é crítico;
- Os recursos do trabalho do indicador após as mudanças de período de tempo.
A execução da função OnCalculate(), que corresponde a Calcular programa, tem um tempo de execução crítico. Assim, o processo de 260 dias (período anual) utilizando as barras de minuto, a história leva muito tempo, até vários minutos. Claro que podemos aceitar isso, se os cálculos realizados de uma só vez, após o indicador anexar-se ao gráfico. Mas este não é o caso para alterações no período de tempo. Quando o indicador muda para os diferentes prazos, a cópia antiga do indicador é destruída e criada uma nova. É por isso que após alterações do período de tempo temos de recalcular os mesmos níveis novamente e isso leva muito tempo.
Mas como costuma-se dizer, se você não sabe o que fazer - "Leia a documentação primeiro", no nosso caso, a documentação do MQL5. A solução era muito simples - implementar este indicador como Expert Advisor que não negocia.
As vantagens do Expert Advisor são:
- O tempo de processamento não é crítico para programa Init no OnTick();
- A possibilidade de obter os parâmetros do programa OnDeinit (const razão int).
Os Experts Advisors diferem-se dos indicadores conforme a seguir: após o prazo mudar o consultor especialista apenas gera o evento DeInit com o parâmetro de razão REASON_CHARTCHANGE, ele não descarrega o Expert Advisor a partir da memória e serve os valores das variáveis globais. Ele nos permite realizar todos os cálculos de uma só vez após anexar o Expert Advisor, alterando seus parâmetros e novos dados que apareçam, no nosso caso, para um novo dia de negociação.
Vamos apresentar algumas definições que serão necessárias mais tarde.
A programação de objeto orientado (OOP) - é um estilo de programação que conceitos básicos são os conceitos de objetos e classes.
O objeto é uma entidade no espaço virtual, com estado e comportamento especificado, que possui alguns valores de propriedades (chamados de atributos) e operações com tais (chamadas de métodos).
Na OOP a classe é um tipo de dado abstrato especial, caracterizado por meio de sua construção. Ela é um conceito chave na OOP e difere-se dos outros tipos de dados abstratos. A definição de dados na classe também contém métodos de classe de seu processamento de dados (interface).
Na programação, há um conceito de interface de software que significa uma lista de possíveis cálculos que podem ser realizados por uma parte do programa, incluindo algoritmos, a descrição dos argumentos e ordem de parâmetros de entrada para prosseguir e os seus valores de retorno. A interface de tipo abstrato de dados foi desenvolvida para uma descrição formal de tal lista. Os próprios algoritmos e o código que irão executar todos esses cálculos não são especificados e chamados como implementação de interface.
A criação de classe é a criação de uma estrutura com campos e métodos. A classe inteira pode ser considerada como um modelo para a criação de objetos, que são objetos específicos de classes. Os objetos específicos de classe são criados usando o mesmo modelo, para que eles tenham os mesmos campos e métodos.
Vamos começar...
O código fonte está localizado em 4 arquivos. O principal arquivo é PriceHistogram.mq5, os outros são: ClassExpert.mqh, ClassPriceHistogram.mqh e ClassProgressBar.mqh. Os arquivos com extensão .mqh contêm as descrições e métodos de classes. Todos os arquivos devem estar localizados no mesmo diretório. Meu diretório é: \MQL5\ Experts\PriceHistogram.
4.1. PriceHistogram.mq5
A primeira afirmação no código-fonte é:
#include "ClassExpert.mqh"
A diretiva de compilação #include inclui o texto a partir do arquivo especificado. No nosso caso é a descrição de classe CExpert (discutida abaixo).
A próxima é um bloco de variáveis de entrada que são parâmetros do Expert Advisor.
// The block input parameters input int DayTheHistogram = 10; // Days for histogram input int DaysForCalculation= 500; // Days for calculation(-1 all) input uint RangePercent = 70; // Percent range input color InnerRange =Indigo; // Inner range input color OuterRange =Magenta; // Outer range input color ControlPoint =Orange; // Point of Control input bool ShowValue =true; // Show Values
Após isso, a variável ExtExpert (do tipo de classe CExpert) é declarada.
A próxima é programas padrões que estão nos programas MQL5. Os programas requerem os métodos correspondentes da classe CExpert.
int OnInit() { //--- // We check for symbol synchronization before the start of calculations int err=0; while(!(bool)SeriesInfoInteger(Symbol(),0,SERIES_SYNCRONIZED) && err<amount_of_attempts) {="" Sleep(500); err++; } // CExpert class initialization ExtExpert.RangePercent=RangePercent; ExtExpert.InnerRange=InnerRange; ExtExpert.OuterRange=OuterRange; ExtExpert.ControlPoint=ControlPoint; ExtExpert.ShowValue=ShowValue; ExtExpert.DaysForCalculation=DaysForCalculation; ExtExpert.DayTheHistogram=DayTheHistogram; ExtExpert.Init(); return(0); }
Quando escrevi a primeira versão do Expert Advisor e executei-o, tive alguma dificuldade em compreender o porquê dele terminar com erro após o reinício do terminal do cliente ou um símbolo mudar. E ocorre quando o terminal de cliente foi desconectado ou um símbolo não é utilizado por um longo tempo.
É ótimo que os desenvolvedores adicionaram o depurador para o MetaEditor5. Lembro-me de um monte de comandos Print() and Comment() (imprimir e comentar) utilizados para a verificação dos valores de variáveis no MetaEditor4. Muito obrigado aos desenvolvedores do MetaEditor5.
No meu caso, tudo era fácil, o especialista começa antes da conexão com o servidor e da atualização dos dados do histórico. Para resolver este problema, tive que usar o SeriesInfoInteger(Symbol(),0,SERIES_SYNCRONIZED), que relata se os dados estão sincronizados ou não, e o tempo de ciclo (), no caso de ausência de conexão que utiliza a variável do contador de erro.
Uma vez que os dados tenham sido sincronizados, ou que o ciclo tenha sido concluído por causa do contador na ausência de conexão, passamos os parâmetros de entrada da nossa classe especialista CExpert e chamamos o método de inicialização de classe Init().
Como se pode ver, graças ao conceito de classes em MQL5, nosso arquivo PriceHistogram.mq5 se transformou em um modelo simples, e todo o processamento está na classe CExpert, declarado no arquivo ClassExpert.mqh.
4.2. ClassExpert.mqh
Vamos considerar sua descrição.
//+------------------------------------------------------------------+ //| Class CExpert | //| Class description | //+------------------------------------------------------------------+ class CExpert { public: int DaysForCalculation; // Days to calculate (-1 for all) int DayTheHistogram; // Days for Histogram int RangePercent; // Percent range color InnerRange; // Internal range color color OuterRange; // Outer range color color ControlPoint; // Point of Control (POC) Color bool ShowValue; // Show value
A seção pública está aberta e acessível a partir de variáveis externas. Você vai notar que os nomes das variáveis coincidem com nomes de seção de parâmetros de entrada descritos no PriceHistogram.mq5. Não é necessário, porque os parâmetros de entrada são globais. Mas neste caso - é um tributo às boas regras de boas reproduções, é desejável para evitar o uso de variáveis externas dentro da classe.
private: CList list_object; // The dynamic list of CObject class instances string name_symbol; // Symbol name int count_bars; // Number of daily bars bool event_on; // Flag of events processing
A seção privada é fechada a partir do exterior e apenas acessível dentro da classe. Eu gostaria de descrever a variável list_object of CList type, que é uma classe da biblioteca padrão do MQL5. A Classe CList é uma classe dinâmica com uma lista de exemplos de classe CObject e seus herdeiros. Usarei essa lista para o armazenamento de referências para os elementos de classe CPriceHistogram, que é um herdeiro da classe CObject, nós consideraremos os detalhes abaixo. A descrição da classe CList está no List.mqh e inclui usando a diretiva de compilação #include.
public: // Class constructor CExpert(); // Class destructor ~CExpert(){Deinit(REASON_CHARTCLOSE);} // Initialization method bool Init(); // Deinitialization method void Deinit(const int reason); // Method of OnTick processing void OnTick(); // Method of OnChartEvent() event processing void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); // Method of OnTimer() event processing void OnTimer(); };
O seguinte é uma seção de métodos públicos. Como você já deve ter adivinhado tais métodos (funções) estão disponíveis fora da classe.
E, finalmente, a chave com um ponto e vírgula completa a descrição da classe.
Vamos considerar métodos de classe em detalhe.
O construtor da classe é um bloco especial de declarações, chamado quando o objeto é criado. O construtor é semelhante ao método, mas difere-se do método que não tenha forma explícita de um certo tipo de dados retornados.
Na linguagem MQL5, os construtores não podem ter parâmetros de entrada e cada classe deve ter um único construtor. No nosso caso, o construtor é uma inicialização primária de variáveis.
O destrutor é um método de classe especial que é utilizado para a finalização do objeto (por exemplo, memória livre). No nosso caso o método é chamado de Deinit (REASON_CHARTCLOSE).
O Init() é um método para a inicialização da classe. Este é o método mais importante da classe CExpert, a criação de objetos de histograma executaram-se lá. Por favor, olhe os comentários para os detalhes. Mas eu gostaria de considerar alguns pontos.
O primeiro, para construir um Histograma de preço diário, precisamos dos dados de tempo abertos por dias para continuar. Aqui eu gostaria de divagar e chamar a atenção para os recursos de trabalho com série de tempo. Para a solicitação de dados de outros prazos que precisávamos de um tempo, então as funções de Bars() e CopyTime(), bem como outras funções para trabalhar com série de tempo não são sempre o retorno dos dados da primeira chamada.
Então, eu tive que colocar essa função no do (...) while () loop, mas para torná-lo finito, usei a variável do contador.
int err=0; do { // Calculate the number of days which available from the history count_bars=Bars(NULL,PERIOD_D1); if(DaysForCalculation+1<count_bars) count="DaysForCalculation+1; else count=count_bars; if(DaysForCalculation<=0) count=count_bars; rates_total=CopyTime(NULL,PERIOD_D1,0,count,day_time_open); Sleep(1); err++; } while(rates_total<=0 && err<amount_of_attempts); if(err>=AMOUNT_OF_ATTEMPTS) { Print("There is no accessible history PERIOD_D1"); name_symbol=NULL; return(false); }
Em segundo lugar, o histórico minuto do MetaTrader 5 está disponível igual aos dias de hoje, para que se possa ter um monte de tempo para prosseguir, por isso é necessário visualizar o processo de cálculo. A classe CProgressBar (#include "ClassProgressBar.mqh"), foi desenvolvida para este fim. Ela cria a barra de progresso na janela do gráfico e atualiza-o durante o processo de cálculo.
// We create the progress bar on the char to shot the loading process CProgressBar *progress=new CProgressBar; progress.Create(0,"Loading",0,150,20); progress.Text("Calculation:"); progress.Maximum=rates_total;
O terceiro, em ciclo, utilizando a instrução "novo", criamos o objeto CPriceHistogram, configure-o usando seus métodos e inicialize-o chamando o Init(). Se bem sucedido, adicionamos à lista list_object, se não, deletamos o hist_obj usando instrução de exclusão. A descrição da classe CPriceHistogram será apresentada ainda, ver comentários no código.
// In this cycle there is creation of object CPriceHistogram // its initialization and addition to the list of objects for(int i=0;i<rates_total;i++) {="" cpricehistogram="" *hist_obj="new CPriceHistogram(); // hist_obj.StepHistigram(step); // We set the flag to show text labels hist_obj.ShowLevel(ShowValue); // We set POCs colour hist_obj.ColorPOCs(ControlPoint); // We set colour for inner range hist_obj.ColorInner(InnerRange); // We set colour for outer range hist_obj.ColorOuter(OuterRange); // We set the percent range hist_obj.RangePercent(RangePercent); // hist_obj.ShowSecondaryPOCs((i>=rates_total-DayTheHistogram),PeriodSeconds(PERIOD_D1)); if(hist_obj.Init(day_time_open[i],day_time_open[i]+PeriodSeconds(PERIOD_D1),(i>=rates_total-DayTheHistogram))) list_object.Add(hist_obj); else delete hist_obj; // Delete object if there was an error progress.Value(i); };
O OnTick() é um método chamado quando você recebe uma nova escala para um símbolo. Nós comparamos os valores do número de dias armazenados nas variáveis count_bars com o número de barras diárias retornadas por Barras (Symbol(), PERIOD_D1) e se elas não são iguais nós chamamos forçadamente o método Init () para inicialização da classe, limpando a lista list_object e mudando a variável para NULL name_symbol. Se o número de dias não mudou, o circuito passa por todos os objetos armazenados na classe CPriceHistogram list_object, e executa um método Redesenhar (), para aqueles que são virgens («virgin").
O Deinit() é um método de finalização de classe. No caso de REASON_PARAMETERS (parâmetros de entrada foram alterados pelo usuário) limpamos a lista list_object e definimos a variável name_symbol para NULL. Em outros casos, o especialista não faz nada, mas se você desejar adicionar algo, leia os comentários.
O OnEvent() é um método para o processamento de evento do terminal do cliente. Os eventos são gerados pelo terminal do cliente quando o usuário trabalhar com gráfico. Os detalhes podem ser encontrados na documentação da linguagem do MQL5. Neste Expert Advisor, o evento de gráfico CHARTEVENT_OBJECT_CLICK foi usado. Ao clicar no elemento histograma, ele mostra os níveis de POC secundários e inverte a cor do histograma.
O OnTimer(void) é um método para processamento de eventos de temporizador. Não é utilizado nos meus programas, mas se você desejar adicionar algumas ações temporizadas (por ex. mostrar a hora) - está aqui. Antes de usá-lo é necessário adicionar a seguinte linha para o construtor da classe:
EventSetTimer(tempo em segundos);
E a seguinte linha para o destrutor:
EventKillTimer();
antes de chamar o método Deinit (REASON_CHARTCLOSE ).
Consideramos a classe CExpert, que foi criada para a demonstração dos métodos de classe CPriceHistogram.
//+------------------------------------------------------------------+ //| Class CPriceHistogram | //| Class description | //+------------------------------------------------------------------+ class CPriceHistogram : public CObject { private: // Class variables double high_day,low_day; bool Init_passed; // Flag if the initialization has passed or not CChartObjectTrend *POCLine; CChartObjectTrend *SecondTopPOCLine,*SecondBottomPOCLine; CChartObjectText *POCLable; CList ListHistogramInner; // list for inner lines storage CList ListHistogramOuter; // list for outer lines storage bool show_level; // to show values of level bool virgin; // is it virgin bool show_second_poc; // show secondary POC levels double second_poc_top; // value of the top secondary POC level double second_poc_bottom; // value of the bottom secondary POC level double poc_value; // POC level value color poc_color; // color of POC level datetime poc_start_time; datetime poc_end_time; bool show_histogram; // show histogram color inner_color; // inner color of the histogram color outer_color; // outer color of the histogram uint range_percent; // percent range datetime time_start; // start time for construction datetime time_end; // final time of construction public: // Class constructor CPriceHistogram(); // Class destructor ~CPriceHistogram(){Delete();} // Class initialization bool Init(datetime time_open,datetime time_close,bool showhistogram); // To level value void ShowLevel(bool show){show_level=show; if(Init_passed) RefreshPOCs();} bool ShowLevel(){return(show_level);} // To show histogram void ShowHistogram(bool show); bool ShowHistogram(){return(show_histogram);} // To show Secondary POC levels void ShowSecondaryPOCs(bool show){show_second_poc=show;if(Init_passed)RefreshPOCs();} bool ShowSecondaryPOCs(){return(show_second_poc);} // To set color of POC levels void ColorPOCs(color col){poc_color=col; if(Init_passed)RefreshPOCs();} color ColorPOCs(){return(poc_color);} // To set internal colour of histogram void ColorInner(color col); color ColorInner(){return(inner_color);} // To set outer colour of histogram void ColorOuter(color col); color ColorOuter(){return(outer_color);} // To set percent range void RangePercent(uint percent){range_percent=percent; if(Init_passed)calculationPOCs();} uint RangePercent(){return(range_percent);} // Returns value of virginity of POC level bool VirginPOCs(){return(virgin);} // Returns starting time of histogram construction datetime GetStartDateTime(){return(time_start);} // Updating of POC levels bool RefreshPOCs(); private: // Calculations of the histogram and POC levels bool calculationPOCs(); // Class delete void Delete(); };
Na descrição da classe, eu tentei fazer comentários para as variáveis e métodos de classe. Vamos considerar alguns deles em detalhes.
//+------------------------------------------------------------------+ //| Class initialization | //+------------------------------------------------------------------+ bool CPriceHistogram::Init(datetime time_open,datetime time_close,bool showhistogram)
Este método usa três parâmetros de entrada - a abertura da construção, o tempo de fechamento da construção e a marcação indicando para construção de um histograma, ou apenas os níveis de POCs.
No meu exemplo (classe CExpert), os parâmetros de entrada são passados no dia e hora de abertura da abertura do day_time_open [i] + PeriodSeconds (PERIOD_D1) do próximo dia. Mas quando você usa essa classe, nada impede de perguntar, por exemplo, o horário da sessão da Europa, América ou o tamanho da distância na semana, mês, etc.
//+---------------------------------------------------------------------------------------+ //| Calculations of the histogram and POCs levels | //+---------------------------------------------------------------------------------------+ bool CPriceHistogram::calculationPOCs()
Neste método, a origem de todos os níveis e cálculos de sua construção é método privado fechado, inacessível por fora.
// We get the data from time_start to time_end int err=0; do { //--- for each bar we are copying the open time rates_time=CopyTime(NULL,PERIOD_M1,time_start,time_end,iTime); if(rates_time<0) PrintErrorOnCopyFunction("CopyTime",_Symbol,PERIOD_M1,GetLastError()); //--- for each bar we are copying the High prices rates_high=CopyHigh(NULL,PERIOD_M1,time_start,time_end,iHigh); if(rates_high<0) PrintErrorOnCopyFunction("CopyHigh",_Symbol,PERIOD_M1,GetLastError()); //--- for each bar we are copying the Low prices rates_total=CopyLow(NULL,PERIOD_M1,time_start,time_end,iLow); if(rates_total<0) PrintErrorOnCopyFunction("CopyLow",_Symbol,PERIOD_M1,GetLastError()); err++; } while((rates_time<=0 || (rates_total!=rates_high && rates_total!=rates_time)) && err<amount_of_attempts&&!IsStopped()); if(err>=AMOUNT_OF_ATTEMPTS) { return(false); } poc_start_time=iTime[0]; high_day=iHigh[ArrayMaximum(iHigh,0,WHOLE_ARRAY)]; low_day=iLow[ArrayMinimum(iLow,0,WHOLE_ARRAY)]; int count=int((high_day-low_day)/_Point)+1; // Count of duration of a finding of the price at each level int ThicknessOfLevel[]; // create an array for count of ticks ArrayResize(ThicknessOfLevel,count); ArrayInitialize(ThicknessOfLevel,0); for(int i=0;i<rates_total;i++) {="" double C=iLow[i]; while(C<ihigh[i]) {="" int Index=int((C-low_day)/_Point); ThicknessOfLevel[Index]++; C+=_Point; } } int MaxLevel=ArrayMaximum(ThicknessOfLevel,0,count); poc_value=low_day+_Point*MaxLevel;</amount_of_attempts&&!
Em primeiro lugar, temos os dados de histórico de barras minutos por um determinado período de tempo (iTime [], iHigh[], iLow[]). Então, encontramos o elemento máximo e o mínimo de iHigh[] iand Low[]. Em seguida, calculamos o número de pontos (contagem) do mínimo ao máximo e reservamos a formação ThicknessOfLevel com os elementos ThicknessOfLevel. No ciclo que passamos a cada minuto da vela de Baixo para o Alto e adicionamos os dados da presença do período de tempo, a este nível de preço. Então, encontramos o elemento máximo da formação ThicknessOfLevel, ele será o nível em que o preço foi o tempo mais longo. Este é o nosso nível POC.
// Search for the secondary POCs int range_min=ThicknessOfLevel[MaxLevel]-ThicknessOfLevel[MaxLevel]*range_percent/100; int DownLine=0; int UpLine=0; for(int i=0;i<count;i++) {="" if(ThicknessOfLevel[i]>=range_min) { DownLine=i; break; } } for(int i=count-1;i>0;i--) { if(ThicknessOfLevel[i]>=range_min) { UpLine=i; break; } } if(DownLine==0) DownLine=MaxLevel; if(UpLine==0) UpLine=MaxLevel; second_poc_top=low_day+_Point*UpLine; second_poc_bottom=low_day+_Point*DownLine;
O próximo passo é encontrarmos os níveis POC secundários. Lembre-se que nosso diagrama é dividido. Lembre-se que nosso histograma é dividido em duas faixas, a faixa interna e a externa (exibida em cores diferentes) e a taxa do tamanho é definida em percentagem de tempo no preço a este nível. A taxa dos limites internos são níveis POC secundários.
Depois de encontrar o POC secundário - taxa de porcentagem de bordas, prosseguir à construção do histograma.
// Histogram formation if(show_histogram) { datetime Delta=(iTime[rates_total-1]-iTime[0]-PeriodSeconds(PERIOD_H1))/ThicknessOfLevel[MaxLevel]; int step=1; if(count>100) step=count/100; // Calculate the step of the histogram (100 lines as max) ListHistogramInner.Clear(); ListHistogramOuter.Clear(); for(int i=0;i<count;i+=step) {="" string name=TimeToString(time_start)+" "+IntegerToString(i); double StartY= low_day+_Point*i; datetime EndX= iTime[0]+(ThicknessOfLevel[i])*Delta; CChartObjectTrend *obj=new CChartObjectTrend(); obj.Create(0,name,0,poc_start_time,StartY,EndX,StartY); obj.Background(true); if(i>=DownLine && i<=UpLine) { obj.Color(inner_color); ListHistogramInner.Add(obj); } else { obj.Color(outer_color); ListHistogramOuter.Add(obj); } } }
Deve ser mencionado que, para reduzir a carga no terminal, eu trago à tela um máximo de 100 linhas para cada histograma. Linhas de histograma são armazenadas em duas listas ListHistogramInner e ListHistogramOuter, que são os objetos já conhecidos à nossa classe CList. Mas esses ponteiros são armazenados em uma classe padrão de objetos CChartObjectTrend. Por que duas listas, eu acho que você pode imaginar do título, são capazes de alterar o histograma de cores.
// We receive data beginning from the final time of the histogram till current time err=0; do { rates_time=CopyTime(NULL,PERIOD_M1,time_end,last_tick.time,iTime); rates_high=CopyHigh(NULL,PERIOD_M1,time_end,last_tick.time,iHigh); rates_total=CopyLow(NULL,PERIOD_M1,time_end,last_tick.time,iLow); err++; } while((rates_time<=0 || (rates_total!=rates_high && rates_total!=rates_time)) && err<amount_of_attempts); // If there isn't history, the present day, level is virgin, we hoist the colours if(rates_time==0) { virgin=true; } else // Otherwise we check history { for(index=0;index<rates_total;index++) if(poc_valueiLow[index]) break; if(index<rates_total) // If level has crossed poc_end_time=iTime[index]; else virgin=true; } if(POCLine==NULL) { POCLine=new CChartObjectTrend(); POCLine.Create(0,TimeToString(time_start)+" POC ",0,poc_start_time,poc_value,0,0); } POCLine.Color(poc_color); RefreshPOCs();
Tentei desenhar o CPriceHistogram com todos os métodos necessários, caso sejam insuficientes, você pode adicioná-los e irei ajudá-lo.
Resumo
Mais uma vez eu gostaria de lembrar que o Histograma de preço é confiável, mas a ferramenta é intuitiva, portanto, os sinais de confirmação são necessários para a sua utilização.
Obrigado por seu interesse. Estou pronto para responder a todas as suas perguntas.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/17





- 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
olá,
sou novo em programação e deu erro na compilação, poderiam me ajudar. obrigado
'ClassPriceHistogram.mqh' ClassPriceHistogram.mqh 1 1
'Object.mqh' Object.mqh 1 1
'StdLibErr.mqh' StdLibErr.mqh 1 1
'List.mqh' List.mqh 1 1
'ChartObjectsLines.mqh' ChartObjectsLines.mqh 1 1
'ChartObject.mqh' ChartObject.mqh 1 1
'ChartObjectsTxtControls.mqh' ChartObjectsTxtControls.mqh 1 1
'Delete' - function already defined and has different type ClassPriceHistogram.mqh 375 18
1 error(s), 0 warning(s) 2 1
olá,
sou novo em programação e deu erro na compilação, poderiam me ajudar. obrigado
'ClassPriceHistogram.mqh' ClassPriceHistogram.mqh 1 1
'Object.mqh' Object.mqh 1 1
'StdLibErr.mqh' StdLibErr.mqh 1 1
'List.mqh' List.mqh 1 1
'ChartObjectsLines.mqh' ChartObjectsLines.mqh 1 1
'ChartObject.mqh' ChartObject.mqh 1 1
'ChartObjectsTxtControls.mqh' ChartObjectsTxtControls.mqh 1 1
'Delete' - function already defined and has different type ClassPriceHistogram.mqh 375 18
1 error(s), 0 warning(s) 2 1
Remova o comando "Delete()" que irá funcionar.
Remova o comando "Delete()" que irá funcionar.
Hey guys, i really liked this indicator, i've being learning about market profile for a while and this is the best a found.
I just made a change in the metod of calculating the profile, i used the volume tick instead verifying just if the price past in the point. I did this cuz if you see, negociations and the diferent times haave pounds diferrents, you can see it in the volume histogram. So we can't junt count if price is there add one.
Do you agree?
The change I made showed diferrences beetween in the two mettods