Do básico ao intermediário: Sub Janelas (IV)
Introdução
No artigo anterior Do básico ao intermediário: Sub Janelas (III), foi dedicado a explicar como poderíamos tratar de certas situações envolvendo sub janelas. O princípio base daquele artigo, está relacionado com as propriedades que podemos atribuir a um certo indicador. Tais propriedades, nos permite dizer ao compilador como uma determinada sub janela deverá ou não ser criada.
Pois bem, como foi explicado no artigo anterior, existem casos em que NÃO QUEREMOS que nosso indicador venha a ter uma segunda instância sendo criada. Este tipo de situação será melhor explorada em um outro artigo no futuro. Quando vamos passar a fazer uso de certas propriedades, com o objetivo de ter um controle maior sobre o que de fato o MetaTrader 5 deverá fazer.
Portanto ainda temos muitas coisas a serem vista ao que se refere aquilo que considero o básico sobre MQL5. Apesar do MetaTrader 5, ser inicialmente e basicamente voltado e destinado a ser uma plataforma de negociação de mercado. Podemos manipular diversas coisas nele, a fim de conseguir fazer com que ele venha a ter um objetivo final muito diferente.
Lembrando que podemos forçar o MetaTrader 5 a fazer qualquer tipo de coisa. Mas em muitos casos será preciso fazer uso de coisas que estão além do que é fornecido por padrão pelo MQL5. Nestes casos precisaremos ir para o C ou C++. E fazendo uso de um tipo links entre o código MQL5 e o C ou C++. Ao fazermos isto, as portas do paraíso, ou talvez do inferno, irão se abrir para você.
No entanto, esta sequência de artigos, não irá entrar neste campo. Já que considero o uso de outras linguagens, como C e C++, para expandir ainda mais o controle que o MQL5, tem sobre o MetaTrader 5, um material realmente avançado. Coisa que não será abordada aqui.
Sub Janelas (IV)
No artigo anterior, vimos algo que nos permitiria cria o código visto logo abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_separate_window 07. #property indicator_height 50 08. #property indicator_plots 0 09. //+------------------------------------------------------------------+ 10. int OnInit(void) 11. { 12. IndicatorSetString(INDICATOR_SHORTNAME, "Test 123."); 13. 14. return INIT_SUCCEEDED; 15. }; 16. //+------------------------------------------------------------------+ 17. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 18. { 19. return rates_total; 20. }; 21. //+------------------------------------------------------------------+
Código 01
E apesar de todos aqueles códigos vistos no artigo anterior, serem funcionais, ou seja, podem ser executados dentro do MetaTrader 5. Durante a fase de compilação, um ou outro, pode vir a fazer o compilador disparar algum alerta. Isto pode ser resolvido, adicionando o que é visto na linha oito, deste código 01. Como este indicador visto acima, é o que considero como sendo um indicador vazio. Ele é ideal para demonstrar e estudar cada uma das propriedades de indicador. Agora quando digo que um indicador é vazio, é quando ele não faz absolutamente nada, ou não tem nenhuma funcionalidade prática, quando é colocado no gráfico. Como não estaremos plotando nenhuma linha ou curva no gráfico, isto ao utilizar este código 01, para evitar do compilador venha a disparar algum tipo de alerta, indicamos o número de plots como zero.
Muito bem, como foi visto no artigo anterior, a linha seis deste código 01, informará ao MetaTrader 5, que ao tentar utilizar este indicador no gráfico, o mesmo necessitará ser colocado em uma sub janela. Podendo esta ser ou não criada, conforme foi demonstrado nos artigos anteriores. E a linha sete irá informar qual é a dimensão desta sub janela, caso a mesma precise ser criada. Agora com relação a estas propriedades do indicador, creio que nenhum de vocês deva ter algum tipo de dúvida. Já que tudo isto é algo bastante simples, claro e direto.
O que preciso que você, entenda é que este código 01, é a base para um outro tipo de abordagem que podemos utilizar. A apesar de que inicialmente este tipo de coisa ser um tanto quanto confusa. A mesma nos permite ter um controle muito maior sobre o que estará ocorrendo em certas situações, que de outra maneira seria muito mais complicadas de serem trabalhadas.
Para que você consiga entender o tipo de problema que podemos resolver, ao assimilar de maneira ampla o que este código 01 faz. Preciso que você tenha compreendido o que foi mostrado nos ultimos artigos desta sequência. Lá foi demonstrado que o MetaTrader 5 consegue evitar que um indicador venha a ter mais de uma instância, em um mesmo gráfico, caso suas propriedades não tenham sido modificadas. Isto garante que não haverá desperdício de recursos de forma desnecessária. Porém, o mesmo não se aplica quando passamos a fazer uso da propriedade que informa a necessidade de uma sub janela. Neste tipo de situação, o MetaTrader 5, passa a ignorar o fato de já existir uma outra instância aberta, e abrirá novas à medida que o usuário, ou operador, adicionar o mesmo indicador novamente ao gráfico. Tudo isto foi explicado em minucias nos artigos anteriores. No entanto, existe uma forma de contornarmos isto. Impedindo, pelo menos de maneira geral, que uma nova instância de um certo indicador que tenhamos implementado venha a ser colocado no gráfico. E isto quando estamos nos referindo ao uso de sub janelas.
Para entender como podemos fazer isto, precisamos recorrer a documentação do MQL5. Pois lá é explicado como isto pode feito. Se você olhar com calma, irá encontrar a função ChartIndicatorAdd. Esta função é muito interessante, apesar de que apenas olhando a documentação ela possa parecer uma função como qualquer outra. E o fato de você, talvez não imaginar usos fora do esperado para esta função, acaba por restringir muito do que você conseguirá fazer. Tornando muitas das vezes até dificil entender por que o código tem um certo comportamento. Mas antes de olharmos isto, quero que você preste atenção a uma observação feita na própria documentação. E para facilitar explicar o entendimento. Abaixo podemos ver na íntegra, uma parte importante, o que é dito na documentação, justamente sobre esta função que iremos usar em breve.
Observação
Se um indicador deve ser elaborado numa sub janela separada (por exemplo, construindo um iMACD ou um indicador personalizado com propriedade especificada #property indicator_separate_window) é aplicada à janela de gráfico principal, não pode ser visível embora ainda estará presente na lista de indicadores. Isto significa que a escala do indicador é diferente da escala do gráfico de preço, e aplicado ao valor do indicador não se enquadra na faixa visualizada do gráfico de preço. Neste caso, GetLastError() retorna código zero indicando a ausência de um erro. Os valores de tal indicador “invisível” podem ser vistos na Janela de Dados (Data Window) e recebidos a partir de outras aplicações MQL5
Em resumo o que está sendo dito na documentação, é que, podemos carregar um indicador, que é feito para se utilizar uma sub janela, dentro da janela principal. Porém este não será visível, e não irá criar uma sub janela para sua apresentação. Caso isto não venha a ser devidamente informados durante a declaração da função ChartIndicatorAdd.
Não compreender logo de cara, o que está sendo explicado na documentação, é algo perfeitamente normal. Muitos bons programadores tem esta dificildade no começo. Isto por que, a documentação visa explicar de forma simplificada, que tipo de comportamento é esperado. E não algo que talvez você esteja querendo fazer, porém não foi pensado no momento que o sistema foi criado. E isto serve para qualquer linguagem de programação. Para quem está começando, muitas informações presentes na documentação podem parecer bem confusas. Mas com a experiência, você irá conseguir capturar da documentação, informações valiosas para conseguir construir algo fora do comum. Justamente por saber disto, e entender a dificuldade de muitos em utilizar a documentação, é que de vez em quando, crio uma ligação entre a explicação do artigo, com o que pode ser visto na documentação. Assim você com o tempo, acaba conseguindo entender qualquer explicação dada ali, podendo assim caminhar com suas próprias penas. Por este motivo, podemos nos aprofundar um pouco mais na explicação a respeito do que foi dito, isto para que de fato você venha a entender o que está sendo expresso na documentação.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_chart_window 07. #property indicator_plots 0 08. //+------------------------------------------------------------------+ 09. int OnInit(void) 10. { 11. IndicatorSetString(INDICATOR_SHORTNAME, "Test 456S."); 12. 13. return INIT_SUCCEEDED; 14. }; 15. //+------------------------------------------------------------------+ 16. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 17. { 18. return rates_total; 19. }; 20. //+------------------------------------------------------------------+
Código 02
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_chart_window 07. #property indicator_plots 0 08. //+------------------------------------------------------------------+ 09. int OnInit(void) 10. { 11. IndicatorSetString(INDICATOR_SHORTNAME, "Test 456."); 12. ChartIndicatorAdd(0, 0, iCustom(NULL, NULL, "Tutor\\Code 01")); 13. 14. return INIT_SUCCEEDED; 15. }; 16. //+------------------------------------------------------------------+ 17. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 18. { 19. return rates_total; 20. }; 21. //+------------------------------------------------------------------+
Código 03
Ok, agora preste atenção a alguns detalhes aqui neste código 03. Observe que na linha doze estamos fazendo uso da função ChartIndicatorAdd. Porém, aqui não estamos efetuando nenhum teste para checagem de erros em tempo de execução, o famoso RUN-TIME. Justamente por conta disto, você precisa tomar alguns cuidados ao tentar executar este código 03 de maneira local. Primeiro, garanta que o código 01 tenha de fato sido compilado. Isto para garantir que quando a linha doze, deste código 03 venha a ser executado, o MetaTrader 5 tenha acesso ao executável do indicador 01. Segundo você pode notar que dentro da função ChartIndicatorAdd, estou fazendo uso de uma chamada a iCustom. Esta chamada tem como objetivo criar uma referência a um indicador customizado. Ou seja, ela nos permite estender, ou melhor dizendo, utilizar indicadores além dos que já são oferecidos pelo MetaTrader 5, dentro da linguagem MQL5.
No artigo Do básico ao intermediário: Indicador (V) começamos a falar sobre estes indicadores, que seriam os tais indicadores técnicos. Aqui estamos estendendo aquele mesmo assunto. Muito bem, neste ponto, é preciso tomar cuidado, para que o diretório e o nome do indicador, a ser carregado por iCustom, de fato estejam corretos. No anexo, a estrutura de diretórios a ser utilizada já estará dentro do esperado. Sendo assim, para testar este código 03, não mude a estrutura, salvo o fato de você entender o que está realmente fazendo. Caso contrário, o resultado final será diferente do que será apresentado aqui.

Animação 01
Mas o que foi isto ? Não entendi. Será que o indicador visto no código 03, não adicionou o indicador 01 ao gráfico ? Vamos checar isto para ver o que aconteceu. Para tal, bastará que venhamos a abrir a lista de indicadores presentes no gráfico e verificar quais estão presentes ali. Isto é visto na imagem logo abaixo.

Imagem 01
Que coisa estranha. De fato, o indicador 03 conseguiu carregar o indicador 01 para o gráfico. Porém, o indicador 01 não criou a sub janela como era esperado. Ou melhor dizendo, eu imaginava que quando o indicador 01 fosse executado, ele deveria criar uma sub janela. Hum, espere um pouco. Será que este indicador 01 está mesmo sendo executado ? Já que ao meu ver isto que aconteceu não faz o menor sentido. De fato estou um tanto quanto confuso.
Por isto é importante que você procure utilizar todo o conhecimento demonstrado nestes artigos, meu amigo leitor. E sempre procure fazer seus próprios testes locais, a fim de entender os por menores. Já que qualquer dúvida não sanada neste estágio do aprendizado, irá no futuro cobrar o seu preço. De qualquer maneira, quando você procurar analisar o que está acontecendo aqui, irá notar que o indicador 01, além de estar sendo carregado, também está sendo executado. Porém, e esta é a parte importante, ele não estará sendo apresentado no gráfico. Justamente devido ao fato de que no código 03 não estamos pedindo para que ele seja apresentado. E é isto que o texto presente na documentação explica.

Imagem 02
Esta região destacada na imagem 02 é justamente a parte que nos interessa. Perceba o seguinte: Aqui está sendo informado, que quando um indicador for adicionado usando para isto a função ChartIndicatorAdd, precisamos indicar a sub janela na qual ele deverá ser adicionado. Preste muita atenção a esta informação, meu caro leitor. Pois dependendo do tipo de coisa que você esteja planejando fazer, e isto via código automatizando assim algum tipo de estratégia. Entender de maneira clara e objetiva, o que está sendo destacado nesta imagem 02, pode ser a diferença entre seu código funcionar ou não funcionar, da forma como você haveria planejado.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_chart_window 07. #property indicator_plots 0 08. //+------------------------------------------------------------------+ 09. int OnInit(void) 10. { 11. IndicatorSetString(INDICATOR_SHORTNAME, "Test 456."); 12. ChartIndicatorAdd(0, (int)ChartGetInteger(0, CHART_WINDOWS_TOTAL), iCustom(NULL, NULL, "Tutor\\Code 01")); 13. 14. return INIT_SUCCEEDED; 15. }; 16. //+------------------------------------------------------------------+ 17. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 18. { 19. return rates_total; 20. }; 21. //+------------------------------------------------------------------+
Código 04
Agora foco total no que será explicado. Pois isto irá ser de suma importância para entender o que iremos fazer a seguir. Note que a única diferença entre o código 03 e este código 04, é justamente o segundo argumento presente na função ChartIndicatorAdd, que pode ser vista na linha doze de ambos os códigos. Porém, e esta é a parte importante, esta simples diferença é mais do que o suficiente para fazer com que o executável do indicador tenha um comportamento completamente diferente do que foi visto na animação 01.

Animação 02
Note que coisa curiosa. Diferente do que acontecia antes, agora de fato uma nova janela está sendo criada, como esperado. E ao olhar a lista de indicadores, poderemos ver o resultado logo abaixo.

Imagem 03
Legal. Mas a pergunta é, por que funcionou agora e não funcionou antes ? A resposta é: Que se você olhar o código 03, irá notar que o segundo argumento passado para a função ChartIndicatorAdd, diz para o MetaTrader 5, adicionar o indicador naquilo que seria a janela principal. Como o indicador visto no código 01 ESPERA E NECESSITA de uma sub janela, o mesmo não é mostrado na tela. Mesmo que ele estivesse plotando alguma informação importante, ele NÃO SERIA PLOTADO. Ficando invisível para o usuário ou operador que estivesse olhando o gráfico.
Porém, já no código 04, no mesmo argumento, que antes apontava para a janela principal. Agora estamos pedindo para que o MetaTrader 5, verifique e nos informe, a quantidade de sub janelas presentes no gráfico. E que venha a adicionar o indicador informado, no terceiro argumento, naquilo que seria a próxima sub janela. Por conta disto, este código 04, consegue fazer com que o código 01 crie uma nova sub janela. E este tipo de coisa é muito útil, nos permitindo fazer diversas coisas bem legais. Que iremos ver e explorar em um outro momento.
Agora antes de finalizarmos este artigo, quero lhe explicar uma última coisa a respeito desta função ChartIndicatorAdd. Considere isto como um bônus extra. Se você notou e prestou atenção ao que foi feito até aqui, deve ter percebido uma coisa. Em todos os casos, podemos conseguir resultados bem interessantes e de uma forma muito simples. E tudo isto, com muito pouco trabalho. Porém, em um caso indicamos que o indicador a ser adicionado seria colocado na janela principal. E no outro caso, uma nova sub janela deveria ser criada. Pergunta: O que acontece se já tivermos uma sub janela no gráfico e fizermos o indicador ser carregado e colocado dentro dela ? Calma lá. Onde você está querendo chegar, com esta hipótese de utilização ?
Bem, a ideia que pretendo que você entenda foi vista em um outro artigo, aqui nesta mesma sequência. O artigo em questão é Do básico ao intermediário: Sub Janelas (II). Naquele artigo, foi demonstrado que poderíamos fazer com que um indicador utilizasse valores calculados por outro indicador a fim de criar um terceiro indicador. A ideia em si é bem simples e bastante interessante. Porém fazer isto de maneira automática, assim que adicionamos o indicador ao gráfico, demanda você saber exatamente o que está sendo implementado.

Animação 03
Feito isto, agora vamos criar um novo indicador, e você logo irá entender o motivo. Este é visto no código logo abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_chart_window 07. #property indicator_plots 0 08. //+------------------------------------------------------------------+ 09. int OnInit(void) 10. { 11. for (int c0 = 0; c0 < (int)(ChartGetInteger(0, CHART_WINDOWS_TOTAL)); c0++) 12. for (int c1 = (ChartIndicatorsTotal(0, c0) - 1); c1 >= 0; c1--) 13. PrintFormat("In the sub window [%d] was found this indicator >>%s<<", c0, ChartIndicatorName(0, c0, c1)); 14. 15. return INIT_SUCCEEDED; 16. }; 17. //+------------------------------------------------------------------+ 18. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 19. { 20. return rates_total; 21. }; 22. //+------------------------------------------------------------------+
Código 05
O objetivo deste código 05 é simplesmente no dizer o nome dos indicadores presentes no gráfico. Isto já foi explicado nos artigos anteriores. Mas aqui iremos dar um passo a diante do que foi visto lá. Ok, executando este código 05, teremos como resposta o resultado visto na imagem logo abaixo.

Imagem 04
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_chart_window 07. #property indicator_plots 0 08. //+------------------------------------------------------------------+ 09. int OnInit(void) 10. { 11. int index = -1; 12. 13. for (int c0 = 0; (index < 0) && (c0 < (int)(ChartGetInteger(0, CHART_WINDOWS_TOTAL))); c0++) 14. index = (ChartIndicatorName(0, c0, 0) == "StdDev(20)" ? c0 : index); 15. 16. IndicatorSetString(INDICATOR_SHORTNAME, "Demo 123."); 17. if (index >= 0) 18. ChartIndicatorAdd(0, index, iCustom(NULL, NULL, "Examples\\Custom Moving Average", 20, 0, 0, PRICE_CLOSE)); 19. 20. return (index < 0 ? INIT_FAILED : INIT_SUCCEEDED); 21. }; 22. //+------------------------------------------------------------------+ 23. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 24. { 25. return rates_total; 26. }; 27. //+------------------------------------------------------------------+
Código 06
Ok, agora antes de vermos o resultado da execução deste código 06. Preciso explicar uma coisa a respeito dele. Observe na linha dezoito qual indicador estamos utilizando. No caso estou fazendo uso de um indicador, que é mantido e está presente no próprio MQL5. Isto facilita bastante as coisas, reduzindo bastante a quatidade de coisas a serem explicadas aqui. Contudo, isto não fecha totalmente o cenário. Tornando assim o código 100% funcional. E o motivo é simples. Estão vendo o último argumento da chamada iCustom ? Pois bem, este argumento, PRICE_CLOSE, irá fazer com que o indicador que será colocado, venha a calcular os dados com base nas informações de cotação do gráfico principal. Porém para que venhamos a utilizar os valores de cálculo do indicador adicionado na animação 03, precisamos que este argumento seja outro. Mas para fazer isto, não basta mudar ele, precisamos seguir por um outro caminho. E este caminho será visto em um outro momento. Já que entender o motivo é necessário explicar uma outra coisa da qual ainda não foi devidamente mencionada aqui, nesta série de artigos. Então tenha paciência.

Imagem 05
Perceba que ao adicionarmos este código 06 ao gráfico, precisaríamos que o indicador carregado pela linha dezoito, tivesse o mesmo desenho que esta linha preta na imagem 05. Porém, devido a justamente a questão mencionada acima, ele irá ficar diferente, necessitando um ajuste por parte do usuário ou operador. Veja nas animações abaixo como isto seria feito.

Animação 04
Bem note que de fato o código 06 consegui adicionar o indicador desejado. No entanto, os valores de cálculo estão errados, já que ele está usando os valores oriundos da cotação do ativo. Assim precisamos fazer um pequeno ajuste.

Animação 05
Considerações finais
Neste artigo, foi demonstrado como trabalha de uma maneira um pouco mais avançada naquilo que rege o uso de sub janelas. Apesar de que, o que foi visto aqui é apenas a parte que considero ser a base de todo um desenvolvimento mais profundo. O fato é que entender isto, irá lhe ajudar a utilizar de uma forma mais adequada os recursos presentes no MetaTrader 5. Se bem que para conseguir fazer isto precisamos utilizar o MQL5 para um melhor controle do que nos será apresentado.
| Arquivo MQ5 | Descrição |
|---|---|
| Indicators\Code 01 | Demonstração básica |
| Indicators\Code 02 | Demonstração básica |
| Indicators\Code 03 | Demonstração básica |
| Indicators\Code 04 | Demonstração básica |
| Indicators\Code 05 | Demonstração básica |
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.
Caminhe em novos trilhos: Personalize indicadores no MQL5
Automatizando Estratégias de Trading em MQL5 (Parte 9): Construindo um Expert Advisor para a Estratégia Asian Breakout
Está chegando o novo MetaTrader 5 e MQL5
Automatizando Estratégias de Trading em MQL5 (Parte 8): Construindo um Expert Advisor com Padrões Harmônicos Butterfly
- 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