preview
Simulação de mercado: Position View (IX)

Simulação de mercado: Position View (IX)

MetaTrader 5Testador |
24 0
Daniel Jose
Daniel Jose

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 (VIII), mostrei como poderia ser implementado, ou melhor dizendo, como deveríamos modificar o código do indicador de posição. A fim de que este pudesse conseguir, via interação, remover as linhas de take profit e stop loss. Além de nos permitir fechar muito facilmente a posição. Para quem vem acompanhando esta sequência. Acredito que não estão tendo dificuldades em entender o que está sendo implementado. No entanto, até o momento, ainda não fizemos nada relacionado a questão de ter uma simulação do que seria uma operação. Mas não se preocupem com isto por enquanto. Estamos fazendo progresso em direção a isto. Mesmo que pareça não está ocorrendo tal coisa. Ela de fato está acontecendo.

Porém agora temos um problema, que de um lado é algo bastante chato, mas por outro é algo muito interessante de explicar como resolver. E o problema é: Como fazer para adicionar as linhas de take profit e stop loss, depois que elas foram removidas? Isto sem usar o terminal, mas sim fazendo a operação direto no gráfico. Bem isto de fato é algo, à primeira vista simples. Porém existem alguns percalços a serem superados.


Refletindo sobre uma solução para o problema

Basicamente, este problema pode ser resolvido da seguinte maneira: Ao clicarmos na linha de preço, podemos adicionar uma nova linha ao gráfico. Esta linha poderá ser arrastada até um ponto desejado. E no momento em que ela for solta. O Expert Advisor deverá entender que ali é onde queremos a linha de take profit ou stop loss. Basicamente é isto. Algo bastante simples, diga-se de passagem.

Mas vamos pensar um pouco mais sobre esta abordagem. Bem, primeiro precisamos adicionar, ou implementar um sistema que consiga arrastar a linha de maneira correta. Pois não é só arrastar ela de qualquer forma. Lembre-se que o preço, onde a linha vier a ser solta, deverá cumprir alguns critérios. Isto para que o servidor de negociação, não venha a rejeitar o pedido, enviado pelo Expert Advisor. O problema neste ponto é que cada classe de ativo, pode ter um certo valor de tick. Alguns podem ser na ordem de $ 0,01 enquanto outros podem ser de $ 0,5 e também podem existir casos em que este valor seja de $ 0,2. Note que é algo muito complicado à primeira vista. Mas felizmente já implementamos uma solução para este problema. E ela está no indicador de mouse. Ok, já não precisamos nos preocupar com esta questão de ajustar o preço. Tudo que precisamos fazer, é olhar onde o indicador de mouse se encontra, e usar este ponto como valor a ser informado ao Expert Advisor. Isto para que o Expert Advisor, saiba qual é o preço a ser enviado ao servidor de negociação, a fim de que a linha de stop loss ou take profit seja criada. Muito bem, menos um problema.

Mas ainda temos outros, para pensar e tentar resolver. O próximo problema tem haver, com qual linha seria criada. Isto quando ambas linhas não estiverem presentes na posição. Este problema, é um dos mais interessantes, neste primeiro momento. Isto por que, se a posição for comprada, ao arrastar a linha para um preço mais alto, podemos definir isto como sendo uma linha de take profit. Ou quando em uma posição vendida arrastamos a linha da mesma maneira, ou seja, para um preço mais alto. Poderemos está definindo que esta seria uma linha de stop loss. A mesma coisa vale se o movimento vier a ser ao contrário do que acabei de mencionar. Onde teríamos a definição de uma linha de stop loss ou uma linha de take profit. Mas também poderíamos usar o preço onde, naquele instante estaria saindo negócios. Ou seja, se você arrasta-se a linha, em uma posição comprada, para um ponto acima de onde atualmente o preço estaria sendo negociado. Teríamos a definição de um take profit. Se a posição fosse de venda, teríamos a definição de um stop loss. Agora se a linha, mesmo em uma posição comprada, fosse arrastada abaixo do preço atualmente negociado. Teríamos a definição de um stop loss. E se a posição fosse vendida teríamos a definição de um take profit.

Talvez esta explicação possa ter lhe confundido um pouco, meu caro leitor. Mas entender o que estou tentando explicar é primordial, para compreender o porquê de eu tomar a decisão de implementar o sistema de uma forma ou de outra. Não existe uma maneira correta. Apenas uma maneira que se adéque ao que eu, estou planejando fazer. Porém, se você, desejar fazer as coisas de uma outra forma. Seja por um motivo ou outro. Deve entender o que estou explicando. Pois assim conseguirá implementar as coisas de forma mais coesa e simples.

Porém, apesar de a explicação ser parecido ser muito confusa. Ainda existe um outro pequeno problema. E isto dentro daquela mesma explicação. Para tentar tornar a coisa um pouco menos confusa. Tente imaginar por um instante a seguinte situação: Você, como operador, está negociando um ativo qualquer. E decide comprar ele em um preço, por exemplo: $ 100. Bem, a ordem foi dada a mercado e usando o indicador Chart Trade. Então o Expert Advisor enviará um pedido com as linhas de take profit e stop loss já definidas. Depois de um tempo, você resolve remover estas linhas. Para isto, você usa os botões que foram implementados nos artigos anteriores. Isto usando o Indicador de posição. Ok, o Expert Advisor, entende seu pedido, e envia ao servidor o requerimento a fim de remover tanto o take profit quanto o stop loss. Agora temos o cenário que desejamos. Ou seja, uma posição aberta, sem as linhas de take profit e stop loss. Neste ponto quero que você comece a pensar e tente acompanhar o meu raciocínio.

Supondo que o preço subiu e alcançou os $ 150, você decide, que é hora de adicionar a linha de stop loss. Esta linha fará parte da posição, ela não será uma nova ordem que estará no book esperando o preço voltar. Isto é importante, pois são situações diferentes. Ok, qual deverá ser a sua atitude como operador, a fim de adicionar a linha de stop loss na posição? A atitude mais natural será clicar na linha da posição e arrastar ela. Perfeito. Mas arrastar ela para onde e até em que ponto? Aqui é que está o problema. Mas vamos facilitar um pouco as coisas. A sua ideia, como operador, é colocar o stop loss, na posição de $ 140. Bem, isto é o que você como operador deseja fazer. Mas como você vai fazer isto de fato? Ou melhor dizendo: Como você, sendo um programador, deverá programar isto? E é neste ponto que o bicho pega. Pois se você, como programador não planejar adequadamente este tipo de coisa. Mesmo você, ao usar um sistema que você mesmo implementou poderá acabar fazendo besteiras, ao usar o sistema que você mesmo programou.

Para simplificar, se você implementou um sistema em que é preciso clicar na linha de preço que está em $ 100. Arrastar o mouse para um preço, suponhamos de $ 90. Soltar o mouse, para que o Expert Advisor saiba que deverá, fazer um requerimento ao servidor de negociação, para que a linha de stop loss seja criada. Para somente depois pegar esta mesma linha que está em $ 90 e arrastar ela para os $ 140. Poderá acabar cometendo um erro quando arrastar a linha diretamente dos $ 100 para os $ 140. Isto por que o Expert Advisor entenderá isto como sendo um pedido para criar a linha de take profit e não de stop loss como você poderia esperar.

Aparentemente isto não seria de fato um grande problema. Já que a aquela linha de preço não significa absolutamente nada. Neste momento, é preciso abrir um parêntese para explicar uma coisa. Algo que muitos operadores imaginam ser verdade, mas que não passa de um grande equívoco. As linhas de take profit e stop loss. NÃO, e vou repetir, NÃO SÃO ONDE AS COISAS ACONTECEM. A posição somente será fechada. Se e, somente si, houver algum negócio, exatamente naquele preço. E o número de negócios que ocorrerem ali, deverão ser o suficiente para consumir todos os lotes, antes do preço se mover. Caso ele se mova antes de consumir todos os lotes presentes ali. A ordem será pulada. Ou seja, a posição continuará aberta. Este é um problema bastante sério e que afeta muitos operadores com menos experiência. Já que muitos, fazem uso de robôs, e imaginam que as ordens de take profit e stop loss, jamais serão puladas.

Em uma sequência de artigos mais antiga, expliquei sobre este tipo de coisa. Se você não viu, recomendo fortemente que você leia esta sequência. São 15 artigos bastante simples, onde explico como você pode desenvolver um Expert Advisor que funcione de forma 100% automática. Lá nesta sequência, mostro como resolver justamente este problema da ordem pular. E que neste ponto do desenvolvimento do sistema de replay/simulador. Pode vir a lhe ajudar a pensar em outras soluções. Como o uso de uma contra ordem, com o mesmo volume, porém que mesmo que o preço pule a ordem, ela ainda assim seria executada de qualquer maneira. Já que ela entraria e mercado. O primeiro artigo de tal sequência pode ser visto em:

Aprendendo a construindo um EA que opera de forma automática (Parte 01): Conceitos e estruturas

Por conta deste detalhe, da ordem poder pular é que disse que não poderíamos pensar em uma implementação, onde o stop loss ou take profit seria uma contra ordem que estaria no book. Pois isto mudaria completamente a maneira de abordar o problema. Desta forma, não sei se você, meu caro leitor e entusiasta, conseguiu entender a profundidade do que precisa ser implementado de fato. Minha solução para este problema é simples. Por que complicar, se podemos dar ao operador ou usuário, a capacidade de indicar antecipadamente, se uma linha que será arrastada será a de stop loss ou take profit. No passado em uma outra sequência de artigos eu mostrei como isto foi feito. Porém lá, na época, o foco dos artigos era outro. Eu não imagino que eles poderiam vir a serem usados por pessoas que estivessem começando na programação. Então apesar da implementação na época funcionar. A explicação contida nos artigos, não ajudava em nada quem desejasse aprender a desenvolver algo baseado naquele sistema.

Porém, e felizmente, agora o foco é outro. Aqui quero que você, meu caro leitor, aprenda e entenda por que da implementação está sendo feita desta ou daquela maneira. Mas principalmente, quero que você, busque estudar e crie suas próprias soluções. Usando para isto um pouco do conhecimento que estou tentando lhe passar.

Muito bem, então vamos começar a fazer as coisas. Em todas as situações explicadas acima. Uma coisa ficou bastante clara: Precisamos de alguma maneira, arrastar as linhas no gráfico. Mesmo por que arrastar elas, irá nos permitir mudar o valor do take profit e stop loss. Então precisamos começar a implementação neste ponto. Assim podemos partir para o próximo tópico.


Preparando para arrastar as linhas de preço

A primeira coisa que precisamos fazer, para conseguir arrastar as linhas de preço. E quando eu mencionar linhas de preço, no indicador de posição, estou me referindo as linhas de stop loss e take profit. É adicionar um novo evento ao sistema. Isto é facilmente feito, conforme mostrado 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.             evMsgClosePositionEA,            //Event to communication
49.             evMsgCloseTakeProfit,            //Event to communication
50.             evMsgCloseStopLoss,              //Event to communication
51.             evMsgNewTakeProfit,              //Event to communication
52.             evMsgNewStopLoss                 //Event to communication
53.                         };
54. //+------------------------------------------------------------------+
55. enum EnumPriority {                          //Priority list on objects
56.             ePriorityNull = -1,
57.             ePriorityDefault = 0,
58.             ePriorityChartTrade = 5,
59.             ePriorityOrders = 10
60.                         };
61. //+------------------------------------------------------------------+

Defines.mqh

Note que foram adicionados dois novos eventos a lista. Estes servirão para nós auxiliar na comunicação entre o Indicador de posição e o Expert Advisor. Feito isto podemos ir para a classe C_Orders dentro do Expert Advisor, e implementar estes dois eventos. Assim o novo código da classe pode ser visto logo abaixo:

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #include "..\Defines.mqh"
005. //+------------------------------------------------------------------+
006. class C_Orders
007. {
008.     protected:
009. //+------------------------------------------------------------------+
010. inline const ulong GetMagicNumber(void) const { return m_Base.MagicNumber; }
011. //+------------------------------------------------------------------+
012.         bool ClosePosition(const ulong ticket)
013.             {
014.                 bool   IsBuy;
015.                 string szContract;
016.                 
017.                 if  (!PositionSelectByTicket(ticket)) return false;
018.                 IsBuy = PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY;
019.                 szContract = PositionGetString(POSITION_SYMBOL);
020.                 ZeroMemory(m_Base.TradeRequest);
021.                 m_Base.TradeRequest.action    = TRADE_ACTION_DEAL;
022.                 m_Base.TradeRequest.type      = (IsBuy ? ORDER_TYPE_SELL : ORDER_TYPE_BUY);
023.                 m_Base.TradeRequest.price     = NormalizeDouble(SymbolInfoDouble(szContract, (IsBuy ? SYMBOL_BID : SYMBOL_ASK)), (int)SymbolInfoInteger(szContract, SYMBOL_DIGITS));
024.                 m_Base.TradeRequest.position  = ticket;
025.                 m_Base.TradeRequest.symbol    = szContract;
026.                 m_Base.TradeRequest.volume    = PositionGetDouble(POSITION_VOLUME);
027.                 m_Base.TradeRequest.deviation = 1000;
028.                 
029.                 return SendToPhysicalServer() != 0;
030.             };
031. //+------------------------------------------------------------------+    
032.     private    :
033. //+------------------------------------------------------------------+
034.         struct stBase
035.         {
036.             MqlTradeRequest TradeRequest;
037.             ulong           MagicNumber;
038.             bool            bTrash;
039.         }m_Base;
040. //+------------------------------------------------------------------+
041.         struct stChartTrade
042.         {
043.             struct stEvent
044.             {
045.                 EnumEvents  ev;
046.                 string      szSymbol,
047.                             szContract;
048.                 bool        IsDayTrade;
049.                 ushort      Leverange;
050.                 double      PointsTake,
051.                             PointsStop;
052.             }Data;
053. //---
054.             bool Decode(const EnumEvents ev, const string sparam)
055.                 {
056.                     string Res[];
057.         
058.                     if (StringSplit(sparam, '?', Res) != 7) return false;
059.                     stEvent loc = {(EnumEvents) StringToInteger(Res[0]), Res[1], Res[2], (bool)(Res[3] == "D"), (ushort) StringToInteger(Res[4]), StringToDouble(Res[5]), StringToDouble(Res[6])};
060.                     if ((ev == loc.ev) && (loc.szSymbol == _Symbol)) Data = loc;
061.                     else return false;
062.                     
063.                     return true;
064.                 }
065. //---
066.         }m_ChartTrade;
067. //+------------------------------------------------------------------+
068.         ulong SendToPhysicalServer(void)
069.             {
070.                 MqlTradeCheckResult  TradeCheck;
071.                 MqlTradeResult       TradeResult;
072.                 
073.                 ZeroMemory(TradeCheck);
074.                 ZeroMemory(TradeResult);
075.                 if (!OrderCheck(m_Base.TradeRequest, TradeCheck))
076.                 {
077.                     PrintFormat("Order System - Check Error: %d", GetLastError());
078.                     return 0;
079.                 }
080.                 m_Base.bTrash = OrderSend(m_Base.TradeRequest, TradeResult);
081.                 if (TradeResult.retcode != TRADE_RETCODE_DONE)
082.                 {
083.                     PrintFormat("Order System - Send Error: %d", TradeResult.retcode);
084.                     return 0;
085.                 };
086.                 
087.                 return TradeResult.order;
088.             }
089. //+------------------------------------------------------------------+    
090.         ulong ToMarket(const ENUM_ORDER_TYPE type)
091.             {
092.                 double price  = SymbolInfoDouble(m_ChartTrade.Data.szContract, (type == ORDER_TYPE_BUY ? SYMBOL_ASK : SYMBOL_BID));
093.                 double vol    = SymbolInfoDouble(m_ChartTrade.Data.szContract, SYMBOL_VOLUME_STEP);
094.                 uchar  nDigit = (uchar)SymbolInfoInteger(m_ChartTrade.Data.szContract, SYMBOL_DIGITS);
095.                 
096.                 ZeroMemory(m_Base.TradeRequest);
097.                 m_Base.TradeRequest.magic         = m_Base.MagicNumber;
098.                 m_Base.TradeRequest.symbol        = m_ChartTrade.Data.szContract;
099.                 m_Base.TradeRequest.price         = NormalizeDouble(price, nDigit);
100.                 m_Base.TradeRequest.action        = TRADE_ACTION_DEAL;
101.                 m_Base.TradeRequest.sl            = NormalizeDouble(m_ChartTrade.Data.PointsStop == 0 ? 0 : price + (m_ChartTrade.Data.PointsStop * (type == ORDER_TYPE_BUY ? -1 : 1)), nDigit);
102.                 m_Base.TradeRequest.tp            = NormalizeDouble(m_ChartTrade.Data.PointsTake == 0 ? 0 : price + (m_ChartTrade.Data.PointsTake * (type == ORDER_TYPE_BUY ? 1 : -1)), nDigit);
103.                 m_Base.TradeRequest.volume        = NormalizeDouble(vol + (vol * (m_ChartTrade.Data.Leverange - 1)), nDigit);
104.                 m_Base.TradeRequest.type          = type;
105.                 m_Base.TradeRequest.type_time     = (m_ChartTrade.Data.IsDayTrade ? ORDER_TIME_DAY : ORDER_TIME_GTC);
106.                 m_Base.TradeRequest.stoplimit     = 0;
107.                 m_Base.TradeRequest.expiration    = 0;
108.                 m_Base.TradeRequest.type_filling  = ORDER_FILLING_RETURN;
109.                 m_Base.TradeRequest.deviation     = 1000;
110.                 m_Base.TradeRequest.comment       = "Order Generated by Experts Advisor.";
111. 
112.                 MqlTradeRequest TradeRequest[1];
113. 
114.                 TradeRequest[0] = m_Base.TradeRequest;
115.                 ArrayPrint(TradeRequest);
116. 
117.                 return (((type == ORDER_TYPE_BUY) || (type == ORDER_TYPE_SELL)) ? SendToPhysicalServer() : 0);
118.             };
119. //+------------------------------------------------------------------+
120.         void CloseAllsPosition(void)
121.             {
122.                 for (int count = PositionsTotal() - 1; count >= 0; count--)
123.                 {
124.                     if (PositionGetSymbol(count) != m_ChartTrade.Data.szContract) continue;
125.                     if (PositionGetInteger(POSITION_MAGIC) != m_Base.MagicNumber) continue;
126.                     ClosePosition(PositionGetInteger(POSITION_TICKET));
127.                 }
128.             };
129. //+------------------------------------------------------------------+    
130.         void ModifyValueSLTP(const ulong ticket, const string symbol, const double sl, const double tp)
131.             {
132.                 ZeroMemory(m_Base.TradeRequest);            
133.                 MqlTradeRequest TradeRequest[1];
134. 
135.                 if ((sl < 0) || (tp < 0)) if (!PositionSelectByTicket(ticket)) return;
136.                 m_Base.TradeRequest.magic     = m_Base.MagicNumber;
137.                 m_Base.TradeRequest.action    = TRADE_ACTION_SLTP;
138.                 m_Base.TradeRequest.symbol    = symbol;
139.                 m_Base.TradeRequest.position  = ticket;
140.                 m_Base.TradeRequest.sl        = (sl < 0 ? PositionGetDouble(POSITION_SL) : sl);
141.                 m_Base.TradeRequest.tp        = (tp < 0 ? PositionGetDouble(POSITION_TP) : tp);
142.                 
143.                 TradeRequest[0] = m_Base.TradeRequest;
144.                 ArrayPrint(TradeRequest);
145.                 
146.                 SendToPhysicalServer();
147.             }
148. //+------------------------------------------------------------------+    
149.     public    :
150. //+------------------------------------------------------------------+
151.         C_Orders(const ulong magic)
152.             {
153.                 m_Base.MagicNumber = magic;
154.             }
155. //+------------------------------------------------------------------+    
156.         void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
157.             {
158.                 switch (id)
159.                 {
160.                     case CHARTEVENT_CUSTOM + evChartTradeBuy     :
161.                     case CHARTEVENT_CUSTOM + evChartTradeSell    :
162.                     case CHARTEVENT_CUSTOM + evChartTradeCloseAll:
163.                         if (m_ChartTrade.Decode((EnumEvents)(id - CHARTEVENT_CUSTOM), sparam)) switch (m_ChartTrade.Data.ev)
164.                         {
165.                             case evChartTradeBuy:
166.                                 ToMarket(ORDER_TYPE_BUY);
167.                                 break;
168.                             case evChartTradeSell:
169.                                 ToMarket(ORDER_TYPE_SELL);
170.                                 break;
171.                             case evChartTradeCloseAll:
172.                                 CloseAllsPosition();
173.                                 break;
174.                         }
175.                         break;
176.                     case CHARTEVENT_CUSTOM + evMsgClosePositionEA:
177.                         ClosePosition((ulong)(lparam));
178.                         break;
179.                     case CHARTEVENT_CUSTOM + evMsgCloseTakeProfit:
180.                         ModifyValueSLTP((ulong)(lparam), sparam, dparam, 0);
181.                         break;
182.                     case CHARTEVENT_CUSTOM + evMsgCloseStopLoss:
183.                         ModifyValueSLTP((ulong)(lparam), sparam, 0, dparam);
184.                         break;
185.                     case CHARTEVENT_CUSTOM + evMsgNewTakeProfit:
186.                         ModifyValueSLTP((ulong)(lparam), sparam, -1, dparam);
187.                         break;
188.                     case CHARTEVENT_CUSTOM + evMsgNewStopLoss:
189.                         ModifyValueSLTP((ulong)(lparam), sparam, dparam, -1);
190.                         break;
191.                 }
192.             }
193. //+------------------------------------------------------------------+    
194. };
195. //+------------------------------------------------------------------+

C_Orders.mqh

Talvez seja bobagem, colocar todo o código da classe na íntegra. Já que apenas parte dele sofreu mudanças. Mas tudo bem, vamos as mudanças que ocorreram. Note que na linha 185 e 188, estamos justamente implementando os novos eventos para o Expert Advisor, entender como os processar. Agora preste atenção a uma coisa. Estamos usando a mesma rotina que foi implementada anteriormente. Ou seja, a ModifyValueSLTP. Mas diferente do que estava sendo feito antes, agora estamos passando um valor negativo, em um dos campos. O novo valor do campo da mensagem é informado no parâmetro dparam. Assim como era antes. Mas e este valor negativo, por que disto? Para entender, é preciso olhar o código na linha 130, que é justamente onde estamos implementando a rotina ModifyValueSLTP.

Note que agora dentro deste procedimento temos algumas pequenas diferenças. Em primeiro lugar na linha 135, fazemos um teste a fim de verificar se o valor de sl ou tp são negativos. Se este for o caso, teremos uma chamada a PositionSelectByTicket. Esta chamada visa carregar os valores mais atuais da posição. Mas por que? O motivo é visto nas linhas 140 e 141. Caso os valores de algum dos argumentos, seja negativo. O valor mais atual presente na posição será usado. Isto para que o servidor não remova o valor presente. Porém, se o valor for zero, como no caso da remoção da linha ou outro valor qualquer que não seja negativo. Irá ser usado para que o servidor possa colocar a linha de stop loss ou take profit no ponto desejado pelo operador. Com isto, o código do Expert Advisor acaba se ser atualizado. Não necessitando de nenhuma outra mudança em sua estrutura.

Agora podemos voltar a nossa atenção ao indicador de posição. Já que o código do Expert Advisor, já consegue compreender um pedido de mudanças do preço, seja ele do stop loss ou take profit. Mas antes de começarmos a ver o código do indicador. Quero lembrar a você, meu caro leitor. Que quando o preço for atualizado, automaticamente o indicador irá refletir isto. Ou seja, não precisamos nos preocupar em posicionar a linha do preço de fato. Apenas precisamos criar algum procedimento, que faça com que um evento seja disparado, para que o Expert Advisor, mude a linha do preço.

Então o que irei mostrar neste momento, não é de fato o que será implementado em definitivo. Apenas quero mostrar como você pode mover a linha do preço. Para isto, precisamos fazer alguns pequenos ajustes no código original. E como não quero deixar você, meu caro e estimado leitor e entusiasta perdido, com tantas mudanças. Vamos fazer a coisa aos poucos. Primeiramente vamos modificar o código do indicador, para que apenas e somente o indicador de mouse, faça as coisas acontecerem. Para que isto ocorra é preciso mudar um pouco o código visto nos artigos anteriores. Então no novo código pode ser visto logo abaixo.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #define def_NameHLine        m_Info.szPrefixName + "#HLINE"
005. #define def_NameBtnClose     m_Info.szPrefixName + "#CLOSE"
006. //+------------------------------------------------------------------+
007. #define def_PathBtns "Images\\Market Replay\\Orders\\"
008. #define def_Btn_Close def_PathBtns + "Btn_Close.bmp"
009. #resource "\\" + def_Btn_Close;
010. //+------------------------------------------------------------------+
011. #include "..\Auxiliar\C_Mouse.mqh"
012. //+------------------------------------------------------------------+
013. class C_ElementsTrade : private C_Mouse
014. {
015.     private    :
016. //+------------------------------------------------------------------+
017.         enum eObjects {LINE_PRICE, BTN_CLOSE, ELEM_NULL};
018. //+------------------------------------------------------------------+
019.         struct st00
020.         {
021.             ulong        ticket;
022.             string       szPrefixName;
023.             EnumEvents   ev;
024.             double       price;
025.             struct st01
026.             {
027.                 short xi, xf, yi, yf;
028.             }Positions[ELEM_NULL];
029.         }m_Info;
030. //+------------------------------------------------------------------+
031.         void UpdateViewPort(void)
032.         {
033.             int x, y;
034.             
035.             ChartTimePriceToXY(0, 0, 0, m_Info.price, x, y);
036.             ObjectSetDouble(0, def_NameHLine, OBJPROP_PRICE, m_Info.price);
037.             x = 130;
038.             m_Info.Positions[BTN_CLOSE].xi = (short)(x - 8);
039.             m_Info.Positions[BTN_CLOSE].xf = (short)(x + 8);
040.             m_Info.Positions[BTN_CLOSE].yi = (short)(y - 8);
041.             m_Info.Positions[BTN_CLOSE].yf = (short)(y + 8);
042.             ObjectSetInteger(0, def_NameBtnClose, OBJPROP_XDISTANCE, x);
043.             ObjectSetInteger(0, def_NameBtnClose, OBJPROP_YDISTANCE, y);
044.         }
045. //+------------------------------------------------------------------+
046.         eObjects CheckMousePosition(double &price)
047.             {
048.                 short x, y;
049.                 st_Mouse loc;
050.                 
051.                 loc = GetPositionsMouse();
052.                 price = loc.Position.Price;
053.                 x = loc.Position.X_Graphics;
054.                 y = loc.Position.Y_Graphics;
055.                 for (eObjects c0 = LINE_PRICE; c0 < ELEM_NULL; c0++)
056.                     if ((x > m_Info.Positions[c0].xi) && (x < m_Info.Positions[c0].xf) &&
057.                         (y > m_Info.Positions[c0].yi) && (y < m_Info.Positions[c0].yf)) return c0;
058.                 return ELEM_NULL;
059.             }
060. //+------------------------------------------------------------------+
061.     public    :
062. //+------------------------------------------------------------------+
063.         C_ElementsTrade(const ulong ticket, const EnumEvents ev, color _color, EnumPriority ePrio, string szDescr = "\n")
064.             :C_Mouse(0, "")
065.         {
066.             string szObj;
067.             
068.             ZeroMemory(m_Info);
069.             m_Info.szPrefixName = StringFormat("%I64u@%d", m_Info.ticket = ticket, (int)(m_Info.ev = ev));
070.             CreateObjectGraphics(szObj = def_NameHLine, OBJ_HLINE, _color, ePrio);
071.             ObjectSetInteger(0, szObj, OBJPROP_WIDTH, 2);
072.             ObjectSetString(0, szObj, OBJPROP_TEXT, szDescr);
073.             ObjectSetString(0, szObj, OBJPROP_TOOLTIP, szDescr);
074.             ObjectSetInteger(0, szObj, OBJPROP_SELECTABLE, ePrio != ePriorityNull);
075.             CreateObjectGraphics(szObj = def_NameBtnClose, OBJ_BITMAP_LABEL, clrNONE, (EnumPriority)(ePriorityOrders + 1));
076.             ObjectSetString(0, szObj, OBJPROP_BMPFILE, 0, "::" + def_Btn_Close);
077.             ObjectSetInteger(0, szObj, OBJPROP_ANCHOR, ANCHOR_CENTER);
078.         }
079. //+------------------------------------------------------------------+
080.         ~C_ElementsTrade()
081.         {
082.             if (m_Info.szPrefixName != "")
083.                 ObjectsDeleteAll(0, m_Info.szPrefixName);
084.         }
085. //+------------------------------------------------------------------+
086.         inline void UpdatePrice(const double price)
087.         {
088.             m_Info.price = price;
089.             UpdateViewPort();
090.         }
091. //+------------------------------------------------------------------+
092.         void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
093.         {
094.             double price;
095.             
096.             C_Mouse::DispatchMessage(id, lparam, dparam, sparam);
097.             switch (id)
098.             {
099.                 case CHARTEVENT_MOUSE_MOVE:
100.                     if (CheckClick(C_Mouse::eClickLeft)) switch(CheckMousePosition(price))
101.                     {
102.                         case LINE_PRICE:
103.                             break;
104.                         case BTN_CLOSE:
105.                             if (PositionSelectByTicket(m_Info.ticket)) switch (m_Info.ev)
106.                             {
107.                                 case evMsgClosePositionEA:
108.                                     EventChartCustom(0, evMsgClosePositionEA, m_Info.ticket, 0, "");
109.                                     break;
110.                                 case evMsgCloseTakeProfit:
111.                                     EventChartCustom(0, evMsgCloseTakeProfit, m_Info.ticket, PositionGetDouble(POSITION_SL), PositionGetString(POSITION_SYMBOL));
112.                                     break;
113.                                 case evMsgCloseStopLoss:
114.                                     EventChartCustom(0, evMsgCloseStopLoss, m_Info.ticket, PositionGetDouble(POSITION_TP), PositionGetString(POSITION_SYMBOL));
115.                                     break;
116.                             }
117.                             break;
118.                     }
119.                     break;
120.                 case CHARTEVENT_CHART_CHANGE:
121.                     UpdateViewPort();
122.                     break;
123.             }
124.         }
125. //+------------------------------------------------------------------+
126. };
127. //+------------------------------------------------------------------+
128. #undef def_Btn_Close
129. #undef def_PathBtns
130. //+------------------------------------------------------------------+
131. #undef def_NameBtnClose
132. #undef def_NameHLine
133. //+------------------------------------------------------------------+

C_ElementsTrade.mqh

Olhando este código você deve estar pensando: Cara mas não mudou nada no código. Mas não é bem isto meu amigo. O código mudou completamente seu comportamento. Observe que agora não mais estamos incluindo a classe C_Terminal, mas sim a classe C_Mouse. E isto é feito na linha 11. Da mesma maneira, a classe agora, não mais está herdando C_Terminal. Estamos herdando a classe C_Mouse, e por tabela trazendo junto a classe C_Terminal. Com isto, agora começamos a usar o indicador de mouse para interagir com o indicador de posição. Mas apenas fazer estas mudanças ditas acima, não são suficientes para que isto ocorra. É preciso um pouco mais de mudanças no código. Assim surge a enumeração na linha 17. Esta tem como objetivo, substituir o antigo trabalho feito pelo MetaTrader 5. Ou seja, agora iremos controlar um pouco mais as coisas feitas no código.

Por conta desta substituição na linha 25 declaramos uma nova estrutura, esta conta com quatro variáveis que são declaradas na linha 27. Porém esta estrutura é na verdade um array de posições, e isto pode ser observado na linha 28. Onde dizemos que o array terá a dimensão de X elementos. No caso atual 3 elementos. Muito bem, agora temos que adicionar os elementos a este array. E isto é feito no procedimento da linha 31. Observe que entre as linhas 38 e 41, incluímos a posição, ou box de colisão. Onde o botão de fechar, aguardará para receber um clique do mouse. Os valores oito que podem ser vistos nestas linhas representam o a metade do tamanho do bitmap. Lembre-se o bitmap tem 16 x 16 pixels. E como ele está sendo posicionado de maneira centralizada. Precisamos ajustar corretamente este box de colisão. Perfeito, já temos a localização do botão de fechar.

Mas antes de prosseguirmos para a linha 46, vamos pular para o constructor da classe. Este pode ser visto na linha 63. Observe que na linha 64, agora estamos inicializando a classe C_Mouse. Antes era a classe C_Terminal. Esta forma como a classe C_Mouse está sendo inicializada, diz para o MetaTrader 5, que não queremos criar o Mouse. Apenas queremos poder acessar o indicador de mouse, caso ele esteja presente no gráfico.

Agora podemos voltar a linha 46 e ver o que está acontecendo ali. Observe que esta função parece ser muito mais complicada do que realmente ela é. Aqui estamos simplesmente capturando a posição do indicador de mouse. Isto na linha 51. Logo depois, na linha 52, marcamos o valor de preço para ser retornado ao chamador, que veremos em breve. Mas o que nos interessa de fato é justamente as próximas linhas. Elas têm como finalidade, verificar o box de colisão, a fim de retornar qual foi o objeto que recebeu um clique. Se nenhum objeto foi identificado, iremos na linha 58 retornar um valor invalido para o chamador.

Agora finalmente podemos ver o chamador desta função CheckMousePosition. E ele é justamente o procedimento DispatchMessage, que está presente na linha 92. Agora é que vem a verdadeira mudança. Pois a primeira coisa que fazemos é chamar o tratador de eventos da classe C_Mouse. Isto na linha 96. O motivo, é que precisamos garantir que os dados estejam corretos. Já que não usamos um sistema de buffer, a fim de obter os dados do indicador de Mouse. Depois de tratado os eventos na classe C_Mouse, o código irá, quando um evento de mouse ocorrer, executar a linha 99.

Agora preste atenção. Os eventos do mouse, aqui, não são os mesmos esperados por você, caso você esteja pensando em usar a mesma maneira de codificar o mouse, como normalmente acontece quando usamos ele no MQL5. Aqui os eventos do mouse, são filtrados e tratados de uma outra maneira. Para entender isto, volte nesta mesma sequência de artigos sobre o sistema de replay/simulador, e veja como o indicador de mouse foi implementado. Lá você irá notar que quando usamos o indicador de mouse. Alguns eventos de clique podem vir a ser ignorados. Isto por que, o indicador estava sendo usado com o propósito de gerar um estudo. Nesta mesma sequência, mostrei como você pode modificar o indicador, permitindo criar um estudo particular. Onde você pode interagir diretamente com o gráfico sem necessitar ajustar algum objeto de estudo. O próprio indicador de mouse fará isto para você.

Pois bem, por conta disto, o teste na linha 100 somente terá sucesso, caso o clique do mouse não tenha sido dado durante um estudo. Caso você durante um estudo, venha acidentalmente clicar em um objeto, que está sendo observado por este código da classe C_ElementsTrade. O clique será ignorado. Então supondo que você não estivesse em um estudo, e clique em algum ponto do gráfico. O teste irá passar e a função da CheckMousePosition será chamada. Agora tem um detalhe, que é importante ser mencionado. Esta checagem irá ignorar completamente a ordem vista no gráfico, ou o valor da propriedade ZOrder. Ou seja, cuidado. Pois mesmo clicando em um objeto com um ZOrder mais baixo, ele poderá ter prioridade. Já que quem irá comandar a ordem aqui será a enumeração na linha 17. E dois objetos, mesmo que de indicadores diferentes, mas que compartilham a mesma posição do box de colisão, irão receber o evento. Não importando quem tenha um ZOrder maior, ou quem está na frente de quem. Tenha cuidado com isto. Até que a correção seja providenciada.

Depois iremos ver como fazer isto. Mas por hora tome cuidado. Mas voltando ao código. Quando a função CheckMousePosition retorna, ela dirá que objeto recebeu um clique. Nesta hora, separamos as coisas. Note que na linha 102, já começamos a dizer que quando o objeto LINE_PRICE receber um clique algo acontecerá. Já na linha 104, colocamos exatamente o mesmo código que existia antes. Isto quando o MetaTrader 5, fazia o trabalho para nós. Desta maneira, agora acabamos de substituir o que antes era gerenciado pelo MetaTrader 5, para ser gerenciado por nosso código.

Todo o restante do código do indicador irá permanecer intacto. Não precisando desta maneira ser mostrado aqui.


Considerações finais

Neste artigo foi abordado um problema que ainda iremos lidar com mais profundidade no próximo artigo. Mas antes de terminar, quero mostrar uma pequena correção no código do Expert Advisor. Esta visa forçar o Expert Advisor a disparar um evento, quando a posição for fechada. Isto quando a linha de stop loss ou take profit, vierem a ser atingidas pelo preço. Sem esta correção, o indicador de posição, não será informado que já pode se retirar do gráfico. O código corrigido pode ser visto 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.121"
007. #property link "https://www.mql5.com/pt/articles/13265"
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.     static ulong ticket = 0;
064.     
065.     if (Terminal == NULL) return;
066.     switch (trans.type)
067.     {
068.         case TRADE_TRANSACTION_HISTORY_ADD:
069.             EventChartCustom(0, evUpdate_Position, trans.position, 0, "");
070.             ticket = (trans.order != trans.position ? trans.position : 0);
071.             break;
072.         case TRADE_TRANSACTION_REQUEST:
073.             if ((request.symbol == (*Terminal).GetInfoTerminal().szSymbol) && (result.retcode == TRADE_RETCODE_DONE)) switch (request.action)
074.             {
075.                 case TRADE_ACTION_DEAL:
076.                     if (ticket > 0) EventChartCustom(0, evUpdate_Position, ticket, 0, "");
077.                     else
078.                     {
079.                         int handle = iCustom(NULL, PERIOD_CURRENT, "\\Indicators\\Position View.ex5", result.order);
080.                         ChartIndicatorAdd(0, 0, handle);
081.                         IndicatorRelease(handle);
082.                     }
083.                     ticket = 0;
084.                     break;
085.                 case TRADE_ACTION_SLTP:
086.                     EventChartCustom(0, evUpdate_Position, request.position, 0, "");
087.                     break;
088.             }
089.             break;
090.     };
091. }
092. //+------------------------------------------------------------------+
093. void OnDeinit(const int reason)
094. {
095.     ulong ul;
096.     
097.     switch (reason)
098.     {
099.         case REASON_REMOVE:
100.         case REASON_INITFAILED:
101.             EventChartCustom(0, evEA_At_ChartTrade, -1, 0, "");
102.             break;
103.     }
104.     if (Terminal != NULL) for (int count = PositionsTotal() - 1; count >= 0; count--)
105.     {
106.         ul = PositionGetTicket(count);
107.         if (PositionGetString(POSITION_SYMBOL) != (*Terminal).GetInfoTerminal().szSymbol) continue;
108.         ChartIndicatorDelete(0, 0, IntegerToString(ul));
109.     }
110.     delete Orders;
111.     delete Terminal;
112. }
113. //+------------------------------------------------------------------+

Expert Advisor.mq5

A correção é justamente a inclusão da linha 69 no código. Sem a presença desta linha o evento de atualização, não estava sendo disparado. Isto quando a posição era fechada por atingir uma das linhas de preço. E como uma pequena explicação bônus, existe uma questão que talvez não tenha ficado clara durante este artigo. Tal questão envolve justamente a movimentação das linhas de stop loss e take profit. Muito provavelmente, você pode até dizer, e não estará errado em afirmar isto. De que por que estou me preocupando em criar tal movimentação. Se a mesma acontece, quando tentamos arrastar as linhas, que o indicador de posição estará criando.

Mas não é bem isto, que está acontecendo meu caro leitor. O detalhe, é que se você estiver usando um ativo, que pode ser negociado. Muito provavelmente o que está acontecendo é que você esteja movimentando as linhas criadas pelo MetaTrader 5. A tal movimentação que estamos planejando em criar, se dá justamente quando tais linhas criadas pelo MetaTrader 5, não estão presentes. Ou quando as configurações do MetaTrader 5, não indica que ele possa movimentar tais linhas.

Se você não sabe onde tal configuração é feita, basta olhar na imagem abaixo.

Por padrão, o MetaTrader 5, estará com a configuração mostrada acima. Porém se você a modificar para o que é visto na imagem logo a seguir, tal movimentação não ocorrerá.

É justamente neste ponto em que estaríamos utilizando o MetaTrader 5, como se o ativo no gráfico fosse um ativo não negociável. Ou seja, o típico caso que será visto quando estivermos usando este mesmo sistema ou indicadores no replay/simulação. Por isto que é importante que criemos todos os processos envolvidos na movimentação das linhas de preço. Não é uma questão de se precisamos ou não fazer isto. É uma questão de como e quando vamos fazer isto. Como forma de mostrar aqueles que estão acompanhando os artigos, porém não conseguem compilar os fontes. No anexo, deixo disponível os executáveis já modificados neste artigo. E nos vemos no próximo artigo, onde continuaremos a implementar um pouco mais o sistema de replay/simulador.

ArquivoDescriçã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.mq5Cria a janela para configuração da ordem a ser enviada (É necessário o Mouse Study para interação )
Indicators\Market Replay.mq5Cria os controles para interação com o serviço de replay/simulador (É necessário o Mouse Study para interação )
Indicators\Mouse Study.mq5Permite 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.mq5Responsável pela indicação de ordens de mercado, permitindo interação e controle das mesmas
Indicators\Position View.mq5Responsável pela indicação de posições de mercado, permitindo interação e controle das mesmas
Services\Market Replay.mq5Cria e mantém o serviço de replay e simulação de mercado (Arquivo principal de todo o sistema )
Arquivos anexados |
Anexo.zip (779.24 KB)
Negociação de notícias facilitada (parte 5): realizando negociações (II) Negociação de notícias facilitada (parte 5): realizando negociações (II)
Este artigo expandirá a classe de gerenciamento de trades para incluir ordens buy-stop e sell-stop para operar em eventos de notícias e implementará uma restrição de expiração nessas ordens para evitar qualquer negociação durante a noite. Uma função de slippage será incorporada ao expert para tentar prevenir ou minimizar possíveis deslizes que podem ocorrer ao usar ordens stop no trading, especialmente durante eventos de notícias.
Do básico ao intermediário: Filas, Listas e Árvores (I) Do básico ao intermediário: Filas, Listas e Árvores (I)
Neste artigo começaremos a explorar uma pequena série de conceitos, que é de suma importância para quem realmente deseja aprender a programar da maneira correta. Com se trata de algo que a principio pode ser muito complicado. Apesar de usar coisas simples. Iremos ver isto aos poucos. Então aqui iremos começar a ver o que seria filas de dados.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Análise de Múltiplos Símbolos com Python e MQL5 (Parte II): Análise de Componentes Principais para Otimização de Portfólio Análise de Múltiplos Símbolos com Python e MQL5 (Parte II): Análise de Componentes Principais para Otimização de Portfólio
Gerenciar o risco da conta de negociação é um desafio para todos os traders. Como podemos desenvolver aplicações de trading que aprendam dinamicamente modos de risco alto, médio e baixo para vários símbolos no MetaTrader 5? Usando PCA, ganhamos mais controle sobre a variância do portfólio. Vou demonstrar como criar aplicações que aprendem esses três modos de risco a partir de dados de mercado obtidos do MetaTrader 5.