
Do básico ao intermediário: Objetos (IV)
Introdução
No artigo anterior Do básico ao intermediário: Objetos (III), mostrei como você poderia implementar um indicador com um objetivo bastante simples: Colocar de maneira razoavelmente simples, uma linha de tendência no gráfico, sem precisar acessar o menu do MetaTrader 5 para isto.
Sei que para grande parte, aquele conteúdo, com aquele objetivo, parece ser algo completamente desnecessário. Porém, quero lembrar, que o objetivo aqui, não é o de implementarmos algo. Mas sim mostrar como podemos fazer as coisas. O fato de algo ser ou não implementado, e este mesmo algo ter alguma utilidade prática, é um mero detalhe. O que importa é que você, meu caro leitor, consiga entender, que qualquer um consegue colocar suas ideias em prática. Desde que estude e pratique o que vem sendo mostrado nos artigos.
Muito bem, aquilo que foi visto e feito no artigo anterior, é apenas um aperitivo, do que realmente podemos fazer, quando passamos a programar, nossas próprias aplicações, com objetivos particulares. Neste artigo, vou tentar mostrar a você, algo bem legal. Um indicador que está oculto no MetaTrader 5. Do qual quase ninguém sabe da sua existência.
Então vamos ao nosso ritual padrão. Que seria afastar qualquer coisa que possa lhe distrair durante o estudo do artigo, e vamos à próximo tópico, para saber que indicador seria este.
Um indicador oculto no MetaTrader 5
Muitos dizem que o MetaTrader 5, tem pouco indicadores, ou poucas coisas que podemos utilizar para analisar o mercado. Eu, pessoalmente discordo sumariamente de tal afirmação. Isto porque, não é a plataforma ou o conteúdo da mesma que é limitado. Mas sim a visão turva e de curto alcance de muitos que sempre esperam ver as coisas prontas e da maneira como eles querem, ou esperam encontrar.
Existe um indicador no MetaTrader 5, que quase ninguém sabe da existência dele. Isto por que, ele está escondido dentro de outro indicador. Na verdade não é bem um indicador, e sim um objeto de análise. O que precisamos fazer é abrir este objeto a fim de que o indicador, ou objeto oculto venha a luz. Já que por padrão, até daria para usar ele como o mesmo se encontra implementado por padrão no MetaTrader 5. Mas se o modificarmos da forma correta. As informações que ele passará a representar, serão muito mais claras e simples de entender. Visto que o objetivo será completamente outro. Totalmente diferente do objetivo original, proposto e disponível por padrão no MetaTrader 5.
E estou falando do objeto Fibonacci. Se bem que daria para criar o que iremos implementar daqui a pouco, usando linhas de tendência. Mas usando o objeto Fibonacci, é muito mais simples de criar o objeto que pretendemos.
Então para começar, vamos ver o código do indicador que criamos no artigo anterior. Este é visto logo abaixo, sendo o nosso ponto de partida, para construir um outro tipo de indicador.
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. #include <Tutorial\File 01.mqh> 09. //+------------------------------------------------------------------+ 10. st_Cross gl_Cross; 11. //+------------------------------------------------------------------+ 12. int OnInit() 13. { 14. gl_Cross.Init(); 15. 16. IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix); 17. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); 18. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false); 19. 20. return INIT_SUCCEEDED; 21. }; 22. //+------------------------------------------------------------------+ 23. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 24. { 25. return rates_total; 26. }; 27. //+------------------------------------------------------------------+ 28. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 29. { 30. st_TimePrice tp; 31. static string isPaint = ""; 32. 33. switch (id) 34. { 35. case CHARTEVENT_KEYDOWN: 36. if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) gl_Cross.Hide(); 37. break; 38. case CHARTEVENT_MOUSE_MOVE: 39. if (((uchar)sparam & MOUSE_MIDDLE) != 0) 40. { 41. tp = gl_Cross.Move((ushort)lparam, (ushort)dparam); 42. if (isPaint == "") 43. { 44. ObjectCreate(0, isPaint = macro_NameObject, OBJ_TREND, 0, tp.Time, tp.Price); 45. ObjectSetInteger(0, isPaint, OBJPROP_SELECTABLE, true); 46. ObjectSetInteger(0, isPaint, OBJPROP_COLOR, clrMagenta); 47. ObjectSetInteger(0, isPaint, OBJPROP_WIDTH, 3); 48. ObjectSetInteger(0, isPaint, OBJPROP_RAY_RIGHT, true); 49. } 50. ObjectMove(0, isPaint, 1, tp.Time, tp.Price); 51. gl_Cross.Show(); 52. }else 53. { 54. isPaint = ""; 55. gl_Cross.Hide(); 56. } 57. break; 58. case CHARTEVENT_MOUSE_WHEEL: 59. break; 60. } 61. ChartRedraw(); 62. }; 63. //+------------------------------------------------------------------+ 64. void OnDeinit(const int reason) 65. { 66. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); 67. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true); 68. 69. gl_Cross.Hide(); 70. 71. if (reason == REASON_REMOVE) 72. ObjectsDeleteAll(0, def_Prefix); 73. }; 74. //+------------------------------------------------------------------+
Código 01
Este código apesar de funcionar tem um pequeno inconveniente, pelo ponto de vista de grande parte dos usuários. Ele cria o objeto que queremos adicionar ao gráfico, fazendo uso do botão do meio. Algo que não é muito comum. Já que naturalmente, você espera usar o botão esquerdo para fazer tão tipo de coisa. Porém isto é apenas um pequeno detalhe que por hora não nos incomoda. Já que para resolver esta questão, a fim de poder utilizar o botão esquerdo, precisamos mudar algumas coisas na forma como o código trabalha. Mas isto será feito em outro momento.
Neste momento, o que queremos é efetuar a troca do objeto OBJ_TREND pelo objeto OBJ_FIBO. Fazendo esta simples troca, passamos a ter o que é visto logo abaixo.
Animação 01
Note que mudamos o que era uma linha de tendência, para o que agora é um objeto Fibonacci. Mas não queremos de fato usar o objeto desta forma como ele está sendo criado. Já que o objeto que queremos e iremos criar, se baseia neste objeto Fibonacci. Mas não é exatamente ele. O objeto que iremos criar é uma modificação deste objeto Fibonacci. Então para simplificar este trabalho de modificação do objeto Fibonacci, vamos começar com o 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. st_Cross gl_Cross; 011. //+------------------------------------------------------------------+ 012. int OnInit() 013. { 014. gl_Cross.Init(); 015. 016. IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix); 017. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); 018. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false); 019. 020. return INIT_SUCCEEDED; 021. }; 022. //+------------------------------------------------------------------+ 023. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 024. { 025. return rates_total; 026. }; 027. //+------------------------------------------------------------------+ 028. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 029. { 030. st_TimePrice tp; 031. static string isPaint = ""; 032. 033. switch (id) 034. { 035. case CHARTEVENT_KEYDOWN: 036. if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) gl_Cross.Hide(); 037. break; 038. case CHARTEVENT_MOUSE_MOVE: 039. if (((uchar)sparam & MOUSE_MIDDLE) != 0) 040. { 041. tp = gl_Cross.Move((ushort)lparam, (ushort)dparam); 042. if (isPaint == "") 043. { 044. ObjectCreate(0, isPaint = macro_NameObject, OBJ_FIBO, 0, tp.Time, tp.Price); 045. Modifier_OBJ_FIBO(isPaint); 046. } 047. ObjectMove(0, isPaint, 1, tp.Time, tp.Price); 048. gl_Cross.Show(); 049. }else 050. { 051. isPaint = ""; 052. gl_Cross.Hide(); 053. } 054. break; 055. case CHARTEVENT_MOUSE_WHEEL: 056. break; 057. } 058. ChartRedraw(); 059. }; 060. //+------------------------------------------------------------------+ 061. void OnDeinit(const int reason) 062. { 063. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); 064. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true); 065. 066. gl_Cross.Hide(); 067. 068. if (reason == REASON_REMOVE) 069. ObjectsDeleteAll(0, def_Prefix); 070. }; 071. //+------------------------------------------------------------------+ 072. void Modifier_OBJ_FIBO(const string szNameObj) 073. { 074. const double nLevels[] = 075. { 076. 0, 077. 1, 078. 2.5 079. }; 080. const string sLevels[] = 081. { 082. "Stop", 083. "Enter", 084. "Take" 085. }; 086. const color cLevels[] = 087. { 088. clrRed, 089. clrBlue, 090. clrGreen 091. }; 092. 093. ObjectSetInteger(0, szNameObj, OBJPROP_SELECTABLE, false); 094. ObjectSetInteger(0, szNameObj, OBJPROP_COLOR, clrNONE); 095. ObjectSetInteger(0, szNameObj, OBJPROP_WIDTH, 3); 096. ObjectSetInteger(0, szNameObj, OBJPROP_RAY_RIGHT, true); 097. 098. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELS, nLevels.Size()); 099. for (uint c = 0; c < nLevels.Size(); c++) 100. { 101. ObjectSetDouble(0, szNameObj, OBJPROP_LEVELVALUE, c, nLevels[c]); 102. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELCOLOR, c, cLevels[c]); 103. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELWIDTH, c, 2); 104. ObjectSetString(0, szNameObj, OBJPROP_LEVELTEXT, c, sLevels[c]); 105. } 106. } 107. //+------------------------------------------------------------------+
Código 02
Este código 02 é muito divertido. Ainda mais que ele praticamente já tem o objeto que quero mostrar, praticamente sendo implementado. Mas como? Bem, meu caro leitor, se você observar, irá ver que na linha 45 estamos fazendo uma chamada para um procedimento, que pode ser visto lá na linha 72. Este procedimento, está um tanto quanto feio, por assim dizer. Já que ele está bem mais bagunçado, do que eu gostaria de tê-lo implementado inicialmente. Mas apesar disto, acredito que será mais simples de entender como tudo funciona.
Então antes de explicar o funcionamento deste procedimento. Que tal vermos o resultado? Este é mostrado na animação logo abaixo.
Animação 02
Note que é algo bem simples o objetivo que queremos implementar. Mas qual seria a utilidade desta ferramenta? Bem, meu caro leitor, muita gente gosta de utilizar certos tipos de setups de operação no mercado. E muitos destes setups tem alvo e stop muito bem definidos. É importante que você entenda isto, para conseguir entender o que está sendo implementado. E principalmente entender, como modificar esta mesma implementação para objetivos particulares.
Este objeto OBJ_FIBO modificado, nos permite justamente verificar este tipo de condição. Onde antes de entrar em uma operação podemos ver onde estaria a ordem de entrada, onde deveria estar a posição de stop e onde ficaria o alvo. Com base nisto, podemos avaliar se uma operação é ou não plausível. Já que um stop mal colocado, com toda a certeza irá gerar um movimento de violino. Assim como um alvo mal dimensionado. Que fará com que ele possivelmente não seja atingido.
Como diversos operadores profissionais do mercado, fazem uma análise vários minutos antes de entrar de fato em uma operação. Esta ferramenta é muito útil e imprescindível. Já que ela nos fornece a correta dimensão do que esperar durante uma operação.
Ok, mas como foi possível criar esta ferramenta? E mais, como podemos fazer para tornar ela ainda melhor, ou adaptada ao nosso estilo de trabalho? Bem, entender como isto pode ser feito, vamos agora focar no procedimento Modifier_OBJ_FIBO, que se inicia na linha 72 do código 02.
Ali podemos observar três arrays sendo criados. Cada um destes arrrays tem um objetivo, e estão correlacionados entre si. Mas antes de entender o que estes arrays fazem, vamos entender outras coisas dentro deste mesmo procedimento. Na linha 93, estamos mudando a propriedade do objeto OBJ_FIBO, para que ele não possa ser selecionado pelo usuário, quando este clicar nele. Isto é importante, pois não queremos que o objeto seja movimentado depois que ele tenha sido posicionado.
Porém isto nos trará um outro problema, que é o fato de que não poderemos remover o objeto, clicando nele e logo em seguida pressionando a tecla DELETE. Mas isto não impede de você o deletar, usando a janela que contém a lista de objetos no gráfico. Ou removendo o indicador do gráfico.
A linha 94, impede que a linha de traço seja vista no gráfico. Esta linha pode ser vista na animação 01 em magenta. Porém quando colocamos a cor clrNONE, a linha deixa de ser visível. Apesar de ainda está sendo criada. Já as duas outras linhas, 95 e 96 são simples linhas de propriedade de ajuste para o OBJ_FIBO. Nada mais a comentar sobre elas. Agora vem a parte que realmente nos interessa, e está se inicia na linha 98.
Um objeto OBJ_FIBO, é constituído de níveis, ou linhas de níveis. Não importa que tipo de variação do objeto Fibonacci que você esteja utilizando. Em qualquer caso, o objeto é criado com base em níveis. Como o MetaTrader 5, não sabe quantos níveis precisam de fato serem criados, usamos a linha 98 para informar isto a ele. Neste momento o MetaTrader 5, irá saber quantos níveis, deverão existir. Você pode indicar mais ou menos níveis. Porém, como aqui o objetivo é o de criar uma modificação que é vista na animação 02, estaremos usando poucos níveis. No caso três.
Agora preste atenção meu caro leitor. Cada um dos níveis, tem sua própria propriedade. Como estes níveis, podem ser linhas de tendência, ou mesmo curvas com a mesma finalidade. Podemos indicar como cada uma destas linhas deverá ser plotada no gráfico. Assim conseguimos construir o padrão desejado.
E como este padrão é construído? Bem, esta é a parte divertida e interessante do objeto que estamos modificando. Veja que dentro do laço, estaremos varrendo os arrays definidos a pouco. Cada um daqueles arrays, irá atribuir um valor a uma das propriedades da linha que será criada. Sendo algo bem simples de entender. No entanto, existe uma coisa que talvez seja um pouco complicado. Que é justamente o array nLevels definido na linha 74.
A parte complicada deste array é justamente os valores. Por que usar estes valores? Não poderíamos utilizar outros? Bem, para entender isto, você primeiro precisa entender uma outra coisa, sobre o objeto Fibonacci. Dentro de um objeto de Fibonacci, temos valores que irão de zero até um. Sendo que tudo que estiver dentro deste range irá ser plotado dentro do que seria o Fibonacci que todos conhecem. No entanto, podemos colocar valores menores que zero e maiores que um. E ao fazermos isto, criamos uma projeção estendida do próprio objeto. Perceba o seguinte: Quando você começa a desenhar um objeto OBJ_FIBO no gráfico. O ponto onde o desenho começa é onde estaria o valor um. E conforme você arrasta o objeto a fim de o criar, teremos a posição de onde estaria o valor zero.
Parece um tanto quanto estranho isto. Mas é assim mesmo que funciona. Assim quando adicionamos um valor dois ponto cinco, como você pode observar na linha 78, não estamos dizendo para ser criada uma projeção duas vezes e meia maior que a projeção entre o ponto um e o ponto zero. Mas sim, estamos pedindo para ser criada uma projeção uma vez e meia maior.
E é desta forma que criamos a projeção de onde estaria o alvo de uma possível operação. Se você fosse usar um alvo de 1:1 deveria colocar na linha 78 o valor de dois. Assim a mesma distância que existir entre o ponto de entrada e o stop, será projetada como sendo o alvo da operação.
Você, meu caro leitor, pode estar pensando: Cara mais isto é muito doido. E de fato é mesmo, já que você pode incluir de forma muito simples, níveis de parcial por exemplo. Tudo que precisa fazer é adicionar onde estaria os pontos, neste array declarado na linha 74. Lembrando que, ao fazer isto, você também precisaria mudar, ou ajustar, os outros dois arrays. Isto para evitar que venha a ter uma plotagem diferente da esperada durante o uso, de seu indicador personalizado, no MetaTrader 5.
Notaram que não é preciso muita coisa? Tudo que precisamos de fato é criatividade e a necessidade de se criar algo. Daí usando conhecimento simples, que foi explicado nos outros artigos desta série. Criar e implementar as nossas ideias. Simples assim.
Este tipo de coisa que estamos fazendo aqui é tão legal e tão divertido, que não nos limitamos a apenas o que foi visto acima. Podemos fazer bem mais do que isto. Para demonstrar o que estou dizendo, vamos fazer o seguinte: Originalmente o código visto em código 02, irá gerar algo parecido com o que foi visto na animação 02. Mas se mudarmos apenas o conteúdo presente no procedimento Modifier_OBJ_FIBO, para outra coisa? Como por exemplo o que é visto no fragmento de código logo abaixo. O que irá acontecer?
. . . 71. //+------------------------------------------------------------------+ 72. void Modifier_OBJ_FIBO(const string szNameObj) 73. { 74. #define macro_Mod_OBJ_FIBO(txt, pos, cor, width, style) { \ 75. ObjectSetDouble(0, szNameObj, OBJPROP_LEVELVALUE, levels, pos); \ 76. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELCOLOR, levels, cor); \ 77. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELWIDTH, levels, width); \ 78. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELSTYLE, levels, style); \ 79. ObjectSetString(0, szNameObj, OBJPROP_LEVELTEXT, levels, txt); \ 80. levels++; \ 81. } 82. 83. int levels = 0; 84. 85. ObjectSetInteger(0, szNameObj, OBJPROP_SELECTABLE, false); 86. ObjectSetInteger(0, szNameObj, OBJPROP_COLOR, clrNONE); 87. ObjectSetInteger(0, szNameObj, OBJPROP_RAY_RIGHT, true); 88. 89. macro_Mod_OBJ_FIBO("Stop", 0, clrRed, 2, STYLE_SOLID); 90. macro_Mod_OBJ_FIBO("Enter", 1, clrBlue, 2, STYLE_DASH); 91. macro_Mod_OBJ_FIBO("Partial", 1.5, clrYellowGreen, 1, STYLE_DASHDOTDOT); 92. macro_Mod_OBJ_FIBO("Take", 2, clrGreen, 2, STYLE_SOLID); 93. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELS, levels); 94. 95. #undef macro_Mod_OBJ_FIBO 96. } 97. //+------------------------------------------------------------------+
Código 03
Como todo o restante do código permanecerá inalterado. Estou apenas mostrando a parte que realmente nos interessa, neste fragmento de código 03. Porém quando você executar o código, como esta modificação vista em código 03, o resultado será bem diferente, como você pode observar na imagem logo abaixo.
Imagem 01
Observe, meu caro leitor, que isto que estamos fazendo e pode ser observado nesta imagem 01, é algo impossível de ser feito, manipulando um objeto Fibonacci diretamente no gráfico. Não importa o quanto você venha a tentar fazer isto. Definitivamente não irá conseguir criar algo como o que pode ser visto na imagem 01. Isto somente será conseguido, se for feito via código. Neste caso, a relação entre o ponto de stop e o ponto alvo é de 1:1, tendo uma parcial sendo efetuada em 50% do movimento, como você pode observar.
Mas a parte que é complicada de ser feita, é justamente o padrão de cores e linhas. Se não acredita, tente criar algo assim usando um objeto Fibonacci que você colocou via menu do MetaTrader 5. Você irá comprovar que este padrão não poderá ser criado.
Agora observe que neste caso, que pode ser visto no fragmento mostrado no código 03. O procedimento Modifier_OBJ_FIBO, ao meu entender, está bem mais fácil de ser modificado e ajustando. Isto porque, estamos utilizando uma macro, para conseguir criar os níveis de maneira muito simples. Assim qualquer novo nível pode ser adicionado. Bastando para isto, que ele fique antes da linha 93. Isto para que o MetaTrader 5, seja informado de quantos e quais níveis devem ser desenhados no gráfico.
Muito legal este tipo de coisa que você vem mostrando, meu amigo autor. Mas agora fiquei com uma pequena dúvida. Sei que o objetivo, destes artigos, não é o de mostrar como criar uma aplicação. Mas e se desejarmos implementar uma forma de o usuário interagir com este último indicador mostrado. Como poderíamos elaborar uma maneira de fazer isto? Estou perguntando isto, devido a questão de que, uma vez compilado, os valores ajustados não poderão ser mais modificados. Então como poderíamos fazer para permitir, pelo mesmos o ajuste da relação stop alvo? Ok, não vejo problemas em mostrar isto. Ainda mais que temos um pouco de tempo, que posso usar para explicar como isto poderia ser feito. Mas para separar as coisas, vamos ver isto em um outro tópico.
Ajustando a relação stop alvo
Existem diversas formas de você meu amigo leitor, implementar uma maneira de o usuário dizer qual seria a relação entre stop e alvo. Uma forma direta seria usar um valor tipo double, onde você poderia criar algo parecido como o que é mostrado no código logo abaixo.
. . . 09. //+------------------------------------------------------------------+ 10. input double user01 = 1.5; //Stop-Target Relationship 11. //+------------------------------------------------------------------+ . . . 73. //+------------------------------------------------------------------+ 74. void Modifier_OBJ_FIBO(const string szNameObj) 75. { 76. #define macro_Mod_OBJ_FIBO(txt, pos, cor, width, style) { \ 77. ObjectSetDouble(0, szNameObj, OBJPROP_LEVELVALUE, levels, pos); \ 78. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELCOLOR, levels, cor); \ 79. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELWIDTH, levels, width); \ 80. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELSTYLE, levels, style); \ 81. ObjectSetString(0, szNameObj, OBJPROP_LEVELTEXT, levels, txt); \ 82. levels++; \ 83. } 84. 85. int levels = 0; 86. 87. ObjectSetInteger(0, szNameObj, OBJPROP_SELECTABLE, false); 88. ObjectSetInteger(0, szNameObj, OBJPROP_COLOR, clrNONE); 89. ObjectSetInteger(0, szNameObj, OBJPROP_RAY_RIGHT, true); 90. 91. macro_Mod_OBJ_FIBO("Stop", 0, clrRed, 2, STYLE_SOLID); 92. macro_Mod_OBJ_FIBO("Enter", 1, clrBlue, 2, STYLE_DASH); 93. macro_Mod_OBJ_FIBO("Partial", 1 + (user01 / 2), clrYellowGreen, 1, STYLE_DASHDOTDOT); 94. macro_Mod_OBJ_FIBO("Take", 1 + user01, clrGreen, 2, STYLE_SOLID); 95. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELS, levels); 96. 97. #undef macro_Mod_OBJ_FIBO 98. } 99. //+------------------------------------------------------------------+
Código 04
Neste fragmento que podemos observar, o que está sendo feito no código 04, temos a maneira mais direta e simples de informar uma relação direta entre um stop e seu alvo. Note que foi preciso fazer muita pouca coisa. Apenas adicionamos a linha dez ao fragmento de código, e foi preciso ajustar as linhas 93 e 94. Isto para que a relação viesse a ser criada. Quando executamos o código 04, teremos acesso ao que pode ser visto na imagem logo abaixo.
Imagem 02
Uma vez ajustada esta relação, que você pode observar na imagem 02. Podemos fazer uso da mesma diretamente no gráfico. E o resultado é algo parecido com o que podemos ver na imagem abaixo.
Imagem 03
Algo realmente notável, devido ao nível de simplicidade adotados aqui. Mas você provavelmente deva estar pensando: Mas e se o usuário vier a utilizar um valor abaixo de um na relação? Ou seja, e se ele estiver querendo operar, em um tipo de situação onde a relação stop alvo seja desfavorável, por assim dizer. O que irá acontecer e que tipo de valor precisa ser colocado para que o indicador funcione? Bem, não que eu esteja incentivando este tipo de situação. Mas para que você tenha uma relação stop alvo, onde o stop será maior que o alvo final. Podemos utilizar algo parecido com o que é visto na imagem logo abaixo.
Imagem 04
Neste caso, como o valor é inferior a um, a relação estará desfavorável, por assim dizer. E quando você vier a usar este indicador no gráfico, irá notar que o resultado é algo parecido como o visto logo abaixo.
Imagem 05
Perceba que neste caso, procurei utilizar os mesmos valores aqui, como ponto de entrada. Porém a saída é bem diferente, como você claramente pode observar comparando as imagens. Definitivamente temos algo realmente muito prático e bastante funcional. Já que você pode colocar a aplicação no gráfico. Efetuar um estudo. Daí, modifica o valor como mostrado na imagem 04, e repete o estudo. Tendo assim, a possibilidade de ter diversos estudos sendo feitos ao mesmo tempo.
O único problema, talvez, seria o fato de que as linhas iriam se cruzar. Mas isto é facilmente resolvido, permitindo que o usuário utilize ou não uma linha estendida a direita. Para isto, basta que mudemos o código como mostrado logo abaixo.
. . . 09. //+------------------------------------------------------------------+ 10. input double user01 = 1.5; //Stop-Target Relationship 11. input bool user02 = true; //Extend lines to the right 12. //+------------------------------------------------------------------+ . . . 73. //+------------------------------------------------------------------+ 74. void Modifier_OBJ_FIBO(const string szNameObj) 75. { 76. #define macro_Mod_OBJ_FIBO(txt, pos, cor, width, style) { \ 77. ObjectSetDouble(0, szNameObj, OBJPROP_LEVELVALUE, levels, pos); \ 78. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELCOLOR, levels, cor); \ 79. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELWIDTH, levels, width); \ 80. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELSTYLE, levels, style); \ 81. ObjectSetString(0, szNameObj, OBJPROP_LEVELTEXT, levels, txt); \ 82. levels++; \ 83. } 84. 85. int levels = 0; 86. 87. ObjectSetInteger(0, szNameObj, OBJPROP_SELECTABLE, false); 88. ObjectSetInteger(0, szNameObj, OBJPROP_COLOR, clrNONE); 89. ObjectSetInteger(0, szNameObj, OBJPROP_RAY_RIGHT, user02); 90. 91. macro_Mod_OBJ_FIBO("Stop", 0, clrRed, 2, STYLE_SOLID); 92. macro_Mod_OBJ_FIBO("Enter", 1, clrBlue, 2, STYLE_DASH); 93. macro_Mod_OBJ_FIBO("Partial", 1 + (user01 / 2), clrYellowGreen, 1, STYLE_DASHDOTDOT); 94. macro_Mod_OBJ_FIBO("Take", 1 + user01, clrGreen, 2, STYLE_SOLID); 95. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELS, levels); 96. 97. #undef macro_Mod_OBJ_FIBO 98. } 99. //+------------------------------------------------------------------+
Código 05
Novamente, uma simples mudança que está sendo feita no fragmento mostrado no código 05. Neste caso, é a linha 11 que estamos adicionando. Esta linha terá seu valor sendo utilizado na linha 89. Onde iremos controlar se a linha será ou não estendida para o canto direito. Na imagem abaixo, podemos ver uma configuração onde a linha não será estendida.
Imagem 06
E como resultado, poderemos criar no gráfico, algo parecido com o que é visto logo abaixo.
Imagem 07
Note a seguinte coisa sendo feita aqui meu caro leitor, estamos adicionando um novo estudo no que seria a imagem 05. Mas como você pode observar, o fato de termos mudado, como é visto na imagem 06, a configuração do indicador, sem remover ele do gráfico, não remove, ou interfere do que já existia antes. Ou seja, realmente com muito pouco trabalho, conseguimos criar algo realmente muito interessante.
Enquanto muitos dizem não ser possível fazer certas coisas no MetaTrader 5, você acabou de perceber que podemos fazer qualquer tipo de coisa. E tudo isto, fazendo uso de um conhecimento mínimo e bem básico. Já que não foi preciso usar nenhum tipo de artimanha ou formas extremamente elaboradas e complexas.
Ok, tudo isto foi muito divertido. Mas ainda temos uma questão a resolver. E está será vista no tópico logo abaixo.
Usando o botão esquerdo para fazer o desenho
Uma coisa que pode estar lhe deixando um tanto quanto deprimido. Isto por não ser algo muito natural de ser feito. É utilizar o botão do meio, do mouse, como forma de fazer um desenho no gráfico. Grande parte dos usuários, de fato, está acostumado em fazer algum tipo de interação, via botão esquerdo. Utilizar o botão do meio é um tanto quanto estranho. Apesar de funcionar perfeitamente bem, como você pode constatar ao experimentar os códigos vistos até este momento. Porém isto não é o natural. Portanto, precisamos, como programadores, corrigir isto. Mas existe um pequeno porém.
E este é o seguinte: Quando você clica com o botão do meio, e efetua o desenho, todo evento do mouse, é direcionado para a linha 38. Isto pode ser visto no código 02. E enquanto este botão estiver pressionado, a cruz de analise estará no gráfico, permitindo assim que o desenho possa ser feito. Uma vez liberado o botão do meio, a linha 52 do código 02, irá remover a cruz do gráfico. Mostrando assim que já não podemos interagir com o sistema de desenho.
Muito bem, se você conseguiu entender isto, consegue entender o que é preciso ser feito, para resolver o nosso problema. Quando o botão do meio, for pressionado, teremos um evento. Este irá ficar aguardando um segundo evento. No caso um evento que seja o pressionar da tecla ESCAPE, ou um outro que seria o pressionar do botão esquerdo a fim de criar o desenho no gráfico. Posicionando assim o objeto da forma como estamos fazendo até este momento. Mas ao invés de fazer isto, com o botão do meio, será usado o botão da esquerda.
Beleza, isto é o que precisa ser feito. Agora para fazer isto, existem muitos caminhos diferentes. Uns mais trabalhosos, outros nem tanto. Porém, como o objetivo aqui é a didática, irei pelo caminho mais simples, apesar de não ser o mais indicado para toda e qualquer situação. Este é mostrado logo abaixo.
. . . 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. } 037. 038. st_TimePrice tp; 039. static string isPaint = ""; 040. static bool bMouseL = false; 041. 042. switch (id) 043. { 044. case CHARTEVENT_KEYDOWN: 045. if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) macro_CLEAN_EVENT; 046. break; 047. case CHARTEVENT_MOUSE_MOVE: 048. tp = gl_Cross.Move((ushort)lparam, (ushort)dparam); 049. if (((uchar)sparam & MOUSE_LEFT) != 0) 050. { 051. if (isPaint != "") 052. { 053. bMouseL = true; 054. if (!ObjectGetInteger(0, isPaint, OBJPROP_TIME)) ObjectMove(0, isPaint, 0, tp.Time, tp.Price); 055. ObjectMove(0, isPaint, 1, tp.Time, tp.Price); 056. } 057. }else if (bMouseL) macro_CLEAN_EVENT; 058. if ((((uchar)sparam & MOUSE_MIDDLE) != 0) && (isPaint == "")) 059. { 060. ObjectCreate(0, isPaint = macro_NameObject, OBJ_FIBO, 0, 0, 0); 061. Modifier_OBJ_FIBO(isPaint); 062. gl_Cross.Show(); 063. } 064. break; 065. case CHARTEVENT_MOUSE_WHEEL: 066. break; 067. } 068. ChartRedraw(); 069. 070. #undef macro_CLEAN_EVENT 071. }; 072. //+------------------------------------------------------------------+ . . .
Código 06
Neste fragmento de código 06, podemos ver como lidar com a situação. Onde queremos ativar o desenho quando pressionamos o botão do meio. Mas iremos fazer o desenho somente durante o período que o botão esquerdo estiver pressionado. Mas nem tudo são flores, apesar de a ideia funcionar, existe um pequeno problema, e este pode ser observado na animação logo abaixo.
Animação 03
Nesta animação 03, você claramente nota que temos uma grande dificuldade em desenhar o objeto no gráfico, devido ao fato de que o gráfico fica mexendo. As vezes este movimento do gráfico é de fato desejável. Porém não é o caso aqui. Já que ela acaba mais atrapalhando do que ajudando. Antes de ser mostrado, como resolver este problema. Vamos ver o que foi preciso mudar no código, para que pudéssemos utilizar o botão esquerdo para desenhar. Como é visto na animação 03.
Primeiramente você pode observar que adicionei uma macro na linha 32. Está irá servir para que seja possível encerrar o evento de criação do desenho no estágio em que ele vier a se encontrar. O próximo ponto a ser observado é com relação ao tratamento do evento do mouse. Observe que mudei a ordem em que as coisas são feitas. Isto é necessário para que possamos fazer com que os eventos venham a ser tratados na ordem correta. Primeiro precisamos pressionar o botão direito. Feito isto, A linha 60 irá criar o objeto OBJ_FIBO. Este será ajustado conforme desejamos, e a cruz será mostrada.
Neste momento, caso venhamos a pressionar o botão esquerdo do mouse, o teste da linha 51 irá ter êxito e teremos na linha 53 uma nova marcação. Ao mesmo tempo que as linhas 54 e 55 posicionam o objeto OBJ_FIBO no gráfico. Esta marcação que fizemos na linha 53 irá na linha 57 permitir que a cruz seja removida do gráfico, assim que o objeto OBJ_FIBO tenha sido desenhado. Isto no momento em que liberarmos o botão esquerdo do mouse.
Para corrigir o que foi visto na animação 03, precisamos mudar este fragmento de código 06, adicionando duas novas linhas a ele. Estas mudanças podem ser vistas no fragmento de código logo abaixo.
. . . 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. } 070. ChartRedraw(); 071. 072. #undef macro_CLEAN_EVENT 073. }; 074. //+------------------------------------------------------------------+ . . .
Código 07
Quando este código 07 estiver sendo utilizado, você terá como resultado o que é visto na animação logo na sequência.
Animação 04
É de fato muito curioso, que o simples fato de estarmos usando as linhas 36 e 62, neste fragmento de código 07, seja capaz de corrigir o problema da animação 03. Mas se você pensa isto, meu caro leitor, é por que não vem experimentado o que tem sido mostrado nos artigos. Já que em artigos anteriores, mostrei justamente estas mesmas funções sendo utilizadas, assim como outras. Porém, no momento em que isto a via sido feito, não chegamos neste ponto de ligar e desligar o padrão do MetaTrader 5, a fim de que algo fosse feito de maneira interativa. Como acontece neste momento.
Considerações finais
Este talvez tenha sido o artigo, no qual mais nos divertimos até este momento. Isto por que, com tão pouco já tendo sido visto e mostrado. Ainda assim conseguimos implementar algo, que não existe originalmente no MetaTrader 5. Tornando assim possível que implementássemos um indicador bastante curioso. Apenas modificando um objeto, que existe no MetaTrader 5 para outro proposito.
Sei que muitos de vocês, talvez pensassem que seria necessário aprender muito mais, antes de conseguir programar algo que fosse tão interessante e ao mesmo tempo tão divertido. Porém, este trabalho ainda não terminou. Existe neste indicador que vimos neste artigo, uma pequena falha. Falha esta, que deixei de maneira proposital, para que você meu caro leitor e aluno, pudesse praticar a fim de corrigir o problema. Vou explicar que problema é este, mas não irei mostra a solução. Isto deverá ser feito por você.
No fragmento do código 07, podemos ver que na linha 61 é criado um objeto OBJ_FIBO. Este é criado antes da cruz ser criada na linha 64. O problema é: Caso o usuário, ou mesmo você pressione a tecla ESCAPE, a linha 46 será executada. Fazendo com que a cruz seja removida do gráfico. Porém o OBJ_FIBO, criado na linha 61 permanece no gráfico. Apesar de não aparecer nele, devido ao fato de não ter sido posicionado.
Seu trabalho, será resolver isto, meu caro leitor. Isto a fim de que o OBJ_FIBO, somente seja colocado na lista de objetos, se e somente se, o botão esquerdo for pressionado, depois do botão direito ter sido pressionado. Lembre-se do problema existia quando criávamos um objeto depois de ter criado a cruz, e que mostrei como solucionar.
A solução para o problema que estou expondo, passa por algo muito parecido. Ou seja, você apenas precisa mudar a sequência em que certas operações estão sendo feitas no fragmento de código 07. Não precisando criar nenhuma rotina, ou adicionar novas funções ou procedimentos para resolver esta questão. Apenas precisa mudar a sequência em que as operações estão sendo feitas. Se você fizer isto de maneira adequada, irá conseguir sem nenhum esforço, remover a cruz e evitar que o objeto OBJ_FIBO seja criado sem necessidade. Isto permitirá ao usuário pressionar ESCAPE e não ter um objeto, sendo listado, e não aparecendo no gráfico.
No anexo, você terá acesso aos códigos vistos neste artigo. Procure praticar, resolvendo esta pequena questão, e nos vemos no próximo artigo.
Arquivo MQ5 | Descrição |
---|---|
Code 01 | Demonstração de objeto |
Code 02 | Demonstração de objeto |
Code 03 | Demonstração de objeto |
Code 04 | Demonstração de objeto |
Code 05 | Demonstração de 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