Do básico ao intermediário: Objetos e sub janelas (I)
Introdução
No artigo anterior Do básico ao intermediário: Recursos, introduzimos um conceito bastante interessante e altamente contagiante. Que é justamente o de utilizar dados ou algum tipo de informação como sendo recurso interno de uma aplicação que estejamos implementando. No entanto, o que foi visto ali é apenas uma pequena e insignificante fração de tudo o que podemos fazer com aquele tipo de conceito. Na prática, a única limitação é de fato a sua própria imaginação e experiência no uso daquele conceito explicado ali. E como aqui o objetivo é a didática e mostrar as coisas da forma que todos possam entender, mesmo um iniciante. Não iremos pular etapas na explicação de como certos conceitos podem e devem ser entendidos.
Muito bem, ao longo desta sequência, já falamos sobre objetos gráficos. Como lidar com eventos simples nestes mesmos objetos. Já foi dada uma pequena apresentação sobre indicadores e como podemos lidar com algumas situações específicas envolvendo o uso de indicadores. Já tendo sido dada uma boa base sobre utilização de subjanelas. Porém, ainda não falamos sobre como usar objetos dentro de sub janelas. Muitos de vocês podem pensar: Mas qual a importância em se saber fazer isto? Não seria a mesma coisa que já foi apresentada quando falamos sobre objetos gráficos? Bem, seria mais ou menos a mesma coisa, isto olhando as coisas a grosso modo. Porém, e é este o ponto que irei explicar. Existem algumas pequenas diferenças e nuances em se usar um objeto na janela principal e usar o mesmo objeto em uma sub janela. Mas a parte interessante surge quando passamos a utilizar coisas que a princípio deveriam estar na janela principal, e no entanto, passarão a ser usadas em alguma sub janela. Falando assim, talvez, ou melhor, com toda a certeza, você não consegue entender o que estou tentando lhe dizer.
Então vamos começar a explorar justamente este tipo de situação, o uso de objetos gráficos dentro de sub janelas. Assim, vamos dar um tempo nas distrações e focar no que será explicado neste artigo. Pois o assunto aqui é mesmo algo que pode fazer a diferença na maneira como você pensa em seus códigos.Objetos e sub janelas (I)
Apesar de alguns conceitos e estruturas de programação não terem ainda sido explicadas. Não quero fazer com que você, fique imaginando que para conseguir criar algo de útil é preciso anos de experiência em programação. Pois isto não seria nem um pouco verdadeiro. Programação é uma forma de arte, na qual você tendo uma ideia, consegue por meios matemáticos dizer ao computador o que ele precisa fazer, para tornar sua ideia realidade. E não se engane, computadores não passam de simples máquinas de calcular. Mesmo que você não os veja assim, isto não os torna diferentes. Sendo assim, mesmo que tenhamos algumas limitações neste primeiro momento, quero mostrar para você, que já podemos fazer diversas coisas bem interessantes. Mesmo que a princípio elas pareçam muito bobas e sem graça.
Como de costume, vamos iniciar com algo bem simples e fácil de entender. Para isto vamos implementar um pequeno indicador que pode ser visto logo abaixo.01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_chart_window 07. #property indicator_plots 0 08. //+------------------------------------------------------------------+ 09. #define def_ObjName "Mini Chart" 10. //+------------------------------------------------------------------+ 11. int OnInit(void) 12. { 13. IndicatorSetString(INDICATOR_SHORTNAME, "Test 123."); 14. 15. ObjectCreate(0, def_ObjName, OBJ_CHART, 0, 0, 0); 16. ObjectSetInteger(0, def_ObjName, OBJPROP_XDISTANCE, 10); 17. ObjectSetInteger(0, def_ObjName, OBJPROP_YDISTANCE, 10); 18. ObjectSetInteger(0, def_ObjName, OBJPROP_XSIZE, 300); 19. ObjectSetInteger(0, def_ObjName, OBJPROP_YSIZE, 300); 20. ObjectSetInteger(0, def_ObjName, OBJPROP_PERIOD, PERIOD_M15); 21. ObjectSetInteger(0, def_ObjName, OBJPROP_DATE_SCALE, false); 22. ObjectSetInteger(0, def_ObjName, OBJPROP_PRICE_SCALE, false); 23. ObjectSetString(0, def_ObjName, OBJPROP_SYMBOL, _Symbol); 24. ObjectSetInteger(0, def_ObjName, OBJPROP_SELECTABLE, true); 25. ObjectSetInteger(0, def_ObjName, OBJPROP_SELECTED, false); 26. 27. return INIT_SUCCEEDED; 28. }; 29. //+------------------------------------------------------------------+ 30. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 31. { 32. return rates_total; 33. }; 34. //+------------------------------------------------------------------+ 35. void OnDeinit(const int reason) 36. { 37. ObjectDelete(0, def_ObjName); 38. ChartRedraw(); 39. }; 40. //+------------------------------------------------------------------+
Código 01
Este código é muito direto naquilo que estamos pretendendo fazer. Porém ele não é a melhor maneira de se fazer isto, apesar de ser algo que todos conseguem, ou deveriam conseguir entender. Mas como já foi explicado, dentro desta série de artigos, algumas coisas relacionadas ao que se refere a programação orientada em objetos. Podemos melhorar este mesmo código 01, de forma a termos o mesmo resultado que seria apresentado por ele. No entanto, o código em si ficaria muito mais simples de ser utilizado. Pois mesmo que venhamos a esquecer algo, a própria programação orientada em objetos irá nos ajudar a resolver tais pendencia. Sendo assim este mesmo código 01 pode ser reescrito como o código visto logo na sequência.01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_chart_window 07. #property indicator_plots 0 08. //+------------------------------------------------------------------+ 09. class C_MiniChart 10. { 11. private : 12. //+----------------+ 13. string m_szNameObject; 14. //+----------------+ 15. void SetInteger(ENUM_OBJECT_PROPERTY_INTEGER prop, int value) { ObjectSetInteger(0, m_szNameObject, prop, value); } 16. //+----------------+ 17. public : 18. //+----------------+ 19. C_MiniChart(string szName) 20. :m_szNameObject(szName) 21. { 22. ObjectCreate(0, m_szNameObject, OBJ_CHART, 0, 0, 0); 23. ObjectSetString(0, m_szNameObject, OBJPROP_SYMBOL, _Symbol); 24. SetInteger(OBJPROP_XDISTANCE, 10); 25. SetInteger(OBJPROP_YDISTANCE, 10); 26. SetInteger(OBJPROP_XSIZE, 300); 27. SetInteger(OBJPROP_YSIZE, 300); 28. SetInteger(OBJPROP_PERIOD, PERIOD_M15); 29. SetInteger(OBJPROP_DATE_SCALE, false); 30. SetInteger(OBJPROP_PRICE_SCALE, false); 31. SetInteger(OBJPROP_SELECTABLE, true); 32. SetInteger(OBJPROP_SELECTED, false); 33. } 34. //+----------------+ 35. ~C_MiniChart() 36. { 37. ObjectDelete(0, m_szNameObject); 38. ChartRedraw(); 39. } 40. //+----------------+ 41. }gl_MiniChart("Mini Chart"); 42. //+------------------------------------------------------------------+ 43. int OnInit(void) 44. { 45. IndicatorSetString(INDICATOR_SHORTNAME, "Test 123."); 46. 47. return INIT_SUCCEEDED; 48. }; 49. //+------------------------------------------------------------------+ 50. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 51. { 52. return rates_total; 53. }; 54. //+------------------------------------------------------------------+
Código 02
Ok, agora temos sim um código consideravelmente mais simples de ser modificado e explicado. Além é claro, de termos algo bem mais adequado, no que diz respeito a didática. Agora quero que você preste atenção a alguns detalhes neste código 02. Note que na linha seis, estamos dizendo que o indicador NÃO IRÁ FAZER USO DE UMA SUB JANELA. É extremamente importante que você entenda muito bem isto que estamos informando nesta linha seis. Bem, o segundo ponto a ser observado é com relação a linha quarenta e um. Observe que ali, estamos declarando uma variável global, e esta está inicializando a classe. Porém, ao observar o conteúdo dentro de OnInit, você logo pensa: Bem, mas este código não irá ter o mesmo resultado que seria criado pelo código 01. Mas é justamente neste ponto que você acaba tropeçando e beijando o chão. Pois apesar de este código 02 ser aparentemente diferente do código 01. Ele tem o mesmo tipo de resultado e comportamento. Isto justamente por conta desta linha quarenta e um, e o fato de estarmos utilizando a programação orientada em objetos.
Se você tem algum tipo de dúvida a este respeito, veja este artigo Do básico ao intermediário: Classes (III) onde mostro algo parecido com o que estamos fazendo aqui. Ok, mas este código 02 é algo muito chato e sem graça. Já que a única coisa que ele faz é criar um gráfico cujo ativo é o mesmo do gráfico principal só que usando o timeframe de quinze minutos. E isto pode ser observado o analisarmos as linhas vinte e três, onde dizemos qual o ativo que irá aparecer no gráfico. E a linha vinte e oito, onde dizemos a base do tempo gráfico que deverá ser usada para se plotar as barras dentro da pequena janela que estará sendo criada. No entanto, antes de nos aprofundarmos, preciso que você entenda muito bem isto que está acontecendo aqui. E para não deixar nenhuma sombra de dúvida de como este código visto acima funciona. Temos a animação logo abaixo.

Animação 01
Nesta animação é mostrado o resultado da colocação do código 01 em um gráfico qualquer. Assim como a animação logo abaixo, mostra o que acontece quando removemos o indicador criado nos códigos acima de um gráfico no qual ele tenha sido e ainda esteja inserido.

Animação 02
Você claramente nota que o objeto colocado no gráfico é removido assim que o indicador é retirado do gráfico. Algo realmente esperado, justamente devido a forma como o código foi implementado. Porém, apesar de obvias este tipo de resultado que foi observado nestas animações e que você poderá comprovar, ao utilizar os códigos no anexo. Nem sempre temos o óbvio acontecendo, quando unimos diversas coisas que foram mostradas até este momento nesta sequência de artigos. Uma destas coisas está relacionada ao fato de usarmos o que foi visto recentemente, nos últimos artigos. Que é justamente o fato de aplicarmos o indicador, via uma chamada da biblioteca do MQL5.
Devido ao fato que de não quero complicar as coisas neste momento, sem necessidade. Vamos fazer o seguinte: Vamos criar um outro indicador, e com base no que já foi explicado em artigos recentemente postados. Vamos fazer com que este novo indicador, mande o indicador construído no código 02, ser lançado para dentro do que seria uma sub janela. Lembrando que este indicador implementado no código 02, NÃO FAZ USO DE UMA SUB JANELA. Mas sim utiliza a janela principal como meio de interação com o usuário, ou operador do gráfico. Para fazer isto, iremos utilizar o código que pode ser observado logo abaixo.01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_chart_window 07. #property indicator_plots 0 08. //+------------------------------------------------------------------+ 09. #define def_Resource "Code 01.ex5" 10. //+------------------------------------------------------------------+ 11. #resource def_Resource 12. //+------------------------------------------------------------------+ 13. int OnInit(void) 14. { 15. ChartIndicatorAdd(0, (int)ChartGetInteger(0, CHART_WINDOWS_TOTAL), iCustom(NULL, NULL, "::" + def_Resource)); 16. 17. return INIT_SUCCEEDED; 18. }; 19. //+------------------------------------------------------------------+ 20. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 21. { 22. return rates_total; 23. }; 24. //+------------------------------------------------------------------+
Código 03
Agora preste atenção, pois diferente de quando estamos plotando alguma média no gráfico. Quando trabalhamos com objetos, existem alguns cuidados que precisamos tomar. E como quero deixar a coisa bem simples de entender. Este código 03 conta com apenas e tão somente o necessário para conseguirmos fazer o que era pretendido. Ou seja, fazer com que o indicador visto no código 02 fosse colocado em uma sub janela. Porém como o código será integrado ao código 03 justamente devido a presença da linha onze, onde incluímos o executável como sendo um recurso interno do código 03. Não precisaremos que o código 02 seja transportado entre instalações do MetaTrader 5. Tudo que precisamos fazer é transferir o executável gerado ao compilar este código 03, para outro computador. E ainda assim teremos o mesmo tipo de comportamento. Isto foi explicado no artigo anterior. Para mais detalhes, estude o que foi mostrado lá.
Considerando que você já consegue entender, o que a linha quinze, presente no código 03 estará de fato fazendo. É esperado que tenhamos a criação de uma sub janela e que o objeto seja colocado nela. Certo? Bem, isto é o que você imagina que deveria acontecer. Porém ao executar o código você se depara com o seguinte resultado, que é visto na animação logo abaixo. 
Animação 03
Mas o que foi isto? Não entendi. Bem, meu caro leitor, vamos fazer uma pequena mudança no código 02. Isto para que as coisas fiquem bem mais claras. Esta mudança é mostrada no fragmento logo abaixo.. . . 26. SetInteger(OBJPROP_XSIZE, 300); 27. SetInteger(OBJPROP_YSIZE, 150); . . .
Fragmento 01
Aqui estamos mudando a dimensão do objeto OBJ_CHART que será criado. Então agora deletamos o executável do código 02 e voltamos a compilar novamente o código 03. Com isto teremos uma nova integração com as novas dimensões para serem utilizadas pelo objeto OBJ_CHART. Isto fará com que ao executáramos o código 03, teremos o que é mostrado na imagem logo abaixo.

Imagem 01
Mas que coisa mais estranha. Achei que o objeto OBJ_CHART seria adicionado a sub janela. Já que estamos direcionando o indicador visto no código 02 para dentro de uma sub janela. Mas aparentemente o código não entendeu isto, e acabou por colocar o objeto OBJ_CHART na janela principal. Cara que coisa mais estranha. Mas espere um pouco, talvez o indicador visto no código 02 não esteja de fato sendo direcionado para uma sub janela. Talvez por isto que o resultado está sendo este que estou vendo na imagem 01. Seria este o motivo? Na verdade, não, meu caro leitor. Se você pedir ao MetaTrader 5, para listar os indicadores presentes no gráfico, irá notar que de fato o indicador visto no código 02, está sendo colocado em uma sub janela. Como pode ser claramente observado na imagem logo na sequência. 
Imagem 02
Agora que não estou entendendo mais nada mesmo. Achei que as coisas iriam trabalhar de uma determinada maneira. Mas isto está ficando um tanto quanto complicado demais para mim. Calma meu amigo. A diversão está apenas começando. O que está acontecendo, é que você imaginava que as coisas funcionariam de uma determinada maneira. Porém você acabou de ver que na prática nem sempre as coisas são como imaginamos. Que realmente precisamos aprender e estudar antes de sairmos por aí, achando que já sabemos das coisas. Para tornar as coisas um tanto quanto mais amigáveis. Vamos modificar o código 02, para que o objeto OBJ_CHART venja a ser mostrado em uma sub janela. Isto sem precisarmos realmente recorrer ao código 03. Porém não se esqueça de uma coisa: O objetivo aqui é usar o código 02 e o código 03 para conseguir o resultado que será visto daqui a pouco. Mas para que você consiga entender o que será feito, vamos fazer isto por partes. Portanto, mantenha o foco no que será explicado.
Pois bem, modificando o código 02 passamos a ter o código visto logo abaixo.01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_separate_window 07. #property indicator_plots 0 08. #property indicator_height 150 09. //+------------------------------------------------------------------+ 10. class C_MiniChart 11. { 12. private : 13. //+----------------+ 14. string m_szNameObject; 15. //+----------------+ 16. void SetInteger(ENUM_OBJECT_PROPERTY_INTEGER prop, int value) { ObjectSetInteger(0, m_szNameObject, prop, value); } 17. //+----------------+ 18. public : 19. //+----------------+ 20. C_MiniChart(string szName) 21. :m_szNameObject(szName) 22. { 23. ObjectCreate(0, m_szNameObject, OBJ_CHART, 1, 0, 0); 24. ObjectSetString(0, m_szNameObject, OBJPROP_SYMBOL, _Symbol); 25. SetInteger(OBJPROP_XDISTANCE, 10); 26. SetInteger(OBJPROP_YDISTANCE, 0); 27. SetInteger(OBJPROP_XSIZE, 300); 28. SetInteger(OBJPROP_YSIZE, indicator_height); 29. SetInteger(OBJPROP_PERIOD, PERIOD_M15); 30. SetInteger(OBJPROP_DATE_SCALE, false); 31. SetInteger(OBJPROP_PRICE_SCALE, false); 32. SetInteger(OBJPROP_SELECTABLE, true); 33. SetInteger(OBJPROP_SELECTED, false); 34. } 35. //+----------------+ 36. ~C_MiniChart() 37. { 38. ObjectDelete(0, m_szNameObject); 39. ChartRedraw(); 40. } 41. //+----------------+ 42. }gl_MiniChart("Mini Chart"); 43. //+------------------------------------------------------------------+ 44. int OnInit(void) 45. { 46. IndicatorSetString(INDICATOR_SHORTNAME, "Test 123."); 47. 48. return INIT_SUCCEEDED; 49. }; 50. //+------------------------------------------------------------------+ 51. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 52. { 53. return rates_total; 54. }; 55. //+------------------------------------------------------------------+
Código 04
Agora quando executarmos este código 04 iremos ver e ter algo como o que é mostrado na animação logo a seguir. 
Animação 04
Hum, isto parece bem interessante. De fato, meu caro leitor, este tipo de coisa é bem interessante, e irá ficar ainda mais, conforme formos avançando as coisas. Porém, apesar de ser interessante, este código 04 tem um problema. E é um problema, que se você não entender muito bem o que esta sendo feito pelo MetaTrader 5, irá ter muitas dores de cabeça e muitos aborrecimentos. Podendo inclusive lhe desanimar de continuar a estudar MQL5. Então preste atenção. Se você comparar este código 04 com seu antecessor que seria o código 02, irá notar que foram feitas algumas mudanças. Porém, e este é o ponto crucial, a real mudança que nos interessa acontece na linha vinte e três, aquele que seria o quarto argumento passado para a função ObjectCreate. Não estou entendendo, por que este quarto argumento seria uma falha neste código 04. Poderia explicar isto melhor? Na verdade, a forma mais simples de entender isto, seria que você experimentasse o código pessoalmente. Mas vou tentar explicar para que você possa ter uma vaga ideia do problema neste quarto argumento.
Já que na linha seis deste código 04 estamos dizendo que será necessária uma sub janela. O MetaTrader 5, irá providenciar a criação da mesma. Isto quando for necessário, conforme foi visto nos artigos anteriores. Porém, e esta é a parte confusa para muitos, quando o objeto OBJ_CHART vier a ser criado. Estaremos dizendo ao MetaTrader 5 para criar o objeto e o colocar em uma sub janela. Agora lhe pergunto: Qual sub janela? Bem, você pode dizer que deveria ser a sub janela criada para comportar o indicador. Certo? Errado, meu amigo leitor. Ou melhor dizendo, talvez isto até venha a ocorrer, desde que no momento em que este código 04 vier a ser colocado no gráfico, NÃO EXISTA NENHUMA OUTRA SUB JANELA PRESENTE ALI.
Preste muita atenção a esta afirmação. Pois isto pode vir a ser útil em muitos momentos, quando precisarmos fazer um determinado tipo de atividade dentro do gráfico. Porém, este não é o caso aqui. Por conta disto, caso exista alguma sub janela, ANTES de você adicionar o indicador visto no código 04 ao gráfico. O MetaTrader 5 irá fazer com que o objeto OBJ_CHART seja criado e posicionado naquela que é a sub janela de index um. Isto por que o quarto argumento está apontando justamente para esta sub janela.
Para tentar deixar isto um pouco mais claro, veja a animação logo abaixo. 
Animação 05
Note como de fato o comportamento do código está sendo diferente daquilo que você imaginava ser o correto. Porém, em algumas situações bem específicas este tipo de comportamento visto nesta animação 05 é exatamente o que pretendemos criar. Mas isto talvez venha a ser mostrado com mais detalhe em outro momento. Então vamos voltar ao nosso problema inicial. Que seria justamente o de criar uma sub janela e dentro dela adicionar o tal objeto OBJ_CHART. Bem, existem muitas maneiras diferentes de se resolver este problema. Cada uma sendo um pouco mais fácil ou complicada dependendo de cada caso específico e de qual o proposito, ou objetivo a ser alcançado. Mas para manter a didática adequada ao artigo, vamos fazer uso daquilo que ao meu entender seria a maneira mais simples de todas. Lembrando que existem maneiras ainda mais simples. Porém, como ainda não expliquei alguns recursos da biblioteca MQL5. O que será mostrado aqui é a mais simples entre as atualmente disponíveis. Isto por que o tipo de coisa que iremos fazer aqui, já foi explicado em um outro artigo nesta mesma sequência.
No artigo Do básico ao intermediário: Sub Janelas (III), mostrei como poderíamos visualizar quais indicadores estão presentes em um determinado gráfico. Assim, caso você tenha dúvidas a respeito do que será visto aqui, veja o referido artigo para mais detalhes. Ok, agora vamos a parte realmente divertida do artigo. E para isto, vamos começar pelo código visto logo abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_separate_window 07. #property indicator_plots 0 08. #property indicator_height 150 09. //+------------------------------------------------------------------+ 10. #define def_ShortName "Test 123." 11. //+------------------------------------------------------------------+ 12. class C_MiniChart 13. { 14. private : 15. //+----------------+ 16. string m_szNameObject; 17. int m_Sub; 18. //+----------------+ 19. void SetInteger(ENUM_OBJECT_PROPERTY_INTEGER prop, int value) { ObjectSetInteger(0, m_szNameObject, prop, value); } 20. //+----------------+ 21. int WhatSubWin(void) 22. { 23. for (int c0 = 0; c0 < (int)(ChartGetInteger(0, CHART_WINDOWS_TOTAL)); c0++) 24. for (int c1 = (ChartIndicatorsTotal(0, c0) - 1); c1 >= 0; c1--) 25. if (ChartIndicatorName(0, c0, c1) == def_ShortName) 26. return c0; 27. return INVALID_HANDLE; 28. } 29. //+----------------+ 30. public : 31. //+----------------+ 32. C_MiniChart(string szName) 33. { 34. if ((m_Sub = WhatSubWin()) == INVALID_HANDLE) return; 35. ObjectCreate(0, m_szNameObject = szName, OBJ_CHART, m_Sub, 0, 0); 36. ObjectSetString(0, m_szNameObject, OBJPROP_SYMBOL, _Symbol); 37. SetInteger(OBJPROP_XDISTANCE, 10); 38. SetInteger(OBJPROP_YDISTANCE, 0); 39. SetInteger(OBJPROP_XSIZE, 300); 40. SetInteger(OBJPROP_YSIZE, indicator_height); 41. SetInteger(OBJPROP_PERIOD, PERIOD_M15); 42. SetInteger(OBJPROP_DATE_SCALE, false); 43. SetInteger(OBJPROP_PRICE_SCALE, false); 44. SetInteger(OBJPROP_SELECTABLE, true); 45. SetInteger(OBJPROP_SELECTED, false); 46. } 47. //+----------------+ 48. ~C_MiniChart() 49. { 50. ObjectDelete(0, m_szNameObject); 51. ChartRedraw(); 52. } 53. //+----------------+ 54. }*gl_MiniChart; 55. //+------------------------------------------------------------------+ 56. int OnInit(void) 57. { 58. IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName); 59. 60. gl_MiniChart = new C_MiniChart("Mini Chart"); 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 OnDeinit(const int reason) 71. { 72. delete gl_MiniChart; 73. }; 74. //+------------------------------------------------------------------+
Código 05
Este código 05, pode a princípio, ser algo muito complicado e extremamente elaborado. Porém, nada do que está sendo feito aqui, é, ou deveria ser novidade para nenhum de vocês que estão acompanhando e estudando estes meus artigos. Tudo que está sendo feito aqui, já foi visto antes. Claro que foram feitos alguns pequenos ajustes a fim de tornar o código um pouco mais fácil de entender. Mas a questão principal aqui tem tudo a ver com o que está sendo feito na linha cinquenta e quatro. Observe que diferente do que estávamos fazendo antes, agora não temos mais aquele tipo de liberdade. E o motivo é bastante simples. Precisamos saber onde o indicador estará sendo colocado. Mas como assim? É claro que eu sei onde ele estará sendo colocado. Não é isto, que estou querendo dizer, meu amigo.
A questão é que sem que o MetaTrader 5 tenha tornado, ou melhor dizendo, definido o que seria o nome do executável, em uma string que podemos testar de maneira clara e simplificada, não temos como saber onde e o que, o MetaTrader 5 estará, ou terá resolvido fazer com o indicador. Não se esqueça de que dependendo de onde você coloque o indicador e das configurações que ele venha a ter. O MetaTrader 5 poderá fazer com que o indicador venha a ser tratado de uma ou de outra forma. Isto foi explicado nos artigos anteriores.
Uma vez que a linha cinquenta e oito tenha sido executada, temos meios de realmente saber onde o indicador estará sendo colocado. Assim poderemos passar a trabalhar a fim de conseguir saber qual é a sub janela onde o objeto OBJ_CHART deverá ser colocado. Pois bem, isto é feito na linha trinta e quatro. Agora, como não estamos mais trabalhando da mesma maneira que era feito antes, precisamos garantir que o ponteiro criado na linha sessenta seja destruído. Por isto precisamos adicionar o tratador OnDeinit que você pode observar na linha setenta.
Legal, mas será que este código 05 de fato funciona como queremos? Bem, para responder isto, veja a animação logo abaixo. 
Animação 06
Uau, isto sim ficou bem mais interessante. Agora sim senti firmeza. De fato, meu caro leitor, a coisa ficou bem mais interessante. Mas, e sempre existe um mas, em toda história. Mesmo este código 05 contém uma falha. Cara, por que você já não mostra o código sem nenhum tipo de defeito? Por que fazer isto comigo? Primeiro me dá uma injeção de ânimo, para logo depois de dá uma marretada na cabeça? É muita maldade fazer as coisas assim. Bom, pensando desta forma, talvez possa até parecer maldade. Mas acho que você está se esquecendo que você ainda não é um programador, e que está lendo estes artigos, justamente para aprender como podemos fazer as coisas da melhor maneira possível.
Ok, a falha que este código 05 contém, se deve ao fato de que se você tentar adicionar duas instâncias do mesmo, em um mesmo gráfico, o objeto OBJ_CHART não terá novas instâncias sendo criadas. E o motivo é que estamos dizendo ao MetaTrader 5 para usar apenas e tão somente um único nome, para o objeto OBJ_CHART. Bem, então é muito simples corrigir isto, basta que venhamos a dar um novo nome para cada nova instância do objeto que estaremos criando. Fácil demais resolver este tipo de problema. Para dizer a verdade isto nem é assim um problema.
Deveras, se as coisas fossem assim, tão simples como você as vezes pensa que elas são. Na prática o buraco é um pouco mais profundo. Preste atenção: Mesmo que você faça o que acabou de dizer, e você não está errado ao pensar assim. O real problema acontece quando a linha trinta e quatro chama a função presente na linha vinte e um. Hum, não entendi. Então pare e pense um pouco, que você logo irá entender o real problema aqui.
Quando o indicador visto no código 05 é adicionado ao gráfico, ele irá procurar a primeira instância, cujo indicador é definido pelo nome que estamos declarando na linha dez. Mesmo que você venha a indicar um nome diferente para o objeto OBJ_CHART, quando a função da linha vinte e um retornar, ela irá nos dizer, em que sub janela se encontra a primeira instância do indicador definido com o nome da linha dez. Por conta disto, se você fizer apenas a mudança no nome do objeto OBJ_CHART, não irá de fato conseguir atribuir a sub janela correta no novo objeto que estará sendo criado.
Existem formas de se contornar este tipo de problema. Algumas até bastante inusitadas. Porém, este não é o nosso objetivo neste primeiro momento. Apenas estou mencionando isto, para que você esteja ciente de que por mais que tudo pareça funcionar sem defeitos e percalços, ainda assim, existem falhas que você talvez não tenha notado. E que para resolver elas, precisaremos abordar assuntos e coisas um pouco mais avançadas. Por isto é bom estudar cada um destes artigos com calma.
Ok, dado o recado, e já tendo demonstrado como podemos trabalhar com isto que acabamos de criar e que é visto no código 05. Podemos voltar nossa atenção novamente para aquilo que seria a integração do código 02 ao código 03. E não se esqueça, diferente do código 02 onde não estamos dizendo que usaremos uma sub janela. O princípio adotado aqui no código 05 será muito bem utilizado para conseguir corrigir aquela questão de o objeto está sendo criado e posicionado na sub janela errada. Assim sendo, para corrigir o código 02, a fim de o integrar ao código 03 posteriormente. Precisamos mudar ele como mostrado logo abaixo.01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_chart_window 07. #property indicator_plots 0 08. //+------------------------------------------------------------------+ 09. #define def_ShortName "Test 123." 10. //+------------------------------------------------------------------+ 11. class C_MiniChart 12. { 13. private : 14. //+----------------+ 15. string m_szNameObject; 16. int m_Sub; 17. //+----------------+ 18. void SetInteger(ENUM_OBJECT_PROPERTY_INTEGER prop, int value) { ObjectSetInteger(0, m_szNameObject, prop, value); } 19. //+----------------+ 20. int WhatSubWin(void) 21. { 22. for (int c0 = 0; c0 < (int)(ChartGetInteger(0, CHART_WINDOWS_TOTAL)); c0++) 23. for (int c1 = (ChartIndicatorsTotal(0, c0) - 1); c1 >= 0; c1--) 24. if (ChartIndicatorName(0, c0, c1) == def_ShortName) 25. return c0; 26. return INVALID_HANDLE; 27. } 28. //+----------------+ 29. public : 30. //+----------------+ 31. C_MiniChart(string szName) 32. { 33. if ((m_Sub = WhatSubWin()) == INVALID_HANDLE) return; 34. ObjectCreate(0, m_szNameObject = szName, OBJ_CHART, m_Sub, 0, 0); 35. ObjectSetString(0, m_szNameObject, OBJPROP_SYMBOL, _Symbol); 36. SetInteger(OBJPROP_XDISTANCE, 10); 37. SetInteger(OBJPROP_YDISTANCE, 0); 38. SetInteger(OBJPROP_XSIZE, 300); 39. SetInteger(OBJPROP_YSIZE, 150); 40. SetInteger(OBJPROP_PERIOD, PERIOD_M15); 41. SetInteger(OBJPROP_DATE_SCALE, false); 42. SetInteger(OBJPROP_PRICE_SCALE, false); 43. SetInteger(OBJPROP_SELECTABLE, true); 44. SetInteger(OBJPROP_SELECTED, false); 45. } 46. //+----------------+ 47. ~C_MiniChart() 48. { 49. ObjectDelete(0, m_szNameObject); 50. ChartRedraw(); 51. } 52. //+----------------+ 53. }*gl_MiniChart; 54. //+------------------------------------------------------------------+ 55. int OnInit(void) 56. { 57. IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName); 58. 59. gl_MiniChart = new C_MiniChart("Mini Chart"); 60. 61. return INIT_SUCCEEDED; 62. }; 63. //+------------------------------------------------------------------+ 64. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 65. { 66. return rates_total; 67. }; 68. //+------------------------------------------------------------------+ 69. void OnDeinit(const int reason) 70. { 71. delete gl_MiniChart; 72. }; 73. //+------------------------------------------------------------------+
Código 06
Agora observe o seguinte: Este código 06 se parece em muito com o código 05. No entanto, este código 06, diferente do código 05, é feito para ser utilizado dentro daquilo que é conhecido como sendo a janela principal do gráfico. Isto justamente por conta de declaração que está sendo feita na linha seis deste código 06. Mas, e esta é a parte que nos interessa aqui e agora. Se mudarmos o código 03 para que ele venha a utilizar o executável criado aqui pelo código 06 passaremos a ter um comportamento bem interessante. E praticamente aquele que nos era desejado desde o início.
Para garantir que você terá os códigos fontes vistos aqui, para poder estudar e experimentar isto aos poucos, no anexo, além do código 03 teremos outros, para lhe ajudar a entender cada detalhe com calma. Assim sendo, o código que irá integrar este código 06 é visto logo abaixo.01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_chart_window 07. #property indicator_plots 0 08. //+------------------------------------------------------------------+ 09. #define def_Resource "Code 05.ex5" 10. //+------------------------------------------------------------------+ 11. #resource def_Resource 12. //+------------------------------------------------------------------+ 13. int OnInit(void) 14. { 15. ChartIndicatorAdd(0, (int)ChartGetInteger(0, CHART_WINDOWS_TOTAL), iCustom(NULL, NULL, "::" + def_Resource)); 16. 17. return INIT_SUCCEEDED; 18. }; 19. //+------------------------------------------------------------------+ 20. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 21. { 22. return rates_total; 23. }; 24. //+------------------------------------------------------------------+
Código 07
Note que a única diferença entre este código 07 e o código 03 é justamente a linha nove, todo o restante é exatamente a mesma coisa. Porém, está simples diferença, fará com que o código 06 seja integrado a este código 07. E depois de compilar o código 07, você o poderá executar no MetaTrader 5 em algum gráfico e o resultado será algo parecido com o que é visto na animação logo na sequência. 
Animação 07
Caramba, de fato este tipo de coisa se mostrou um verdadeiro show de bola. Que coisa mais maravilhosa. Agora sim já me sinto bem mais confiante e ainda mais interessado em estudar cada detalhe em cada um dos seus artigos. No entanto, notei que o código 06, não tem somente a linha seis diferente do código 05. Por que? Será que não podemos usar o código 05, fazendo apenas e tão somente a mudança na linha seis? De fato, podemos meu caro leitor. Porém, devido ao fato de que este código 06 seria o que precisaria ser o código 02 para que o objeto OBJ_CHART pudesse ser posicionado no local correto. Fiz as mudanças apenas para demonstrar esta atualização do código 02. Mas nada lhe impede de utilizar o código 05 com a única mudança sendo feita na linha seis. O resultado seria algo que ainda não vamos usar neste primeiro momento. Entretanto, pode ser que você já esteja planejando algo, então vamos ver como deveria ser feito. Sendo que no anexo, você também terá estes códigos para experimentar. A primeira mudança iria gerar o código visto logo abaixo.01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_chart_window 07. #property indicator_height 150 08. #property indicator_plots 0 09. //+------------------------------------------------------------------+ 10. #define def_ShortName "Test 123." 11. //+------------------------------------------------------------------+ 12. class C_MiniChart 13. { 14. private : 15. //+----------------+ 16. string m_szNameObject; 17. int m_Sub; 18. //+----------------+ 19. void SetInteger(ENUM_OBJECT_PROPERTY_INTEGER prop, int value) { ObjectSetInteger(0, m_szNameObject, prop, value); } 20. //+----------------+ 21. int WhatSubWin(void) 22. { 23. for (int c0 = 0; c0 < (int)(ChartGetInteger(0, CHART_WINDOWS_TOTAL)); c0++) 24. for (int c1 = (ChartIndicatorsTotal(0, c0) - 1); c1 >= 0; c1--) 25. if (ChartIndicatorName(0, c0, c1) == def_ShortName) 26. return c0; 27. return INVALID_HANDLE; 28. } 29. //+----------------+ 30. public : 31. //+----------------+ 32. C_MiniChart(string szName) 33. { 34. if ((m_Sub = WhatSubWin()) == INVALID_HANDLE) return; 35. ObjectCreate(0, m_szNameObject = szName, OBJ_CHART, m_Sub, 0, 0); 36. ObjectSetString(0, m_szNameObject, OBJPROP_SYMBOL, _Symbol); 37. SetInteger(OBJPROP_XDISTANCE, 10); 38. SetInteger(OBJPROP_YDISTANCE, 0); 39. SetInteger(OBJPROP_XSIZE, 300); 40. SetInteger(OBJPROP_YSIZE, indicator_height); 41. SetInteger(OBJPROP_PERIOD, PERIOD_M15); 42. SetInteger(OBJPROP_DATE_SCALE, false); 43. SetInteger(OBJPROP_PRICE_SCALE, false); 44. SetInteger(OBJPROP_SELECTABLE, true); 45. SetInteger(OBJPROP_SELECTED, false); 46. } 47. //+----------------+ 48. ~C_MiniChart() 49. { 50. ObjectDelete(0, m_szNameObject); 51. ChartRedraw(); 52. } 53. //+----------------+ 54. }*gl_MiniChart; 55. //+------------------------------------------------------------------+ 56. int OnInit(void) 57. { 58. IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName); 59. 60. gl_MiniChart = new C_MiniChart("Mini Chart"); 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 OnDeinit(const int reason) 71. { 72. delete gl_MiniChart; 73. }; 74. //+------------------------------------------------------------------+
Código 08
Já o código em que este código 08 irá se integrar, e que será responsável por chamar e criar a sub janela é visto logo abaixo.01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_chart_window 07. #property indicator_plots 0 08. //+------------------------------------------------------------------+ 09. #define def_Resource "Code 07.ex5" 10. //+------------------------------------------------------------------+ 11. #resource def_Resource 12. //+------------------------------------------------------------------+ 13. int OnInit(void) 14. { 15. ChartIndicatorAdd(0, (int)ChartGetInteger(0, CHART_WINDOWS_TOTAL), iCustom(NULL, NULL, "::" + def_Resource)); 16. 17. return INIT_SUCCEEDED; 18. }; 19. //+------------------------------------------------------------------+ 20. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 21. { 22. return rates_total; 23. }; 24. //+------------------------------------------------------------------+
Código 09
O código 09 é muito parecido com os demais onde faremos a integração. Sendo basicamente a diferença dele para os demais, o que estará sendo definido na linha nove. Porém, e esta é a parte na qual você poderá testar localmente. No código 08, temos uma definição sendo feita na linha sete. Esta definição irá nos permitir dizer a altura que a sub janela deverá ter. Isto quando ela vier a ser criada. Porém, todavia e, entretanto, este código 08, diferentemente do que foi visto sendo feito no código 05, NÃO CRIARÁ UMA SUB JANELA. Quem fará isto por ele é o código 09. Portanto, mesmo que você não faça questão, você poderá adicionar este indicador visto no código 09 em qualquer outro indicador presente em uma sub janela. E isto nos permite criar novas e divertidas configurações para serem utilizadas no MetaTrader 5.
Mas este tipo de coisa será visto com mais detalhes, em um outro artigo em breve. Por hora, acho que você já tem muito a estudar e praticar.Considerações finais
Muitas das vezes imaginamos que certas coisas não podem ser feitas, quando na verdade o que nos falta é o conhecimento correto e adequado para podermos encontrar a melhor solução para um dado problema.
Neste artigo, vimos um pouco daquilo que podemos explorar de maneira muito mais profunda e com resultados realmente incríveis. E fizemos tudo isto, usando conhecimento básico e sem nenhum tipo de complicação. Portanto, a diferença entre conseguir um resultado incrível e um meramente adequado, está no quanto você se esforça para ir onde ninguém mais foi. Contudo, tenho certeza, de que mesmo vendo o que foi mostrado aqui, muitos vão dizer que tudo isto não precisaria ser feito. Pois temos formas melhores e mais fáceis de conseguir o mesmo tipo de resultado. Devo concordar, com tais palavras. Porém ainda não chegamos no ponto no qual sem este conhecimento mostrado aqui, você não conseguirá replicar os mesmos resultados conseguidos por quem sabe de fato o que está fazendo. Então procure estudar com calma, o conteúdo apresentado aqui. Pois nos próximos artigos, iremos nos aprofundar ainda mais nesta questão de utilizar objetos em sub janelas.| Arquivo MQ5 | Descrição |
|---|---|
| Indicators\Code 01 | Demonstração básica |
| Indicators\Code 02 | Demonstração básica |
| Indicators\Code 03 | Demonstração básica |
| Indicators\Code 04 | Demonstração básica |
| Indicators\Code 05 | Demonstração básica |
| Indicators\Code 06 | Demonstração básica |
| Indicators\Code 07 | Demonstração básica |
| Indicators\Code 08 | Demonstração básica |
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.
Rede neural na prática: Gradiente
Otimização extrema — Extremal Optimization (EO)
Está chegando o novo MetaTrader 5 e MQL5
Redes neurais em trading: Previsão probabilística de séries temporais (Conclusão)
- 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