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

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

MetaTrader 5Testador |
36 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 (VI), demonstrei como você poderia fazer para que o Expert Advisor pudesse dizer ao Indicador de posição, se ele deveria ou não ser atualizado. Ou em grande maioria dos casos, dizer para o indicador de posição, que ele deveria permanecer ou ser retirado do gráfico. Apesar do que foi visto no artigo anterior, ser de fato algo bastante interessante. Isto pelo ponto de vista, de como você pode começar a projetar algumas coisas no MetaTrader 5. Aquilo que foi visto, ainda não é algo realmente prático. Isto por conta que não podemos trabalhar diretamente no indicador de posição. Dizendo que uma linha do preço, seja o Stop Loss ou Take Profit devem ser movidos. Ou no mínimo, removidos da posição.

E mesmo assim, ainda temos uma outra questão. E talvez esta seja ainda mais interessante de ser feita logo. Que é justamente a possibilidade de fechar uma posição, usando para isto, algum tipo de interação com o indicador de posição. Isto nos pouparia o trabalho, ou preocupação, de ter que manter a janela do terminal na aba de negociação. O que pode ser interessante durante os testes, mas se torna algo desnecessário se pudermos interagir com o indicador de posição.

Então neste artigo, começaremos a fazer algumas melhorias no indicador de posição. Isto para que seja possível interagir com ele. E modificar as linhas de preço, ou fechar uma posição diretamente via interação com o indicador de posição. Antes de realmente começarmos a parte da implementação. Vamos entender uma coisa aqui. Isto para os menos avisados. Não é possível, de maneira ou forma alguma, usar um indicador a fim de modificar algo no servidor de negociação. Isto por conta que o MetaTrader 5, conta com um sistema de segurança que permite apenas e somente aos Expert Advisores, fazerem algo em uma ordem ou posição.

Apesar de você poder usar o próprio MetaTrader 5, em sua configuração padrão, para tal coisa. Nenhuma outra aplicação que não seja um Expert Advisor, conseguirá manipular ordens ou posições. Assim, o que iremos e faremos a partir deste momento. É criar um mecanismo de comunicação entre o indicador de posição e um Expert Advisor. De maneira que tenhamos a ilusão de que o indicador de posição esteja afetando o que se encontra no servidor. Mas isto, como acabei de informar é apenas uma ilusão.

Se você, entusiasta, pretende usar o que explicarei daqui a pouco. Saiba que terá que fazer com que as aplicações no MetaTrader 5, venham a trabalhar de forma colaborativa. Não pense que uma aplicação separada conseguirá fazer tudo que será mostrado. Pois isto não é algo real, apenas uma ilusão que estaremos criando. Porém tal ilusão, se for bem implementada, conseguirá permitir que você trabalhe, ou opere no MetaTrader 5, de uma maneira bastante agradável e confortável. Então vamos ao que interessa de fato.


Fechando uma posição, via interação com o indicador

Antes de começarmos a implementar certos mecanismos. Vamos fazer um mecanismo de segurança, por assim dizer. Isto por que, mesmo em uma conta de demonstração. Queremos logo de início começar a implementar uma maneira de fechar uma posição, sem precisar recorrer a outros mecanismos que não o indicador de posição.

Fazer tal coisa é algo relativamente simples e direto. Isto por que tudo que precisamos fazer, é criar algum tipo de objeto no gráfico, que ficará em uma dada posição. E quando este objeto receber um clique ou evento qualquer. Ele forçará o indicador de posição a disparar um evento. Este evento que será disparado, será capturado pelo Expert Advisor. Agora dentro do Expert Advisor, criaremos os mecanismos necessários para que este evento, vindo do indicador de posição, possa ser usado para enviar um requerimento ao servidor. Este requerimento terá como finalidade fechar a posição que o indicador de posição estiver mostrando no gráfico.

Veja que isto, apesar de à primeira vista parecer algo complexo e difícil. É algo relativamente simples, de ser feito. Desde é claro você esteja acompanhando esta sequência de artigos sobre como desenvolver um sistema de replay/simulador. E o motivo, é justamente por que já fizemos algo muito parecido antes. Isto quando o indicador Chart Trade foi construído. O que faremos agora é algo muito parecido com o mecanismo presente no indicador Chart Trade. Mas existem algumas pequenas diferenças que fazem de fato, o indicador de posição trabalhar, em temos de código, de maneira diferente do indicador Chart Trade. Então vamos começar, para que você consiga entender do que estou falando.

Muito bem, a primeira coisa que faremos será adicionar um novo evento ao arquivo Defines.mqh. Então o novo arquivo, 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.             evMsgClosePositionEA             //Event to communication
49.                         };
50. //+------------------------------------------------------------------+
51. enum EnumPriority {                          //Priority list on objects
52.             ePriorityNull = -1,
53.             ePriorityDefault = 0,
54.             ePriorityChartTrade = 5,
55.             ePriorityOrders = 10
56.                         };
57. //+------------------------------------------------------------------+

Defines.mqh

O novo evento foi colocado na linha 48. Acredito ser algo bastante evidente o que será feito. Mas por que não usar o evento do indicador Chart Trade, que está declarado na linha 42? O motivo é simples: Não quero limitar o indicador de posição ou mesmo o Expert Advisor, a trabalhar apenas em um tipo de conta. Se houvesse a certeza de que a aplicação somente seria executada em contas do tipo NETTING. Ok, poderíamos usar o evento da linha 42 sem nenhum problema. Porém, caso você viesse a usar estas mesmas aplicações, ou seja, o indicador de posição, mais o Expert Advisor em uma conta HEDGING, ao tentar fechar uma posição, todas as posições seriam fechadas juntas. Esta é uma das diferenças que existem na implementação de ambos indicadores.

Muito bem, agora que você sabe o que faremos. Precisamos modificar o código do indicador de posição e também o código do Expert Advisor. Isto para que o evento seja corretamente interpretado e executado. Bem, você pode estar preocupado e pensando: Gente mais isto será muito trabalhoso. Vamos ter que fazer muitas mudanças no código. Mas se você pensou isto, é por que, não está compreendendo ao código de fato. As mudanças para que tal tarefa possa ser executadas serão muito poucas. Então vamos primeiro ver as mudanças a serem feitas no código do Expert Advisor. Estas podem ser vista no código 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.     public    :
131. //+------------------------------------------------------------------+
132.         C_Orders(const ulong magic)
133.             {
134.                 m_Base.MagicNumber = magic;
135.             }
136. //+------------------------------------------------------------------+    
137.         void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
138.             {
139.                 switch (id)
140.                 {
141.                     case CHARTEVENT_CUSTOM + evChartTradeBuy     :
142.                     case CHARTEVENT_CUSTOM + evChartTradeSell    :
143.                     case CHARTEVENT_CUSTOM + evChartTradeCloseAll:
144.                         if (m_ChartTrade.Decode((EnumEvents)(id - CHARTEVENT_CUSTOM), sparam)) switch (m_ChartTrade.Data.ev)
145.                         {
146.                             case evChartTradeBuy:
147.                                 ToMarket(ORDER_TYPE_BUY);
148.                                 break;
149.                             case evChartTradeSell:
150.                                 ToMarket(ORDER_TYPE_SELL);
151.                                 break;
152.                             case evChartTradeCloseAll:
153.                                 CloseAllsPosition();
154.                                 break;
155.                         }
156.                         break;
157.                     case CHARTEVENT_CUSTOM + evMsgClosePositionEA:
158.                         ClosePosition((ulong)StringToInteger(sparam));
159.                         break;
160.                 }
161.             }
162. //+------------------------------------------------------------------+    
163. };
164. //+------------------------------------------------------------------+

C_Orders.mqh

Apesar de estarmos mostrando todo o código na íntegra da classe C_Orders. Isto para que você, caso não esteja acompanhando esta sequência, possa entender o que está acontecendo. Apenas tivemos o acréscimo de três misérias linhas no código da classe. Tais linhas são 157, 158 e 159. E é somente isto que foi preciso adicionar ao código do Expert Advisor, para que ele possa compreender um pedido de fechamento de posição. Agora preste atenção ao seguinte fato: Aqui não estamos discriminando absolutamente nenhuma informação. Então este mesmo evento pode ser disparado de um serviço, ou mesmo por um script, por exemplo. Não estamos prendendo, ou limitando em nada quem diz ao Expert Advisor para fazer algo. Que no caso é fechar uma posição. Tudo que precisamos realmente nos preocupar, será em informar no campo sparam, o bilhete da posição que desejamos fechar. Se o bilhete existir, a posição será fechada.

Agora observe o fato que mencionei acima. Onde não poderíamos usar o evento evChartTradeCloseAll. Justamente pelo fato de que a chamada a ser executada é diferente da que iremos de fato executar. Isto por conta, que está implementação que está sendo mostrada. Está sendo pensada para conseguir trabalhar em qualquer tipo de conta. Seja ela NETTING ou HEDGING. Ok. A parte referente ao Expert Advisor, já foi implementada. E com certeza funciona. Isto por que este código que estamos usando na classe C_Orders, já vem sendo testado a um bom tempo.

Então podemos nos concentrar na parte, que você caro leitor, e entusiasta, pode estar imaginando ser a mais complexa. Mas você verá que ela é igualmente simples. Bem, para mostrar que o trabalho a ser implementado no indicador de posição é algo simples. Não mudarei ele abruptamente neste momento. Irei simplesmente adicionar, o que é preciso, a fim de que a interação com o indicador de posição. Possa enviar um pedido para o Expert Advisor a fim de fechar a posição indicada. Isto é muito facilmente conseguido, conforme você pode ver abaixo.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #define def_SufixTake        "Take"
005. #define def_SufixStop        "Stop"
006. //+------------------------------------------------------------------+
007. #define def_NameBtnClose     m_Infos.szShortName + "Close"
008. //+------------------------------------------------------------------+
009. #define def_PathBtns "Images\\Market Replay\\Orders\\"
010. #define def_Btn_Close def_PathBtns + "Btn_Close.bmp"
011. #resource "\\" + def_Btn_Close;
012. //+------------------------------------------------------------------+
013. #include "..\Auxiliar\C_Terminal.mqh"
014. //+------------------------------------------------------------------+
015. class C_IndicatorPosition : private C_Terminal
016. {
017.     private    :
018.         struct st00
019.         {
020.             ulong     ticket;
021.             color     corPrice, corTake, corStop;
022.             string    szShortName;
023.         }m_Infos;
024. //+------------------------------------------------------------------+
025.         inline void MoveLineInfos(const string szDefine, const double price)
026.         {
027.             string szName = m_Infos.szShortName + szDefine;
028.             int x, y;
029.             
030.             if (price <= 0) ObjectDelete(0, szName);
031.             else
032.             {
033.                 if (ObjectFind(0, szName) < 0)
034.                 {
035.                     if (szDefine == def_SufixTake) CreateLineInfos(def_SufixTake, m_Infos.corTake, "Take Profit point."); else
036.                     if (szDefine == def_SufixStop) CreateLineInfos(def_SufixStop, m_Infos.corStop, "Stop Loss point."); else
037.                     {
038.                         CreateLineInfos(NULL, m_Infos.corPrice, "Position opening price.");
039.                         CreateObjectGraphics(def_NameBtnClose, OBJ_BITMAP_LABEL, clrNONE, (EnumPriority)(ePriorityOrders + 1));
040.                         ObjectSetString(0, def_NameBtnClose, OBJPROP_BMPFILE, 0, "::" + def_Btn_Close);
041.                     }
042.                 }                    
043.                 ObjectSetDouble(0, szName, OBJPROP_PRICE, price);
044.                 if (szDefine == NULL)
045.                 {
046.                     ChartTimePriceToXY(0, 0, 0, price, x, y);
047.                     ObjectSetInteger(0, def_NameBtnClose, OBJPROP_XDISTANCE, 130);
048.                     ObjectSetInteger(0, def_NameBtnClose, OBJPROP_YDISTANCE, y - 8);
049.                 }
050.             }
051.         }
052. //+------------------------------------------------------------------+
053.         void CreateLineInfos(string szObjName, const color cor, const string szDescription = "\n")
054.         {            
055.             szObjName = m_Infos.szShortName + szObjName;
056.             CreateObjectGraphics(szObjName, OBJ_HLINE, cor, (EnumPriority)(cor == m_Infos.corPrice ? ePriorityNull : (ePriorityOrders + (cor == m_Infos.corStop))));
057.             ObjectSetString(0, szObjName, OBJPROP_TEXT, szDescription);
058.             ObjectSetString(0, szObjName, OBJPROP_TOOLTIP, szDescription);
059.             ObjectSetInteger(0, szObjName, OBJPROP_SELECTABLE, cor != m_Infos.corPrice);
060.         }
061. //+------------------------------------------------------------------+
062.     public    :
063. //+------------------------------------------------------------------+
064.         C_IndicatorPosition(color corPrice, color corTake, color corStop)
065.             :C_Terminal()
066.         {
067.             ZeroMemory(m_Infos);
068.             m_Infos.corPrice = corPrice;
069.             m_Infos.corTake  = corTake;
070.             m_Infos.corStop  = corStop;
071.         }
072. //+------------------------------------------------------------------+
073.         ~C_IndicatorPosition()
074.         {
075.             if (m_Infos.ticket != 0)
076.                 ObjectsDeleteAll(0, IntegerToString(m_Infos.ticket));
077.         }
078. //+------------------------------------------------------------------+
079.         bool CheckCatch(ulong ticket)
080.         {
081.             m_Infos.szShortName = IntegerToString(m_Infos.ticket = ticket);            
082.             if (!PositionSelectByTicket(m_Infos.ticket)) return false;
083.             if (ObjectFind(0, m_Infos.szShortName) >= 0)
084.             {
085.                 m_Infos.ticket = 0;
086.                 return false;
087.             }
088.             IndicatorSetString(INDICATOR_SHORTNAME, m_Infos.szShortName);
089.             EventChartCustom(0, evUpdate_Position, ticket, 0, "");
090.             
091.             return true;
092.         }
093. //+------------------------------------------------------------------+
094.         void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
095.         {
096.             static double price = 0;
097.             
098.             switch (id)
099.             {
100.                 case CHARTEVENT_CUSTOM + evUpdate_Position:
101.                     if (lparam != m_Infos.ticket) return;
102.                     if (!PositionSelectByTicket(m_Infos.ticket))
103.                     {
104.                         ChartIndicatorDelete(0, 0, m_Infos.szShortName);
105.                         return;
106.                     };
107.                     MoveLineInfos(NULL, price = PositionGetDouble(POSITION_PRICE_OPEN));
108.                     MoveLineInfos(def_SufixTake, PositionGetDouble(POSITION_TP));
109.                     MoveLineInfos(def_SufixStop, PositionGetDouble(POSITION_SL));
110.                     break;
111.                 case CHARTEVENT_CHART_CHANGE:
112.                     MoveLineInfos(NULL, price);
113.                     break;
114.                 case CHARTEVENT_OBJECT_CLICK:
115.                     if (sparam == def_NameBtnClose)
116.                         EventChartCustom(0, evMsgClosePositionEA, 0, 0, m_Infos.szShortName);
117.                     break;
118.             }
119.             ChartRedraw();
120.         }
121. //+------------------------------------------------------------------+
122. };
123. //+------------------------------------------------------------------+
124. #undef def_Btn_Close
125. #undef def_PathBtns
126. //+------------------------------------------------------------------+
127. #undef def_NameBtnClose
128. //+------------------------------------------------------------------+
129. #undef def_SufixTake
130. #undef def_SufixStop
131. //+------------------------------------------------------------------+

C_IndicatorPosition.mqh

Muito bem, aqui temos o código da classe C_IndicatorPosition. Veja que ele sofreu muito, mais muito pouco em termos de implementação. Porém, este código, consegue colocar um objeto no gráfico que nos permite interagir e pedir para que o Expert Advisor, feche a posição. Mas como isto acontece? Bem, vamos entender este código antes de o tornar um pouco melhor. Isto por que este código não é adequado para implementarmos ainda mais o nosso indicador. Mas é bom que você, caro leitor, o entenda antes de partirmos para um código mais elaborado.

Observe que na linha sete, temos uma definição. Esta tem como objetivo criar um nome para o objeto que iremos interagir a fim de fechar a posição. Logo depois, entre as linhas nove e onze. Temos algo que você deverá providenciar localmente. Isto caso queira criar o seu próprio modelo. Caso você não queira ter este trabalho. Não se preocupe, pois em breve irei disponibilizar os aplicativos no artigo. Assim como foi feito no artigo anterior.

Bem, continuando. Na linha nove, dizemos onde o bitmap da imagem estará localizado. Na linha 10, informamos qual é o bitmap. Neste caso, você deverá providenciar uma imagem de 16 x 16 pixels. Mas poderá usar uma imagem diferente, desde é claro faça as devidas mudanças no código. O local onde você deverá mudar, será visto depois. Por hora, vamos nos preocupar com a linha 11. Nesta linha, dizemos ao compilador MQL5, que desejamos que o bitmap seja colocado como recurso no executável. Isto permite que uma vez feita a compilação. O bitmap não precisará ser transportado junto com o restante da aplicação. O que facilita muito a nossa vida e a vida do usuário final.

Muito bem, prosseguimos no código sem muitas mudanças. A não ser por dois pontos. Por hora, não vamos nos preocupar com a rotina presente na linha 25. Que é um dos pontos onde as mudanças aconteceram. Vamos direto para a linha 94. Onde temos a implementação do código responsável por tratar as mensagens oriundas do MetaTrader 5.

Agora preste atenção, pois entender o que está acontecendo neste procedimento da linha 94, será muito importante para o que será visto depois. Note que na linha 96, foi adicionada uma variável estática. Ela não existirá no futuro. Mas neste momento ela nos permite armazenar localmente, e servir como memória para o preço onde a posição foi aberta. Note que esta mesma variável é inicializada na linha 107. Muito bem. Agora já temos o preço onde a posição foi aberta. É importante notar que este valor não se alterará durante todo o tempo. Mas precisamos dele em um ponto bastante específico. Tal ponto é justamente a linha 112. Observe que esta linha está presente, dentro do tratador de evento CHARTEVENT_CHART_CHANGE. O motivo disto é simples. Quando você muda a escala de preço no gráfico, as linhas de preço mudam junto.

Porém temos um problema, que será visto depois, quando voltarmos a linha 25. Que é o fato do botão que estamos colocando no gráfico, não se mover junto das linhas de preço. Para resolver isto, enviamos um pedindo como é visto na linha 112, a fim de atualizar a posição do botão no gráfico. Por isto precisamos saber o preço onde a posição foi aberta. Se a cada movimentação na escala do preço, tivéssemos que procurar o valor onde a posição foi aberta. Teríamos um atraso significativo na execução das aplicações presentes no gráfico. E como o preço da posição não muda. Podemos simplificar as coisas ao máximo.

Porém, o que realmente nos interessa neste procedimento DispatchMessage, é justamente o que vem a seguir. Ou seja, o código implementado na linha 114. Note que ali, verificamos se um objeto recebeu um clique do mouse. Quando o MetaTrader 5 reportar que isto ocorreu, ele dirá qual o objeto que recebeu um clique. E o nome do objeto, vem justamente na variável sparam. Assim, na linha 115 testamos se o nome bate com o nome do objeto criado lá no início, ou seja, na linha sete. Caso tal teste feito na linha 115, seja verdadeiro. Na linha 116, pedimos para o MetaTrader 5, enviar um evento customizado a fim de ser capturado pelo Expert Advisor.

Note os valores que estão no tal evento. São justamente os esperados pelo Expert Advisor a fim de conseguir entender, que o usuário ou operador deseja fechar a posição. Legal não é mesmo? Agora vamos ver como o objeto, ou bitmap que representa o botão para fechar a posição é criado e posicionado no gráfico. Para isto, iremos neste momento voltar nossa atenção a linha 25. Que é justamente onde as coisas acontecem.

Note que aqui fizemos algumas poucas mudanças frente ao que existia antes. A primeira foi adicionar na linha 28, as variáveis x e y. Depois disto, na linha 38 criamos a nossa linha de preço. Como era feito antes. Porém, como precisamos de um outro objeto, que neste caso será o botão para fechar a posição. Na linha 39 o criamos. Observe como estamos fazendo isto, e o tipo de objeto que estamos criando. Ou seja, um objeto OBJ_BITMAP_LABEL. Este objeto para ser posicionado adequadamente precisa receber os valores em termos de coordenadas X e Y. Não podemos usar coordenadas de preço. Mas logo depois de criar o objeto. Na linha 40, dizemos para o MetaTrader 5, usar a imagem que se encontra como sendo um recurso do executável. É neste ponto, e não na linha onze, que fazemos a ligação da imagem presente no executável e ignoramos a imagem presente no diretório. Mas até neste momento, apenas criamos o objeto. Não o apresentamos ainda na tela.

Para posicionar ele no ponto correto, precisamos efetuar uma conversão, entre os valores que fazem uso de coordenadas de preço tempo para coordenadas cartesianas. Felizmente o MQL5 tem uma função para nos ajudar que é usada na linha 46. Ali convertemos os valores do preço em uma posição adequada para a coordenada do eixo Y. Muito bem, esta é a parte fácil, porém você deve tomar um pequeno cuidado. Isto por que, observem na linha 48 o que estamos fazendo. Ali estou subtraindo oito do valor que a função da linha 46, me devolveu. Por que estou fazendo esta subtração e por que deste valor oito? Bem, o motivo de estarmos fazendo esta subtração é pelo fato de que o objeto OBJ_BITMAP_LABEL não está ancorado em seu centro. Mas sim no canto superior esquerdo.

Como não me preocupei em fazer a ancoragem no centro do objeto, preciso ajustar a posição do mesmo. Daí vai o fato de precisar subtrair oito. Isto por que a imagem bitmap usada tem 16 x 16 pixel e para centralizar ela, precisamos subtrair oito pixels. Simples assim. Com tudo isto sendo executado, você poderá interagir com o indicador de posição. Isto a fim de fechar uma posição clicando no objeto que acabamos de criar e posicionar. Mas podemos fazer bem mais. Porém, para que o código não se torne algo insustentável, precisamos e iremos melhorar o mesmo. Assim teremos bem mais capacidades, com um mínimo de codificação. Porém para separar adequadamente as coisas, vamos ver isto em um novo tópico.


Melhorando ainda mais as coisas

Se você, caro leitor e entusiasta, parar e pensar um pouco. Irá notar que, já temos o objeto que nos permite fechar uma posição. Temos as linhas de preço sendo mostradas no gráfico. Temos a capacidade de enviar pedidos do indicador de posição para o Expert Advisor. E tudo isto com um mínimo de modificações necessárias. Porém, como poderíamos colocar o mesmo tipo de interação usada para fechar a posição. Nas linhas de stop loss e take profit a fim de remover o limite de perda e limite de ganho. Isto diretamente via interação com o indicador de posição. Sem fazer uso da aba negociação presente no terminal do MetaTrader 5.

Você, caro leitor e entusiasta, pode imaginar que isto seria algo simples. Já que bastaria duplicar o mesmo código usado para fechar a posição, e o modificar a fim de remover o stop loss ou o take profit do gráfico. De certa maneira, é desta forma mesmo que você deveria pensar. Porém, imagine o seguinte cenário: Se você duplicar o código, a fim de conseguir cumprir o objetivo, terá sucesso. Mas o trabalho exigido caso você deseje melhorar ainda mais o indicador, será muito maior. Já que seria necessário, que você viesse a atualizar todos os pontos em que o código foi replicado. Em muitos casos isto é uma tarefa relativamente simples e pouco custosa.

Mas que tal fazermos a coisa de uma maneira um pouco mais agradável. Ou melhor, de forma que você não precise se preocupar com isto. Bastará dizer que uma linha representa algo e o próprio código se encarregaria de criá-la da forma correta? Com todos os objetos já inclusos e funcionais. Seria muito bom, não é mesmo? Pois bem. É justamente isto que faremos neste momento. Vamos criar um meio para que isto aconteça. Mas como é uma tarefa que exigirá atenção. E quero de fato que você, meu caro leitor e entusiasta entenda o que e por que estou fazendo. Vamos ver isto aos poucos. Assim você conseguirá modificar facilmente o código, caso deseje fazer isto.

A primeira coisa que faremos, antes de mais nada, será adicionar alguns novos eventos ao arquivo Defines.mqh. Assim o novo arquivo pode ser visto logo abaixo. Já com os novos eventos já definidos.

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.                         };
52. //+------------------------------------------------------------------+
53. enum EnumPriority {                          //Priority list on objects
54.             ePriorityNull = -1,
55.             ePriorityDefault = 0,
56.             ePriorityChartTrade = 5,
57.             ePriorityOrders = 10
58.                         };
59. //+------------------------------------------------------------------+

Defines.mqh

Observe que é tudo muito simples e prático. Não existe nenhuma complicação em entender o que foi feito aqui. Logo depois de termos feito isto, vamos passar a próxima etapa. Está na verdade é um pouco mais trabalhosa neste primeiro momento. Então irei com calma para que você de fato entenda o que está acontecendo. Muito bem, o que desejamos fazer é adicionar o mecanismo que nos permite remover as linhas de take profit e stop loss. Mas não basta apenas adicionar isto ao bloco de mensagem. Já que não temos como executar o pedido. Desta forma, precisamos modificar o código do Expert Advisor. E para fazer esta mudança, iremos direto no ponto vital. Que é justamente o arquivo de cabeçalho C_Orders.mqh. Este arquivo receberá um novo código como é 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.                 m_Base.TradeRequest.magic    = m_Base.MagicNumber;
136.                 m_Base.TradeRequest.action   = TRADE_ACTION_SLTP;
137.                 m_Base.TradeRequest.symbol   = symbol;
138.                 m_Base.TradeRequest.position = ticket;
139.                 m_Base.TradeRequest.sl       = sl;
140.                 m_Base.TradeRequest.tp       = tp;
141.                 
142.                 TradeRequest[0] = m_Base.TradeRequest;
143.                 ArrayPrint(TradeRequest);
144.                 
145.                 SendToPhysicalServer();
146.             }
147. //+------------------------------------------------------------------+    
148.     public    :
149. //+------------------------------------------------------------------+
150.         C_Orders(const ulong magic)
151.             {
152.                 m_Base.MagicNumber = magic;
153.             }
154. //+------------------------------------------------------------------+    
155.         void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
156.             {
157.                 switch (id)
158.                 {
159.                     case CHARTEVENT_CUSTOM + evChartTradeBuy     :
160.                     case CHARTEVENT_CUSTOM + evChartTradeSell    :
161.                     case CHARTEVENT_CUSTOM + evChartTradeCloseAll:
162.                         if (m_ChartTrade.Decode((EnumEvents)(id - CHARTEVENT_CUSTOM), sparam)) switch (m_ChartTrade.Data.ev)
163.                         {
164.                             case evChartTradeBuy:
165.                                 ToMarket(ORDER_TYPE_BUY);
166.                                 break;
167.                             case evChartTradeSell:
168.                                 ToMarket(ORDER_TYPE_SELL);
169.                                 break;
170.                             case evChartTradeCloseAll:
171.                                 CloseAllsPosition();
172.                                 break;
173.                         }
174.                         break;
175.                     case CHARTEVENT_CUSTOM + evMsgClosePositionEA:
176.                         ClosePosition((ulong)(lparam));
177.                         break;
178.                     case CHARTEVENT_CUSTOM + evMsgCloseTakeProfit:
179.                         ModifyValueSLTP((ulong)(lparam), sparam, dparam, 0);
180.                         break;
181.                     case CHARTEVENT_CUSTOM + evMsgCloseStopLoss:
182.                         ModifyValueSLTP((ulong)(lparam), sparam, 0, dparam);
183.                         break;
184.                 }
185.             }
186. //+------------------------------------------------------------------+    
187. };
188. //+------------------------------------------------------------------+

C_Orders.mqh

Este código acima está na íntegra, como todos outros. E olhando ele você pode pensar: Bem, não estou vendo nenhuma grande diferença frente ao que existia antes. De fato, eu sempre tento evitar mudanças muito radicais no código. Mas sim existem mudanças aqui. E elas visam nos dar suporte ao que precisamos, para este e o próximo passo no desenvolvimento. Mas vamos primeiramente nos focar neste passo. Que é remover as linhas de take profit e stop loss. Observe no código acima, que na linha 130 temos um novo procedimento. Este visa modificar o valor do stop loss e take profit de uma posição aberta. Preste atenção a isto. Neste momento não estamos nos preocupando em ordens presentes no book. E sim em trabalhar em uma posição já aberta. Existe diferença entre ambas situações.

Basicamente, recebemos alguns parâmetros a serem usados, e enviamos o pedido para o servidor possa modificar os pontos de take profit e stop loss. Na linha 143 imprimimos no terminal o pedido que foi enviado ao servidor. Isto para que possamos conferir o mesmo a fim de analisar o funcionamento do sistema. Ok, já que este procedimento é bastante simples, sendo necessário apenas passar os argumentos para ele. Podemos ir ao próximo ponto onde o código sofreu mudanças. Este ponto é visto no procedimento da linha 155.

Neste ponto, é que realmente trataremos os pedidos que o Expert Advisor receberá. Lembre-se, o pedido pode ter qualquer fonte, não precisa necessariamente ser o indicador de posição que estou mostrando. Então estude o que estou mostrando para criar a sua própria solução. Note que o código deste procedimento DispatchMessage, permanece praticamente idêntico ao que era antes. Porém, olhe com mais atenção. Você verá que aqui mudei algumas coisas. E o motivo será visto no próximo artigo.

Note que na linha 175, onde testamos se a mensagem recebida é um pedido de fechamento de posição. Que o código que implementa o fechamento foi modificado. Isto é a linha 176, sofreu uma leve mudança. Antes o bilhete era informado na variável sparam, agora estou usando a variável lparam. Note que isto tem uma justificativa, mas será melhor compreendida no próximo artigo. Agora, observe os dois outros testes que estão sendo feitos a fim de verificar qual a mensagem recebida. O primeiro teste é visto na linha 178, onde verificamos se a mensagem é de remoção do take profit. Assim como o teste na linha 181, onde verificamos se a mensagem é um pedido de remoção do stop loss.

Em ambos casos, temos um mesmo destino, ou seja, o procedimento ModifyValueSLTP, que visa mudar o valor dos limites da posição. Observem, com atenção, o que cada um dos parâmetros repassados. Note que a diferença aqui, é apenas onde o parâmetro dparam é usado. Em um caso ele está no que seria o take profit e no outro onde seria o stop loss. Desta forma conseguimos remover um dos limites. Já que quando um deles receber o valor zero, ele será removido. Isto por que o servidor de negociação entende que o valor zero, representa que o limite, seja ele o take profit ou stop loss, simplesmente não existe. Com isto concluímos a parte de modificação necessária no código do Expert Advisor, não precisando fazer nenhuma outra mudança no código. Pelo menos por hora.


Considerações finais

Neste artigo, mostrei como você pode de maneira bastante simples e eficiente. Implementar uma forma de fechar uma posição. Fazendo uso de uma interação entre o Indicador de mouse e o indicador de posição, aliados ao Expert Advisor devidamente codificado. Todo o trabalho foi feito de uma forma bastante elegante. Já que não foi preciso fazer grandes mudanças no código. Também mostrei toda a parte que foi necessário implementar no código do Expert Advisor para que, possamos criar um mecanismo cuja finalidade seria remover as linhas de take profit e stop loss.

No entanto, devido ao maior número de mudanças que deverão acontecer no código do indicador de posição. Não irei neste artigo apresentar o código já modificado. Farei a devida apresentação e explicação no próximo artigo. Isto para que você, meu caro leitor e entusiasta, consiga de fato entender como e por que o código funciona. Mas principalmente, por que o MetaTrader 5, consegue entender a apresentar devidamente as coisas para você que esteja operando. Você verá que não precisamos nos preocupar com certos detalhes. E muito do que realmente precisamos fazer, será simplesmente dizer ao MetaTrader 5, para enviar uma mensagem e o resto acontecerá naturalmente. Sem muitos esforços ou preocupações.

Espero que você, que tem mais experiência em MQL5, ou mesmo que esteja começando, compreenda que aqui, meu intuito é ensinar as pessoas, como podemos fazer as coisas. Então se ficou curioso, estude este artigo e o código com cautela. Pois no próximo, iremos ver a parte do indicador de posição.

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)
Redes neurais em trading: Modelos bidimensionais do espaço de conexões (Conclusão) Redes neurais em trading: Modelos bidimensionais do espaço de conexões (Conclusão)
Damos continuidade ao estudo do framework inovador Chimera, um modelo bidimensional do espaço de estados que utiliza tecnologias de redes neurais para análise de séries temporais multidimensionais. Esse método garante alta precisão de previsão com baixo custo computacional.
Do básico ao intermediário: Navegando na SandBox Do básico ao intermediário: Navegando na SandBox
Neste artigo veremos duas formas de observar e até mesmo ter alguma interação com o conteúdo presente em uma SandBox. Isto usando a plataforma MetaTrader 5 como ponto de apoio. Entender o conteúdo mostrado neste artigo, será primordial para entender o que será visto nos próximos artigos.
Análise de todas as variantes do movimento do preço em um computador quântico da IBM Análise de todas as variantes do movimento do preço em um computador quântico da IBM
Usamos o computador quântico da IBM para abrir todos os cenários possíveis de movimento do preço. Parece ficção científica? Bem-vindo ao mundo dos cálculos quânticos aplicados ao trading!
Negociando com o Calendário Econômico do MQL5 (Parte 1): Dominando as Funções do Calendário Econômico do MQL5 Negociando com o Calendário Econômico do MQL5 (Parte 1): Dominando as Funções do Calendário Econômico do MQL5
Neste artigo, exploramos como usar o Calendário Econômico do MQL5 para negociar, primeiro entendendo suas funcionalidades principais. Em seguida, implementamos funções-chave do Calendário Econômico no MQL5 para extrair dados relevantes de notícias para decisões de negociação. Por fim, concluímos mostrando como utilizar essas informações para aprimorar as estratégias de negociação de forma eficaz.