English Русский Español
preview
Desenvolvendo um sistema de Replay (Parte 33): Sistema de Ordens (II)

Desenvolvendo um sistema de Replay (Parte 33): Sistema de Ordens (II)

MetaTrader 5Exemplos | 31 outubro 2023, 12:53
268 0
Daniel Jose
Daniel Jose

Introdução

No artigo anterior, Desenvolvendo um sistema de Replay - Simulação de mercado ( Parte 32 ) - Sistema de Ordens ( I ), começamos a desenvolver o sistema de ordens a ser usando dentro de um Expert Advisor. Lá desenvolvemos a classe base do sistema, com apenas e somente as rotinas, que de fato precisamos inicialmente.

Você pode achar, e isto não estará de fato errado, de que aquelas rotinas são em essência, muito básicas e não irá cobrir totalmente o sistema de ordens. Isto de fato é verdade, mas neste primeiro momento iremos desenvolver um sistema, não para ser usado diretamente no serviço de replay / simulador. Iremos desenvolver, primeiramente e é essencial que você entenda isto, um sistema que consiga ser operado junto ao servidor de negociação real, seja usando uma conta demo, seja usando uma conta real. Vamos fazer uso massivo e extensivo da plataforma MetaTrader 5, para nos fornecer todo o suporte do qual precisaremos neste inicio de jornada. É extremamente importante, que o sistema primeiro funcione quando a plataforma esta se comunicando com o servidor. Pois quando estiver apenas usando o replay / simulador, não poderemos ficar adequando o sistema do Expert Advisor ao nosso replay/simulador. Deveremos sim, fazer com que o replay / simulador, se adeque ao que é feito pelo Expert Advisor. Por isto precisamos que o Expert Advisor funcione primeiramente no servidor real.

O fato de ter tomado esta decisão, faz com que o sistema, e consequentemente a classe C_Orders, tenha um numero diminuto de procedimentos e funções. Isto pensando em um sistema mais amplo. Mas não se engane, imaginando que a classe C_Orders, não será capaz de suprir as nossas necessidades neste momento. Teremos de fazer com que a plataforma MetaTrader 5, nos dê o máximo de suporte do qual precisamos, para poder operar junto ao servidor de negociação. Esta questão de fazer o MetaTrader 5, nos dar o máximo de suporte, é justamente para evitar criar coisas sem necessidade. Não devemos tentar recriar a roda. A plataforma tem que ser explorada ao seu nível máximo, para que precisemos fazer o mínimo de esforço, quando formos tratar com o sistema de replay / simulação.

Mas antes de continuar a falar do sistema de ordens, gostaria de mostrar como solucionar um problema. Se bem que não se trata de um problema. Mas apenas de um inconveniente presente no MetaTrader 5.


Tentando deixar as coisas mais simples

Quem é usuário assíduo do MetaTrader 5, deve ter notado, ou no mínimo esbarrado, em uma questão que por um lado é bastante chata, e por outro é no mínimo desanimador. E o que estou dizendo, é mais notado por parte de pessoas que migram de outras plataformas para o MetaTrader 5, e ao se deparar com o funcionamento do mesmo, fica chateado, ou desmotivado a usar ele em alguns momentos. Principalmente os envolvendo estudos de gráfico.

A questão, e esta acredito que muitos devam ficar bastante descontentes. É o fato de que quando fazemos um estudo, ou algum tipo de anotação no gráfico de um ativo. Somos impedidos, normalmente, depois de reiniciar a plataforma, de modificar, ou remover tais objetos usados nos estudos. Isto de maneira simples. Pois existem algumas coisas das quais é preciso saber configurar no MetaTrader 5, para de fato saber como lidar com as coisas nele. Mas vamos supor, que você acabou de instalar a plataforma no seu computador, e nunca mexeu com ela. Então este será o seu primeiro contato com a mesma. E quero ressaltar este detalhe: Esta será a primeira vez que você irá mexer no MetaTrader 5.

Aqui mora uma questão curiosa. Apesar de podermos acessar os objetos antigos, dando um duplo clique neles, isto desde que eles não estejam com a flag ( caixa de check box, vista na figura 01 ) marcada como Desativar seleção. Poderemos de fato acessar o objeto.

Figura 01

Figura 01 - Check box ativada.

Mas independentemente disto, a questão não é bem esta. A questão é que muitos usuários, ao migrarem de outras plataformas, tem o costume de dar apenas, e somente um clique no objeto. E este passa a ser selecionado, podendo ser modificado, ou removido do gráfico. O fato do MetaTrader 5, exigir um duplo clique, não é de todo obvio, sendo preciso ter uma certa familiaridade, ou no mínimo uma certa dose de curiosidade, para com a plataforma a fim de saber como proceder nestes casos.

Agora vem um detalhe. No MetaTrader 5, existe uma opção, que permite mudar este comportamento. Para ter acesso a ela, você deverá pressionar a combinação CTRL + O. Isto abrirá a janela de opção do MetaTrader 5. Nesta janela você deve ir na aba Gráficos e marcar a opção : Selecionar objetos com um clique do mouse. Se isto for feito, você poderá fazer uso do MetaTrader 5, da mesma forma que faria em qualquer outra plataforma. Mas ainda assim, teria que fazer este pequeno ajuste, e mesmo assim ainda não teria algumas possibilidades. E esta será a intensão aqui. Mostrar como fazer isto de outra forma, mas com novas possibilidades.

Como programador, me vejo em uma situação, no qual posso de alguma forma, fazer com que um usuário, que esta migrando para o MetaTrader 5, tenha uma experiência adequada e agradável ao usar a plataforma. E fazer com que tenhamos que dar apenas um único clique é algo bastante adequado. Porém cuja programação não parece assim tão obvia, a ponto de vermos códigos mostrando como fazer tal coisa. Isto talvez pelo fato de muitos acharem desnecessário tal trabalho. Mas lembre-se de que podemos ampliar as possibilidades da coisa toda.

Mas para resolver esta questão, voltaremos a classe C_Terminal, e adicionaremos algumas poucas linhas de código no sistema. Isto já será o suficiente, para promover uma experiência bem mais agradável por parte de novos usuários. Vejamos então o que deverá ser de fato adicionado ao código. Isto pode ser apreciado no código abaixo:

virtual void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
   {
      static string st_str = "";
                                
      switch (id)
      {
         case CHARTEVENT_CHART_CHANGE:
            m_Infos.Width  = (int)ChartGetInteger(m_Infos.ID, CHART_WIDTH_IN_PIXELS);
            m_Infos.Height = (int)ChartGetInteger(m_Infos.ID, CHART_HEIGHT_IN_PIXELS);
            break;
         case CHARTEVENT_OBJECT_CLICK:
            if (st_str != sparam) ObjectSetInteger(m_Infos.ID, st_str, OBJPROP_SELECTED, false);
            if (ObjectGetInteger(m_Infos.ID, sparam, OBJPROP_SELECTABLE) == true)
            ObjectSetInteger(m_Infos.ID, st_str = sparam, OBJPROP_SELECTED, true);
            break;
         case CHARTEVENT_OBJECT_CREATE:
            if (st_str != sparam) ObjectSetInteger(m_Infos.ID, st_str, OBJPROP_SELECTED, false);
            st_str = sparam;
            break;
      }
   }

Este procedimento acima, já faz parte do código original da classe C_Terminal. Mas aqui foram adicionados algumas poucas linhas extras, onde iremos tratar de dois novos eventos. Estes serão informados ao nos, pela plataforma MetaTrader 5. Existe um detalhe, neste código acima. Mas posso explicar o código e depois explicar o detalhe. Observem que declaramos uma variável local estática, esta serve para armazenar o nome do objeto que estará recebendo o foco. Esta variável se inicia como sendo uma string vazia. Isto é importante para que consigamos fazer as coisas sem falhas. Assim que um objeto no gráfico, recebe um clique, o nome do objeto é repassado ao nosso programa. Assim como o evento, que no caso é informado pela plataforma como sendo um CHARTEVENT_OBJECT_CLICK, e o nome do objeto estará na variável sparam. Estes pequenos detalhes irão nos ajudar na próxima etapa. Agora verificamos se o nome presente na nossa variável local, é o mesmo que esta sendo informado pelo MetaTrader 5. No caso da primeira execução, eles serão diferentes. Caso eles sejam iguais nada irá de fato acontecer. Mas se forem diferentes, o objeto que estava sobre o foco da plataforma, irá perder o foco, e isto é feito nesta linha, onde testamos e se necessário removemos o foco do objeto.

Agora quero que prestem atenção ao seguinte fato: Quando um objeto, tem as suas propriedades modificadas, a fim de ficar como mostrado na figura 01. Devemos entender que o usuário, está de forma consciente, dizendo que aquele objeto não deverá receber atenção de maneira inadvertida. Seja por conta de que o objeto não deverá ser modificado, seja por conta que ele indicará algo, e não queremos mudar ele de posição, ou mudar algo do tipo. De qualquer forma, ao marcar o check box conforme mostrado na figura 01, devemos entender que o objeto deverá ser ignorado. E é justamente isto que este teste faz. Ele estará verificando se o objeto deve ou não ser ignorado. Se este teste não fosse feito, a marcação que o usuário teria feito na propriedade do objeto, segundo a figura 01, seria ignorada e o objeto seria acessado, recebendo o foco. Então a forma de fazer com que o objeto receba o foco, é fazendo uso exatamente deste código. Notem que neste código, estaremos armazenando o nome do objeto para que quando ele tiver que perder o foco, o nosso programa, saiba qual era o objeto. Algo bastante parecido acontece quando o MetaTrader 5, dispara o evento CHARTEVENT_OBJECT_CREATE. Mas aqui existe um detalhe. Diferente do evento CHARTEVENT_OBJECT_CLICK, este evento de criação de objeto somente será disparado para o nosso programa. Se dissermos ao MetaTrader 5, que desejamos saber quando um objeto é criado, tal evento será disparado.

Nota: De qualquer forma o MetaTrader 5, sempre irá disparar os eventos. Mas alguns somente serão direcionados para o nosso código, se informamos isto a plataforma.

Para dizer ao MetaTrader 5, que queremos receber notificações, quando um objeto for criado no gráfico, procedemos de uma maneira bastante próxima, do que fazemos quando queremos ser notificados quando um objeto é removido. Assim é necessário adicionar a seguinte linha de código:

C_Terminal()
   {
      m_Infos.ID = ChartID();
      CurrentSymbol();
      m_Mem.Show_Descr = ChartGetInteger(m_Infos.ID, CHART_SHOW_OBJECT_DESCR);
      m_Mem.Show_Date  = ChartGetInteger(m_Infos.ID, CHART_SHOW_DATE_SCALE);
      ChartSetInteger(m_Infos.ID, CHART_SHOW_OBJECT_DESCR, false);
      ChartSetInteger(m_Infos.ID, CHART_EVENT_OBJECT_DELETE, 0, true);
      ChartSetInteger(m_Infos.ID, CHART_EVENT_OBJECT_CREATE, 0, true);
      ChartSetInteger(m_Infos.ID, CHART_SHOW_DATE_SCALE, false);
      m_Infos.nDigits = (int) SymbolInfoInteger(m_Infos.szSymbol, SYMBOL_DIGITS);
      m_Infos.Width   = (int)ChartGetInteger(m_Infos.ID, CHART_WIDTH_IN_PIXELS);
      m_Infos.Height  = (int)ChartGetInteger(m_Infos.ID, CHART_HEIGHT_IN_PIXELS);
      m_Infos.PointPerTick  = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_TRADE_TICK_SIZE);
      m_Infos.ValuePerPoint = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_TRADE_TICK_VALUE);
      m_Infos.VolumeMinimal = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_VOLUME_STEP);
      m_Infos.AdjustToTrade = m_Infos.ValuePerPoint / m_Infos.PointPerTick;
      m_Infos.ChartMode     = (ENUM_SYMBOL_CHART_MODE) SymbolInfoInteger(m_Infos.szSymbol, SYMBOL_CHART_MODE);
      ResetLastError();
   }

Esta linha informa ao MetaTrader 5, que a partir deste momento, queremos ser notificados quando um novo objeto for criado no gráfico. Igualmente, precisamos informar ao MetaTrader 5, quando não queremos mais ser notificados, e isto é feito usando o seguinte código:

~C_Terminal()
   {
      ChartSetInteger(m_Infos.ID, CHART_SHOW_DATE_SCALE, m_Mem.Show_Date);
      ChartSetInteger(m_Infos.ID, CHART_SHOW_OBJECT_DESCR, m_Mem.Show_Descr);
      ChartSetInteger(m_Infos.ID, CHART_EVENT_OBJECT_DELETE, 0, false);
      ChartSetInteger(m_Infos.ID, CHART_EVENT_OBJECT_CREATE, 0, false);
   }

No momento que esta linha for executada, o MetaTrader 5, não mais irá notificar o nosso código, sobre eventos de criação de objetos. Este tipo de coisa, é bastante importante e interessante, pois pode ser que você queira saber quando o usuário adiciona ou remove objetos do gráfico. E tentar fazer isto " na unha " é algo bastante complicado e difícil de ser feito. Mas tendo auxilio do MetaTrader 5, fica bastante simples fazer isto. Acredito que você tenha notado, que podemos de fato, subjugar a plataforma a fim de fazer com que ela aja segundo o que esperamos. Este tipo de comportamento, e o fato de poder fazer isto, faz com que possamos ajudar novos usuários a terem uma melhor experiência no uso da plataforma, o que é bastante motivador. É tudo uma questão de adaptação, mas esta será mais rápida se você como programador, poder ajudar quem não é programador.

Legal, mas vamos voltar ao que viemos de fato fazer aqui neste artigo. Pois ainda temos muitas coisas a serem feitas, antes que possamos de fato mexer em outra coisa.


Ampliando o sistema de ordens

O titulo deste tópico, talvez seja um pouco de exagero. Mas quero trazer para este nosso sistema de ordens, algo que foi mostrado em uma outra serie de artigos. Assim você poderá utilizar os mesmos conceitos e conhecimentos que foram expostos lá. A serie em questão teve o seu último artigo, até este momento, que pode ser acessado neste link: Aprendendo a construindo um Expert Advisor que opera de forma automática ( Parte 15 ) - Automação ( VII ). Lá demonstrei como você faz para tornar um Expert Advisor que foi construído e operado de maneira manual, em um Expert Advisor automático. O fato de trazer este assunto neste momento, é devido ao fato de que pode ser interessante, para você observar o Expert Advisor trabalhando em um replay / simulador, a fim de poder fazer algum tipo de ajuste nele. Lembrado que para testar e verificar a produtividade do Expert Advisor, a plataforma MetaTrader 5, conta com o testador de estratégias que serve muito bem ao seu proposito. Aqui não estou criando algo paralelo ao testador. A ideia aqui é que você possa praticar alguma técnica, mesmo quando o mercado estiver fechado.

Então vamos trazer os conceitos e ideias que foram vista na serie sobre o Expert Advisor automático para cá. E para fazer isto, iremos começar trazendo a classe de controle de tempo.

Um detalhe importante: Nesta primeira fase, onde iremos usar o Expert Advisor, e desenvolver ele, fazendo com que o mesmo, seja voltado a nos dar acesso mais simples ao servidor de negociação. Darei uma rápida pincelada nas funções que importaremos daquela serie de artigos. Para que você tenha mais detalhes, e uma explicação mais aprofundada, veja a serie que de certa forma irá lhe ajudar bastante em algumas questões.


Controlando o tempo com C_ControlOfTime

Esta classe C_ControlOfTime, é uma classe bastante curiosa. Apesar de ter um código bastante compacto, ela nos permite, de uma forma bastante simples, fazer com que o Expert Advisor, tenha algum nível de gerenciamento, baseados no horário no qual podemos operar. Muitos operadores costumam ficar bastante ansiosos nos primeiros movimentos do mercado. Entrando ou finalizando de maneira prematura posições. O fato de tomarmos decisões baseadas em emoção, em um tipo de atividade onde a emoção não é bem o que precisamos. Faz com que muitas vezes tomemos prejuízo, quando na verdade, ao seguirmos um plano operacional não teríamos de fato se quer operado naquele momento. Uma das maneira mais simples de promover este controle é por meio do horário. Já que durante a sequencia sobre o Expert Advisor automático, mostrei como implementar tal dispositivo. Vamos trazer ele para este Expert Advisor daqui. Ao fazer isto, teremos o mesmo tipo de comportamento visto lá. O que é muito bom, pois ninguém quer de fato operar fora de uma faixa de horário, que ele considere adequada e um pouco mais seguro de operar no mercado. Então que tão fazer com que o Expert Advisor nos ajude nisto ?!?!

Bem, a classe C_ControlOfTime, começa da seguinte forma. Vista abaixo:

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#include "C_Orders.mqh"
//+------------------------------------------------------------------+
class C_ControlOfTime : protected C_Orders
{
   private :
      struct st_00
      {
         datetime Init,
                  End;
      }m_InfoCtrl[SATURDAY + 1];
//+------------------------------------------------------------------+

Aqui iremos armazenar em uma matriz, o horário permitido para as operações. Isto voltado dia a dia. Talvez a parte mais curiosa deste código, de fato é o uso da definição SATURDAY. De fato, para quem não viu a serie do Expert Advisor automático, vou dar uma rápida explicação aqui, do que significa usar esta definição. Quando usamos esta definição, estamos dizendo que nossa matriz irá cobrir os dias da semana. Mas existe um detalhe nesta história, que é o fato de precisarmos adicionar uma unidade ao valor. Isto para que a matriz tenha o comprimento adequado, já que ela começa no ZERO. No entanto, não podemos ter uma matriz com zero elementos. Temos sempre que começar com um valor maior que zero. Por isto somamos uma unidade. Caso isto não fosse feito, teríamos uma matriz de 6 elementos ao invés de 7 como seria de fato esperado. Um outro detalhe é que você pode notar que a classe C_ControlOfTime, está herdando a classe C_Orders. Desta forma, estaremos ampliando as capacidades da classe C_Orders. Mas esta ampliação não será de fato levada ao Expert Advisor, como você irá perceber ao longo das explicações que serão dadas. O motivo pode ser melhor compreendido na sequencia de artigos, sobre o Expert Advisor automático.

Continuando, a próxima coisa a ser vista no código, é o constructor da classe. Este pode ser visto logo abaixo:

C_ControlOfTime(C_Terminal *arg, const ulong magic)
                :C_Orders(arg, magic)
   {
      for (ENUM_DAY_OF_WEEK c0 = SUNDAY; c0 <= SATURDAY; c0++) ZeroMemory(m_InfoCtrl[c0]);
   }

Aqui temos duas coisas bastante simples de serem compreendidas. A primeira, é o fato de estamos inicializado a classe C_Orders, antes mesmo de qualquer código do constructor C_ControlOfTime, se de fato executado. A segunda e talvez bem curiosa, é a presença de um laço. Mas a questão curiosa não é o laço em si. Mas sim a forma como ele trabalha. Observem que estamos usando uma enumeração neste laço, e que ela começa no SUNDAY, e a variável será incrementada até o SATURDAY. Mas pode isto ?!?! Sim, podemos fazer isto. Mas temos que tomar alguns cuidados. Basicamente, o principal cuidado, é que SUNDAY deve ter um valor menor que SATURDAY. Se isto não for um fato, teremos problemas ao executar o acesso aos dados da matriz. Felizmente, a enumeração começa no SUNDAY e vai progredido, dia a dia, até o SATURDAY. Nos dando assim os dias da semana.

A principal vantagem, em se usar tal modo de programação, é que isto eleva o nível de nosso código. Permitindo que a linguagem MQL5 venha a ter uma aparência bem próxima da linguagem natural. Este tipo de coisa foi bastante explorada e explicada na sequencia de artigos sobre o Expert Advisor automático. Além é claro de eu ter dado uma palhinha aqui nesta sequencia também. Veja os artigos anteriores e você irá encontrar como tornar o código ainda mais legível. Este tipo de coisa faz com que o seu código passe a ser compreendido mesmo por aqueles com pouco conhecimento em programação. Lembre-se: Você não programa para a máquina, você programa para outros programadores.

Muito bem, agora vamos dar uma rápida passada em outros dois procedimentos. Começando com o que pode ser visto logo a seguir:

virtual void SetInfoCtrl(const ENUM_DAY_OF_WEEK index, const string szArg) final
   {
      string szRes[], sz1[];
      bool bLocal;
                                
      if (_LastError != ERR_SUCCESS) return;
      if ((index > SATURDAY) || (index < SUNDAY)) return;
      if (bLocal = (StringSplit(szArg, '-', szRes) == 2))
      {
         m_InfoCtrl[index].Init = (StringToTime(szRes[0]) % 86400);
         m_InfoCtrl[index].End = (StringToTime(szRes[1]) % 86400);
         bLocal = (m_InfoCtrl[index].Init <= m_InfoCtrl[index].End);
         for (char c0 = 0; (c0 <= 1) && (bLocal); c0++)
            if (bLocal = (StringSplit(szRes[0], ':', sz1) == 2))
               bLocal = (StringToInteger(sz1[0]) <= 23) && (StringToInteger(sz1[1]) <= 59);
         if (_LastError == ERR_WRONG_STRING_DATE) ResetLastError();
      }
      if ((_LastError != ERR_SUCCESS) || (!bLocal))
      {
         Print("Error in the declaration of the time of day: ", EnumToString(index));
         ExpertRemove();
      }
   }

Este procedimento acima, foi explicado e dissecado no artigo  Aprendendo a construindo um Expert Advisor que opera de forma automática ( Parte 10 ) - Automação ( II ), onde expliquei detalhadamente como ele funciona, de maneira que se você deseja mais detalhes sobre o mesmo. Caso não esteja compreendendo o código, dê uma olhada neste artigo mencionado, pois irá de fato valer bastante a pena. Já o próximo procedimento, que é visto abaixo, que também foi explicado no mesmo artigo. De fato, todo o trabalho feito aqui na classe C_ControlOfTime, pode ser visto e compreendido no artigo mencionado acima. A única diferença foi feita no constructor. Mas isto se deve ao que iremos fazer depois.

virtual const bool CtrlTimeIsPassed(void) final
   {
      datetime dt;
      MqlDateTime mdt;
                                
      TimeCurrent(mdt);
      dt = (mdt.hour * 3600) + (mdt.min * 60);
      return ((m_InfoCtrl[mdt.day_of_week].Init <= dt) && (m_InfoCtrl[mdt.day_of_week].End >= dt));
   }

Com isto explicado, e caso você tenha visto o artigo mencionado, irá perceber que o Expert Advisor irá receber alguns parâmetros extras, a fim de que o usuário possa configurar esta classe C_ControlOfTime. Mas precisamos levar isto para um nova classe. Assim como foi feito na sequencia sobre o Expert Advisor automático, usaremos uma classe intermediária. E este é tema para o próximo tópico.


C_Manager: A classe sindico.

C_Manager, de fato é uma classe bem interessante, já que ela irá fazer com que grande parte da complexidade envolvida no código do Expert Advisor, fique isolada do mesmo. Ou seja, no Expert Advisor teremos apenas algumas poucas linhas de código, e tudo será gerenciado e manipulado pelas classes. Diferente do código que pode ser visto na sequencia do Expert Advisor automático. Aqui vamos começar com algo um pouco mais básico, mas nem por isto menos interessante de ser visto e explicado. A grande questão aqui, é que o Expert Advisor não irá de fato funcionar em todos os tipos de cenários. Inicialmente focaremos, em fazer com que o Expert Advisor trabalhe de maneira o mais segura quanto for possível fazer. Já que precisaremos depois, fazer com que ele consiga trabalhar, também no sistema de replay / simulação. E esta é a parte complicada do sistema.

Para evitar que a coisa fique extremamente complexa, vamos fazer com que o Expert Advisor trabalhe primeiro, com todo e qualquer auxilio que a plataforma MetaTrader 5 possa nos oferecer. E isto faz com que o sistema de ordens, não seja de fato tão amplo assim. Não podendo ser usado por exemplo em um modo CrossOrder, ou seja, você não poderá usar o sistema de ordens, neste primeiro momento, a fim de enviar ordens usando um ativo diferente daquele onde o Expert Advisor estiver executando. O indicaria que estariamos fazendo uso do sistema CrossOrder.

Mas vamos ver o código desta classe C_Manager, no atual estágio de desenvolvimento. O código começa com as seguintes linhas:

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#include "C_ControlOfTime.mqh"
#include "..\System EA\Auxiliar\Study\C_Study.mqh"
//+------------------------------------------------------------------+
#define def_Prefix "Manager"
#define def_LINE_PRICE  def_Prefix + "_PRICE"
#define def_LINE_TAKE   def_Prefix + "_TAKE"
#define def_LINE_STOP   def_Prefix + "_STOP"
//+------------------------------------------------------------------+
#define def_AcessTerminal       (*Terminal)
#define def_InfoTerminal        def_AcessTerminal.GetInfoTerminal()
#define def_AcessMouse          (*Study)
#define def_InfoMouse           def_AcessMouse.GetInfoMouse()
//+------------------------------------------------------------------+

Aqui temos a declaração de algumas definições, a fim de facilitar a nossa codificação posterior. Muito provavelmente estas definições irão sofrer algum tipo de mudança futura, dado o fato do sistema ser bastante complexo.

Mas vamos ver como a classe se inicia. Podemos ver isto observando o seguinte fragmento:

class C_Manager : public C_ControlOfTime
{
   private :
      struct st00
      {
         double  FinanceStop,
                 FinanceTake;
         uint    Leverage;
         bool    IsDayTrade,
                 AccountHedging;                                         
      }m_Infos;
      struct st01
      {
         color   corPrice,
                 corTake,
                 corStop;
         bool    bCreate;
      }m_Objects;             
//+------------------------------------------------------------------+
      C_Terminal *Terminal;
      C_Study    *Study;

Aqui temos a declaração das variáveis globais privativas da classe. Para melhor organização usei, e dividi as coisas em termos de estruturas, desta maneira ficará mais simples modificar e remover partes do código depois. Com toda a certeza isto irá acontecer no decorrer dos próximos artigos. Por hora vamos tentar fazer o sistema funcionar na sua forma mais simples, e utilizando ao máximo o auxilio do MetaTrader 5. Estou repetindo isto, pois você não deve tomar este sistema como sendo definitivo. Ele ainda está sendo projetado.

Vamos ver o primeiro procedimento presente na classe C_Manager. Este podendo ser visto no código imediatamente abaixo:

bool CreateOrder(const ENUM_ORDER_TYPE type, const double Price)
   {
      ulong tmp;
                                
      if (!CtrlTimeIsPassed()) return false;
      tmp = C_Orders::CreateOrder(type, Price, m_Infos.FinanceStop, m_Infos.FinanceTake, m_Infos.Leverage, m_Infos.IsDayTrade);
                                
      return tmp > 0;
   }

O que este procedimento faz é lançar uma ordem pendente para o servidor de negociação. Mas atenção, a ordem somente será enviada, caso o sistema de controle de tempo habilite o envio. Se isto não for possível, devido ao fato de estarmos fora da janela permitida de tempo, a ordem não será enviada. Observem o fato de que precisamos apenas informar o preço onde a ordem será colocada. Se estaremos efetuando compra ou venda, todo o restante é preenchido conforme indicado por variáveis globais, dentro da classe.

A próxima rotina que temos, e esta também é uma rotina privativa da classe, é vista a seguir:

bool ToMarket(const ENUM_ORDER_TYPE type)
   {
      ulong tmp;
                                
      if (!CtrlTimeIsPassed()) return false;
      tmp = C_Orders::ToMarket(type, m_Infos.FinanceStop, m_Infos.FinanceTake, m_Infos.Leverage, m_Infos.IsDayTrade);
                                
      return tmp > 0;
   }

Já aqui, estamos enviando um pedido de execução a mercado, no melhor preço disponível. Neste caso tudo que precisamos informar, é se estaremos comprando ou vendendo. Todo o restante é preenchido com base, nas informações das variáveis globais da classe. Mas você pode estar pensando: Como posso inicializar estas variáveis globais ?!?! Será que isto será feito dentro do código do Expert Advisor ??? A resposta é um sonoro : NÃO. As variáveis globais presentes na classe, não devem de forma alguma serem acessadas, sem o devido cuidado e conhecimento da classe, a qual elas pertencem.

Para inicializar tais variáveis, contamos com alguns meios e recursos. No momento, usaremos o método mais simples de todos. O constructor. Fazer uso do constructor para inicializar as variáveis da classe, é sem dúvida o melhor caminho de todos. Mas depois mudaremos isto, por questões de praticidade. Por hora isto dará conta do recado e fará o que precisamos que seja feito. Então o código do constructor pode ser visto logo abaixo:

C_Manager(C_Terminal *arg1, C_Study *arg2, color cPrice, color cStop, color cTake, const ulong magic, const double FinanceStop, const double FinanceTake, uint Leverage, bool IsDayTrade)
          :C_ControlOfTime(arg1, magic)
   {
      string szInfo = "HEDGING";
                                
      Terminal = arg1;
      Study = arg2;
      if (CheckPointer(Terminal) == POINTER_INVALID) SetUserError(C_Terminal::ERR_PointerInvalid);
      if (CheckPointer(Study) == POINTER_INVALID) SetUserError(C_Terminal::ERR_PointerInvalid);
      if (_LastError != ERR_SUCCESS) return;
      m_Infos.FinanceStop     = FinanceStop;
      m_Infos.FinanceTake     = FinanceTake;
      m_Infos.Leverage        = Leverage;
      m_Infos.IsDayTrade      = IsDayTrade;
      m_Infos.AccountHedging  = false;
      m_Objects.corPrice      = cPrice;
      m_Objects.corStop       = cStop;
      m_Objects.corTake       = cTake;
      m_Objects.bCreate       = false;
      switch ((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE))
      {
         case ACCOUNT_MARGIN_MODE_RETAIL_HEDGING: m_Infos.AccountHedging = true; break;
         case ACCOUNT_MARGIN_MODE_RETAIL_NETTING: szInfo = "NETTING";            break;
         case ACCOUNT_MARGIN_MODE_EXCHANGE      : szInfo = "EXCHANGE";           break;
      }
      Print("Detected Account ", szInfo);
   }

Apesar de parecer ser longo, este código na verdade é super simples, dado o fato de que estaremos basicamente inicializando, todas as variáveis globais presentes na classe. Toda esta inicialização, é de fato dada com base nos parâmetros informados pelo código do Expert Advisor. Mas não ficamos apenas nisto, aproveitamos o fato de estamos inicializado o sistema, e verificamos qual o tipo de conta na qual o Expert Advisor esta sendo executado. Isto será importante depois, por hora, isto nos serve apenas como informação de analise, de forma que o usuário saiba qual o tipo de conta utilizada. Isto é informado na caixa de ferramentas, da plataforma MetaTrader 5. Usando a mensagem criada nesta linha.

Temos também um destructor, este pode ser visto abaixo:

~C_Manager()
   {
      ObjectsDeleteAll(def_InfoTerminal.ID, def_Prefix);
   }

E apesar deste código conter esta linha, a mesma dificilmente irá fazer alguma coisa. Mas não podemos simplesmente esperar que tudo aconteça sem problemas. Então se algum problema ocorrer, este destructor irá remover os objetos que esta classe estará criando.


Conclusão

Você pode ter notado que o conhecimento é reutilizável. Não criamos de fato algo do nada. Estamos sempre reutilizando e aperfeiçoando as coisa. Por conta disto as mesmas vão melhorando com o tempo. Mas ainda falta um procedimento para ser explicado na classe C_Manager. Isto no atual estágio de desenvolvimento que ela se encontra, assim como o código do Expert Advisor. Mas para dar uma explicação mais adequada, e principalmente não deixar este artigo daqui, longo e cansativo de ser lido e compreendido. Deixarei para falar sobre o procedimento e o código do Expert Advisor, no próximo artigo.

E como ainda não foi totalmente explicado o código. E não desejo que você venha a utilizar algo sem de fato saber do que se trata. Neste artigo, não haverá nenhum código em anexo. Lamento, mas não acho correto fazer diferente.


Arquivos anexados |
Anexo.zip (130.63 KB)
Teoria das Categorias em MQL5 (Parte 11): Grafos Teoria das Categorias em MQL5 (Parte 11): Grafos
Esse artigo é uma continuação da série sobre como implementar a teoria das categorias no MQL5. Aqui consideramos como a teoria dos grafos pode ser integrada com monoides e outras estruturas de dados ao desenvolver uma estratégia para fechar um sistema de negociação.
Desenvolvendo um sistema de Replay (Parte 32): Sistema de Ordens (I) Desenvolvendo um sistema de Replay (Parte 32): Sistema de Ordens (I)
De todas as coisas desenvolvidas até aqui. Esta com toda a certeza, vocês também irão notar, e com o tempo irão concordar, que é a mais desafiadora de todas. O que temos de fazer é algo simples. Fazer com que o nosso sistema, simule o que um servidor de negociação efetua na prática. Isto de ter que implementar uma forma de simular, exatamente o que seria feito, pelo servidor de negociação, parece simples. Pelo menos nas palavras. Mas precisamos fazer isto de uma maneira, que para o usuário do sistema de replay / simulação, tudo venha a acontecer, de forma o mais invisível, ou transparente, possível.
Teoria das Categorias em MQL5 (Parte 12): Ordem Teoria das Categorias em MQL5 (Parte 12): Ordem
Este artigo faz parte de uma série sobre a implementação de grafos usando a teoria das categorias no MQL5 e é dedicado à teoria da ordem (Order Theory). Consideraremos dois tipos básicos de ordenação e exploraremos como os conceitos de relação de ordem podem auxiliar os conjuntos monoidais na tomada de decisões de negociação.
Desenvolvendo um sistema de Replay (Parte 31): Projeto Expert Advisor - Classe C_Mouse (V) Desenvolvendo um sistema de Replay (Parte 31): Projeto Expert Advisor - Classe C_Mouse (V)
Desenvolver uma forma de colocar o cronometro, de modo que durante um replay / simulação, ele consiga nos dizer quanto tempo falta, pode parecer a principio uma tarefa simples e de rápida solução. Muitos iriam simplesmente tentar adaptar e usar o mesmo sistema que é usado quando temos o servidor de negociação ao nosso lado. Mas aqui mora um ponto que muitos talvez não se atentem ao pensar em tal solução. Quando você está fazendo um replay, e isto para não falar do fato da simulação, o relógio não funciona da mesma forma. Este tipo de coisa torna complexo construir tal sistema.