
Simulação de mercado: Position View (IV)
Introdução
Olá pessoal, e sejam bem-vindos a mais um artigo da série sobre como construir um sistema de replay/simulação.
No artigo anterior Simulação de mercado: Position View (III), mostrei a importância de você saber, quando e por que configurar a propriedade ZOrder dos objetos. Até o momento, tenho sido bastante compreensivo, e não tenho mostrado o que de fato vamos fazer. Talvez você, lendo os artigos anteriores, esteja pensando que tudo aquilo é muito lindo. Mas no entanto, nada prático. Pois bem, chega de moleza. Agora vamos fazer algo, que se não for feito, não nos permitirá continuar a implementar o indicador de posição. Tal coisa é: Iremos unir as quatro aplicações que já temos. Isto para que possamos continuar a implementar o indicador de posição. No entanto, não quero que você, caro leitor, venha a se preocupar por hora com as ordens pendentes. A forma como iremos trabalhar com elas, será vista no futuro. Então precisamos dar um passo de cada vez.
E o passo mais importante neste momento, não é a questão envolvendo ordens pendentes. E sim fazer com que as posições sejam trabalhadas de maneira adequada. Lembre-se do seguinte. Já temos um Expert Advisor, que consegue abrir e fechar posições. Isto a mercado. Assim como também temos um indicador de mouse, que já nos permite fazer estudos simples. Mas que você pode modificá-lo para gerar estudos mais elaborados. Também já contamos com um Chart Trade, que nos permite enviar ordens para o Expert Advisor. E isto a fim de dizer ao Expert Advisor, se é para comprar ou vender, assim como o volume a ser negociado. Mas estas três aplicações, precisam de uma outra, a fim de que possamos de fato ter um sistema viável. Tal aplicação faltante é justamente o indicador que estamos implementando.
No atual estágio de desenvolvimento, o indicador de posição, não passa de uma aplicação interessante. Mas se o unirmos as outras três aplicações já construídas. A coisa começa a ficar de fato bem mais interessante. Ok, mas você pode estar pensando: Como faremos isto? Será que vamos usar a classe C_IndicatorPosition dentro do Expert Advisor? Não. Não faremos isto. Iremos de fato, manter o indicador de posição separado do Expert Advisor. Desta maneira, você poderá adicionar ele ao seu Expert Advisor particular.
Claro, você terá que fazer algumas coisas para que seu Expert Advisor, consiga utilizar o Indicador de Posição. Mas acredite, será bem mais simples fazer isto, do que ficar criando diversos Expert Advisores com as mesmas capacidades de trabalho. Já que qualquer mudança no Indicador de posição, irá imediatamente se refletir em todos os Expert Advisores que o estiverem usando. Diferente do que seria, se cada Expert Advisor tivesse o seu próprio indicador de posição.
Esta ideia que estou propondo e mostrando como fazer, não é nova. Ela na verdade é o que torna possível, programas diferentes se beneficiarem de coisas comuns. Estilo jogos de computador, que fazem uso do DirectX. Quando o DirectX sofre uma atualização, todos os jogos e programas que utilizam a biblioteca DirectX, são atualizados juntos. Agora pense se cada uma das aplicações tivesse que ser atualizada manualmente a cada melhoria na biblioteca do DirectX. Seria algo completamente inviável de ser feito. Então não pense, neste modelo que estou mostrando, como sendo um problema em potencial. Veja ele como uma solução, onde com o tempo, você terá aplicações cada vez mais úteis e seguras. Já que qualquer correção, ou melhoria em uma aplicação, irá refletir em toda a cadeia de aplicações que você utiliza no MetaTrader 5. Dito tais palavras, vamos a começar.
Recordando como o Expert Advisor está atualmente
Antes mesmo de fazermos qualquer mudança no código, precisamos ver como o código principal do Expert Advisor se encontra. Isto por que já faz um bom tempo, desde a última vez que mexemos nele. Assim, no código abaixo, você pode ver o atual estágio de implementação do Expert Advisor.
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 do Expert Advisor Original
Caramba. A última vez em que este código sofreu alguma modificação foi no artigo 84? Sim. Desde então ele tem permanecido sem nenhuma nova modificação. Mas agora chegou a hora de voltarmos a mexer nele. E para isto, você deve entender o seguinte, antes mesmo de mudar qualquer coisa aqui. Quero que você observe, o fato de que, na linha 13 temos a única forma de interação com o usuário, ou operador. Esta interação visa, dizer a todas as demais aplicações, que de alguma forma irão interagir com o Expert Advisor. De que ele estará voltado a trabalhar com um contrato cheio, ou um mini contrato.
Para quem não faz operações na B3 (Bolsa do Brasil), tal interação não faz sentido algum. Mas independente do que você esteja operando de fato, você deverá ter o indicador Chart Trade presente no gráfico. Junto com este Expert Advisor. Assim que o Expert Advisor, for adicionado ao gráfico, ele enviará uma mensagem a todas aplicações, dentro do MetaTrader 5. Já expliquei sobre isto no passado, nesta mesma sequência de artigos. Se você não sabe do que estou falando, procure ler os artigos anteriores, para se aprofundar no assunto. Pois entender esta questão das mensagens será de suma importância, deste momento em diante. Sem tão entendimento, você não conseguirá acompanhar os próximos artigos.
Muito bem, uma vez que esta mensagem foi enviada. Todas as aplicações saberão o que o Expert Advisor, estará esperando delas. Este Expert Advisor, não irá de maneira alguma receber comandos diretamente do operador ou usuário. Ele apenas receberá e enviar comandos via mensagens. Então não espere ver um código linear e tudo certinho. A coisa aqui é bem dinâmica mesmo.
Muito bem. Mas onde o indicador de posição entra nesta história toda? Como poderemos usar ele, se o Expert Advisor não sabe da presença dele no gráfico? De fato, o Expert Advisor, assim como as outras aplicações, não sabem da presença uns dos outros. Eles simplesmente esperam que o operador, esteja com todos eles presentes no gráfico. Isto para que eles executem corretamente a sua tarefa. Mas aqui mora um porém. Como cada indicador de posição, pertencerá a apenas e somente uma única posição em particular. Não podemos colocar ele no gráfico. Isto antes que alguma posição exista, naquele ativo em específico. Diferente dos outros indicadores, este indicador de posição será colocado e retirado, pelo Expert Advisor. Isto de forma automática. A ideia é que o operador não venha a de fato interferir nesta questão. O próprio Expert Advisor tratará disto.
No entanto, não embutirei o indicador de posição ao Expert Advisor. Já que a ideia, é que, o indicador possa ser modificado, ou melhorado, de forma que todos os Expert Advisores o usem. Sem que seja necessário recompilar os Expert Advisores para isto. Mas para que tudo funcione em perfeita harmonia, será preciso mudar algumas coisas. E ao fazer isto, você, caro leitor, deverá prestar bastante atenção ao que será explicado. Caso contrário, todo o conjunto falhará. Não fornecendo as informações que de fato deveriam ser apresentadas no gráfico. Um outro detalhe, é que você não deve neste momento se preocupar com os detalhes envolvendo as linhas de preço. A primeira coisa a ser feita, neste momento, é criar uma forma de interação entre o Expert Advisor e o Indicador de Posição. Depois iremos nos preocupar com a interação do indicador de posição com o indicador de mouse. Que será o responsável por manipular as linhas de preço.
Começando a implementar a interação
Bem, vamos começar fazendo algumas mudanças no código principal do indicador de posição. Isto por que, agora ele não será, ou não deverá ser lançado no gráfico pelo operador, ou usuário. Isto será feito pelo Expert Advisor. Mas como queremos que o Expert Advisor, saiba, qual indicador representa qual posição, precisamos mudar algumas coisas no código do indicador. Assim como também algumas mudanças no código do Expert Advisor.
Muito bem, tendo esta consciência do que precisaremos fazer. Vamos começar pelo novo código do indicador de posição. Este pode ser visto logo abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Indicator for tracking an open position on the server." 04. #property description "This should preferably be used together with an Expert Advisor." 05. #property description "For more details see the same article." 06. #property link "https://www.mql5.com/pt/articles/13168" 07. #property version "1.116" 08. #property indicator_chart_window 09. #property indicator_plots 0 10. //+------------------------------------------------------------------+ 11. #define def_ShortName "Position View" 12. //+------------------------------------------------------------------+ 13. #include <Market Replay\Order System\C_IndicatorPosition.mqh> 14. //+------------------------------------------------------------------+ 15. input ulong user00 = 0; //For Expert Advisor use 16. input color user01 = clrRoyalBlue; //Color Line Price 17. input color user02 = clrForestGreen; //Color Line Take Profit 18. input color user03 = clrFireBrick; //Color Line Stop Loss 19. //+------------------------------------------------------------------+ 20. C_IndicatorPosition *Positions = NULL; 21. //+------------------------------------------------------------------+ 22. int OnInit() 23. { 24. IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName); 25. Positions = new C_IndicatorPosition(user01, user02, user03); 26. if (!Positions.CheckCatch(user00)) 27. { 28. ChartIndicatorDelete(ChartID(), 0, def_ShortName); 29. return INIT_FAILED; 30. } 31. 32. return INIT_SUCCEEDED; 33. } 34. //+------------------------------------------------------------------+ 35. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 36. { 37. return rates_total; 38. } 39. //+------------------------------------------------------------------+ 40. void OnDeinit(const int reason) 41. { 42. delete Positions; 43. } 44. //+------------------------------------------------------------------+
Código do indicador Position View
Note que o código sofreu pequenas mudanças. Coisas simples de entender, não merecendo assim grande destaque. Mas você deve observar atentamente, que agora na linha 15, é esperado uma informação vinda do Expert Advisor. Você como operador, pode até informar tal dado. Mas lhe aconselho a não mexer nesta informação. Você pode mudar as cores, desde que tome o cuidado de não as deixar iguais. Já que por enquanto, ainda usamos elas para testar que linha horizontal cada cor representa. Mas de qualquer forma, evite ao máximo mexer no dado que deverá vir do Expert Advisor. Isto por que, justamente esta será a informação que o Expert Advisor, fará uso para trocar informações com o Indicador quando ambos estiverem no gráfico.
Agora note que na linha 26, agora passamos um parâmetro para dentro da função de checagem. Antes tal parâmetro não existia. Então vamos ver o código da classe C_IndicatorPosition. Que é mostrado na íntegra logo abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #define def_SufixTake "Take" 05. #define def_SufixStop "Stop" 06. //+------------------------------------------------------------------+ 07. #include "..\Auxiliar\C_Terminal.mqh" 08. //+------------------------------------------------------------------+ 09. class C_IndicatorPosition : private C_Terminal 10. { 11. private : 12. struct st00 13. { 14. ulong ticket; 15. color corPrice, corTake, corStop; 16. }m_Infos; 17. //+------------------------------------------------------------------+ 18. void CreateLineInfos(const string szObjName, const double price, const color cor, const string szDescription = "\n") 19. { 20. if (price <= 0) return; 21. CreateObjectGraphics(szObjName, OBJ_HLINE, cor, (EnumPriority)(cor == m_Infos.corPrice ? ePriorityNull : (ePriorityOrders + (cor == m_Infos.corStop)))); 22. ObjectSetDouble(GetInfoTerminal().ID, szObjName, OBJPROP_PRICE, price); 23. ObjectSetString(GetInfoTerminal().ID, szObjName, OBJPROP_TEXT, szDescription); 24. ObjectSetString(GetInfoTerminal().ID, szObjName, OBJPROP_TOOLTIP, szDescription); 25. ObjectSetInteger(GetInfoTerminal().ID, szObjName, OBJPROP_SELECTABLE, cor != m_Infos.corPrice); 26. } 27. //+------------------------------------------------------------------+ 28. public : 29. //+------------------------------------------------------------------+ 30. C_IndicatorPosition(color corPrice, color corTake, color corStop) 31. :C_Terminal() 32. { 33. ZeroMemory(m_Infos); 34. m_Infos.corPrice = corPrice; 35. m_Infos.corTake = corTake; 36. m_Infos.corStop = corStop; 37. } 38. //+------------------------------------------------------------------+ 39. ~C_IndicatorPosition() 40. { 41. if (m_Infos.ticket != 0) 42. ObjectsDeleteAll(GetInfoTerminal().ID, IntegerToString(m_Infos.ticket)); 43. } 44. //+------------------------------------------------------------------+ 45. bool CheckCatch(ulong ticket) 46. { 47. string szName = IntegerToString(m_Infos.ticket = ticket); 48. 49. if (!PositionSelectByTicket(m_Infos.ticket)) return false; 50. if (ObjectFind(GetInfoTerminal().ID, szName) >= 0) 51. { 52. m_Infos.ticket = 0; 53. return false; 54. } 55. IndicatorSetString(INDICATOR_SHORTNAME, szName); 56. CreateLineInfos(szName, PositionGetDouble(POSITION_PRICE_OPEN), m_Infos.corPrice, "Position opening price."); 57. CreateLineInfos(szName + def_SufixTake, PositionGetDouble(POSITION_TP), m_Infos.corTake, "Take Profit point."); 58. CreateLineInfos(szName + def_SufixStop, PositionGetDouble(POSITION_SL), m_Infos.corStop, "Stop Loss point."); 59. 60. return true; 61. } 62. //+------------------------------------------------------------------+ 63. }; 64. //+------------------------------------------------------------------+ 65. #undef def_SufixTake 66. #undef def_SufixStop 67. //+------------------------------------------------------------------+
C_IndicatorPosition.mqh
Observe que algumas coisas mudaram neste código de uma maneira geral. Porém nada de muito complicado, não merecendo desta forma algum destaque em especial. No entanto, conforme foi mencionado acima. A função de checagem, passou a receber um argumento. Assim sendo, vamos dar uma olhada no que mudou nesta função. Para isto vamos nos dirigir a linha 45, onde a função CheckCatch se encontra definida.
Note que assim, que a função se inicia, temos a linha 47. Neste ponto, transformamos a informação que o Expert Advisor estará nos passando, para ser usada no nome dos objetos que iremos criar. Depois disto, na linha 49, checamos se a posição existe ou não. Bem, aqui vale explicar por que estou testando novamente isto. Já que o Expert Advisor irá nos informar e garantir que de fato a posição existe. Ok. O detalhe, é que não tenho pretensão em tornar este indicador de posição, parte integrante do Expert Advisor. Então caso um operador, ou mesmo um usuário, tente lançar este indicador no gráfico. Precisamos confirma se de fato a posição existe. Observe, que não estamos procurando ela aqui no indicador, como foi feito no artigo anterior.
Uma vez que a posição seja confirmada, como existente, teremos um novo teste. Este é feito na linha 50. Mas neste caso o teste visa garantir que somente teremos um indicador por posição no gráfico. Existem outras formas de se fazer este mesmo teste. Porém aqui testamos a presença de uma linha com um dado nome. Se tudo ocorrer bem, o indicador funcionará como foi visto até no artigo anterior. Assim podemos passar para o código do Expert Advisor. Isto para compreender como as coisas ocorrerão quando o Expert Advisor, for lançado no gráfico. Desta maneira, você pode observar o novo código do Expert Advisor logo a seguir.
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.116" 07. #property link "https://www.mql5.com/pt/articles/13168" 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; 35. else 36. { 37. GL_ID = ChartID(); 38. for (int handle, count = PositionsTotal() - 1; count >= 0; count--) 39. { 40. handle = iCustom(_Symbol, PERIOD_CURRENT, "\\Indicators\\Position View.ex5", PositionGetTicket(count)); 41. ChartIndicatorAdd(GL_ID, 0, handle); 42. IndicatorRelease(handle); 43. } 44. } 45. case CHARTEVENT_CUSTOM + evChartTrade_At_EA: 46. EventChartCustom(GL_ID, evEA_At_ChartTrade, user00, 0, ""); 47. break; 48. } 49. } 50. //+------------------------------------------------------------------+ 51. void OnDeinit(const int reason) 52. { 53. switch (reason) 54. { 55. case REASON_REMOVE: 56. case REASON_INITFAILED: 57. EventChartCustom(GL_ID, evEA_At_ChartTrade, -1, 0, ""); 58. break; 59. } 60. 61. delete Orders; 62. } 63. //+------------------------------------------------------------------+
Expert Advisor.mq5
Observe que o código mudou muito pouco, se comparado ao visto no começo deste mesmo artigo. O real motivo de tão poucas mudanças, se deve ao fato de que, o intuito aqui, é explicar a você, caro leitor e entusiasta. De que não é preciso muita coisa, para que tudo funcione adequadamente. Note que tudo que foi de fato modificado, ou melhor adicionado ao código, se encontra entre as linhas 38 e 43. Mas isto já será o suficiente, para que o Expert Advisor, consiga pelo menos, estabelecer algum tipo de comunicação com o Indicador de posição. Na verdade, o que estamos fazendo aqui, era feito anteriormente, dentro do código do indicador. Onde para cada posição que estivesse aberta. Teríamos a presença de um indicador de posição sendo colocado no gráfico.
Porém, preste atenção a uma coisa importante aqui. Nós estamos capturando todas as posições abertas. Mas, e isto é importante ser observado, não estamos filtrando as mesmas. Simplesmente estamos lançando indicadores no gráfico onde o Expert Advisor se encontra. Mas a posição pode ser de um ativo diferente da esperada ser vista no gráfico. Bem, você pode pensar que isto foi falha minha. Mas não, fiz isto de propósito para mostrar, que muitos as vezes acabam cometendo este erro. E quando se dão conta, estão fazendo uso, se algo que não é confiável.
Observe, que o problema está no fato não de usarmos a variável _Symbol, presente no MQL5, a fim de termos acesso ao nome do ativo, presente no gráfico. O erro não está ali. Mas sim no fato de que não estamos verificando, como era feito no código presente no indicador. Se a posição retornada pela função PositionGetTicket, é de fato uma posição pertencente, ou de alguma forma ligada ao ativo presente no gráfico. Este é o erro. Que você deve sempre tomar cuidado. Já que durante os testes você pode achar que está tudo bem, isto em uma conta demo. Mas quando vai para a conta real, pode acabar perdendo dinheiro por conta de um descuido durante a programação, ou por conta de testes insuficientes na fase de implementação. Então, para você, meu caro leitor, que esteja aprendendo ou tentando aprender algumas coisas. Tome cuidado ao fazer mudanças em qualquer código. Sempre teste muito bem as coisas. E sempre leia a documentação a fim de tirar quaisquer dúvidas.
Muito bem. Agora você começou a perceber, que algumas coisas em programação, são um pouco mais complicadas do que possa parecer à primeira vista. Porém, não existe motivo para desanimar e desistir de estudar programação. Tudo é uma questão de saber se adaptar e encontrar o caminho correto. Mas você deve estar pensando que então bastaria testar se o ativo, cuja posição é indicada pelo ticket, pertence ou não ao que esperamos usar. Certo? Bem, é mais ou menos isto.
E o motivo de eu dizer isto, é justamente por conta que não sei qual é o mercado que você está operando. Como foi falando no começo deste artigo. Existem casos, principalmente na B3 (Bolsa do Brasil) em que temos a presença de um contrato cheio e um mini contrato. Assim como também temos o histórico do contrato vigente. Alguns operadores gostam de usar o histórico para operar. Enquanto outros, fazem uso do gráfico do ativo em que desejam operar.
Note que apesar de parecer ser uma situação complicada. E você ficar pensando: Por que alguém faria tal complicação, em tentar operar um gráfico diferente daquele que define o contrato, ou ativo correto. Pense que isto é uma escolha do operador. E não podemos limitar o mesmo, devemos como programadores, satisfazer a necessidade que o operador tem.
Desta maneira surge outra questão: Então como podemos lidar com tal situação? Já que não temos como saber qual é o ativo, correto? No entanto, a coisa não é assim tão complicada, meu caro leitor. Sabemos sim onde está a informação do ativo correto. Ela está no Indicador Chart Trade. E é neste ponto em que a coisa se torna verdadeiramente interessante. Você, como programador, tem duas alternativas. A primeira é perguntar, ao Chart Trade qual é o ativo correto, a ter suas posições colocadas no gráfico. Bem, você pode pensar: Mas por que preciso perguntar isto ao Chart Trade? Já que a informação é mostrada em um objeto no Chart Trade. Basta eu ir e ler o conteúdo deste objeto.
Deverás meu caro leitor. A informação de fato está em um objeto presente no Chart Trade. Porém, ela não estará acessível, assim tão facilmente. Você precisará realmente criar uma mensagem apenas para obter esta informação junto ao Chart Trade. Mas fazer isto, tornaria o código do Expert Advisor muito complexo. No entanto, existe uma outra solução. E esta é consideravelmente mais simples. Porém você deve fazer as coisas da maneira correta. Caso contrário, acabará criando uma quebra no encapsulamento já criado e testado já um bom tempo. Então, pensando com calma e analisando o código, você acabará notando que o Chart Trade, recebe a informação do ativo, vindo da classe C_Terminal. Para ser mais preciso, do procedimento CurrentSymbol. Que se encontra presente na linha 47 da classe C_Terminal.
É neste ponto em que mora o perigo. Principalmente para quem está começando a aprender a programação. Muitos iniciantes, tentarão acessar diretamente este procedimento pelo Expert Advisor. Isto não poderá ser feito, já que o dito procedimento, está na cláusula protected. Assim você pensa: Vou colocar este procedimento na cláusula public. Isto é um erro. O segundo erro, seria: Ao observar o procedimento, você nota que ele não retorna nenhum valor ou argumento. Então você decide modificá-lo para que ele retorne os dados sobre o ativo correto. Mas ao fazer isto, você quebrará totalmente o procedimento. Já que ele pode vir no futuro a mudar a fim de nos permitir fazer mais coisas. Então o mais correto, é NÃO mexer no procedimento presente na linha 47, da classe C_Terminal.
Assim você como iniciante, pode imaginar: Então não tem como solucionar o problema. Já que não existem meios de saber qual o ativo a ser usado. No entanto, esta não é a forma, ou maneira correta de pensar as coisas. Existe sim uma solução. Simples, elegante e barata. Já que não trará efeitos colaterais aos códigos já construídos e testados. Tudo que você precisa fazer é ir no constructor da classe C_Terminal e o modificar. O código original pode ser visto no fragmento logo abaixo.
106. //+------------------------------------------------------------------+ 107. C_Terminal(const long id = 0, const uchar sub = 0) 108. { 109. m_Infos.ID = (id == 0 ? ChartID() : id); 110. m_Mem.AccountLock = false; 111. m_Infos.SubWin = (int) sub; 112. CurrentSymbol(false); 113. ZeroMemory(m_Mouse); 114. m_Mem.Show_Descr = ChartGetInteger(m_Infos.ID, CHART_SHOW_OBJECT_DESCR);
Fragmento original de C_Terminal.mqh
Já a modificação a ser feita é vista logo a seguir.
106. //+------------------------------------------------------------------+ 107. C_Terminal(const long id = 0, const uchar sub = 0, const bool bFull = false) 108. { 109. m_Infos.ID = (id == 0 ? ChartID() : id); 110. m_Mem.AccountLock = false; 111. m_Infos.SubWin = (int) sub; 112. CurrentSymbol(bFull); 113. ZeroMemory(m_Mouse); 114. m_Mem.Show_Descr = ChartGetInteger(m_Infos.ID, CHART_SHOW_OBJECT_DESCR);
Fragmento modificado de C_Terminal.mqh
Perceberam a diferença entre os códigos? Ela é extremamente sútil, simples e elegante. E agora podemos usar a classe C_Terminal a fim de saber, diretamente no Expert Advisor, qual o nome do ativo. Ou podemos passar a informação para o indicador de posição para que ele mesmo faça tal tarefa para nós. De qualquer maneira. Agora o Expert Advisor poderá dizer ao indicador de posição, se deseja mostrar contratos cheios ou mini contratos. Isto usando diretamente o histórico do contrato. Mas você pode pensar que isto será um problema, já que pode entrar em conflito com o que esteja sendo indicado no Chart Trade. Mas não. A informação irá bater exatamente com o que se encontra no Chart Trade.
Então vamos implementar a solução. Como não quero ficar testando as coisas no indicador. Já que o propósito dele é outro. Vamos testar a informação diretamente no Expert Advisor. Assim o código corrigido do Expert Advisor 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.116" 07. #property link "https://www.mql5.com/pt/articles/13168" 08. //+------------------------------------------------------------------+ 09. #include <Market Replay\Order System\C_Orders.mqh> 10. #include <Market Replay\Auxiliar\C_Terminal.mqh> 11. //+------------------------------------------------------------------+ 12. enum eTypeContract {MINI, FULL}; 13. //+------------------------------------------------------------------+ 14. input eTypeContract user00 = MINI; //Cross order in contract 15. //+------------------------------------------------------------------+ 16. C_Orders *Orders = NULL; 17. C_Terminal *Terminal = NULL; 18. //+------------------------------------------------------------------+ 19. int OnInit() 20. { 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 (Terminal != NULL) break; 35. else 36. { 37. ulong ul; 38. Terminal = new C_Terminal(0, 0, user00); 39. for (int handle, count = PositionsTotal() - 1; count >= 0; count--) 40. { 41. ul = PositionGetTicket(count); 42. if (PositionGetString(POSITION_SYMBOL) != (*Terminal).GetInfoTerminal().szSymbol) continue; 43. handle = iCustom(_Symbol, PERIOD_CURRENT, "\\Indicators\\Position View.ex5", ul); 44. ChartIndicatorAdd((*Terminal).GetInfoTerminal().ID, 0, handle); 45. IndicatorRelease(handle); 46. } 47. } 48. case CHARTEVENT_CUSTOM + evChartTrade_At_EA: 49. if (Terminal != NULL) 50. EventChartCustom((*Terminal).GetInfoTerminal().ID, evEA_At_ChartTrade, user00, 0, ""); 51. break; 52. } 53. } 54. //+------------------------------------------------------------------+ 55. void OnDeinit(const int reason) 56. { 57. switch (reason) 58. { 59. case REASON_REMOVE: 60. case REASON_INITFAILED: 61. if (Terminal != NULL) 62. EventChartCustom((*Terminal).GetInfoTerminal().ID, evEA_At_ChartTrade, -1, 0, ""); 63. break; 64. } 65. 66. delete Orders; 67. delete Terminal; 68. } 69. //+------------------------------------------------------------------+
Expert Advisor.mq5
Esta é a beleza na programação. Compare este código visto acima, com os demais códigos do Expert Advisor, mostrados neste artigo. E veja como a programação é uma coisa linda e maravilhosa. Pois usando um pouco de conhecimento sobre ponteiros em C/C++, aqui no MQL5. Foi possível remover uma variável global e deixar apenas declarações de classes. Na verdade seriam ponteiros para classes. Mas tudo bem, o MQL5, não usa ponteiros como no C/C++. Mas mesmo assim, é possível usar um pouco daquilo possível ser feito em C/C++. Se você não consegue, entender o que está acontecendo neste Expert Advisor. Não se preocupe, pois estou aqui, para lhe ajudar a entender este código.
Note que na linha 10, incluímos o arquivo de cabeçalho C_Terminal.mqh, que acabamos de ajustar para os nossos interesses. Na linha 17, declaramos uma variável global, a fim de poder acessar a classe. Porém, apesar de não ser obrigatório, quero deixar explicito o fato de que a variável ponteiro está sendo inicializada como NULL. Se você não colocar isto o compilador irá fazer isto implicitamente. Mas é bom deixar claro o que estamos fazendo.
Ok. Assim que a função OnInit é executada. O MetaTrader 5, irá disparar um evento CHART_CHANGE. Este irá ser capturado pela função OnChartEvent na linha 28, dando início ao tratamento de eventos por parte do Expert Advisor. Na primeira execução desta função, o ponteiro Terminal estará com o valor NULL. Assim sendo, a linha 34 irá falhar, permitindo que a linha 35 seja executada. Neste ponto começa a mágica. Observe que o código neste ponto se parece em muito com o código visto anteriormente no Exepert Advisor. Porém, na linha 38, inicializamos o constructor da classe C_Terminal. Dizendo a ele, se estaremos usando um ou outro tipo de contrato.
Ao fazer isto, o constructor irá produzir para nós, o nome correto do ativo. Assim na linha 41, capturamos o valor do ticket. Precisamos fazer isto antes de chamar outras funções para capturar dados da posição. Isto é mencionado na documentação do MQL5, estude a mesma para mais detalhes. Depois disto, já podemos na linha 42, verificar se o nome do ativo na qual a posição foi encontrada, é o mesmo que esperado pelo Expert Advisor. Se não for o caso, iremos retornar para a linha 39. Caso contrário, ou seja, o ativo tendo o nome esperado. fazemos a chamada ao indicador de posição, assim como era feito antes.
Agora quero que você observe a linha 49 e 61. E responda: Por que estou fazendo um teste nestas linhas? Pense um pouco antes de ler a resposta que darei a seguir. Bem, espero que você tenha pelo menos tentado antes de ler a resposta. Pois o motivo de estas linhas existirem, é justamente para melhorar a confiabilidade do código do Expert Advisor. Se você tentar usar uma chamada a alguma função ou procedimento contido na classe C_Terminal. Antes mesmo da classe ter sido corretamente inicializada. O teste para verificar se o valor no ponteiro é NULL impedirá que o Expert Advisor, simplesmente lance um valor de falha no terminal do MetaTrader 5. Fazendo tal testagem, você garante que tudo estará perfeitamente como esperado.
Muitos programadores, de C/C++, mas principalmente em C. Não costumam fazer tais testes, ao usar ponteiros. E por conta disto, a linguagem C é considerada por muitos, como uma linguagem que os programas contêm muitos erros, quando executados. Porém tais erros não se devem a linguagem em si. Mas se deve a forma como o programa foi escrito. Ou por que motivo ele foi escrito daquela maneira. Já que em alguns casos, é intencional fazer programas que procurem alguma brecha no sistema, a fim de fazer algo não planejado pelo proprietário do sistema.
Considerações finais
Neste artigo, começamos a unir diversas coisas, ou aplicações que antes estavam complemente isoladas entre si. Apesar de que o Chart Trade, o Indicador de Mouse e o Expert Advisor, já tinham algum tipo de relacionamento. Não havia ainda uma forma de podermos observar, posições que estivessem abertas no servidor de negociação, diretamente no gráfico. Isto muitas das vezes fazendo uso de um sistema de cross order. Mas a partir deste momento isto começa a se tornar possível. Abrindo diversas portas para novas ideias e implementações. Se bem que estamos apenas começando a fazer as coisas acontecerem. Mas já temos uma direção a qual seguir.
Apesar de à primeira vista este sistema ser muito primitivo, e podendo ter sido apresentado em um estágio mais avançado no desenvolvimento. Não achei prudente fazer tal coisa. Já que isto deixaria muitos iniciantes ou entusiastas sem de fato compreender o que estaria acontecendo de fato no código. Notem que as mudanças estão acontecendo aos poucos para que todos possam acompanhar. Este material tem como finalidade ser didático. E não de fato mostrar a única forma de se fazer algo no MetaTrader 5. Espero que todo este material esteja ajudando a quem realmente esteja procurando conhecimento. E no próximo artigo, continuaremos a desenvolver ainda mais o que foi visto aqui. Então até breve.
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) |
Indicators\Order Indicator.mq5 | Responsável pela indicação de ordens de mercado, permitindo interação e controle das mesmas |
Indicators\Position View.mq5 | Responsável pela indicação de posições de mercado, permitindo interação e controle das mesmas |
Services\Market Replay.mq5 | Cria e mantém 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