
Simulação de mercado (Parte 05): Iniciando a classe C_Orders (II)
Introdução
No artigo anterior Simulação de mercado (Parte 04): Iniciando a classe C_Orders (I), fiquei basicamente focado, em explicar, como seria o código para enviar pedidos de negociação a mercado. Basicamente toda aquela explicação, tinha como intuito, mostrar. Ou melhor dizendo: Demonstrar como você poderia estruturar o código da classe a fim de poder decodificar as informações recebidas do indicador Chart Trade.
Porém, mesmo sem ter visto o código fonte do Expert Advisor, acredito que aqueles com algum conhecimento, já conseguiriam de fato o implementar. E mesmo que pareça que aquele código, visto no artigo anterior, não seria capaz de executar operações no servidor de negociação físico. Isto não é bem verdade, se bem, que aquele código não seria suficiente para ser usado quando o assunto fosse contas do tipo HEDGING.
No entanto, para contas do tipo NETTING, aquele código já conseguiria, abrir e fechar uma posição. Mas para contas do tipo HEDGING, a coisa funciona de forma um pouco diferente.
Se você tentar fechar uma posição, por exemplo de compra, usando o botão de venda, você iria de fato, abrir uma posição vendida. Isto para contas do tipo HEDGING. Para uma conta do tipo NETTING, fazer o que foi dito, fecharia a posição comprada. Ou no mínimo iria produzir algum tipo de efeito. Como:
- Uma virada de mão. Que seria conseguida se você vendesse um volume maior do que o volume da posição comprada. Neste caso você deixaria de estar comprado, e passaria a estar em uma posição vendida. O volume da posição vendida, seria a diferença entre o volume da posição que estava comprada, com o volume enviado para a virada de mão.
- Fazer uma parcial. Esta seria conseguida se o volume vendido, fosse menor que o volume da posição comprada. Neste caso, parte do volume comprado seria encerrado. Isto faria com que um resíduo da posição comprada, continua-se em aberto na visão do mercado.
Tudo isto é bastante interessante, e foi largamente explicado em uma outra sequência de artigos, que postei a algum tempo. Tal sequência de artigos tinha como objetivo explicar em detalhes, como você faria para criar um Expert Advisor, que pudesse ser usado de forma automática. Sendo composto de 15 artigos, onde em cada um, explico um dos aspectos e cuidados para se criar tal Expert Advisor. Partindo de um modelo que funciona manualmente, até chegar ao ponto de torná-lo 100% automático. Quem tiver interesse em saber mais procure pelos artigos sobre o assunto. O primeiro dos artigos desta série pode ser visto aqui: Aprendendo a construindo um EA que opera de forma automática (Parte 01): Conceitos e estruturas
Muito do código que será visto aqui, vem exatamente daquela sequência. Só que aqui a ênfase será um pouco diferente. Isto por que o objetivo primário aqui é outro. Ou seja, não queremos de fato, desenvolver um sistema de envio de ordens, ou de comunicação com um servidor de negociação real. Queremos e iremos de fato fazer, é desenvolver um servidor simulado. Porém, antes de fazer isto, precisamos implementar algumas coisas. E já que o ideal, é podermos fazer uso de aplicações comuns, entre o nosso sistema de replay/simulador e o uso do servidor de negociação real. Isto tanto em conta demo, quanto em conta real. Faremos a implementação primeiramente do Expert Advisor, para que ele possa se comunicar com o servidor real. Quando tal implementação estiver concluída, iremos de fato, desenvolver um simulador do servidor de negociação.
O motivo de fazer desta forma, é limitar, ou delimitar o tipo de chamadas que precisaremos de fato utilizar. Não tenho, pelo menos neste primeiro momento, simular todas as chamadas que o servidor real de fato responde. Visto que na grande maioria das vezes, não precisamos de todas elas. Mas com o tempo, talvez eu venha a mudar de ideia. Mas por hora, vamos fazer as coisas assim. Muito bem, dito tais coisas, podemos iniciar o primeiro tópico deste artigo.
Tratando a mensagem para fechar as posições
Ok. Se você não entendeu o conteúdo do artigo anterior. Sugiro que volte a ele, e entenda primeiro aquele conteúdo. Pois aqui iremos apenas continuar o que foi visto lá. Mas como ocorreu, uma pequena melhoria na estruturação do código. Você poderá ver todo ele, novamente na íntegra logo abaixo. Porém, as partes que foram explicadas no artigo anterior, não serão revistas aqui. Isto por que o fato da estruturação de ocorrido, não invalida de forma alguma a explicação que foi dada lá. Então vamos ao código em si.
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_Base.MagicNumber; } 011. //+------------------------------------------------------------------+ 012. bool ClosePosition(const ulong ticket) 013. { 014. bool IsBuy; 015. string szContract; 016. 017. if (!PositionSelectByTicket(ticket)) return false; 018. IsBuy = PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY; 019. szContract = PositionGetString(POSITION_SYMBOL); 020. ZeroMemory(m_Base.TradeRequest); 021. m_Base.TradeRequest.action = TRADE_ACTION_DEAL; 022. m_Base.TradeRequest.type = (IsBuy ? ORDER_TYPE_SELL : ORDER_TYPE_BUY); 023. m_Base.TradeRequest.price = NormalizeDouble(SymbolInfoDouble(szContract, (IsBuy ? SYMBOL_BID : SYMBOL_ASK)), (int)SymbolInfoInteger(szContract, SYMBOL_DIGITS)); 024. m_Base.TradeRequest.position = ticket; 025. m_Base.TradeRequest.symbol = szContract; 026. m_Base.TradeRequest.volume = PositionGetDouble(POSITION_VOLUME); 027. m_Base.TradeRequest.deviation = 1000; 028. 029. return SendToPhysicalServer() != 0; 030. }; 031. //+------------------------------------------------------------------+ 032. private : 033. //+------------------------------------------------------------------+ 034. struct stBase 035. { 036. MqlTradeRequest TradeRequest; 037. ulong MagicNumber; 038. bool bTrash; 039. }m_Base; 040. //+------------------------------------------------------------------+ 041. struct stChartTrade 042. { 043. struct stEvent 044. { 045. EnumEvents ev; 046. string szSymbol, 047. szContract; 048. bool IsDayTrade; 049. ushort Leverange; 050. double PointsTake, 051. PointsStop; 052. }Data; 053. //--- 054. bool Decode(const EnumEvents ev, const string sparam) 055. { 056. string Res[]; 057. 058. if (StringSplit(sparam, '?', Res) != 7) return false; 059. stEvent loc = {(EnumEvents) StringToInteger(Res[0]), Res[1], Res[2], (bool)(Res[3] == "D"), (ushort) StringToInteger(Res[4]), StringToDouble(Res[5]), StringToDouble(Res[6])}; 060. if ((ev == loc.ev) && (loc.szSymbol == _Symbol)) Data = loc; 061. else return false; 062. 063. return true; 064. } 065. //--- 066. }m_ChartTrade; 067. //+------------------------------------------------------------------+ 068. ulong SendToPhysicalServer(void) 069. { 070. MqlTradeCheckResult TradeCheck; 071. MqlTradeResult TradeResult; 072. 073. ZeroMemory(TradeCheck); 074. ZeroMemory(TradeResult); 075. if (!OrderCheck(m_Base.TradeRequest, TradeCheck)) 076. { 077. PrintFormat("Order System - Check Error: %d", GetLastError()); 078. return 0; 079. } 080. m_Base.bTrash = OrderSend(m_Base.TradeRequest, TradeResult); 081. if (TradeResult.retcode != TRADE_RETCODE_DONE) 082. { 083. PrintFormat("Order System - Send Error: %d", TradeResult.retcode); 084. return 0; 085. }; 086. 087. return TradeResult.order; 088. } 089. //+------------------------------------------------------------------+ 090. ulong ToMarket(const ENUM_ORDER_TYPE type) 091. { 092. double price = SymbolInfoDouble(m_ChartTrade.Data.szContract, (type == ORDER_TYPE_BUY ? SYMBOL_ASK : SYMBOL_BID)); 093. double vol = SymbolInfoDouble(m_ChartTrade.Data.szContract, SYMBOL_VOLUME_STEP); 094. uchar nDigit = (uchar)SymbolInfoInteger(m_ChartTrade.Data.szContract, SYMBOL_DIGITS); 095. 096. ZeroMemory(m_Base.TradeRequest); 097. m_Base.TradeRequest.magic = m_Base.MagicNumber; 098. m_Base.TradeRequest.symbol = m_ChartTrade.Data.szContract; 099. m_Base.TradeRequest.price = NormalizeDouble(price, nDigit); 100. m_Base.TradeRequest.action = TRADE_ACTION_DEAL; 101. m_Base.TradeRequest.sl = NormalizeDouble(m_ChartTrade.Data.PointsStop == 0 ? 0 : price + (m_ChartTrade.Data.PointsStop * (type == ORDER_TYPE_BUY ? -1 : 1)), nDigit); 102. m_Base.TradeRequest.tp = NormalizeDouble(m_ChartTrade.Data.PointsTake == 0 ? 0 : price + (m_ChartTrade.Data.PointsTake * (type == ORDER_TYPE_BUY ? 1 : -1)), nDigit); 103. m_Base.TradeRequest.volume = NormalizeDouble(vol + (vol * (m_ChartTrade.Data.Leverange - 1)), nDigit); 104. m_Base.TradeRequest.type = type; 105. m_Base.TradeRequest.type_time = (m_ChartTrade.Data.IsDayTrade ? ORDER_TIME_DAY : ORDER_TIME_GTC); 106. m_Base.TradeRequest.stoplimit = 0; 107. m_Base.TradeRequest.expiration = 0; 108. m_Base.TradeRequest.type_filling = ORDER_FILLING_RETURN; 109. m_Base.TradeRequest.deviation = 1000; 110. m_Base.TradeRequest.comment = "Order Generated by Experts Advisor."; 111. 112. MqlTradeRequest TradeRequest[1]; 113. 114. TradeRequest[0] = m_Base.TradeRequest; 115. ArrayPrint(TradeRequest); 116. 117. return (((type == ORDER_TYPE_BUY) || (type == ORDER_TYPE_SELL)) ? SendToPhysicalServer() : 0); 118. }; 119. //+------------------------------------------------------------------+ 120. void CloseAllsPosition(void) 121. { 122. for (int count = PositionsTotal() - 1; count >= 0; count--) 123. { 124. if (PositionGetSymbol(count) != m_ChartTrade.Data.szContract) continue; 125. if (PositionGetInteger(POSITION_MAGIC) != m_Base.MagicNumber) continue; 126. ClosePosition(PositionGetInteger(POSITION_TICKET)); 127. } 128. }; 129. //+------------------------------------------------------------------+ 130. public : 131. //+------------------------------------------------------------------+ 132. C_Orders(const ulong magic) 133. { 134. m_Base.MagicNumber = magic; 135. } 136. //+------------------------------------------------------------------+ 137. void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) 138. { 139. switch (id) 140. { 141. case CHARTEVENT_CUSTOM + evChartTradeBuy : 142. case CHARTEVENT_CUSTOM + evChartTradeSell : 143. case CHARTEVENT_CUSTOM + evChartTradeCloseAll: 144. if (m_ChartTrade.Decode((EnumEvents)(id - CHARTEVENT_CUSTOM), sparam)) switch (m_ChartTrade.Data.ev) 145. { 146. case evChartTradeBuy: 147. ToMarket(ORDER_TYPE_BUY); 148. break; 149. case evChartTradeSell: 150. ToMarket(ORDER_TYPE_SELL); 151. break; 152. case evChartTradeCloseAll: 153. CloseAllsPosition(); 154. break; 155. } 156. break; 157. } 158. } 159. //+------------------------------------------------------------------+ 160. }; 161. //+------------------------------------------------------------------+
Código do arquivo de cabeçalho C_Orders.mqh
E ai está ele. Este código visto acima, consegue responder adequadamente a todas as mensagens que o indicador Chart Trade envia para o Expert Advisor, a fim de conversar com o servidor de negociação. A partir deste momento, todos os botões e controles do indicador Chart Trade, se tornam funcionais. Você pode utilizar este código em qualquer Expert Advisor, desde é claro você faça algumas coisas que será visto mais a frente neste artigo. A ideia aqui, é justamente permitir isto. Você poderá usar os módulos que compõem o Chart Trade e o Indicador de Mouse. Assim fazendo uso deste código visto acima, tornar o seu Expert Advisor, compatível com os módulos já compilados do Chart Trade e do Indicador de Mouse. Ou seja, programe uma vez, teste para confirma que funciona, e não mexa mais. Parta para a próxima etapa. Esta é a ideia.
Mas para quem está começando, e não consegue compreender este código. Vamos então explicar o que é novidade aqui. Lembrando, que a tal mudança que mencionei na estruturação, se deu no que pode ser visto na linha 34. Onde agrupei as variáveis privativas da classe em uma estrutura. Mas isto, como foi dito, não muda em nada o que foi explicado no artigo anterior.
A primeira coisa que você pode estar pensando é: Como esta classe sabe qual a posição que deverá ser fechada, quando pressionamos o botão que fecha as posições no indicador Chart Trade? Pois a resposta é: A classe não sabe qual a posição deverá ser fechada. Você talvez ache que isto pode ser algum tipo de bobagem. Já que ao observar os botões, o que fecha a posição está sendo declarado como: CLOSE ALLS POSITION. Então é de se imaginar que todas as posições serão fechadas. Certo? Errado. Pois não é bem isto que esta classe estará fazendo. Pelo menos não sem que o código visto acima venha a sofrer algumas modificações.
Muito provavelmente, agora talvez, você pode estar confuso com tudo isto. Se ao pressionar o botão CLOSE ALLS POSITION, não teremos o fechamento de todas as posições. Por que ele está com esta mensagem? Bem, para entender isto, será preciso voltar um pouco no tempo. Isto antes de vermos realmente como o código da classe funciona.
Nos artigos sobre sistema de ordens cruzadas:
Expliquei como, e por que as vezes precisamos fazer uso, de um tipo específico de ativo, o chamado histórico. Ali, foi explicado que teríamos de fazer, com que de alguma forma, o indicador Chart Trade pudesse dizer ao Expert Advisor, qual seria o real ativo que deveria ser negociado. Isto por que o chamado histórico, não é de fato um ativo negociável. Não sendo possível assim enviar pedidos de negociação por ele. Muitos destes ativos de históricos existem por conta dos contratos. E lá nestes dois artigos expliquei esta questão dos contratos. Porém, aqui, o problema se agrava enormemente. Visto que você pode estar utilizando o gráfico de um ativo histórico. E pedir para o Expert Advisor trocar do contrato cheio para o minicontrato a qualquer momento. Isto fará com que tanto o Expert Advisor, mas principalmente o Indicador Chart Trade, mude o ativo a ser negociado.
Agora vem o verdadeiro problema. Se você durante algum tempo, usando o gráfico de histórico, por exemplo do DÓLAR. Pediu para o Expert Advisor, anotar que seria feito operações no contrato de dólar cheio, mudar depois de ideia e pedir para o Expert Advisor usar o minicontrato. O Expert Advisor emitirá uma mensagem para o Indicador Chart Trade, informando a mudança de contrato. Até ai nada de errado. O problema realmente começa a partir do ponto, em que você viesse a ter uma posição aberta no contrato cheio. Pois bem, se você disser ao Expert Advisor, que deseja mudar, por qualquer motivo para o minicontrato. Mesmo tendo uma posição aberta no contrato cheio. O Expert Advisor irá simplesmente obedecer. Porém, ao fazer isto, o Chart Trade, também irá de fato mudar. Agora temos um problema. E é este problema que você deve entender, para adequar o código ao que você precisa fazer.
Se neste momento, em que o Chart Trade estiver indicado que o contrato a ser negociado é o minicontrato. O que acontece se você pedir para fechar todas as posições abertas? Lembrando que estamos com uma posição aberta no contrato cheio. E indicador Chart Trade, irá de fato gerar uma mensagem para o Expert Advisor. Esta mensagem, conforme pode ser vista nos artigos anteriores, conterá todos os dados para que o Expert Advisor possa saber o que fazer. Porém, o Expert Advisor não sabe o que fazer. Isto por que estamos com o Expert Advisor, em um gráfico cujo conteúdo não pode ser negociado. Ou seja, um gráfico de histórico do contrato. Para que o Expert Advisor saiba o que fazer. A mensagem será interceptada na linha 153 do código. Lembrando que para isto ocorrer, a mensagem já terá sido traduzida. Tal tradução ocorreu sem problemas. Assim o código será conduzido para a linha 120. Agora começa o verdadeiro trabalho.
Muito bem, na linha 122, temos um laço. Este laço irá de fato ler todas as posições que estão abertas. Absolutamente todas, sem exceção. Porém, por que estamos fazendo isto? Por que ler todas posições abertas, mesmo que elas não tenham nada a ver com o contrato de DÓLAR do nosso exemplo? O motivo é que não estamos armazenando o bilhete, que o servidor nos informou, quando a posição foi aberta. Por isto, precisamos procurar novamente este mesmo bilhete.
Agora a outra questão é: Então por que não armazenamos estes bilhetes. Isto tornaria o trabalho mais simples. De fato tornaria. Porém, o armazenamento destes bilhetes, não poderá se dar dentro do Expert Advisor. Já que no momento que algo no gráfico envolvendo o Expert Advisor ocorrer. Teremos a perda da informação referente a estes mesmos bilhetes. Assim seremos forçados a buscar os mesmos novamente. Este tipo de coisa sempre ocorrerá, se o tempo gráfico for modificado. Ou o tipo de contrato for alterado.
Então por enquanto, vamos fazer assim. Mas, ao fazer as coisas assim, não podemos simplesmente chamar o procedimento que fecha a posição. Pois estaremos varrendo todas as posições, até mesmo aquelas não relacionadas a mensagem vinda do Chart Trade.
Desta forma, temos que filtrar as coisas. O primeiro filtro, se encontra na linha 124. Aqui verificamos o nome do ativo daquela posição, e comparamos este mesmo nome com o nome informado pelo Chart Trade. Agora preste atenção. No nosso exemplo, existe uma posição aberta no contrato cheio. Porém, a mensagem vinda do Chart Trade indica que o ativo é o minicontrato. Desta forma este teste irá de fato falhar. Já que o nome do ativo não está batendo. A mesma coisa aconteceria, se estivéssemos em uma situação contrária. Onde teríamos uma posição aberta no minicontrato e usássemos o Chart Trade para fechar as posições no contrato cheio. Este teste evitaria a confusão.
Agora é preciso notar uma coisa. Este teste apesar de parecer complicar as coisas é necessário. Mesmo que você esteja utilizando o histórico do contrato, para poder negociar tanto o minicontrato quanto o contrato cheio, isto via cross order. Você não deve remover este teste da linha 124 do código. Mesmo que você queira no momento fechar qualquer posição relacionada ao contrato de DÓLAR. E o motivo é simples. Sem este teste, mesmo posições de outros ativos, poderão vim a ser fechadas no momento que você fizesse uso do Chart Trade. Isto devido ao fato de que estaremos varrendo todas as posições em aberto.
Mas se o teste da linha 124 tiver sucesso, teremos um novo teste. Este tem como objetivo isolar e filtrar uma outra coisa. No artigo anterior, eu mencionei o fato de que esta classe representaria uma entidade única. Isto devido ao número mágico. Assim um mesmo Expert Advisor poderia conter diversas estratégias de negociação diferentes. E todas elas seriam independentes umas das outras. Tal separação seria feita pelo número mágico.
Apesar de tudo, para contas do tipo NETTING isto não faria sentido. Já que neste tipo de conta, o servidor de negociação fará um preço médio da posição. Então você teria apenas e somente uma única posição aberta por ativo.
No entanto, para contas do tipo HEDGING, a coisa muda totalmente de figura. Neste caso, podemos ter diversas posições abertas, mesmo uma sendo de venda e outra de compra, ao mesmo tempo no mesmo ativo. E é nestes casos que faz sentido, que esta classe saiba se diferenciar de outras presentes no mesmo Expert Advisor. Mas para não complicar as coisas, não entrarei nos detalhes de como fazer isto. Você apenas precisa saber, que isto é sim possível e previsto nesta classe.
Pois bem, além do fato de que o Expert Advisor ter aberto posições. E estas estarão marcadas com um número mágico, que diz qual foi a classe que fez isto. Temos outra possibilidade. O operador, pode também ter aberto de forma manual alguma posição. E neste caso específico a coisa de fato pode pegar. Isto por que, pode ser que o operador não queira que a sua posição seja fechada. Isto quando for feito o uso do Chart Trade. Pois o Expert Advisor fará a comparação do número mágico da posição, com o número mágico da classe. E se estes não forem iguais, a posição será ignorada, permanecendo assim aberta. Então se o operador tiver aberto uma posição manualmente. O Expert Advisor ignorará esta posição e ela ficará aberta. Devendo o operar a fechar de forma manual.
Está vendo como as coisas vão ocorrendo. Apesar de este comportamento poder ser modificado. Todo o sistema está sendo pensado de forma a trabalhar em contas do tipo HEDGING. E de forma a não interferir naquilo que não lhe diz respeito. Assim, se estes dois testes, tiverem sucesso. Teremos a execução da linha 126. Esta fará a captura do bilhete da posição e chamará o procedimento para fechar a posição indicada. Este procedimento chamado, se encontra na linha 12. Atenção ao fato de que ele está dentro da cláusula protegida. Ou seja, ele poderá ser utilizado via herança, mas não poderá ser acessado diretamente fora do sistema de herança. Resumindo: Não será possível chamar este procedimento, diretamente de dentro do código do Expert Advisor, ou de qualquer outro código.
Aqui temos algumas coisas curiosas, que talvez futuramente eu venha a remover do código. É o seguinte: Quando este código da linha 12 é chamado, ele já sabendo de algumas coisas. Como por exemplo: O nome do ativo da posição e o bilhete do ativo. Porém aqui na linha 17, verificamos novamente se o bilhete é mesmo de uma posição aberta. Por que estou fazendo isto novamente aqui? O motivo é que neste exato momento, não sei como uma outra ferramenta que será criada ainda, irá se comunicar com este procedimento. Porém, é preciso usar a função de biblioteca PositionSelectByTicket, para poder atualizar algumas informações que precisaremos buscar no servidor. No entanto, esta atualização foi feita também, quando na linha 124, chamamos PositionGetSymbol. Ou seja, estamos duplicando as coisas. Mas por hora isto não é um problema.
De qualquer forma, precisamos realmente atualizar as informações. Então uma vez que elas estejam atualizadas e o bilhete realmente for de uma posição. Verificamos na linha 18 se a posição é de compra ou venda. Isto é importante para nós depois. Logo depois a linha 19 fazemos a captura do nome do ativo da posição. Este tipo de coisa talvez venha a ser modificado no futuro, quando a outra ferramenta for implementada. Isto por que apenas olhando este código, desta classe, tais coisas seriam totalmente desnecessárias. Isto por que o procedimento da linha 120, poderia passar estas informações para nós. Novamente, não sei como este procedimento ClosePosition será no futuro. Então entramos na fase de preenchimento da ficha, ou melhor dizendo, estrutura a ser passada ao servidor.
Diferente do que aconteceu no procedimento ToMarket, visto no artigo anterior, onde foi dito que a explicação de cada campos será vista depois. Aqui posso explicar os campos principais. Isto por que saber o que cada um representa será importante no futuro. Na linha 21 dizemos ao servidor o tipo de ação a ser tomada. Agora muitos podem estar se indagando. Por que você não usa a ação TRADE_ACTION_CLOSE_BY, já que a ideia aqui é fechar a posição? Este questionamento é interessante, e o motivo principal é a conta do tipo NETTING. Para entender, é preciso observar o valor que está sendo indicado na linha 26, onde dizemos ao servidor o volume a ser utilizado. Se fosse usado a ação TRADE_ACTION_CLOSE_BY, o servidor simplesmente encerraria a posição.
Assim seriamos obrigados a criar toda uma lógica e também um código para fazer uma outra coisa, que a conta do tipo NETTING nos permite fazer. Esta coisa é a parcial. Onde encerramos parte da nossa posição. Aqui não estou incluindo a lógica para se fazer parciais. Assim como também a lógica para virada de mão. Isto é uma questão de decisão a respeito do que será ou deverá ser implementado. Já que podemos usar este sistema em qualquer tipo de conta. Temos que priorizar algumas coisas em detrimento de outras. E já que a conta NETTING permite coisas não possíveis na conta HEDGING e vice-versa. Estou tentando cobrir ambos os tipos de conta. Por isto está explicação é importante.
Todos os outros campos, tem como objetivo dizer ao servidor se iremos vender ou comprar, isto na linha 22. O preço em que o negócio deverá ser feito, isto na linha 23. O bilhete da posição a ser usado, isto na linha 24. O nome do ativo, isto na linha 25. Um detalhe: Este nome tem que bater com o nome presente no bilhete, caso contrário ocorrerá uma falha. Além do volume, que diz muito a respeito do que será feito, isto na linha 26. E por último a derivação, que seria um desvio no preço informado, isto na linha 27. Todas estas informações dirão ao servidor, para executar o requerimento passado a mercado. Ou seja, ele fará a operação no melhor preço possível. Modificando assim o volume, ou a direção esperada para o movimento, ou encerrando e fechando a posição.
Notaram que diferente da ação TRADE_ACTION_CLOSE_BY, que apenas fecharia a posição. Aqui temos a possibilidade de fazer bem mais coisas. Por isto estou fazendo uso desta ação TRADE_ACTION_DEAL. Mas ela serve apenas quando uma posição já se encontra aberta. E ela não serve para mudar os pontos de stop loss ou take profit. Isto é feito por meio de uma outra ação, que será vista no futuro. Desta forma, por hora, iremos de fato fazer uso do sistema presente no MetaTrader 5. Ou seja, mesmo que seja possível, negociar via histórico do contrato futuro. Você não verá as linhas de preço neste contrato. Elas estarão presentes no contrato indicado na posição. Mas futuramente isto será modificado.
Muito bem falta uma última coisa a ser vista. O código do Expert Advisor. Este pode ser visto logo abaixo:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property icon "/Images/Market Replay/Icons/Replay - EA.ico" 04. #property description "Demo version between interaction" 05. #property description "of Chart Trade and Expert Advisor" 06. #property version "1.84" 07. #property link "https://www.mql5.com/pt/articles/12598" 08. //+------------------------------------------------------------------+ 09. #include <Market Replay\Order System\C_Orders.mqh> 10. //+------------------------------------------------------------------+ 11. enum eTypeContract {MINI, FULL}; 12. //+------------------------------------------------------------------+ 13. input eTypeContract user00 = MINI; //Cross order in contract 14. //+------------------------------------------------------------------+ 15. C_Orders *Orders; 16. long GL_ID; 17. //+------------------------------------------------------------------+ 18. int OnInit() 19. { 20. GL_ID = 0; 21. Orders = new C_Orders(0xC0DEDAFE78514269); 22. 23. return INIT_SUCCEEDED; 24. } 25. //+------------------------------------------------------------------+ 26. void OnTick() {} 27. //+------------------------------------------------------------------+ 28. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 29. { 30. (*Orders).DispatchMessage(id, lparam, dparam, sparam); 31. switch (id) 32. { 33. case CHARTEVENT_CHART_CHANGE: 34. if (GL_ID > 0) break; else GL_ID = ChartID(); 35. case CHARTEVENT_CUSTOM + evChartTrade_At_EA: 36. EventChartCustom(GL_ID, evEA_At_ChartTrade, user00, 0, ""); 37. break; 38. } 39. } 40. //+------------------------------------------------------------------+ 41. void OnDeinit(const int reason) 42. { 43. switch (reason) 44. { 45. case REASON_REMOVE: 46. case REASON_INITFAILED: 47. EventChartCustom(GL_ID, evEA_At_ChartTrade, -1, 0, ""); 48. break; 49. } 50. 51. delete Orders; 52. } 53. //+------------------------------------------------------------------+
Código fonte do Expert Advisor
Este código já foi quase totalmente visto no artigo Simulação de mercado (Parte 02): Cross Order (II), tendo assim recebido poucas mudanças, a fim de poder fazer uso da classe C_Orders. Tais mudanças são bem simples. Porém se você não tem muita experiência em codificar em C. Algumas coisas aqui podem ser meio estranhas. Mas não é nada demais, apenas diferentes. A primeira mudança é na linha nove, onde incluímos o arquivo de cabeçalho visto neste artigo. Outra mudança, é a adição da linha 15, onde declaramos a classe com um ponteiro.
Na linha 21, inicializamos a classe via operador NEW. Mas você pode estar estranhando um fato nesta linha. O constructor da classe é declarado esperando um valor longo de 64 bits. Mas ali temos algo estranho: 0xC0DEDAFE78514269, onde temos letras e não apenas números. Mas que coisa maluca é esta? Na verdade não é algo maluco. É um valor hexadecimal. Repare no início do valor que temos um 0x, isto diz ao compilador que o valor indicado será um valor hexadecimal. Isto é muito útil em diversas situações. Apesar de que no momento que você olhar isto como sendo o número mágico da posição verá algo totalmente diferente. Sendo aquele valor o valor decimal que este código Hexadecimal representa. Vou deixar o valor decimal algo para você ver depois. Não farei a revelação dele aqui.
E como última mudança que foi adicionada, temos a linha 30. Esta linha repassará dos dados para que a classe possa fazer o seu trabalho. Assim o Expert Advisor conseguirá lidar com as mensagens fornecidas pelo indicador Chart Trade. Note que com muito pouco código, temos algo admirável e bastante interessante. Já que todo o sistema está dividido em módulos. Assim a melhoria em um módulo, não afetará diretamente um outro módulo, podendo o código crescer de forma bastante segura e com muito mais agilidade. Isto comparando este sistema com um sistema monolítico. Onde tudo estaria contido em um único e gigantesco arquivo. Tornando o trabalho de desenvolvimento e melhoria uma coisa muito mais cansativa de ser feita.
Considerações finais
Nestes dois últimos artigos, apresentei o Expert Advisor, junto com o código da classe responsável por envio de ordens a mercado. Este sistema é capaz de funcionar perfeitamente bem, em qualquer tipo de conta, seja ela NETTING ou HEDGING. Permitindo assim você usar o mesmo Expert Advisor, tanto em mercados de forex, quanto em mercados de bolsa ou balcão. Isto torna tudo muito mais amigável e acessível.
Porém, este Expert Advisor ainda não está concluído. Temos muito, mas muita coisa a ser adicionada a ele, antes que ele tenha de fato o seu papel principal sendo implementado. E o papel principal é: Simular o servidor de negociação para usarmos no replay/simulação.
No entanto, antes de fazermos isto teremos que fazer algumas outras coisas. Então não perca o próximo artigo. Pois nele começarei a explicar algo que já é possível ser feito, mesmo com este Expert Advisor ainda não terminado. Porém, quero começar a explicar agora, para simplificar as coisas. Já que se deixar para depois, pode ser que a explicação venha a se tornar muito complicada. E se isto ocorrer, você caro leitor, pode não conseguir entender todos os detalhes envolvidos.
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) |





- 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