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

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

MetaTrader 5Exemplos |
142 0
CODE X
CODE X

Introdução

No artigo anterior Do básico ao intermediário: Objetos (I), tivemos o que poderíamos denominar como sendo o primeiro contato com objetos gráficos presentes no MQL5. Além é claro de mostrar como poderíamos colocar tais objetos em um gráfico. Manipulando os mesmos de uma maneira relativamente simples. Apesar de pouco eficiente em termos gerais. Já que não estamos de fato interessados em criar aplicações. Mas sim, interessados em manter o código o mais simples e didático, quanto for possível ser feito.

Devo confessar que o artigo anterior, foi bem divertido. Porém, perto do que iremos fazer, aquilo foi de uma chatice sem tamanho. Isto porque, a partir do momento, em que começamos de fato a manipular e controlar objetos via código. Coisas que antes pareceriam impossíveis de serem feita, passam a se tornar cada vez mais comuns.

Mas como ainda estamos bem no começo, temos diversas coisas que precisam ser vistas, antes de podermos soltar a nossa imaginação, e transformar o MetaTrader 5, em algo realmente interessante e divertido. Isto pelo ponto de vista de programadores. Pelo ponto de vista de um usuário, o que iremos fazer, pode parecer insano e sem nenhum propósito. Ok, como de costume, vamos iniciar um novo tópico, para começar a nos divertir.


Primeiras manipulações

O que foi feito no artigo anterior, não pode ser considerado, necessariamente, as primeiras manipulações de objetos. Isto pelo simples fato de que, apenas os colocamos no gráfico e pronto. Qualquer outra coisa que viesse a precisar ser feita, seria necessário abrir a caixa de diálogo, onde teríamos acesso as algumas propriedades do objeto, e as manipular ali. No entanto, quando estamos programando as coisas, podemos ir muito além. Sendo que teoricamente não existe limite para o que podemos fazer. Apenas a nossa imaginação. Isto em teoria. Já que o fato de que o MQL5, foi projetado visando programar aplicações para serem utilizadas no MetaTrader 5. E a plataforma MetaTrader 5, tem como objetivo, apresentação de gráficos de cotação. Existe sim um limite real do que podemos fazer diretamente no MQL5.

Mas acredite, meu caro leitor, este limite é mesmo algo muito além do que grande parte das pessoas imaginam onde ele de fato estaria. E quando este limite é alcançado, podemos utilizar programação C e C++, a fim de ampliar o mesmo. Mas isto, já é outro nível, no qual esta sequência de artigos não irá abordar. Já que iremos apenas até a beirada, ou limiar do que separaria um nível que ao meu ver seja intermediário e um nível avançado. Onde este nível avançado, começa a acontecer, quando precisamos utilizar linguagens como C e C++, para ampliar as capacidades do MQL5.

Então, voltando a nossa questão principal. Para efetuar manipulações nos objetos, precisamos utilizar, mecanismos de entrada e interação com o usuário. Tais mecanismos envolvem uso do teclado, e ou, do mouse. Isto tratando as coisas de forma que seja a mais simples possível. Porém como você já deve, possivelmente estar pensando, utilizar tais mecanismos envolvem capturar eventos. Pois o próprio sistema operacional, seja ele Windows, Linux ou outro qualquer, basicamente utilizam eventos para comunicação entre o usuário e alguma aplicação qualquer. Isto foi visto no artigo Do básico ao intermediário: Eventos (I). Porém, lá falamos de maneira muito superficial a respeito deste tipo de coisa. Aqui iremos nos aprofundar um pouco mais naquele assunto.

Para começar, vamos criar um pequeno código de exemplo. Algo bem todos consigam entender, mesmo sem que eu necessite explicar uma única linha se quer. Este primeiro código é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_NameObj "Demo"
05. //+------------------------------------------------------------------+
06. int OnInit()
07. {
08.     ObjectCreate(0, def_NameObj, OBJ_HLINE, 0, 0, 0);
09.     ObjectSetInteger(0, def_NameObj, OBJPROP_COLOR, clrPurple);
10. 
11.     return INIT_SUCCEEDED;
12. };
13. //+------------------------------------------------------------------+
14. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
15. {
16.     static double p = 0;
17. 
18.     ObjectMove(0, def_NameObj, 0, 0, p);
19. 
20.     if (prev_calculated > 0)
21.         p = price[prev_calculated - 1];
22. 
23.     return rates_total;
24. };
25. //+------------------------------------------------------------------+
26. void OnDeinit(const int reason)
27. {
28.     ObjectDelete(0, def_NameObj);
29.     ChartRedraw();
30. };
31. //+------------------------------------------------------------------+

Código 01

Bem, se você vem estudando e praticando o que estou mostrando nestes artigos, consegue entender perfeitamente bem este código. Pois ele de fato é bem interessante e muito simples. Digo que ele é interessante pelo que ele consegue fazer. E talvez você esteja olhando e pensando: Cara não consigo entender, por que você diz que este código é interessante? E pior, não entendo, por que você está fazendo este tipo de coisa na função OnCalculate, vista na linha 14. Poderia, por favor me explicar o que está acontecendo aqui? Bem, meu caro leitor, se você está com dúvidas sobre como este código funciona. É por que não tem praticado o que venho mostrando nestes artigos.

Este código quando executado irá produzir algo semelhante ao que podemos ver na animação logo abaixo. 

Animação 01

Neste caso fazer uso de apenas uma única imagem não seria o suficiente. Já que você, ao observar a animação, irá notar que a linha purpura está sempre um passo atrás da linha de cotação. As vezes esta linha purpura toca na linha de cotação. Mas a parte interessante é: Por que isto acontece? Já que, na maior parte das vezes a linha purpura estará sempre apontando para o que foi o preço da cotação anterior. Porém as vezes, ela se igual ao preço da cotação atual. Parece que temos um problema neste indicador que vemos no código 01.

Pois bem, meu caro leitor, não existe nenhum problema no código, e tão pouco na plataforma. De fato a linha purpura está fazendo exatamente aquilo para o qual ela foi planejada. Ou seja, mostrando onde a última cotação estaria. Porém, se depois de termos recebido uma cotação, o MetaTrader, disparar um novo evento Calculate, isto, sem que o preço da nova cotação, tenha sido modificado. A linha purpura irá coincidir com a linha de última cotação. E é justamente isto que vemos na animação 01. E o motivo é justamente a linha 18. Pois entre pegamos o que seria o último preço e o que seria um novo preço de cotação. Podemos ter um descasamento entre os valores. Caso isto esteja acontecendo, a linha purpura, sempre irá ficar atrás da linha de preço. Porém se ocorrer um casamento entre os preços, a linha purpura irá coincidir com a linha de ultimo preço.

Bacana e bastante didático, não é mesmo? Muitos operadores e programadores, não tem esta noção que você acaba de conquistar. Imaginando que sempre que um evento Calculate tenha sido disparado, é por conta que o preço mudou. Porém, você acaba de perceber que isto nem sempre acontece. Por isto é importante saber muito bem como otimizar seu código. Para não fazer com que uma aplicação venha a degradar completamente a performance do MetaTrader 5.

Muito bem, agora que já brincamos com algo simples e aparentemente banal. Vamos finalmente manipular algum tipo de evento. No caso, vamos começar pelo mais simples. Ou seja, a manipulação de eventos de teclado. E digo que eventos de teclado são mais simples, pelo fato de que, não precisamos habilitar e desabilitar o mesmo. Sempre que uma tecla for pressionada, o MetaTrader 5, irá disparar um evento automaticamente. Se alguma de nossas aplicações presentes no gráfico, tiver um tratador para o evento ChartEvent. Teremos possibilidade de tratar e responder, de maneira adequada ao pressionar de uma tecla. Para demonstrar este primeiro sistema. Vamos criar um novo código, para que ele responda eventos de teclado. Algo que seja simples de entender e com um objetivo bem interessante para todo iniciante. Este código é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. int OnInit()
05. {
06.    return INIT_SUCCEEDED;
07. };
08. //+------------------------------------------------------------------+
09. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
10. {
11.    return rates_total;
12. };
13. //+------------------------------------------------------------------+
14. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
15. {
16.    switch(id)
17.    {
18.       case CHARTEVENT_KEYDOWN:
19.          Print(lparam);
20.          break;
21.    }
22. };
23. //+------------------------------------------------------------------+

Código 02

Você já se perguntou como um programador sabe que tecla foi pressionada? Como ele consegue saber se uma seta, ou uma tecla como Home, ou End foi pressionada? Parece mágica, já que as teclas alfanuméricas você consegue imaginar. Porém e as demais teclas? Certo meu caro leitor, de fato, o programador NÃO SABE isto. Mas ele sabe como buscar esta informação. para isto, ele utiliza um código parecido com este que você pode observar logo acima. Este código quando executado, irá permitir que você saiba, qual o código numérico que uma determinada tecla, ao ser pressionada irá gerar.

Na verdade, a tecla ao ser pressionada irá gerar um código diferente do que estaremos vendo aqui. Porém, por conta do sistema operacional "traduzir", por assim dizer o valor da tecla pressionada. O MetaTrader 5, quando estiver executando uma aplicação parecida com a vista no código 02. Irá nos mostrar qual o valor devemos utilizar. Na animação logo abaixo, podemos ver o resultado, de uma captura sendo feita.

Animação 02

Note que é muito intuitivo. Quando pressionamos uma tecla, nos é mostrado um valor no terminal. Assim podemos usar este valor para testar se uma tecla foi ou não pressionadas. Lembrando que existe na biblioteca padrão do MQL5, uma função que nos permite testar se algumas teclas especiais foram ou não pressionadas. Mas o que aquela função faz, é criar uma abstração para o que você acabou de aprender como fazer. Legal não é mesmo?

Bem, mas como podemos utilizar isto? Parece um tanto quanto sem sentido fazer este tipo de coisa. Ok, então vamos ver como podemos usar este tipo de informação que conseguimos ao usar o código 02. Para isto, vamos modificar o código 01 a fim de agora fazer uma coisa um pouco diferente. Esta modificação pode ser observada logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_NameObj     "Demo"
05. #define def_KEY_UP      38
06. #define def_KEY_DOWN    40
07. //+------------------------------------------------------------------+
08. int OnInit()
09. {
10.    ObjectCreate(0, def_NameObj, OBJ_HLINE, 0, 0, 0);
11.    ObjectSetInteger(0, def_NameObj, OBJPROP_COLOR, clrPurple);
12. 
13.    return INIT_SUCCEEDED;
14. };
15. //+------------------------------------------------------------------+
16. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
17. {
18.    return rates_total;
19. };
20. //+------------------------------------------------------------------+
21. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
22. {
23.    static int p = 0;
24.    MqlRates rate[1];
25. 
26.    switch(id)
27.    {
28.       case CHARTEVENT_KEYDOWN:
29.          switch ((int)lparam)
30.          {
31.             case def_KEY_DOWN:
32.                p = (p < Bars(_Symbol, _Period) ? p + 1 : p);
33.                break;
34.             case def_KEY_UP:
35.                p = (p > 0 ? p - 1 : p);
36.                break;
37.             default:
38.                return;
39.          }
40.          Comment(StringFormat("Current bar analyzed: %d", p));
41.          CopyRates(_Symbol, _Period, p, rate.Size(), rate);
42.          ObjectMove(0, def_NameObj, 0, rate[0].time, rate[0].close);
43.          break;
44.    }
45.    ChartRedraw();
46. };
47. //+------------------------------------------------------------------+
48. void OnDeinit(const int reason)
49. {
50.    Comment("");
51.    ObjectDelete(0, def_NameObj);
52.    ChartRedraw();
53. };
54. //+------------------------------------------------------------------+

Código 03

Este código 03 é um pouco mais complicado que os demais, vistos neste artigo. No entanto, ele ainda assim tem muita pouca coisa nova sendo feita aqui. Assim sendo, irei focar apenas nas novas coisas, deixando o restante de lado. Já que, as demais partes serão fáceis de entender.

Muito bem, na linha 23 iniciamos um contador local. Este irá server para nos dizer, quantas barras estamos deslocando em relação a barra mais recente no gráfico. Para deixar isto claro, usamos a linha 40 a fim de imprimir uma certa informação diretamente no gráfico. Já o código entre as linhas 29 e 39, servem para garantir que somente as teclas previamente definidas serão capturadas e tratadas. Já a linha 41, irá buscar os dados de cotação da barra atualmente apontada pelo contador p. Note que estamos buscando somente uma única barra. Já a linha 42 irá mover o objeto no gráfico. Assim quando este código é executado, temos o que é visto na animação logo abaixo.

Animação 03

Isto sim foi interessante. Porém, um tanto quanto confuso. Já que precisamos ficar contando as barras para saber qual está sendo utilizada naquele momento. Porém, quase me esqueço de mencionar o que a linha 50 faz. Quando removemos o indicador do gráfico, usamos a linha 50 para remover antigos textos colocados lá. Algo muito simples, mas que alguns acabam esquecendo de fazer. O que tornar o gráfico poluído sem necessidade.

Certo, está tudo muito lindo e maravilhoso. Já sabemos como fazer pequenas e simples manipulações em um objeto. Porém existe uma coisa, que precisamos aprender a fazer agora. Já que se você notou, até o presente momento, todos os objetos receberam o mesmo nome. O que não é algo realmente interessante e tão pouco prático. E como cada objeto presente no gráfico, precisa ter um nome único. Precisamos pensar em uma forma de podermos colocar mais de um objeto, ao mesmo tempo no gráfico. Mas para explicar como podermos fazer isto, vamos a um novo tópico.


Mais de um objeto no mesmo gráfico

Existe uma questão, que faz muito iniciante ficar completamente perdido. Que é justamente o fato de ele, não entender como um código funciona, mas veio a se interessar por ele. E quando decide unir diversos códigos, ou mesmo utilizar diferentes códigos, em um mesmo gráfico. Cujo propósito de cada um destes tais códigos seria o de criar algum objeto no gráfico. Ele acaba tendo um problema. E olha que estou sendo amistoso, dizendo que o usuário, não adicionou objetos por conta própria no gráfico. Estou considerando apenas o fato, de que ele esteja tentando usar códigos que fazem isto por ele.

O problema é que para simplificar, tanto a vida dos desenvolvedores, assim como a vida do próprio MetaTrader 5. Cada objeto, que venha a estar presente no gráfico, precisa, OBRIGATORIAMENTE ter um nome único. Se você tentar criar um objeto, com um nome que já existe no gráfico, irá gerar problemas para você. Isto porque, quando você estiver tentando manipular algo, que de fato não estará no gráfico. Estará no entanto, manipulando outra coisa, que de fato estará presente no gráfico. E isto causa uma baita de uma tremenda confusão, na mente de um iniciante em programação. Ou mesmo na mente de um usuário menos experiente.

Como na maior parte das vezes, programas, ou aplicações, são pensadas para serem usadas para um dado proposito. Não existe de fato um cuidado, por parte de um desenvolvedor em explicar ao usuário, que ele deverá ter cuidado com os nomes de objetos presentes no gráfico. Basicamente, todo desenvolvedor, acredita que, todo usuário, não cometerá o erro de tentar unir diversas aplicações em uma única aplicação. Ou mesmo utilizar diferentes aplicações em um mesmo gráfico ao mesmo tempo.

Mas voltando a questão da programação, o real problema acontece devido ao fato de que grande parte dos iniciantes, apenas usa a técnica de cópia e cola. Não entendendo de fato o que estão fazendo no código e as consequências disto durante a execução do código. Para demonstrar que tipo de problema, esta técnica de cópia e cola, que muito iniciante utiliza. Vamos criar um pequeno código de exemplo. Este é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_NameObj     "Demo"
05. #define def_KEY_UP      38
06. #define def_KEY_DOWN    40
07. //+------------------------------------------------------------------+
08. int OnInit()
09. {
10.    ObjectCreate(0, def_NameObj, OBJ_VLINE, 0, 0, 0);
11.    ObjectSetInteger(0, def_NameObj, OBJPROP_COLOR, clrRoyalBlue);
12.    ObjectCreate(0, def_NameObj, OBJ_HLINE, 0, 0, 0);
13.    ObjectSetInteger(0, def_NameObj, OBJPROP_COLOR, clrPurple);
14. 
15.    return INIT_SUCCEEDED;
16. };
17. //+------------------------------------------------------------------+
18. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
19. {
20.    return rates_total;
21. };
22. //+------------------------------------------------------------------+
23. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
24. {
25.    static int p = 0;
26.    MqlRates rate[1];
27. 
28.    switch(id)
29.    {
30.       case CHARTEVENT_KEYDOWN:
31.          switch ((int)lparam)
32.          {
33.             case def_KEY_DOWN:
34.                p = (p < Bars(_Symbol, _Period) ? p + 1 : p);
35.                break;
36.             case def_KEY_UP:
37.                p = (p > 0 ? p - 1 : p);
38.                break;
39.             default:
40.                return;
41.          }
42.          Comment(StringFormat("Current bar analyzed: %d", p));
43.          CopyRates(_Symbol, _Period, p, rate.Size(), rate);
44.          ObjectMove(0, def_NameObj, 0, rate[0].time, rate[0].close);
45.          ObjectMove(0, def_NameObj, 0, rate[0].time, rate[0].close);
46.          break;
47.    }
48.    ChartRedraw();
49. };
50. //+------------------------------------------------------------------+
51. void OnDeinit(const int reason)
52. {
53.    Comment("");
54.    ObjectDelete(0, def_NameObj);
55.    ChartRedraw();
56. };
57. //+------------------------------------------------------------------+

Código 04

Aqui estou demonstrando um erro bem tosco. Porém, muito comum em códigos de iniciantes em programação. Já que o objetivo dele aparentemente seria criar uma cruz no gráfico. Porém, quando este código é executado, o resultado é o que podemos ver na animação logo abaixo.

Animação 04

Hum, que coisa estranha. Lá no tratador de evento OnInit, estamos criando dois objetos. Um que seria uma linha horizontal e outro que seria uma linha vertical. Mas apenas a linha vertical é que está sendo mostrada. Por que? Bem meu caro leitor, não é somente isto. Se você reparar com atenção, irá acabar notando que a linha vertical não foi definida para ter esta cor, que está sendo mostrada na animação 04. Então o que aconteceu de fato aqui?

O problema é que apesar de estamos definindo dois objetos para serem criados. Um na linha dez e o outro na linha doze. Apenas o objeto que está sendo declarado na linha dez é que está sendo criado. Isto porque, no momento em que a linha doze vier a ser executada. O MetaTrader 5, irá informar que já temos um objeto com este mesmo nome, definido na linha doze no gráfico. Bem, na verdade ele ainda não está no gráfico, mas sim na fila de execução, pronto para ser colocado no gráfico assim que for possível.

De qualquer maneira, a criação do objeto declarado na linha doze será recusada. Como grande parte dos códigos são relativamente simples. Muitos acabam não se atentando a este tipo de detalhe. E pior, por falta de interesse em estudar a documentação. Mas principalmente de experiência, o programador iniciante acaba achando que o erro pode estar em outro lugar. Mas quando isto acontece com um usuário, que está tentando utilizar duas ou mais aplicações, ao mesmo tempo, no mesmo gráfico. E por coincidência, o nome dos objetos são iguais, a coisa realmente fica muito confusa. Apesar de ser algo extremamente raro de acontecer. Pode ser que você venha a experimentar tal situação.

Bem, existem diversos métodos de se trabalhar com mais de um objeto no gráfico. Mas independentemente disto, se você tentar criar um objeto, com um mesmo nome, de outro que já existe no gráfico, poderá ter dificuldades em lidar com os erros por ventura surgirão. Existem casos em que podemos usar objetos diferentes, com um mesmo nome, mas não ao mesmo tempo. Mas como isto é um tipo de situação muito especifica, não irei entrar em detalhes neste momento, sobre a mesma. Isto para não confundir, quem esteja tentando aprender, a forma correta de se fazer as coisas, e assim evitar erros estranhos.

De qualquer forma, uma das soluções mais simples que existe, para quase todos os tipos de casos, é o de criar um array de objetos. Onde cada objeto, que você vier a colocar no gráfico, irá ser representado como sendo um elemento dentro deste array. Está ao meu ver, é talvez a solução mais simples e genérica, que eu consigo imaginar neste momento. Assim, aquele mesmo código 04, pode ser modificado para o que é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_KEY_UP          38
05. #define def_KEY_DOWN        40
06. //+----------------+
07. #define macro_NameObject  "Demo" + (string)ObjectsTotal(0)
08. //+------------------------------------------------------------------+
09. string  gl_Objs[2];
10. //+------------------------------------------------------------------+
11. int OnInit()
12. {
13.     ObjectCreate(0, gl_Objs[0] = macro_NameObject, OBJ_VLINE, 0, 0, 0);
14.     ObjectSetInteger(0, gl_Objs[0], OBJPROP_COLOR, clrRoyalBlue);
15.     ObjectCreate(0, gl_Objs[1] = macro_NameObject, OBJ_HLINE, 0, 0, 0);
16.     ObjectSetInteger(0, gl_Objs[1], OBJPROP_COLOR, clrPurple);
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.     return rates_total;
24. };
25. //+------------------------------------------------------------------+
26. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
27. {
28.     static int p = 0;
29.     MqlRates rate[1];
30. 
31.     switch(id)
32.     {
33.         case CHARTEVENT_KEYDOWN:
34.             switch ((int)lparam)
35.             {
36.                 case def_KEY_DOWN:
37.                     p = (p < Bars(_Symbol, _Period) ? p + 1 : p);
38.                     break;
39.                 case def_KEY_UP:
40.                     p = (p > 0 ? p - 1 : p);
41.                     break;
42.                 default:
43.                     return;
44.             }
45.             Comment(StringFormat("Current bar analyzed: %d", p));
46.             CopyRates(_Symbol, _Period, p, rate.Size(), rate);
47.             ObjectMove(0, gl_Objs[0], 0, rate[0].time, rate[0].close);
48.             ObjectMove(0, gl_Objs[1], 0, rate[0].time, rate[0].close);
49.             break;
50.     }
51.     ChartRedraw();
52. };
53. //+------------------------------------------------------------------+
54. void OnDeinit(const int reason)
55. {
56.     Comment("");
57.     for (uint c = 0; c < gl_Objs.Size(); c++)
58.         ObjectDelete(0, gl_Objs[c]);
59.     ChartRedraw();
60. };
61. //+------------------------------------------------------------------+

Código 05

Claro que aqui estou fazendo as coisas da maneira o mais simples possível. Quem vem acompanhando e praticando o que está sendo mostrado nos artigos, sabe que podemos criar uma solução bem mais elaborada, com o atual nível de conhecimento mostrado até aqui. Porém, toda via e, entretanto, o que de fato nos interessa, será sempre o resultado final. Este pode ser visto na animação logo abaixo.

Animação 05

Note que o resultado é completamente diferente do que foi visto na animação 04. Porém, a parte importante, é que se você comparar o código 05, com o código 04. Irá notar que fizemos quase que nenhuma mudança no código. Isto a fim de corrigir o problema que estava sendo gerado pelo código 04. Sendo o ponto mais marcante, a declaração que é vista na linha nove deste código 05. Mas como somente isto, não seria de fato suficiente para resolver todos os problemas. Foi preciso também uma outra mudança. Esta pode ser vista na linha sete deste código 05.

Note que neste caso, mudamos a definição do que seria o nome do objeto, para uma macro. Nesta macro temos algo realmente importante sendo feito. Que é a utilização da função ObjectsTotal. Esta função da biblioteca padrão do MQL5, irá nos dizer quantos objetos existem no gráfico, ou que estão na fila para serem colocados no gráfico. Ao fazermos isto, não importa quantos objetos venhamos a colocar no gráfico. Todos irão sempre ter um nome único. Mesmo que estejamos utilizando programas diferentes. De diferentes autores. Já que, se removermos um objeto e logo depois criarmos um outro, mesmo que eles venham a ter um nome muito parecido. Ambos serão de fato únicos. Justamente devido a esta função ObjectsTotal, que podemos observar sendo utilizada na macro.

Algo muito simples, porém muito eficiente. No resto, as mudanças que foram feitas, são muito fáceis de serem compreendidas por quem vem estudado os artigos. Não precisando assim que entremos em mais detalhes sobre elas. Apesar de toda esta simplicidade, você não deve se esquecer do seguinte fato: Como a macro irá sempre criar um nome único. Você precisa guardar o nome de um objeto já criado, em algum lugar. No caso o lugar é justamente o array da linha nove. Sem isto, você não conseguiria encontrar um objeto que já estivesse presente no gráfico.

Agora antes de terminamos este artigo. Quero explicar uma outra coisa, que iremos utilizar muito. Mas muito mesmo, durante diversos outros artigos futuros. No entanto, para separar adequadamente as coisas, vamos a um novo tópico.


Nome curto

Até o devido momento, todos os códigos mostrados, são quase que um código único. Devendo ser utilizado, via de regra, um após o outro. Porém, na pratica e em um ambiente real, as coisas nem sempre são assim tão simples e simpáticas. Por conta disto, nós programadores, precisamos tomar alguns cuidados e saber como fazer certas coisas. Entre estas coisas, está o de saber, como acessar um indicador que esteja no gráfico. E o motivo para isto, você meu caro e estimado leitor, irá ver mais para a frente, quando começarmos a desenvolver algumas coisas um pouco mais elaboradas, por assim dizer.

Como usuário, você talvez esteja imaginando: Mas é claro que sei como acessar um indicador. Basta pressionar CTRL + I. Uma janela será aberta, e nela me será permitido ter acesso aos indicadores presentes no gráfico. E se eu desejar colocar um no gráfico, tudo que preciso fazer, será ir no navegador, procurar o indicador desejado, e pronto. Depois arrasto ele para o gráfico, e o MetaTrader 5 o irá fazer o resto. Simples assim.

Bem, como eu disse, esta é a visão de um usuário. Porém, toda via e, entretanto, como programador, temos meios diferentes de fazer as coisas. E precisamos de uma visão, igualmente diferente a fim de conseguir compreender como as coisas funcionam. Neste caso, esta visão de usuário, nada irá lhe ajudar. Muito pelo contrário. Ela talvez até venha a lhe atrapalhar a entender certos detalhes que iremos ver futuramente.

E como quero que você, comece a se acostumar, e a pensar como um programador. Precisamos começar a falar de modo um pouco mais profundo, sobre como seria a visão de um programador, frente ao que podemos ou não fazer no MetaTrader 5. Assim como também, precisamos entender, como o MetaTrader 5 entende o que estamos colocando em um código em MQL5. Isto porque o MQL5, foi pensado para ser a nossa forma de dizer ao MetaTrader 5 o que desejamos fazer.

Ok, diferente da forma como um usuário enxerga uma aplicação que esteja rodando em um gráfico no MetaTrader 5. Nos programadores temos meios de perguntar ao MetaTrader 5, quais aplicações estão sendo executadas, naquele momento. E com isto, podemos de forma automática, adicionar ou mesmo remover uma aplicação do gráfico. Na maior parte das vezes, o problema está em identificar os indicadores que estejam no gráfico. Isto por que, diferente do que muitos podem imaginar. Um indicador pode ter um nome, que será visto pelo código, totalmente diferente do nome que o executável da aplicação terá.

E este nome, que será visto pelo código, não pode ser, ou melhor dizendo, não deverá ser modificado pelo usuário. Se bem que você, como programador, até possa permitir isto. Porém não é aconselhável. Isto para evitar problemas, que neste momento, será difícil de você entender a natureza do mesmo.

Legal, então temos como definir um nome, para nossa aplicação. Isto quando estamos lidando com indicadores. Bem, mas como isto é feito? Certo, meu caro leitor, isto é feito, com o uso de uma função presente na biblioteca padrão do MQL5, IndicatorSetString. Apesar de parecer algo banal e até mesmo desnecessário. O fato de definirmos um nome curto para nosso indicador, tornará diversas coisas muito mais simples de serem feitas. Mas esta mesma função não se pressa apenas a definir um nome para nosso indicador. Ela também serve para outros propósitos ainda mais nobres. Mas primeiro vamos ver como fazemos para definir um nome interno para nosso indicador. Isto é feito utilizando algo parecido como o que é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. int OnInit()
05. {
06.     IndicatorSetString(INDICATOR_SHORTNAME, "Version Demo");
07. 
08.     return INIT_SUCCEEDED;
09. };
10. //+------------------------------------------------------------------+
11. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
12. {
13.     return rates_total;
14. };
15. //+------------------------------------------------------------------+

Código 06

Não importa o nome que o usuário, ou até mesmo você, venha a dar ao executável deste código 06. No final das contas, o nome que nos interessa, será o que estiver sendo definido na linha seis. Você pode colocar qualquer coisa como sendo o nome do indicador. Porém, é aconselhável que você defina um nome sugestivo. Que diga o propósito do indicador em poucas palavras. Isto é que definimos como sendo um nome curto.

Mas por que definir este tipo de coisa? Qual a utilidade ou proposito para tal coisa? Bem, meu caro leitor, explicar isto, neste exato momento, é um tanto quanto complicado. Isto por que, para que viesse de fato a ficar claro, por que precisamos definir um nome curto, para nossos indicadores, exigiria mostrar algo. Que neste momento, iria mais confundir e complicar a sua cabeça, do que de fato esclarecer as coisas. Porém, quero que você procure sempre, definir um nome curto e significativo para qualquer indicador que você venha a implementar. Pois futuramente, você isto irá lhe poupar o trabalho de ter que definir tais nomes. Isto caso você queira utilizar o que será mostrado. De qualquer forma, é uma simples linha que você precisa adicionar ao código. E irá lhe poupar muitas frustrações futuras.


Considerações finais

Neste artigo foi visto como poderíamos controlar de forma simples alguns objetos. Vimos como podemos colocar mais de um objeto em um mesmo gráfico, usando para isto uma aplicação. E além disto, começamos a ver a importância de definir um nome curto, para todo e qualquer indicador que venhamos a implementar.

Todos estes conceitos, que aparentemente parecem ser coisas isoladas. Devem ser pensando como uma entidade mais global. De qualquer forma, este artigo, foi apenas para apresentarmos o que seria, uma maneira simples de lidar com diferentes problemas. Já que muitas vezes, quando estamos iniciando nosso aprendizado, acabamos cometendo diversos erros. Que apesar de serem simples e fáceis de serem evitados. Destrói completamente a nossa moral e acabamos achando que programar é algo para poucos. Sendo que na verdade, programação é algo que todos deveriam saber fazer. Isto para sempre conseguir colocar suas ideias em prática.

Pelo sim, ou pelo não, no anexo, estarei deixando os códigos que foram vistos aqui. Isto para que você pratique e estude a fim de não cometer os mesmos erros, que todos cometemos quando estamos aprendendo a fazer as coisas.

Arquivos anexados |
Anexo.zip (3.7 KB)
Exemplo de Otimização Estocástica e Controle Ótimo Exemplo de Otimização Estocástica e Controle Ótimo
Este Expert Advisor, chamado SMOC (provavelmente abreviação de Stochastic Model Optimal Control), é um exemplo simples de um sistema de negociação algorítmica avançado para o MetaTrader 5. Ele utiliza uma combinação de indicadores técnicos, controle preditivo baseado em modelos e gerenciamento dinâmico de risco para tomar decisões de negociação. O EA incorpora parâmetros adaptativos, dimensionamento de posição baseado em volatilidade e análise de tendências para otimizar seu desempenho em diferentes condições de mercado.
Criando um Expert Advisor Integrado MQL5-Telegram (Parte 5): Enviando Comandos do Telegram para o MQL5 e Recebendo Respostas em Tempo Real Criando um Expert Advisor Integrado MQL5-Telegram (Parte 5): Enviando Comandos do Telegram para o MQL5 e Recebendo Respostas em Tempo Real
Neste artigo, criamos diversas classes para facilitar a comunicação em tempo real entre o MQL5 e o Telegram. Focamos na obtenção de comandos a partir do Telegram, sua decodificação e interpretação, e no envio de respostas adequadas de volta. Ao final, garantimos que essas interações estejam efetivamente testadas e operacionais dentro do ambiente de negociação.
Criando um Painel Administrativo de Negociação em MQL5 (Parte II): Aprimorando a Responsividade e Mensagens Rápidas Criando um Painel Administrativo de Negociação em MQL5 (Parte II): Aprimorando a Responsividade e Mensagens Rápidas
Neste artigo, vamos aprimorar a responsividade do Painel Administrativo que criamos anteriormente. Além disso, vamos explorar a importância das mensagens rápidas no contexto de sinais de negociação.
Critérios de tendência no trading Critérios de tendência no trading
As tendências são parte importante de muitas estratégias de negociação. Neste artigo, examinaremos algumas das ferramentas usadas para identificar tendências e suas características. Compreender e interpretar corretamente as tendências pode aumentar significativamente o desempenho do trading e minimizar riscos.