preview
Do básico ao intermediário: Indicador (II)

Do básico ao intermediário: Indicador (II)

MetaTrader 5Exemplos | 21 março 2025, 09:37
111 0
CODE X
CODE X

No artigo anterior Do básico ao intermediário: Indicador (I), começamos a falar de maneira prática, como você precisando utilizar de muito pouco conhecimento, conseguiria criar um indicador muito simples e singelo. Apesar de muitos acreditarem ser necessário uma quantidade monstruosa de código e conhecimento para fazer as coisas acontecerem. Ficou bem evidente que mesmo um iniciante, com algum estudo e esforço consegue criar algo relativamente simples e funcional. E isto de maneira bastante elegante. Já que grande parte do trabalho está sendo jogado nas mãos do MetaTrader 5. A nós cabe apenas a tarefa de implementar de maneira adequada, como um evento deverá ser respondido. Isto para que o MetaTrader 5, possa conseguir saber o que fazer com as demais informações que estamos tratando, durante eventos que possam estar ocorrendo.

Pois bem, você talvez esteja pensando: Mas aquele código que conseguimos criar não parece de fato com algum indicador que já vi anteriormente. Apesar de que estamos conseguindo plotar algo no gráfico. Não é bem aquilo que eu esperava conseguir. Esperava conseguir fazer muito mais coisas.

Ok, meu caro leitor, talvez você possa estar achando tudo isto um tanto quando pouco promissor. Mas devo te lembrar, que conhecimento não se adquire de uma hora para outra. Ele precisa ser cultivado. E o objetivo destes artigos é justamente este. Cultivar e espalhar conhecimento. E não o de dizer: Faça isto, pois irá dar certo, somente desta forma como estou mostrando. Assim sendo, vamos ver até onde chegamos no artigo anterior.


Implementando uma média móvel de X períodos

Bem, no artigo anterior, vimos como poderíamos plotar informações no gráfico. Fizemos isto de uma maneira pudesse ser a simples de entender e que ao mesmo tempo, completamente funcional e bastante didática. No entanto, o objetivo do artigo anterior era justamente mostrar que haveria uma maneira, de fazermos um melhor uso dos recursos presente e disponibilizados pelo MetaTrader 5. Por conta disto não me aprofundei muito em certos critérios ou possibilidades.

Porém, aquele tipo de coisa que foi mostrada no artigo anterior, poderia ser conseguida de várias outras maneiras. No entanto acredito que muitos de fato gostariam de ver como poderíamos implementar um sistema de médias móveis mais próximo do rotineiro. Ou seja, o que muitos colocariam como sendo algo interessante, seria o fato de podermos criar médias moveis que fossem de fato similares ao que vemos. Tipo a famosa média móvel exponencial de nove períodos. Que é famosa justamente por conta de um modelo operacional muito rentável, porém difícil de ser seguido. Apesar de sua extrema simplicidade em termos operacionais.

Ok, então você, meu caro leitor, pode estar pensando, como poderíamos tornar aquele código totalmente sem graça. Que foi implementado no artigo anterior, em um código mais interessante. Isto talvez seja algo bem mais difícil de ser feito. Agora acredito, e tenho certeza, de que você irá ser forçado, a criar algo com muito mais linhas. E não aquela coisa que foi mostrada no artigo anterior.

Pois bem, aceito o desafio. Tentar criar um indicador de médias moveis que venha a necessitar de uma quantidade mínima de código. Quanto menos melhor. Mas apesar de isto ser desafiador para muitos. Eu mesmo acho isto um tanto quanto chato e monótono. Então antes de vermos como podemos fazer isto. Vamos ver o código disponibilizado no anexo do artigo anterior. Este pode ser visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. double   gl_buffer[];
11. //+------------------------------------------------------------------+
12. int OnInit()
13. {
14.    SetIndexBuffer(0, gl_buffer, INDICATOR_DATA);
15. 
16.    return INIT_SUCCEEDED;
17. };
18. //+------------------------------------------------------------------+
19. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
20. {
21.    for (int c = prev_calculated; c < rates_total; c++)
22.       gl_buffer[c] = price[c];
23. 
24.    return rates_total;
25. };
26. //+------------------------------------------------------------------+

Código 01

Acredito que você deve ter estudado e praticado bastante em cima deste código 01. Visto que ele é muito simples e divertido ao ponto de nos explicar coisas que de outras maneiras seriam difíceis de entender. Mas, vamos ao desafio proposto. Como tornar este código capaz de calcular e plotar uma média móvel? Para cumprir este objetivo, primeiro precisamos tomar algumas decisões. Não que elas de fato, sejam necessárias, mas é bom para praticar a respeito de como pensar em um código que queremos implementar.

Primeira decisão a ser tomada: Que tipo de cálculo queremos utilizar? Sim, existe diferenças entre cálculos de média móvel. Existem médias ponderadas e não ponderadas. Esta ponderação pode ser em termos de volume, preço, ou tempo. Entender e saber como escolher isto é importante. No caso de uma média móvel exponencial, ela acaba sendo ponderada pelo tempo, ou número de períodos presentes nela. Uma VWAP seria uma média móvel ponderada pelo volume no preço, ou seria o preço no volume? Bem, quem sabe? De qualquer maneira o tempo não seria levado em consideração. No caso de uma média móvel aritmética, não temos esta ponderação. Sendo o valor calculado de uma maneira que iremos levar em conta apenas um dado e não a variação dele relacionada a outros dados. Naturalmente para simplificar as coisas, chamamos as médias de: Média móvel exponencial e média móvel simples.

É justamente isto de levar um dado a ser relacionado a outros, é que gera ou não a ponderação. Mas não vamos entrar nestes detalhes matemáticos chatos, isto por não ser necessário fazer isto aqui. Porém, precisamos saber, pelo menos a formula do tipo de cálculo, que iremos implementar. Caso contrário, como poderemos, se quer implementar algo, sem nem saber como calcular este algo. Como a média móvel aritmética é muito simples, de calcular, isto por que é só ir somando e subtraindo valores dentro de um dado número de períodos. Vamos ver um caso um pouco mais complicado, ou que muitos acham complicado. Que é justamente a média exponencial.

A formula a ser adotada é vista logo abaixo.

Imagem 01

Nesta imagem 01 temos a expressão para calcular a média exponencial com qualquer número de períodos. Aqui P representa o valor da atual cotação. O valor M representa o valor anterior da média exponencial. Já N representa o número de períodos que serão utilizados na média. Com estas informações já podemos partir para a fase de implementar o cálculo. Antes vou esclarecer um pequeno detalhe, que mencionei a pouco. A média aritmética é calculada somando um X número de valores e dividindo o resultado por este X utilizado.

Porém quanto formos calcular X + 1, ou seja o próximo período, tudo que precisamos fazer é remover da soma o valor da primeira entrada, e somar o valor da nova entrada. O resultado dividimos por X. Por isto que falei que a média aritmética é chata e sem graça. Já que precisamos apenas somar e subtrair. Mas a média exponencial muitos acreditam ser necessário uma quantidade enorme de cálculos. Mas você irá perceber que é quase a mesma coisa da média aritmética.

Ok, então vamos entender uma coisa nesta expressão vista na imagem 01. Para conseguirmos calcular a MME atual, ou médio móvel exponencial, que irei chamar de MME. Precisamos do valor anterior da média. Hum. Isto parece um problema. Já que quando iniciamos o cálculo, NÃO TEMOS ainda este valor. Por isto precisamos de um pequeno subterfugio matemático aqui. O subterfugio é simplesmente fazer M igual a zero. Agora sim podemos implementar o cálculo. Para fazer isto, basta olharmos o código 01 e ver onde precisamos mexer nele. No caso precisamos apenas mexer na linha 22. Mas como não sou sacana e quero que você, meu caro leitor, compreenda que NÃO precisamos de complicar ou fazer coisas estranhas no código. Vou mostrar o código na integra. Este é visto logo na sequência.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. double   gl_buffer[];
11. //+------------------------------------------------------------------+
12. int OnInit()
13. {
14.    SetIndexBuffer(0, gl_buffer, INDICATOR_DATA);
15. 
16.    return INIT_SUCCEEDED;
17. };
18. //+------------------------------------------------------------------+
19. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
20. {
21.    for (int c = prev_calculated; c < rates_total; c++)
22.       gl_buffer[c] = (price[c] - (c ? gl_buffer[c - 1] : 0)) * (2. / (1.0 + 9)) + (c ? gl_buffer[c - 1] : 0);
23. 
24.    return rates_total;
25. };
26. //+------------------------------------------------------------------+

Código 02

Note que a única coisa que mexemos no código, ou melhor dizendo, que modificamos foi a linha 22. NENHUMA OUTRA COISA FOI MODIFICADA. Porém quando executamos o código, podemos ver o que é mostrado logo abaixo.

Imagem 02

Talvez você esteja pensando: Mas será que estamos mesmo vendo uma média exponencial de nove períodos sendo mostrada nesta imagem 02? Bem, de fato é difícil de acreditar que para colocar uma média móvel exponencial, seria preciso tão pouco. Sendo assim, vamos comprovar se realmente estou ou não mostrando algo que podemos acreditar. Para isto, iremos utilizar um indicador, que vem por padrão junto do MetaTrader 5. Assim podemos checar se estamos ou não fazendo as coisas da maneira correta. Isto pode ser visto na animação logo abaixo.

Animação 01

Nesta animação, podemos ver a nossa média da imagem 02, ao fundo. E o indicador de checagem em primeiro plano. Note os valores que estamos utilizando nele. Conformando estes valores, o indicador será colocado no gráfico como é visto na animação. E perfeito. De fato, o código 02 está calculando a média exponencial de nove períodos. Mas como isto foi possível?

Bem, se você vem estudando e praticando os conceitos mostrados nos artigos, vai perceber que estamos simplesmente usando a expressão vista na imagem 01. Porém como foi dito, é necessário efetuar um subterfugio, por conta de que precisamos zerar o primeiro valor na cadeia de cálculos. Por isto a expressão ficou um tanto quanto confusa, à primeira vista. Mas se você desejar, e achar que fica mais simples, pode mudar o código da linha 22. Para algo um pouco menos compacto. Assim o tratador do evento Calculate, fica como mostrado logo abaixo.

                   .
                   .
                   .
18. //+------------------------------------------------------------------+
19. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
20. {
21. #define def_N     9
22.    
23.    for (int c = prev_calculated; c < rates_total; c++)
24.    {
25.       double M = (c ? gl_buffer[c - 1] : 0);
26.    
27.       gl_buffer[c] = (price[c] - M) * (2. / (1.0 + def_N)) + M;
28.    }
29. 
30.    return rates_total;
31. 
32. #undef def_N
33. };
34. //+------------------------------------------------------------------+

Fragmento 01

Neste fragmento 01, temos a mesma coisa que está sendo feita no código 02. Só que usando um pouco mais de linhas. Beleza, mas antes de continuarmos devo alertar a você, meu caro leitor, de que existe um pequeno problema neste código. Porém, não vou explicar que problema é este. Vou deixar você na curiosidade. Assim você com certeza, irá tentar entender, e até irá conseguir construir um conceito bem melhor, a respeito de certas coisas na programação. Entre elas a de que nem sempre, devemos fazer as coisas de uma determinada maneira. Somente porque uma expressão matemática, está nos dizendo para fazer daquela maneira.

Para que o problema deixe de existir, precisamos mudar o código para o que é mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. double   gl_buffer[];
11. //+------------------------------------------------------------------+
12. int OnInit()
13. {
14.    SetIndexBuffer(0, gl_buffer, INDICATOR_DATA);
15. 
16.    return INIT_SUCCEEDED;
17. };
18. //+------------------------------------------------------------------+
19. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
20. {
21.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
22.       gl_buffer[c] = (c ? ((price[c] - gl_buffer[c - 1]) * 2. / (1 + 9)) + gl_buffer[c - 1] : price[c] * 2. / (1 + 9));
23. 
24.    return rates_total;
25. };
26. //+------------------------------------------------------------------+

Código 03

Porém não se preocupe, no anexo, você terá ambos os códigos para poder experimentar e tentar entender que diabos de problema é este que olhando o código parece não fazer sentido. De qualquer maneira, agora acredito que de fato podemos falar de um outro assunto. Você já deve estar curioso e pensando: Cara, mas e se eu desejar utilizar uma média móvel exponencial, com um número diferente de períodos? Irei precisar a todo momento, ter de compilar o código novamente, apenas para poder utilizar um novo valor de período. E isto não parece muito promissor. De fato, meu amigo leitor. Este tipo de implementação que vimos até aqui, apenas atende a um modelo muito específico. Porém sem entender cada ponto implementado até este momento, fica difícil de entender novos pontos que vão surgindo a cada passo dado.

Mas devido a tudo que foi explicado até este dado momento, acredito que você já esteja pronto para podemos ir para o que seria o próximo nível de implementação. Mas para separa as coisas, vamos a um novo tópico.


Interagindo com o usuário

Muito, mas muito raramente, alguém vai desejar implementar um código como o mostrado no tópico anterior. Justamente devido ao fato, de que não podemos mudar o número de períodos de cálculo. Bem, é verdade que existem casos, como por exemplo o cálculo de uma VWAP, onde a média a ser plotada é do tipo atemporal. Porém este seria um caso bastante específico, o que não tira o mérito, ou a necessidade, de se explicar e entender, o que será visto neste tópico.

Aqui iremos ver, como podemos permitir ao usuário, mudar alguns parâmetros de cálculo, sem necessariamente precisar compilar o código novamente. Para conseguir fazer isto, iremos precisar dizer ao compilador MQL5, que desejamos permitir ao usuário, ou a outras aplicações. Informar valores internos usados em nosso código. Ou seja, iremos ter um tipo de constante, que na visão do usuário será uma variável. Mas na visão da nossa aplicação isto que iremos criar, será vista como sendo uma constante. E sim, meu caro leitor, é possível fazer estas mudanças diretamente por meio de outros aplicativos, como iremos ver futuramente. Mesmo que a princípio, tal recurso tenha como objetivo, permitir uma interação mais próxima com o usuário.

Muito bem, para começar, precisamos ajeitar o código 03. Isto por que, da forma como ele está, acabará deixando as coisas um tanto quanto confusas. Assim, apenas por motivos didáticos e não por motivos de performance, iremos mudar o código para o que é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. double   gl_buffer[];
11. //+------------------------------------------------------------------+
12. int OnInit()
13. {
14.    SetIndexBuffer(0, gl_buffer, INDICATOR_DATA);
15. 
16.    return INIT_SUCCEEDED;
17. };
18. //+------------------------------------------------------------------+
19. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
20. {
21.    double k = 2. / (1 + 9);
22. 
23.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
24.       gl_buffer[c] = (c ? ((price[c] - gl_buffer[c - 1]) * k) + gl_buffer[c - 1] : price[c] * k);
25. 
26.    return rates_total;
27. };
28. //+------------------------------------------------------------------+

Código 04

Note que a mudança foi bem simples, apenas com o surgimento da linha 21. Que cria uma constante para permitir ajustar o cálculo da média exponencial. Agora vem a questão: O valor que precisamos mudar aqui é justamente esta nove que podemos ver na linha 21 do código 04. Para fazer isto tudo que precisamos fazer é adicionar uma nova linha a este código 04. Com isto, poderemos dizer qual o período que desejamos utilizar no cálculo da média. Esta mudança pode ser vista logo na sequência.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. input uchar user01 = 9;
11. //+----------------+
12. double   gl_buffer[];
13. //+------------------------------------------------------------------+
14. int OnInit()
15. {
16.    SetIndexBuffer(0, gl_buffer, INDICATOR_DATA);
17. 
18.    return INIT_SUCCEEDED;
19. };
20. //+------------------------------------------------------------------+
21. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
22. {
23.    double k = 2. / (1 + user01);
24. 
25.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
26.       gl_buffer[c] = (c ? ((price[c] - gl_buffer[c - 1]) * k) + gl_buffer[c - 1] : price[c] * k);
27. 
28.    return rates_total;
29. };
30. //+------------------------------------------------------------------+

Código 05

Pronto. Agora tem como o usuário, dizer qual o período da média móvel exponencial que será utilizada. Porém existe um pequeno detalhe ainda a ser explicado. Quando você for colocar este indicador no gráfico, irá se deparar com a imagem logo abaixo.

Imagem 03

Note que estou marcando uma nova aba nesta imagem. Esta aba não existia antes. Mas passou a existir, justamente por conta da linha dez do código 05. Ou seja, este é o tal ponto de interação com o usuário. Permitindo a ele ajustar e configurar algumas constantes que iremos utilizar internamente no código. Ok, até neste ponto, nada de errado, tudo muito lindo e maravilhoso. Porém, ao selecionar a tal nova aba, nos deparamos com a imagem vista logo abaixo.

Imagem 04

E é este o problema. Note que estou destacando uma informação nesta imagem 04. Bem, para nós aqui que estamos desenvolvendo a aplicação. Sabemos muito bem o que este valor irá fazer. Porém, conforme adicionamos mais e mais valores, começa a ficar um tanto quanto confuso, até para quem implementou o código, saber o que cada valor de fato representa. E é aqui onde precisamos recorrer a um outro pequeno detalhe. E este será repassado ao compilador de uma maneira bastante inusitada. Pelo menos no começo achei um tanto quanto estranho. Mas acabei me acostumando.

Observe nesta imagem 04, que a string vista em destaque é a mesma que dá nome a constante vista na linha dez do código 05. E sim, meu caro leitor, na linha dez não estamos declarando uma variável, e sim uma constante. Pois bem, em casos simples, podemos colocar um nome que seja representativo, tanto para nosso código quanto para o usuário da aplicação, como sendo o nome da constante. Porém isto nem sempre se aplica. Já que na maior parte das vezes um pequeno texto a ser mostrado ao usuário é sim o mais adequado. No entanto, como podemos colocar um texto neste ponto que se encontra destacado na imagem 04?

Esta é a parte inusitada. Para fazer isto, precisamos adicionar um comentário, do tipo linha. Como este tipo de comentário, deverá ser obrigatoriamente colocado depois da declaração da constante. Temos que fazer algo parecido com o que é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. input uchar user01 = 9;             //Exponential average periods
11. //+----------------+
                   .
                   .
                   .

Código 06

Observe atentamente este código 06, especialmente a linha dez. Isto que foi adicionado a esta linha, é o que chamamos de comentário de linha. Quando fazemos isto, em uma constante que será apresentada na aba vista na imagem 04, estaremos dizendo ao compilador para utilizar aquele texto, que seria o comentário da linha, com sendo uma string a ser mostrada ao usuário. Para tornar isto bem mais claro e para que você de fato compreenda o que foi dito. Veja o que acontece quando observamos a mesma aba vista na imagem 04, mas utilizando o que é mostrado neste código 06. Isto pode ser observado na imagem abaixo.

Imagem 05

Note que agora, ao observar esta imagem 05, qualquer pessoa saberá que tipo de coisa estará sendo ajustada na aplicação. Facilitando e muito o uso da mesma.

Viram como é muito simples criar um indicador? Foi preciso muita pouca coisa para tornar as coisas realmente funcionais e perfeitamente adequadas, a um determinado tipo de interesse. Existem mais algumas coisas que precisamos, de fato fazer, para que um indicador possa realmente vir a ser mais útil e se integrar de melhor ao MetaTrader 5. Isto para que possamos vir a utilizar ele para outros proposito. No entanto, este tipo de coisa irá ser vista aos poucos. Para que você possa compreender de fato, como e por que, usar esta ou aquela função da biblioteca padrão do MQL5. Isto dentro de um indicador. Pois como você pode ver, precisamos de poucas funções para que o indicador funcione. Porém ele ainda não é um indicador realmente versátil.

Muito bem, esta foi a primeira parte. Vamos agora ver como utilizar a segunda versão de OnCalculate. Isto por que, esta primeira versão, atende a certos critérios. Mas pode ser que precisemos de outras informações. Por conta disto, precisamos da outra versão. Porém para separar as coisas, vamos ver isto em um outro tópico.


Usado a segunda versão de OnCalculate

Nos artigos anteriores, falamos que a função OnCalculate, é a única função dentro da biblioteca padrão do MQL5, que se encontra sobrecarregada. Isto por que, em alguns momentos podemos usar uma versão e em outros precisaremos usar a outra versão. No entanto, além escolher uma ou outra versão, não influencia apenas o que estará na interface do usuário. Também influencia a forma como você meu caro leitor, deverá pensar em termos de implementação. Sem a ajuda do MetaTrader 5, precisamos ter um maior cuidado e atenção durante a implementação. Isto por que, diferente da primeira versão, vista até este momento. Esta segunda versão conta com mais dados que podem ser utilizados. E dependendo da forma como você os decide utilizar, pode ter um ou outro tipo de resultado.

Devido a natureza do que se pode fazer ao utilizar esta segunda versão de OnCalculate. Irei neste momento, apenas mostrar como seria o mesmo código do indicador visto aqui. Mas nesta versão sobrecarregada. Isto por que, é importante que você entenda que existe diferença entre usar uma ou outra versão. Mas as diferenças são criadas por você, como programador. Assim, o mesmo código 06, visto no tópico anterior, ficaria como mostrado logo abaixo. Isto usando a segunda versão do OnCalculate.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. input uchar user01 = 9;             //Exponential average periods
11. //+----------------+
12. double   gl_buffer[];
13. //+------------------------------------------------------------------+
14. int OnInit()
15. {
16.    SetIndexBuffer(0, gl_buffer, INDICATOR_DATA);
17. 
18.    return INIT_SUCCEEDED;
19. };
20. //+------------------------------------------------------------------+
21. int OnCalculate(const int rates_total, const int prev_calculated, const datetime &Time[], const double &Open[], const double &High[], const double &Low[], const double &Close[], const long &TickVolume[], const long &Volume[], const int &Spread[])
22. {
23.    double k = 2. / (1 + user01);
24. 
25.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
26.       gl_buffer[c] = (c ? ((Close[c] - gl_buffer[c - 1]) * k) + gl_buffer[c - 1] : Close[c] * k);
27. 
28.    return rates_total;
29. };
30. //+------------------------------------------------------------------+

Código 07

Agora preste atenção a um detalhe aqui meu caro leitor. Diferente do que acontecia antes, onde podíamos selecionar que tipo de informação seria usada para plotar a média. Aqui, neste código 07, já não será possível fazer isto. O motivo para isto, é que estamos "travando" o cálculo em cima de um dos valores. No caso o valor de fechamento da barra. Todas as outras informações serão ignoradas. Não sendo de fato utilizadas aqui. Mas não é somente isto que mudou. Lembra de que foi dito que a interface com o usuário também mudaria? Pois bem, quando você for colocar este indicador, visto no código 07 no gráfico. Você notará a ausência de uma das abas, como pode ser visto na imagem logo abaixo.

Imagem 06

Note que nesta imagem 06 estou destacando o fato de não termos mais uma das abas que existia antes. E o motivo disto, é que o cálculo do indicador está travado em um determinado tipo de valor. Assim sendo, não será possível que o usuário modifique a origem como era feito antes. No entanto, isto não é de fato um impedimento para usar os demais tipos de cálculos. Podemos dar ao usuário o direito de escolher o tipo de entrada a ser utilizado no cálculo. Para isto, bastará adicionar novas inputs.

Esta parte é bem interessante. Porém como é relativamente muito simples, vamos usar o restante deste artigo, para explicar como fazer isto. Assim você já poderá começar a criar diversas soluções de forma bem interessante e criativa.

Para dar acesso ao usuário, a outros tipos de valores de entrada. Podemos utilizar de diversos métodos diferentes. O meu preferido, é o uso de enumeradores. Isto por que, enumeradores são fáceis de implementar e simples de entender e modificar. Basicamente precisamos de uma pequena sequência de passos para que tudo fique bastante agradável e bem intuitivo. Tanto para você que estará implementado, mas principalmente para o usuário que irá utilizar sua aplicação.

O primeiro passo a ser dado é criar o enumerador. Vamos fazer um bem simples, apenas para demonstrar como se faz. Então o código 07 será modificado para o que é visto logo abaixo.

                   .
                   .
                   .
09. //+----------------+
10. enum Enum_TypeInput {
11.             HIGH,
12.             OPEN,
13.             CLOSE,
14.             LOW
15.                     };
16. //+----------------+
17. input uchar user01 = 9;             //Exponential average periods
18. input uchar user02 = HIGH;          //Data type for calculation
19. //+----------------+
                   .
                   .
                   .

Código 08

Ao executar o código 07, com estas mudanças vistas no código 08, você irá ver o que é mostrado na imagem logo abaixo.

Imagem 07

Epá. Mas não é isto que eu estava querendo fazer. O que eu queria de fato era que os dados, ou tipos definidos na enumeração da linha dez, fosse mostrada para o usuário, e que ele pudesse escolher com base neste tipo de enumeração. Mas porque não deu certo? Bem meu caro leitor, o motivo é o tipo de dado esperado na linha 18. Perceba o seguinte, você declarou a enumeração. E isto está ok, o problema é que a enumeração está sendo convertida para valores inteiros. Isto por conta que o compilador não entendeu o que você estaria querendo fazer. Para corrigir isto, basta mudar o tipo de valor esperado pela constante. Mas também vamos mudar o tipo HIGH para CLOSE, que seria o mais comum na maior parte dos casos. Assim o mesmo código 08 será modificado para o código logo abaixo.

                   .
                   .
                   .
16. //+----------------+
17. input uchar             user01 = 9;             //Exponential average periods
18. input Enum_TypeInput    user02 = CLOSE;         //Data type for calculation
19. //+----------------+
                   .
                   .
                   .

Código 09

Agora depois de aplicar esta modificação vista no código 09 ao código 08. Podemos ver o seguinte resultado, observado logo abaixo, ao executar o código no terminal.

Imagem 08

Veja que funciona. Mas não é somente isto. Devido ao fato de agora o compilador ter compreendido o que você deseja fazer. Podemos também selecionar as coisas utilizando o mesmo texto que se encontra na enumeração declarada na linha dez do código 08. Porém preste atenção meu caro leitor, diferente do que acontecia antes, quando tínhamos a assistência do MetaTrader 5. Agora estamos por nossa própria conta. Ou seja, não é só colocar as coisas como visto acima, que tudo já estará funcionando logo de cara. Precisamos modificar o tratador de evento. No caso, agora vamos para o próximo passo, que é justamente fazer com que o nosso código venha a utilizar a seleção feita pelo usuário. Para fazer isto, bastará modificarmos o código como mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. enum Enum_TypeInput {
11.             HIGH,
12.             OPEN,
13.             CLOSE,
14.             LOW
15.                     };
16. //+----------------+
17. input uchar             user01 = 9;             //Exponential average periods
18. input Enum_TypeInput    user02 = CLOSE;         //Data type for calculation
19. //+----------------+
20. double   gl_buffer[];
21. //+------------------------------------------------------------------+
22. int OnInit()
23. {
24.    SetIndexBuffer(0, gl_buffer, INDICATOR_DATA);
25. 
26.    return INIT_SUCCEEDED;
27. };
28. //+------------------------------------------------------------------+
29. int OnCalculate(const int rates_total, const int prev_calculated, const datetime &Time[], const double &Open[], const double &High[], const double &Low[], const double &Close[], const long &TickVolume[], const long &Volume[], const int &Spread[])
30. {
31.    double   k = 2. / (1 + user01),
32.             price = 0;
33. 
34.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
35.    {
36.         switch (user02)
37.         {
38.             case HIGH   :
39.                 price = High[c];
40.                 break;
41.             case OPEN   :
42.                 price = Open[c];
43.                 break;
44.             case CLOSE  :
45.                 price = Close[c];
46.                 break;
47.             case LOW    :
48.                 price = Low[c];
49.                 break;
50.         }
51.         gl_buffer[c] = (c ? ((price - gl_buffer[c - 1]) * k) + gl_buffer[c - 1] : price * k);
52.    }
53. 
54.    return rates_total;
55. };
56. //+------------------------------------------------------------------+

Código 10

Agora neste código 10, podemos observar que na linha 32 adicionei uma nova variável. Esta tem como objetivo nos permitir controlar as coisas de forma mais simples. Então na linha 36 adicionamos um comando switch a fim de capturar o valor a ser colocado na variável price. Ao fazermos isto, não precisamos de muitas mudanças no código de cálculo. Já que tudo que precisamos fazer é ajustar a linha de cálculo para usar a variável price. Assim como pode ser visto na linha 51. Legal não é mesmo, meu caro leitor? Mas podemos fazer uma última coisa, antes de finalizarmos este artigo.

Observe o seguinte: Na enumeração declarada na linha 10 temos alguns valores, que são claros e podem ser utilizados diretamente na interface. No entanto, pode acontecer de você desejar utilizar um código diferente. Então como poderíamos deixar as coisas claras, tanto para futuros usuários, como também para você? Isto para que a informação de que tipo de valor será usado no cálculo, possa ser facilmente compreendida. Bem, para fazer isto, usamos algo parecido com o que fazemos nas linhas de input. Ou seja, adicionaremos um comentário de linha. Com isto, chegamos ao código visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. enum Enum_TypeInput {
11.             en_HIGH,           //Use maximum prices
12.             en_OPEN,           //Use opening prices
13.             en_CLOSE,          //Use closing prices
14.             en_LOW             //Use minimum prices
15.                     };
16. //+----------------+
17. input uchar             user01 = 9;             //Exponential average periods
18. input Enum_TypeInput    user02 = en_CLOSE;      //Data type for calculation
19. //+----------------+
20. double   gl_buffer[];
21. //+------------------------------------------------------------------+
22. int OnInit()
23. {
24.    SetIndexBuffer(0, gl_buffer, INDICATOR_DATA);
25. 
26.    return INIT_SUCCEEDED;
27. };
28. //+------------------------------------------------------------------+
29. int OnCalculate(const int rates_total, const int prev_calculated, const datetime &Time[], const double &Open[], const double &High[], const double &Low[], const double &Close[], const long &TickVolume[], const long &Volume[], const int &Spread[])
30. {
31.    double   k = 2. / (1 + user01),
32.             price = 0;
33. 
34.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
35.    {
36.         switch (user02)
37.         {
38.             case en_HIGH   :
39.                 price = High[c];
40.                 break;
41.             case en_OPEN   :
42.                 price = Open[c];
43.                 break;
44.             case en_CLOSE  :
45.                 price = Close[c];
46.                 break;
47.             case en_LOW    :
48.                 price = Low[c];
49.                 break;
50.         }
51.         gl_buffer[c] = (c ? ((price - gl_buffer[c - 1]) * k) + gl_buffer[c - 1] : price * k);
52.    }
53. 
54.    return rates_total;
55. };
56. //+------------------------------------------------------------------+

Código 11

Note como o código ficou no final. E é este código que você irá ter no anexo para poder estudar e prática. Ao executarmos ele, iremos ter no terminal do MetaTrader 5, o que pode ser visto logo abaixo.

Imagem 09

Como foi dito, acabamos de ocultar do usuário, toda e qualquer informação referente a forma como o código está estruturado internamente. Para o usuário, nada terá sido de fato modificado. Mas para você, como programador, este código 11, é um pouco mais trabalhoso de ser implementado, já que temos diversas regras e bem menos auxilio do MetaTrader 5, como era feito anteriormente. Mas como cada caso é um caso. Agora você, meu caro e estimado leitor, já sabe como implementar um indicador simples e singelo. Mas que poderá lhe ensinar muito sobre diversas outras coisas.


Considerações finais

Neste artigo mostrei como você, de maneira relativamente simples e fazendo uso de uma série de passos, pode implementar um indicador simples. Claro que aqui não mostrei coisas como deslocamento da linha de plotagem. Mas como este tipo de coisa é muito simples, bastando apenas adicionar mais uma constante no código e depois a utilizar na função de evento OnCalculate. Não vou mostrar como fazer isto. Ficando assim este tipo de coisa, como dever de casa para aqueles que de fato querem praticar e tentar entender ainda mais sobre indicadores.

No próximo artigo iremos abordar uma outra coisa, também relacionada a indicadores. Então até lá.

Arquivos anexados |
Anexo.zip (3.04 KB)
Simulação de mercado (Parte 12): Sockets (VI) Simulação de mercado (Parte 12): Sockets (VI)
Neste artigo, vamos ver como resolver algumas questões e ver alguns problemas que temos ao usar código feito em Python dentro de outros programas. No caso o que mostrarei aqui, é um típico problema que existe, quando você vai usar o Excel junto com o MetaTrader 5. Mas para fazer esta comunicação estaremos usando o Python. Porém existe um pequeno problema nesta implementação. Não em todos os casos, mas em alguns casos específicos e quando o problema ocorre você tem que entender por que ele ocorre. Neste artigo iniciarei a explicação de como resolver tal coisa.
Funcionalidades do Assistente MQL5 que você precisa conhecer (Parte 31): Escolha da função de perda Funcionalidades do Assistente MQL5 que você precisa conhecer (Parte 31): Escolha da função de perda
A função de perda (Loss Function) é uma métrica fundamental nos algoritmos de aprendizado de máquina, que fornece feedback para o processo de aprendizado ao quantificar o quão bem um determinado conjunto de parâmetros se comporta em comparação com o valor-alvo esperado. Vamos explorar os diferentes formatos dessa função na classe personalizada do Assistente MQL5.
Auto-otimização de take-profits e parâmetros do indicador usando SMA e EMA Auto-otimização de take-profits e parâmetros do indicador usando SMA e EMA
Este artigo apresenta um EA avançado para negociação no mercado Forex, que combina aprendizado de máquina com análise técnica. Ele é projetado para operar ações da Apple por meio de otimização adaptativa, gerenciamento de risco e múltiplas estratégias. Testes com dados históricos têm apresentado resultados promissores, embora também tenham evidenciado retrações significativas, indicando potencial para melhorias adicionais.
EA MQL5 integrado ao Telegram (Parte 2): Envio de sinais do MQL5 para o Telegram EA MQL5 integrado ao Telegram (Parte 2): Envio de sinais do MQL5 para o Telegram
Nesta parte do artigo, vamos criar um EA MQL5 integrado ao Telegram que envia sinais de cruzamento de médias móveis para o mensageiro. Descreveremos detalhadamente o processo de geração de sinais de negociação com base nesses cruzamentos, implementaremos o código necessário em MQL5 e garantiremos uma integração contínua. Como resultado, teremos um sistema que envia alertas de negociação em tempo real diretamente para um grupo no Telegram.