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

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

MetaTrader 5Exemplos |
71 0
CODE X
CODE X

Introdução

No artigo anterior Do básico ao intermediário: Eventos em Objetos (I), foi explicado e demonstrado, o que seria a primeira parte básica onde eventos em objetos seria o foco principal. Porém ficou faltando falar de outros três eventos que podem vir a ser disparados quando um objeto recebe algum tipo de interação com o usuário. Sendo que destes três, um precisaria ser ligado, para que de fato o MetaTrader 5 o viesse a disparar. Caso contrário, mesmo que seu código tenha meios de tratar este evento. Ele jamais iria ser notificado de que tal evento ocorreu.

Ok, como quero que você, meu caro leitor, entenda cada um destes eventos, antes de poder usá-los em conjunto. Vamos fazer o seguinte: Iremos criar pequenos tópicos, apenas para explicar, como e quando cada um destes três últimos eventos são disparados pelo MetaTrader 5. Assim que você os entender, poderemos ver como os usar em conjunto de modo a implementar algum tipo de funcionalidade, que possa vir a ser divertida. Então vamos começar.


Evento CHARTEVENT_OBJECT_DELETE

Este evento assim como o CHARTEVENT_OBJECT_CREATE e entre outros que estão relacionados ao mouse, precisam ser ligados e desligados pela sua aplicação. Isto para que o MetaTrader 5, saiba quando uma aplicação em um gráfico precise ser notificada sobre a remoção de algum objeto que estaria presente no gráfico.

Este definitivamente é um evento, cujo objetivo podemos afirmar ser preventivo. Isto porque, sempre que desejamos manter nossa aplicação dentro de uma certa configuração de objetos. Podemos usar este evento, para garantir que nenhum objeto sensível, ou essencial será removido do gráfico pelo usuário. Seja por erro ao remover objetos do gráfico. Seja por qualquer outro motivo.

Basicamente este evento, é bem simples. Porém é preciso tomar alguns cuidados no que tange a parte da programação, ou implementação do código. O motivo para tais cuidados é o fato de que em alguns casos podemos ter problemas relacionados ao padrão de cores. O que acaba atrapalhando e muito a correta visualização do objeto quando este venha a precisar ser recriado de modo automático pela aplicação.

Mas isto que estou dizendo, não será de modo algum, uma preocupação aqui para nós. Já que o conteúdo aqui, não é voltado a explicar como implementar uma solução genérica, que consiga cobrir todos os casos possíveis. Mesmo porque, cada caso é um caso.

Não existe de forma alguma, uma maneira totalmente integrada e genérica, de se recriar um objeto, que tenha sido removido indevidamente do gráfico. Você como programador, pode pensar em diversas formas e maneiras de garantir isto. Pessoalmente sugiro o uso de uma pequena estrutura, onde as propriedades dos objetos que você, ou melhor dizendo, que sua aplicação esteja criando, sejam armazenadas. Assim quando a aplicação vier a precisar recriar o objeto, ela o fará com um padrão de cores, ou posicionamento adequado. Além é claro de outras questões, como fonte, tamanho da fonte, dimensão do objeto, enfim acho que deu para entender.

Ok, depois desta breve introdução, acredito que você já esteja pronto para ver o que será o primeiro código deste artigo. Este é mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_Prefix  "Demo"
05. //+------------------------------------------------------------------+
06. #define macro_NameObject  def_Prefix + (string)(ObjectsTotal(0) + 1)
07. //+------------------------------------------------------------------+
08. string gl_szObjectName;
09. //+------------------------------------------------------------------+
10. int OnInit()
11. {
12.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
13.     ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true);
14. 
15.     gl_szObjectName = macro_NameObject;
16.     Proc_Object();
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.     switch (id)
29.     {
30.         case CHARTEVENT_MOUSE_MOVE:
31.             ObjectSetString(0, gl_szObjectName, OBJPROP_TEXT, StringFormat("%03d : %03d", (ushort)lparam, (ushort)dparam));
32.             break;        
33.         case CHARTEVENT_OBJECT_DELETE:
34.             if (sparam == gl_szObjectName) Proc_Object();
35.             break;
36.     }
37.     ChartRedraw();
38. };
39. //+------------------------------------------------------------------+
40. void OnDeinit(const int reason)
41. {
42.     ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, false);
43.     ObjectsDeleteAll(0, def_Prefix);
44.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
45.     ChartRedraw();
46. };
47. //+------------------------------------------------------------------+
48. void Proc_Object(void)
49. {
50.     ObjectCreate(0, gl_szObjectName, OBJ_LABEL, 0, 0, 0);
51.     ObjectSetInteger(0, gl_szObjectName, OBJPROP_SELECTABLE, true);
52.     ObjectSetInteger(0, gl_szObjectName, OBJPROP_XDISTANCE, 50);
53.     ObjectSetInteger(0, gl_szObjectName, OBJPROP_YDISTANCE, 50);
54.     ObjectSetInteger(0, gl_szObjectName, OBJPROP_XSIZE, 150);
55.     ObjectSetInteger(0, gl_szObjectName, OBJPROP_COLOR, clrMediumBlue);
56.     ObjectSetInteger(0, gl_szObjectName, OBJPROP_FONTSIZE, 20);
57.     ObjectSetString(0, gl_szObjectName, OBJPROP_FONT, "Lucida Console");
58. }
59. //+------------------------------------------------------------------+

Código 01

Este código 01, tem um objetivo muito simples: Mostrar o que acontece quando removemos um objeto do gráfico. Como precisamos ligar e desligar a notificação, para que o MetaTrader 5 nos diga se um objeto foi ou não removido. Este código torna bastante simples entender como podemos fazer as coisas acontecerem.

Talvez a parte mais complicada, não seja o de ligar a notificação. Pois isto é simples de ser feito. Bastando para isto usarmos a linha 13. Normalmente ligamos a notificação, já logo no início da execução da aplicação. Isto para evitar perder algum evento de remoção que possa vir a acontecer. Porém, a parte difícil é justamente saber quando desligar a notificação. Já que o MetaTrader 5 trabalhar de uma determinada maneira. E dependendo do momento em que a notificação vier a ser desligada, você pode vir a ter resultados bem estranhos. Mas na maior parte das vezes completamente inofensivo.

Para entender isto, procure mudar o conteúdo visto na linha 42 de lugar. Já que ela é a responsável por desligar as notificações de evento, quando removemos um objeto do gráfico. Como o código fonte estará no anexo. Você pode experimentar trocar o conteúdo da linha 42 com a linha 43. Isto tornará o resultado da retirada do indicador do gráfico, algo bem interessante. Já que ao fazer este tipo de coisa, você irá ver que nem sempre podemos fazer as coisas em qualquer ordem. E isto lhe ajudará a entender diversas questões, que de outra forma seria complicado de ser explicado.

De qualquer maneira, quando este código 01 for executado, você poderá fazer basicamente dois tipos de coisas. A primeira é vista na animação logo abaixo.

Animação 01

Neste caso, estamos selecionando o objeto e o deletando fazendo uso da tecla DELETE. Note que o objeto é recriado imediatamente após termos pressionado DELETE. No entanto, devido ao fato de ele estar ligado ao evento de mouse, para ter as informações sendo atualizadas. Somente depois de um movimento ou evento do mouse ter ocorrido, é que passamos a ter as informações como esperado. A segunda situação, seria uma tentativa de remover o objeto, usando para isto a janela com a lista de objetos. Isto pode ser visto na animação logo na sequência.

Animação 02

Da mesma forma que a animação 01 mostra. Aqui na animação 02, fica claro, que no exato momento em que removemos o objeto, ele é recriado. No entanto, apesar disto, a janela não o mostra imediatamente. É preciso abrir novamente a janela para que ele volte a ser mostrado na lista de objetos presentes no gráfico.

Ok. Este foi o evento para que fossemos informados de que um objeto foi removido do gráfico. Agora temos outros dois para podermos ver. Porém, agora vem algumas questões um tanto quanto curiosas. E para explicar melhor, isto vamos iniciar um novo tópico.


Evento CHARTEVENT_OBJECT_CHANGE

Este evento, que iremos ver agora, é um tanto quanto curioso, se você entender como o mesmo funciona. Isto porque, dependendo da situação, você pode implementar coisas bem interessantes e muito bacanas com ele. Já que ele é disparado sempre que um objeto vier a sofrer alguma mudança em uma de suas propriedades.

No tópico anterior, mencionei o fato de que, não existe uma forma de criamos um mecanismo 100% genérico para recriar um objeto que foi deletado. Isto de fato é verdade. Porém, dependendo da forma como você implementar o código, pode ser que você consiga um meio adequado para recriar, quase todo tipo de objeto, de maneira genérica. Com o atual nível, mostrado até aqui, fazer isto é de fato uma tarefa bastante desafiadora. Portanto, tenha calma, pois apesar de podermos gerar boas aplicações com mecanismos relativamente simples. Pode ser que você encontre, no futuro forma melhores. Já que o conhecimento, vai se acumulando, assim como a experiência. Por isto, é bom estudar e praticar sempre. Não tenha presa. Mas seja esforçado, no que tange buscar por mais conhecimento.

Para mostrar como as coisas podem vir a ser interessantes, e como conhecer o que se está implementando é importante. Vamos pegar o código 01, visto no tópico anterior, e o modificar para podermos ver este evento deste tópico de agora funcionando. Isto é feito, no código logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_Prefix  "Demo"
05. //+------------------------------------------------------------------+
06. #define macro_NameObject  def_Prefix + (string)(ObjectsTotal(0) + 1)
07. //+------------------------------------------------------------------+
08. struct st_Obj
09. {
10. //+----------------+
11.     private:
12.         string  szName,
13.                 font;
14.         bool    Selectable;
15.         int     x,
16.                 y,
17.                 w,
18.                 fontSize;
19.         color   cor;
20. //+----------------+
21.     public:
22. //+----------------+
23.         void SetDefault(const string arg)
24.         {
25.             szName      = arg;
26.             font        = "Lucida Console";
27.             Selectable  = true;
28.             x           = 50;
29.             y           = 50;
30.             w           = 150;
31.             cor         = clrMediumBlue;
32.             fontSize    = 20;
33.         }
34. //+----------------+
35.         void Create(void)
36.         {
37.             ObjectCreate(0, szName, OBJ_LABEL, 0, 0, 0);
38.             ObjectSetInteger(0, szName, OBJPROP_SELECTABLE, Selectable);
39.             ObjectSetInteger(0, szName, OBJPROP_XDISTANCE, x);
40.             ObjectSetInteger(0, szName, OBJPROP_YDISTANCE, y);
41.             ObjectSetInteger(0, szName, OBJPROP_XSIZE, w);
42.             ObjectSetInteger(0, szName, OBJPROP_COLOR, cor);
43.             ObjectSetInteger(0, szName, OBJPROP_FONTSIZE, fontSize);
44.             ObjectSetString(0, szName, OBJPROP_FONT, font);
45.         }
46. //+----------------+
47.         string GetName(void)
48.         {
49.             return szName;
50.         }
51. //+----------------+
52. }gl_Obj;
53. //+------------------------------------------------------------------+
54. int OnInit()
55. {
56.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
57.     ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true);
58. 
59.     gl_Obj.SetDefault(macro_NameObject);
60.     gl_Obj.Create();
61. 
62.     return INIT_SUCCEEDED;
63. };
64. //+------------------------------------------------------------------+
65. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
66. {
67.     return rates_total;
68. };
69. //+------------------------------------------------------------------+
70. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
71. {
72.     switch (id)
73.     {
74.         case CHARTEVENT_MOUSE_MOVE:
75.             ObjectSetString(0, gl_Obj.GetName(), OBJPROP_TEXT, StringFormat("%03d : %03d", (ushort)lparam, (ushort)dparam));
76.             break;        
77.         case CHARTEVENT_OBJECT_DELETE:
78.             if (sparam == gl_Obj.GetName()) gl_Obj.Create();
79.             break;
80.         case CHARTEVENT_OBJECT_CHANGE:
81.             Comment("Ocorreu um evento: CHARTEVENT_OBJECT_CHANGE no objeto ["+sparam+"]");
82.             break;
83.     }
84.     ChartRedraw();
85. };
86. //+------------------------------------------------------------------+
87. void OnDeinit(const int reason)
88. {
89.     Comment("");
90.     ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, false);
91.     ObjectsDeleteAll(0, def_Prefix);
92.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
93.     ChartRedraw();
94. };
95. //+------------------------------------------------------------------+

Código 02

Quando você executar este código 02, irá poder ver duas coisas. A primeira é mostrada na animação logo abaixo.

Animação 03

Note que no exato instante em que mudamos alguma propriedade o objeto, temos disparado um evento que será capturado pela linha 80. Como não estamos filtrando a origem do evento. Qualquer mudança em qualquer objeto irá fazer com que a linha 81 seja mostrada no canto superior esquerdo do gráfico. Como você pode observar sendo feito na animação 03. Mas a questão interessante é justamente, quando um segundo evento acontece, que neste caso é visto na animação 04 logo abaixo.

Animação 04

Que coisa estranha. Por que o objeto não manteve a sua propriedade? Já que estamos chamando o procedimento visto na linha 35. No caso do código 01, eu até entendo o motivo. Mas neste caso, imaginei que se o objeto fosse removido do gráfico. A aplicação o iria criar com os mesmos atributos. Já que não aconteceu uma chamada a SetDefault, a fim de restabelecer os valores que foram modificados na animação 03. Isto ao meu ver é um tanto quanto estranho.

De fato, meu caro leitor, muitos iniciantes costumam cair neste mesmo tipo de armadilha. Onde eles criam um código, mas não conseguem entender certas questões internas do próprio código. Normalmente isto acontece, justamente devido ao fato de que estão copiando o código de algum outro local. Mas também pode acontecer, quando você está experimentando uma nova implementação. Onde tudo parece estar em perfeita ordem, mas quando você vai testar acaba percebendo que falta alguns detalhes ainda a serem implementados. Isto de maneira alguma é um erro. Muito pelo contrário. É uma boa forma de praticar e tentar novas soluções, que podem vir a ser interessantes em algum momento futuro.

Legal. Mas então qual o problema aqui? O detalhe é que, você ao usar o MetaTrader 5, para atualizar alguma propriedade do objeto, não está atualizando as propriedades que o criaram. Apenas está atualizando as propriedades locais do objeto em questão. Assim, quando ele for destruído, e a linha 80 neste código 02 o recriar. Ela o fará utilizando justamente os parâmetros, ou propriedades definidas e ainda mantidas dentro da variável global.

Por isto o objeto está sendo recriado como ele foi configurado no código. Para mudarmos isto, precisamos fazer com que o objeto, de dentro da aplicação, consiga acompanhar esta mudança também. E para isto, precisamos utilizar a captura de evento, feita justamente pela linha 82. Por isto não estou filtrando o resultado neste código 02. Quero que você entenda como a aplicação é notificada sobre uma mudança na propriedade de um dos objetos presentes no gráfico.

Como o MetaTrader apenas nos informa qual o nome do objeto, e não quais propriedades foram modificadas. Precisamos capturar todas elas. Pelo menos as que nos interessa de fato. Já que, apesar de muitos objetos terem propriedades semelhantes, existem aquelas que são oriundas exclusivamente de um determinado objeto. E não aparece em outro. Por isto, falhei que criar uma solução 100% genérica é algo muito complicado.

Ok, tendo isto em mente podemos modificar o código 02, para algo que possa manter algumas das propriedades intactas. Pelo menos durante a execução do código. Já que se a aplicação for removida do gráfico, ela irá perder as propriedades definidas pelo usuário. Voltando a ser aquilo que implementados no código. Existem várias formas de se contornar isto. Mas veremos isto em outro momento.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #define def_Prefix  "Demo"
005. //+------------------------------------------------------------------+
006. #define macro_NameObject  def_Prefix + (string)(ObjectsTotal(0) + 1)
007. //+------------------------------------------------------------------+
008. struct st_Obj
009. {
010. //+----------------+
011.     private:
012.         string  szName,
013.                 font;
014.         bool    Selectable;
015.         int     x,
016.                 y,
017.                 w,
018.                 fontSize;
019.         color   cor;
020. //+----------------+
021.     public:
022. //+----------------+
023.         void SetDefault(const string arg)
024.         {
025.             szName      = arg;
026.             font        = "Lucida Console";
027.             Selectable  = true;
028.             x           = 50;
029.             y           = 50;
030.             w           = 150;
031.             cor         = clrMediumBlue;
032.             fontSize    = 20;
033.         }
034. //+----------------+
035.         void Create(void)
036.         {
037.             ObjectCreate(0, szName, OBJ_LABEL, 0, 0, 0);
038.             ObjectSetInteger(0, szName, OBJPROP_SELECTABLE, Selectable);
039.             ObjectSetInteger(0, szName, OBJPROP_XDISTANCE, x);
040.             ObjectSetInteger(0, szName, OBJPROP_YDISTANCE, y);
041.             ObjectSetInteger(0, szName, OBJPROP_XSIZE, w);
042.             ObjectSetInteger(0, szName, OBJPROP_COLOR, cor);
043.             ObjectSetInteger(0, szName, OBJPROP_FONTSIZE, fontSize);
044.             ObjectSetString(0, szName, OBJPROP_FONT, font);
045.         }
046. //+----------------+
047.         string GetName(void)
048.         {
049.             return szName;
050.         }
051. //+----------------+
052.         void Update(void)
053.         {
054.             font        = ObjectGetString(0, szName, OBJPROP_FONT);
055.             Selectable  = (int)ObjectGetInteger(0, szName, OBJPROP_SELECTABLE);
056.             x           = (int)ObjectGetInteger(0, szName, OBJPROP_XDISTANCE);
057.             y           = (int)ObjectGetInteger(0, szName, OBJPROP_YDISTANCE);
058.             w           = (int)ObjectGetInteger(0, szName, OBJPROP_XSIZE);
059.             fontSize    = (int)ObjectGetInteger(0, szName, OBJPROP_FONTSIZE);
060.             cor         = (color)ObjectGetInteger(0, szName, OBJPROP_COLOR);
061.         }
062. //+----------------+
063. }gl_Obj;
064. //+------------------------------------------------------------------+
065. int OnInit()
066. {
067.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
068.     ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true);
069. 
070.     gl_Obj.SetDefault(macro_NameObject);
071.     gl_Obj.Create();
072. 
073.     return INIT_SUCCEEDED;
074. };
075. //+------------------------------------------------------------------+
076. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
077. {
078.     return rates_total;
079. };
080. //+------------------------------------------------------------------+
081. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
082. {
083.     switch (id)
084.     {
085.         case CHARTEVENT_MOUSE_MOVE:
086.             ObjectSetString(0, gl_Obj.GetName(), OBJPROP_TEXT, StringFormat("%03d : %03d", (ushort)lparam, (ushort)dparam));
087.             break;        
088.         case CHARTEVENT_OBJECT_DELETE:
089.             if (sparam == gl_Obj.GetName()) gl_Obj.Create();
090.             break;
091.         case CHARTEVENT_OBJECT_CHANGE:
092.             if (sparam == gl_Obj.GetName()) gl_Obj.Update();
093.             break;
094.     }
095.     ChartRedraw();
096. };
097. //+------------------------------------------------------------------+
098. void OnDeinit(const int reason)
099. {
100.     ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, false);
101.     ObjectsDeleteAll(0, def_Prefix);
102.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
103.     ChartRedraw();
104. };
105. //+------------------------------------------------------------------+

Código 03

Este código 03, mostra o que precisa ser feito. Quando ele é executado, o resultado é o que podemos ver na animação logo abaixo.

Animação 05

Observe que agora, de fato temos a recriação do objeto, conforme as propriedades que o usuário definiu a pouco. Mesmo que o objeto venha a ser removido do gráfico. Devido a sua importância o mesmo será recriado. Porém, diferente do que acontecia antes, agora ele será recriado não com as propriedades definidas na aplicação. Mas sim utilizando as propriedades definidas pelo usuário e que foram salvas graças a chamada efetuada na linha 92.

Mas, toda via e, entretanto, repare no fato de que estamos filtrando desta vez as coisas. Isto é importante, justamente por conta da própria natureza do que estamos fazendo. Pense no seguinte cenário: Você tem dois objetos no gráfico, e resolve modificar as propriedades de um deles. Até aí ok. Porém quando você remove o objeto que sua aplicação esteja utilizando, ele será imediatamente recriado. No entanto, se não fosse feita a filtragem que é vista na linha 92. O fato de você modificar um objeto, que não aquele observado pela aplicação. Faria com que as propriedades deste outro objeto, fossem colocadas no objeto que a aplicação estaria recriando. Causando assim uma confusão tremenda em tudo que estivesse sendo feito no gráfico em termos de uso de objetos. Por isto está filtragem da linha 92 é tão importante para nós.

Procure experimentar este mesmo código 03, sem o uso desta filtragem da linha 92 e veja os resultados. Existem momentos, em que de fato, tal abordagem pode vir a ser interessante de ser feita. Portanto, entender e ver o que acontece, pode acabar sendo útil para você em algum momento, meu caro leitor.

O aprendizado, não acontece quando apenas acertamos a forma de implementar o código.

Ele também acontece, quando o código não funciona como era esperado.

Neste caso, entender e saber como foi feita a solução, é tão importante quanto a própria solução adotada.

Muito bem, agora já temos elementos suficientes para podemos ver o próximo e último tipo de evento que pode acontecer com um objeto. No caso como se trata de um objeto único, e com um evento totalmente direcionado a ele. Vamos fazer uma brincadeira, que ao meu ver será muito divertida e bastante instrutiva. Já que iremos fazer algo, que por padrão não é feito pelo MetaTrader 5. Mas que poderemos criar uma aplicação que possa fazer tal coisa. Será algo muito interessante e até mesmo bastante divertido, dada a natureza da própria implementação.

Então vamos a um novo tópico, para deixar tudo devidamente separado.


Evento CHARTEVENT_OBJECT_ENDEDIT

Uma das coisas que ao meu entender, é bem engraçada, é o fato de que muitos usuários, não fazem ideia do quanto podemos manipular o MetaTrader 5, a fim de conseguir fazer certos tipos de trabalho. Muitas das vezes, coisas que as pessoas insistem em dizer que não tem como ou não haveria possibilidades de serem feitas.

Bem, basicamente existe uma questão, que por um lado é um tanto quanto inusitada. Enquanto por outro, não faz muito sentido de ser feita como é feita. Mas paciência. O fato é que, diferente do que muitos pensam o MQL5 não é uma linguagem voltada a criar aplicações para o MetaTrader 5. Apesar de servir a grosso modo para tal. Bem lá no fundo, o MQL5, é uma linguagem voltada a nos dar algum tipo de controle sobre como o MetaTrader 5 deverá ou queremos que ele funcione. Claro que dentro de determinadas regras. Estou dizendo isto, pois sem entender este simples e singelo detalhe, fica difícil entender o que iremos fazer neste tópico.

Já que para grande maioria dos usuários, principalmente iniciantes, o que será feito aqui é algo de outro mundo. Talvez algum tipo de código criado por Inteligência artificial ou alienígena. De qualquer forma, não é nada disto. O que vamos fazer, é perfeitamente possível com muito pouco conhecimento, mas com uma boa dose de imaginação e criatividade. Além é claro, uma bela de uma dose de observação.

Não sei se você já reparou em uma coisa: Um objeto OBJ_LABEL é muito parecido com um OBJ_EDIT. Sendo que, a grosso modo, a maior e talvez a única diferença entre ambos objetos seja o fato de que o OBJ_EDIT nos permite editar um texto diretamente no gráfico. Enquanto o objeto OBJ_LABEL, não. Mas será mesmo assim?

Bem, meu caro leitor, o fato é que apesar de muito semelhantes. Um objeto OBJ_EDIT não compartilha coisas com um OBJ_LABEL, e vice-versa. Mas isto se estivermos olhando as coisas pelo ponto de vista do usuário. Já pelo ponto de vista de programação. As coisas não são bem assim. Neste caso, ambos objetos, são basicamente iguais. Podendo inclusive serem colocados para trabalhar em conjunto. Desde que você pense em como fazer isto.

O que iremos fazer aqui é o seguinte: Iremos criar uma forma de tornar um OBJ_LABEL editável diretamente no gráfico. Sem necessitar abrir a janela de propriedades dele a fim de colocar um texto ali. Parece impossível? Bem, vamos ver como isto poderia ser feito. Lembrando que o objetivo aqui é a didática. Então não fique muito apegado ao como o código irá ser implementado. Procure entender, por que o que será visto depois funciona. Esta é a parte importante.

Para começar, precisamos de um código inicial. Como não quero criar muita coisa do zero, para não tomar muito tempo explicado o que está sendo feito. Vamos criar uma variação do código visto no tópico anterior. Este pode ser visto logo abaixo.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #define def_Prefix  "Demo"
005. //+------------------------------------------------------------------+
006. #define macro_NameObject  def_Prefix + (string)(ObjectsTotal(0) + 1)
007. //+------------------------------------------------------------------+
008. struct st_Obj
009. {
010. //+----------------+
011.     private:
012.         string  szName,
013.                 font;
014.         bool    Selectable;
015.         int     x,
016.                 y,
017.                 w,
018.                 h,
019.                 fontSize;
020.         color   cor,
021.                 backColor;
022.         ENUM_OBJECT actual;
023. //+----------------+
024.     public:
025. //+----------------+
026.         void SetDefault(const string arg)
027.         {
028.             szName      = arg;
029.             font        = "Lucida Console";
030.             Selectable  = true;
031.             x           = 50;
032.             y           = 50;
033.             w           = 150;
034.             h           = 27;
035.             cor         = clrMediumBlue;
036.             backColor   = clrWhite;
037.             fontSize    = 20;
038.         }
039. //+----------------+
040.         void Create(const ENUM_OBJECT type)
041.         {
042.             actual = type;
043.             Recreates();
044.         }
045. //+----------------+
046.         void Recreates(void)
047.         {
048.             ObjectCreate(0, szName, actual, 0, 0, 0);
049.             ObjectSetInteger(0, szName, OBJPROP_SELECTABLE, (actual != OBJ_EDIT ? Selectable : false));
050.             ObjectSetInteger(0, szName, OBJPROP_XDISTANCE, x);
051.             ObjectSetInteger(0, szName, OBJPROP_YDISTANCE, y);
052.             ObjectSetInteger(0, szName, OBJPROP_XSIZE, w);
053.             ObjectSetInteger(0, szName, OBJPROP_YSIZE, h);
054.             ObjectSetInteger(0, szName, OBJPROP_COLOR, cor);
055.             ObjectSetInteger(0, szName, OBJPROP_FONTSIZE, fontSize);
056.             ObjectSetString(0, szName, OBJPROP_FONT, font);
057.             if (actual == OBJ_EDIT)
058.             {
059.                 ObjectSetInteger(0, szName, OBJPROP_BGCOLOR, backColor);
060.                 ObjectSetInteger(0, szName, OBJPROP_READONLY, false);
061.             }
062.         }
063. //+----------------+
064.         string GetName(void)
065.         {
066.             return szName;
067.         }
068. //+----------------+
069.         void Update(void)
070.         {
071.             font        = ObjectGetString(0, szName, OBJPROP_FONT);
072.             Selectable  = (int)ObjectGetInteger(0, szName, OBJPROP_SELECTABLE);
073.             x           = (int)ObjectGetInteger(0, szName, OBJPROP_XDISTANCE);
074.             y           = (int)ObjectGetInteger(0, szName, OBJPROP_YDISTANCE);
075.             w           = (int)ObjectGetInteger(0, szName, OBJPROP_XSIZE);
076.             h           = (int)ObjectGetInteger(0, szName, OBJPROP_YSIZE);
077.             fontSize    = (int)ObjectGetInteger(0, szName, OBJPROP_FONTSIZE);
078.             cor         = (color)ObjectGetInteger(0, szName, OBJPROP_COLOR);
079.             backColor   = (color)((ENUM_OBJECT)ObjectGetInteger(0, szName, OBJPROP_TYPE) == OBJ_LABEL ? backColor : ObjectGetInteger(0, szName, OBJPROP_BGCOLOR));
080.         }
081. //+----------------+
082. }gl_Obj;
083. //+------------------------------------------------------------------+
084. int OnInit()
085. {
086.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
087.     ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true);
088. 
089.     gl_Obj.SetDefault(macro_NameObject);
090.     gl_Obj.Create(OBJ_LABEL);
091. 
092.     return INIT_SUCCEEDED;
093. };
094. //+------------------------------------------------------------------+
095. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
096. {
097.     return rates_total;
098. };
099. //+------------------------------------------------------------------+
100. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
101. {
102.     switch (id)
103.     {
104.         case CHARTEVENT_MOUSE_MOVE      :
105.             ObjectSetString(0, gl_Obj.GetName(), OBJPROP_TEXT, StringFormat("%03d : %03d", (ushort)lparam, (ushort)dparam));
106.             break;        
107.         case CHARTEVENT_OBJECT_DELETE   :
108.             if (sparam == gl_Obj.GetName())gl_Obj.Recreates();
109.             break;
110.         case CHARTEVENT_OBJECT_CHANGE   :
111.             if (sparam == gl_Obj.GetName()) gl_Obj.Update();
112.             break;
113.     }
114.     ChartRedraw();
115. };
116. //+------------------------------------------------------------------+
117. void OnDeinit(const int reason)
118. {
119.     ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, false);
120.     ObjectsDeleteAll(0, def_Prefix);
121.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
122.     ChartRedraw();
123. };
124. //+------------------------------------------------------------------+

Código 04

Aqui adicionei algumas poucas coisas. Porém você precisa notar o seguinte: O funcionando deste código 04 é o mesmo do código 03. Mas note que na linha 40, quando chamamos o procedimento de criar o objeto, precisamos dizer que tipo de objeto deverá ser criado. No caso, iremos trabalhar com as possibilidades de usar o OBJ_EDIT e OBJ_LABEL. Ao fazermos estas mudanças, começamos a nos preparar a fim de permitir uma outra coisa que você logo irá entender. Que será justamente a manipulação do objeto OBJ_LABEL a fim de editar o texto diretamente no gráfico.

Agora preste muita atenção ao seguinte ponto, visto neste código 04. Observe que na linha 49, que é onde realmente criamos o objeto. Estamos definindo a propriedade OBJPROP_SELECTABLE. Esta propriedade é muito importante que venhamos a fazer a definição da mesma de forma correta. Em um objeto OBJ_LABEL, precisamos definir esta propriedade como sendo true. Isto caso você queira poder selecionar o objeto posteriormente. Como temos feito até o presente momento. No entanto, ao definir esta mesma propriedade como true em um objeto do tipo OBJ_EDIT. Ficaremos impedidos de editar o texto diretamente no gráfico.

Como foi dito antes. Cada objeto tem seus detalhes e dependendo do tipo de coisa que desejamos fazer, precisamos que ele tenha suas propriedades definidas de uma determinada maneira. Então de forma resumida. Quando tivermos um objeto OBJ_EDIT com a propriedade OBJPROP_SELECTABLE em true, não poderemos editar o texto. Mas poderemos mover o objeto na tela. Quando esta mesma propriedade, estiver configurada como false, poderemos editar o texto, porém não poderemos mover o objeto na tela.

Ok, agora note que na linha 90 estamos dizendo que tipo de objeto queremos e iremos criar. Ou seja, um objeto do tipo OBJ_LABEL. Porém na linha 108, não usamos mais a chamada Create. Mas sim a chamada que irá recriar o objeto. Isto porque já sabemos que tipo precisaremos criar. Mas a aplicação não, já que se você utilizar o método de carregar o tipo de objeto, irá quase sempre obter o tipo errado. Isto por conta que o MetaTrader 5, já terá destruído o objeto.

Quando este evento CHARTEVENT_OBJECT_DELETE, chega até nós, ele não estará nos pedindo permissão para destruir o objeto. O MetaTrader 5 já terá destruído objeto. Por isto, salvo o fato de que estejamos utilizando um objeto do tipo zero, ou seja um OBJ_VLINE, nunca iremos saber o tipo do objeto destruído, perguntando ao MetaTrader 5, que tipo de objeto foi destruído. Já que ele não saberá informar isto. Por conta que o objeto já não existe mais.

Até aqui, acredito que tudo tenha sido muito simples e fácil de entender. Agora vem a parte divertida. Vamos pegar e modificar este código 04 de forma que teremos diversos eventos trabalhando em conjunto. Isto de forma a conseguir obter o resultado que pretendemos criar.

Como a coisa pode vir a ser um tanto quanto complicada, se vier a ser vista de uma só vez. Vamos fazer isto em dois passos simples. O primeiro é mostrado logo no código que você pode ver na sequência.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #define def_Prefix  "Demo"
005. //+------------------------------------------------------------------+
006. #define macro_NameObject  def_Prefix + (string)(ObjectsTotal(0) + 1)
007. //+------------------------------------------------------------------+
008. struct st_Obj
009. {
010. //+----------------+
011.     private:
012.         string  szName,
013.                 font,
014.                 text;
015.         bool    Selectable;
016.         int     x,
017.                 y,
018.                 w,
019.                 h,
020.                 fontSize;
021.         color   cor,
022.                 backColor;
023.         ENUM_OBJECT actual;
024. //+----------------+
025.     public:
026. //+----------------+
027.         void SetDefault(const string arg)
028.         {
029.             szName      = arg;
030.             font        = "Lucida Console";
031.             Selectable  = true;
032.             x           = 50;
033.             y           = 50;
034.             w           = 250;
035.             h           = 27;
036.             cor         = clrMediumBlue;
037.             backColor   = clrWhite;
038.             fontSize    = 20;
039.         }
040. //+----------------+
041.         void Create(const ENUM_OBJECT type)
042.         {
043.             actual  = type;
044.             text    = EnumToString(type);
045.             Recreates();
046.         }
047. //+----------------+
048.         void Recreates(void)
049.         {
050.             ObjectCreate(0, szName, actual, 0, 0, 0);
051.             ObjectSetInteger(0, szName, OBJPROP_SELECTABLE, (actual != OBJ_EDIT ? Selectable : false));
052.             ObjectSetInteger(0, szName, OBJPROP_XDISTANCE, x);
053.             ObjectSetInteger(0, szName, OBJPROP_YDISTANCE, y);
054.             ObjectSetInteger(0, szName, OBJPROP_XSIZE, w);
055.             ObjectSetInteger(0, szName, OBJPROP_YSIZE, h);
056.             ObjectSetInteger(0, szName, OBJPROP_COLOR, cor);
057.             ObjectSetInteger(0, szName, OBJPROP_FONTSIZE, fontSize);
058.             ObjectSetString(0, szName, OBJPROP_FONT, font);
059.             ObjectSetString(0, szName, OBJPROP_TEXT, text);
060.             if (actual == OBJ_EDIT)
061.             {
062.                 ObjectSetInteger(0, szName, OBJPROP_BGCOLOR, backColor);
063.                 ObjectSetInteger(0, szName, OBJPROP_READONLY, false);
064.             }
065.         }
066. //+----------------+
067.         string GetName(void)
068.         {
069.             return szName;
070.         }
071. //+----------------+
072.         void Update(void)
073.         {
074.             font        = ObjectGetString(0, szName, OBJPROP_FONT);
075.             Selectable  = (int)ObjectGetInteger(0, szName, OBJPROP_SELECTABLE);
076.             x           = (int)ObjectGetInteger(0, szName, OBJPROP_XDISTANCE);
077.             y           = (int)ObjectGetInteger(0, szName, OBJPROP_YDISTANCE);
078.             w           = (int)ObjectGetInteger(0, szName, OBJPROP_XSIZE);
079.             h           = (int)ObjectGetInteger(0, szName, OBJPROP_YSIZE);
080.             fontSize    = (int)ObjectGetInteger(0, szName, OBJPROP_FONTSIZE);
081.             cor         = (color)ObjectGetInteger(0, szName, OBJPROP_COLOR);
082.             backColor   = (color)((ENUM_OBJECT)ObjectGetInteger(0, szName, OBJPROP_TYPE) == OBJ_LABEL ? backColor : ObjectGetInteger(0, szName, OBJPROP_BGCOLOR));
083.         }
084. //+----------------+
085. }gl_Obj;
086. //+------------------------------------------------------------------+
087. int OnInit()
088. {
089.     ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true);
090. 
091.     gl_Obj.SetDefault(macro_NameObject);
092.     gl_Obj.Create(OBJ_LABEL);
093. 
094.     return INIT_SUCCEEDED;
095. };
096. //+------------------------------------------------------------------+
097. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
098. {
099.     return rates_total;
100. };
101. //+------------------------------------------------------------------+
102. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
103. {
104.     switch (id)
105.     {
106.         case CHARTEVENT_OBJECT_CLICK    :
107.             if (sparam == gl_Obj.GetName())
108.             {
109.                 string sz0 = ObjectGetString(0, sparam, OBJPROP_TEXT);
110.                 if ((ENUM_OBJECT)ObjectGetInteger(0, sparam, OBJPROP_TYPE) == OBJ_EDIT)
111.                     break;
112.                 ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, false);
113.                 ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, true);
114.                 ObjectDelete(0, sparam);
115.                 gl_Obj.Create(OBJ_EDIT);
116.                 ObjectSetString(0, sparam, OBJPROP_TEXT, sz0);
117.             }
118.             break;
119.         case CHARTEVENT_OBJECT_CREATE   :
120.             if (sparam == gl_Obj.GetName())
121.             {
122.                 ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, false);
123.                 ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true);
124.             }
125.             break;
126.         case CHARTEVENT_OBJECT_DELETE   :
127.             if (sparam == gl_Obj.GetName())gl_Obj.Recreates();
128.             break;
129.         case CHARTEVENT_OBJECT_CHANGE   :
130.             if (sparam == gl_Obj.GetName()) gl_Obj.Update();
131.             break;
132.     }
133.     ChartRedraw();
134. };
135. //+------------------------------------------------------------------+
136. void OnDeinit(const int reason)
137. {
138.     ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, false);
139.     ObjectsDeleteAll(0, def_Prefix);
140.     ChartRedraw();
141. };
142. //+------------------------------------------------------------------+

Código 05

Aqui neste código 05, temos uma coisa muito doida acontecendo. Você pode observar isto, na animação logo abaixo.

Animação 06

Preste muita atenção a esta animação 06, meu caro leitor. Observe que na linha 92 estamos pedindo para criar um objeto do tipo OBJ_LABEL. Por conta disto, na linha 44, o texto que nos será mostrado é o tipo de objeto do qual estaremos utilizando. Até aí normal. Porém no momento em que você criar neste objeto do tipo OBJ_LABEL, ele será modificado para um objeto do tipo OBJ_EDIT. E isto estará sendo feito justamente por conta do código de tratamento de evento que está sendo capturado na linha 106. Note que estamos focando toda a nossa atenção ao objeto que estaremos criando inicialmente.

No entanto, devido a linha 109, o texto que estiver no objeto OBJ_LABEL será transferido para o objeto OBJ_EDIT, na linha 116. Isto é importante para nós. Já que sem está transferência, iriamos ter um outro texto sendo colocado no objeto OBJ_EDIT. E não é isto que queremos. Queremos de fato é poder modificar o texto do objeto OBJ_LABEL, diretamente no gráfico.

Agora quero que você note o seguinte: Dentro deste evento CHARTEVENT_OBJECT_CLICK, estaremos destruindo o objeto do tipo OBJ_LABEL e criando um do tipo OBJ_EDIT. Mas como ligamos a notificação para o evento CHARTEVENT_OBJECT_DELETE, na linha 89, precisamos desligar ele. Isto é feito na linha 112. Logo depois ligamos um outro evento, cujo objetivo será o de informar ao MetaTrader 5 que desejamos ser notificados sobre a criação de um objeto. Isto irá fazer com que a linha 119 venha a capturar o evento de criação do objeto, que estará sendo feito pela aplicação. Neste tratador, iremos desligar a notificação de criação e ligar novamente a notificação de destruição.

Com isto agora o tratador da linha 126 irá voltar a funcionar. Porém não de forma totalmente perfeita. Isto pelo simples fato, de que se você destruir o objeto OBJ_EDIT, ele será recriado, mas seu texto já não corresponderá ao texto original que existia antes do objeto ser destruído.

Esta pequena correção irei deixar como dever de casa para que você pratique e procure uma forma de resolver este pequeno inconvincente. É algo muito simples de ser feito. Porém, lembre-se de que você precisará manipular algumas informações, a fim de reaver o texto que existia no momento em que o objeto do tipo OBJ_EDIT foi criado. Já reaver o texto que existia entre a criação do OBJ_EDIT e a sua destruição, exigirá bem mais trabalho. Já que você precisará também observar os eventos de teclado e de mouse. Isto a fim de manter um texto atualizado em memória, para poder recriar o mesmo.

Pessoalmente esta segunda parte acho um tanto quanto desnecessário e um trabalho um tanto quanto chato. Já que se o usuário destruiu o texto, antes de ter salvado o mesmo dentro do objeto do tipo OBJ_LABEL. Ele é que procure relembrar o texto que havia no objeto do tipo OBJ_EDIT. (RISOS).

Ok, agora vem a parte final, que é justamente utilizar o evento tema deste tópico. Para fazer isto, faremos uma última modificação no código. Esta pode ser vista logo abaixo.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #define def_Prefix  "Demo"
005. //+------------------------------------------------------------------+
006. #define macro_NameObject  def_Prefix + (string)(ObjectsTotal(0) + 1)
007. //+------------------------------------------------------------------+
008. struct st_Obj
009. {
010. //+----------------+
011.     private:
012.         string  szName,
013.                 font,
014.                 text;
015.         bool    Selectable;
016.         int     x,
017.                 y,
018.                 w,
019.                 h,
020.                 fontSize;
021.         color   cor,
022.                 backColor;
023.         ENUM_OBJECT actual;
024. //+----------------+
025.     public:
026. //+----------------+
027.         void SetDefault(const string arg)
028.         {
029.             szName      = arg;
030.             font        = "Lucida Console";
031.             Selectable  = true;
032.             x           = 50;
033.             y           = 50;
034.             w           = 250;
035.             h           = 27;
036.             cor         = clrMediumBlue;
037.             backColor   = clrWhite;
038.             fontSize    = 20;
039.         }
040. //+----------------+
041.         void Create(const ENUM_OBJECT type)
042.         {
043.             actual  = type;
044.             text    = EnumToString(type);
045.             Recreates();
046.         }
047. //+----------------+
048.         void Recreates(void)
049.         {
050.             ObjectCreate(0, szName, actual, 0, 0, 0);
051.             ObjectSetInteger(0, szName, OBJPROP_SELECTABLE, (actual != OBJ_EDIT ? Selectable : false));
052.             ObjectSetInteger(0, szName, OBJPROP_XDISTANCE, x);
053.             ObjectSetInteger(0, szName, OBJPROP_YDISTANCE, y);
054.             ObjectSetInteger(0, szName, OBJPROP_XSIZE, w);
055.             ObjectSetInteger(0, szName, OBJPROP_YSIZE, h);
056.             ObjectSetInteger(0, szName, OBJPROP_COLOR, cor);
057.             ObjectSetInteger(0, szName, OBJPROP_FONTSIZE, fontSize);
058.             ObjectSetString(0, szName, OBJPROP_FONT, font);
059.             ObjectSetString(0, szName, OBJPROP_TEXT, text);
060.             if (actual == OBJ_EDIT)
061.             {
062.                 ObjectSetInteger(0, szName, OBJPROP_BGCOLOR, backColor);
063.                 ObjectSetInteger(0, szName, OBJPROP_READONLY, false);
064.             }
065.         }
066. //+----------------+
067.         string GetName(void)
068.         {
069.             return szName;
070.         }
071. //+----------------+
072.         void Update(void)
073.         {
074.             font        = ObjectGetString(0, szName, OBJPROP_FONT);
075.             Selectable  = (int)ObjectGetInteger(0, szName, OBJPROP_SELECTABLE);
076.             x           = (int)ObjectGetInteger(0, szName, OBJPROP_XDISTANCE);
077.             y           = (int)ObjectGetInteger(0, szName, OBJPROP_YDISTANCE);
078.             w           = (int)ObjectGetInteger(0, szName, OBJPROP_XSIZE);
079.             h           = (int)ObjectGetInteger(0, szName, OBJPROP_YSIZE);
080.             fontSize    = (int)ObjectGetInteger(0, szName, OBJPROP_FONTSIZE);
081.             cor         = (color)ObjectGetInteger(0, szName, OBJPROP_COLOR);
082.             backColor   = (color)((ENUM_OBJECT)ObjectGetInteger(0, szName, OBJPROP_TYPE) == OBJ_LABEL ? backColor : ObjectGetInteger(0, szName, OBJPROP_BGCOLOR));
083.             text        = ObjectGetString(0, szName, OBJPROP_TEXT);
084.         }
085. //+----------------+
086. }gl_Obj;
087. //+------------------------------------------------------------------+
088. int OnInit()
089. {
090.     ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true);
091. 
092.     gl_Obj.SetDefault(macro_NameObject);
093.     gl_Obj.Create(OBJ_LABEL);
094. 
095.     return INIT_SUCCEEDED;
096. };
097. //+------------------------------------------------------------------+
098. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
099. {
100.     return rates_total;
101. };
102. //+------------------------------------------------------------------+
103. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
104. {
105. //+----------------+
106.     #define macro_SWAP(A)   {                                           \
107.                 string sz0 = ObjectGetString(0, sparam, OBJPROP_TEXT);  \
108.                 ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, false);   \
109.                 ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, true);    \
110.                 ObjectDelete(0, sparam);                                \
111.                 gl_Obj.Create(A);                                       \
112.                 ObjectSetString(0, sparam, OBJPROP_TEXT, sz0);          \
113.                 gl_Obj.Update();                                        \
114.                             }
115. //+----------------+
116.     switch (id)
117.     {
118.         case CHARTEVENT_OBJECT_CLICK    :
119.             if (sparam == gl_Obj.GetName())
120.                 if ((ENUM_OBJECT)ObjectGetInteger(0, sparam, OBJPROP_TYPE) != OBJ_EDIT)
121.                     macro_SWAP(OBJ_EDIT);
122.             break;
123.         case CHARTEVENT_OBJECT_CREATE   :
124.             if (sparam == gl_Obj.GetName())
125.             {
126.                 ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, false);
127.                 ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true);
128.             }
129.             break;
130.         case CHARTEVENT_OBJECT_DELETE   :
131.             if (sparam == gl_Obj.GetName())gl_Obj.Recreates();
132.             break;
133.         case CHARTEVENT_OBJECT_CHANGE   :
134.             if (sparam == gl_Obj.GetName()) gl_Obj.Update();
135.             break;
136.         case CHARTEVENT_OBJECT_ENDEDIT  :
137.             if (sparam == gl_Obj.GetName()) macro_SWAP(OBJ_LABEL)
138.             break;
139.     }
140.     ChartRedraw();
141. //+----------------+
142.     #undef macro_SWAP
143. //+----------------+
144. };
145. //+------------------------------------------------------------------+
146. void OnDeinit(const int reason)
147. {
148.     ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, false);
149.     ObjectsDeleteAll(0, def_Prefix);
150.     ChartRedraw();
151. };
152. //+------------------------------------------------------------------+

Código 06

Este código 06 já tem diversas coisas já funcionando, inclusive a correção daquele pequeno inconvincente. Mas de proposito, mudei parte do código para ocultar a forma como resolvi o problema. Isto para que usuários menos experientes não consigam enxergar logo de cara como a solução foi obtida.

Como este código 06 é tal simples quanto os demais, e quem vem estudando e praticando, vai conseguir tirar ele de letra. Acho que não preciso explicar muita coisa. Somente vou dizer o seguinte: Quando o objeto do tipo OBJ_EDIT terminar a edição. Isto normalmente acontece quando pressionamos a tecla ENTER. Será disparado pelo MetaTrader 5, um evento do tipo CHARTEVENT_OBJECT_ENDEDIT. Este evento será capturado pela linha 136 e esta irá tornar o objeto que antes era do tipo OBJ_EDIT novamente em um objeto do tipo OBJ_LABEL.

O resultado de uma possível execução pode ser visto logo abaixo.

Animação 07

Mas não se iluda com esta animação 07, meu caro leitor. Procure estudar e entender o que está acontecendo de fato aqui. Pois o que você está vendo nesta animação 07 é apenas a ponta de um enorme iceberg. Isto por que, aqui apenas mostrei o básico do básico da coisa toda. Podemos ir muito mais muito mais longe do que isto que foi mostrado aqui.


Considerações finais

Talvez muitos tenham achado este artigo um tanto quanto chato, já que a todo momento mostrei todos os códigos na integra, dando pouca explicação sobre como eles de fato trabalham. Mas pessoalmente considero desnecessário ficar repetindo coisas que já foram explicadas em outros artigos desta mesma sequência. Claro que aqui, fizemos algo que muito poderiam ficar admirados e até mesmo um tanto quanto desconfiados. Tudo bem, faz parte do processo de aprendizado.

Mas gostaria de dar uma última dica a você meu caro leitor. Isto antes de finalizar o artigo e partirmos para o próximo. Neste último tópico, você viu que podemos fazer muitas coisas legais. E se notar, deve acabar percebendo que mudei as dimensões o objeto do tipo OBJ_LABEL. Isto para que fosse possível incluir um texto um pouco maior. Minha dica é: Procure entender como o texto de fato é criado em um objeto do tipo OBJ_EDIT. Isto para que você possa mudar as dimensões do objeto OBJ_LABEL, quando for apresentar o texto no gráfico.

Além disto, procure bolar uma forma de poder mover o objeto do tipo OBJ_LABEL no gráfico. Isto por que, ele sempre ficará meio que empacado no local onde ele foi criado. Perceba que isto acontece justamente por conta do fato de que, no momento em que ele for selecionado, devido ao evento CHARTEVENT_OBJECT_CLICK, o mesmo irá se transformado em um objeto do tipo OBJ_EDIT. E isto nos impede de mudar ele de localização.

Além disto, existe uma outra coisa, que também podemos fazer, mas muito provavelmente iremos ver isto no próximo artigo. Se por ventura eu perceber que é algo chato, ou que não irá agregar muito para ser colocado em um artigo. Irei dizer do que se trata. Mas de qualquer forma, agora você já sabe um pouco mais sobre MQL5 e MetaTrader 5 do que sabia no início deste artigo.

Então procure estudar e praticar com os códigos presentes no anexo e nos vemos no próximo artigo.

Arquivo MQ5 Descrição
Code 01 Demonstração de evento em objeto
Code 02 Demonstração de evento em objeto
Code 03  Demonstração de evento em objeto
Code 04  Demonstração de evento em objeto
Arquivos anexados |
Anexo.zip (4.5 KB)
Algoritmo evolutivo de trading com aprendizado por reforço e extinção de estratégias não lucrativas (ETARE) Algoritmo evolutivo de trading com aprendizado por reforço e extinção de estratégias não lucrativas (ETARE)
Apresentamos um algoritmo de trading inovador que combina algoritmos evolutivos com aprendizado profundo por reforço para operar no mercado Forex. O algoritmo utiliza um mecanismo de extinção das estratégias ineficientes, com o objetivo de otimizar a estratégia de negociação.
Simulação de mercado: Iniciando o SQL no MQL5 (V) Simulação de mercado: Iniciando o SQL no MQL5 (V)
No artigo anterior mostrei como você deveria proceder, a fim de conseguir adicionar o mecanismo de pesquisa. Isto para que dentro do código MQL5, você pudesse de fato fazer uso pleno do SQL. A fim de conseguir obter os resultados quando for usar o comando SELECT FROM do SQL. Mas ficou faltando falar da última função que precisamos implementar. Esta é a função DatabaseReadBind. E como para entender ela adequadamente é algo que exigirá um pouco mais de explicações. Ficou decidido que isto seria feito, não naquele artigo anterior, mas sim neste daqui. Já que o assunto é bem extenso.
Algoritmo da viagem evolutiva no tempo — Time Evolution Travel Algorithm (TETA) Algoritmo da viagem evolutiva no tempo — Time Evolution Travel Algorithm (TETA)
Meu algoritmo original. Neste artigo é apresentado o Algoritmo da Viagem Evolutiva no Tempo (TETA), inspirado no conceito de universos paralelos e fluxos temporais. A ideia central do algoritmo é que, embora a viagem no tempo no sentido convencional seja impossível, podemos escolher uma sequência de eventos que leva a diferentes realidades.
Análise pós-fato da negociação: ajustando TrailingStop e novos stops no testador de estratégias Análise pós-fato da negociação: ajustando TrailingStop e novos stops no testador de estratégias
Seguimos com o tema da análise de negociações realizadas no testador de estratégias para melhorar a qualidade da negociação. Vamos verificar como o uso de diferentes métodos de trailing pode alterar os resultados de negociação já obtidos.