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

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

MetaTrader 5Exemplos |
223 0
CODE X
CODE X

Introdução

No artigo anterior Do básico ao intermediário: Herança, falamos sobre como utilizar herança em uma programação estruturada. Como não quero colocar muita informação em cima de mais informação. Isto para não lhe deixar completamente atordoado com tanta coisa para ser absorvida. Neste artigo, vamos trabalhar em algo um pouco mais simples. Pelo menos algo que você poderá estudar e praticar em paralelo com o que foi mostrado nos artigos anteriores.

Como sei que aquele assunto abordado, pode ser um tanto quanto complicado, no início para ser corretamente compreendido. E já que foram seis artigos seguidos, de material bastante denso. Vamos dar uma relaxada e ver algo um pouco mais simples e prático.

Nos artigos sobre indicadores, tendo sido Do básico ao intermediário: Indicador (IV), o último naquela pegada. Vimos como poderíamos plotar alguma coisa diretamente no gráfico, fazendo uso de uma implementação completamente estática e muito simples. Além é claro, de ser uma forma muito direta de se criar um indicador. No entanto, apesar de aquele formato mostrado, naqueles artigos em específico, terem se mostrado, ser o formato ideal, para praticamente quase todo indicador, que você possa a vir a construir. Não ficamos de fato limitados a somente aquilo. Temos também a possibilidade de criar indicadores dinâmicos. Se é que podemos classificar eles desta forma.

Porém para que você, meu caro leitor, possa vir a entender, por que considero aquele formato anterior, como sendo um formato estático. E como ele se diferenciaria de um formato de criação dinâmica. Preciso explicar algumas coisas. Mas para fazer isto de maneira adequada vamos a um novo tópico.


Diferença entre um indicador estático e um dinâmico

Muito provavelmente, muitos outros programadores não venham a concordar com o que irei dizer. Mas isto, é um mero detalhe, visto que cada um pode ter uma opinião. E uma opinião não necessariamente invalida outras. Desde que fique bem configurado e explicado, o motivo pela qual esta ou aquela opinião ter sido formada.

Para entender, o motivo pelo qual, chamo aqueles indicadores vistos anteriormente de indicadores estáticos. Precisamos entender o próprio código dos mesmos. É bem verdade, que não entrei em muitos detalhes na época. Mesmo porque, aquele tipo de implementação é bem simples de entender. Mas para entender o que será visto daqui a pouco. Precisamos primeiro entender aqueles códigos anteriores.

Vamos então usar um daqueles códigos como exemplo. Logo abaixo, você pode ver um que iremos utilizar, para iniciar a explicação sobre certas coisas.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1       DRAW_COLOR_CANDLES
05. #property indicator_color1      clrRed, clrRoyalBlue, clrGreen
06. //+----------------+
07. #property indicator_buffers     5
08. #property indicator_plots       1
09. //+----------------+
10. double  gl_Buff_High[],
11.         gl_Buff_Open[],
12.         gl_Buff_Close[],
13.         gl_Buff_Low[],
14.         gl_Buff_Color[];
15. //+------------------------------------------------------------------+
16. int OnInit()
17. {
18.    SetIndexBuffer(1, gl_Buff_High, INDICATOR_DATA);
19.    SetIndexBuffer(0, gl_Buff_Open, INDICATOR_DATA);
20.    SetIndexBuffer(3, gl_Buff_Close, INDICATOR_DATA);
21.    SetIndexBuffer(2, gl_Buff_Low, INDICATOR_DATA);
22.    SetIndexBuffer(4, gl_Buff_Color, INDICATOR_COLOR_INDEX);
23. 
24.    return INIT_SUCCEEDED;
25. };
26. //+------------------------------------------------------------------+
27. 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[])
28. {
29.    static double  high = DBL_MIN,
30.                   low = DBL_MAX;
31. 
32.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
33.    {
34.       gl_Buff_High[c] = High[c];
35.       gl_Buff_Open[c] = Open[c];
36.       gl_Buff_Close[c] = Close[c];
37.       gl_Buff_Low[c] = Low[c];
38. 
39.       gl_Buff_Color[c] = (Open[c] > Close[c] ? 0 : 2);
40.       if ((c - 1) > 0)
41.       {
42.          high = (High[c - 1] > high ? High[c - 1] : high);
43.          low = (Low[c - 1] < low ? Low[c - 1] : low);
44.          gl_Buff_Color[c] = ((high > High[c]) && (low < Low[c]) ? 1 : gl_Buff_Color[c]);
45.          if (gl_Buff_Color[c] != 1)
46.          {
47.             high = DBL_MIN;
48.             low = DBL_MAX;
49.          }
50.       }
51.    }
52. 
53.    return rates_total;
54. };
55. //+------------------------------------------------------------------+

Código 01

Este código 01, quando executado irá transformar o gráfico em um indicador. No caso um indicador de inside bar. Como você pode observar vendo a imagem logo abaixo.

Imagem 01

Ok, sabemos como este código 01 funciona, pelo menos a parte básica. Justamente por conta do fato de que, quando ele foi apresentado, foi explicado, como fazer para declarar as coisas. Porém, este indicador, visto no código 01. É ao meu entender um indicador estático. E o motivo é justamente as declarações feitas nas linhas quatro e cinco. E por favor, meu caro leitor, não me interprete mal. O fato de que estou dizendo que este indicador visto no código 01 ser estático. É justamente pelo fato, de que, uma vez compilado, não podemos mudar o próprio indicador. Visto que o mesmo foi declarado fazendo uso de diretivas de compilação próprias do MQL5. Que é justamente as linhas mencionadas.

Entretanto, o que de fato importa, é se o indicador funciona ou não. E se ele consegue, ou não efetuar a tarefa para qual foi designado. Com ele consegue, e de forma bem direta e sem muitos rodeios. Então não existe problema em se utilizar esta implementação estática. No entanto, podemos criar este mesmo código, ou melhor dizendo, criar um indicador, muito parecido, mas com propriedades dinâmicas. Pelo menos no que diz respeito a forma de implementar e apresentar as coisas.

E como um indicador dinâmico funcionária? E qual a vantagem em se implementar um indicador dinâmico? Bem, vamos por partes. Primeiro, um indicador dinâmico não iria ter em seu código, as linhas quatro e cinco, vistas no código 01. Esta é a primeira e maior diferença. E a vantagem, seria justamente a não presença destas duas linhas mencionadas. Isto talvez possa estar parecendo muito estranho. Mas depois você irá entender melhor este tipo de coisa, conforme formos avançando para modelos mais elaborados.

Porém justamente pelo fato, de não termos estas linhas sendo declaradas. Podemos mudar a forma como o indicador apresentaria as informações. Sem necessariamente precisar compilar o código, para mudar esta forma de apresentação. Entretanto, talvez a maior vantagem estaria no fato de não precisarmos criar, um verdadeiro circuito lógico dentro do código do indicador. Isto a fim de selecionar a forma como o indicador deveria apresentar as informações no gráfico.

Agora preste atenção meu caro leitor. O que iremos fazer aqui, não irá mudar a forma como o indicador, visto no código 01, irá trabalhar. Iremos apenas criar uma forma de implementar as coisas, via código. Ou seja, parte do que seria feito por diretivas, será feito via chamadas de biblioteca padrão do MQL5. Então a primeira coisa a fazer, será remover as linhas que tornam o indicador, visto no código 01, em um indicador estático. Fazendo a remoção da parte estática, temos o que é visto no código logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_buffers     5
05. #property indicator_plots       1
06. //+----------------+
07. double  gl_Buff_High[],
08.         gl_Buff_Open[],
09.         gl_Buff_Close[],
10.         gl_Buff_Low[],
11.         gl_Buff_Color[];
12. //+------------------------------------------------------------------+
13. int OnInit()
14. {
15.    SetIndexBuffer(1, gl_Buff_High, INDICATOR_DATA);
16.    SetIndexBuffer(0, gl_Buff_Open, INDICATOR_DATA);
17.    SetIndexBuffer(3, gl_Buff_Close, INDICATOR_DATA);
18.    SetIndexBuffer(2, gl_Buff_Low, INDICATOR_DATA);
19.    SetIndexBuffer(4, gl_Buff_Color, INDICATOR_COLOR_INDEX);
20. 
21.    return INIT_SUCCEEDED;
22. };
23. //+------------------------------------------------------------------+
24. 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[])
25. {
26.    static double  high = DBL_MIN,
27.                   low = DBL_MAX;
28. 
29.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
30.    {
31.       gl_Buff_High[c] = High[c];
32.       gl_Buff_Open[c] = Open[c];
33.       gl_Buff_Close[c] = Close[c];
34.       gl_Buff_Low[c] = Low[c];
35. 
36.       gl_Buff_Color[c] = (Open[c] > Close[c] ? 0 : 2);
37.       if ((c - 1) > 0)
38.       {
39.          high = (High[c - 1] > high ? High[c - 1] : high);
40.          low = (Low[c - 1] < low ? Low[c - 1] : low);
41.          gl_Buff_Color[c] = ((high > High[c]) && (low < Low[c]) ? 1 : gl_Buff_Color[c]);
42.          if (gl_Buff_Color[c] != 1)
43.          {
44.             high = DBL_MIN;
45.             low = DBL_MAX;
46.          }
47.       }
48.    }
49. 
50.    return rates_total;
51. };
52. //+------------------------------------------------------------------+

Código 02

Este código 02, apesar de poder ser compilado, NÃO FUNCIONA. Pelo menos, não irá fazer nada ao gráfico em que ele for colocado. Porém, isto não é de fato um problema. Isto porque, removemos a parte que informa ao MetaTrader 5, como o indicador será de fato utilizado. Assim, tudo que o MetaTrader 5 sabe, é que temos quatro buffers de dados e um buffer de cor. E que será feita uma plotagem apenas. Mas o MetaTrader 5, NÃO SABE COMO utilizar estes buffers. Apesar de eles estarem sendo ajustados de forma a apresentar alguma informação. Por isto, nada acontece ao gráfico.

Ok, então como podemos resolver está questão? Isto de forma a dizer ao MetaTrader 5, como utilizar os buffers que estão sendo declarado neste código 02? Bem, meu caro leitor, esta é a parte interessante. Pois, neste momento, iremos dizer, de forma dinâmica, ao MetaTrader 5, como os buffers deverão ser utilizados. E isto é conseguido, adicionando algumas novas linhas ao código, como você pode observar logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_buffers     5
05. #property indicator_plots       1
06. //+----------------+
07. double  gl_Buff_High[],
08.         gl_Buff_Open[],
09.         gl_Buff_Close[],
10.         gl_Buff_Low[],
11.         gl_Buff_Color[];
12. //+------------------------------------------------------------------+
13. int OnInit()
14. {
15.    const color cor[] = {clrRed, clrRoyalBlue, clrGreen};
16. 
17.    PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_COLOR_CANDLES);   
18.    PlotIndexSetInteger(0, PLOT_COLOR_INDEXES, cor.Size());
19.    for (uint c = 0; c < cor.Size(); c++)
20.       PlotIndexSetInteger(c, PLOT_LINE_COLOR, c, cor[c]);
21. 
22.    SetIndexBuffer(1, gl_Buff_High, INDICATOR_DATA);
23.    SetIndexBuffer(0, gl_Buff_Open, INDICATOR_DATA);
24.    SetIndexBuffer(3, gl_Buff_Close, INDICATOR_DATA);
25.    SetIndexBuffer(2, gl_Buff_Low, INDICATOR_DATA);
26.    SetIndexBuffer(4, gl_Buff_Color, INDICATOR_COLOR_INDEX);
27. 
28.    return INIT_SUCCEEDED;
29. };
30. //+------------------------------------------------------------------+
                   .
                   .
                   .

Código 03

Como o resultado final é o mesmo visto na imagem 01, não irei replicar ela novamente. Porém quando você vier a utilizar este indicador dinâmico, que vemos neste fragmento de código 03. As coisas irão funcionar de uma maneira um pouco diferente da que seria ao utilizar o indicador estático visto em código 01.

Mas antes de falarmos sobre isto, vamos entender o que foi feito neste fragmento de código 03. Onde apenas a parte que nos interessa é vista. Lembrando que o código na integra estará no anexo. Observe o seguinte meu caro leitor, na linha 15 temos um array de cores constantes sendo definido. A sequência das cores é a mesma usada no código 01, na linha cinco. É importante que você entenda isto, para compreender como o código de fato funciona. Agora, quando a linha 17, neste código 03, for executada, teremos o mesmo tipo de efeito, que seria dado, quando a linha quatro no código 01, foi vista pelo compilador. Perceba a diferença sutil que existe aqui. Diferente do que acontecia no código 01, onde durante a compilação dizíamos como as coisas seriam. Aqui, não estamos fazendo isto. Estamos apenas dizendo ao compilador: Crie o código e utilize este valor daqui. Mas isto tem fortes implicações como será visto depois.

Logo em seguida, na linha 18 do código 03, dizemos ao MetaTrader 5, quantas cores existem no buffer de cor. Detalhe, o fato de dizermos quantas cores existem, nesta linha 18, não nos diz que valores cada cor terá. Assim, se você não inicializar as mesmas, o MetaTrader 5 fara isto de alguma maneira. E o padrão de cores pode ficar todo bagunçado. Por isto, usamos o laço na linha 19, a fim de inicializar as cores pela chamada da linha 20. Tudo isto equivale ao que seria a linha cinco no código 01.

Porém, toda via e, entretanto, a equivalência termina neste ponto. Pois quando você for aplicar este indicador visto no fragmento de código 03. Irá se deparar com uma situação, no mínimo bem inusitada. Isto pode ser observado na imagem logo abaixo.

Imagem 02

Epá. Espera um pouco aí. Onde estão as cores que irão ser aplicadas no indicador? Acredito, que tanto você, esteja bastante surpreso com este tipo de coisa vista na imagem 02. E tanto você como também o pobre do usuário, acabariam ficando bastante confusos ao ver esta imagem 02. Mas vamos ver o que acontece quando aplicamos o indicador ao gráfico. Isto pode ser observado na animação logo abaixo.

Animação 01

Que coisa mais sinistra. Não entendi. Por que apesar de não podermos ajustar as cores, como pode ser observado na imagem 02, ainda assim, o indicador teve o mesmo resultado visto na imagem 01? Isto sim é algo bem estranho.

Bem lá no fundo, este comportamento não é muito estranho. Isto porque, estamos definindo as coisas de maneira dinâmica. E como o MetaTrader 5, ainda não sabe como construir as cores, ele não pode as utilizar, ou melhor dizendo, não pode as apresentar, para que possamos ajustar as mesmas. Tendo em vista, que ele não sabe ainda quantas cores e quais cores serão utilizadas. Isto de fato, é algo bem interessante. E que podemos explorar de formas diferentes no futuro. Por hora, vamos nos manter no básico da coisa toda.

Tendo em visto o fato de que o padrão de cores, foi o mesmo que vimos na imagem 01. Sabemos que o indicador funciona. E também podemos mostrar ao usuário, que padrão definimos durante a fase de codificação. Mas será que não podemos mudar isto? Permitindo que o usuário possa colocar assim cores que ele venha a desejar? Quanto a isto, meu caro leitor, não existe de fato nenhum problema. Visto que uma vez que o indicador esteja no gráfico, o usuário, pode abrir as propriedades do mesmo para poder as mudar. Neste caso, veja o que acontece, na animação 02.

Animação 02

Hum, intrigante. Agora podemos ver quais a cores estão sendo definidas para ser usadas no indicador. Mas espere um pouco. Você disse que podemos mudar as cores. Porém acabo de me lembrar de uma coisa. Na linha 15 do fragmento de código 03, estamos definindo justamente estas cores que estão sendo vistas na animação 02. No entanto, elas estão sendo definidas como constante. Agora fiquei confuso. Se elas estão sendo definidas como constantes. Como o usuário irá conseguir modificar as cores do padrão?

Quanto a isto, meu caro leitor. Temos a beneficie do MetaTrader 5, em entender o que estará sendo feito. Já que estamos simplesmente mudando algum argumento, ou parâmetro do indicador. O MetaTrader 5, não o irá remover totalmente do gráfico. Ele o irá manter, por assim dizer no gráfico, mudando apenas o que precisa ser alterado. Isto pode ser visto na animação logo abaixo.

Animação 03

Observe que de fato funciona. Porém, toda via e, entretanto, existe um pequeno problema neste tipo de abordagem. Quando o usuário, remover o indicador do gráfico, ou melhor, pedir para o MetaTrader 5 reconstruir o gráfico, por qualquer motivo. Aqueles valores declarados na linha 15 voltarão a ser utilizados. Fazendo com que qualquer mudança na configuração feita pelo usuário, venha a ser perdida. Precisando ser refeita novamente.

Um exemplo de pedido de reconstrução de gráfico, é o simples fato, de pedir para mudar o tempo do gráfico. Por mais absurdo que possa parecer, para grande parte dos usuários, o simples fato mudar as configurações, estando em um tempo gráfico, suponhamos de 5 minutos. E logo depois, pedir para o MetaTrader 5, usar um tempo gráfico de 10 minutos, por exemplo. Fará com que as configurações definidas no momento da criação do indicador, venham a ser utilizadas novamente. Fazendo com que as modificações sejam perdidas. Já expliquei em outro artigo, como sanar ou contornar este tipo de situação. Então não vou repetir aqui novamente aquela explicação.

Ok, com esta simples demonstração, acredito que você tenha compreendido a diferença entre uma implementação estática e uma dinâmica. Porém, para quem desejar saber um pouco melhor até onde podemos ou não ir, na documentação do MQL5, existe uma tabela que mostra este tipo de coisa. Olhe em: Conexão entre as propriedades de indicadores e funções correspondentes para saber quais diretivas, ou propriedades, podem ou não serem implementadas de forma dinâmica.

Muito bem, meu amigo autor. Mas aqui entre nós, até o momento, não consegui de fato entender onde estaria a vantagem em se usar este sistema dinâmico. Tal pouco, não vejo como isto poderia me ser útil de alguma forma. Ok, compreendo sua falta de entusiasmo com este tipo de implementação. De fato, ela não parece ser assim lá grandes coisas. Ainda mais tendo em vista algumas dificuldades que ela acaba nos proporcionando em muitas das vezes, em que venhamos a utilizar tal forma de implementar um indicador.

No entanto, pode ser que em alguns tipos de casos bem específicos e voltados para uma implementação pessoal. Você até venha a se interessar em utilizar este tipo de abordagem. Para mostrar um exemplo disto, vamos ver um caso bem específico de implementação. Este será discutido no próximo tópico.


Indicador Inside bar em diferentes tipos de gráfico

O indicador que vimos no tópico anterior, é basicamente voltado a ser utilizado em um gráfico de candles. Porém, como sabemos, o MetaTrader 5, nos permite utilizar o gráfico de barras e o gráfico de linha. Além é claro do gráfico de candles. Se por um acaso o usuário, vier a mudar para um outro tipo de apresentação, que não seja o de candles. Irá obter um comportamento muito desagradável no gráfico. Isto pode ser visto logo abaixo.

Imagem 03

Nesta imagem 03, temos o indicador de inside bar sendo utilizado em um gráfico de barras. Note que é completamente estranho a forma como as informações são plotadas. Assim como é visto na imagem logo na sequência.

Imagem 04

Aqui temos algo muito parecido, com o problema visualizado na imagem 03. Porém, no caso desta imagem 04, pedimos para utilizar o gráfico de linha, e isto junto com o indicador de inside bar. Talvez para grande parte, e na realidade, este tipo de situação não faz sentido. Já que quando utilizamos o gráfico de linha, visamos obter a informação de apenas e tão somente um dos valores OHCL. Sendo que quase sempre, o que nos importa seria o valor de fechamento. Porém, não é este o caso. A questão aqui, é que apesar de termos pedido para visualizar o gráfico em um outro formato. Continuamos vendo candles sendo apresentados. E isto precisa ser corrigido.

Existem, basicamente duas maneiras de se fazer isto. E digo duas, pois existia uma terceira, que envolveria, criar um indicador para cada modo gráfico. Mas isto tornaria a utilização extremamente desagradável e confusa por parte dos usuários. Então vamos focar nas duas outras maneiras. Uma seria criar um circuito de execução, baseando o código, naquilo que seria criado pelo compilador. E a outra seria criando uma manipulação dinâmica das informações a serem plotadas.

Para evitar aborrecimentos desnecessários, vamos mudar o código 03 visto no tópico anterior para uma versão onde, podemos já definir as cores do indicador logo no início. Porém, não vamos definir o tipo de indicador que será plotado. Assim, aquele mesmo fragmento de código 03, irá ficar como mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_color1      clrRed, clrRoyalBlue, clrGreen
05. //+----------------+
06. #property indicator_buffers     5
07. #property indicator_plots       1
08. //+----------------+
09. double  gl_Buff_High[],
10.         gl_Buff_Open[],
11.         gl_Buff_Close[],
12.         gl_Buff_Low[],
13.         gl_Buff_Color[];
14. //+------------------------------------------------------------------+
15. int OnInit()
16. {
17.    PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_COLOR_CANDLES);   
18. 
19.    SetIndexBuffer(1, gl_Buff_High, INDICATOR_DATA);
20.    SetIndexBuffer(0, gl_Buff_Open, INDICATOR_DATA);
21.    SetIndexBuffer(3, gl_Buff_Close, INDICATOR_DATA);
22.    SetIndexBuffer(2, gl_Buff_Low, INDICATOR_DATA);
23.    SetIndexBuffer(4, gl_Buff_Color, INDICATOR_COLOR_INDEX);
24. 
25.    return INIT_SUCCEEDED;
26. };
27. //+------------------------------------------------------------------+
28. 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[])
29. {
30.    static double  high = DBL_MIN,
31.                   low = DBL_MAX;
32. 
33.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
34.    {
35.       gl_Buff_High[c] = High[c];
36.       gl_Buff_Open[c] = Open[c];
37.       gl_Buff_Close[c] = Close[c];
38.       gl_Buff_Low[c] = Low[c];
39. 
40.       gl_Buff_Color[c] = (Open[c] > Close[c] ? 0 : 2);
41.       if ((c - 1) > 0)
42.       {
43.          high = (High[c - 1] > high ? High[c - 1] : high);
44.          low = (Low[c - 1] < low ? Low[c - 1] : low);
45.          gl_Buff_Color[c] = ((high > High[c]) && (low < Low[c]) ? 1 : gl_Buff_Color[c]);
46.          if (gl_Buff_Color[c] != 1)
47.          {
48.             high = DBL_MIN;
49.             low = DBL_MAX;
50.          }
51.       }
52.    }
53. 
54.    return rates_total;
55. };
56. //+------------------------------------------------------------------+

Código 04

Agora temos o nosso código 04, funcionando de forma mais adequada ao que seria o ideal para qualquer usuário do indicador. Já que podemos definir as cores logo no início. E tudo isto é devido ao fato de que na linha quatro, deste código 04, estamos definindo a propriedade do indicador. Observe que devido a isto, removemos aquela parte de carregamento das cores, de dentro do bloco de tratamento do evento OnInit. Com isto temos o que seria o indicador base que precisaremos manipular.

Agora vem a parte divertida. Se este indicador que vemos no código 04, funciona de maneira dinâmica e ao mesmo tempo, tem a parte estática, definida a fim de que possamos informar o padrão de cores. Como podemos fazer com que ele funcione a fim de se adequar ao tipo de gráfico que está sendo visualizado?

Bem, esta é a parte onde muitos ao olharem meus códigos, costumam ficar de cabelos em pé. Observe que na linha 17 estamos dizendo que o sistema de plotagem do indicador será do tipo candle. Porém, ao mudarmos o gráfico para o tipo barra, termos problemas como foi visto nas imagens anteriores. Mas se você estudar a documentação, irá encontrar uma função da biblioteca padrão bastante interessante. Está nos permite saber que tipo de gráfico está sendo utilizado naquele momento. A tal função em questão é ChartGetInteger. Quando pedimos para esta função nos informar que tipo de gráfico está sendo utilizado, ela irá nos devolver uma enumeração. No caso ENUM_CHART_MODE.

E é justamente isto que precisamos saber. Mas antes de pôr isto em prática. Vamos ver como o indicador iria se comportar, em um primeiro momento. Para isto, mudamos o código para o que é visto logo abaixo.

                   .
                   .
                   .
14. //+------------------------------------------------------------------+
15. #define PrintX(X) Print(__FUNCTION__, " => ",#X, " :: ",X);
16. //+------------------------------------------------------------------+
17. int OnInit()
18. {
19.     PrintX(EnumToString((ENUM_CHART_MODE)ChartGetInteger(0, CHART_MODE)));
20.     PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_COLOR_CANDLES);   
21. 
22.     SetIndexBuffer(1, gl_Buff_High, INDICATOR_DATA);
23.     SetIndexBuffer(0, gl_Buff_Open, INDICATOR_DATA);
24.     SetIndexBuffer(3, gl_Buff_Close, INDICATOR_DATA);
25.     SetIndexBuffer(2, gl_Buff_Low, INDICATOR_DATA);
26.     SetIndexBuffer(4, gl_Buff_Color, INDICATOR_COLOR_INDEX);
27. 
28.     return INIT_SUCCEEDED;
29. };
30. //+------------------------------------------------------------------+
                   .
                   .
                   .

Código 05

Agora preste atenção ao que irei explicar. Pois senão depois você iria ficar boiando na explicação do que será feito. Neste fragmento que podemos ver no código 05, temos as mudanças que precisaram ser feitas no código 04. Isto a fim de que consigamos saber o tipo de gráfico que está sendo utilizado em um dado momento. Então na linha 19, fazemos uma chamada que no final será traduzida pela definição vista na linha 15, em uma informação que será plotada no terminal do MetaTrader 5. Estas informações podem ser vistas nas imagens logo abaixo.

Imagem 05

Nesta imagem 05, podemos ver que estamos utilizando o gráfico CHART_CANDLES.

Imagem 06

Nesta imagem 06, claramente notamos que o gráfico é CHART_BARS.

Imagem 07

E finalmente nesta imagem 07, podemos ver que o gráfico é CHART_LINE. Ok, mas como utilizar isto ao nosso favor? Bem meu caro leitor. É muito simples, com exceção do gráfico CHART_LINE que iremos ver depois como resolver. Para que o gráfico indicador use o modo de plotagem correta, precisamos apenas fazer com que a chamada da linha 20, vista neste fragmento de código 05, aponte para o tipo DRAW_COLOR_CANDLES, quando estivermos no gráfico tipo candle e DRAW_COLOR_BARS quando estivermos no gráfico de barras.

O resto é história. Isto pode ser feito de maneira muito simples por qualquer um. Funcionando perfeitamente bem, desde é claro, o MetaTrader 5, esteja ampliando o indicador a partir de um evento Init. Ou seja, se você desejar utilizar a coisa da maneira mais simplória. O código precisa ficar como mostrado abaixo.

                   .
                   .
                   .
14. //+------------------------------------------------------------------+
15. int OnInit()
16. {
17.     switch ((ENUM_CHART_MODE)ChartGetInteger(0, CHART_MODE))
18.     {
19.         case CHART_BARS:
20.             PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_COLOR_BARS);
21.             break;
22.         case CHART_CANDLES:
23.             PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_COLOR_CANDLES);   
24.             break;
25.         case CHART_LINE:
26.             break;
27.     }   
28. 
29.     SetIndexBuffer(1, gl_Buff_High, INDICATOR_DATA);
30.     SetIndexBuffer(0, gl_Buff_Open, INDICATOR_DATA);
31.     SetIndexBuffer(3, gl_Buff_Close, INDICATOR_DATA);
32.     SetIndexBuffer(2, gl_Buff_Low, INDICATOR_DATA);
33.     SetIndexBuffer(4, gl_Buff_Color, INDICATOR_COLOR_INDEX);
34. 
35.     return INIT_SUCCEEDED;
36. };
37. //+------------------------------------------------------------------+
                   .
                   .
                   .

Código 06

Note que neste fragmento do código 06, não estamos lidando com modo de plotagem do gráfico de linha. Isto será visto depois. Mas note como estamos fazendo para plotar os demais modos. E isto que você está vendo, neste código 06, funciona. Mas tem um pequeno problema. Na animação abaixo, podemos ver que problema é este.

Animação 04

Nesta animação 04, podemos ver que quando mudamos o gráfico para outro modo de plotagem, o indicador não consegue acompanhar o que o MetaTrader 5 está fazendo. Muitos desistiriam dizendo não ser possível criar o indicador da forma adequada. Porém, tais pessoas desconhecem como o MetaTrader 5, de fato funciona. Sempre que alguma coisa acontece, normalmente em um gráfico, o MetaTrader 5, dispara um evento muito especifico, com algumas informações para nos ajudar a identificar o que aconteceu. Alguns eventos podem ser ligados e desligados, enquanto outros não. E cada evento que ligamos ou desligamos, influencia na performance geral do MetaTrader 5. Já que ele acaba ficando ocupado precisando olhar eventos, que normalmente ele não observaria.

E isto, para quem quer um sistema de alta performance é trivial. Muitos operadores, quando vão usar o MetaTrader 5, não utilizam absolutamente nada junto dele. Como indicadores ou Expert Advisores. Isto por que, muitas vezes, estas aplicações acabam atrapalhando a velocidade do MetaTrader 5 durante momentos de alta volatilidade. E estes momentos, estes operadores querem aproveitar, então eles utilizam o MetaTrader 5 básico, e somente isto, nada mais.

Ok, mas aqui, não iremos, ou queremos focar em operar com o MetaTrader 5 no seu formato mais básico. Queremos sim, adicionar aplicações ao gráfico, a fim de nos ajudar de alguma forma. Sendo assim, precisamos capturar um certo evento que o MetaTrader 5, dispara a cada coisa que é feita no gráfico. Não importando a natureza do evento.

Ente evento que queremos capturar é o ChartEvent. Ele é tratado no nosso código pelo procedimento OnChartEvent. Agora preste bastante atenção, meu caro leitor. Um ChartEvent, acontece SEMPRE que algo ocorre no gráfico. Porém podemos ligar e desligar certas coisas a fim de não capturar cada mínimo momento, ou alteração que venha a ser feito no gráfico. No entanto, quando você adiciona um indicador ao gráfico, o MetaTrader 5 dispara dois eventos. Um após o outro. Em alguns casos dispara um terceiro. Mas vamos focar apenas nos dois primeiros.

O primeiro evento disparado é um Init, que é capturado e tratado pela função OnInit. Que estamos vendo desde o início, deste assunto sobre indicadores. Logo depois que o evento Init tenha sido tratado, um novo evento é disparado sem termos feito nada ainda. Este seria um evento ChartEvent, que é quando o indicador é colocado de fato no gráfico.

Ok, mas para entender o que acontece a seguir, precisamos olhar a declaração do procedimento de captura deste evento ChartEvent. Esta declaração pode ser vista logo abaixo.

void OnChartEvent(const int id,         // Event ID
                  const long& lparam,   // Parameter of type long event
                  const double& dparam, // Parameter of type double event
                  const string& sparam  // Parameter of type string events
  );

Código 07

Agora se você olhar na documentação OnChartEvent, irá ver uma pequena tabela. O valor que nos interessa nesta tabela é: CHARTEVENT_CHART_CHANGE que acontece quando existe uma mudança no gráfico. Sendo então este valor que vem no primeiro disparo do ChartEvent. Agora, sabendo disto, podemos fazer uma coisa bem interessante no nosso código. Assim o mesmo depois de atualizado fica como mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_color1      clrRed, clrRoyalBlue, clrGreen
05. //+----------------+
06. #property indicator_buffers     5
07. #property indicator_plots       1
08. //+----------------+
09. double  gl_Buff_High[],
10.         gl_Buff_Open[],
11.         gl_Buff_Close[],
12.         gl_Buff_Low[],
13.         gl_Buff_Color[];
14. //+------------------------------------------------------------------+
15. int OnInit()
16. {
17.     SetIndexBuffer(0, gl_Buff_Open, INDICATOR_DATA);
18.     SetIndexBuffer(1, gl_Buff_High, INDICATOR_DATA);
19.     SetIndexBuffer(2, gl_Buff_Low, INDICATOR_DATA);
20.     SetIndexBuffer(3, gl_Buff_Close, INDICATOR_DATA);
21.     SetIndexBuffer(4, gl_Buff_Color, INDICATOR_COLOR_INDEX);
22. 
23.     return INIT_SUCCEEDED;
24. };
25. //+------------------------------------------------------------------+
26. 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[])
27. {
28.    static double  high = DBL_MIN,
29.                   low = DBL_MAX;
30. 
31.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
32.    {
33.       gl_Buff_High[c] = High[c];
34.       gl_Buff_Open[c] = Open[c];
35.       gl_Buff_Close[c] = Close[c];
36.       gl_Buff_Low[c] = Low[c];
37. 
38.       gl_Buff_Color[c] = (Open[c] > Close[c] ? 0 : 2);
39.       if ((c - 1) > 0)
40.       {
41.          high = (High[c - 1] > high ? High[c - 1] : high);
42.          low = (Low[c - 1] < low ? Low[c - 1] : low);
43.          gl_Buff_Color[c] = ((high > High[c]) && (low < Low[c]) ? 1 : gl_Buff_Color[c]);
44.          if (gl_Buff_Color[c] != 1)
45.          {
46.             high = DBL_MIN;
47.             low = DBL_MAX;
48.          }
49.       }
50.    }
51. 
52.    return rates_total;
53. };
54. //+------------------------------------------------------------------+
55. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
56. {
57.     switch (id)
58.     {
59.         case CHARTEVENT_CHART_CHANGE:
60.             switch ((ENUM_CHART_MODE)ChartGetInteger(0, CHART_MODE))
61.             {
62.                 case CHART_BARS:
63.                     PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_COLOR_BARS);
64.                     break;
65.                 case CHART_CANDLES:
66.                     PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_COLOR_CANDLES);   
67.                     break;
68.                 case CHART_LINE:
69.                     break;
70.             }
71.             break;
72.     }
73.     ChartRedraw();
74. };
75. //+------------------------------------------------------------------+

Código 08

Hum. Sei não, este código acho que não irá funcionar. Isto por que, não estamos dizendo ao MetaTrader 5, qual sistema de plotagem a ser utilizado. Isto quando a função OnInit for executada. Sei não. Tenho quase certeza que o resultado será igual ao do código 02.

Ok, temos um descrente entre nós. Então vamos mostrar a ele que o mundo é muito maior do que ele imagina conhecer. Para provar que este código 08 de fato funciona, veja o que é a animação logo abaixo.

Animação 05

Note que a única coisa que não está seguindo o que está sendo feito no gráfico pelo MetaTrader 5. É quando mudamos para o modo CHART_LINE. Ali, nosso indicador por não está implementando o modelo de plotagem. Não consegue acompanhar o que o usuário está fazendo no MetaTrader 5.


Considerações finais

Neste artigo, foi demonstrando um princípio básico, porém bastante interessante de se trabalhar com indicadores. Mesmo que aqui não tenhamos mostrado como resolver a questão de utilizar um indicador a fim de plotar e acompanhar o que está sendo requisitado pelo MetaTrader 5, em todos os sentidos. Conseguimos fazer com que um indicador simples obedecesse a um comando a fim de acompanhar o modo de plotagem do gráfico. Isto em parte, já que ficou faltando mostrar como fazer com que o indicador mostrasse a plotagem de linha seguindo o que o usuário estaria selecionando na plataforma.

Porém como a mudança da plotagem de barras ou candles, que necessitam de quatro buffers de dados e um de cor, para um de linha colorida, que necessita de um buffer de dado e um de cor, é um tanto quanto complicada de ser mostrada neste momento. Iremos deixar para ver isto futuramente. Já que para fazer isto, precisamos utilizar uma abordagem um pouco diferente. Carregando e descarregando um indicador via chamadas de biblioteca padrão. Coisa que neste exato momento, seria um tanto quanto complicado, de se explicar ou até mesmo de ser devidamente compreendido por você, meu caro e estimado leitor.

De qualquer modo, conforme formos avançando, para materiais ainda mais complexos e elaborados. Irei em algum momento, mostrar como solucionar esta questão abordada aqui. Até lá, sugiro que você procure estudar o que foi mostrado neste artigo. E principalmente, não se esqueça dar uma revisada no que foi visto nos artigos anteriores. Pois no próximo artigo, iremos unir alguns conceitos a este assunto de indicadores. Algo que realmente será muito interessante de ser visto. Então não perca.

Arquivos anexados |
Anexo.zip (2.69 KB)
Simulação de mercado (Parte 21): Iniciando o SQL (IV) Simulação de mercado (Parte 21): Iniciando o SQL (IV)
Muitos de vocês, caros leitores, podem ter um nível de experiência muito superior ao meu, no que rege trabalhar com bancos de dados. Tendo assim uma visão diferente da minha. Porém, como era preciso definir, e desenvolver alguma forma de explicar o motivo pelo qual os bancos de dados, são criados da forma como são criados. Explicar o por que o SQL tem o formato que tem. Mas principalmente, por que as chaves primárias e chaves estrangeiras vieram a surgir. Foi preciso deixar as coisas um pouco abstratas.
Criando barras 3D com base em tempo, preço e volume Criando barras 3D com base em tempo, preço e volume
O que são gráficos de preços 3D multidimensionais e como eles são construídos. Como as barras 3D preveem reversões de preço e como Python e MetaTrader 5 permitem construir essas barras volumétricas em tempo real.
Introdução ao MQL5 (Parte 9): Compreendendo e Usando Objetos no MQL5 Introdução ao MQL5 (Parte 9): Compreendendo e Usando Objetos no MQL5
Aprenda a criar e personalizar objetos de gráfico no MQL5 usando dados atuais e históricos. Este guia baseado em projetos ajuda você a visualizar negociações e aplicar conceitos do MQL5 na prática, facilitando a criação de ferramentas adaptadas às suas necessidades de negociação.
Redes neurais em trading: Modelo adaptativo multiagente (MASA) Redes neurais em trading: Modelo adaptativo multiagente (MASA)
Apresento o framework adaptativo multiagente MASA, que une aprendizado por reforço e estratégias adaptativas, oferecendo um equilíbrio harmonioso entre rentabilidade e controle de riscos em condições de mercado turbulentas.