
Simulação de mercado: Position View (VI)
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 (V), expliquei como você pode fazer para conseguir os dados necessários, a fim de conseguir entender o que está acontecendo em uma aplicação. Isto para que venha a ser possível implementar o sistema, fazendo uso da função OnTradeTransaction. Pois bem, ali foi apresentado apenas a forma de fazer isto no Expert Advisor. Mas olhando aqueles dados, e vendo o Expert Advisor. Você, meu caro leitor, certamente deve ter ficado bastante confuso e desconfiado se aquilo de fato é prático. Bem, um pouco de ceticismo não faz mal algum. Na verdade é até mesmo aconselhável e saudável, que tenhamos um pouco de dúvidas, ao nos depararmos com algo completamente novo.
Assim sendo, neste artigo, implementaremos os primeiros passos. Isto de modo, que aqueles mesmos dados, vistos no artigo anterior, possam e venham a fazer algum sentido. Como o que veremos é algo, que à primeira vista pode ser um pouco confuso. Quero que você procure estudar com calma este artigo depois. Fazendo testes a fim de tentar compreender o que será explicado. Não, faça em hipótese alguma, uso do que iremos ver neste artigo, em uma conta real. Isto sem de fato ter compreendido o que está acontecendo. Já que as possibilidades de perdas e falhas em interpretar os dados que serão fornecidos no gráfico. Podem vir a fazer você ter uma grande e desagradável experiência com este sistema que estamos montando.
Então novamente: Não use este sistema que montaremos, sem de fato entender o que está acontecendo. E para isto, experimente e estude bastante o código. Já que aqui ele tem como finalidade ser o mais didático possível. A eficiência no caso é apenas um detalhe. A premissa principal é que o código seja o mais simples possível. Para que todos consigam entender o que está ocorrendo.
Entendendo o que faremos
Muitos de vocês, devem e muito provavelmente estejam acostumados a sempre ver ou fazer o mesmo tipo de coisa. Não que esteja errado fazer assim. Mas se podemos fazer diferente. Porque não tentar. E é justamente este o ponto a ser entendido aqui. A tarefa principal de um Expert Advisor, não é colocar objetos no gráfico, ou ficar fazendo cálculos. Você pode até pode fazer assim. Não é errado. Mas a principal tarefa de um Expert Advisor, é construir um meio de nos comunicar adequadamente com o servidor de negociação. Por isto que somente podemos colocar um único Expert Advisor em cada gráfico. Porém, colocar no Expert Advisor, coisas como, adicionar objetos ou manipular estes mesmos objetos no gráfico. Não é algo assim tão adequado.
Novamente, vou reforçar isto: Não que seja errado implementar em um Expert Advisor tais coisas. Mas pense, no fato de que você pode ter mais de um Expert Advisor, implementado. Cada um voltado a ser utilizado em um dado tipo de cenário, ou mercado. Não é muito prático que você coloque tudo em um único código. Já que se você decidir colocar um sistema de visualização de posições em cada Expert Advisor. Ao aperfeiçoar este mesmo sistema em um outro Expert Advisor, você acabará por ficar um pouco descontente quando for usar a versão anterior. Já que o código terá de ser transferido entre cada um dos Expert Advisores existentes.
Por isto, estou propondo o uso de um indicador para isto. Mas o indicador, como você já deve ter notado, nestes últimos artigos, não consegue fazer certas coisas. E não é possível, ou aconselhável que você tente forçar o indicador a fazer determinadas tarefas. Mas podemos perfeitamente criar um indicador que nos permita ter no gráfico a visualização de posições abertas. Mas precisamos de alguma forma criar mecanismos que tornem possível usar os indicadores de uma maneira mais sustentável e menos confusa.
Um destes mecanismos é a passagem de mensagens entre o indicador e o Expert Advisor. Já estamos a algum tempo, fazendo uso de tal mecanismo. Isto por que o indicador Chart Trade, assim como o indicador de mouse. Fazem uso exatamente deste mesmo mecanismo para se comunicar com o Expert Advisor. Mas ainda não criamos. Ou melhor não começamos a desenvolver este mesmo mecanismo para permitir que o indicador de posição, possa se comunicar com o Expert Advisor.
Um pequeno aperfeiçoamento
A primeira coisa que precisamos de fato fazer, é colocar o Expert Advisor, com a capacidade de poder, sempre que uma nova posição venha a ser aberta. Adicionar um indicador de posição no gráfico. Tal coisa é relativamente simples de ser feita. Já que podemos usar o mesmo mecanismo usado quando o Expert Advisor é colocado no gráfico. Se você observar os artigos anteriores. Irá notar que, no momento que o Expert Advisor é colocado no gráfico, ele procurará entre as posições abertas, qual corresponde ao critério indicado e esperado por ele. Isto para que o Expert Advisor, possa colocar adequadamente um indicador de posição no gráfico.
E como foi visto, nos artigos anteriores. Quando o Expert Advisor é removido do gráfico, por qualquer motivo, ele removerá os indicadores de posição colocados no gráfico. Ok. Isto ocorrerá sem problemas caso o Expert Advisor seja removido adequadamente. No caso de um crash no programa. Tal remoção não ocorrerá. Assim quando o Expert Advisor, for recolocado no gráfico, podemos ter algum tipo de resíduo que deverá ser removido do gráfico. Tal resíduo, é justamente o indicador de posição. Lembre-se de uma coisa: O que estamos fazendo, será assumir que o operador, não mexeu em nenhum elemento no gráfico. Ele apenas viu o Expert Advisor, sair do gráfico, deixando algum indicador de posição no gráfico.
Então quando o operador vier a recolocar o Expert Advisor novamente no gráfico. Ele pode ter mudado alguma coisa no cenário. Ou melhor dizendo. Antes do crash, o Expert Advisor, tinha sido orientado a observar mini contratos. Porém quando o operador volta com ele, o Expert Advisor, para o gráfico, ele poderá estar orientado a observar contratos cheios. Porém, algum indicador de posição, que havia no gráfico, estava mostrando uma posição de mini contrato. Neste momento poderemos ter problemas. Por conta disto, e para evitar tal coisa, precisamos mexer, ou melhor adicionar uma linha de código no sistema de inicialização do Expert Advisor. Isto para que ele limpe, possíveis indicadores residuais.
Fazer tal coisa é muito simples e direto. No fragmento abaixo, você pode ver como isto é conseguido.
15. //+------------------------------------------------------------------+ 16. C_Orders *Orders; 17. C_Terminal *Terminal; 18. //+------------------------------------------------------------------+ 19. int OnInit() 20. { 21. Terminal = NULL; 22. Orders = new C_Orders(0xC0DEDAFE78514269); 23. 24. return INIT_SUCCEEDED; 25. } 26. //+------------------------------------------------------------------+ 27. void OnTick() {} 28. //+------------------------------------------------------------------+ 29. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 30. { 31. int handle; 32. 33. (*Orders).DispatchMessage(id, lparam, dparam, sparam); 34. switch (id) 35. { 36. case CHARTEVENT_CHART_CHANGE: 37. if (Terminal != NULL) break; 38. else 39. { 40. ulong ul; 41. Terminal = new C_Terminal(0, 0, user00); 42. for (int count = PositionsTotal() - 1; count >= 0; count--) 43. { 44. ul = PositionGetTicket(count); 45. if (PositionGetString(POSITION_SYMBOL) != (*Terminal).GetInfoTerminal().szSymbol) 46. { 47. ChartIndicatorDelete(0, 0, IntegerToString(ul)); 48. continue; 49. } 50. handle = iCustom(NULL, PERIOD_CURRENT, "\\Indicators\\Position View.ex5", ul); 51. ChartIndicatorAdd(0, 0, handle); 52. IndicatorRelease(handle); 53. } 54. } 55. case CHARTEVENT_CUSTOM + evChartTrade_At_EA: 56. EventChartCustom(0, evEA_At_ChartTrade, user00, 0, ""); 57. break; 58. } 59. } 60. //+------------------------------------------------------------------+
Fragmento do código do Expert Advisor
Observe justamente a linha 47 neste fragmento acima. Ela é justamente a responsável por evitar justamente o que acabamos de descrever acima. Ou seja, quando o Expert Advisor volta a ser colocado no gráfico, ele removerá, usando justamente esta linha 47. Os antigos indicadores que possivelmente, não correspondam ao critério de inicialização. Ou seja, se o operador mudar o tipo de contrato. O Expert Advisor notará isto, e removerá os indicadores de posição que não corresponderem ao esperado. Se o indicador corresponder ao tipo de contrato. Tudo bem, nada acontecerá com ele. No máximo ele retornará um erro para o Expert Advisor. Mas tal erro é perfeitamente admissível e podemos ignorar o mesmo.
Muito bem. Agora já temos alguma consistência nas informações que poderão estar de fato presentes no gráfico. Podemos passar para a próxima etapa. E esta envolve envio de mensagens entre o Expert Advisor e o indicador de posição.
Implementando a comunicação entre o Expert Advisor e o Indicador de posição
Neste momento, começaremos a implementar as primeiras trocas de informações, entre estas duas aplicações. Como toda troca de mensagens envolve um grande número de coisas a serem vistas. Faremos isto aos poucos. Começando pelo mais básico e nos aprofundando cada vez mais. Até conseguirmos um indicador de posição totalmente funcional.
Como o nosso indicador de posição neste momento, somente conta com as linhas horizontais. Os tais objetos HLINE. Não precisamos de muitas mensagens sendo repassadas. Mas precisamos fazer algumas coisas extras no código. Começando pelo arquivo de cabeçalho Defines.mqh, que pode ser visto logo abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #define def_VERSION_DEBUG 05. //+------------------------------------------------------------------+ 06. #ifdef def_VERSION_DEBUG 07. #define macro_DEBUG_MODE(A) \ 08. Print(__FILE__, " ", __LINE__, " ", __FUNCTION__ + " " + #A + " = " + (string)(A)); 09. #else 10. #define macro_DEBUG_MODE(A) 11. #endif 12. //+------------------------------------------------------------------+ 13. #define def_SymbolReplay "RePlay" 14. #define def_MaxPosSlider 400 15. #define def_MaskTimeService 0xFED00000 16. #define def_IndicatorTimeFrame (_Period < 60 ? _Period : (_Period < PERIOD_D1 ? _Period - 16325 : (_Period == PERIOD_D1 ? 84 : (_Period == PERIOD_W1 ? 91 : 96)))) 17. #define def_IndexTimeFrame 4 18. //+------------------------------------------------------------------+ 19. union uCast_Double 20. { 21. double dValue; 22. long _long; // 1 Information 23. datetime _datetime; // 1 Information 24. uint _32b[sizeof(double) / sizeof(uint)]; // 2 Informations 25. ushort _16b[sizeof(double) / sizeof(ushort)]; // 4 Informations 26. uchar _8b [sizeof(double) / sizeof(uchar)]; // 8 Informations 27. }; 28. //+------------------------------------------------------------------+ 29. enum EnumEvents { 30. evTicTac, //Event of tic-tac 31. evHideMouse, //Hide mouse price line 32. evShowMouse, //Show mouse price line 33. evHideBarTime, //Hide bar time 34. evShowBarTime, //Show bar time 35. evHideDailyVar, //Hide daily variation 36. evShowDailyVar, //Show daily variation 37. evHidePriceVar, //Hide instantaneous variation 38. evShowPriceVar, //Show instantaneous variation 39. evCtrlReplayInit, //Initialize replay control 40. evChartTradeBuy, //Market buy event 41. evChartTradeSell, //Market sales event 42. evChartTradeCloseAll, //Event to close positions 43. evChartTrade_At_EA, //Event to communication 44. evEA_At_ChartTrade, //Event to communication 45. evChatWriteSocket, //Event to Mini Chat 46. evChatReadSocket, //Event To Mini Chat 47. evUpdate_Position //Event to communication 48. }; 49. //+------------------------------------------------------------------+ 50. enum EnumPriority { //Priority list on objects 51. ePriorityNull = -1, 52. ePriorityDefault = 0, 53. ePriorityChartTrade = 5, 54. ePriorityOrders = 10 55. }; 56. //+------------------------------------------------------------------+
Defines.mqh
Neste arquivo, adicionamos uma nova enumeração, que será o evento, cujo objetivo é promover uma chamada de atualização do indicador de posição. Tal evento se encontra definido na linha 47. Feito isto, podemos ir para o código do Expert Advisor. O código completo do Expert Advisor, pode ser visto na íntegra logo abaixo.
001. //+------------------------------------------------------------------+ 002. #property copyright "Daniel Jose" 003. #property icon "/Images/Market Replay/Icons/Replay - EA.ico" 004. #property description "Demo version between interaction" 005. #property description "of Chart Trade and Expert Advisor" 006. #property version "1.118" 007. #property link "https://www.mql5.com/pt/articles/13203" 008. //+------------------------------------------------------------------+ 009. #include <Market Replay\Order System\C_Orders.mqh> 010. #include <Market Replay\Auxiliar\C_Terminal.mqh> 011. //+------------------------------------------------------------------+ 012. enum eTypeContract {MINI, FULL}; 013. //+------------------------------------------------------------------+ 014. input eTypeContract user00 = MINI; //Cross order in contract 015. //+------------------------------------------------------------------+ 016. C_Orders *Orders; 017. C_Terminal *Terminal; 018. //+------------------------------------------------------------------+ 019. int OnInit() 020. { 021. Terminal = NULL; 022. Orders = new C_Orders(0xC0DEDAFE78514269); 023. 024. return INIT_SUCCEEDED; 025. } 026. //+------------------------------------------------------------------+ 027. void OnTick() {} 028. //+------------------------------------------------------------------+ 029. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 030. { 031. int handle; 032. 033. (*Orders).DispatchMessage(id, lparam, dparam, sparam); 034. switch (id) 035. { 036. case CHARTEVENT_CHART_CHANGE: 037. if (Terminal != NULL) break; 038. else 039. { 040. ulong ul; 041. Terminal = new C_Terminal(0, 0, user00); 042. for (int count = PositionsTotal() - 1; count >= 0; count--) 043. { 044. ul = PositionGetTicket(count); 045. if (PositionGetString(POSITION_SYMBOL) != (*Terminal).GetInfoTerminal().szSymbol) 046. { 047. ChartIndicatorDelete(0, 0, IntegerToString(ul)); 048. continue; 049. } 050. handle = iCustom(NULL, PERIOD_CURRENT, "\\Indicators\\Position View.ex5", ul); 051. ChartIndicatorAdd(0, 0, handle); 052. IndicatorRelease(handle); 053. } 054. } 055. case CHARTEVENT_CUSTOM + evChartTrade_At_EA: 056. EventChartCustom(0, evEA_At_ChartTrade, user00, 0, ""); 057. break; 058. } 059. } 060. //+------------------------------------------------------------------+ 061. void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result) 062. { 063. if (Terminal == NULL) return; 064. static ulong ticket = 0; 065. switch (trans.type) 066. { 067. case TRADE_TRANSACTION_HISTORY_ADD: 068. ticket = (trans.order != trans.position ? trans.position : 0); 069. break; 070. case TRADE_TRANSACTION_REQUEST: 071. if ((request.symbol == (*Terminal).GetInfoTerminal().szSymbol) && (result.retcode == TRADE_RETCODE_DONE)) switch (request.action) 072. { 073. case TRADE_ACTION_DEAL: 074. if (ticket) EventChartCustom(0, evUpdate_Position, ticket, 0, ""); 075. else 076. { 077. int handle = iCustom(NULL, PERIOD_CURRENT, "\\Indicators\\Position View.ex5", result.order); 078. ChartIndicatorAdd(0, 0, handle); 079. IndicatorRelease(handle); 080. } 081. ticket = 0; 082. break; 083. case TRADE_ACTION_SLTP: 084. EventChartCustom(0, evUpdate_Position, request.position, 0, ""); 085. break; 086. } 087. break; 088. }; 089. } 090. //+------------------------------------------------------------------+ 091. void OnDeinit(const int reason) 092. { 093. ulong ul; 094. 095. switch (reason) 096. { 097. case REASON_REMOVE: 098. case REASON_INITFAILED: 099. EventChartCustom(0, evEA_At_ChartTrade, -1, 0, ""); 100. break; 101. } 102. if (Terminal != NULL) for (int count = PositionsTotal() - 1; count >= 0; count--) 103. { 104. ul = PositionGetTicket(count); 105. if (PositionGetString(POSITION_SYMBOL) != (*Terminal).GetInfoTerminal().szSymbol) continue; 106. ChartIndicatorDelete(0, 0, IntegerToString(ul)); 107. } 108. delete Orders; 109. delete Terminal; 110. } 111. //+------------------------------------------------------------------+
Expert Advisor.mq5
Grande parte deste código, já foi explicado anteriormente. Então deveremos de fato focar no que é novidade aqui. Ou seja, a função OnTradeTransaction. Por enquanto, não se preocupe com algumas coisas, que talvez você não esteja compreendendo neste momento. Explicarei as coisas com calma, e aos poucos. Mas o que quero chamar a sua atenção aqui, é para a presença da função EventChartCustom. Isto nas linhas 74 e 84. Estas linhas são justamente as que tornam possível, ao Expert Advisor, comunicar ao Indicador de posição, que algo ocorreu. E que o indicador de posição precisa ser atualizado.
Não se preocupe por enquanto como isto será feito no indicador. Apenas veja quando o Expert Advisor, toma a atitude de informar ao indicador que ele precisa ser atualizado. Para entender melhor isto, é preciso entender justamente o que foi visto no artigo anterior. Se você tiver alguma dúvida com relação a alguma informação. Veja no artigo anterior, como você pode buscar as informações necessárias, para que as coisas façam algum sentido.
Mas aqui estamos tratado, três situações distintas. A primeira situação acontece quando, via indicador Chart Trade, pedimos para que o Expert Advisor, efetue uma compra ou venda a mercado. Quando isto for feito, teremos o valor da variável estática ticket, um valor igual a zero. O motivo é que a linha 68 conterá valores idênticos para trans.order e trans.position. Ok. Assim quando o servidor reportar um TRADE_TRANSACTION_REQUEST, teremos um tratamento adequado do que foi feito. Lembre-se: Ainda estamos abrindo a posição. Desta forma, quando TRADE_ACTION_DEAL, for disparada pelo servidor, o teste na linha 74 falhará. Isto por que a variável ticket está como zero. Então teremos a execução, do código entre as linhas 76 e 80. Observe que ele é o mesmo código usado na inicialização do Expert Advisor. Tendo como finalidade dizer ao MetaTrader 5, que desejamos colocar um indicador de posição no gráfico.
No final, como não sabemos o motivo do disparo de TRADE_ACTION_DEAL, tornamos a variável ticket, novamente em zero. Fim de jogo. O indicador de posição aparecerá no gráfico, dando as mesmas informações que você veria, se tivéssemos auxilio do MetaTrader 5, neste caso. Lembrando mais uma vez. O MetaTrader 5, não consegue cobrir de maneira adequada sistema de ordens cruzadas, o tal cross order. Por conta disto, quando vamos fazer uso de tal modelo de operação, precisamos criar uma forma de indicar as coisas no gráfico. E é para isto que o indicador de posição serve.
Muito bem, a nossa posição foi criada e se encontra no gráfico. Depois de algum tempo, o operador decide, que é hora de aumentar a posição. Então ele, usando novamente o indicador Chart Trade, pede para que o volume da posição aumente. Aqui mora uma questão. Em contas do tipo HEDGING, esta nova entrada, ou pedido de aumento de uma posição, não fará com que o volume de fato mude. O que acontece de fato, é que uma nova posição será aberta. Como não fazemos uma distinção entre uma conta HEDGING e uma NETTING. O que acontece, ao fazermos um pedido de aumento do volume em uma conta HEDGING. É justamente o que acabei de explicar, no caso de se abrir uma posição. Porém, ao fazermos o mesmo tipo de pedido. Ou seja, um aumento de posição em uma conta NETTING, a coisa irá ser um pouco diferente. Neste caso, quando o servidor disparar uma TRADE_TRANSACTION_HISTORY_ADD, teremos valores diferentes entre trans.order e trans.position. Quando isto acontece, é por que algo aconteceu na posição que se encontra aberta. Assim o valor da variável ticket, já não será igual a zero. Neste caso ela será o valor da posição afetada. Em um dado momento, o servidor disparará uma TRADE_TRANSACTION_REQUEST em resposta ao pedido efetuado.
Quando isto ocorrer, e tivermos o disparo de um TRADE_ACTION_DEAL. O teste na linha 74 irá ter sucesso. Neste momento, será disparado um evento customizado, dizendo ao indicador de posição que ele deverá ser atualizado. Note que não direcionamos o evento a um indicador ou aplicação em específico. Todas as aplicações que estão no gráfico, receberam este mesmo evento customizado. Porém, como estamos filtrando, isto dentro de cada aplicação. Acaba que apenas o indicador, ou aplicação correta entenderá a mensagem. O trabalho do Expert Advisor, termina neste ponto. Ele de fato, não faz ideia de que o indicador de posição, irá ou não entender o recado. Ou mesmo se o indicador esteja de fato no gráfico. Para o Expert Advisor isto pouco importa. Ele fez a sua tarefa e pronto. A mesma coisa acontece, quando você mudar os valores de take profit e stop loss de uma posição. Só que neste caso, teremos a execução do evento TRADE_ACTION_SLTP, que é visto na linha 83. Note que na linha 84, fazemos o mesmo tipo de coisa feito quando temos um aumento da posição. Ou uma realização parcial de um dado volume. Isto considerando o fato de você está usando um conta do tipo NETTING. Legal.
Mas o que acontece quando uma posição é encerrada? Acredito, que você, meu caro leitor, obviamente esperaria ver um código, aqui no Expert Advisor, que estaria removendo o indicador de posição no gráfico. Mas não é bem isto que pode ser visto no código do Expert Advisor. Mas então como ele consegue remover o indicador do gráfico? Simples. Ele faz a mesma coisa que é feita na mudança de volume em contas NETTING. Ou seja, iremos ter na linha 68, um valor diferente entre trans.order e trans.position. Com isto o teste na linha 74 terá sucesso. Enviando assim um pedido para que o indicador seja atualizado. Mas como a posição foi fechada o indicador irá ser removido do gráfico. Mas para de fato entender isto em plenitude, precisamos ver o código o Indicador de posição. E para separar as coisas, vamos ver isto em um novo tópico.
Indicador de posição aperfeiçoado
Muito bem, como você, meu caro leitor, deve saber, o código do Indicador de posição, no momento é composto de duas partes. A primeira pode ser observada na íntegra logo abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property icon "/Images/Market Replay/Icons/Positions.ico" 04. #property description "Indicator for tracking an open position on the server." 05. #property description "This should preferably be used together with an Expert Advisor." 06. #property description "For more details see the same article." 07. #property version "1.118" 08. #property link "https://www.mql5.com/pt/articles/13203" 09. #property indicator_chart_window 10. #property indicator_plots 0 11. //+------------------------------------------------------------------+ 12. #define def_ShortName "Position View" 13. //+------------------------------------------------------------------+ 14. #include <Market Replay\Order System\C_IndicatorPosition.mqh> 15. #include <Market Replay\Defines.mqh> 16. //+------------------------------------------------------------------+ 17. input ulong user00 = 0; //For Expert Advisor use 18. input color user01 = clrRoyalBlue; //Color Line Price 19. input color user02 = clrForestGreen; //Color Line Take Profit 20. input color user03 = clrFireBrick; //Color Line Stop Loss 21. //+------------------------------------------------------------------+ 22. C_IndicatorPosition *Positions = NULL; 23. //+------------------------------------------------------------------+ 24. int OnInit() 25. { 26. IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName); 27. Positions = new C_IndicatorPosition(user01, user02, user03); 28. if (!Positions.CheckCatch(user00)) 29. { 30. ChartIndicatorDelete(0, 0, def_ShortName); 31. return INIT_FAILED; 32. } 33. 34. return INIT_SUCCEEDED; 35. } 36. //+------------------------------------------------------------------+ 37. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 38. { 39. return rates_total; 40. } 41. //+------------------------------------------------------------------+ 42. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 43. { 44. (*Positions).DispatchMessage(id, lparam, dparam, sparam); 45. }; 46. //+------------------------------------------------------------------+ 47. void OnDeinit(const int reason) 48. { 49. delete Positions; 50. } 51. //+------------------------------------------------------------------+
Position View.mq5
Este sendo o código principal do indicador. Note que basicamente a única coisa que temos aqui de diferente é a função OnChartEvent. Como precisamos de algumas informações que são privativas da classe C_IndicatorPosition. Não fazemos nada neste código principal. Mas simplesmente fazemos uma chamada ao procedimento DispatchMessage. Então apenas observando este código daqui. Não temos como entender como a comunicação com o Expert Advisor. Assim vamos então olhar o arquivo de cabeçalho C_IndicatorPosition.mqh, que pode ser visto 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. string szShortName; 17. }m_Infos; 18. //+------------------------------------------------------------------+ 19. inline void MoveLineInfos(string szObjName, const double price) 20. { 21. szObjName = m_Infos.szShortName + szObjName; 22. if (price <= 0) ObjectDelete(0, szObjName); 23. else ObjectSetDouble(0, szObjName, OBJPROP_PRICE, price); 24. } 25. //+------------------------------------------------------------------+ 26. void CreateLineInfos(string szObjName, const color cor, const string szDescription = "\n") 27. { 28. szObjName = m_Infos.szShortName + szObjName; 29. CreateObjectGraphics(szObjName, OBJ_HLINE, cor, (EnumPriority)(cor == m_Infos.corPrice ? ePriorityNull : (ePriorityOrders + (cor == m_Infos.corStop)))); 30. ObjectSetString(0, szObjName, OBJPROP_TEXT, szDescription); 31. ObjectSetString(0, szObjName, OBJPROP_TOOLTIP, szDescription); 32. ObjectSetInteger(0, szObjName, OBJPROP_SELECTABLE, cor != m_Infos.corPrice); 33. } 34. //+------------------------------------------------------------------+ 35. public : 36. //+------------------------------------------------------------------+ 37. C_IndicatorPosition(color corPrice, color corTake, color corStop) 38. :C_Terminal() 39. { 40. ZeroMemory(m_Infos); 41. m_Infos.corPrice = corPrice; 42. m_Infos.corTake = corTake; 43. m_Infos.corStop = corStop; 44. } 45. //+------------------------------------------------------------------+ 46. ~C_IndicatorPosition() 47. { 48. if (m_Infos.ticket != 0) 49. ObjectsDeleteAll(0, IntegerToString(m_Infos.ticket)); 50. } 51. //+------------------------------------------------------------------+ 52. bool CheckCatch(ulong ticket) 53. { 54. m_Infos.szShortName = IntegerToString(m_Infos.ticket = ticket); 55. if (!PositionSelectByTicket(m_Infos.ticket)) return false; 56. if (ObjectFind(0, m_Infos.szShortName) >= 0) 57. { 58. m_Infos.ticket = 0; 59. return false; 60. } 61. IndicatorSetString(INDICATOR_SHORTNAME, m_Infos.szShortName); 62. CreateLineInfos(NULL, m_Infos.corPrice, "Position opening price."); 63. CreateLineInfos(def_SufixTake, m_Infos.corTake, "Take Profit point."); 64. CreateLineInfos(def_SufixStop, m_Infos.corStop, "Stop Loss point."); 65. EventChartCustom(0, evUpdate_Position, ticket, 0, ""); 66. 67. return true; 68. } 69. //+------------------------------------------------------------------+ 70. void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) 71. { 72. switch (id) 73. { 74. case CHARTEVENT_CUSTOM + evUpdate_Position: 75. if (lparam != m_Infos.ticket) return; 76. if (!PositionSelectByTicket(m_Infos.ticket)) 77. { 78. ChartIndicatorDelete(0, 0, m_Infos.szShortName); 79. return; 80. }; 81. MoveLineInfos(NULL, PositionGetDouble(POSITION_PRICE_OPEN)); 82. MoveLineInfos(def_SufixTake, PositionGetDouble(POSITION_TP)); 83. MoveLineInfos(def_SufixStop, PositionGetDouble(POSITION_SL)); 84. break; 85. } 86. } 87. //+------------------------------------------------------------------+ 88. }; 89. //+------------------------------------------------------------------+ 90. #undef def_SufixTake 91. #undef def_SufixStop 92. //+------------------------------------------------------------------+
C_IndicatorPosition.mqh
Apesar de você, caro leitor, poder imaginar que as coisas deveriam ser feitas de uma maneira. Aqui neste código iremos fazer as coisas de uma forma um pouco diferente do que muitos pensam ser o mais usual. Basicamente, neste momento, não fiz muitas mudanças no código. Mas você pode notar que existem coisas diferentes aqui. Para começar na linha 19, temos um novo procedimento. Este visa mudar o ponto onde a linha horizontal do preço se encontra. Não existe muita coisa a ser dita neste procedimento. Isto pelo fato de que quando o preço é igual a zero ou negativo, teremos a remoção do objeto linha. Isto é feito na linha 22 do código acima.
Porém, vale lembrar que apesar de normalmente não termos a possibilidade de um preço negativo. Isto não se aplica a índices, ou melhor dizendo: Quando você usa uma combinação de dois ou mais valores, de modo a gerar um novo valor. Pode sim ocorrer valores negativos. Mas tal valor não se refere a um preço negativo. E sim a um índice ou relação negativa. Caso você esteja tendo problemas, por estar usando um gráfico de relação entre valores. Você precisará ajustar este indicador de posição. Pois no momento, não estamos focados em fazer ele trabalhar com relações e sim com preços. Mas futuramente irei mostrar como podemos trabalhar com relações no MetaTrader 5.
Mas uma coisa de cada vez. Primeiro vamos ver como fazer este indicador de posição funcionar. Ok, caso o preço seja válido, iremos na linha 23, dizer ao objeto HLINE onde ele deverá ficar. Simples assim. Agora, vamos ver algo curioso na função da linha 52. Observe que na linha 65 temos um lançamento de evento customizado. Mas por que? O motivo é programe uma vez e teste sempre. Como este indicador irá receber mensagens, ou eventos customizados. Podemos fazer com que ele ao ser colocado no gráfico, também tenha o mesmo comportamento, de quando receber um pedido de atualização do Expert Advisor.
Como eu informei no tópico anterior, o Expert Advisor, não irá verificar se o indicador de posição fez ou não seu trabalho. Ele simplesmente lança o evento e vai cuidar de outras coisas. Depende do indicador de posição fazer todo o restante do trabalho. Por isto é bom, ter uma certa metodologia em termos de implementação. Já que se o indicador de posição, fizer o seu trabalho, ao ser colocado manualmente no gráfico. Porém não esteja conseguindo entender o que o Expert Advisor está querendo. Você logo poderá concluir, que existe uma falha de comunicação, entre o Expert Advisor e o Indicador. Já que os eventos estarão sendo tratados adequadamente quando o Indicador é colocado manualmente no gráfico.
Assim, da mesma maneira que o Expert Advisor, lança um evento para que o indicador de posição efetue a sua tarefa. O indicador de posição ao checar se pode ou não ser colocado no gráfico. Também fará um lançamento, do mesmo tipo de evento. Desta maneira, em ambas situações teremos a chamada da linha 70 no código mostrado acima.
Este código da linha 70 é bem interessante. Isto por que, no momento, estamos apenas nos preocupando em tratar de um único evento. O evento evUpdate_Position, que tem seu tratamento iniciado na linha 74. Pois bem, na linha 75, verificamos se o bilhete da posição informada na chamada do evento é o mesmo esperado pelo indicador. Se eles forem diferentes encerramos aqui. É importante verificar se o bilhete é o mesmo, pois a mensagem de evento é enviada a todas as aplicações presentes no gráfico. Então fazer a correta filtragem as coisas, antes de sair usando os dados é importante. Uma vez filtrado, podemos verificar na linha 76, se a posição existe. Lembre-se: O Expert Advisor não diz se estamos atualizando, fechando ou abrindo uma nova posição. Ele apenas diz: Indicador de posição, tenho algo para você. Faça o que for preciso ser feito. E somente isto.
Todo resto, é de responsabilidade do indicador fazer e verificar o que deve ser feito. Se a posição não existe, na linha 78 encerramos o indicador. E ele será removido do gráfico. Mas se a posição está sendo criada, ou está sendo atualizada, termos a movimentação das linhas de preço. Isto é feito nas linhas 81 a 83. E é assim que as coisas funcionam. Porém, este mesmo código visto acima, tem um problema. Mas é preciso que você o entenda antes de tentar entender o próximo que é visto no próximo tópico.
Mas precisa ser assim?
No código da classe C_IndicatorPosition, visto acima, temos um problema. Na verdade é mais um incomodo do que um problema. O detalhe é que se você remover ou não colocar as linhas de stop loss e take profit. E depois de um tempo, decidir as colocar no gráfico. Atualizando assim a posição, não poderá fazer isto diretamente. Isto por que a classe vista acima não consegue fazer isto. Porém, com poucas mudanças no código. Podemos começar a fazer isto. Tais mudanças são vistas no código 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. string szShortName; 17. }m_Infos; 18. //+------------------------------------------------------------------+ 19. inline void MoveLineInfos(const string szDefine, const double price) 20. { 21. string szName = m_Infos.szShortName + szDefine; 22. if (price <= 0) ObjectDelete(0, szName); 23. else 24. { 25. if (ObjectFind(0, szName) < 0) 26. { 27. if (szDefine == def_SufixTake) CreateLineInfos(def_SufixTake, m_Infos.corTake, "Take Profit point."); else 28. if (szDefine == def_SufixStop) CreateLineInfos(def_SufixStop, m_Infos.corStop, "Stop Loss point."); else 29. CreateLineInfos(NULL, m_Infos.corPrice, "Position opening price."); 30. } 31. ObjectSetDouble(0, szName, OBJPROP_PRICE, price); 32. } 33. } 34. //+------------------------------------------------------------------+ 35. void CreateLineInfos(string szObjName, const color cor, const string szDescription = "\n") 36. { 37. szObjName = m_Infos.szShortName + szObjName; 38. CreateObjectGraphics(szObjName, OBJ_HLINE, cor, (EnumPriority)(cor == m_Infos.corPrice ? ePriorityNull : (ePriorityOrders + (cor == m_Infos.corStop)))); 39. ObjectSetString(0, szObjName, OBJPROP_TEXT, szDescription); 40. ObjectSetString(0, szObjName, OBJPROP_TOOLTIP, szDescription); 41. ObjectSetInteger(0, szObjName, OBJPROP_SELECTABLE, cor != m_Infos.corPrice); 42. } 43. //+------------------------------------------------------------------+ 44. public : 45. //+------------------------------------------------------------------+ 46. C_IndicatorPosition(color corPrice, color corTake, color corStop) 47. :C_Terminal() 48. { 49. ZeroMemory(m_Infos); 50. m_Infos.corPrice = corPrice; 51. m_Infos.corTake = corTake; 52. m_Infos.corStop = corStop; 53. } 54. //+------------------------------------------------------------------+ 55. ~C_IndicatorPosition() 56. { 57. if (m_Infos.ticket != 0) 58. ObjectsDeleteAll(0, IntegerToString(m_Infos.ticket)); 59. } 60. //+------------------------------------------------------------------+ 61. bool CheckCatch(ulong ticket) 62. { 63. m_Infos.szShortName = IntegerToString(m_Infos.ticket = ticket); 64. if (!PositionSelectByTicket(m_Infos.ticket)) return false; 65. if (ObjectFind(0, m_Infos.szShortName) >= 0) 66. { 67. m_Infos.ticket = 0; 68. return false; 69. } 70. IndicatorSetString(INDICATOR_SHORTNAME, m_Infos.szShortName); 71. EventChartCustom(0, evUpdate_Position, ticket, 0, ""); 72. 73. return true; 74. } 75. //+------------------------------------------------------------------+ 76. void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) 77. { 78. switch (id) 79. { 80. case CHARTEVENT_CUSTOM + evUpdate_Position: 81. if (lparam != m_Infos.ticket) return; 82. if (!PositionSelectByTicket(m_Infos.ticket)) 83. { 84. ChartIndicatorDelete(0, 0, m_Infos.szShortName); 85. return; 86. }; 87. MoveLineInfos(NULL, PositionGetDouble(POSITION_PRICE_OPEN)); 88. MoveLineInfos(def_SufixTake, PositionGetDouble(POSITION_TP)); 89. MoveLineInfos(def_SufixStop, PositionGetDouble(POSITION_SL)); 90. break; 91. } 92. ChartRedraw(); 93. } 94. //+------------------------------------------------------------------+ 95. }; 96. //+------------------------------------------------------------------+ 97. #undef def_SufixTake 98. #undef def_SufixStop 99. //+------------------------------------------------------------------+
C_IndicatorPosition.mqh
Este código que você pode observar logo acima. Deverá ser colocado no lugar do código original visto no tópico anterior. Você pode notar, que as mudanças que ocorreram foram poucas. Mas são suficientes para permitir que o indicador de posição, consiga lidar com a situação descrita no início deste tópico. Então vamos entender o que mudou aqui neste código, frente ao que era feito anteriormente.
Basicamente na função da linha 61, agora não mais criamos os objetos HLINE. Então aquelas linhas que faziam isto foram removidas. Bem, na verdade elas não foram removidas, mas sim relocadas. Note que todo o código continua igual. Porém, ao irmos para a linha 19, poderemos ver algo muito que estranho, acontecendo. Que antes não ocorria.
Note o seguinte: Antes quando pedíamos para mover uma linha de preço. O código apenas dizia para o objeto se mover. Mas agora temos um passo extra, sendo feito. Este passo se encontra na linha 25. O fato deste passo existir, nos permite recriar a linha quando for necessário. Ou seja, quando o operador remover a linha. O Expert Advisor dirá ao indicador de posição para atualizar os dados. O Indicador removerá a mesma linha que o operador terá removido. Porém, quando o operador, realocar a linha dizendo que agora teremos um preço de stop loss ou take profit. O Expert Advisor dirá ao Indicador de posição para atualizar novamente os dados. Neste ponto, quando a linha 25 for executada, o indicador de posição notará que o objeto HLINE não existe, criando-o de forma adequar ao novo status da posição. Somente depois é que o Indicador de posição posicionará a linha no local adequado. Isto usando a linha 31.
O que acabei de explicar pode ser visto no vídeo abaixo. De maneira a deixar claro como este indicador de posição se encontra funcionando no momento.
Considerações finais
Neste artigo, fizemos diversas melhorias, visando fazer com que o indicador de posição, venha a refletir o que de fato está ocorrendo no servidor de negociação em termos de posições e seu status atual. Devo lembrar, que estas aplicações mostradas aqui, não visam de maneira alguma substituir qualquer elemento presente no MetaTrader 5. E tal pouco devem ser utilizadas sem os devidos cuidados e critérios. Já que elas têm como objetivo terem um código didático. Ou seja, para fins de aprendizado de como as coisas funcionam.
E o motivo para que eu diga que o código é didático. É pelo fato de que o uso de mensagens em alguns casos não é a melhor forma de implementar as coisas. Vejam o fato de que, o indicador de posição ao ser lançado no gráfico. Cria uma mensagem que ele mesmo irá responder. Tal característica tira um pouco da agilidade que o código poderia de fato obter. Visto que estamos adicionando uma chamada onde não haveria necessidade para tal.
Mas de qualquer forma, não pretendo mudar a maneira como o código está sendo apresentado. E para aqueles que desejam experimentar este código, mas não sabem como criar todos os arquivos. Apesar de que, todo o código esteja sendo integralmente apresentado. No anexo, você terá as aplicações já compiladas, bastando então usá-las no MetaTrader 5, e ver como a passagem de mensagens funciona. Tais aplicações foram testadas em contas HEDGING e NETTING funcionando perfeitamente. Basta que você não mude nada. Apenas descompacte o anexo no diretório do MQL5. E você terá o mesmo resultado visto no vídeo.
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.
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.





- 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