
Simulação de mercado: Position View (VIII)
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 (VII), vimos como poderíamos implementar o indicador de posição, para que pudéssemos fechar uma posição aberta diretamente via gráfico. Isto interagindo com um objeto que estaria a nossa disposição no gráfico. Depois que o primeiro mecanismo estava concluído e funcionando. Começamos a fazer algumas modificações para que também fosse possível remover as linhas de take profit e stop loss. Isto de uma posição que estivesse aberta. Porém como as mudanças a serem feitas precisariam de uma explicação adequada. Naquele mesmo artigo, apenas mostrei as mudanças que deveriam ocorrer no âmbito do Expert Advisor. Sendo necessário mostrar ainda as mudanças que deveriam ocorrer no Indicador de posição.
As mudanças no código em si, são relativamente pequenas. Porém, devido a minha observação, do público que de fato tem demonstrado interesse neste sistema de replay / simulador. Notei que muitos, se não a grande maioria, não tem tanta experiência em programação. Ainda mais no tipo de programação que estou apresentando e fazendo uso. Assim se torna necessário, ao meu ver, dar uma explicação um pouco mais detalhada. De forma que todos consigam entender e se desejar, modificar os códigos para atender a uma necessidade particular. Todo e qualquer código aqui, visa única e exclusivamente ser voltado para fins didáticos. Então procure estudar tanto o código quanto a explicação que estarei dando. Pois agora vamos trabalhar pesado.
Modificando o Indicador de posição
Como pretendo mostrar um pouco mais neste artigo. Vamos logo ver o que ficou faltando no artigo anterior. Desta maneira, vamos partir direto para a classe C_IndicatorPosition, que tem seu novo código mostrado logo abaixo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #include "C_ElementsTrade.mqh" 05. //+------------------------------------------------------------------+ 06. class C_IndicatorPosition 07. { 08. private : 09. struct st00 10. { 11. ulong ticket; 12. color corPrice, corTake, corStop; 13. string szShortName; 14. }m_Infos; 15. C_ElementsTrade *Open, 16. *Stop, 17. *Take; 18. //+------------------------------------------------------------------+ 19. public : 20. //+------------------------------------------------------------------+ 21. C_IndicatorPosition(color corPrice, color corTake, color corStop) 22. { 23. ZeroMemory(m_Infos); 24. m_Infos.corPrice = corPrice; 25. m_Infos.corTake = corTake; 26. m_Infos.corStop = corStop; 27. Open = Take = Stop = NULL; 28. } 29. //+------------------------------------------------------------------+ 30. ~C_IndicatorPosition() 31. { 32. delete Open; 33. delete Take; 34. delete Stop; 35. } 36. //+------------------------------------------------------------------+ 37. bool CheckCatch(ulong ticket) 38. { 39. m_Infos.szShortName = StringFormat("%I64u", m_Infos.ticket = ticket); 40. if (!PositionSelectByTicket(m_Infos.ticket)) return false; 41. if (ObjectFind(0, m_Infos.szShortName) >= 0) 42. { 43. m_Infos.ticket = 0; 44. return false; 45. } 46. IndicatorSetString(INDICATOR_SHORTNAME, m_Infos.szShortName); 47. EventChartCustom(0, evUpdate_Position, ticket, 0, ""); 48. 49. return true; 50. } 51. //+------------------------------------------------------------------+ 52. void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) 53. { 54. double value; 55. 56. if (Open != NULL) (*Open).DispatchMessage(id, lparam, dparam, sparam); 57. if (Take != NULL) (*Take).DispatchMessage(id, lparam, dparam, sparam); 58. if (Stop != NULL) (*Stop).DispatchMessage(id, lparam, dparam, sparam); 59. switch (id) 60. { 61. case CHARTEVENT_CUSTOM + evUpdate_Position: 62. if (lparam != m_Infos.ticket) return; 63. if (!PositionSelectByTicket(m_Infos.ticket)) 64. { 65. ChartIndicatorDelete(0, 0, m_Infos.szShortName); 66. return; 67. }; 68. if (Open == NULL) Open = new C_ElementsTrade(m_Infos.ticket, evMsgClosePositionEA, m_Infos.corPrice, ePriorityNull, "Position opening price."); 69. if (Take == NULL) Take = new C_ElementsTrade(m_Infos.ticket, evMsgCloseTakeProfit, m_Infos.corTake, ePriorityOrders, "Take Profit point."); 70. if (Stop == NULL) Stop = new C_ElementsTrade(m_Infos.ticket, evMsgCloseStopLoss, m_Infos.corStop, (EnumPriority)(ePriorityOrders + 1), "Stop Loss point."); 71. (*Open).UpdatePrice(PositionGetDouble(POSITION_PRICE_OPEN)); 72. if ((value = PositionGetDouble(POSITION_TP)) > 0) (*Take).UpdatePrice(value); else 73. { 74. delete Take; 75. Take = NULL; 76. } 77. if ((value = PositionGetDouble(POSITION_SL)) > 0) (*Stop).UpdatePrice(value); else 78. { 79. delete Stop; 80. Stop = NULL; 81. } 82. break; 83. } 84. ChartRedraw(); 85. } 86. //+------------------------------------------------------------------+ 87. }; 88. //+------------------------------------------------------------------+
C_IndicatorPosition.mqh
Bem, você deve estar completamente sem entender o que aconteceu aqui. Pois o código deu uma mudança quase totalmente abrupta de uma hora para outra. Mas esta mudança foi proposital e providencial. Isto por que, precisamos começar a separar alguns detalhes no código para no momento que formos desenvolver a parte sobre ordens pendentes, que será vista no futuro. Não precisarmos de fato criar muito código, ou ter um código tão adensado que dificultaria qualquer remoção de partes que poderiam ser reutilizadas. Então, meu caro leitor, não fique assustado ou apreensivo conforme as mudanças forem ocorrendo. Elas de fato irão se dar, conforme vai sendo necessário. Separar partes que podem vir a ser reutilizadas no futuro.
Muito bem, então olhando este código acima, você logo de cara nota na linha quatro, que estamos incluindo um novo arquivo de cabeçalho. Este será visto mais para o final deste mesmo artigo. Por hora não se preocupe com ele. Vamos nos concentrar neste arquivo daqui por enquanto. Assim, na linha 15 declaramos três ponteiros para a classe C_ElementsTrade. Estes ponteiros, tem como objetivo, nos permitir um acesso controlado ao código da classe
C_ElementsTrade. Preste atenção ao seguinte: Estou usando três ponteiros, por que na classe C_ElementsTrade, criaremos tudo que será preciso para que o indicador de posição seja corretamente apresentado. Como diversos elementos são comuns entre o que será apresentado. Como por exemplo, o botão de fechar, a linha que indica o ponto do preço, entre outros elementos que adicionaremos depois. Podemos para facilitar, colocar tudo em uma única classe. E no momento em que formos referenciar a classe que cria tais elementos gráficos. Podemos facilmente mudar de um tipo de estrutura para outro. Ou melhor dizendo, podemos usar tudo que existe na indicação de uma linha de stop loss, em uma indicação de take profit. Desde é claro, criemos alguma diferenciação aqui no código, de modo que o operador saiba facilmente qual indicador representa o que. Não precisaremos codificar uma classe só para indicar o stop loss e outra só para o take profit. Não sei se ficou claro esta minha explicação. Mas ao ver mais detalhes sobre o código, você, meu caro leitor e entusiasta, entenderá o que se passa.
Pois bem, normalmente o compilador, inicializa as variáveis com um valor adequado. Mas como queremos ter certeza disto, fazemos a inicialização no constructor. Isto é feito na linha 27, onde dizemos que os ponteiros, serão inicializados com um valor NULL. Muita atenção a este detalhe. Pois é importante que você saiba disto. E como não podia deixar de destacar, no destructor destruímos os ponteiros. Devolvendo assim a memória para o sistema. Isto é feito entre as linhas 32 e 34. Mas neste ponto, você que é um entusiasta, pode se perguntar: Mas por que usar um comando delete, se ainda não alocamos memória via comando new ? Isto não faz sentido. De fato, não faz sentido à primeira vista. Mas você não deve de fato se descuidar de variáveis que são ponteiros. É muito comum, durante a execução de programas, ou aplicações, termos como resultado em algum momento, o disparo de um erro. Isto por conta que o programa fez algo que envolve ponteiros. E como os nossos ponteiros, estarão contidos dentro da classe C_IndicatorPosition, devemos no momento em que a classe for encerrada. Garantir que a memória será devidamente liberada.
Ok. Esta foi a explicação preliminar. Agora vamos ver onde ocorreu mais mudanças no código original. Então vamos direto para a linha 52, onde temos a implementação do procedimento DispatchMessage. Neste ponto, se você não prestar atenção, ficará perdido. Já que é aqui onde a mágica acontece. Veja que o restante do código permaneceu praticamente igual ao que era antes. Mas neste procedimento da linha 52, temos diversas coisas que podem lhe confundir, meu caro amigo leitor. A primeira coisa, que de fato pode ser muito confusa é o código que aparece entre as linhas 56 e 58. Por que estou fazendo estes testes, antes de chamar o procedimento DispatchMessage de cada um dos elementos que adicionaremos ao gráfico ? O motivo é muito simples. No primeiro momento, em que chamamos este procedimento da linha 52. NÃO TEMOS NENHUM ELEMENTO NO GRÁFICO. Então sem testar se os ponteiros estariam de fato apontando para algo realmente valido na memória. Correremos o risco de executar 'lixo'. Mas como o MQL5, parece ter algum mecanismo de segurança. Ao tentarmos executar 'lixo', o código falharia. Gerando assim uma saída abrupta do indicador do gráfico. Ok, entendi. Precisaríamos fazer este teste a todo momento ? Sim. É preciso fazer ele toda vez que este procedimento da linha 52 for executado. E o motivo, você entenderá em breve. Então vamos para o próximo ponto. Que é onde começamos a tratar o evento que é esperado neste procedimento. Tal evento começa a ser tratado na linha 61. Agora preste muita, mais muita atenção mesmo. Pois a primeira coisa que fazemos é testar na linha 62, se o valor do parâmetro lparam é o mesmo que o bilhete observado pelo indicador. Se os valores forem diferentes, encerramos por aqui. Caso sejam iguais, verificamos na linha 63 se a posição existe no servidor. Se ela não existir mais, na linha 65 removemos o indicador de posição do gráfico, e na linha 66 encerramos o tratamento da mensagem. Se ainda assim tivermos sucesso nestes primeiros passos. Na linha 68, testaremos se o ponteiro que mostra os elementos do preço de abertura, já foi ou não criado. Este teste somente irá ser verdadeiro, na primeira chamada que estivermos executado. Em todas as demais ele irá ser falso. Como esta é a primeira chamada, iremos usando o operador new, chamar o constructor. E é importante que você entenda isto. O motivo, é que você pode dizer ao constructor, para criar um dado tipo de organização dos elementos. Assim, você poderá usando a mesma classe, criar um indicador para o take profit, um outro para o stop loss e um outro para o preço de abertura. E é justamente isto que estamos fazendo entre as linhas 68 e 70. Note que de qualquer forma inicializaremos os ponteiros. Salvo o caso de que o ponteiro, já tenha sido inicializado. Porém podemos melhorar ainda mais este sistema, de forma e evitar chamadas desnecessárias. Mas isto será visto depois. Primeiro, é preciso que você, meu caro leitor e entusiasta, consiga entender como as coisas estão funcionando.
Uma vez que tenhamos inicializado os três ponteiros, nas linhas 68 e 70. Na linha 71, dizemos a classe C_ElementsTrade, que é referenciada pelo ponteiro OPEN, para atualizar o preço. Talvez você ache, ou imagine que isto é bobagem. Que poderíamos fazer isto, diretamente no constructor. De fato, poderíamos. Isto desde é claro, tivéssemos certeza de que a conta é do tipo HEDGING. Já que se estivermos usando uma conta NETTING, o preço pode ser diferente. Devido ao fato de que o servidor estará nos informando um valor que seria a média da posição. Por isto que não estou passando o valor diretamente pelo constructor da classe C_ElementsTrade. No futuro, faremos diferente. Não se desespere meu caro leitor. Um passo de cada vez. Entenda primeiro este código mais simples. Para no futuro entender um mais elaborado.
Muito bem. Agora vem a parte realmente interessante neste procedimento DispatchMessage. O que irei explicar aqui, serve também para o que será feito entre as linhas 77 e 81. Não é algo complicado. Apenas preste atenção e você entenderá facilmente o que está acontecendo. Primeiramente buscamos o valor na que precisamos e o colocamos na variável value. Depois disto, testamos se o valor é maior que zero. Caso seja, significa que existe a linha de limite. Seja ela de take profit ou stop loss. De qualquer forma, se o valor existe, iremos repassar ele para a classe C_ElementsTrade, adequada. OU seja, faremos algo parecido com o que foi feito na linha 71. Agora tem um detalhe, e este é diferente do que foi feito no caso da atualização do preço de abertura. Caso o valor testado seja zero, isto indicará que não temos o limite esperado. Assim os elementos que representam o preço, deverão ser removidos do gráfico. Você talvez estivesse esperando ver isto sendo feito aqui. Na classe C_IndicatorPosition. Mas olhando o código você não consegue encontrar este ponto. Onde os objetos são removidos do gráfico. Mas sim, ele está aqui. E é justamente na linha 74 que fazemos isto. Já que estaremos chamando o destructor adequado. Como a execução do comando delete, não torna nulo o valor encontrado no ponteiro. Apenas devolve, ou desaloca a memória que estava sendo usada. Precisamos dizer explicitamente ao ponteiro que ele agora é um ponteiro nulo. Isto é feito na linha 75. Preste atenção a isto. A localização indicada para o ponteiro é uma local onde pode conter lixo. Como o código espera testar se o valor do ponteiro é nulo ou não, precisamos informar isto de forma explicita. Não por conta que será sempre necessário fazer isto. Mas sim por que, o código não será encerrado. Podendo, no momento em que os testes nas linhas 56 a 58, apontar para lixo. E isto quebraria o código, assim que você removesse o preço do servidor. Fosse ele o valor de stop loss ou take profit.
Muito bem, até neste momento, apenas foquei em explicar a parte referente ao código presente na classe C_IndicatorPosition. Mas a explicação não estará de fato completa, sem que venhamos a ver a classe C_ElementsTrade. Que é justamente a que faz todo o trabalho para nós. Mas para separar adequadamente as coisas, vamos ver isto em um novo tópico.
Iniciando a classe C_ElementsTrade
Bem, até agora tudo que foi visto, foi algo que para muitos pode parecer complicado e confuso. Mas se este foi o seu caso, meu caro leitor. Não desanime. Volte alguns artigos e comece a estudar as coisas com um pouco mais de calma. Pois estou tentando mostrar as coisas da forma o mais simples e didáticas quanto é possível ser feito. Sei que muito do que estou mostrando parece ser algo extremamente complicado e difícil de ser entendido e imaginado. Mas isto se deve ao fato de que você não esperava, ou imaginava que isto que estou fazendo era mesmo possível. Já que praticamente ninguém mostrou antes tais coisas.
De qualquer forma, vamos continuar. E agora vamos começar a ver um novo código, que iremos trabalhar bastante nele. Você não irá mais ver com muita frequência, eu modificar os códigos vistos anteriormente. Agora nosso foco será neste nível em diante. Ok. A nova classe a ser criada pode ser vista logo abaixo. Com todo o seu código na íntegra.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #define def_NameHLine m_Info.szPrefixName + "#HLINE" 05. #define def_NameBtnClose m_Info.szPrefixName + "#CLOSE" 06. //+------------------------------------------------------------------+ 07. #define def_PathBtns "Images\\Market Replay\\Orders\\" 08. #define def_Btn_Close def_PathBtns + "Btn_Close.bmp" 09. #resource "\\" + def_Btn_Close; 10. //+------------------------------------------------------------------+ 11. #include "..\Auxiliar\C_Terminal.mqh" 12. //+------------------------------------------------------------------+ 13. class C_ElementsTrade : private C_Terminal 14. { 15. private : 16. //+------------------------------------------------------------------+ 17. struct st00 18. { 19. ulong ticket; 20. string szPrefixName; 21. EnumEvents ev; 22. double price; 23. }m_Info; 24. //+------------------------------------------------------------------+ 25. void UpdateViewPort(void) 26. { 27. int x, y; 28. 29. ChartTimePriceToXY(0, 0, 0, m_Info.price, x, y); 30. ObjectSetDouble(0, def_NameHLine, OBJPROP_PRICE, m_Info.price); 31. ObjectSetInteger(0, def_NameBtnClose, OBJPROP_XDISTANCE, 130); 32. ObjectSetInteger(0, def_NameBtnClose, OBJPROP_YDISTANCE, y); 33. } 34. //+------------------------------------------------------------------+ 35. public : 36. //+------------------------------------------------------------------+ 37. C_ElementsTrade(const ulong ticket, const EnumEvents ev, color _color, EnumPriority ePrio, string szDescr = "\n") 38. :C_Terminal() 39. { 40. string szObj; 41. 42. ZeroMemory(m_Info); 43. m_Info.szPrefixName = StringFormat("%I64u@%d", m_Info.ticket = ticket, (int)(m_Info.ev = ev)); 44. CreateObjectGraphics(szObj = def_NameHLine, OBJ_HLINE, _color, ePrio); 45. ObjectSetString(0, szObj, OBJPROP_TEXT, szDescr); 46. ObjectSetString(0, szObj, OBJPROP_TOOLTIP, szDescr); 47. ObjectSetInteger(0, szObj, OBJPROP_SELECTABLE, ePrio != ePriorityNull); 48. CreateObjectGraphics(szObj = def_NameBtnClose, OBJ_BITMAP_LABEL, clrNONE, (EnumPriority)(ePriorityOrders + 1)); 49. ObjectSetString(0, szObj, OBJPROP_BMPFILE, 0, "::" + def_Btn_Close); 50. ObjectSetInteger(0, szObj, OBJPROP_ANCHOR, ANCHOR_CENTER); 51. } 52. //+------------------------------------------------------------------+ 53. ~C_ElementsTrade() 54. { 55. if (m_Info.szPrefixName != "") 56. ObjectsDeleteAll(0, m_Info.szPrefixName); 57. } 58. //+------------------------------------------------------------------+ 59. inline void UpdatePrice(const double price) 60. { 61. m_Info.price = price; 62. UpdateViewPort(); 63. } 64. //+------------------------------------------------------------------+ 65. void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) 66. { 67. switch (id) 68. { 69. case CHARTEVENT_OBJECT_CLICK: 70. if (sparam == def_NameBtnClose) 71. { 72. if (PositionSelectByTicket(m_Info.ticket)) switch (m_Info.ev) 73. { 74. case evMsgClosePositionEA: 75. EventChartCustom(0, evMsgClosePositionEA, m_Info.ticket, 0, ""); 76. break; 77. case evMsgCloseTakeProfit: 78. EventChartCustom(0, evMsgCloseTakeProfit, m_Info.ticket, PositionGetDouble(POSITION_SL), PositionGetString(POSITION_SYMBOL)); 79. break; 80. case evMsgCloseStopLoss: 81. EventChartCustom(0, evMsgCloseStopLoss, m_Info.ticket, PositionGetDouble(POSITION_TP), PositionGetString(POSITION_SYMBOL)); 82. break; 83. }; 84. } 85. break; 86. case CHARTEVENT_CHART_CHANGE: 87. UpdateViewPort(); 88. break; 89. } 90. } 91. //+------------------------------------------------------------------+ 92. }; 93. //+------------------------------------------------------------------+ 94. #undef def_Btn_Close 95. #undef def_PathBtns 96. //+------------------------------------------------------------------+ 97. #undef def_NameBtnClose 98. #undef def_NameHLine 99. //+------------------------------------------------------------------+
C_ElementsTrade.mqh
Agora sim, a coisa complicou de vez. Já que muitos poderiam esperar um código muito maior, ou com bem mais informações ou coisas sendo feitas. Mas olhando este código acima, fica evidente que o trabalho é feito de uma maneira completamente diferente, da esperada por muitos. Então vamos entender o que está acontecendo aqui. Mas principalmente: Porque este código consegue fazer o que ele promete fazer. Que é permitir ao operador, usar um elemento gráfico, que seria um botão presente na linha de preço para fechar ou remover algo. Que no caso seria os pontos de take profit e stop loss. Ao mesmo tempo nos permitir fechar uma posição aberta. E tudo isto de uma forma bastante simples e elegante.
Legal, se você chegou até aqui, significa que realmente está curioso em entender com as coisas estão funcionando. Então vamos começar pelo seguinte: Esqueça toda aquela tralha de colocar nomes e mais nomes em objetos no gráfico. Aquilo apenas complica de maneira desnecessária o nosso trabalho. Procure sempre usar uma nomenclatura simples e eficaz. Segundo: Não tente controlar ou administrar o que está no gráfico. Deixe isto para que o MetaTrader 5, se preocupe por você. Então não usaremos listas de objetos, ou coisas do tipo neste trabalho. Apenas criaremos os objetos de forma adequada e deixaremos que o MetaTrader 5, os organize da melhor forma possível. Mantendo a lista de objetos presentes no gráfico sobre seu controle.
Um detalhe a respeito do que acabei de falar. O MetaTrader 5, não é uma ferramenta mágica. Ele não conseguirá efetuar um bom trabalho, se você fizer bobagens. É preciso que você entenda o MetaTrader 5, para que de fato consiga tirar proveito do que ele tem a oferecer. Por isto a primeira coisa que existe no código acima, é justamente algumas definições. Observe nas linhas quatro e cinco a presença de duas definições a serem usadas apenas neste arquivo de cabeçalho. Digo apenas, por que nas linhas 97 e 98, destruímos estas mesmas definições. Então se você tentar usá-las fora deste arquivo, o compilador gerará erros. E o código não será compilado. Muito bem, observe o que temos nestas duas definições. Temos uma variável que será vista depois e uma string. Apenas isto, nada mais. Porém isto é mais que o suficiente, para que o MetaTrader 5, consiga organizar as informações para nós. Mantendo em uma lista interna os objetos que criaremos neste código. Então não precisamos de uma lista extra, apenas para isto. Deixe o MetaTrader 5, cuidar da lista de objetos.
As linhas de sete a nove, já foram comentadas anteriormente, não merecendo destaque extra. Então podemos entrar no código da classe, e note que são poucos procedimentos e funções presentes aqui. Porém, estamos apenas começando a criar este código. Mas vamos com calma. A primeira coisa que você ao olhar uma classe deve fazer é procurar os procedimentos de criação e destruição da mesma. Estes são o constructor e o destructor. Pois bem, na linha 37 temos a declaração do constructor da classe. Agora quero que você volte no tópico anterior, e veja o que cada um dos parâmetros aqui, representa frente ao que foi explicando anteriormente. Note que o código deste constructor é bastante simples. Tudo que estamos fazendo é criando os objetos que serão apresentados no gráfico. Basicamente estou pegando o código que existia antes na classe C_IndicatorPosition, e o replicando aqui. Simples assim. Porém, diferente do que acontecia antes, quando tínhamos apenas uma linha horizontal sendo criada. Neste caso temos dois objetos sendo criados. Um que seria a linha, que é criada na linha 44 do código. E o outro é o botão para interação. Este está sendo criado na linha 48 do código. Agora vem a parte onde aquelas definições das linhas quatro e cinco, farão algum sentido. Note que linha 43, que estou definido o valor daquela mesma variável, usada nas definições. Ou seja, quando usamos as definições, para dizer ao MetaTrader 5: Quero mudar algo no objeto tal. Ou quero que você me diga se o objeto tal, recebeu um evento. O MetaTrader 5, entenderá e responderá de maneira adequada ao nosso pedido. Fazendo exatamente o que queremos que seja feito. Por isto não precisamos de uma lista extra de objetos. O MetaTrader 5, fará a organização para nós. E isto é ótimo para nós. Pois nos poupa bastante trabalho em fazer tal organização. Mas antes de passarmos ao destructor, quero chamar a sua atenção a um detalhe, meu caro leitor. Lembra que antes quando íamos posicionar o botão de interação, precisávamos ajustar a posição do mesmo, subtraindo um valor ? Pois bem, como eu disse na ocasião, temos uma forma melhor de fazer isto. E a forma é usando a linha 50. Só que tem um detalhe. Ali, o botão será posicionado no ponto onde estivemos indicando. Isto será melhor explorado no futuro. Por hora veja que não precisamos fazer mas aquele ajuste.
Ok. Assim como o constructor reflete o que já existia antes. O mesmo se aplica ao destructor presente na linha 53. Então não vou dar destaque a ele. Apenas o estou mencionando.
Note que além do que foi visto, temos três outros procedimentos. Se bem, que poderia ser dois. Mas por questões práticas decidi fazer o trabalho em três. O procedimento da linha 59, é básico, ele apenas joga as coisas para o procedimento na linha 25. Este procedimento também é bem básico. Tento como único trabalho apresentar os objetos no gráfico nos locais adequados. Algo que não merece muito destaque, já que estamos falando a um bom tempo dos mesmos. Porém o procedimento na linha 65. Este sim merece um destaque especial. Já que sem ele, nada que você vê acontecendo no gráfico irá de fato ocorrer. Então vamos ver este procedimento com calma, a partir de agora.
Neste procedimento DispatchMesssage, que é o cerne desta classe. Tratamos neste começo. Dois eventos. Um de clique nos objetos e outro de atualização do gráfico. Bem, o evento de atualização, que é visto na linha 86 é simples e direto. Ele apenas posiciona os elementos, ou objetos no gráfico. Algo que já fazíamos antes. No entanto, o evento de clique é um pouco mais complicado do que existia antes. Mas não fique com receio. Ele é apenas um pouco mais complicado. Não é nenhum bicho de sete cabeças.
Observe que quando a linha 69 é disparada, a primeira coisa que fazemos é verificar se o objeto informado pelo MetaTrader 5 é o mesmo que esperamos tratar. Ou seja, um objeto do tipo CLOSE. Novamente, não tente pensar nas coisas de maneira convencional. Cada classe C_ElementsTrade pertencerá a uma e somente uma das informações que precisaremos apresentar. Ou seja, não precisamos saber se o objeto CLOSE é referente ao take profit, stop loss ou do preço de abertura. Isto pouco importa. O que realmente importa é que o objeto, é do tipo CLOSE. Apenas isto, saber a quem ele pertence, é um trabalho que será feito depois.
Assim se o teste para verificar o objeto for verdadeiro. Faremos um novo teste. Isto na linha 72. Neste testamos se o bilhete que se encontra na classe, é o de uma posição válida. Este teste é importante, para que possamos separar ordens de posições. Apesar de ainda não termos falado sobre as ordens, já estamos preparando o terreno para que quando elas forem implementadas, não tenhamos que mudar muito o código. Se este novo teste também obtiver sucesso, entraremos em um pequeno sistema. Este fará o trabalho que muitos esperariam fazer lá no início do código.
Aqui vamos testar, qual elemento recebeu o evento de clique. Mas como assim ? O MetaTrader 5, não nos informará isto ? De certa forma, o MetaTrader 5 nos informa isto perfeitamente bem. Porém como quero explicar com calma como isto acontece. Estamos fazendo uso de uma outra abordagem. Assim você caro leitor, e entusiasta, conseguirá entender como trabalhar de uma forma bem mais elaborada depois. Mas de qualquer maneira a ideia será a mesma. Pois na classe atual, existe um valor que é definido durante a fase de construção. Ou seja, volte ao código do constructor, e veja que na linha 43 estamos armazenando o mesmo valor que será testado aqui, entre as linhas 73 e 83.
Observem agora a mágica. Quando você lá na classe C_IndicatorPosition, diz que a classe C_ElementsTrade, deverá criar os elementos, ou objetos gráficos para expressar um take profit. Você na verdade será criando uma separação entre cada um dos conjuntos a serem criados. Esta separação se dá na linha 43. Porém ela somente é usada aqui entre as linhas 73 e 83.
Observe o seguinte: Se o conjunto criado, novamente lá na classe C_IndicadorPosition. For de um stop loss. Quando você clicar no botão de interação para o Stop Loss. O código que realmente será executado será o da linha 81. Enviando uma mensagem para o Expert Advisor a fim de dizer a ele: Olha Expert Advisor, eu quero que o valor de stop loss seja removido. E o Expert Advisor fará um pedido ao servidor para que isto aconteça. Quando o servidor retornar, dizendo que o pedido foi ou não atendido. O Expert Advisor, enviará uma mensagem para o gráfico, dizendo a todos que um evento aconteceu. Porém, este evento é esperado pelo Indicador de posição. E este irá lá na classe C_IndicatorPosition remover a classe C_ElementsTrade, que estará ligada ao stop loss da memória. Assim todos os objetos que estiverem presentes lá serão removidos. Pois o destructor da classe dirá ao Metatrader 5, para remover os objetos com um determinado nome do gráfico.
Por isto, eu disse no começo do tópico, de que você não precisa se preocupar com certas coisas. Que se fizer as coisas de maneira adequada, terá ajuda do MetaTrader 5, para conseguir efetuar as tarefas que você deseja cumprir.
Considerações finais
Neste artigo, começamos a explorar mais profundamente certos detalhes. Mas como quero explicar e tornar as coisas o mais didáticas possível. Pode parecer aos olhos de muitos, que estamos caminhando devagar. Mas se eu de fato desse os passos que considero adequados. No final, poucos conseguiriam entender o que de fato acontece. E entre estes pouco, ainda menos conseguiriam modificar o código a fim de conseguir adequar ele a seus propósitos particulares. Então se você já tem um bom conhecimento em programação, tenha paciência, com aqueles que estão começando.
Para aqueles que desejarem verificar o funcionamento do sistema, no anexo, estou deixando os arquivos necessários já compilados. Para que tudo aconteça de forma adequada, você não deverá mudar a estrutura de diretórios usada no anexo. Apenas extraia e experimente o sistema. Usando para isto o indicador de mouse, o indicador Chart Trade, além do Expert Advisor. Devendo para isto colocar estas três aplicações no gráfico. Já o indicador de posição será carregado automaticamente conforme venha a ser necessário.
Um último detalhe. Mesmo que você deseja usar apenas o Expert Advisor, e usar o sistema de ordens de um clique do MetaTrader 5. Terá o mesmo tipo de resultado que seria obtido com todas as aplicações no gráfico. Porém, sugiro que você comece a se acostumar a usar o conjunto das três. Já que ainda faremos melhorias no sistema. E algumas coisas não funcionaram, se você estiver usando as coisas de forma diferente.
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