
Simulação de mercado (Parte 04): Iniciando a classe C_Orders (I)
Introdução
No artigo anterior Simulação de mercado (Parte 82): Uma questão de performance, fizemos alguns ajustes nas classes, a fim de contornar, pelo menos por hora, alguns problemas que estávamos experimentando. Tais problemas, estavam degradando a performance geral do sistema. Apesar de termos resolvido, por hora, tais questões, temos agora algo realmente bastante complicado de ser feito. Não nesta primeira parte, pois já abordei o assunto que será tratado aqui em outros artigos, mais antigos. Porém, agora estamos fazendo as coisas de uma forma um pouco diferente. Por conta disto, a maneira como também iremos e deveremos lidar com a questão, também será um pouco diferente.
Sei que muitos devem estar bastante ansiosos para ver a aplicação de replay/simulador, finalmente executando ordens. Porém, antes de realmente fazer isto, precisamos garantir que o sistema de ordens esteja realmente funcionando. Isto no que diz respeito a podermos nos comunicar com o servidor de negociação real. Seja por meio de uma conta DEMO, seja por meio de uma conta REAL. De qualquer forma, as aplicações, que no caso serão o indicador Chart Trade, indicador de Mouse e o Expert Advisor. Deverão trabalhar na mais perfeita harmonia, de maneira que a comunicação como o servidor real de negociação, esteja ocorrendo sem grandes propensos.
Além destas aplicações que mencionei acima, ainda será preciso criar outras coisas. No entanto, tais coisas podem ser deixadas de lado por enquanto. Visto que a sua criação, seja a fase se idealização, seja na fase de implementação. Dependem de diversas outras coisas, que serão de fato resolvidas nesta parte do desenvolvimento.
Então neste artigo começarei a explicar como faremos para nos comunicar com o servidor de negociação. Sei que muitos de vocês, já devem saber como fazer isto perfeitamente bem. Neste caso, peço para que tenham um pouco de paciência. Pois não faremos as coisas de forma muito rápida. Visto que é necessário que você entenda e compreenda perfeitamente, o que está acontecendo de fato. Pois diferente do que normalmente muitos programam, aqui a coisa será feita em módulos. E cada um deles é responsável por executar uma tarefa bem específica. Se um modulo falhar, todo o sistema irá de fato falhar. Isto por que não existe nenhuma redundância que garanta, que as coisas funcionarão de outra forma.
Compreendendo a ideia
Se você vem acompanhando de fato esta sequência, deve ter notado que no artigo Desenvolvendo um sistema de Replay (Parte 78): Um novo Chart Trade (V), onde comecei a mostrar como a interação será dada. Deve ter notado que o Expert Advisor de fato não sabe de onde está vindo os pedidos. Porém, este mesmo Expert Advisor, sabe como interpretar as mensagens que estão sendo recebidas. Apesar de aqueles meios utilizados, não permitirem fazer uso de um sistema de ordens cruzadas. Resolvemos este mesmo problema nos artigos que vieram logo depois. Sendo que no Simulação de mercado (Parte 02): Cross Order (II) mostrei como de fato ficaria o sistema de mensagens a ser repassado para o Expert Advisor.
Todo este mecanismo, faz parte de algo ainda maior. Então entender este mecanismo de mensagens, é de fato primordial para entender o que começaremos a ver deste artigo em diante. Não subestime ou ignore o foi explicado nos artigos passados. Mas principalmente não ache que você já entendeu, de fato as coisas antes de as ver em funcionamento.
Se você entendeu, o código do Expert Advisor, que foi mostrado anteriormente. Acredito que não terá muitas dificuldades em entender o que será programado aqui. Mas novamente, não ache que você já sabe das coisas apenas olhando o código. É preciso realmente entender como cada um dos detalhes funcionam, para de fato ter uma visão mais geral de todo o sistema.
Iniciando as ordens de mercado
Já que existem várias coisas, a serem explicadas, no código que você verá um pouco mais abaixo no artigo. Não vou mostrar toda a classe, assim logo de cara. Da mesma forma, não vou despejar uma quantidade muito grande de código no artigo. Esta parte realmente precisa ser muito bem compreendida. Isto por que, o código que será visto, irá de fato mexer com dinheiro. E é com o seu dinheiro, caro leitor. Então entender como cada detalhe funciona, permitirá que você se sinta mais seguro e confiante com o código que será apresentado. Não quero que você tente mudar o código, apenas por que não o está entendendo. Quero que, caso você venha a modificar o código, o faça por que precisa adicionar alguma funcionalidade, que não está presente nele. E não por que, está acostumando a usar este ou aquele tipo de código. Então procure entender o código, pois este mesmo código será usado, quando formos fazer a simulação de ordens.
Para facilitar ao máximo a explicação, vamos começar fazendo o seguinte: Vamos ver a classe inicial, que será responsável pelo envio das ordens para o servidor. Seja ele o servidor real, que trataremos agora. Seja ele o servidor simulado, que será visto no futuro. De qualquer maneira, o código se inicia como mostrado abaixo. Este primeiro código visto está na íntegra.
001. //+------------------------------------------------------------------+ 002. #property copyright "Daniel Jose" 003. //+------------------------------------------------------------------+ 004. #include "..\Defines.mqh" 005. //+------------------------------------------------------------------+ 006. class C_Orders 007. { 008. protected: 009. //+------------------------------------------------------------------+ 010. inline const ulong GetMagicNumber(void) const {return m_MagicNumber;} 011. //+------------------------------------------------------------------+ 012. private : 013. //+------------------------------------------------------------------+ 014. MqlTradeRequest m_TradeRequest; 015. ulong m_MagicNumber; 016. bool m_bTrash; 017. //+------------------------------------------------------------------+ 018. struct stChartTrade 019. { 020. struct stEvent 021. { 022. EnumEvents ev; 023. string szSymbol, 024. szContract; 025. bool IsDayTrade; 026. ushort Leverange; 027. double PointsTake, 028. PointsStop; 029. }Data; 030. //--- 031. bool Decode(const EnumEvents ev, const string sparam) 032. { 033. string Res[]; 034. 035. if (StringSplit(sparam, '?', Res) != 7) return false; 036. stEvent loc = {(EnumEvents) StringToInteger(Res[0]), Res[1], Res[2], (bool)(Res[3] == "D"), (ushort) StringToInteger(Res[4]), StringToDouble(Res[5]), StringToDouble(Res[6])}; 037. if ((ev == loc.ev) && (loc.szSymbol == _Symbol)) Data = loc; 038. 039. return true; 040. } 041. //--- 042. }m_ChartTrade; 043. //+------------------------------------------------------------------+ 044. ulong SendToPhysicalServer(void) 045. { 046. MqlTradeCheckResult TradeCheck; 047. MqlTradeResult TradeResult; 048. 049. ZeroMemory(TradeCheck); 050. ZeroMemory(TradeResult); 051. if (!OrderCheck(m_TradeRequest, TradeCheck)) 052. { 053. PrintFormat("Order System - Check Error: %d", GetLastError()); 054. return 0; 055. } 056. m_bTrash = OrderSend(m_TradeRequest, TradeResult); 057. if (TradeResult.retcode != TRADE_RETCODE_DONE) 058. { 059. PrintFormat("Order System - Send Error: %d", TradeResult.retcode); 060. return 0; 061. }; 062. 063. return TradeResult.order; 064. } 065. //+------------------------------------------------------------------+ 066. ulong ToMarket(const ENUM_ORDER_TYPE type) 067. { 068. double price = SymbolInfoDouble(m_ChartTrade.Data.szContract, (type == ORDER_TYPE_BUY ? SYMBOL_ASK : SYMBOL_BID)); 069. double vol = SymbolInfoDouble(m_ChartTrade.Data.szContract, SYMBOL_VOLUME_STEP); 070. uchar nDigit = (uchar)SymbolInfoInteger(m_ChartTrade.Data.szContract, SYMBOL_DIGITS); 071. 072. ZeroMemory(m_TradeRequest); 073. m_TradeRequest.magic = m_MagicNumber; 074. m_TradeRequest.symbol = m_ChartTrade.Data.szContract; 075. m_TradeRequest.price = NormalizeDouble(price, nDigit); 076. m_TradeRequest.action = TRADE_ACTION_DEAL; 077. m_TradeRequest.sl = NormalizeDouble(m_ChartTrade.Data.PointsStop == 0 ? 0 : price + (m_ChartTrade.Data.PointsStop * (type == ORDER_TYPE_BUY ? -1 : 1)), nDigit); 078. m_TradeRequest.tp = NormalizeDouble(m_ChartTrade.Data.PointsTake == 0 ? 0 : price + (m_ChartTrade.Data.PointsTake * (type == ORDER_TYPE_BUY ? 1 : -1)), nDigit); 079. m_TradeRequest.volume = NormalizeDouble(vol + (vol * (m_ChartTrade.Data.Leverange - 1)), nDigit); 080. m_TradeRequest.type = type; 081. m_TradeRequest.type_time = (m_ChartTrade.Data.IsDayTrade ? ORDER_TIME_DAY : ORDER_TIME_GTC); 082. m_TradeRequest.stoplimit = 0; 083. m_TradeRequest.expiration = 0; 084. m_TradeRequest.type_filling = ORDER_FILLING_RETURN; 085. m_TradeRequest.deviation = 1000; 086. m_TradeRequest.comment = "Order Generated by Experts Advisor."; 087. 088. MqlTradeRequest TradeRequest[1]; 089. 090. TradeRequest[0] = m_TradeRequest; 091. ArrayPrint(TradeRequest); 092. 093. return (((type == ORDER_TYPE_BUY) || (type == ORDER_TYPE_SELL)) ? SendToPhysicalServer() : 0); 094. }; 095. //+------------------------------------------------------------------+ 096. public : 097. //+------------------------------------------------------------------+ 098. C_Orders(const ulong magic) 099. :m_MagicNumber(magic) 100. { 101. } 102. //+------------------------------------------------------------------+ 103. void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) 104. { 105. switch (id) 106. { 107. case CHARTEVENT_CUSTOM + evChartTradeBuy : 108. case CHARTEVENT_CUSTOM + evChartTradeSell : 109. case CHARTEVENT_CUSTOM + evChartTradeCloseAll: 110. if (m_ChartTrade.Decode((EnumEvents)(id - CHARTEVENT_CUSTOM), sparam)) switch (m_ChartTrade.Data.ev) 111. { 112. case evChartTradeBuy: 113. ToMarket(ORDER_TYPE_BUY); 114. break; 115. case evChartTradeSell: 116. ToMarket(ORDER_TYPE_SELL); 117. break; 118. case evChartTradeCloseAll: 119. break; 120. } 121. break; 122. } 123. } 124. //+------------------------------------------------------------------+ 125. }; 126. //+------------------------------------------------------------------+
Código fonte do arquivo C_Orders.mqh
Muito bem, então vamos entender o que este código realmente faz. Apesar de parecer complicado, ele é bem simples, e somente faz uma única coisa: Ele envia ordens de compra ou venda a mercado, a pedido da interação entre o usuário e o indicador Chart Trade. Mas como ele consegue fazer isto? Você provavelmente deve estar pensando, que iremos de alguma forma, modificar o indicador Chart Trade. Mas se pensou isto, você não compreendeu de fato como o sistema funciona. Indicadores não nos permite, de fato, enviar ordens para o servidor de negociação. Indicadores servem para indicar algo no gráfico. Ou no caso do indicador Chart Trade, permitir interações do usuário com o restante do sistema.
Então antes de apresentar o Expert Advisor, que de fato fará uso deste arquivo de cabeçalho. Vamos voltar um pouco no tempo, e relembrar o que já foi explicado. Assim ficará mais simples entender este arquivo de cabeçalho.
Quando no artigo Desenvolvendo um sistema de Replay (Parte 78): Um novo Chart Trade (V), foi explicado as mensagens que o Expert Advisor deveria interceptar. Você deve ter notado, que fazíamos uso do procedimento OnChartEvent, a fim de capturar tais mensagens. Dentro deste procedimento, efetuávamos uma chamada a uma classe. Está de fato, fazia a tradução da mensagem recebida e assim imprimia no terminal uma mensagem para que pudéssemos analisar. Ok, esta era a parte fácil e tranquila. Já que ali, não precisávamos usar aqueles dados a fim de nos comunicar com o servidor de negociação.
Quando o código fonte do Expert Advisor, for visto. Você notará que lá no procedimento OnChartEvent, existe uma chamada para DispatchMessage. Tal chamada irá de fato cair neste arquivo de cabeçalho. Para ser mais preciso, ela chamará a linha 103 deste arquivo. Mas antes de ver isto, vamos começar do início. Ou seja, vamos ver o constructor da classe.
Este é bastante simples e está presente na linha 98. Quando este constructor é chamado, ele deverá receber um argumento. Tal argumento irá de fato, ser utilizado para identificar esta classe com um número mágico. Atenção a este detalhe: Não estou identificando o Expert Advisor, estou identificando a classe. Apesar de a mesma ser utilizada dentro do Expert Advisor, eu não estou identificando o Expert Advisor. Mas por que desta distinção? O motivo, é que as vezes, e é bom que você entenda isto. As vezes se torna interessante usar classes parecidas, porém diferentes para fazer o mesmo tipo de coisa. Neste momento, isto não faz sentido. Mas fará conforme a explicação for sendo dada. Já que esta classe daqui, não faz uso de determinadas coisas, como será visto depois.
Então vamos supor o seguinte fato. Uma vez que não exista mais ordens e somente posições. Você pode desejar que elas sejam tratadas de uma forma especifica. Fazer isto usando diversos Expert Advisores diferentes é algo muito sujeito a erros. Além é claro de não ser possível, manter mais de um Expert Advisor no mesmos gráfico. Não estou dizendo, que você não pode usar, mais de um Expert Advisor no mesmo ativo. Estou dizendo que você não pode usar mais de um no mesmo gráfico. Não confunda as coisas.
Porém, ao abrir vários gráficos, do mesmo ativo, apenas para colocar Expert Advisores diferentes, em cada um, ao meu ver não é algo muito controlável. Algumas pessoas conseguem administrar isto, mas eu acho muito confuso. Porém, colocar classes levemente diferentes, dentro de um mesmo Expert Advisor, de maneira que elas trabalhem em harmonia. Para mim, é algo perfeitamente administrável e possível de ser controlado. Para poder fazer isto de maneira mais simples, no momento que o constructor criar a classe, a mesma será identificada por um número mágico. Este mesmo número será utilizado depois nas ordens e posições. Mas isto será visto depois.
Este número é inicializado na linha 99, e a variável que o armazena está declarada na linha 15. Observe que na linha 12 existe uma cláusula privativa, que faz com que tudo que estiver entre esta linha 12 e a linha 96, fique encapsulado dentro da classe. Inclusive as variáveis que estamos declarando entre as linhas 14 e 16.
Antes de prosseguirmos, quero chamar a sua atenção para a linha 10. Aqui temos uma função que tem como objetivo, retornar ao chamador o número mágico definido nesta classe. Porém, o fato desta linha está entre a linha 8, onde temos uma cláusula protegida e a linha 12 que temos a cláusula privativa. Faz com que esta função não possa ser usada fora do sistema de herança. Ou seja, se você tentar acessar esta função, que é protegida, fora de uma classe que herde esta classe C_Orders, você irá de fato receber uma mensagem de erro do compilador.
Então sendo assim, esta função se encontra aqui, por motivos futuros. Não quero precisar colocar ela depois, apenas para cobrir uma tarefa que faço uso pessoal. Talvez eu venha a mostrar, no futuro, do que se trata. Mas até lá, você não precisa se preocupar com isto. Apenas saiba que esta função na linha 10, não pode ser acessada fora do sistema de herança, e que ela serve apenas para retornar o número mágico desta classe.
Agora para explicar de forma mais clara, o restante deste código. Vamos dividir o mesmo em tópicos. Porém, cada um dos tópicos fará referência a este mesmo código.
Um procedimento dentro de uma estrutura?
No artigo Desenvolvendo um sistema de Replay (Parte 78): Um novo Chart Trade (V), quando mostrei o sistema de tradução, fiz isto usando uma classe. Porém, aqui estou usando algo um pouco diferente. Estou usando uma estrutura. Mas podemos fazer isto? Sim. E estou fazendo isto. Já que classes nada mais são, do que uma estrutura mais elaborada. Porém, como o que precisamos pode ser modelado de uma forma mais simples. Decidi fazer isto dentro de uma estrutura. Você pode observar isto entre as linhas 18 e 42.
Agora preste atenção: Na linha 18, estou declarando a estrutura. Mas se no lugar dela estivesse declarando uma classe. Tudo entre as linhas 18 e 42 seria tratado de forma privativa. Neste caso seria necessário, que fosse adicionado uma clausula publica para modificar no tipo de acesso. Isto não é um problema. Mas pense no seguinte: Por que alguém criaria uma classe dentro de outra? Não faz sentido. Além de muitas das vezes deixar o código muito mais confuso.
Porém, como os dados que precisamos, está sendo recebidos oriundos de uma mensagem. E tal mensagem pode ser vista como um conjunto de variáveis, como foi explicado no artigo que mencionei no início deste tópico. Por que não pensar na mensagem como uma grande cadeia de variáveis? Desta forma seria bem mais simples entender o seu conteúdo. Não é mesmo.
Desta maneira a mensagem é vista como uma estrutura de dados. E tal estrutura está entre a linhas 20 e 29. Mas espere um pouco. A estrutura de dados não seria das linhas 18 a 42? NÃO. A estrutura da mensagem está entre as linhas 20 e 29. Porém, como foi explicado em um artigo passado, a mensagem deve ser pensada como uma string. Mas se você pegar esta string e a recortar se baseando no comprimento da estrutura dos dados da mensagem. Correrá um imenso risco de não entender a mensagem. Sendo assim precisamos de algum código extra, a fim de nos ajudar a compreender a mensagem.
Por conta disto, entre as linhas 31 e 40, temos uma função. Esta está dentro da estrutura principal, mas não faz parte da estrutura da mensagem. Por que? O motivo é a separação das coisas. Nas impede de você colocar tudo junto. Tanto a estrutura da mensagem, quanto as funções e procedimentos. Porém, quando colocamos tudo junto, corremos um risco de implementação.
Agora quero que você preste, muita, mas muita atenção, pois isto é bastante confuso. Porém se você entender isto, conseguirá entender por que muitos programadores evitam usar estruturas, quando poderiam fazer este tipo de coisa. E quando alguns programadores tentam fazer uso de estruturas, acabam tornando seus programas uma bomba relógio. Principalmente quando o código é feito em C legado.
Observe a linha 36. Esta linha é que é o real perigo de você misturar as coisas. Novamente, não existe uma obrigação, que faz você as separar. Porém a linha 36 deixa isto claro. Pois esta linha está escrevendo na estrutura de dados, todos os valores que desejamos. Agora se no lugar da estrutura de dados tivéssemos por exemplo, uma função ou procedimento. O que aconteceria quando a linha 36 fosse executada? E pior. O que de fato aconteceria quando você chamasse a função ou procedimento, que está na memória e que foi sobrescrita pela linha 36? Se você não faz ideia do que pode acontecer. Sinta-se feliz por ainda não ter visto, o verdadeiro problema e perigo da linguagem C legado. Mas se você sabe, ou já viu isto acontecer, sabe e entende por que as classes foram criadas.
Não irei de fato detalhar o que pode acontecer. Mas saiba que um programador realmente malicioso, pode fazer coisas que você não acredita ser possível ser feito. Porém vamos voltar a explicação do nosso código. A função presente na linha 31 faz exatamente o que era feito anteriormente. Então sendo assim não vejo necessidade de explicar novamente a mesma. Porém, observe na linha 110, onde fazemos a chamada desta função. Note que ali, na linha 110, não estamos chamando diretamente a função pelo seu nome. Precisamos usar uma referência extra. Esta referência é justamente o nome da variável que contém os dados que representam nossa estrutura de dados. Parece confuso, mas não é. Esqueça por um momento que estamos usando uma estrutura, e pense nisto como se fosse uma classe. Você não faria as coisas da mesma forma? Pois então não existe de fato uma confusão aqui.
Porém, muitos podem imaginar que DECODE, deveria ser uma função da classe C_Orders. Assim não necessitaríamos chamada da forma como está sendo feito na linha 110. No entanto, esta função DECODE, somente existe, por que precisamos decodificar a mensagem que contém os nossos dados. Por isto não faz sentido, a declarar dentro da classe C_Orders. Novamente, pense sempre em separar as coisas de forma lógica, e não de forma que lhe seja mais conveniente. Se DECODE fosse declarada dentro da classe C_Orders, quando no futuro, fosse desejado usar um procedimento com um nome parecido. Porém voltado para uma outra estrutura de dados, você teria que criar um nome totalmente diferente, a fim de evitar conflitos. E pior, depois de um tempo quando você fosse, modificar o código, teria dificuldades em entender o que faz o que. Assim as possibilidades de erro acabariam crescendo de forma descontrolada.
Conversando com o servidor
Esta parte é a que costuma mais ser confusa para novos programadores. Mas isto é devido ao fato, que se se esta parte lhe parece confusa, é devido a um mal entendimento do que você de fato deve fazer. Diferente de um operador, que olha o gráfico e vê ali preços e cotações. Você como programador, deve ver as coisas como se fosse uma ficha a ser preenchida de maneira adequada. Se esta ficha estiver com algum erro, o servidor que você deverá pensar como se fosse a pessoa que estará lhe contratando, não aceitará a ficha.
O servidor, não tem obrigação, assim como alguém para quem você deseja trabalhar, de entender o que está na ficha. Ele simplesmente olha ela e se não for do agrado dele, ela será descartada. Diferente de um empregador, o servidor irá lhe dizer o motivo da recusa. Por isto um procedimento de comunicação, bem elaborado, irá com toda a certeza, lhe permitir resolver facilmente os problemas.
Para fazer isto, temos a função que se encontra entre as linhas 44 e 64. Apesar de sua imensa simplicidade. Esta função contém tudo que precisamos para saber o que aconteceu. Observe que aqui existe uma sequência lógica de passos a serem seguidos. Você não pode fazer as coisas na ordem que lhe der na telha. Você tem que fazer as coisas na seguinte ordem: Primeiro, deverá zerar o conteúdo da memória dos dados de resposta do servidor. Isto é feito nas linhas 49 e 50. Logo depois, para evitar enviar um pedido e o mesmo não ser aceito por um motivo banal. Testamos se o pedido tem algum problema. Seria como se você fizesse a revisão da ficha que será enviada ao empregador. Esta revisão é feita na linha 51. Caso aconteça uma falha, o código de erro irá indicar qual foi a falha, e assim você poderá resolver ela, e tentar novamente. Caso tudo pareça perfeitamente adequado, na linha 56 enviamos o nosso pedido para o servidor de negociação.
Para evitar, de o compilador ficar nos alertando, que não estamos verificando o retorno do servidor. Enviamos o retorno para uma variável que será basicamente uma lixeira. O motivo disto, é que não nos importa a resposta da função. O que nos importa de fato, é o que a estrutura de resposta contém. Para checar isto, na linha 57, verificamos se o resultado é diferente do valor TRADE_RETCODE_DONE. Caso este seja o caso, significa que algum tipo de erro aconteceu. Então para saber qual foi o erro, imprimimos no terminal o valor do erro. Isto é feito na linha 59.
De qualquer forma, se um erro aconteceu, esta função da linha 44, retornará um valor igual a zero. Para todos os outros casos, ela retornará o valor do ticket de resposta do servidor. E este ticket é o que identifica da nossa ordem ou posição no servidor. Mas isto será visto depois, quando formos manipular tais posições ou ordens. Aqui, estamos apenas começando, então a única coisa que fazemos é enviar um pedido de negociação a mercado.
Este tipo de pedido, é feito em um outro ponto, ou melhor dizendo, em uma outra função. Esta é vista na linha 66. Esta função irá de fato receber apenas e somente um único argumento. Tal argumento diz se estaremos comprando ou vendendo. Ela é chamada em dois pontos. O primeiro é a linha 113 e o segundo a linha 116. Tais pontos são acessados quando uma mensagem vinda do Chart Trade, diz para fazermos algo a mercado. Mas se esta função da linha 66 recebe apenas um argumento, que diz se estaremos comprando ou vendendo. Como o servidor irá de fato saber onde estará o nosso stop loss ou nosso take profit. E as demais informações com o nível de alavancagem e o ativo, no caso de estamos usando um sistema de ordens cruzadas. Como estas informações serão passadas? Legal. Agora chegamos em um ponto interessante.
Preenchendo a ficha do requerimento
Se você observou a função de comunicação com o servidor. Que está presente na linha 44. Deve ter notado que tanto na linha 51, quanto na linha 56. Fazemos uso de uma estrutura que não está declarada naquela função. Tal estrutura de fato está declarada no corpo da classe C_Orders. Isto na linha 14. Então esta é uma estrutura global, porém privativa a classe. Ou seja, todo o corpo da classe pode acessar esta variável. Porém nenhum código fora da classe pode acessar a mesma.
Assim sendo, esta variável que é usada na função 44, deve ser preenchida em algum lugar. O lugar em questão é este daqui. Entre as linhas 66 e 94. O correto preenchimento da estrutura que esta variável representa. Irá de fato permitir que o servidor consiga executar exatamente o que esperamos. Ou seja, uma venda a mercado, ou uma compra a mercado. As ordens pendentes serão vistas depois. Assim como a forma correta de modificar os pontos de take profit e stop loss de uma posição.
Para preencher corretamente a estrutura, precisamos de alguns dados. Alguns destes dados são fornecidos pelo Chart Trade, outros são fornecidos pelo MetaTrader 5. De qualquer forma, aqui também temos uma certa sequência lógica para fazer as coisas. O primeiro ponto, é que precisamos saber onde o preço atual do ativo se encontra. Isto é conseguido na linha 68. Preste atenção a cada detalhe, nesta linha. Pois cada detalhe aqui é muito importante.
Também precisamos saber qual o volume que teremos de negociar. Muita gente se complica justamente neste ponto. Pois o volume que o servidor espera, é múltiplo de um outro dado. Aquele volume que está no Chart Trade, não é o volume negociado, e sim o nível de alavancagem. Ambas as coisas são diferentes, porém correlacionadas. O nível de alavancagem, diz quantas vezes o volume mínimo esperado será usado. Então não confunda as coisas. Também precisamos saber quantos dígitos decimais são esperados pelo servidor, para o ativo em questão. Esta informação é conseguida na linha 70.
Ok, agora já temos o básico. Podemos começar a preencher a estrutura. A primeira coisa a fazer, é limpar os dados da estrutura. Isto é feito na linha 72. Agora, cada uma das próximas linhas diz exatamente o que o servidor deverá fazer. Esta forma de preenchimento que é mostrada entre as linhas 73 a 86, funcionará tanto para mercados de bolsa ou balcão, como também para forex. O que você precisa saber aqui, é que cada um destes campos tem um significado. O mal entendimento de qualquer um. Poderá fazer você perder dinheiro, ou perder uma oportunidade. Porém explicar cada um destes campos irá de fato ficar para um outro artigo. Já que quando for explicar o sistema de ordens pendentes, será mais fácil compreender cada um destes campos.
De qualquer forma, a informação criada, será apresentada no terminal para que você possa conferir ela depois. Isto é feito usando as linhas 88 a 91. Apesar de podermos fazer as coisas de uma outra forma, fazer uso da chamada ArrayPrint, da biblioteca padrão do MQL5, é algo consideravelmente mais simples e prático. Já que todos os campos são mostrados de maneira bastante simplificada. No final a função retornará a resposta do requerimento. Isto na linha 93.
Considerações finais
Apesar deste artigo tratar apenas e somente uma parte do código. Tratando apenas o envio de ordens a mercado. Este arquivo de cabeçalho mostrado, já é capaz de junto com o indicador Chart Trade, efetuar compras ou vendas a mercado. Mas talvez você ainda não tenha tido todas as suas dúvidas sanadas. Isto por que eu não expliquei o que cada valor na estrutura MqlTradeRequest significa. Mas não se preocupe, quando formos ver sobre ordens pendentes explicarei ela com calma. No demais, nos vemos no próximo artigo, onde continuaremos a tratar do código fonte do Expert Advisor.
Arquivo | Descrição |
---|---|
Experts\Expert Advisor.mq5 | Demonstra a interação entre o Chart Trade e o Expert Advisor (É necessário o Mouse Study para interação) |
Indicators\Chart Trade.mq5 | Cria a janela para configuração da ordem a ser enviada (É necessário o Mouse Study para interação) |
Indicators\Market Replay.mq5 | Cria os controles para interação com o serviço de replay/simulador (É necessário o Mouse Study para interação) |
Indicators\Mouse Study.mq5 | Permite interação entre os controles gráficos e o usuário (Necessário tanto para operar o replay simulador, quanto no mercado real) |
Services\Market Replay.mq5 | Cria e mantem o serviço de replay e simulação de mercado (Arquivo principal de todo o sistema) |
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso