preview
Do básico ao intermediário: Indicadores técnico (II)

Do básico ao intermediário: Indicadores técnico (II)

MetaTrader 5Exemplos |
23 0
CODE X
CODE X

Introdução

No artigo anterior Do básico ao intermediário: Indicadores técnico (I), vimos como poderíamos implementar um código cujo objetivo seria o de demonstrar como utilizar um indicador técnico. Os tais indicadores cujo artigo se propôs a mostrar como utilizar, são aqueles mantidos e presentes dentro do MetaTrader 5. Podendo ser acessados via MQL5 de maneira bem simples e direta.

No entanto, aquele mesmo conteúdo, também se aplica a um outro tipo de indicador. Indicador este que você, meu caro leitor, estará implementado de modo a permitir uma melhor compreensão de algum movimento de mercado. Mas antes de falarmos sobre isto, precisamos ver outras questões, que no meu entender, ajudaram bastante entender, como podemos fazer uso de indicadores pessoais nas mais diversas situações.

Além é claro explicar de uma melhor forma, como também podemos manipular o MetaTrader 5, a fim de que ele nos mostre aquilo que queremos ver ou mesmo fazer.

Para atingir este nível de esclarecimento, será preciso explicar uma série de conceitos, que muitos não entendem, ou se quer tem a noção de que existem e podem ser utilizados aqui na programação MQL5. Quando tais conceitos forem devidamente explicados, e você os tenha compreendido de maneira adequada. Diversas portas irão se abrir para você, meu caro leitor. Isto no que se refere a se tornar um bom programador MQL5.

Ok, então, chegou a hora de dar um tempo nas coisas que podem vir a lhe tirar a atenção, e foca no que será explicado neste artigo.


Indicadores técnico (II)

No artigo anterior, finalizamos vendo o código mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. #property indicator_chart_window
07. #property indicator_applied_price   PRICE_CLOSE
08. #property indicator_buffers         1
09. #property indicator_plots           1
10. #property indicator_type1           DRAW_LINE
11. #property indicator_color1          clrRed
12. #property indicator_style1          STYLE_SOLID
13. #property indicator_width1          1
14. #property indicator_label1          "EMA"
15. //+------------------------------------------------------------------+
16. input uint              def_nPeriods   = 9;           //Period:
17. input ENUM_MA_METHOD    def_MA_Method  = MODE_EMA;    //Method:
18. //+------------------------------------------------------------------+
19. double   Buff_iMA[];
20. int      Handle;
21. //+------------------------------------------------------------------+
22. int OnInit(void)
23. {
24.    SetIndexBuffer(0, Buff_iMA, INDICATOR_DATA);
25.    if ((Handle = iMA(NULL, 0, def_nPeriods, 0, def_MA_Method, _AppliedTo)) == INVALID_HANDLE)
26.    {
27.       Print("Could not start the indicator...");
28.       return INIT_FAILED;
29.    };
30. 
31.    return INIT_SUCCEEDED;
32. };
33. //+------------------------------------------------------------------+
34. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
35. {
36.     ArrayInitialize(Buff_iMA, EMPTY_VALUE);
37.    CopyBuffer(Handle, 0, 0, def_nPeriods, Buff_iMA);
38. 
39.    return rates_total;
40. };
41. //+------------------------------------------------------------------+
42. void OnDeinit(const int reason)
43. {
44.    if (Handle != INVALID_HANDLE) 
45.       IndicatorRelease(Handle);
46. };
47. //+------------------------------------------------------------------+

Código 01

Claro que aqui não irei replicar a explicação que foi dada naquele artigo, a fim de que você compreenda que tipo de resultado será obtido quando este código 01 for executado no MetaTrader 5. Mas, acredito que boa parte de vocês, devam ter ficado um tanto quanto curiosos a respeito de algo. A questão é a seguinte: Suponhamos que você queira adicionar em um mesmo indicador, diversas médias móveis. Isto a fim de não precisar ficar configurando uma por uma toda a vez que for adicionar tais médias em um ativo qualquer. Digo isto pois, alguns operadores tem um modelo previamente estabelecido de medias e indicadores que ficarão visíveis no gráfico. Porém eles não querem ou não gostam de utilizar templates para criar o padrão gráfico. Iremos ver como isto é feito em breve. Mas por hora, vamos nos atentar ao nosso atual artigo.

Assim sendo, muitos destes operadores, tentam criar algum indicador que seja simples de ser feito, e ao mesmo tempo funcional. Porém que permita a colocação de diversas médias móveis ao mesmo tempo. Assim como também remover as mesmas, removendo apenas e tão somente um único indicador.

Isto talvez possa parecer uma daquelas tarefas quase que impossível de ser feita, não é mesmo meu caro leitor? No entanto, com o atual nível de conhecimento demonstrado até este momento nesta série de artigos. Efetuar tal coisa é algo relativamente simples. Entretanto existem alguns macetes que muitos de vocês, talvez não façam a mínima ideia de que podem ser utilizados a fim de acelerar e muito o processo de implementação de tal indicador.

Desta forma, o objetivo inicial a ser visto neste artigo, é justamente entender e demonstrar tais macetes. Não é algo complicado. Porém fará uma enorme diferença na sua forma de codificar. Lhe tornando muito mais produtivo e ao mesmo tempo reduzindo a possibilidades de erros em seu código.

Então vamos começar fazendo o seguinte: Adicionando uma segunda média móvel ao código visto no indicador acima. Porém já que agora o objetivo é montar um indicador previamente estabelecido. O código não será mais como é visto em código 01. Agora iremos usar as coisas de uma maneira um pouco diferente. Isto pode ser visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. #property indicator_chart_window
07. #property indicator_applied_price   PRICE_CLOSE
08. //+----------------+
09. #property indicator_buffers         2
10. #property indicator_plots           2
11. //+----------------+
12. #property indicator_type1           DRAW_LINE
13. #property indicator_color1          clrRed
14. #property indicator_style1          STYLE_SOLID
15. #property indicator_width1          2
16. //+----------------+
17. #property indicator_type2           DRAW_LINE
18. #property indicator_color2          clrBlue
19. #property indicator_style2          STYLE_SOLID
20. #property indicator_width2          2
21. //+------------------------------------------------------------------+
22. double   Buff_iMA_01[],
23.          Buff_iMA_02[];
24. int      Handle_01,
25.          Handle_02;
26. //+------------------------------------------------------------------+
27. int OnInit(void)
28. {
29.    SetIndexBuffer(0, Buff_iMA_01, INDICATOR_DATA);
30.    SetIndexBuffer(1, Buff_iMA_02, INDICATOR_DATA);
31. 
32.    if ((Handle_01 = iMA(NULL, NULL, 9, 0, MODE_EMA, _AppliedTo)) == INVALID_HANDLE)
33.    {
34.       Print("Could not start the indicator...");
35.       return INIT_FAILED;
36.    };
37.    if ((Handle_02 = iMA(NULL, NULL, 20, 0, MODE_SMA, _AppliedTo)) == INVALID_HANDLE)
38.    {
39.       Print("Could not start the indicator...");
40.       return INIT_FAILED;
41.    };
42. 
43.    return INIT_SUCCEEDED;
44. };
45. //+------------------------------------------------------------------+
46. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
47. {
48.     ArrayInitialize(Buff_iMA_01, EMPTY_VALUE);
49.     ArrayInitialize(Buff_iMA_02, EMPTY_VALUE);
50. 
51.    CopyBuffer(Handle_01, 0, 0, 9, Buff_iMA_01);
52.    CopyBuffer(Handle_02, 0, 0, 20, Buff_iMA_02);
53. 
54.    return rates_total;
55. };
56. //+------------------------------------------------------------------+
57. void OnDeinit(const int reason)
58. {
59.    if (Handle_01 != INVALID_HANDLE) 
60.       IndicatorRelease(Handle_01);
61.    if (Handle_02 != INVALID_HANDLE) 
62.       IndicatorRelease(Handle_02);
63. };
64. //+------------------------------------------------------------------+

Código 02

Quando executamos este código 02, e o atrelamos a um gráfico. O resultado é algo parecido com o que é visto logo abaixo.

Imagem 01

Observe atentamente as duas médias móveis vistas nesta imagem 01. Elas irão ter um comportamento muito similar ao que foi visto no artigo anterior. No entanto, apesar de este código 02, funcionar, como é comprovado pela imagem 01. Ele ainda está muito complicado. Pelo menos isto ao meu entender. E o motivo é justamente o fato de que diversas partes deste código estão se repetindo a todo o momento. E pior do que isto. O fato de tais partes estarem sendo repetidas, acaba tornando o código demasiadamente muito chato de ser mantido ou melhorado. Isto tendo como objetivo, adicionar nova médias móveis. Normalmente alguns operadores costumam trabalhar com quatro ou mais médias, além de outros indicadores junto. Então o trabalho que este código 02 irá nos dar, é muito maior do que se fizéssemos uso de alguns macetes a fim de tornar o código bem mais simples e fácil de ser modificado.

O primeiro dos pontos, que você, meu estimado leitor, pode perceber como problema aqui é o fato de que entre as linhas 12 e 15, temos algumas configurações. Praticamente as mesmas configurações são refeitas entre as linhas 17 e 20. E isto porque estamos definindo apenas e somente duas médias móveis. Pense só que forem mais. A próxima questão que também ao meu ver complica de forma inútil o código são as declarações entre as linhas 22 e 25. Note que elas também dependem da quantidade de médias que iremos adicionar ao gráfico.

Consequentemente todas as chamadas, tanto para inicializar, quanto também para acessar o buffer de cada uma das médias, assim como para liberar o próprio manipulador, precisaram ser todas duplicadas. Voltando novamente a frisar que se fossem mais médias, teríamos todas estas chamadas precisando implementadas no código. Ou seja, santa trabalheira.

Mas o pior de tudo mesmo está nas linhas nove e dez. Você pode até bolar forma, como iremos ver em breve, de resolver boa parte destes problemas mencionados acima. No entanto, resolver este problema que é mostrado nas linhas nove e dez é algo bem mais complicado. Isto por que, se você aumentar ou diminuir o número de médias móveis a serem plotadas no gráfico. Precisará mexer nestas duas linhas. As ajustando de maneira correta. Caso isto não seja feito de forma adequada, você poderá vir a ter problemas durante a plotagem no gráfico.

Assim sendo, o objetivo aqui, será lhe mostrar uma alternativa a fim de reduzir todo este trabalho. Fazendo com que o compilador do MQL5, resolva boa parte, se não todos estes pontos para nós. Sendo que a única tarefa que realmente iremos precisar fazer, será o de dizer, quais médias, deverão ser usadas. O resto será história. Pois não iremos nos preocupar com absolutamente mais nada.

Ok, agora fiquei realmente curioso para saber como você irá resolver todos estes pontos. Pois alguns até consigo imaginar como resolver. Porém no caso de outros, como o problema das linhas nove e dez, não faço a mínima ideia de como resolver. Então me acompanhe para aprender como podemos resolver isto. Sendo que o que será visto aqui, é apenas um entre tantos métodos possíveis de se fazer a mesma coisa. Lembre-se o que importa é o resultado. A forma de se chegar nele, pouco importa.

Assim sendo, a primeira coisa a ser feita, será tentar reduzir o número de chamadas a procedimentos ou funções que estejam duplicadas no código. Fazer isto é algo relativamente bem simples e direto, como pode ser visto ao olhar o 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_applied_price   PRICE_CLOSE
08. //+----------------+
09. #property indicator_buffers         2
10. #property indicator_plots           2
11. //+----------------+
12. #property indicator_type1           DRAW_LINE
13. #property indicator_color1          clrRed
14. #property indicator_style1          STYLE_SOLID
15. #property indicator_width1          2
16. //+----------------+
17. #property indicator_type2           DRAW_LINE
18. #property indicator_color2          clrBlue
19. #property indicator_style2          STYLE_SOLID
20. #property indicator_width2          2
21. //+------------------------------------------------------------------+
22. struct stInfos
23. {
24.    double         Buff_iMA[];
25.    int            Handle;
26.    uint           nPeriods;
27.    ENUM_MA_METHOD Method;
28. }Infos[2];
29. //+------------------------------------------------------------------+
30. int OnInit(void)
31. {
32.    Infos[0].nPeriods = 9;
33.    Infos[0].Method = MODE_EMA;
34.    Infos[1].nPeriods = 20;
35.    Infos[1].Method = MODE_SMA;
36.    for (uint c = 0; c < Infos.Size(); c++)
37.    {
38.       SetIndexBuffer(c, Infos[c].Buff_iMA, INDICATOR_DATA);
39.       if ((Infos[c].Handle = iMA(NULL, NULL, Infos[c].nPeriods, 0, Infos[c].Method, _AppliedTo)) == INVALID_HANDLE)
40.       {
41.          Print("Could not start the indicator...");
42.          return INIT_FAILED;
43.       };
44.    }
45. 
46.    return INIT_SUCCEEDED;
47. };
48. //+------------------------------------------------------------------+
49. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
50. {
51.    for (uint c = 0; c < Infos.Size(); c++)
52.    {
53.       ArrayInitialize(Infos[c].Buff_iMA, EMPTY_VALUE);
54.       CopyBuffer(Infos[c].Handle, 0, 0, Infos[c].nPeriods, Infos[c].Buff_iMA);
55.    }
56. 
57.    return rates_total;
58. };
59. //+------------------------------------------------------------------+
60. void OnDeinit(const int reason)
61. {
62.    for (uint c = 0; c < Infos.Size(); c++)
63.       IndicatorRelease(Infos[c].Handle);
64. };
65. //+------------------------------------------------------------------+

Código 03

O resultado deste código 03, quando colocado em um gráfico qualquer, será o mesmo visto na imagem 01. No entanto, note como o código ficou bem mais simples e adequado. Isto por que, eliminamos todos aqueles pontos de chamadas a funções e procedimentos que estavam duplicados. E isto começa a tornar o código muito mais apreciável. Já que se desejarmos adicionar novas médias móveis, precisaremos mudar bem menos coisas. Basicamente precisaremos mexer apenas no que estiver entre as linhas nove e trinta e cinco. Isto por que todo o restante irá se adaptar ao que estiver sendo feito dentro destas linhas mencionadas. Hum, parece que melhorou bastante o trabalho de ajustar e modificar o código para futuras atualizações. Isto é verdade meu caro leitor, mas ainda podemos melhorar isto muito mais.

A próxima melhoria que iremos implementar é um pouco mais complicada, neste primeiro momento. Mas ela é complicada apenas neste momento. Conforme você praticar o que será visto aqui, todas estas coisas passaram a ser muito simples e fáceis de entender.

Então vamos ver o que seria a próxima melhoria a ser realizada aqui. Para entender o que iremos fazer, preciso que você volte ao código 03 e observe o conteúdo presente da linha 32 até a linha 35. Isto que está nestas linhas não precisa necessariamente estar ali. E mais, as variáveis declaradas nas linhas 26 e 27, não precisam ser definidas desta forma.

Por que? Bem o motivo é que uma vez que você esteja querendo criar um indicador contendo determinado conjunto de regras. Estas regras não irão mudar com o tempo. Certo? Sendo assim, não faz muito sentido, que tais valores sejam variáveis. Podemos tornar os mesmos como sendo constantes.

Mas espere um pouco. Como assim? Se transformarmos estes valores em constantes, como iremos fazer para não tornar o código ainda maior? Sinceramente não sei como fazer este tipo de coisa. Bem, é para isto que estamos aqui, meu caro leitor. O objetivo, é justamente lhe mostrar como você pode fazer para manipular um código a fim de o tornar bem mais simples e prático. Nada de ficar ali codificando um monte de coisa, se você pode fazer tudo de maneira muito mais rápida em sem complicações.

Desta maneira, para conseguir o nosso objetivo, iremos modificar este código 03 para o que é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. #property indicator_chart_window
07. #property indicator_applied_price   PRICE_CLOSE
08. #property indicator_buffers         2
09. #property indicator_plots           2
10. //+----------------+
11. #property indicator_type1           DRAW_LINE
12. #property indicator_color1          clrRed
13. #property indicator_style1          STYLE_SOLID
14. #property indicator_width1          2
15. //+----------------+
16. #property indicator_type2           DRAW_LINE
17. #property indicator_color2          clrBlue
18. #property indicator_style2          STYLE_SOLID
19. #property indicator_width2          2
20. //+------------------------------------------------------------------+
21. const struct stAverange
22. {
23.     uint           nPeriods;
24.     ENUM_MA_METHOD Method;
25. }Averange[] =
26. {
27.     {9, MODE_EMA},
28.     {20, MODE_SMA}
29. };
30. //+----------------+
31. struct stInfos
32. {
33.     double   Buff_iMA[];
34.     int      Handle;
35. }Infos[Averange.Size()];
36. //+------------------------------------------------------------------+
37. int OnInit(void)
38. {
39.     for (uint c = 0; c < Averange.Size(); c++)
40.     {
41.         SetIndexBuffer(c, Infos[c].Buff_iMA, INDICATOR_DATA);
42.         if ((Infos[c].Handle = iMA(NULL, NULL, Averange[c].nPeriods, 0, Averange[c].Method, _AppliedTo)) == INVALID_HANDLE)
43.         {
44.             Print("Could not start the indicator...");
45.             return INIT_FAILED;
46.         };
47.     }
48. 
49.     return INIT_SUCCEEDED;
50. };
51. //+------------------------------------------------------------------+
52. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
53. {
54.     for (uint c = 0; c < Averange.Size(); c++)
55.     {
56.         ArrayInitialize(Infos[c].Buff_iMA, EMPTY_VALUE);
57.         CopyBuffer(Infos[c].Handle, 0, 0, Averange[c].nPeriods, Infos[c].Buff_iMA);
58.     }
59. 
60.     return rates_total;
61. };
62. //+------------------------------------------------------------------+
63. void OnDeinit(const int reason)
64. {
65.     for (uint c = 0; c < Averange.Size(); c++)
66.         IndicatorRelease(Infos[c].Handle);
67. };
68. //+------------------------------------------------------------------+

Código 04

Novamente, o resultado da execução deste código 04 continua sendo o que é visto na imagem 01. No entanto, note o que fizemos aqui. Agora temos nesta linha 21 a declaração de uma estrutura constante. Porém diferente do que você possa estar imaginando, aqui NÃO É A ESTRUTURA QUE É CONSTANTE, mas sim a declaração feita na linha 25. Parou geral. Agora quero que você me explique direito esta história. Pois claramente vejo que a declaração está sendo feita na linha 21 e não na linha 25. Então como pode a linha 25 ser uma constante e não a linha 21? Ok, isto de fato merece uma explicação. O problema é que aqui estou colocando o código em um formato mais compacto. Para entender melhor isto, vamos usar um pequeno script. Este é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     struct stInfos
07.     {
08.         uint u32;
09.         double pf64;
10.     };
11. 
12.     const stInfos m1[] = 
13.     {
14.         {10, 1.3},
15.         {15, 3.14}
16.     };
17. 
18.     for (uint c = 0; c < m1.Size(); c++)
19.         Print("[", c, "]:  ", m1[c].u32, "   ", m1[c].pf64);
20. }
21. //+------------------------------------------------------------------+

Código 05

Quando este código 05, for executado, iremos ter como resultado o que é visto na imagem abaixo.

Imagem 02

Agora preste atenção, na linha seis estamos definindo uma estrutura. Esta pode ser utilizada em qualquer variável que viermos a declarar posteriormente. Isto você já deve saber como fazer. Porém, suponhamos que venhamos a desejar uma série de valores que serão constantes. Assim na linha doze, quando formos declarar tais valores, podemos definir o que seria inicialmente como variável, como sendo agora uma constante. Isto não muda o fato de que a declaração da estrutura vista na linha seis, poderia ser utilizada tanto para definir variáveis, quanto também constantes.

Claramente você percebe isto, ao ver as declarações sendo feitas isoladamente. Mas e se a uníssemos como pode ser visto no código 04? O que você diria a este respeito? Obviamente você poderia dizer que a declaração da estrutura passaria e deveria ser considerada como sendo uma constante. Não é mesmo? Porém esta ideia é completamente equivocada. Isto por que, você NÃO ESTÁ ENXERGANDO O CÓDIGO. Mas sim apenas vendo o que está ali. Para que isto fique realmente bem claro em sua mente, meu caro leitor, vamos mexer no código 05, produzindo um pequeno teste, para demonstrar isto. Este novo código pode ser visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     const struct stInfos
07.     {
08.         uint u32;
09.         double pf64;
10.     } m1[] = 
11.     {
12.         {10, 1.3},
13.         {15, 3.14}
14.     };
15. 
16.     stInfos var;
17. 
18.     var.u32 = 5;
19.     var.pf64 = 2.59;
20. 
21.     for (uint c = 0; c < m1.Size(); c++)
22.         Print("[", c, "]:  ", m1[c].u32, "   ", m1[c].pf64);
23.     Print("[ variable ]:  ", var.u32, "   ", var.pf64);
24. }
25. //+------------------------------------------------------------------+

Código 06

E para a surpresa de muitos, quando você executar este código 06, irá obter o resultado que é visto na imagem logo na sequência.

Imagem 03

Mas como assim? Isto não faz o menor sentido, para mim. Se você ainda não entendeu, procure estudar com calma este código 06, experimentado até ver o que acontece. Mas na prática, em bem lá no fundo, aquela palavra const que está aparecendo na linha seis, não está sendo atrelada a declaração da estrutura. Mas sim a declaração do que seria a variável declarada na linha dez. Porém, como existe aquela palavra constante ali na linha seis, antecedendo o que seria a declaração da variável na linha dez. O compilador logo reconhece que temos ali, na linha dez, a declaração de uma constante. Por isto, que na linha 16 podemos declarar as coisas como sendo uma simples variável. Cujo conteúdo deverá obedecer ao conjunto declarado na estrutura da linha seis.

Certo, acho que agora consegui entender. Mas ainda assim isto me parece um tanto quanto confuso. Beleza, existe mais alguma dúvida com relação a esta questão, meu caro leitor? Hum, estou olhando uma coisa aqui, e estou meio sem entender um detalhe nestes códigos. Além desta questão da constante, que depois vou praticar para entender. A questão agora é com relação a esta declaração, ou melhor dizendo, com relação a forma como este array está sendo inicializado. Vejo que você coloca os valores de uma determinada maneira. Por que? Bem, está de fato é uma dúvida bem pertinente. E como até agora isto não foi explicado, acho bastante válido dar uma explicação adequada a este respeito.

Normalmente quando vamos inicializar um array constante, usamos algo que foi explicado no artigo Do básico ao intermediário: Array (II). No entanto, aquilo visto ali, serve apenas e somente para valores discretos. Para estruturas, precisamos ter um outro tipo de cuidado.

Neste caso, como o que é visto nos códigos anteriores, mas vamos nos ater ao código 06. Cada elemento, por assim dizer, seria um bloco que deve conter a própria estrutura. Agora preste atenção pois isto é importante. Normalmente, para deixar o código o mais legível possível, definimos em cada linha um bloco da estrutura. E dentro deste bloco a ordem dos elementos muda o tipo de resultado que iremos obter.

Mas como assim? Bem, meu caro leitor, algumas linguagens como Python, por exemplo, quando você vai declarar algo, você pode informar a qual elemento aquele valor específico está se referindo. Seria algo parecido com o que é visto nas linhas 18 e 19 do código 06. No entanto, diversas linguagens, e nisto inclui o MQL5, a ordem em que os elementos estão sendo declarados em uma estrutura, irá nos dizer, qual deverá ser a ordem que eles deverão aparecer no bloco de definição.

Ou seja, como dentro da estrutura declarada na linha seis do código 06, o primeiro tipo, que está sendo declarado na linha oito, é um valor inteiro, o primeiro dado dentro do bloco na linha 12, TAMBÉM deverá ser um valor inteiro. E não é somente isto, o primeiro elemento dentro do bloco, de fato estará se referindo ao primeiro elemento dentro da própria estrutura. Pode até parecer bobagem. Mas este tipo de conceito, precisa ser levado ao pé da letra. Pois muitos códigos, dão valores errados, justamente por conta de que o programador, digitou o valor de um elemento na posição errada dentro de um bloco. E ao fazer isto, acabamos destruindo completamente o nosso código.

Para que você tenha uma noção do quanto isto é prejudicial. Vamos criar um exemplo bem simples. Onde em um momento temos o bloco sendo criado da maneira correta e em outro de maneira incorreta. Este exemplo pode ser visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     const struct stAverange
07.     {
08.         uint    nPeriods,
09.                 Method;
10.     }Averange[] =
11.     {
12.         {9, MODE_EMA},
13.         {MODE_SMA, 20}
14.     };
15. 
16.     for (uint c = 0; c < Averange.Size(); c++)
17.         Print("[", c, "]:  Periods=> ", Averange[c].nPeriods, "   ", EnumToString((ENUM_MA_METHOD)Averange[c].Method));
18. }
19. //+------------------------------------------------------------------+

Código 07

Quando executado este código 07 irá produzir como resultado algo visto logo a seguir.

Imagem 04

Bem, você pode estar pensando: Mas quem seria tolo o bastante para não se atentar ao fato de que existe algo errado neste código 07? E eu respondo: Todos podemos vir a cometer este tipo de erro meu caro leitor. e por mais estranho que possa parecer, ele é muito mais comum do que você possa imaginar. Aqui claro, estou levando a coisa ao seu extremo. Já que em um caso estamos utilizando um valor numérico inteiro e no outro estamos usando uma enumeração.

No entanto, não se esqueça que uma enumeração nada mais é do que um valor inteiro que está sendo representado por algum tipo de constante em formato de string. Porém devido ao resultado vista na imagem 04. Fica claro que existe algo errado. Porém em uma ampla e vasta gama de casos isto não será tão simples de ser detectado. Por isto, você precisa tomar cuidado quando for declarar um array de constantes que fazem parte de uma estrutura. Já que a ordem dos fatores irá fatalmente modificar imensamente o resultado obtido. Iremos ver isto em um outro momento, quando for explicado a questão sobre matrizes e vetores.

Muito bem, agora que você já tem alguns conceitos, que lhe permite compreender como o código 04 funciona. Podemos passar para o que seria o próximo passo, a fim de buscar uma implementação bem mais adequada. Neste próximo passo, iremos remover uma boa parte do que ainda continua sendo duplicado. Mas vamos fazer isto de uma determinada maneira. Não que seja a melhor, e tão pouco a mais adequada. Mas ao meu ver é a que mais se adequa ao requisito didática. Assim temos como melhoria do código 04 o que é mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. #property indicator_chart_window
07. #property indicator_applied_price   PRICE_CLOSE
08. #property indicator_buffers         2;
09. #property indicator_plots           2;
10. //+------------------------------------------------------------------+
11. const struct stAverange
12. {
13.    uint           nPeriods;
14.    ENUM_MA_METHOD Method;
15.    color          cor;
16.    string         szLabel;
17. }Averange[] = 
18. {
19.    {9, MODE_EMA, clrRed, "exponential of %d"},
20.    {20, MODE_SMA, clrGreen, "arithmetica of %d"}
21. };
22. //+----------------+
23. struct stInfos
24. {
25.    double   Buff_iMA[];
26.    int      Handle;
27. }Infos[Averange.Size()];
28. //+------------------------------------------------------------------+
29. int OnInit(void)
30. {
31.    for (uint c = 0; c < Averange.Size(); c++)
32.    {
33.       SetIndexBuffer(c, Infos[c].Buff_iMA, INDICATOR_DATA);
34.       PlotIndexSetInteger(c, PLOT_DRAW_TYPE, DRAW_LINE);
35.       PlotIndexSetInteger(c, PLOT_LINE_STYLE, STYLE_SOLID);
36.       PlotIndexSetInteger(c, PLOT_LINE_WIDTH, 2);
37.       PlotIndexSetInteger(c, PLOT_LINE_COLOR, Averange[c].cor);
38.       PlotIndexSetString(c, PLOT_LABEL, StringFormat(Averange[c].szLabel, Averange[c].nPeriods));
39.       if ((Infos[c].Handle = iMA(NULL, NULL, Averange[c].nPeriods, 0, Averange[c].Method, _AppliedTo)) == INVALID_HANDLE)
40.       {
41.          Print("Could not start the indicator...");
42.          return INIT_FAILED;
43.       };
44.    }
45. 
46.    return INIT_SUCCEEDED;
47. };
48. //+------------------------------------------------------------------+
49. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
50. {
51.    for (uint c = 0; c < Averange.Size(); c++)
52.    {
53.        ArrayInitialize(Infos[c].Buff_iMA, EMPTY_VALUE);
54.       CopyBuffer(Infos[c].Handle, 0, 0, Averange[c].nPeriods, Infos[c].Buff_iMA);
55.    }
56. 
57.    return rates_total;
58. };
59. //+------------------------------------------------------------------+
60. void OnDeinit(const int reason)
61. {
62.    for (uint c = 0; c < Averange.Size(); c++)
63.       IndicatorRelease(Infos[c].Handle);
64. };
65. //+------------------------------------------------------------------+

Código 08

Agora preste atenção a uma coisa aqui, meu caro leitor. Pois isto que estamos fazendo aqui é algo bem maluco, e que ainda pode ser melhorado. Observe que em relação ao que era o código 04, este código 08, não tem mais aquela infinidade de declarações referentes a propriedades de cada uma das médias que iremos implantar no gráfico. Aqui tudo aquilo foi substituído, por uma série de funções que serão ajustadas conforme um padrão previamente definido.

Observe o conteúdo entre as linhas 34 e 38. Estas linhas fazem de forma dinâmica aquilo que antes era feito de maneira estática, nas declarações vistas no código 04. É bem verdade que esta linha 38, pode lhe parecer bastante estranha. Mas para o compilador ela faz todo o sentido. Por isto, estou trabalhando nela devagar. Para que você de fato consiga compreender o conceito aqui. Note que na linha 16 estamos declarando um novo elemento que irá ficar dentro da estrutura. Este elemento, tem valores diferentes sendo definidos nas linhas 19 e 20. No entanto, preste atenção a estas duas linhas. Elas lhe parecem de alguma forma familiares?

Pois se sim, meus parabéns, pois você vem estudado os artigos e praticado a fim de tentar aprender como fazer as coisas. E para aqueles que não conseguiram entender isto. Estas duas linhas, são na verdade, uma cópia do que seria uma daquelas strings que podemos usar em comandos como PrintFormat ou StringFormat. Isto a fim de formatar uma string de forma a conseguir criar algum tipo de informação com um formato muito específico.

Por estarmos fazendo isto, desta forma nestas linhas 19 e 20, podemos na linha 38, no que seria o primeiro argumento da função StringFormat, usar estas constantes para formatar o código que iremos apresentar depois.

De uma forma ou de outra o resultado final, será exatamente o que podemos ver na imagem 01. Porém, existe uma diferença aqui. Quando você for colocar o indicador pela primeira vez no gráfico. Você irá ver o que é mostrado na imagem logo abaixo.

Imagem 05

Perceba que não temos nenhum tipo de informação que nos indique o que e como podemos ajustar as coisas. Entretanto, uma vez que o indicador tenha sido carregado. Poderemos abrir novamente o mesmo, e o resultado neste caso será o que é visto logo abaixo.

Imagem 06

Perceba que agora, devido ao fato de que o código entre as linhas 34 e 38 terem sido executados, na primeira vez, temos informações que fazem sentido. E isto daqui é algo muito interessante. Justamente pelo seguinte fato. Note que nas linhas 35, 36 e 37 estamos definindo valores constantes. Porém, e esta é a parte interessante, estes mesmos valores serão sobrepostos pelos que forem definidos nesta imagem 06. Ou seja, mesmo que você os defina de uma determinada maneira durante a implementação do código. O MetaTrader 5 irá considerar os valores definidos pelo usuário, como sendo prioritários. Isto permite que tenhamos muito mais flexibilidade do que muitos acreditam que existiria apenas olhando para o código.

Com tudo isto, e pensando com calma, você claramente nota que podemos melhorar ainda mais este código, e com mudanças muitos simples. Tanto que as irei mostrar como sendo um fragmento, que pode ser visto logo abaixo.

                   .
                   .
                   .
10. //+------------------------------------------------------------------+
11. const struct stAverange
12. {
13.    uint           nPeriods;
14.    ENUM_MA_METHOD Method;
15.    color          cor;
16. }Averange[] = 
17. {
18.    {9, MODE_EMA, clrRed},
19.    {20, MODE_SMA, clrGreen}
20. };
21. //+----------------+
                   .
                   .
                   .
37.       PlotIndexSetString(c, PLOT_LABEL, StringFormat("%s of %d", (Averange[c].Method == MODE_EMA ? "Exponential" : "Arithmetica"), Averange[c].nPeriods));
                   .
                   .
                   .

Fragmento 01

Veja que ficou bem mais simples, podendo ter sido já construído desta maneira. Mas como tivemos a oportunidade de mostrar algo diferente, aproveitei a chance para que você pudesse aprender algo novo. Algo que muitos podem não entender caso venha a ver em alguns de meus outros códigos.

Ok, tudo parece muito lindo e maravilhoso. Mas ainda assim temos um ponto de estagnação no nosso código. Mesmo este código 08, que já parece muito adequado, ainda assim, pode melhorar ao ponto que pretendo mostrar neste artigo. Isto por que, ainda temos o problema das linhas oito e nove neste código 08. Você pode notar que precisamos ainda mudar estes números de maneira manual. Ok, mas será que não existe algum outro método, que nos permita agilizar ainda mais as coisas aqui? Sim, meu caro leitor existe sim um outro método. Mas antes de o mostrar, preciso mostrar uma outra coisa. Note que em ambas as linhas, tanto a oito, quanto a nove, temos o mesmo valor sendo definido. Será que não poderíamos mudar isto para algum tipo de definição? Bem, vejamos. Para isto mudamos o código como mostrado no fragmento logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. #define nAveranges                  2
07. //+------------------------------------------------------------------+
08. #property indicator_chart_window
09. #property indicator_applied_price   PRICE_CLOSE
10. #property indicator_buffers         nAveranges;
11. #property indicator_plots           nAveranges;
12. //+------------------------------------------------------------------+
13. const struct stAverange
14. {
15.    uint           nPeriods;
16.    ENUM_MA_METHOD Method;
17.    color          cor;
18. }Averange[] = 
                   .
                   .
                   .

Fragmento 02

Hum, que coisa interessante. Não sabia que podíamos fazer isto. Gostei, já que se precisar mudar algo, agora basta que eu vá e mude o valor visto na linha seis e tudo estará resolvido. Bem, mas pensando bem, isto não me parece assim tão espantoso. Agora que lembro de ter visto no artigo Do básico ao intermediário: Definições (II) que poderíamos usar definições para uma série de coisas. Isto é verdade, meu caro leitor. Mas a ideia de usar a definição é somente um pequeno detalhe para lhe fazer entender uma outra coisa. Agora vamos mudar este fragmento 02, para o que é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. const int nAveranges = 2;
07. //+------------------------------------------------------------------+
08. #property indicator_chart_window
09. #property indicator_applied_price   PRICE_CLOSE
10. #property indicator_buffers         nAveranges;
11. #property indicator_plots           nAveranges;
12. //+------------------------------------------------------------------+
13. const struct stAverange
14. {
15.    uint           nPeriods;
16.    ENUM_MA_METHOD Method;
17.    color          cor;
18. }Averange[] = 
                   .
                   .
                   .

Fragmento 03

Agora preste atenção, pois isto que será feito é algo muito doido. Veja que a única coisa que mudamos entre o fragmento 02 e este fragmento 03 foi a linha seis. Somente isto foi modificado. Porém, se você tentar compilar o código do indicador, irá receber a seguinte mensagem vinda do compilador.

Imagem 07

Ok, temos um erro sendo reportado. E este erro indica que o compilador não conseguiu entender o que precisa ser feito nas linhas dez e onze. No entanto, esta é a parte doida deste sistema que estou lhe explicado como criar meu caro leitor. O compilador não conseguiu entender o que foi feito no fragmento 03. Mas se modificarmos desta vez o código de forma a obter o que é visto logo abaixo. O que irá acontecer?

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. const struct stAverange
07. {
08.    uint           nPeriods;
09.    ENUM_MA_METHOD Method;
10.    color          cor;
11. }Averange[] = 
12. {
13.    {9, MODE_EMA, clrRed},
14.    {20, MODE_SMA, clrGreen},
15.    {50, MODE_SMA, clrBlue},
16.    {200, MODE_SMA, clrBlack}
17. };
18. //+----------------+
19. #property indicator_chart_window
20. #property indicator_applied_price   PRICE_CLOSE
21. #property indicator_buffers         Averange.Size();
22. #property indicator_plots           Averange.Size();
23. //+------------------------------------------------------------------+
24. struct stInfos
25. {
26.    double   Buff_iMA[];
27.    int      Handle;
28. }Infos[Averange.Size()];
29. //+------------------------------------------------------------------+
30. int OnInit(void)
31. {
32.    for (uint c = 0; c < Averange.Size(); c++)
33.    {
34.       SetIndexBuffer(c, Infos[c].Buff_iMA, INDICATOR_DATA);
35.       PlotIndexSetInteger(c, PLOT_DRAW_TYPE, DRAW_LINE);
36.       PlotIndexSetInteger(c, PLOT_LINE_STYLE, STYLE_SOLID);
37.       PlotIndexSetInteger(c, PLOT_LINE_WIDTH, 2);
38.       PlotIndexSetInteger(c, PLOT_LINE_COLOR, Averange[c].cor);
39.       PlotIndexSetString(c, PLOT_LABEL, StringFormat("%s of %d", (Averange[c].Method == MODE_EMA ? "Exponential" : "Arithmetica"), Averange[c].nPeriods));
40.       if ((Infos[c].Handle = iMA(NULL, NULL, Averange[c].nPeriods, 0, Averange[c].Method, _AppliedTo)) == INVALID_HANDLE)
41.       {
42.          Print("Could not start the indicator...");
43.          return INIT_FAILED;
44.       };
45.    }
46. 
47.    return INIT_SUCCEEDED;
48. };
49. //+------------------------------------------------------------------+
50. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
51. {
52.    for (uint c = 0; c < Averange.Size(); c++)
53.    {
54.        ArrayInitialize(Infos[c].Buff_iMA, EMPTY_VALUE);
55.       CopyBuffer(Infos[c].Handle, 0, 0, Averange[c].nPeriods, Infos[c].Buff_iMA);
56.    }
57. 
58.    return rates_total;
59. };
60. //+------------------------------------------------------------------+
61. void OnDeinit(const int reason)
62. {
63.    for (uint c = 0; c < Averange.Size(); c++)
64.       IndicatorRelease(Infos[c].Handle);
65. };
66. //+------------------------------------------------------------------+

Código 09

O que irá acontecer, é que você irá ter como resultado o que é visto na imagem logo abaixo.

Imagem 08

Mas espere um pouco aí. Você não vai sair sem antes me explicar o que foi isto. Como assim? Mas que tipo de código doido e sem noção é este que você criou? Cara até agora a pouco, ele parecia que não iria funcionar. Aí vem você e cria isto? Bem meu caro leitor, este era o ponto em que eu queria chegar. Este código 09, é tão mais, tão prático, que tudo que você precisa fazer para ter mais ou menos médias móveis sendo colocadas no gráfico é adicionar as mesmas na declaração da constante vista na linha seis. Aqui no caso estou declarando quatro medias diferentes, mas se fosse necessário mais ou talvez menos. Bastaria mudar isto aqui neste ponto do código. Ao fazer isto, o compilador irá forçar o código a se adaptar ao que você estivesse declarando ali. E isto de forma que você não precisaria mexer em nenhum outro ponto do código.

Este tipo de conhecimento, não vem de uma hora para outra. Ele vem do fato de que sei como um compilador percebe certas partes do código. Algo que venho praticando e estudando a anos. Observe que apesar do fragmento 03 não funcionar, não significa que se tentarmos fazer algo de uma certa forma, o compilador não irá entender. O fato de que o compilador não ter entendido o fragmento 03 da maneira como queríamos, não o impediu de entender este código 09. E no final, acabamos por gerar algo que antes muitos duvidariam que era possível de ser feito.


Considerações finais

Este foi um artigo relativamente bem divertido. Apesar de em muitos momentos eu não tenha me sentido realmente empolgado. Isto por que, o que foi feito aqui, é algo que para mim é um tedio de tão comum e que já deveria ser de conhecimento de muitos de vocês. No entanto, observando o código de diversas outras pessoas, acabei percebendo que boa parte, não fazia ideia de que isto aqui era possível de ser feito. E se este código visto no final, fosse simplesmente mostrado, sem que uma explicação devida, fosse dada ante chegar a ele. Muitos, com toda a certeza não iriam conseguir entender absolutamente nada do que, mas principalmente o porquê do código 09 funcionar.

Fica então a dica a todos. Procure estudar e praticar de forma a tentar fazer as coisas, de um modo não convencional. Você irá acabar percebendo, que existem soluções bem mais simples, para problemas dos quais parece que todos procuram resolver da mesma maneira. Então divirta-se com os códigos presentes no anexo e nos vemos no próximo artigo.

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
Scripts\Code 01  Demonstração básica
Scripts\Code 02  Demonstração básica
Arquivos anexados |
Anexo.zip (3.6 KB)
Rede neural na prática: Gradiente Descendente Estocástico Rede neural na prática: Gradiente Descendente Estocástico
O artigo explica, na prática, como calcular e aplicar os gradientes de peso e viés no neurônio linear em MQL5, além de apresentar a variante estocástica do gradiente descendente. Discutimos critérios de parada, limitação de iterações e efeitos da amostragem parcial. No terminal do MetaTrader 5, são exibidos resultados e uma plotagem simples. O leitor é orientado a alterar o conjunto de treino e analisar o comportamento.
Mineração de dados da CFTC em Python e modelo de IA com base neles Mineração de dados da CFTC em Python e modelo de IA com base neles
Vamos tentar minerar dados da CFTC, carregar os relatórios COT e TFF via Python, conectar isso às cotações do MetaTrader 5 e a um modelo de IA e obter previsões. O que são os relatórios COT no mercado Forex? Como usar os relatórios COT e TFF para previsão?
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Mineração de dados dos balanços dos bancos centrais e obtenção de um panorama da liquidez global Mineração de dados dos balanços dos bancos centrais e obtenção de um panorama da liquidez global
A mineração de dados dos balanços dos bancos centrais permite obter um panorama da liquidez global do mercado Forex e das principais moedas. Nós unificamos dados do Fed, do BCE, do BOJ e do PBoC em um índice composto e aplicamos aprendizado de máquina para identificar padrões ocultos. Essa abordagem transforma um fluxo bruto de dados em sinais reais de trading, conectando a análise fundamentalista e a análise técnica.