
Do básico ao intermediário: Eventos em Objetos (I)
Introdução
No artigo anterior Do básico ao intermediário: Objetos (IV), foi mostrado como poderíamos fazer para modificar um objeto presente no MetaTrader 5, a fim de construir um outro objeto. E isto com um objetivo que poderia ser bastante interessante além de ser algo que desperta muito curiosidade. No caso, foi deixado também ali, um desafio para você meu caro leitor. Um desafio que não irei mostrar como resolver. Isto porque, quero que você procure praticar e estudar os artigos a fim de aprender como de fato resolver os problemas. Que com toda a certeza deste mundo irão vir a surgir conforme você vai aprendendo e tentando implementar novas coisas.
Apesar de ser algo muito simples de ser resolvido, e o problema não ser algo que atrapalhe o uso do código para fins de estudo. Acredito, que você irá se sentir muito mais orgulhoso, e convicto do que está conseguindo aprender. Se você conseguir resolver o problema sozinho, estudando e analisando cada situação até encontrar a melhor solução possível. Portanto neste artigo, iremos abordar um outro tema. Mas que está de certa maneira ligado ao trabalho com objetos gráficos. Apesar de ser um pouco diferente do que tem sido mostrado até aqui.
Talvez, você já esteja imaginando que estou dando bastante ênfase a esta questão dos objetos. Talvez até mais do que muitos consideram ser algo realmente necessário de ser feito. E de fato, é preciso que você entenda diversas coisas, antes de podermos mergulhar um pouco mais fundo, no que pode ser feito em MQL5. Isto com um objetivo um pouco mais amplo, a fim de criar aplicações mais elaboradas e com algum proposito particular, que você não encontra nenhuma outra aplicação cobrindo. Isto pensando em termos de MetaTrader 5.
Muito bem, então como de costume, vamos iniciar um novo tópico. E assim podemos começar a falar sobre o que será o tema principal deste artigo.
Eventos em objetos
Até o momento foi mostrado e explicado como podemos trabalhar e estudar, eventos que o usuário irá gerar ao interagir com o MetaTrader 5. Isto ligando tais eventos ao gráfico. Como por exemplo, quando pressionamos uma tecla, ou mesmo quando usamos o mouse para algum tipo de atividade. Como por exemplo, o de colocar algum objeto no gráfico. Que apesar de ser um evento, basicamente feito com o uso do mouse. Também gera outros eventos atrelados a ele.
E estes eventos, basicamente fazem com que o MetaTrader 5, venha a disparar outros eventos. Que neste caso, são eventos relacionados aos objetos. E por conta disto são tratados de uma forma diferente. Bem, pelo menos é isto que se espera que seja feito. Já que o MetaTrader 5, dispara estes eventos, justamente para auxiliar o programador e por consequência a aplicação, a lidar com algum tipo de atividade efetuada em um objeto presente no gráfico.
Tais eventos podem ser disparados, quando clicamos, movemos, criamos, deletamos, ou mesmo mudamos algo em um objeto. Porém, nem todos eventos serão de fato disparados, já que alguns precisam ser ligados. Pelo simples motivo, de que, por padrão, estarão deligados no MetaTrader 5. Seria mais ou menos, como acontece com eventos de mouse. Já que tais eventos, podem não ser de fato, algo que a aplicação deseje vir a ser notificada, devido ao fato de não ter interesse em tais eventos. O MetaTrader 5, simplesmente ignora o disparo de tais eventos. Assim, temos um ambiente relativamente mais rápido e com menos chances de problemas ligados a performance, ou mesmo estabilidade da própria plataforma.
Porém existem momentos, em que de fato, tais eventos se tornam necessários. E neste caso, precisamos entender como lidar com tais eventos. Já que passamos a necessitar fazer algum tipo de correção, ou ajuste, justamente devido a alguma modificação que o usuário possa vir a ter feito em algum objeto gráfico.
Analisar de maneira manual, se um objeto gráfico, sofreu ou não alguma mudança. Além de consumir muito tempo de CPU, e tornar o código absurdamente mais complicado. Não é algo que de fato, você, meu caro leitor, e entusiasta irá desejar fazer. Mas justamente por conta do fato de que o MetaTrader 5, nos fornece informações a respeito de mudanças ocorridas no gráfico. Podemos reduzir, e muito, o trabalho de ter de ficar observando cada um dos objetos que venhamos a colocar no gráfico. Isto a fim de que, saibamos quando, onde e por que um usuário efetuou alguma mudança no que seria um objeto cujo proposito seria apenas e tão somente informar algo.
Neste momento, talvez você não tenha ideia de quanto este tipo de evento, que o MetaTrader 5 gera, a fim de notificar nossa aplicação, sobre alguma mudança em algum objeto é importante. E mais, talvez, você não tenha uma compreensão, sobre o quanto, um usuário, mal intencionado, pode vir a prejudicar sua aplicação, quando ele começa a mexer em certas propriedades de alguns objetos. E é por isto, que precisamos falar sobre eventos em objetos. Pois este definitivamente é um assunto, que pode lhe ajudar a evitar problemas, ou mesmo entender certas falhas que sua aplicação pode apresentar, no decorrer da vida útil da mesma.
Já que no momento em que você atualiza sua aplicação, pode também estar reduzindo o risco de falhas. Mas ao mesmo tempo, pode também estar deixando de analisar coisas que seriam importantes de serem analisadas.
Como muitas das vezes, certos eventos, que são disparados pelo MetaTrader 5, que foram originados por algum tipo de atividade em um objeto, podem ser encarados de forma diferente, por diferentes aplicações. Vamos tentar criar não um modelo, ou protocolo de como fazer as coisas. Quero que você, meu caro leitor, procure entender o conceito, que estará sendo usado. Mas também, quero que você procure entender, que existe momentos para que cada coisa seja observada e existe momentos em que podemos ignorar completamente certos tipos de atividades, feitas em algum objeto. Seja um objeto que sua aplicação colocou no gráfico, seja um objeto que o usuário colocou no mesmo gráfico. Existe momento para tudo. Então procure primeiro entender o conceito utilizado. E não o código em si. Pois este pode mudar imensamente.
Ok, então antes de começarmos, é preciso que uma coisa fique muito bem esclarecida. Normalmente o tratamento que um objeto irá receber do MetaTrader 5, pode não vir a ser o mais adequado. Isto pensando em um proposito mais específico. Onde estamos implementando algo com um objetivo muito específico. Portanto, neste tipo de situação, precisamos estabelecer outras regras, além das que o MetaTrader 5, já irá adotar por padrão.
E para que estas regras, que iremos estabelecer em nossa aplicação, possam ser seguidas, utilizamos o recurso oferecido pelo MetaTrader 5, para saber o que ocorreu com um determinado objeto. Fazendo isto, eliminamos a necessidade de ficar o tempo todo observando o que um usuário, possa estar fazendo com aquele objeto em especial. Já que se algo ocorrer com algum objeto, seja pelo fato de o usuário adicionar algum no gráfico, seja pelo fato de ele o ter modificado, ou mesmo excluído. O MetaTrader 5 irá nos notificar, e assim poderemos adotar as medidas necessárias.
Entender isto, é extremamente importante. Talvez até mais do que entender o próprio código em si. De qualquer forma, existem eventos que necessitaram ser ligados, enquanto outros não. E saber a hora certa de ligar ou mesmo desligar tais eventos, é uma das coisas da qual você precisará praticar para entender. Pelo sim ou pelo não, precisamos começar de alguma forma. Então vamos fazer isto de tal forma que venha a ser a mais suave quanto for possível de ser feita. Assim sendo, que tal iniciarmos pelo código 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. #include <Tutorial\File 01.mqh> 009. //+------------------------------------------------------------------+ 010. input double user01 = 1.5; //Stop-Target Relationship 011. input bool user02 = true; //Extend lines to the right 012. //+------------------------------------------------------------------+ 013. st_Cross gl_Cross; 014. //+------------------------------------------------------------------+ 015. int OnInit() 016. { 017. gl_Cross.Init(); 018. IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix); 019. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); 020. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false); 021. 022. return INIT_SUCCEEDED; 023. }; 024. //+------------------------------------------------------------------+ 025. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 026. { 027. return rates_total; 028. }; 029. //+------------------------------------------------------------------+ 030. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 031. { 032. #define macro_CLEAN_EVENT { \ 033. isPaint = ""; \ 034. gl_Cross.Hide(); \ 035. bMouseL = false; \ 036. ChartSetInteger(0, CHART_MOUSE_SCROLL, true); \ 037. } 038. 039. st_TimePrice tp; 040. static string isPaint = ""; 041. static bool bMouseL = false; 042. 043. switch (id) 044. { 045. case CHARTEVENT_KEYDOWN: 046. if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) macro_CLEAN_EVENT; 047. break; 048. case CHARTEVENT_MOUSE_MOVE: 049. tp = gl_Cross.Move((ushort)lparam, (ushort)dparam); 050. if (((uchar)sparam & MOUSE_LEFT) != 0) 051. { 052. if (isPaint != "") 053. { 054. bMouseL = true; 055. if (!ObjectGetInteger(0, isPaint, OBJPROP_TIME)) ObjectMove(0, isPaint, 0, tp.Time, tp.Price); 056. ObjectMove(0, isPaint, 1, tp.Time, tp.Price); 057. } 058. }else if (bMouseL) macro_CLEAN_EVENT; 059. if ((((uchar)sparam & MOUSE_MIDDLE) != 0) && (isPaint == "")) 060. { 061. ObjectCreate(0, isPaint = macro_NameObject, OBJ_FIBO, 0, 0, 0); 062. ChartSetInteger(0, CHART_MOUSE_SCROLL, false); 063. Modifier_OBJ_FIBO(isPaint); 064. gl_Cross.Show(); 065. } 066. break; 067. case CHARTEVENT_MOUSE_WHEEL: 068. break; 069. case CHARTEVENT_OBJECT_CLICK: 070. Comment(StringFormat("CHARTEVENT_OBJECT_CLICK\nX: %03d Y: %03d Object: %s", (ushort)lparam, (ushort)dparam, sparam)); 071. break; 072. case CHARTEVENT_OBJECT_DRAG : 073. Comment(StringFormat("CHARTEVENT_OBJECT_DRAG\nObject: %s", sparam)); 074. break; 075. } 076. ChartRedraw(); 077. 078. #undef macro_CLEAN_EVENT 079. }; 080. //+------------------------------------------------------------------+ 081. void OnDeinit(const int reason) 082. { 083. Comment(""); 084. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); 085. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true); 086. 087. gl_Cross.Hide(); 088. 089. if (reason == REASON_REMOVE) 090. ObjectsDeleteAll(0, def_Prefix); 091. }; 092. //+------------------------------------------------------------------+ 093. void Modifier_OBJ_FIBO(const string szNameObj) 094. { 095. #define macro_Mod_OBJ_FIBO(txt, pos, cor, width, style) { \ 096. ObjectSetDouble(0, szNameObj, OBJPROP_LEVELVALUE, levels, pos); \ 097. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELCOLOR, levels, cor); \ 098. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELWIDTH, levels, width); \ 099. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELSTYLE, levels, style); \ 100. ObjectSetString(0, szNameObj, OBJPROP_LEVELTEXT, levels, txt); \ 101. levels++; \ 102. } 103. 104. int levels = 0; 105. 106. ObjectSetInteger(0, szNameObj, OBJPROP_SELECTABLE, false); 107. ObjectSetInteger(0, szNameObj, OBJPROP_COLOR, clrNONE); 108. ObjectSetInteger(0, szNameObj, OBJPROP_RAY_RIGHT, user02); 109. 110. macro_Mod_OBJ_FIBO("Stop", 0, clrRed, 2, STYLE_SOLID); 111. macro_Mod_OBJ_FIBO("Enter", 1, clrBlue, 2, STYLE_DASH); 112. macro_Mod_OBJ_FIBO("Partial", 1 + (user01 / 2), clrYellowGreen, 1, STYLE_DASHDOTDOT); 113. macro_Mod_OBJ_FIBO("Take", 1 + user01, clrGreen, 2, STYLE_SOLID); 114. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELS, levels); 115. 116. #undef macro_Mod_OBJ_FIBO 117. } 118. //+------------------------------------------------------------------+
Código 01
Aqui temos um código, que foi visto, explicado e disponibilizado, no artigo anterior. Bem, na verdade, não é exatamente este, já que aqui estamos fazendo dois novos acréscimos ao que seria o código original. Estou fazendo isto de maneira proposital, com base em algo já conhecido, justamente para que você venha a perceber que uma aplicação muito complicada, não surge de uma hora para outra. Ela vai sendo construída aos poucos. Pedaço a pedaço. Apesar de que aqui, não estarmos focados em criar nenhum tipo de aplicação especifica. Apenas demonstrar e explicar coisas relacionadas a como programar em MQL5, a fim de controlar o próprio MetaTrader 5.
Ok, uma vez compilado e adicionado em um gráfico, este código 01 terá um comportamento bem interessante de ser observado. Já que agora ele irá nos reportar algumas informações uteis. Lembrando que estas informações são geradas originalmente pelo MetaTrader 5, com base em algum tipo de atividade efetuada no gráfico. Na animação abaixo, você pode ver um pouco daquilo que pode vir a ser esperado pelo uso da aplicação. Isto quando você a estiver utilizando em um gráfico qualquer.
Animação 01
Preste atenção ao canto superior esquerdo desta animação 01. Você irá ver algumas mensagens, cujo propósito é o de nos informar quando algum evento, ocorreu em alguns dos objetos presentes no gráfico. Observe que somos informados, de modo a saber, que tipo de evento ocorreu, além de saber o nome e da posição do mouse, no caso de um evento CHARTEVENT_OBJECT_CLICK. Este tipo de coisa nos abre diversas possibilidades de uso. São realmente muitas possibilidades, apenas pelo simples fato de estamos observando estes meros dois eventos.
Porém, como aqui estamos lidando com algo muito simples e direto. Não vejo necessidade de realmente explicar o que está acontecendo no código 01. Basta que você o observe com calma, e faça uso do conhecimento mostrado nestes artigos até este presente momento, para que possa entender o que está ocorrendo na aplicação. Porém note que mesmo objetos não criados pela nossa aplicação, ainda assim poderão ser observados por ela.
E é justamente isto que eu desejo que você entenda, meu caro leitor. O que estamos fazendo é justamente observando o que seria o comportamento padrão do MetaTrader 5. Isto a fim de entender como ele lida com os objetos, e também como ele irá nos notificar, caso alguma coisa venha a acontecer.
Muito bem, apesar de podemos continuar adicionando nova coisas ao código 01. Não faremos isto. Já que isto acabaria por ocultar nosso objetivo principal, que é justamente ensinar e passar um pouco da minha experiência e conhecimento sobre programação, para que você consiga controlar como a plataforma irá trabalhar ao seu favor. E não contra você. Assim sendo vamos, criar um novo tipo de aplicação. Está voltada para que possamos explicar uma coisa, que pode ser feita, desde é claro você entenda como usar o MQL5, a fim de controlar o MetaTrader 5.
E para isto, preciso que você tenha compreendido, o que foi essencialmente explicado neste tópico atual. Pois sem entender esta parte, que ao meu ver é a base para todas as demais. Será um tanto quanto confuso entender o que será feito logo mais.
Evitando duplicadas
Uma das coisas, que realmente me deixa um tanto quanto entediado, é o tal do CTRL+C CTRL+V. Porém, isto não se aplica aqui no MetaTrader 5. Bem, pelo menos não da forma como grande parte espera que poderia vir a acontecer. Isto porque, quando você seleciona um objeto, e acessa o menu de coisas que podemos fazer com ele. Você irá notar que por padrão o MetaTrader 5, NÃO TEM O TAL CTRL+C CTRL+V para ser aplicado em objetos. O que para muitos, pode ser perfeitamente normal e natural. Enquanto para outros, isto é um tanto quanto estranho e desconcertante. Você pode ver isto, olhando a imagem logo abaixo.
Imagem 01
Ok, isto pode parecer ser um tanto quanto estranho. Mas aqui no MetaTrader 5, o CTRL+C CTRL+V não é acessado desta maneira. E para dizer a verdade, acredito que bem poucos usuários, saibam como fazer um CTRL+C CTRL+V no MetaTrader 5. Isto a fim de duplicar algum objeto presente no gráfico.
Para entender como isto é feito, seria necessário que fosse explicado outras coisas. Porém aqui isto tornaria o artigo muito chato, além de que, não seria de fato algo que ao meu ver, iria gerar um grande interesse. Isto porque, grande parte dos usuários, já se contentam em utilizar a plataforma da forma com eles já a utilizam. Então por que mudar isto? Não é mesmo.
Porém, para o que quero explicar mais a frente, vale realmente bastante a pena, explicar para você, meu caro leitor, como podemos efetuar um CTRL+C CTRL+V em um objeto qualquer. Isto aqui no MetaTrader 5. Já que é algo, que acredito que você não saiba como fazer. Além do mais, fica sendo como um bônus extra, para quem por ventura vier a estudar estes meus artigos. Ok, na animação abaixo podemos ver como, podemos efetuar um CTRL+C CTRL+V, em um objeto qualquer.
Animação 02
Note, que é algo muito fácil, simples e até mesmo engraçado. Porém poucos sabem que para criar uma cópia de algum objeto presente no gráfico. Tudo que temos de fazer é pressionar a tecla CTRL no momento em que viermos a arrastar o objeto. Assim quando fazemos isto, criamos uma cópia exata, do objeto. Se bem que não é bem uma cópia exata, como será explicado em breve. E ainda bem que não é, pois se fosse, seria difícil fazer uma outra coisa, que você talvez ainda não saiba que podemos fazer.
Pois bem, quando fazemos isto, que é mostrado na animação 02. Estamos criando uma duplicada de um objeto que já existia no gráfico. Mas isto em alguns momentos não é exatamente o que queremos que aconteça. Ou melhor dizendo. Existem certos tipos de objetos, que NÃO QUEREMOS que venha a ter uma duplicada no gráfico. Isto porque, tais objetos podem conter algum tipo de informação, que se for duplicada pode acabar por confundir o operador ou até mesmo o usuário.
Ainda mais quando estes objetos podem estar recebendo informações vindas de nossa aplicação. Neste caso, podemos acabar vendo uma informação conflitante em dois objetos aparentemente iguais. E para tornar isto mais claro, a ponto de que você possa vir a entender de maneira adequado o que estou dizendo. Vamos fazer uma pequena brincadeira. Esta será feita com o código visto 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_NameObj; 09. //+------------------------------------------------------------------+ 10. int OnInit() 11. { 12. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); 13. 14. ObjectCreate(0, gl_NameObj = macro_NameObject, OBJ_LABEL, 0, 0, 0); 15. ObjectSetInteger(0, gl_NameObj, OBJPROP_SELECTABLE, true); 16. ObjectSetInteger(0, gl_NameObj, OBJPROP_XDISTANCE, 50); 17. ObjectSetInteger(0, gl_NameObj, OBJPROP_YDISTANCE, 50); 18. ObjectSetInteger(0, gl_NameObj, OBJPROP_XSIZE, 150); 19. ObjectSetInteger(0, gl_NameObj, OBJPROP_COLOR, clrMediumBlue); 20. ObjectSetInteger(0, gl_NameObj, OBJPROP_FONTSIZE, 20); 21. ObjectSetString(0, gl_NameObj, OBJPROP_FONT, "Lucida Console"); 22. 23. return INIT_SUCCEEDED; 24. }; 25. //+------------------------------------------------------------------+ 26. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 27. { 28. return rates_total; 29. }; 30. //+------------------------------------------------------------------+ 31. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 32. { 33. switch (id) 34. { 35. case CHARTEVENT_MOUSE_MOVE: 36. ObjectSetString(0, gl_NameObj, OBJPROP_TEXT, StringFormat("%03d : %03d", (ushort)lparam, (ushort)dparam)); 37. break; 38. } 39. ChartRedraw(); 40. }; 41. //+------------------------------------------------------------------+ 42. void OnDeinit(const int reason) 43. { 44. ObjectsDeleteAll(0, def_Prefix); 45. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); 46. ChartRedraw(); 47. }; 48. //+------------------------------------------------------------------+
Código 02
Este código 02 servirá para ilustrar onde eu quero chegar, com esta estória de duplicata. Como ele é muito simples, podendo ser facilmente entendido por você meu caro e estimado leitor. Desde que você esteja estudando o material visto nos meus artigos. Não irei explicar o que ele faz. Ao invés disto, irei apenas mostrar o tipo de resultado que podemos ver, quando o que foi explicado nos parágrafos anteriores é colocado em prática. Este tipo de coisa, pode ser observado na animação 03 logo na sequência.
Animação 03
Aqui temos uma questão que é a velocidade entre os eventos. Como estamos lidando com eventos do mouse, a velocidade é bem alta, e você acaba percebendo que existe algo estranho. Mas pense em eventos que podem acontecer um a cada cinco minutos ou mesmo um a cada uma hora. Neste caso seria difícil perceber. Então, agora você talvez esteja começando a perceber onde eu quero chegar. Como você talvez não soubesse como duplicar um objeto em um gráfico. Este tipo de coisa que vemos na animação 03, dificilmente iria ocorrer.
Porém, agora que você já sabe, como é simples criar uma duplicada de um objeto no MetaTrader 5. Este tipo de coisa, pode se tornar bastante frequente. E isto, em algum momento, pode acabar gerando sérios problemas para você. Ainda mais se o objeto duplicado, vier a fica na frente do objeto de interesse. O que é muito mais comum de acontecer do que você possa estar imaginando. Causando assim ainda mais confusão e prejuízo.
Porém, podemos evitar de que um objeto possa vir a ser duplicado. Ou no mínimo, minimizar a possibilidade de que isto venha a causar conflitos de interesse. Já que alguns tipos de objetos podem encobrir outros objetos, dependo da forma como ele vier a ser configurado. Porém aqui e para nossa felicidade, o objeto criado completamente inofensivo. Sendo voltado apenas para objetivos e princípios didáticos.
Ok, agora você precisa entender uma coisa, meu caro leitor. Quando duplicamos um objeto, como foi mostrado aqui. O MetaTrader 5 irá criar um nome para este novo objeto. Este nome segue uma regra de padronização, por assim dizer. Sendo este nome dividido em três partes. A primeira parte se refere ao tempo gráfico que estamos utilizando. A segunda parte, será uma referência ao tipo de objeto utilizado. Já a terceira parte é um número gerado aletoriamente. Sendo está terceira parte ignorada por nós, já que o objetivo dela é evitar colisões entre objetos do mesmo tipo.
Bem, mas o que isto quer nos dizer? E como podemos utilizar este conhecimento ao nosso favor? Ok, esta será a parte divertida, meu caro leitor. Já que com base em certas características, que você pode experimentar ao usar o código 01 para verificar como uma duplicata é feita. Podemos averiguar se ocorreu ou não uma duplicada de um objeto. Se bem que isto, não é uma ciência exata. Já que existem complicações a respeito de como podemos fazer as coisas, e até onde podemos ir sem sair do MQL5 puro.
E uma destas complicações será mostrada em breve. Mas antes, podemos fazer algo um pouco mais interessante. Isto pensando em implementar algo com um objetivo de analisar os próprios eventos que estão sendo gerados pelo MetaTrader 5 em resposta a alguma interação do usuário a um objeto. Assim, o código 02, irá se tornar o código visto 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. enum eBtnMouse { 09. MOUSE_LEFT = 0x01, 10. MOUSE_RIGHT = 0x02, 11. MOUSE_KEY_SHIFT = 0x04, 12. MOUSE_KEY_CTRL = 0x08, 13. MOUSE_MIDDLE = 0x10, 14. MOUSE_EXTRA_1 = 0x20, 15. MOUSE_EXTRA_2 = 0x40 16. }; 17. //+------------------------------------------------------------------+ 18. string gl_NameObj; 19. //+------------------------------------------------------------------+ 20. int OnInit() 21. { 22. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); 23. 24. ObjectCreate(0, gl_NameObj = macro_NameObject, OBJ_LABEL, 0, 0, 0); 25. ObjectSetInteger(0, gl_NameObj, OBJPROP_SELECTABLE, true); 26. ObjectSetInteger(0, gl_NameObj, OBJPROP_XDISTANCE, 50); 27. ObjectSetInteger(0, gl_NameObj, OBJPROP_YDISTANCE, 50); 28. ObjectSetInteger(0, gl_NameObj, OBJPROP_XSIZE, 150); 29. ObjectSetInteger(0, gl_NameObj, OBJPROP_COLOR, clrMediumBlue); 30. ObjectSetInteger(0, gl_NameObj, OBJPROP_FONTSIZE, 20); 31. ObjectSetString(0, gl_NameObj, OBJPROP_FONT, "Lucida Console"); 32. 33. ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, true); 34. 35. return INIT_SUCCEEDED; 36. }; 37. //+------------------------------------------------------------------+ 38. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 39. { 40. return rates_total; 41. }; 42. //+------------------------------------------------------------------+ 43. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 44. { 45. static bool check = true; 46. 47. switch (id) 48. { 49. case CHARTEVENT_MOUSE_MOVE: 50. ObjectSetString(0, gl_NameObj, OBJPROP_TEXT, StringFormat("%03d : %03d", (ushort)lparam, (ushort)dparam)); 51. if (((uchar)sparam & (MOUSE_LEFT | MOUSE_KEY_CTRL)) == (MOUSE_LEFT | MOUSE_KEY_CTRL)) 52. { 53. if (check) Print(StringFormat("CHARTEVENT_MOUSE_MOVE\n%s", StringFormat("%03d : %03d", (ushort)lparam, (ushort)dparam))); 54. check = false; 55. }else 56. check = true; 57. break; 58. case CHARTEVENT_OBJECT_CREATE: 59. Print(StringFormat("CHARTEVENT_OBJECT_CREATE\nObject: %s", sparam)); 60. break; 61. case CHARTEVENT_OBJECT_CLICK: 62. Print(StringFormat("CHARTEVENT_OBJECT_CLICK\nX: %03d Y: %03d Object: %s", (ushort)lparam, (ushort)dparam, sparam)); 63. break; 64. case CHARTEVENT_OBJECT_DRAG : 65. Print(StringFormat("CHARTEVENT_OBJECT_DRAG\nObject: %s", sparam)); 66. break; 67. } 68. ChartRedraw(); 69. }; 70. //+------------------------------------------------------------------+ 71. void OnDeinit(const int reason) 72. { 73. Comment(""); 74. ObjectsDeleteAll(0, def_Prefix); 75. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); 76. ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, false); 77. ChartRedraw(); 78. }; 79. //+------------------------------------------------------------------+
Código 03
Olhando este código você pode estar pensando: Cara, mas este código é muito complicado. Será que precisamos de tanta complicação assim, para evitar duplicar objetos no gráfico? Bem, meu caro leitor, aqui este código 03, ainda não estamos de fato tentando evitar que objetos venham a ser duplicados. E não, este código não é assim tão complicado, como parece. Talvez você esteja achando isto, por ter caído de paraquedas justamente neste artigo. E sem ter uma certa base no que já foi explicado nos artigos anteriores. Ai sim este código 03 parece ser uma tremenda de uma complicação.
Porém, apesar disto, e em respeito aqueles que estão acompanhando e estudando o que vem sendo explicado nos meus artigos. Aqui irei dar foco apenas ao que é novidade. Todo o restante acredito, que mesmo os iniciantes irão conseguir entender. Desde que estejam estudando e praticando o que vem sendo explicado.
Muito bem, a primeira parte que é novidade e que nos interessa aqui, é a linha 33. Preste atenção a isto daqui meu caro leitor. Um evento de criação de objeto, por padrão estará desligado no MetaTrader 5. No entanto, sempre que você não desejar que um objeto que você esteja criando, dentro da sua aplicação, seja identificado, a fim de disparar um evento de criação. Precisa desligar este evento que estamos ligando nesta linha 33. Como estamos ligando este evento apenas DEPOIS de criar o objeto OBJ_LABEL. Este objeto não irá disparar o evento de criação, que por sua vez irá ser capturado pelo procedimento OnChartEvent.
Agora, uma vez que este evento, tenha sido ligado. Todo e qualquer objeto colocado no gráfico, irá disparar um evento de criação. E isto será capturado pela linha 58. Imprimindo assim uma mensagem no terminal. No final, quando a linha 76 for executada, iremos desligar este evento de criação, evitando assim que o MetaTrader 5 continue a disparar este evento para o gráfico.
Ok, o resto do código é simples de entender. Então podemos passar para a parte onde fazemos uso prático deste código 03. Vamos começar, com o que pode ser visto na animação logo abaixo.
Animação 04
Nesta animação podemos ver quais objetos estão presentes no gráfico. Assim como também podemos perceber, que nenhuma mensagem foi postada pelo código. Mostrando desta maneira, que os eventos estão de fato alinhados com o que era esperado acontecer, como foi explicado acima.
Uma vez que o código 03 esteja sendo executado, podemos abrir a janela cujo objetivo é verificar a lista de objetos, e visualizar o que temos presente no gráfico. Ao abrirmos a lista, podemos ver a imagem mostrada logo abaixo.
Imagem 02
Agora preste atenção, a uma coisa aqui, meu caro leitor. Existem basicamente, duas formas, de evitar que objetos venham a ser duplicados. A primeira é manter e analisar esta lista de objetos que você pode ver na imagem 02. E dá para fazer isto via código. Porém, ao meu ver isto acaba consumindo mais recursos do que o necessário. Já que cada vez que um evento de criação for capturado pela linha 58, teríamos que analisar o que aconteceu a esta lista de objetos. O que ao meu entender, complica o código sem necessidade. Além de aumentar o custo em termos de uso de CPU.
A outra maneira é analisando eventos de mouse, que venha a ser capturados pela linha 49. Mas principalmente que façam o filtro da linha 51 disparar um sinal verdadeiro. Porém, isto não é um mecanismo 100% perfeito. Já que existem situações, em que este mesmo filtro pode vir a disparar um falso positivo.
Para entender o que poderia causar um falso positivo, veja este meu outro artigo Desenvolvendo um EA de negociação do zero (Parte 23): Um novo sistema de ordens (VI). Ali usamos esta combinação que dispara a linha 51, e que é usada para duplicar um objeto, justamente para poder enviar ordens pendentes ao servidor de negociação. Mas com um pouco de paciência, zelo e cuidado. Podemos conseguir contornar esta questão do falso positivo. Mas isto é algo para ser visto em outro momento. Já que envolve algumas manipulações que não vem ao caso de serem mostradas neste exato momento. O foco aqui é estará sendo exatamente outro. Ou seja, entender como evitar que um objeto possa vir a ter uma duplicada sendo criada.
Muito bem, então vamos ver um pouco mais de como o código 03, irá nos reportar o que estará acontecendo no gráfico. Isto pode ser visto na animação logo na sequência.
Animação 05
Neste caso os únicos eventos que foram gerados foram: CHARTEVENT_OBJECT_CLICK e CHARTEVENT_OBJECT_DRAG, confirmando que de fato, tudo está de acordo com o esperado. Agora vamos fazer algo um pouco diferente com o botão presente no gráfico. Isto pode ser visto na animação logo abaixo.
Animação 06
Observe uma coisa aqui. No exato momento em que a cópia é feita, ou seja, temos a geração de uma duplicata. Acontece de termos dois eventos sendo disparados pelo MetaTrader 5. Estes podem ser melhor visualizados na imagem abaixo.
Imagem 03
Nesta imagem 03, claramente podemos ver o momento em que o objeto é copiado, ou tem uma duplicata sendo gerada. Agora preste atenção. Observe que o objeto original ficou parado. Quem se moveu foi a cópia. Como você pode observar ao comparar a imagem 02 com a imagem 04 logo abaixo.
Imagem 04
E porque saber isto é importante? O motivo é que dependendo do que você queira fazer, pode ser interessante remover a cópia ou o objeto original. Pessoalmente acho mais simples remover a cópia, já que temos o nome dela sendo informado pela captura do evento de criação. Porém, nada impede de que você venha a desejar remover o original e depois renomear a cópia, para que tudo permaneça como antes. Já que a intenção, talvez fosse a de mover o objeto, e acabamos criando uma duplicata do mesmo. Porém, mesmo assim, acho esta opção um tanto quanto trabalhosa demais. Assim, vamos seguir pelo caminho mais simples.
Como o que iremos fazer, envolve algumas modificações no código 03, e estas irão remover o que foi feito e mostrado anteriormente. Vamos fazer diferente. Vou criar um novo arquivo, assim você terá este código 03, presente no anexo, a fim de que possa estudar o mesmo com mais calma, sem precisar ter que digitar o mesmo. Portanto o novo código, com as modificações que precisaram ser feitas, pode ser visto 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. enum eBtnMouse { 09. MOUSE_LEFT = 0x01, 10. MOUSE_RIGHT = 0x02, 11. MOUSE_KEY_SHIFT = 0x04, 12. MOUSE_KEY_CTRL = 0x08, 13. MOUSE_MIDDLE = 0x10, 14. MOUSE_EXTRA_1 = 0x20, 15. MOUSE_EXTRA_2 = 0x40 16. }; 17. //+------------------------------------------------------------------+ 18. string gl_NameObj; 19. //+------------------------------------------------------------------+ 20. int OnInit() 21. { 22. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); 23. 24. ObjectCreate(0, gl_NameObj = macro_NameObject, OBJ_LABEL, 0, 0, 0); 25. ObjectSetInteger(0, gl_NameObj, OBJPROP_SELECTABLE, true); 26. ObjectSetInteger(0, gl_NameObj, OBJPROP_XDISTANCE, 50); 27. ObjectSetInteger(0, gl_NameObj, OBJPROP_YDISTANCE, 50); 28. ObjectSetInteger(0, gl_NameObj, OBJPROP_XSIZE, 150); 29. ObjectSetInteger(0, gl_NameObj, OBJPROP_COLOR, clrMediumBlue); 30. ObjectSetInteger(0, gl_NameObj, OBJPROP_FONTSIZE, 20); 31. ObjectSetString(0, gl_NameObj, OBJPROP_FONT, "Lucida Console"); 32. 33. ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, true); 34. 35. return INIT_SUCCEEDED; 36. }; 37. //+------------------------------------------------------------------+ 38. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 39. { 40. return rates_total; 41. }; 42. //+------------------------------------------------------------------+ 43. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 44. { 45. static bool check = true; 46. static string szObjName = ""; 47. 48. switch (id) 49. { 50. case CHARTEVENT_MOUSE_MOVE: 51. ObjectSetString(0, gl_NameObj, OBJPROP_TEXT, StringFormat("%03d : %03d", (ushort)lparam, (ushort)dparam)); 52. if (((uchar)sparam & (MOUSE_LEFT | MOUSE_KEY_CTRL)) == (MOUSE_LEFT | MOUSE_KEY_CTRL)) 53. { 54. if (check) 55. if (ObjectDelete(0, szObjName)) 56. Comment("Removing copy object: " + szObjName); 57. check = false; 58. }else 59. check = true; 60. break; 61. case CHARTEVENT_OBJECT_CREATE: 62. szObjName = sparam; 63. break; 64. case CHARTEVENT_OBJECT_CLICK: 65. Comment(StringFormat("CHARTEVENT_OBJECT_CLICK\nX: %03d Y: %03d Object: %s", (ushort)lparam, (ushort)dparam, sparam)); 66. break; 67. case CHARTEVENT_OBJECT_DRAG : 68. Comment(StringFormat("CHARTEVENT_OBJECT_DRAG\nObject: %s", sparam)); 69. break; 70. } 71. ChartRedraw(); 72. }; 73. //+------------------------------------------------------------------+ 74. void OnDeinit(const int reason) 75. { 76. Comment(""); 77. ObjectsDeleteAll(0, def_Prefix); 78. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); 79. ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, false); 80. ChartRedraw(); 81. }; 82. //+------------------------------------------------------------------+
Código 04
Quando você executar este código 04, irá ter uma experiência próxima da que pode ser vista na animação logo abaixo.
Animação 07
Observe que aqui adicionei um novo objeto sem problema algum. Logo depois tentamos criar uma duplicata do mesmo, usando o mecanismo visto neste artigo. E veja o tipo de coisa que estará sendo reportado no canto superior esquerdo do gráfico. Ou seja, acabamos de conseguir meios de evitar que objetos venha a ser duplicados. Apesar de todas as coisas que poderiam ser feitas para que obtivéssemos o mesmo tipo de resultado.
Considerações finais
Apesar deste artigo ter sido voltado única e exclusivamente a tratar de eventos em objetos. Ficou faltando falar de outros três eventos que podem acontecer em um objeto. Mas isto será visto no próximo artigo. Não quero tornar as coisas demasiadamente confusas, para aqueles que estão começando agora a aprender como controlar o MetaTrader 5, fazendo uso do MQL5.
Então meu caro leitor, procure estudar e praticar o que foi visto neste artigo. Pois este tipo de conhecimento, com toda a certeza irá lhe ajudar a entender diversas coisas sobre o funcionamento do MetaTrader 5. Coisas estas que precisaram ser muito bem compreendidas, antes que você possa dizer: Sim, eu sei como programar, a fim de controlar o que o MetaTrader 5 irá e poderá fazer.
Então divirta-se com os códigos 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 |
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso