English Русский Español Deutsch 日本語
preview
Desenvolvendo um sistema de Replay (Parte 28): Projeto Expert Advisor — Classe C_Mouse (II)

Desenvolvendo um sistema de Replay (Parte 28): Projeto Expert Advisor — Classe C_Mouse (II)

MetaTrader 5Testador | 27 setembro 2023, 13:13
365 0
Daniel Jose
Daniel Jose

Introdução

No artigo anterior Desenvolvendo um sistema de Replay (Parte 27): Projeto Expert Advisor (II), começamos a desenvolver uma nova classe. Mas ao aproximar do final do artigo, acabei me convencendo de que seria muito bom apresentar uma forma diferente de programação. Esta será apenas para curiosidade, a fim de se aproximar de uma linguagem natural.

Para quem programa a um bom tempo, o que irei mostrar não fará muito sentido. Por que ter o trabalho de tentar aproximar de uma linguagem natural ?!?! A resposta é simples: Você não programa para a máquina e sim para outros programadores. Quanto de fato os primeiros sistema capazes de fatorar alguma coisa, começaram a ser produzidos. Tudo tinha que ser feito por engenheiros com grande conhecimento, no que estava sendo projetado. Isto nos primórdios da computação, onde se quer existia algum tipo de terminal, para que fosse possível programar algo.

Conforme ia se desenvolvendo, e o interesse de que mais pessoas também conseguisse criar algo, começou surgir novas ideias e meios, de programar aquelas máquinas, que antes era feito mudando a posição dos conectores. Assim começamos a ter os primeiros terminais. Mais tempo passou e aquilo de programar inicialmente puramente em binário, deixou de ser a base. Já que os programas estavam crescendo muito rápido. Assim se tornou necessário uma maneira mais eficiente de ler o que estava programado. Surge assim a linguagem Assembly, a base de tudo. Tornando agora toda aquela trabalheira em binário, em algo relativamente mais legível, usando para isto os OpCodes, ou código mnemônico. Mais um tempo se passou, e os programas se tornando ainda mais complexos e tendo a necessidade de mais e mais código, começou a surgir as primeiras linguagens de nível mais alto.

Você já poderia não precisar lidar diretamente com os OpCodes, poderia usar uma linguagem mais próxima da natural. Se bem que no inicio tais linguagens eram voltadas para efetivamente, criar e descrever conceitos matemáticos. Ou seja, as linguagens serviam puramente para facilitar a tradução de formulas em algo que o computador pudesse entender. Este trabalho todo já não precisava ser feito por um ser humano. Começou uma nova era, a dos compilador, que iria fazer a tradução lexica humana em algo compreendido pela máquina. Durante anos sempre programei de forma. Sempre tentei explicar como os programas são criados. Incentivando mais pessoas a estudar e conseguirem colocar as suas ideias, em algo que o computador pudesse compreender. Mas sempre vi que muitos tem dificuldade no começo, em compreender certos conceitos. Já que grande parte da programação trata de combinar e utilizar símbolos, a fim de dizer o que se pretende de fato criar.

Mas já que a linguagem MQL5, deriva da linguagem C/C++, e estas tem a capacidades de fazer coisas, de modo que conseguimos tornar um código mais legível a torna ideal para mostrar uma outra coisa. Então depois de analisar um pouco e acabar vendo que, posso ajudar, um pouco os entusiastas a compreenderem o que está sendo programado, mesmo sem compreender a totalidade do código. Irei mudar um pouco, e durante um breve período, a forma como o código será expresso. No final, tudo será mesmo compreendido pelo compilador. Então não faz nenhuma diferença para ele. Mas para em é entusiasta fará grande diferença já que a linguagem será bem mais próxima da natural. Mesmo que a primeira vista o código pareça estranho e extravagante. A compreensão ficará consideravelmente muito mais fácil para quem está começando.

Então lhe convido a me acompanhar, estes breves momento, em que irei usar a linguagem MQL5, de uma forma bem mais próxima da linguagem natural.


Criando o arquivo Defines.mqh

A dois artigo atrás, falei sobre o uso da diretiva de compilação #define. Disse que existia um caso especial que a definição não era destruída no final do arquivo. Apesar de não ter demonstrado ali, uma aplicação deste uso da diretiva, dado que não existia uma maneira adequada de faze-lo ali. Deixei o assunto naquele ponto em aberto. O grande detalhe é de que fato, se você compreender adequadamente algumas coisas e conceitos sobre MQL5, sabendo que ela deriva de C/C++, começa a ficar mais interessante fazer algumas coisas na linguagem. Isto sem muita dificuldade. Assim o código se torna mais legível, tanto  por parte de quem não é programador e não consiga entender todos aqueles símbolos. Quanto para quem já é programador, e precisa entender o que esta sendo feito.

Uma destas coisas que podemos fazer, isto usando a diretiva #define é tornar mais legível os seus códigos. É bem verdade, que existem limitações, e que no primeiro momento irá lhe parecer bastante estranho. Mas tudo é uma questão de saber definir adequadamente e sem exageros, alguns dos símbolos ou combinações de símbolos, presentes na sintaxe da linguagem MQL5. Nos de fato não iremos criar uma nova linguagem, apenas fazer uma substituição de algumas simbologias presentes, de maneira bastante coerente. Desta forma nasce o seguinte arquivo: Defines.mqh. Este conterá tais definições, a fim de que a sintaxe que era simbólica, passe a ser algum tipo de palavra ou definição mais expressiva para um leitor humano.

O conteúdo inicial deste arquivo, pode ser visto abaixo. Na integra:

//+------------------------------------------------------------------+
#property copyright "Daniel Jose"
/*+------------------------------------------------------------------+
Definitions for increasing the level of the coded language in MQL5, for
more details see the article at the following link:
https://www.mql5.com/en/articles/11349
+------------------------------------------------------------------+*/
#define equal =
#define different !=
#define identical ==
#define and &&
//+------------------------------------------------------------------+

O que este modesto código, praticamente e aparentemente sem nenhum tipo de função está de fato fazendo ?!?! Para entender isto será preciso colocar ele em prática. Mas observe com calma as linhas, que presentes. Cada uma representa um aumento algo, a ponto de tornar mais legível o código. Mesmo uma pessoa com pouco experiência conseguirá entender parte, se não a totalidade do que esta sendo programado. Esta questão sobre o código ser mais legível ou menos legível, é algo que você deve de fato sempre procurar fazer. É preferível um código mais legível, mesmo que isto lhe dê um pouco mais de trabalho no começo. Mas, no final irá valer a pena. Pois ninguém de fato deseja ter em suas mãos um código, que lhe parece um hieróglifo, que apenas quem escreveu, e muitas das vezes nem mesmo este, consegue entender. E uma vez que aquele modo de codificação deixe de existir, seja por que a língua ou o individuo deixou de existir, fará com que todo o conhecimento contido ali também deixe de existir.

Um dos meios de tornar o código mais legível, é o uso de comentários. Mas quem observa os código presentes nos meus artigos, irá notar que em nenhum deles, faço comentários. Isto pelo fato de que para mim, tais códigos são bastante simples e perfeitamente legíveis. Além disto, todo ele é documentado de alguma forma. Mas a pergunta é: Sem estes artigos, Você iria conseguir compreende-los ?!?! E é está a questão aqui. Em algum momento, o código irá ficar tão complexo, que sem uma boa estruturação o mesmo iria ficar totalmente ilegível. E nem mesmo eu conseguiria continuar a manter o código e o melhorar.

Uma vez que este arquivo Defines.mqh, tenha sido criado, precisamos de alguma forma fazer com que o compilador, venha a usá-lo. Para fazer isto, incluiremos o mesmo, em um dos arquivos mais básico de toda a construção do sistema. Este arquivo é o C_Terminal.mqh. Desta forma, ao observar a parte referente as inclusões do arquivo C_Terminal.mqh, você irá ver a seguinte linha de código:

#include "Macros.mqh"
#include "..\..\Defines.mqh"

Prestem atenção, pois é algo importante. O arquivo Macros.mqh, esta sendo declarado entre aspas duplas. Assim o compilador entende que este arquivo se encontra na mesma pasta onde se encontra o arquivo C_Terminal.mqh. No entanto, no momento que incluimos o arquivo Defines.mqh, este se encontra também entre aspas duplas. Mas temos algo diferente ali. Pois bem, esta coisa diferente ( ..\ ) está dizendo ao compilador quantos níveis, partindo do diretório onde C_Terminal.mqh se encontra, deveremos subir na estrutura de diretórios, a fim de encontrar o arquivo Defines.mqh. No caso, teremos que subir dois níveis. Isto por que a estrutura de diretórios, contém níveis diferentes, a fim de organizar o código. Desta maneira, o arquivo Defines.mqh estaria no que seria a raiz, dentro da estrutura de diretórios do projeto. Caso a raiz do projeto, venha a mudar, por qualquer motivo, isto não importará para o compilador. Ele sempre procurará o arquivo Defines.mqh exatamente no mesmo ponto.

Este tipo de coisa é muito interessante, principalmente quando você começa a organizar, a sua base de cabeçalhos, de maneira a  ser fácil de encontrar e programar algo. Podendo distribuir facilmente seu código, ou parte dele, sem se preocupar com relação a falta ou não de um arquivo especifico. Toda a base estando organizada e prevendo que o código será distribuído, facilita muito a vida. Agora que já vimos como incluir o arquivo Defines.mqh no sistema. Já podemos fazer uso dele. Você pode aumentar o numero de definições, a fim de tentar tornar tudo mais legível. Mas para o meu proposito, tais definições já são o suficiente. Mas para que você possa de fato compreender, o quanto isto ajuda na questão de tornar o código mais legível, e assim conseguir resolver problemas que podem aparecer. Veja o exemplo abaixo:

if (m_Info.Study == eStudyExecute) ExecuteStudy(memPrice);
if (m_Info.Study identical eStudyExecute) ExecuteStudy(memPrice);
if_case m_Info.Study identical eStudyExecute then ExecuteStudy(memPrice);

Estas 3 linhas querem dizer a mesma coisa e o compilador, irá entender as 3, da mesma forma, criando exatamente o mesmo código. Mas no caso desta linha aqui, o arquivo Defines.mqh, não conseguirá dizer ao compilador o que é para fazer. Neste caso seria necessário adicionar duas novas definições que podem ser vista abaixo:

#define if_case if(
#define then )

Ao adicionar estas duas linhas ao arquivo Defines.mqh, o compilador irá conseguir interpretar de maneira correta as 3 linhas do exemplo. Mas principalmente a linha em destaque. Agora observem que na linha em destaque temos uma linguagem muito parecida com uma linguagem natural. Por ela, entre as 3 linhas mostras, se a mais parecida com a linguagem natural, ela recebe a denominação de como sendo a de mais auto nível entre as 3 linhas. É justamente isto que quero dizer, quando digo que um código é de auto nível ou de nível mais baixo. Notem que para o compilador, nada irá mudar. Mas para um leitor humano, a terceira linha, é muito mais simples de ser entendida, do que as outras duas. Este é um caso simples. Mas vamos ver um caso mais complexo, onde teremos todo o código escrito da forma mostrada. Lembrando que mesmo os código vistos nos artigos anteriores, sofreram este tipo de mudança a fim de torná-los mais legíveis. Isto por hora.

Voltemos ao ponto, onde paramos no artigo anterior. Onde iriamos ver a última função presente na classe C_Mouse.


Função DispatchMessage: Nosso meio de comunicação com o mundo externo

Todas as classes que de alguma forma vierem a receber eventos da plataforma MetaTrader 5, terão em seu portfólio esta função DispatchMessage. Esta servirá como uma forma da classe receber e responder ao eventos gerados. A parte mais importante que você deve de fato entender, é que o MetaTrader 5, é um programa baseado em eventos. Estes são do tipo REAL TIME. Algo bem complicado de trabalhar, diga-se por passagem. Por conta disto, todo e qualquer código deverá sempre ser bem especifico no que tange tratar tais eventos. Mas antes de observar a função DispatchMessage, precisamos ver um outro código. Que irá surgir na classe C_Terminal. Este pode ser visto abaixo:

const double AdjustPrice(const double arg) const { return NormalizeDouble(round(arg / m_Infos.PointPerTick) * m_Infos.PointPerTick, m_Infos.nDigits); }

Tal código poderia ser colocado na classe C_Mouse. Mas por conta de outros fatores decidi colocar ele na classe C_Terminal. Este código, é apenas uma fatoração que visa corrigir o preço, de maneira que ele sempre será o valor esperado pelo servidor de negociação. Não é raro ver ordens sendo rejeitadas pelo servidor, pelo simples fato de que o preço informado estar incorreto. Muitos acabam por desistir em continuar a estudar sobre a possibilidade de criar um Expert Advisor, pelo simples fato de que ao tentar enviar uma ordem para o servidor de negociação, obtém como retorno um erro. Alguns tipos de ativos tem uma fatoração mais simples a fim de ajustar o preço, já outros tem uma fatoração bem mais complexa envolvendo algumas questões. No entanto de uma maneira bastante prática, a função acima consegue lidar com todos este fatores. Fazendo com que o preço sempre seja o adequado, independente do tipo de ativo que esteja sendo usado. Isto é de suma importância para nos aqui, já que para um Expert Advisor a ser criado para ser utilizado em um sistema de replay / simulador, precisamos que independentemente do ativo, o preço seja realmente adequado, ao que seria usado em uma conta DEMO ou mesmo na conta REAL. Desta maneira use e abuse a vontade da função acima. Se fizer isto, você poderá ver como o sistema de fato consegue se adequar, a qualquer tipo de mercado e ativo. Então use e abuse deste conhecimento.

Agora que já vimos a função que irá de fato ajustar o preço conforme a necessidade. Podemos ver finalmente a função DispatchMessage. Esta pode ser vista, na integra, logo abaixo:

virtual void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
   {
      int w equal 0;
      static double memPrice equal 0;
                                
      C_Terminal::DispatchMessage(id, lparam, dparam, sparam);
      switch (id)
      {
         case (CHARTEVENT_CUSTOM + ev_HideMouse):
            ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, clrNONE);
            break;
         case (CHARTEVENT_CUSTOM + ev_ShowMouse):
            ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, m_Info.corLineH);
            break;
         case CHARTEVENT_MOUSE_MOVE:
            ChartXYToTimePrice(GetInfoTerminal().ID, m_Info.Data.Position.X equal (int)lparam, m_Info.Data.Position.Y equal (int)dparam, w, m_Info.Data.Position.dt, m_Info.Data.Position.Price);
            ObjectMove(GetInfoTerminal().ID, def_NameObjectLineH, 0, 0, m_Info.Data.Position.Price equal AdjustPrice(m_Info.Data.Position.Price));
            if (m_Info.Study different eStudyNull) ObjectMove(GetInfoTerminal().ID, def_NameObjectLineV, 0, m_Info.Data.Position.dt, 0);
            m_Info.Data.ButtonStatus equal (uint) sparam;
            if (CheckClick(eClickMiddle) and ((color)ObjectGetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR) different clrNONE)) CreateStudy();
            if (CheckClick(eClickLeft) and (m_Info.Study identical eStudyCreate))
            {
               ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false);
               ObjectMove(GetInfoTerminal().ID, def_NameObjectLineT, 0, m_Info.Data.Position.dt, memPrice equal m_Info.Data.Position.Price);
               m_Info.Study equal eStudyExecute;
            }
            if (m_Info.Study identical eStudyExecute) ExecuteStudy(memPrice);
            break;
         case CHARTEVENT_OBJECT_DELETE:
            if (sparam identical def_NameObjectLineH) CreateLineH();
            break;
      }
   }

Agora pare por um instante, e olhe para este código, e diga sinceramente: Você consegue entender tudo que está se passando nele ?!?! Muito provavelmente sim, grande parte do que se passa no código acima, de fato dá para compreender, mesmo não tendo muita experiência em programação, apenas observando o código. Mas por que disto ?!?! Como é possível entender um código, sem de fato ter grande conhecimento em programação ?!?! O fato é que se você compreender como programar em uma linguagem, de maneira que seu código comece a se tornar uma linguagem próxima da natural, o entendimento do código passa a ser simplificado. Desta forma, mesmo pessoas que não compreendem a programação, conseguirão entender o que está sendo programado ali. De fato, grande parte do que esta acontecendo ali, é simples de entender. Tão simples, que se quer precisarei de fato detalhar em uma explicação. Mas mesmo assim, vamos dar uma rápida passada pelas linhas. Vamos começar dessecando o código a partir da declaração das variáveis.

int w equal 0;
static double memPrice equal 0;

Apesar de esta sendo declarado desta forma. Você deve ler o código da mesma forma como ele esta escrito. Mas para o compilador, este mesmo código, será visto da seguinte maneira:

int w = 0;
static double memPrice = 0;

Veja que não existe diferença alguma. Mas com toda a certeza em ambos casos qualquer pessoa iria conseguir entender o código. Mas no primeiro caso teremos o formado literal da coisa. Calma estamos apenas começando, e este exemplo acima não condiz totalmente, com o que podemos fazer para deixar o código mais legível.

Vamos ver um outro fragmento. Este já não tem muito haver com o fato de ser legível ou não. Mas precisa ser explicado, mesmo assim.

case (CHARTEVENT_CUSTOM + ev_HideMouse):
   ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, clrNONE);
   break;

Em alguns momentos precisamos que a linha de preço seja ocultada no gráfico. Quem acompanhou o sistema de ordens mostrado na sequencia sobre como desenvolver um Expert Advisor do zero, viu em alguns momentos a linha de preço era ocultada. Naquele código em especifico, isto era feito por meio de uma chamada, a um determinado procedimento, que fazia com que a linha fosse ocultada. Mas agora iremos usar uma mensagem que será enviada a esta classe C_Mouse, para que a linha de preço seja ocultada. Esta decisão de usar uma mensagem no lugar de usar um procedimento se deve ao fato de que desejo construir um sistema bem mais modular e de fácil portabilidade entre outras coisas. Por conta disto temos também uma outra mensagem que também passa pelo mesmo clivo e esta é mostrada abaixo:

case (CHARTEVENT_CUSTOM + ev_ShowMouse):
   ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, m_Info.corLineH);
   break;

Por enquanto não se preocupe em como de fato usar estas mensagens. Isto será explicado em outro momento. Mas de uma forma bem simples, você pode compreender elas pensando que na verdade, ambas mensagens vistas acima seriam de fato procedimentos ou funções que deveriam ocorrer. Mas no lugar de adicionar um procedimento publico ou uma função somente para isto, iremos concentrar toda a coisa em um único ponto central. Este é a rotina de tratamento de mensagens. Somente em casos especiais e específicos é que usarei outro método.

Estes eventos acima são frutos de uma chamada especial que depois irei mostrar com mais calma como proceder. Isto para quem não sabe de fato como fazer, e acredito que muitos não fazem ideia.  Mas não são eventos disparados pela plataforma MetaTrader 5. Estes são eventos disparados pelo nosso código, em momentos bem específicos, visando executar algum tipo de coisa. Mas temos também que tratar eventos vindos da plataforma MetaTrader 5. Estes são tratados da seguinte maneira:

C_Terminal::DispatchMessage(id, lparam, dparam, sparam);

Esta linha acima, que pode ser vista no código da função DispatchMessage na classe C_Mouse, irá repassar as chamadas para a classe C_Terminal, a fim de não precisamos fazer isto dentro de outro código. Isto evita esquecimentos durante a programação. Assim vamos padronizando de alguma forma o código, de maneira que ele seja mais rápido de ser programado, analisado, construído e corrigido. Mas nem todos os eventos serão de fato tratados na classe C_Terminal. Alguns poderão e irão ser tratados localmente, isto é dentro da classe que estamos trabalhando. Um exemplo disto é o evento visto abaixo:

case CHARTEVENT_OBJECT_DELETE:
   if (sparam identical def_NameObjectLineH) CreateLineH();
   break;

Este evento, cujo código visto acima é um código voltado para o leitor, e acredito que o mesmo consiga de fato entender o que esta sendo analisado, é de fato visto pelo compilador da seguinte maneira:

case CHARTEVENT_OBJECT_DELETE:
   if (sparam == def_NameObjectLineH) CreateLineH();
   break;

Independentemente da forma como o código esta sendo apresentado, o resultado é que quando um objeto é removido do gráfico do ativo, uma mensagens, ou melhor um evento, é disparado pela plataforma. De maneira que ela irá informa ao programa que solicitou tal tipo de mensagem, que um objeto foi removido do gráfico. Ao encontrar o tratador CHARTEVENT_OBJECT_DELETE o programa irá executar o código presente ali. Se o nome do objeto que estará sendo informado na variável constante sparam, for o mesmo que estamos indicado no teste, o código que será executado, recriando a linha de preço.

Agora temos um evento que é o CHARTEVENT_MOUSE_MOVE que é um pouco mais extenso. Mas mesmo assim ainda que seja mais extenso, não é de todo complicado. Você pode, mesmo sem saber programação, compreender grande parte do código mostrado abaixo. Apenas tentando ler, literalmente, cada uma das linha. Tente fazer isto e me diga se é mais fácil ou complicado de entender, o que esta sendo feito. Não importa se você não consiga entender todo o código, a ideia é que você tente entender a maior parcela possível de código. Isto sem se esforçar.

case CHARTEVENT_MOUSE_MOVE:
   ChartXYToTimePrice(GetInfoTerminal().ID, m_Info.Data.Position.X equal (int)lparam, m_Info.Data.Position.Y equal (int)dparam, w, m_Info.Data.Position.dt, m_Info.Data.Position.Price);
   ObjectMove(GetInfoTerminal().ID, def_NameObjectLineH, 0, 0, m_Info.Data.Position.Price equal AdjustPrice(m_Info.Data.Position.Price));
   if (m_Info.Study different eStudyNull) ObjectMove(GetInfoTerminal().ID, def_NameObjectLineV, 0, m_Info.Data.Position.dt, 0);
   m_Info.Data.ButtonStatus equal (uint) sparam;
   if (CheckClick(eClickMiddle) and ((color)ObjectGetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR) different clrNONE)) CreateStudy();
   if (CheckClick(eClickLeft) and (m_Info.Study identical eStudyCreate))
   {
      ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false);
      ObjectMove(GetInfoTerminal().ID, def_NameObjectLineT, 0, m_Info.Data.Position.dt, memPrice equal m_Info.Data.Position.Price);
      m_Info.Study equal eStudyExecute;
   }
   if (m_Info.Study identical eStudyExecute) ExecuteStudy(memPrice);
   break;

Com exceção dos pontos onde fazemos chamada a procedimentos da linguagem MQL5. Acredito que você consegui ler todo o código, e entendeu alguns pontos com bastante facilidade como este que estão sendo apontados:

  • Se m_Info.Study é diferente de eStudyNull então algo deverá ser feito.
  • m_Info.Data.ButtonStatus é igual a sparam.
  • Caso tenha clicado com o botão do meio e alguma coisa ( cor da linha de preço ) é diferente de clrNONE então faça isto.
  • Caso tenha clicado com o botão esquerdo e m_Info.Study é igual a eStudyCreate então será feito isto.
  • Torne m_Info.Study igual a eStudyExecute.
  • Se m_Info.Study é igual a eStudyExecute então faça isto.

Veja que mesmo lendo os pontos indicados, como acabei de demonstrar, ainda assim notasse que podemos adicionar ainda mais coisas ao nosso arquivo Defines.mqh, a fim de que a linguagem fique ainda mais legível, do que estou demonstrando. Isto se deve ao fato de que podemos  adicionar mais coisas a ponto de tornar um programa extremamente mais legível. Isto é uma qualidade de uma boa linguagem de programação, e que estará sempre presente em programas de boa qualidade técnica. A outra forma de tornar o código bastante legível, é sempre adicionar comentários as funções ou pontos mais importantes. E isto o MQL5, supera e muito o C / C++. Experimente colocar comentários nas variáveis e procedimentos. Ao usar o MetaEditor o mesmo irá lhe mostrar tais comentários como sendo uma dica. Isto ajuda muito.

E como seria de fato programado o código acima. Ou melhor, como o compilador de fato o vê o código acima ? Isto é mostrado logo abaixo:

case CHARTEVENT_MOUSE_MOVE:
   ChartXYToTimePrice(GetInfoTerminal().ID, m_Info.Data.Position.X = (int)lparam, m_Info.Data.Position.Y = (int)dparam, w, m_Info.Data.Position.dt, m_Info.Data.Position.Price);
   ObjectMove(GetInfoTerminal().ID, def_NameObjectLineH, 0, 0, m_Info.Data.Position.Price = AdjustPrice(m_Info.Data.Position.Price));
   if (m_Info.Study != eStudyNull) ObjectMove(GetInfoTerminal().ID, def_NameObjectLineV, 0, m_Info.Data.Position.dt, 0);
   m_Info.Data.ButtonStatus = (uint) sparam;
   if (CheckClick(eClickMiddle) && ((color)ObjectGetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR) != clrNONE)) CreateStudy();
   if (CheckClick(eClickLeft) && (m_Info.Study == eStudyCreate))
   {
      ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false);
      ObjectMove(GetInfoTerminal().ID, def_NameObjectLineT, 0, m_Info.Data.Position.dt, memPrice = m_Info.Data.Position.Price);
      m_Info.Study = eStudyExecute;
   }
   if (m_Info.Study == eStudyExecute) ExecuteStudy(memPrice);
   break;

Ambos os códigos fazem exatamente a mesma coisa. Então irei explicar neste o que estamos fazendo para quem não tem total conhecimento sobre as funções presentes na linguagem MQL5. A primeira coisa que fazemos é converter as coordenadas gráficas informadas pela plataforma em coordenadas de preço e tempo. Assim podemos saber onde o ponteiro do mouse está, em relação ao gráfico. Depois ajustamos o preço para que ele fique correto, frente ao que é esperado pelo servidor de negociação. Da mesma forma, podemos posicionar alinha de preço no local correto do gráfico. Caso estejamos fazendo um estudo temos que mover a linha do tempo de maneira correta. Armazenamos o status dos botões relacionados ao mouse, e verificamos se ocorreu um clique do botão do meio a fim de fazer um estudo. Mas o estudo somente se dará se a linha de preço estiver visível no gráfico. Assim que o botão esquerdo for pressionado, o estudo irá ser iniciado. Por isto precisamos dizer a plataforma para não mover o gráfico, de maneira que podemos arrastar o mouse com o botão esquerdo pressionado e sem problemas. E enquanto o botão se mantiver pressionado, o estudo estará de fato acontecendo. Usando todos os objetos que desejamos e queremos colocar no gráfico.

E antes de terminar o artigo. Vamos dar uma rápida olhada no código do Exepert Advisor, neste atual ponto de desenvolvimento. Este pode ser completamente visto abaixo:

#property copyright "Daniel Jose"
#property description "Generic EA for use on Demo account, replay system/simulator and Real account."
#property description "This system has means of sending orders using the mouse and keyboard combination."
#property description "For more information see the article about the system."
#property version   "1.28"
#property link "https://www.mql5.com/en/articles/11349"
//+------------------------------------------------------------------+
#include <Market Replay\System EA\Auxiliar\C_Mouse.mqh>
//+------------------------------------------------------------------+
input group "Mouse";
input color     user00 equal clrBlack;          //Price Line
input color     user01 equal clrDarkGreen;      //Positive Study
input color     user02 equal clrMaroon;         //Negative Study
//+------------------------------------------------------------------+
C_Mouse *mouse;
//+------------------------------------------------------------------+
int OnInit()
{
   mouse equal new C_Mouse(user00, user01, user02);
                
   return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   delete mouse;
}
//+------------------------------------------------------------------+
void OnTick() {}
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   (*mouse).DispatchMessage(id, lparam, dparam, sparam);
   ChartRedraw();
}
//+------------------------------------------------------------------+

Notem que é um código super simples. Então não irei entrar em detalhes, explicando nenhum ponto neste atual momento. Já que não é de fato necessário entrar em nenhum tipo de explicação.


Conclusão

A partir de agora, você pode ver como o sistema está funcionando com o Expert Advisor incluso no sistema. É verdade que este Expert Advisor, somente conta com o mouse. Mas você já poderá usar o mesmo não apenas no sistema de replay / simulador. Também poderá usa-lo em contas DEMO ou conta REAL. Apesar de ele ainda, não ter grande serventia nestes casos, será algo bastante interessante ver um Expert Advisor que pode ser usado em todo e qualquer tipo de mercado ou ativo, ou situação.

Um outro detalhe, é que no código em anexo, você terá estas duas últimas classes ( C_Terminal e C_Mouse ) utilizando o conteúdo do arquivo Defines.mqh. Assim você pode verificar como tornar o seu código mais legível. No entanto diferente do que falei no inicio do artigo, onde dei a entender que todo o código irá utilizar tal formatação, isto daqui foi apenas como curiosidade. Se bem que se você desejar, pode de fato fazer uso deste tipo de técnica. No começo como programador C/C++, usei isto durante um tempo a fim de conseguir compreender toda aquela sintaxe da linguagem. Por conta disto, sei que no inicio é bastante confuso, mas com o tempo você acaba se acostumando com ela. Mas se você precisa criar algum tipo de projeto ou programa que seja muito complicado, de ser feito rapidamente, usando a sintaxe da linguagem ( por você não ter tanta experiência assim ), é uma boa, usar a técnica que mostrei aqui. Ela agiliza muito, principalmente quando o programa precisa trabalhar muito em cima de analise e combinações lógicas e booleanas. Já que neste ponto, o fato de existir símbolos duplos, costuma complicar bastante os iniciantes. Um exemplo disto é o seguinte fato:

Quem nunca, mesmo programadores experientes, confundiu o uso de uma operação de E LÓGICO ( & ) com um E BOOLEANO ( && ) ? Notem que praticamente se parecem muito. Mas o primeiro faz a operação Bit a Bit, enquanto o segundo faz a operação analisando toda a variável e retornando verdadeiro ou falso. Isto pega muita gente em momentos que precisamos criar programas de forma bem rápida.

Por este motivo, não menospreze o devido conhecimento de algumas técnicas. Mesmo quando elas parecem ser banais, elas ajudam muito na questão de tornar o programa mais legível e assim mais rápido de ser construído. Mas de uma maneira bem interessante, acredito ter mostrado a todos como fazer as coisas, de forma muito mais rápida e ao mesmo tempo, garantindo que o código saia sempre correto. Não precisando ficar ali esquentando a cabeça, tentando entender por que uma parte está ou não dando certo.


Arquivos anexados |
Files_-_BOLSA.zip (1358.24 KB)
Files_-_FOREX.zip (3743.96 KB)
Files_-_FUTUROS.zip (11397.51 KB)
Domine e utilize o testador de estratégias MQL5 de forma eficiente Domine e utilize o testador de estratégias MQL5 de forma eficiente
Os desenvolvedores MQL5 devem dominar diversas ferramentas essenciais. Entre elas, destaca-se o testador de estratégias. Este artigo serve como um guia prático para a utilização do testador de estratégias MQL5.
Como criar um indicador personalizado True Strength Index usando MQL5 Como criar um indicador personalizado True Strength Index usando MQL5
Apresento um novo artigo sobre como criar um indicador personalizado. Desta vez, trabalharemos com o True Strength Index (TSI) e criaremos um Expert Advisor com base nele.
Redes neurais de maneira fácil (Parte 44): Explorando habilidades de forma dinâmica Redes neurais de maneira fácil (Parte 44): Explorando habilidades de forma dinâmica
No artigo anterior, apresentamos o método DIAYN, que oferece um algoritmo para aprender uma variedade de habilidades. O uso das habilidades adquiridas pode ser usado para diversas tarefas. Mas essas habilidades podem ser bastante imprevisíveis, o que pode dificultar seu uso. Neste artigo, veremos um algoritmo para ensinar habilidades previsíveis.
Desenvolvendo um sistema de Replay (Parte 27): Projeto Expert Advisor — Classe C_Mouse (I) Desenvolvendo um sistema de Replay (Parte 27): Projeto Expert Advisor — Classe C_Mouse (I)
Neste artigo irá nascer a classe C_Mouse. Esta foi pensada de maneira que a programação, seja feita no mais alto nível quanto for possível ser feita. Mas dizer que trabalharemos em alto, ou baixo nível, nada tem haver com questões de colocarmos palavrões ou chavões no meio do código. Longe disto. Trabalhar em alto nível ou de baixo nível, quando se fala em programação, diz o quanto o programa pode ser mais simples ou mais difícil de ser lido por outro programador.