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

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

MetaTrader 5Exemplos |
136 0
CODE X
CODE X

Introdução

No artigo anterior Do básico ao intermediário: Eventos de mouse, vimos como lidar de maneira simples, clara e bastante objetiva como eventos relacionados com o mouse. Assim como também a combinação do mouse com o teclado. Isto de modo a produzir combinações de botões sendo pressionados a fim de criar algum tipo de atividade no gráfico.

Apesar de à primeira vista, aquele tipo de coisa, tratada no artigo anterior ser algo relativamente simples. Quando partimos para a prática, notamos que temos ali algo que pode ser bem mais complicado do que muitos poderiam imaginar. Isto porque, dependendo do tipo de coisa que venhamos a implementar, e da forma como venhamos a implementar. Um ou outro usuário pode não ter o hardware adequado. Isto porque, apesar de ser algo relativamente comum nos dias de hoje. Muita gente não faz uso de um desktop.

E mesmo estes que utilizam um computador de mesa, como é conhecido, os tais desktops. Um ou outro usuário, pode não ter um mouse, com mais de três botões. E isto, torna complicado, implementar certos tipos de funcionalidades voltadas ao público em geral. Para uso pessoal, sem problema. Mas se você pretende aprender a programar, a fim de comercializar suas aplicações. Você irá perceber, que nem todos possuem o equipamento adequado. Então você, ou faz as coisas, de modo a atender este público, ou os ignora e corre o risco de perder uma fatia do mercado. E tudo isto, por conta de uma simples decisão.

Ok, mas não estamos aqui, para aprender como comercializar aplicações que estamos criando. E sim aprender como colocar nossas ideias em prática. Fazendo para isto, uso do MQL5, como porta de acesso. Como o artigo anterior, ficou mais voltado a questões técnicas e de demonstração simples. Chegou a hora de colocarmos aquilo que foi mostrado lá em prática. Criando assim, uma alternativa ao que seria a cruz de análise que existe presente no MetaTrader 5.

Se bem que a ideia, não é de fato criar um substituído para tal. Mas sim, mostrar a você, meu caro leitor, que é possível fazer as coisas com muito pouco conhecimento. Mas com os conceitos corretos.


Um indicador personalizado

O que desejo mostrar aqui, foi tema de outros de meus artigos, Desenvolvendo um sistema de Replay (Parte 30): Projeto Expert Advisor - Classe C_Mouse (IV). Lá mostrei como implementar um indicador de mouse, utilizando programação orientada em objetos. Mas aqui iremos fazer algo parecido. Porém usando uma programação muito mais simples. Voltada a iniciantes. Como você, meu caro e estimado leitor.

Mas por que repetir o que já foi mostrado antes? Na verdade, não estaremos repetindo nada. Apenas o conceito. Porém, como até este momento, não falei absolutamente nada sobre programação orientada em objetos. Tendo sido demonstrando apenas a programação estrutural. Quero mostrar, que não precisamos ser especialista para construir algo que seja adequado as nossas necessidades. Podemos fazer isto, com um mínimo de conhecimento. Porém sempre visando utilizar os conceitos visto até o momento. E mesmo assim, no final, teremos o resultado que procuramos. Ou seja, o simples funciona. Mesmo quando parece não ser o suficiente.

Para começar, vamos implementar um código com base um dos vistos no artigo anterior. Este pode ser visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_Prefix  "Demo"
05. //+------------------------------------------------------------------+
06. int OnInit()
07. {
08.     IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix);
09.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
10. //+----------------+    
11.     ChartSetInteger(0, CHART_MOUSE_SCROLL, false);
12.     ChartSetInteger(0, CHART_CONTEXT_MENU, false);
13.     ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false);
14. //+----------------+
15.     ChartSetInteger(0, CHART_KEYBOARD_CONTROL, false);
16.     ChartSetInteger(0, CHART_QUICK_NAVIGATION, false);
17. //+----------------+
18. 
19.     return INIT_SUCCEEDED;
20. };
21. //+------------------------------------------------------------------+
22. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
23. {
24.     return rates_total;
25. };
26. //+------------------------------------------------------------------+
27. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
28. {
29.     string sz = "";
30. 
31.     switch (id)
32.     {
33.         case CHARTEVENT_KEYDOWN:
34.             break;
35.         case CHARTEVENT_MOUSE_MOVE:
36.             Comment(sz);
37.             sz += "Mouse position X: " + (string)(short)lparam;
38.             sz += "\nMouse position Y: " + (string)(short)dparam;
39.             Comment(sz);
40.             if ((uchar)sparam != 0) PrintFormat("Hexadecimal mask of mouse buttons is: 0x%02X", (uchar)sparam);
41.             break;
42.         case CHARTEVENT_MOUSE_WHEEL:
43.             break;
44.     }
45. };
46. //+------------------------------------------------------------------+
47. void OnDeinit(const int reason)
48. {
49.     Comment("");
50.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
51. //+----------------+    
52.     ChartSetInteger(0, CHART_MOUSE_SCROLL, true);
53.     ChartSetInteger(0, CHART_CONTEXT_MENU, true);
54.     ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true);
55. //+----------------+
56.     ChartSetInteger(0, CHART_KEYBOARD_CONTROL, true);
57.     ChartSetInteger(0, CHART_QUICK_NAVIGATION, true);
58. //+----------------+
59. };
60. //+------------------------------------------------------------------+

Código 01

Este código 01 é uma mudança do código visto no artigo anterior. Isto de forma que podemos testar uma coisa, de maneira mais simples. Note que na linha 40 estaremos imprimindo algo no terminal. Este valor é justamente o que queremos utilizar. Assim ao executar este código 01, você irá ver algo parecido como a imagem logo abaixo.

Imagem 01

Esta informação que está sendo destacada nesta imagem 01, é justamente uma máscara que precisamos utilizar. Isto para que possamos construir o evento, que dará origem a cruz de analise personalizada. Preste atenção a isto meu caro leitor. Este valor que estamos vendo aqui na imagem 01, representa o valor informado, quando acontece um clique no botão do meio. Assim sendo, considerando o fato de que ao pressionarmos o botão do meio, deverá ser criada a cruz de análise. Podemos começar a pensar em como fazer isto.

Mas existe uma outra coisa que você precisa entender também. Se você praticou com os códigos visto no artigo anterior, deve ter notado que cada uma das chamadas vistas no evento Init, ou seja, na função OnInit, vista na linha seis deste código 01. Irá habilitar ou desabilitar uma propriedade padrão do MetaTrader 5. Porém, como desejamos apenas criar uma cruz de analise personalizada. Não precisamos desligar todos aqueles eventos. Pois isto limita em demasia o uso do MetaTrader 5, por parte de algum usuário. O melhor mesmo é que venhamos a desligar apenas e somente o evento que não queremos que o MetaTrader 5, venha a utilizar por padrão. No caso seria o evento da linha 13 do código 01.

Ok, então temos um primeiro ponto a ser efetivamente mexido no código 01. Mas podemos começar a trabalhar na cruz, isto antes de vermos o próximo código a ser implementado. Agora preste atenção pois isto que iremos tratar é importante.

No artigo Do básico ao intermediário: Objetos (II), foi demonstrado como poderíamos lidar com dois objetos no gráfico ao mesmo tempo. Sendo uma linha vertical e outra horizontal.

Pois bem, tanto um, quanto o outro objeto, mencionado, NÃO FAZEM USO DE COORDENADAS DE TELA. Com são conhecidas as coordenadas X e Y, quando o assunto são gráficos em um computador. Ambos objetos OBJ_VLINE e OBJ_HLINE, utilizam coordenadas de cotação. Estas coordenadas fazem uso do preço e do tempo. E como o sistema operacional, nos fornece coordenadas X e Y, precisamos converter estes valores de coordenadas de tela em coordenadas de cotação. Fazer isto manualmente é uma tarefa bem chata, isto por que, precisamos levar em conta o preço mínimo e máximo, além do tempo mínimo e máximo, a fim de conseguir criar uma correlação entre preço e tempo, com os valores X e Y que o sistema operacional nos fornece.

Felizmente, tal tarefa é efetuada por um procedimento da biblioteca padrão do MQL5. O que facilita bastante as coisas. Então antes de começarmos a ver a cruz sendo plotada no gráfico. Vamos ver como transformar os valores X e Y em coordenadas de cotação.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_Prefix  "Demo"
05. //+------------------------------------------------------------------+
06. int OnInit()
07. {
08.     IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix);
09.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
10.     ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false);
11. 
12.     return INIT_SUCCEEDED;
13. };
14. //+------------------------------------------------------------------+
15. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
16. {
17.     return rates_total;
18. };
19. //+------------------------------------------------------------------+
20. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
21. {
22.     string      sz = "";
23.     short       x, y;
24.     int         sub;
25.     datetime    dt;
26.     double      price;
27. 
28.     switch (id)
29.     {
30.         case CHARTEVENT_KEYDOWN:
31.             break;
32.         case CHARTEVENT_MOUSE_MOVE:
33.             x = (short)lparam;
34.             y = (short)dparam;
35.             ChartXYToTimePrice(0, x, y, sub, dt, price);
36.             Comment(sz);
37.             sz += "Mouse position X: " + (string)x;
38.             sz += "\nMouse position Y: " + (string)y;
39.             sz += "\nMouse position time: " + TimeToString(dt, TIME_DATE | TIME_MINUTES);
40.             sz += "\nMouse position price: " + (string)price;
41.             Comment(sz);
42.             if ((uchar)sparam != 0) PrintFormat("Hexadecimal mask of mouse buttons is: 0x%02X", (uchar)sparam);
43.             break;
44.         case CHARTEVENT_MOUSE_WHEEL:
45.             break;
46.     }
47. };
48. //+------------------------------------------------------------------+
49. void OnDeinit(const int reason)
50. {
51.     Comment("");
52.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
53.     ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true);
54. };
55. //+------------------------------------------------------------------+

Código 02

Aqui temos um código mais simples e voltado a ligar ou desligar somente o que de fato é necessário. Todo o restante permanecerá sendo o padrão do MetaTrader 5. Note que fizemos pequenas mudanças na parte referente ao tratador de eventos do mouse. E na linha 35 temos exatamente o procedimento da biblioteca sendo usado. Isto a fim de converter os valores naqueles que realmente precisamos ou queremos utilizar. É importante que você entenda isto, antes mesmo de passar a usar os valores diretamente para controlar os objetos OBJ_VLINE e OBJ_HLINE. Para que as coisas fiquem adequadamente demonstradas, veja a animação logo abaixo.

Animação 01

Nesta animação 01, você pode observar que o gráfico está no diário. Porém olhando os valores de tempo mostrados na própria animação, podemos ver que temos dados no que seria considerando intraday. E isto pode acabar causando uma certa confusão na mente de muita gente. Isto por que, se estamos em um gráfico diário. Como poderíamos estar vendo valores de intraday?

Na verdade estes valores, são mostrados justamente por conta de que o procedimento ChartXYToTimePrice, NÃO CONVERTE valores para algo esperado por você, mas sim converte coordenadas de tela em coordenadas de cotação. E como pequenas variações no eixo produzem valores quebrados, estes valores acabam sendo convertidos em valores presentes no intraday. Por isto, vemos valores que aparentemente não fazem muito sentido de serem visto. Não configurando assim uma falha. Mas um mero detalhe da mudança de um tipo de coordenada para outro tipo.

De qualquer maneira, com base no que foi visto aqui, e usando um pouco de imaginação e bom senso. Você logo percebe, que já temos os meios necessários, para poder pensar  em como controlar os objetos OBJ_HLINE e OBJ_VLINE. Isto modificando o que foi visto no artigo Do básico ao intermediário: Objetos (II), onde o controle era feito com base no teclado. Mas agora iremos passar a utilizar o mouse para isto.

Ok, e como faremos isto? Esta é a parte divertida, meu caro leitor. Para isto, vamos primeiro criar uma cruz que irá ficar o tempo todo no gráfico. Isto é feito usando 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)
07. //+------------------------------------------------------------------+
08. string  gl_Objs[2];
09. //+------------------------------------------------------------------+
10. int OnInit()
11. {
12.     IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix);
13.     ObjectCreate(0, gl_Objs[0] = macro_NameObject, OBJ_VLINE, 0, 0, 0);
14.     ObjectCreate(0, gl_Objs[1] = macro_NameObject, OBJ_HLINE, 0, 0, 0);
15.     ObjectSetString(0, gl_Objs[0], OBJPROP_TOOLTIP, "\n");
16.     ObjectSetString(0, gl_Objs[1], OBJPROP_TOOLTIP, "\n");
17.     ObjectSetInteger(0, gl_Objs[0], OBJPROP_COLOR, clrBlue);
18.     ObjectSetInteger(0, gl_Objs[1], OBJPROP_COLOR, clrBlue);
19. 
20.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
21.     ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false);
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.     int         sub;
34.     datetime    dt;
35.     double      price;
36. 
37.     switch (id)
38.     {
39.         case CHARTEVENT_KEYDOWN:
40.             break;
41.         case CHARTEVENT_MOUSE_MOVE:
42.             ChartXYToTimePrice(0, (short)lparam, (short)dparam, sub, dt, price);
43.             ObjectMove(0, gl_Objs[0], 0, dt, price);
44.             ObjectMove(0, gl_Objs[1], 0, dt, price);
45.             if ((uchar)sparam != 0) PrintFormat("Hexadecimal mask of mouse buttons is: 0x%02X", (uchar)sparam);
46.             break;
47.         case CHARTEVENT_MOUSE_WHEEL:
48.             break;
49.     }
50.     ChartRedraw();
51. };
52. //+------------------------------------------------------------------+
53. void OnDeinit(const int reason)
54. {
55.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
56.     ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true);
57. 
58.     ObjectsDeleteAll(0, def_Prefix);
59.     ChartRedraw();
60. };
61. //+------------------------------------------------------------------+

Código 03

Este código 03, quando aplicado a um gráfico, irá produzir algo parecido com o que é visto logo abaixo.

Animação 02

Note que no começo desta animação 02, o valor no tempo muda, mesmo que a linha vertical de fato não venha a mudar. E isto devido a pequenos movimentos do mouse. Algo perfeitamente normal e aceitável. Mas observe que conforme movemos o ponteiro do mouse, as linhas vertical e horizontal seguem o movimento do mouse, nos permitindo assim ter uma cruz o tempo todo no gráfico.

Como o que está sendo feito aqui, já foi estudado em parte no artigo Do básico ao intermediário: Objetos (II), ficamos apenas com o que é novidade aqui. No caso é justamente o fato de que o movimento agora está ligado aos valores retornados pelo procedimento de biblioteca ao converter coordenadas de tela em coordenadas de cotação.

Porém, este não era exatamente o que queríamos fazer. Queríamos era mostrar esta mesma cruz. Só que depois de pressionarmos o botão do meio. Então precisamos mudar alguns pontos no código, para que isto aconteça. Mas antes de fazermos isto, vamos ver o porquê das linhas 15, 16 e 58. Bem, as linhas 15 e 16, evitam de termos uma pequena mensagem sendo mostrada pelo MetaTrader 5, quando estivermos sobre o objeto. Caso você queira mostrar uma mensagem, explicando o próprio objeto, mas que não fique o tempo todo no gráfico. Utilize este procedimento visto nas linhas 15 e 16 para colocar ali alguma mensagem significativa. Esta mensagem será mostrada, quando o mouse parar durante um pequeno período sobre o objeto apontado.

Já a linha 58, irá remover todos os objetos presentes no gráfico, cujo prefixo seja o indicado. Como estamos ligando os objetos ao próprio nome curto do indicador. Fica mais simples eliminar objetos ligados ao próprio indicador. Caso queira que o objeto permaneça no gráfico, bastará usar um prefixo diferente do que é o nome do indicador. Agora sim podemos ver o próximo código.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #define def_Prefix  "Demo"
005. //+------------------------------------------------------------------+
006. #define macro_NameObject  def_Prefix + (string)ObjectsTotal(0)
007. //+------------------------------------------------------------------+
008. enum eBtnMouse  {
009.         MOUSE_LEFT      = 0x01, 
010.         MOUSE_RIGHT     = 0x02,
011.         MOUSE_KEY_SHIFT = 0x04,
012.         MOUSE_KEY_CTRL  = 0x08,
013.         MOUSE_MIDDLE    = 0x10,
014.         MOUSE_EXTRA_1   = 0x20,
015.         MOUSE_EXTRA_2   = 0x40
016.                 };
017. //+------------------------------------------------------------------+
018. struct st_Cross
019. {
020.     private :
021. //+----------------+
022.         bool    IsView;
023.         string  Objs[2];
024. //+----------------+
025.         void Create(char index, ENUM_OBJECT type)
026.         {
027.             ObjectCreate(0, Objs[index] = macro_NameObject, type, 0, 0, 0);
028.             ObjectSetString(0, Objs[index], OBJPROP_TOOLTIP, "\n");
029.             ObjectSetInteger(0, Objs[index], OBJPROP_COLOR, clrBlue);
030.         }
031. //+----------------+
032.     public  :
033. //+----------------+
034.         void Show(void)
035.         {
036.             if (IsView) return;
037.             Create(0, OBJ_VLINE);
038.             Create(1, OBJ_HLINE);
039.             IsView = true;
040.             ChartRedraw();
041.         }
042. //+----------------+
043.         void Hide(void)
044.         {
045.             if (!IsView) return;
046.             for(uint c = 0; c < Objs.Size(); c++)
047.                 ObjectDelete(0, Objs[c]);
048.             ChartRedraw();
049.             IsView = false;
050.         }
051. //+----------------+
052.         void Move(short x, short y)
053.         {
054.             int         sub;
055.             datetime    dt;
056.             double      price;
057. 
058.             if (!IsView) return;
059.             ChartXYToTimePrice(0, x, y, sub, dt, price);
060.             ObjectMove(0, Objs[0], 0, dt, price);
061.             ObjectMove(0, Objs[1], 0, dt, price);
062.             ChartRedraw();
063.         }
064. //+----------------+
065. }gl_Cross;
066. //+------------------------------------------------------------------+
067. int OnInit()
068. {
069.     gl_Cross.Hide();
070.     
071.     IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix);
072.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
073.     ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false);
074. 
075.     return INIT_SUCCEEDED;
076. };
077. //+------------------------------------------------------------------+
078. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
079. {
080.     return rates_total;
081. };
082. //+------------------------------------------------------------------+
083. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
084. {
085. 
086.     switch (id)
087.     {
088.         case CHARTEVENT_KEYDOWN:
089.             break;
090.         case CHARTEVENT_MOUSE_MOVE:
091.             if (((uchar)sparam & MOUSE_MIDDLE) != 0) gl_Cross.Show();
092.             gl_Cross.Move((ushort)lparam, (ushort)dparam);
093.             break;
094.         case CHARTEVENT_MOUSE_WHEEL:
095.             break;
096.     }
097.     ChartRedraw();
098. };
099. //+------------------------------------------------------------------+
100. void OnDeinit(const int reason)
101. {
102.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
103.     ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true);
104. 
105.     gl_Cross.Hide();
106. };
107. //+------------------------------------------------------------------+

Código 04

Legal, mas o que este código 04 faz? Bem, ele irá fazer o que é visto na animação logo abaixo.

Animação 03

Hum, interessante. Mas vejo que você passou a utilizar um código estruturado. Por que? Bem, meu caro leitor, o motivo para isto, é justamente pelo fato de que um código estruturado ser mais simples de construir e manter a própria cruz. Lembre-se de que o objetivo de uma estrutura é justamente criar todo um conjunto de funções e procedimentos que estejam diretamente correlacionados com um dado objetivo.

Nos artigos Do básico ao intermediário: Struct (VII) onde expliquei a forma de estruturar um código, as coisas foram mostradas de uma maneira abstrata. Mas quando levamos isto a um objetivo menos abstrato, as coisas começam a fazer um pouco mais de sentido.

Aqui, neste código 04, estamos na tábua da beirada, no que se refere a um código estrutura e um código orientado em objetos. Isto por que, neste código 04, você pode notar que existem pontos que precisam ser inicializados antes mesmo de podemos utilizar a própria estrutura. E este é um dos motivos pelo qual a programação orientada em objetos foi criada. Note o seguinte: Quando a estrutura st_Cross é declarada na linha 65 para ser utilizada pela variável gl_Cross, não temos certeza dos valores que IsView e o array Objs, contém. Isto torna tenso criar certos tipos de código. Ainda mais códigos voltados a trabalhar com determinados tipos de dados.

Porém como a coisa aqui transcorre com uma certa tranquilidade, podemos usar a linha 69, parar preparar a estrutura a fim de começarmos a trabalhar com ela. Não é a forma mais adequada de se fazer isto. No entanto, como foi dito, aqui estamos trabalhando com algo relativamente tranquilo. Então quando na linha 91 verificamos se o botão do meio foi ou não pressionado, podemos mostrar ou não os objetos que criam a cruz de analise simples. Isto é feito chamando ou não o procedimento Show da estrutura st_Cross.

De qualquer forma, na linha 92 pedimos para os objetos terem suas posições corrigidas de modo a ficarem atrelados ao ponteiro do mouse. Entretanto, se os objetos não estiverem presentes no gráfico, IsView será falso. E isto na linha 58 evitará que o código prossiga, retornando imediatamente ao chamador, que no caso é a linha 92. E as coisas irão se manter assim, até que o botão do meio seja pressionado. Quando finalmente a cruz será criada. Passando deste momento em diante a ser atualizada a cada movimento do mouse. Já que IsView neste caso passará a ter um valor verdadeiro, permitindo assim que a linha 92 atualize a posição. Já que a linha 58 irá falhar.

Ok, mas então como fazemos a cruz desaparecer, uma vez que ela esteja visível? Isto depende do que você pretende fazer com a cruz e de como ela irá funcionar. Mas sem muito trabalho, e com pouco código, podemos adicionar uma tecla, para remover a cruz do gráfico. Isto até que ela esteja de fato funcional. Para isto, mudamos o código de tratamento de eventos, a fim de implementar esta forma de remover a cruz do gráfico, como mostrado no fragmento de código logo abaixo.

                   .
                   .
                   .
082. //+------------------------------------------------------------------+
083. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
084. {
085. 
086.     switch (id)
087.     {
088.         case CHARTEVENT_KEYDOWN:
089.             if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) gl_Cross.Hide();
090.             break;
091.         case CHARTEVENT_MOUSE_MOVE:
092.             if (((uchar)sparam & MOUSE_MIDDLE) != 0) gl_Cross.Show();
093.             gl_Cross.Move((ushort)lparam, (ushort)dparam);
094.             break;
095.         case CHARTEVENT_MOUSE_WHEEL:
096.             break;
097.     }
098.     ChartRedraw();
099. };
100. //+------------------------------------------------------------------+
                   .
                   .
                   .

Código 05

Esta simples mudança que você pode ver sendo feita na linha 89, nos permite fazer o que é mostrado na animação logo abaixo.

Animação 04

Perceba que agora podemos mostrar ou não a cruz de análise. Mas aqui na animação 04 existe uma questão que é importante. O tamanho do ticket do contrato. Ou de quantos em quantos pontos varia a cotação. Diferente de muitos dos casos, este contrato futuro, que no caso é o contrato futuro de dólar, não se move de um em um. mas sim de 0,5 em 0,5. Para constatar isto, podemos olhar as especificações do contrato, como é mostrado logo abaixo.

Imagem 02

E o que esta imagem 02 está nos mostrando? Bem, nesta imagem 02, podemos ver de quanto em quanto varia a cotação de um ativo. E é justamente isto que estou destacando aqui. Esta informação é importante para que possamos construir um método adequado a fim de que a linha de preço sempre venha a refletir uma cotação real. Nada adianta a linha de preço refletir um valor que jamais será utilizado. Isto porque, tal valor não pode ser utilizado para envios de ordens por exemplo.

Para resolver isto, precisamos mexer novamente no código. Mas desta vez, não iremos mexer no tratador de eventos. E sim na estrutura st_Cross, como pode ser visto logo abaixo.

                   .
                   .
                   .
                   
017. //+------------------------------------------------------------------+
018. struct st_Cross
019. {
020.     private :
021. //+----------------+
022.         bool    IsView;
023.         string  Objs[2];
024.         int     nDigits;
025.             double  PointPerTick;
026. //+----------------+
027.         void Create(char index, ENUM_OBJECT type)
028.         {
029.             ObjectCreate(0, Objs[index] = macro_NameObject, type, 0, 0, 0);
030.             ObjectSetString(0, Objs[index], OBJPROP_TOOLTIP, "\n");
031.             ObjectSetInteger(0, Objs[index], OBJPROP_COLOR, clrBlue);
032.         }
033. //+----------------+
034.     public  :
035. //+----------------+
036.         void Init(void)
037.         {
038.             nDigits         = (int) SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
039.             PointPerTick    = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
040.             Hide();
041.         }
042. //+----------------+
                   .
                   .
                   .
060. //+----------------+
061.         void Move(short x, short y)
062.         {
063.             int         sub;
064.             datetime    dt;
065.             double      price;
066. 
067.             if (!IsView) return;
068.             ChartXYToTimePrice(0, x, y, sub, dt, price);
069.             price = NormalizeDouble(MathRound(price / PointPerTick) * PointPerTick, nDigits);
070.             ObjectMove(0, Objs[0], 0, dt, price);
071.             ObjectMove(0, Objs[1], 0, dt, price);
072.             ChartRedraw();
073.         }
074. //+----------------+
075. }gl_Cross;
076. //+------------------------------------------------------------------+
077. int OnInit()
078. {
079.     gl_Cross.Init();
080. 
081.     IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix);
082.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
083.     ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false);
084. 
085.     return INIT_SUCCEEDED;
086. };
087. //+------------------------------------------------------------------+
                   .
                   .
                   .

Código 06

Agora veja que fizemos mudanças muito simples neste fragmento que podemos ver no código 06. Primeiro adicionamos novas variáveis a estrutura. Estas servem para evitar que venhamos a precisar ficar lendo o mesmo tipo de coisa o tempo todo. Logo depois adicionamos um novo procedimento: Init, este está na linha 36, onde inicializamos a estrutura de maneira um pouco mais adequada. Devido a isto, em OnInit, mudamos a chamada que antes era feita para o procedimento Hide, e a redirecionamos para Init, como você pode ver na linha 79.

Agora para corrigir aquela variação na linha do preço, usamos a linha 69, a fim de corrigir o preço de maneira adequada. No final temos o que podemos ver na animação logo abaixo.

Animação 05

Simplesmente perfeito. Com um código extremamente simples, conseguimos criar o que seria o nosso indicador primordial e completamente personalizado. Agora vem a questão: Que tipo de estudo podemos fazer com este indicador? Já que ele não está criado nenhum estudo específico. Bem, meu caro leitor, esta é a questão que não existe de fato uma maneira simples de responder. Isto por que, podemos implementar absolutamente qualquer tipo de estudo. Tudo depende do que você queira de fato fazer, e como pretende utilizar o que será criado deste momento em diante.

Lembre-se que o conteúdo proposto a estes artigos, tem como objetivo a didática. E como cada ponto que está sendo visto aqui, não existe de modo algum um objetivo previamente definido, no qual estamos buscando alcançar. Então não se apegue a esta ou aquela forma de implementar as coisas, apenas procure entender os conceitos. E uma vez compreendido o conceito, tudo que restará a você em fazer, é implementar o que deseja ou precisa fazer.

Como podemos tornar este indicador visto aqui, em algo realmente muito prático e extremamente divertido e interessante. Vamos fazer o seguinte: Remover a estrutura st_Cross, para um arquivo de cabeçalho. Assim, você poderá implementar diversos outros indicadores com um mínimo de trabalho. Além do mais, podemos preparar ela para que venha a se tornar uma futura classe, isto depois que estivermos falando sobre classes. Assim, passamos a ter dois arquivos, sendo construídos, um que é visto logo abaixo, que seria o arquivo de cabeçalho.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. enum eBtnMouse  {
05.         MOUSE_LEFT      = 0x01, 
06.         MOUSE_RIGHT     = 0x02,
07.         MOUSE_KEY_SHIFT = 0x04,
08.         MOUSE_KEY_CTRL  = 0x08,
09.         MOUSE_MIDDLE    = 0x10,
10.         MOUSE_EXTRA_1   = 0x20,
11.         MOUSE_EXTRA_2   = 0x40
12.                 };
13. //+------------------------------------------------------------------+
14. struct st_TimePrice
15. {
16.     double      Price;
17.     datetime    Time;
18. };
19. //+------------------------------------------------------------------+
20. struct st_Cross
21. {
22.     private :
23. //+----------------+
24.         bool    IsView;
25.         string  Objs[2];
26.         int     nDigits;
27.         double      PointPerTick;
28. //+----------------+
29.         void Create(char index, ENUM_OBJECT type)
30.         {
31.             ObjectCreate(0, Objs[index] = macro_NameObject, type, 0, 0, 0);
32.             ObjectSetString(0, Objs[index], OBJPROP_TOOLTIP, "\n");
33.             ObjectSetInteger(0, Objs[index], OBJPROP_COLOR, clrBlue);
34.         }
35. //+----------------+
36.     public  :
37. //+----------------+
38.         void Init(void)
39.         {
40.             nDigits         = (int) SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
41.             PointPerTick    = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
42.             Hide();
43.         }
44. //+----------------+
45.         void Show(void)
46.         {
47.             if (IsView) return;
48.             Create(0, OBJ_VLINE);
49.             Create(1, OBJ_HLINE);
50.             IsView = true;
51.             ChartRedraw();
52.         }
53. //+----------------+
54.         void Hide(void)
55.         {
56.             if (!IsView) return;
57.             for(uint c = 0; c < Objs.Size(); c++)
58.                 ObjectDelete(0, Objs[c]);
59.             ChartRedraw();
60.             IsView = false;
61.         }
62. //+----------------+
63.         st_TimePrice Move(short x, short y)
64.         {
65.             int             sub;
66.             st_TimePrice    tp;
67. 
68.             ChartXYToTimePrice(0, x, y, sub, tp.Time, tp.Price);
69.             tp.Price = NormalizeDouble(MathRound(tp.Price / PointPerTick) * PointPerTick, nDigits);
70.             if (IsView)
71.             {
72.                 ObjectMove(0, Objs[0], 0, tp.Time, tp.Price);
73.                 ObjectMove(0, Objs[1], 0, tp.Time, tp.Price);
74.                 ChartRedraw();
75.             }
76. 
77.             return tp;
78.         }
79. //+----------------+
80. };
81. //+------------------------------------------------------------------+

Código 07

E este outro, que nos remota ao indicador que queremos implementar.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_Prefix  "Demo"
05. //+------------------------------------------------------------------+
06. #define macro_NameObject  def_Prefix + (string)ObjectsTotal(0)
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. 
31.     switch (id)
32.     {
33.         case CHARTEVENT_KEYDOWN:
34.             if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) gl_Cross.Hide();
35.             break;
36.         case CHARTEVENT_MOUSE_MOVE:
37.             if (((uchar)sparam & MOUSE_MIDDLE) != 0) gl_Cross.Show();
38.             gl_Cross.Move((ushort)lparam, (ushort)dparam);
39.             break;
40.         case CHARTEVENT_MOUSE_WHEEL:
41.             break;
42.     }
43.     ChartRedraw();
44. };
45. //+------------------------------------------------------------------+
46. void OnDeinit(const int reason)
47. {
48.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
49.     ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true);
50. 
51.     gl_Cross.Hide();
52. };
53. //+------------------------------------------------------------------+

Código 08

Observe que no código 07, adicionamos uma nova estrutura. Esta tem como objetivo retornar o atual valor com base no movimento e posição do mouse. E no código 08, você precisa prestar atenção ao fato de que, o arquivo de cabeçalho está sendo adicionado depois das definições. Isto é importante para que o arquivo possa de fato vir a ser compilado. Com isto agora temos algo com o qual podemos nos divertir durante um bom tempo.

Então vamos começar com um indicador relativamente simples e barato. Digo que ele é barato, por não exigir muito esforço na sua implementação. Apenas um pouco de cuidado. Mas para separar as coisas de maneira adequada vamos a um novo tópico.


Indicador de linha de tendência

Um dos indicadores mais simples, baratos e menos custosos de serem criados, é o de linha de tendência. Pense no seguinte, você deseja criar um indicador, que lhe permita adicionar linhas de tendência sem precisar de todo aquele trabalho, de ter que selecionar o objeto no menu do MetaTrader 5. Assim você decide criar um indicador para agilizar este tipo de atividade. Com base no código 08, que é um código no qual podemos nos basear para criar todos os demais tipos de indicadores que utilizam objetos. Faremos pequenas modificações no código para criar o indicador que fará uso da linha de tendência.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_Prefix  "Demo"
05. //+------------------------------------------------------------------+
06. #define macro_NameObject  def_Prefix + (string)ObjectsTotal(0)
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.                 gl_Cross.Show();
42.                 tp = gl_Cross.Move((ushort)lparam, (ushort)dparam);
43.                 if (isPaint == "")
44.                 {
45.                     ObjectCreate(0, isPaint = macro_NameObject, OBJ_TREND, 0, tp.Time, tp.Price);
46.                     ObjectSetInteger(0, isPaint, OBJPROP_SELECTABLE, true);
47.                     ObjectSetInteger(0, isPaint, OBJPROP_COLOR, clrMagenta);
48.                     ObjectSetInteger(0, isPaint, OBJPROP_WIDTH, 3);
49.                     ObjectSetInteger(0, isPaint, OBJPROP_RAY_RIGHT, true);
50.                 }
51.                 ObjectMove(0, isPaint, 1, tp.Time, tp.Price);
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 09

Este código 09 servirá para que eu possa explicar uma coisa, que muito iniciante desconhece.

Em programação, a ordem dos fatores altera o produto.

Esta simples frase, que parece não ter efeito, na maior parte das decisões que tomamos na vida de todo programador. De fato, é uma verdade suprema, desconhecida por muito iniciante. Tanto que se você executar o código 09 em um gráfico, irá obter o que é visto logo abaixo.

Animação 06

Ou seja, o que pretendíamos fazer funciona. Mas você pode estar pensando: E se eu desejar mudar o traçado, da linha de tendência. Seja por qualquer motivo. Como poderei fazer isto? Esta é a parte fácil meu caro leitor. Normalmente precisamos efetuar um duplo clique em um objeto para poder selecionar o mesmo. Mas se você mudar a opção mostrada na imagem logo abaixo, precisará apenas dar um único clique para selecionar um objeto.

Imagem 03

Lembrando que isto apenas irá valer para objetos selecionáveis. Mas depois iremos falar mais sobre isto. Por hora, todos os objetos, são incialmente selecionáveis dentro do MetaTrader 5. Ok, deixada a opção demarcada na imagem 03, da forma como está sendo mostrado. Podemos fazer o que é mostrado na animação logo abaixo.

Animação 07

Ou seja, você logo fica todo orgulhoso, por ter conseguido criar um código, com base em outro. Porém, toda via e, entretanto existe uma falha aqui. Caso você tente criar uma nova linha de tendência, como mostrado na animação logo a seguir, veja o que irá acontecer.

Animação 08

Epá, agora não entendi. Que coisa mais estranha. Por que a linha de tendência anterior foi apagada? E por que uma das linhas da cruz não apareceu durante a tentativa de criarmos uma nova linha de tendência? Este tipo de coisa é muito estranho. Não esperava que isto poderia vir a acontecer. Já que aparentemente o código haveria funcionado perfeitamente bem, ao olharmos a animação 06. Bem, meu caro leitor, o problema é que os objetos estão sendo criados em uma ordem errada. Parece estranho dizer isto. Mas sim, o que podemos ver nesta animação 08, é justamente a consequência desta criação sendo feita na ordem errada.

Se você observar no código 09 irá notar que primeiro estamos criando a cruz. Isto é feito na linha 41. Logo depois na linha 45 criamos a linha de tendência. Não haveria nenhum tipo de problema nesta sequência de criação, desde é claro não fosse tentada a criação de um novo objeto. Quando isto é feito, como você pode observar na animação 08. Temos um problema. Se bem que na verdade, seriam dois problemas. O primeiro se deve ao fato de que a macro da linha seis do código 09, não está levando em consideração o fato de existir ou não algum objeto já presente no gráfico. Por conta disto, se os objetos estiverem sendo enumerados, tendo um mesmo prefixo, iremos em algum momento colidir com um objeto já presente no gráfico.

Mas como assim? Bem, vamos considerar que não exista inicialmente nenhum objeto no gráfico. Assim que você criar a cruz, teremos dois objetos, um que será o objeto como o nome "Demo0" e o outro que será o "Demo1". Até aí ok, quando a linha de tendência for criada na linha 45 do código 09, teremos um terceiro objeto, "Demo2".

Agora chegamos ao ponto onde a linha que está sendo visto na animação 06. Quando for tentado criar uma nova linha de tendência, a cruz agora irá ser criada com uma tentativa de se criar o objeto "Demo1" e "Demo2". Mas espere um pouco, já existe um objeto no gráfico chamado "Demo2", que seria a linha de tendência anterior. Sim, meu caro leitor, por conta disto, uma das linhas da cruz não será criada. E isto gera o que você pode ver no início da animação 08. Porém quando a cruz for ser removida. Iremos remover tanto "Demo1" como "Demo2", eliminando assim a antiga linha de tendência. E neste ponto, não teremos mais nenhum objeto no gráfico. Fazendo com que venhamos a voltar na condição inicial de criação da linha de tendência.

Veja que o primeiro problema foi causado por conta da contagem de objetos presentes no gráfico. Já o segundo problema se deve a ordem em que os objetos estão sendo criados. Assim para eliminar ambos os problemas, precisamos modificar o código 09 para o que é 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. #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 10

Ao executarmos este código 10, iremos ver o que é mostrado na animação logo abaixo.

Animação 09

Note que agora podemos adicionar tantas linhas de tendência, quanto venhamos a desejar adicionar. E isto sem nenhum tipo de problema. Já que a linha seis deste código 10, corrige o problema de colisão nos nomes. E a cruz somente é mostrada depois de termos criado a linha de tendência que será colocada no gráfico. Isto você pode ver sendo feito na linha 51, onde efetivamente criamos a cruz de analise simples. Ou seja, o simples fato de termos mudado a ordem em que as coisas seriam efetivamente executadas, passou a nos permitir a solução do segundo problema, que impedia manter o objeto desejado no gráfico.


Considerações finais

Neste artigo, vimos como poderíamos colocar em prática, algo que muitos acham difícil de ser feito. Ou no mínimo não conseguem bolar uma maneira que seja possível trabalhar com objetos diretamente em um indicador. Podendo colocar eles em um gráfico e depois fazer uso dos mesmos.

É bem verdade, que aqui foi demonstrando como trabalhar com um objeto relativamente bem simples. Que é uma linha de tendência. Mas não fique imaginando que apesar disto, tal aplicação que foi mostrada aqui, é algo bobo e sem muito proposito. Você pode utilizar o que foi visto aqui, a fim de treinar e praticar diversas coisas. Ao mesmo tempo, que tenta produzir uma aplicação que venha a ser realmente útil para você, meu caro leitor. Procure estudar e ver o que pode ser melhorado no que foi mostrado neste artigo.

Lembrando que aqui, ainda não estamos trabalhando com classes. O que torna o desafio ainda mais interessante. Isto porque, dependendo da forma como você planejar implementar as coisas, irá começar a ver que existem pontos que podem ser melhorados na forma de implementar as coisas. E tais pontos nos remete a um novo estilo de programação. Que ainda não foi visto ou mostrado aqui nesta pequena sequência de artigos, mas que em breve fará parte do nosso repertorio.

Então divirta-se com os códigos presentes no anexo, e nos vemos no próximo artigo. Onde iremos ver como fazer outros tipos de manipulação em objetos presentes no gráfico.

Arquivo MQ5Descrição
Code 01Demonstração de objetos
Arquivos anexados |
Anexo.zip (2.42 KB)
Computação quântica e trading: Um novo olhar sobre as previsões de preços Computação quântica e trading: Um novo olhar sobre as previsões de preços
Este artigo analisa uma abordagem inovadora para prever os movimentos de preços nos mercados financeiros mediante computação quântica. O foco principal está na aplicação do algoritmo de estimativa de fase quântica (QPE) para buscar precursores de padrões de preços, o que permite acelerar significativamente o processo de análise de dados de mercado.
Do básico ao intermediário: Eventos de mouse Do básico ao intermediário: Eventos de mouse
Este artigo, é uns dos que definitivamente, é necessário não apenas ver o código e o estudar para compreender o que estará acontecendo. É de fato, necessário, criar uma aplicação executável e a utilizar em um gráfico qualquer. Isto maneira a conseguir entender pequenos detalhes, que de outra forma são muito complicados de serem compreendidos. Como por exemplo, a combinação de teclado com o mouse, a fim de construir certos tipos de coisas.
Funções de ativação de neurônios durante o aprendizado: chave para uma convergência rápida? Funções de ativação de neurônios durante o aprendizado: chave para uma convergência rápida?
Este trabalho apresenta uma análise da interação entre diferentes funções de ativação e algoritmos de otimização no contexto do treinamento de redes neurais. A atenção principal está voltada para a comparação entre o ADAM clássico e sua versão populacional ao lidar com uma ampla gama de funções de ativação, incluindo as funções oscilatórias ACON e Snake. Mediante uma arquitetura MLP minimalista (1-1-1) e um único exemplo de treino, isola-se a influência das funções de ativação no processo de otimização, eliminando interferências de outros fatores. Propomos um método de controle dos pesos da rede por meio dos limites das funções de ativação e um mecanismo de reflexão de pesos, permitindo evitar problemas de saturação e estagnação no aprendizado.
Analisamos o código binário dos preços no mercado (Parte I): Um novo olhar sobre a análise técnica Analisamos o código binário dos preços no mercado (Parte I): Um novo olhar sobre a análise técnica
Este artigo apresenta uma abordagem inovadora para a análise técnica, baseada na conversão dos movimentos de preço em código binário. O autor mostra como diferentes aspectos do comportamento do mercado - desde movimentos simples de preço até padrões complexos - podem ser codificados em sequências de zeros e uns.