English Русский 中文 Español Deutsch 日本語
Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXVIII): ordens pendentes de negociação - fechamento, exclusão, modificações

Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXVIII): ordens pendentes de negociação - fechamento, exclusão, modificações

MetaTrader 5Exemplos | 18 março 2020, 09:38
2 021 0
Artyom Trishkin
Artyom Trishkin

Sumário

Este é o terceiro artigo por trás do conceito de ordens pendentes. Nele, concluiremos o teste de ordens pendentes de negociação, após criar métodos para fechar posições, excluir ordens pendentes e alterar os stop de posições e os parâmetros modificáveis de ordens pendentes.

Também complementaremos um pouco a classe da ordem abstrata, uma vez que, por algum motivo que desconheço, esqueci-me do retorno de valores das duas propriedades das ordens e posições, nomeadamente esqueci o tipo de preenchimento de ordem e do seu tipo de expiração. Eis que os adicionaremos. Como o código de todos os métodos do objeto básico de negociação multiplataforma foi ligeiramente otimizado, não vamos descrevê-lo em detalhes, em vez disso, tomaremos apenas um exemplo de algum dos métodos alterados.

Preparação de dados

Precisamos de mensagens de texto para descrever as propriedades adicionadas da ordem abstrata e uma mensagem para a classe de ordens pendentes.

Ao arquivo Datas.mqh adicionamos os índices destas mensagens:

   MSG_ORD_TIME_EXP,                                  // Expiration date
   MSG_ORD_TYPE_FILLING,                              // Type of execution by remainder
   MSG_ORD_TYPE_TIME,                                 // Order lifetime
   MSG_ORD_TYPE,                                      // Type

...

   MSG_LIB_TEXT_PEND_REQUEST_CREATED,                 // Pending request created
   MSG_LIB_TEXT_PEND_REQUEST_DELETED,                 // Pending request is removed due to its expiration
   MSG_LIB_TEXT_PEND_REQUEST_EXECUTED,                // Pending request is removed due to its execution

e as mensagens de texto correspondente aos índices declarados:

   {"Дата экспирации","Date of expiration"},
   {"Тип исполнения по остатку","Order filling type"},
   {"Время жизни ордера","Order lifetime"},
   {"Тип","Type"},

...

   {"Создан отложенный запрос","Pending request created"},
   {"Отложенный запрос удалён в связи с окончанием времени его действия","Pending request deleted due to expiration"},
   {"Отложенный запрос удалён в связи с его исполнением","Pending request deleted due to execution"},

Como adicionamos mais duas propriedades ao objeto de ordem abstrata, faremos alterações em parte de suas propriedades no arquivo Defines.mqh.

No bloco de propriedades inteiras da ordem escrevemos duas novas propriedades e aumentamos o número total de propriedades inteiras de 24 para 26:

//+------------------------------------------------------------------+
//| Order, deal, position integer properties                         |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_INTEGER
  {
   ORDER_PROP_TICKET = 0,                                   // Order ticket
   ORDER_PROP_MAGIC,                                        // Real order magic number
   ORDER_PROP_TIME_OPEN,                                    // Open time in milliseconds (MQL5 Deal time)
   ORDER_PROP_TIME_CLOSE,                                   // Close time in milliseconds (MQL5 Execution or removal time - ORDER_TIME_DONE)
   ORDER_PROP_TIME_EXP,                                     // Order expiration date (for pending orders)
   ORDER_PROP_TYPE_FILLING,                                 // Type of execution by remainder
   ORDER_PROP_TYPE_TIME,                                    // Order lifetime
   ORDER_PROP_STATUS,                                       // Order status (from the ENUM_ORDER_STATUS enumeration)
   ORDER_PROP_TYPE,                                         // Order/deal type
   ORDER_PROP_REASON,                                       // Deal/order/position reason or source
   ORDER_PROP_STATE,                                        // Order status (from the ENUM_ORDER_STATE enumeration)
   ORDER_PROP_POSITION_ID,                                  // Position ID
   ORDER_PROP_POSITION_BY_ID,                               // Opposite position ID
   ORDER_PROP_DEAL_ORDER_TICKET,                            // Ticket of the order that triggered a deal
   ORDER_PROP_DEAL_ENTRY,                                   // Deal direction – IN, OUT or IN/OUT
   ORDER_PROP_TIME_UPDATE,                                  // Position change time in milliseconds
   ORDER_PROP_TICKET_FROM,                                  // Parent order ticket
   ORDER_PROP_TICKET_TO,                                    // Derived order ticket
   ORDER_PROP_PROFIT_PT,                                    // Profit in points
   ORDER_PROP_CLOSE_BY_SL,                                  // Flag of closing by StopLoss
   ORDER_PROP_CLOSE_BY_TP,                                  // Flag of closing by TakeProfit
   ORDER_PROP_MAGIC_ID,                                     // Order's "magic number" ID
   ORDER_PROP_GROUP_ID1,                                    // First order/position group ID
   ORDER_PROP_GROUP_ID2,                                    // Second order/position group ID
   ORDER_PROP_PEND_REQ_ID,                                  // Pending request ID
   ORDER_PROP_DIRECTION,                                    // Type by direction (Buy, Sell)
  }; 
#define ORDER_PROP_INTEGER_TOTAL    (26)                    // Total number of integer properties
#define ORDER_PROP_INTEGER_SKIP     (0)                     // Number of order properties not used in sorting
//+------------------------------------------------------------------+

Adicionamos um recurso para classificação de ordem segundo estas duas propriedades:

//+------------------------------------------------------------------+
//| Possible criteria of sorting orders and deals                    |
//+------------------------------------------------------------------+
#define FIRST_ORD_DBL_PROP          (ORDER_PROP_INTEGER_TOTAL-ORDER_PROP_INTEGER_SKIP)
#define FIRST_ORD_STR_PROP          (ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_DOUBLE_TOTAL-ORDER_PROP_INTEGER_SKIP)
enum ENUM_SORT_ORDERS_MODE
  {
//--- Sort by integer properties
   SORT_BY_ORDER_TICKET = 0,                                // Sort by an order ticket
   SORT_BY_ORDER_MAGIC,                                     // Sort by an order magic number
   SORT_BY_ORDER_TIME_OPEN,                                 // Sort by an order open time in milliseconds
   SORT_BY_ORDER_TIME_CLOSE,                                // Sort by an order close time in milliseconds
   SORT_BY_ORDER_TIME_EXP,                                  // Sort by an order expiration date
   SORT_BY_ORDER_TYPE_FILLING,                              // Sort by execution type by remainder
   SORT_BY_ORDER_TYPE_TIME,                                 // Sort by order lifetime
   SORT_BY_ORDER_STATUS,                                    // Sort by an order status (market order/pending order/deal/balance and credit operation)
   SORT_BY_ORDER_TYPE,                                      // Sort by an order type
   SORT_BY_ORDER_REASON,                                    // Sort by a deal/order/position reason/source
   SORT_BY_ORDER_STATE,                                     // Sort by an order status
   SORT_BY_ORDER_POSITION_ID,                               // Sort by a position ID
   SORT_BY_ORDER_POSITION_BY_ID,                            // Sort by an opposite position ID
   SORT_BY_ORDER_DEAL_ORDER,                                // Sort by the order a deal is based on
   SORT_BY_ORDER_DEAL_ENTRY,                                // Sort by a deal direction – IN, OUT or IN/OUT
   SORT_BY_ORDER_TIME_UPDATE,                               // Sort by position change time in seconds
   SORT_BY_ORDER_TICKET_FROM,                               // Sort by a parent order ticket
   SORT_BY_ORDER_TICKET_TO,                                 // Sort by a derived order ticket
   SORT_BY_ORDER_PROFIT_PT,                                 // Sort by order profit in points
   SORT_BY_ORDER_CLOSE_BY_SL,                               // Sort by the flag of closing an order by StopLoss
   SORT_BY_ORDER_CLOSE_BY_TP,                               // Sort by the flag of closing an order by TakeProfit
   SORT_BY_ORDER_MAGIC_ID,                                  // Sort by an order/position "magic number" ID
   SORT_BY_ORDER_GROUP_ID1,                                 // Sort by the first order/position group ID
   SORT_BY_ORDER_GROUP_ID2,                                 // Sort by the second order/position group ID
   SORT_BY_ORDER_PEND_REQ_ID,                               // Sort by a pending request ID
   SORT_BY_ORDER_DIRECTION,                                 // Sort by direction (Buy, Sell)
//--- Sort by real properties
   SORT_BY_ORDER_PRICE_OPEN = FIRST_ORD_DBL_PROP,           // Sort by open price
   SORT_BY_ORDER_PRICE_CLOSE,                               // Sort by close price
   SORT_BY_ORDER_SL,                                        // Sort by StopLoss price
   SORT_BY_ORDER_TP,                                        // Sort by TakeProfit price
   SORT_BY_ORDER_PROFIT,                                    // Sort by profit
   SORT_BY_ORDER_COMMISSION,                                // Sort by commission
   SORT_BY_ORDER_SWAP,                                      // Sort by swap
   SORT_BY_ORDER_VOLUME,                                    // Sort by volume
   SORT_BY_ORDER_VOLUME_CURRENT,                            // Sort by unexecuted volume
   SORT_BY_ORDER_PROFIT_FULL,                               // Sort by profit+commission+swap
   SORT_BY_ORDER_PRICE_STOP_LIMIT,                          // Sort by Limit order when StopLimit order is activated
//--- Sort by string properties
   SORT_BY_ORDER_SYMBOL = FIRST_ORD_STR_PROP,               // Sort by symbol
   SORT_BY_ORDER_COMMENT,                                   // Sort by comment
   SORT_BY_ORDER_COMMENT_EXT,                               // Sort by custom comment
   SORT_BY_ORDER_EXT_ID                                     // Sort by order ID in an external trading system
  };
//+------------------------------------------------------------------+

Como agora passaremos completamente para o trabalho com ordens pendentes ao receber erros do servidor, erros esses que exigem uma espera (em vez de Sleep(), que atrasa a execução da restante lógica do programa),
na lista que descreve o comportamento do EA quanto ao processamento de erros excluímos o item para criação de ordem pendente
, pois ele será criado por padrão:

//+------------------------------------------------------------------+
//| EA behavior when handling errors                                 |
//+------------------------------------------------------------------+
enum ENUM_ERROR_HANDLING_BEHAVIOR
  {
   ERROR_HANDLING_BEHAVIOR_BREAK,                           // Abort trading attempt
   ERROR_HANDLING_BEHAVIOR_CORRECT,                         // Correct invalid parameters
   ERROR_HANDLING_BEHAVIOR_PENDING_REQUEST,                 // Create a pending request
  };
//+------------------------------------------------------------------+

Agora, esta enumeração fica assim:

//+------------------------------------------------------------------+
//| EA behavior when handling errors                                 |
//+------------------------------------------------------------------+
enum ENUM_ERROR_HANDLING_BEHAVIOR
  {
   ERROR_HANDLING_BEHAVIOR_BREAK,                           // Abort trading attempt
   ERROR_HANDLING_BEHAVIOR_CORRECT,                         // Correct invalid parameters
  };
//+------------------------------------------------------------------+

Da mesma forma, não precisamos deste item na enumeração que descreve os métodos para processar códigos de retorno do servidor, vamos o excluir:

//+------------------------------------------------------------------+
//| The methods of handling errors and server return codes           |
//+------------------------------------------------------------------+
enum ENUM_ERROR_CODE_PROCESSING_METHOD
  {
   ERROR_CODE_PROCESSING_METHOD_OK,                         // No errors
   ERROR_CODE_PROCESSING_METHOD_DISABLE,                    // Disable trading for the EA
   ERROR_CODE_PROCESSING_METHOD_EXIT,                       // Exit the trading method
   ERROR_CODE_PROCESSING_METHOD_CORRECT,                    // Correct trading request parameters and repeat
   ERROR_CODE_PROCESSING_METHOD_REFRESH,                    // Update data and repeat
   ERROR_CODE_PROCESSING_METHOD_PENDING,                    // Create a pending request
   ERROR_CODE_PROCESSING_METHOD_WAIT,                       // Wait and repeat
  };
//+------------------------------------------------------------------+

Agora, esta enumeração fica assim:

//+------------------------------------------------------------------+
//| The methods of handling errors and server return codes           |
//+------------------------------------------------------------------+
enum ENUM_ERROR_CODE_PROCESSING_METHOD
  {
   ERROR_CODE_PROCESSING_METHOD_OK,                         // No errors
   ERROR_CODE_PROCESSING_METHOD_DISABLE,                    // Disable trading for the EA
   ERROR_CODE_PROCESSING_METHOD_EXIT,                       // Exit the trading method
   ERROR_CODE_PROCESSING_METHOD_CORRECT,                    // Correct trading request parameters and repeat
   ERROR_CODE_PROCESSING_METHOD_REFRESH,                    // Update data and repeat
   ERROR_CODE_PROCESSING_METHOD_WAIT,                       // Wait and repeat
  };
//+------------------------------------------------------------------+

Hoje, aos parâmetros de ordens pendentes adicionaremos novas propriedades e (olhando para o futuro) para não retornar ao arquivo Defines.mqh, escreveremos no seu final uma enumeração com possíveis critérios para classificar ordens pendentes. Para encontrá-los será necessário:

//+------------------------------------------------------------------+
//| Possible pending request sorting criteria                        |
//+------------------------------------------------------------------+
enum ENUM_SORT_PEND_REQ_MODE
  {
   SORT_BY_PEND_REQ_ID = 0,                                 // Sort by ID
   SORT_BY_PEND_REQ_TYPE,                                   // Sort by type
   SORT_BY_PEND_REQ_TICKET,                                 // Sort by ticket
  };
//+------------------------------------------------------------------+

Agora diretamente na classe de ordem abstrata COrder no arquivo Order.mqh escrevemos todas as alterações necessárias.

No bloco de métodos de acesso simplificado às propriedades inteiras de objeto-ordem inserimos métodos para retornar essas novas propriedades:

//+------------------------------------------------------------------+
//| Methods of a simplified access to the order object properties    |
//+------------------------------------------------------------------+
//--- Return (1) ticket, (2) parent order ticket, (3) derived order ticket, (4) magic number, (5) order reason,
//--- (6) position ID, (7) opposite position ID, (8) first group ID, (9) second group ID,
//--- (10) pending request ID, (11) magic number ID, (12) type, (13) flag of closing by StopLoss,
//--- (14) flag of closing by TakeProfit (15) open time, (16) close time,
//--- (17) order expiration date, (18) state, (19) status, (20) type by direction, (21) execution type by remainder, (22) order lifetime
   long              Ticket(void)                                       const { return this.GetProperty(ORDER_PROP_TICKET);                     }
   long              TicketFrom(void)                                   const { return this.GetProperty(ORDER_PROP_TICKET_FROM);                }
   long              TicketTo(void)                                     const { return this.GetProperty(ORDER_PROP_TICKET_TO);                  }
   long              Magic(void)                                        const { return this.GetProperty(ORDER_PROP_MAGIC);                      }
   long              Reason(void)                                       const { return this.GetProperty(ORDER_PROP_REASON);                     }
   long              PositionID(void)                                   const { return this.GetProperty(ORDER_PROP_POSITION_ID);                }
   long              PositionByID(void)                                 const { return this.GetProperty(ORDER_PROP_POSITION_BY_ID);             }
   long              MagicID(void)                                      const { return this.GetProperty(ORDER_PROP_MAGIC_ID);                   }
   long              GroupID1(void)                                     const { return this.GetProperty(ORDER_PROP_GROUP_ID1);                  }
   long              GroupID2(void)                                     const { return this.GetProperty(ORDER_PROP_GROUP_ID2);                  }
   long              PendReqID(void)                                    const { return this.GetProperty(ORDER_PROP_PEND_REQ_ID);                }
   long              TypeOrder(void)                                    const { return this.GetProperty(ORDER_PROP_TYPE);                       }
   bool              IsCloseByStopLoss(void)                            const { return (bool)this.GetProperty(ORDER_PROP_CLOSE_BY_SL);          }
   bool              IsCloseByTakeProfit(void)                          const { return (bool)this.GetProperty(ORDER_PROP_CLOSE_BY_TP);          }
   long              TimeOpen(void)                                     const { return this.GetProperty(ORDER_PROP_TIME_OPEN);                  }
   long              TimeClose(void)                                    const { return this.GetProperty(ORDER_PROP_TIME_CLOSE);                 }
   datetime          TimeExpiration(void)                               const { return (datetime)this.GetProperty(ORDER_PROP_TIME_EXP);         }
   ENUM_ORDER_STATE  State(void)                                        const { return (ENUM_ORDER_STATE)this.GetProperty(ORDER_PROP_STATE);    }
   ENUM_ORDER_STATUS Status(void)                                       const { return (ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS);  }
   ENUM_ORDER_TYPE   TypeByDirection(void)                              const { return (ENUM_ORDER_TYPE)this.GetProperty(ORDER_PROP_DIRECTION); }
   ENUM_ORDER_TYPE_FILLING TypeFilling(void)                            const { return (ENUM_ORDER_TYPE_FILLING)this.GetProperty(ORDER_PROP_TYPE_FILLING);  }
   ENUM_ORDER_TYPE_TIME TypeTime(void)                                  const { return (ENUM_ORDER_TYPE_TIME)this.GetProperty(ORDER_PROP_TYPE_TIME);        }

Os métodos simplesmente retornam os valores especificados nos parâmetros inteiros correspondentes a estas propriedades.

Num construtor de classe fechado escrevemos o preenchimento de duas novas propriedades do objeto-ordem:

//+------------------------------------------------------------------+
//| Closed parametric constructor                                    |
//+------------------------------------------------------------------+
COrder::COrder(ENUM_ORDER_STATUS order_status,const ulong ticket)
  {
//--- Save integer properties
   this.m_ticket=ticket;
   this.m_long_prop[ORDER_PROP_STATUS]                               = order_status;
   this.m_long_prop[ORDER_PROP_MAGIC]                                = this.OrderMagicNumber();
   this.m_long_prop[ORDER_PROP_TICKET]                               = this.OrderTicket();
   this.m_long_prop[ORDER_PROP_TIME_EXP]                             = this.OrderExpiration();
   this.m_long_prop[ORDER_PROP_TYPE_FILLING]                         = this.OrderTypeFilling();
   this.m_long_prop[ORDER_PROP_TYPE_TIME]                            = this.OrderTypeTime();
   this.m_long_prop[ORDER_PROP_TYPE]                                 = this.OrderType();
   this.m_long_prop[ORDER_PROP_STATE]                                = this.OrderState();
   this.m_long_prop[ORDER_PROP_DIRECTION]                            = this.OrderTypeByDirection();
   this.m_long_prop[ORDER_PROP_POSITION_ID]                          = this.OrderPositionID();
   this.m_long_prop[ORDER_PROP_REASON]                               = this.OrderReason();
   this.m_long_prop[ORDER_PROP_DEAL_ORDER_TICKET]                    = this.DealOrderTicket();
   this.m_long_prop[ORDER_PROP_DEAL_ENTRY]                           = this.DealEntry();
   this.m_long_prop[ORDER_PROP_POSITION_BY_ID]                       = this.OrderPositionByID();
   this.m_long_prop[ORDER_PROP_TIME_OPEN]                            = this.OrderOpenTimeMSC();
   this.m_long_prop[ORDER_PROP_TIME_CLOSE]                           = this.OrderCloseTimeMSC();
   this.m_long_prop[ORDER_PROP_TIME_UPDATE]                          = this.PositionTimeUpdateMSC();
   
//--- Save real properties
   this.m_double_prop[this.IndexProp(ORDER_PROP_PRICE_OPEN)]         = this.OrderOpenPrice();
   this.m_double_prop[this.IndexProp(ORDER_PROP_PRICE_CLOSE)]        = this.OrderClosePrice();
   this.m_double_prop[this.IndexProp(ORDER_PROP_PROFIT)]             = this.OrderProfit();
   this.m_double_prop[this.IndexProp(ORDER_PROP_COMMISSION)]         = this.OrderCommission();
   this.m_double_prop[this.IndexProp(ORDER_PROP_SWAP)]               = this.OrderSwap();
   this.m_double_prop[this.IndexProp(ORDER_PROP_VOLUME)]             = this.OrderVolume();
   this.m_double_prop[this.IndexProp(ORDER_PROP_SL)]                 = this.OrderStopLoss();
   this.m_double_prop[this.IndexProp(ORDER_PROP_TP)]                 = this.OrderTakeProfit();
   this.m_double_prop[this.IndexProp(ORDER_PROP_VOLUME_CURRENT)]     = this.OrderVolumeCurrent();
   this.m_double_prop[this.IndexProp(ORDER_PROP_PRICE_STOP_LIMIT)]   = this.OrderPriceStopLimit();
   
//--- Save string properties
   this.m_string_prop[this.IndexProp(ORDER_PROP_SYMBOL)]             = this.OrderSymbol();
   this.m_string_prop[this.IndexProp(ORDER_PROP_COMMENT)]            = this.OrderComment();
   this.m_string_prop[this.IndexProp(ORDER_PROP_EXT_ID)]             = this.OrderExternalID();
   
//--- Save additional integer properties
   this.m_long_prop[ORDER_PROP_PROFIT_PT]                            = this.ProfitInPoints();
   this.m_long_prop[ORDER_PROP_TICKET_FROM]                          = this.OrderTicketFrom();
   this.m_long_prop[ORDER_PROP_TICKET_TO]                            = this.OrderTicketTo();
   this.m_long_prop[ORDER_PROP_CLOSE_BY_SL]                          = this.OrderCloseByStopLoss();
   this.m_long_prop[ORDER_PROP_CLOSE_BY_TP]                          = this.OrderCloseByTakeProfit();
   this.m_long_prop[ORDER_PROP_MAGIC_ID]                             = this.GetMagicID();
   this.m_long_prop[ORDER_PROP_GROUP_ID1]                            = this.GetGroupID1();
   this.m_long_prop[ORDER_PROP_GROUP_ID2]                            = this.GetGroupID2();
   this.m_long_prop[ORDER_PROP_PEND_REQ_ID]                          = this.GetPendReqID();
   
//--- Save additional real properties
   this.m_double_prop[this.IndexProp(ORDER_PROP_PROFIT_FULL)]        = this.ProfitFull();
   
//--- Save additional string properties
   this.m_string_prop[this.IndexProp(ORDER_PROP_COMMENT_EXT)]        = "";
  }
//+------------------------------------------------------------------+

Neste caso, simplesmente nos respectivos valores da matriz de propriedades da ordem são inseridos os valores retornados pelos métodos OrderTypeFilling() e OrderTypeTime(), que retornam estas propriedades.

No método que retorna as descrições de propriedades inteiras do objeto-ordem, inserimos a exibição de descrição de duas novas propriedades:

//+------------------------------------------------------------------+
//| Return description of an order's integer property                |
//+------------------------------------------------------------------+
string COrder::GetPropertyDescription(ENUM_ORDER_PROP_INTEGER property)
  {
   return
     (
   //--- General properties
      property==ORDER_PROP_MAGIC             ?  CMessage::Text(MSG_ORD_MAGIC)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET            ?  CMessage::Text(MSG_ORD_TICKET)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET_FROM       ?  CMessage::Text(MSG_ORD_TICKET_FROM)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET_TO         ?  CMessage::Text(MSG_ORD_TICKET_TO)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TIME_EXP          ?  CMessage::Text(MSG_ORD_TIME_EXP)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          (this.GetProperty(property)==0     ?  CMessage::Text(MSG_LIB_PROP_NOT_SET)            :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS))
         )  :
      property==ORDER_PROP_TYPE_FILLING      ?  CMessage::Text(MSG_ORD_TYPE_FILLING)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+OrderTypeFillingDescription((ENUM_ORDER_TYPE_FILLING)this.GetProperty(property))
         )  :
      property==ORDER_PROP_TYPE_TIME         ?  CMessage::Text(MSG_ORD_TYPE_TIME)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+OrderTypeTimeDescription((ENUM_ORDER_TYPE_TIME)this.GetProperty(property))
         )  :
      property==ORDER_PROP_TYPE              ?  CMessage::Text(MSG_ORD_TYPE)+": "+this.TypeDescription()   :
      property==ORDER_PROP_DIRECTION         ?  CMessage::Text(MSG_ORD_TYPE_BY_DIRECTION)+": "+this.DirectionDescription() :
      
      property==ORDER_PROP_REASON            ?  CMessage::Text(MSG_ORD_REASON)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetReasonDescription(this.GetProperty(property))
         )  :
      property==ORDER_PROP_POSITION_ID       ?  CMessage::Text(MSG_ORD_POSITION_ID)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_DEAL_ORDER_TICKET ?  CMessage::Text(MSG_ORD_DEAL_ORDER_TICKET)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_DEAL_ENTRY        ?  CMessage::Text(MSG_ORD_DEAL_ENTRY)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetEntryDescription(this.GetProperty(property))
         )  :
      property==ORDER_PROP_POSITION_BY_ID    ?  CMessage::Text(MSG_ORD_POSITION_BY_ID)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TIME_OPEN         ?  CMessage::Text(MSG_ORD_TIME_OPEN)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+TimeMSCtoString(this.GetProperty(property))+" ("+(string)this.GetProperty(property)+")"
         )  :
      property==ORDER_PROP_TIME_CLOSE        ?  CMessage::Text(MSG_ORD_TIME_CLOSE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+TimeMSCtoString(this.GetProperty(property))+" ("+(string)this.GetProperty(property)+")"
         )  :
      property==ORDER_PROP_TIME_UPDATE       ?  CMessage::Text(MSG_ORD_TIME_UPDATE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property)!=0 ? TimeMSCtoString(this.GetProperty(property))+" ("+(string)this.GetProperty(property)+")" : "0")
         )  :
      property==ORDER_PROP_STATE             ?  CMessage::Text(MSG_ORD_STATE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": \""+this.StateDescription()+"\""
         )  :
   //--- Additional property
      property==ORDER_PROP_STATUS            ?  CMessage::Text(MSG_ORD_STATUS)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": \""+this.StatusDescription()+"\""
         )  :
      property==ORDER_PROP_PROFIT_PT         ?  (
                                                 this.Status()==ORDER_STATUS_MARKET_PENDING ? 
                                                 CMessage::Text(MSG_ORD_DISTANCE_PT)  : 
                                                 CMessage::Text(MSG_ORD_PROFIT_PT)
                                                )+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_CLOSE_BY_SL       ?  CMessage::Text(MSG_LIB_PROP_CLOSE_BY_SL)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property)   ?  CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==ORDER_PROP_CLOSE_BY_TP       ?  CMessage::Text(MSG_LIB_PROP_CLOSE_BY_TP)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property)   ?  CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==ORDER_PROP_MAGIC_ID          ?  CMessage::Text(MSG_ORD_MAGIC_ID)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_GROUP_ID1         ?  CMessage::Text(MSG_ORD_GROUP_ID1)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_GROUP_ID2         ?  CMessage::Text(MSG_ORD_GROUP_ID2)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_PEND_REQ_ID       ?  CMessage::Text(MSG_ORD_PEND_REQ_ID)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

Como no primeiro artigo dedicado à criação de um objeto de ordem abstrata vimos o funcionamento desse método, aqui não o consideraremos novamente.

Nos artigos anteriores, ao implementar os métodos de abertura de posições e de definição de ordens pendentes com a ajuda de objetos de ordens pendentes, nós, para identificar cada ordem pendente, usávamos seu identificador exclusivo, que durante a abertura de posições ou durante a definição da ordem era gravado no valor do número mágico da posição ou da ordem. Por isso, era fácil identificar a presença de ordens pendentes já criadas, bem como entender como eram abertas as posições (devido a uma ordem habitual ou ao funcionamento do objeto da ordem pendente). Isso era necessário para não criar vários objetos de ordens pendentes para a mesma ação de negociação.

Mas, aqui, ao fechar posições, excluir ordens ou modificá-las, o identificador já não será mais útil, pois, afinal, podemos realizar operações de negociação com quaisquer ordens ou posições, segundo um ticket. Por essa razão, para entender para qual ordem/posição é criada a ordem pendente, precisamos usar o número do ticket. Este ticket está na estrutura da ordem de negociação no objeto da ordem pendente. Com o seu valor podemos determinar inequivocamente o ticket da ordem ou da posição, para as quais foi criada a ordem pendente. Mas também precisamos determinar o momento do processamento bem-sucedido da ordem pendente, isto é, quando, com a ajuda de tal solicitação, uma ordem de negociação é enviada ao servidor e é executada com êxito. Em seguida, devemos determinar se o funcionamento da ordem de negociação pendente é bem-sucedido e excluir esse objeto-ordem, para que não faça outra tentativa de negociação após a execução bem-sucedida da anterior.

Para isso, nós já fizemos tudo: classe de eventos de negociação na conta e classe-coleção desses eventos. A classe-coleção de eventos de negociação já nos dá acesso total a todos os eventos ocorridos desde a inicialização do programa e aos eventos atuais "aqui e agora". Por isso, para obter acesso à classe-coleção de eventos de negociação, precisamos anexá-la à classe de negociação, transferindo à classe de negociação um ponteiro para a classe-coleção de eventos de negociação. Para fazer isso, precisamos que esta classe consiga se retornar a si mesma. Adicionamos essa possibilidade.

No arquivo da classe de eventos de negociação EventsCollection.mqh adicionamos o método público GetObject():

//+------------------------------------------------------------------+
//| Collection of account trading events                             |
//+------------------------------------------------------------------+
class CEventsCollection : public CBaseObj
  {
private:
   CListObj          m_list_trade_events;             // List of events
   bool              m_is_hedge;                      // Hedge account flag
   int               m_trade_event_code;              // Trading event code
   ENUM_TRADE_EVENT  m_trade_event;                   // Account trading event
   CEvent            m_event_instance;                // Event object for searching by property
   ulong             m_position_id;                   // Position ID (MQL4)
   ENUM_ORDER_TYPE   m_type_first;                    // Opening order type (MQL4)
   
//--- Create a trading event depending on the (1) order status and (2) change type
   void              CreateNewEvent(COrder* order,CArrayObj* list_history,CArrayObj* list_market,CArrayObj* list_control);
   void              CreateNewEvent(COrderControl* order);
//--- Create an event for a (1) hedging account, (2) netting account
   void              NewDealEventHedge(COrder* deal,CArrayObj* list_history,CArrayObj* list_market);
   void              NewDealEventNetto(COrder* deal,CArrayObj* list_history,CArrayObj* list_market);
//--- Select and return the list of (1) market pending orders and (2) open positions
   CArrayObj*        GetListMarketPendings(CArrayObj* list);
   CArrayObj*        GetListPositions(CArrayObj* list);
//--- Select and return the list of historical (1) closed positions,
//--- (2) removed pending orders, (3) deals, (4) all closing orders 
   CArrayObj*        GetListHistoryPositions(CArrayObj* list);
   CArrayObj*        GetListHistoryPendings(CArrayObj* list);
   CArrayObj*        GetListDeals(CArrayObj* list);
   CArrayObj*        GetListCloseByOrders(CArrayObj* list);
//--- Return the list of (1) all position orders by its ID, (2) all deal positions by its ID
//--- (3) all market entry deals by position ID, (4) all market exit deals by position ID,
//--- (5) all position reversal deals by position ID
   CArrayObj*        GetListAllOrdersByPosID(CArrayObj* list,const ulong position_id);
   CArrayObj*        GetListAllDealsByPosID(CArrayObj* list,const ulong position_id);
   CArrayObj*        GetListAllDealsInByPosID(CArrayObj* list,const ulong position_id);
   CArrayObj*        GetListAllDealsOutByPosID(CArrayObj* list,const ulong position_id);
   CArrayObj*        GetListAllDealsInOutByPosID(CArrayObj* list,const ulong position_id);
//--- Return the total volume of all deals (1) IN, (2) OUT of the position by its ID
   double            SummaryVolumeDealsInByPosID(CArrayObj* list,const ulong position_id);
   double            SummaryVolumeDealsOutByPosID(CArrayObj* list,const ulong position_id);
//--- Return the (1) first, (2) last and (3) closing order from the list of all position orders,
//--- (4) an order by ticket, (5) market position by ID,
//--- (6) the last and (7) penultimate InOut deal by position ID
   COrder*           GetFirstOrderFromList(CArrayObj* list,const ulong position_id);
   COrder*           GetLastOrderFromList(CArrayObj* list,const ulong position_id);
   COrder*           GetCloseByOrderFromList(CArrayObj* list,const ulong position_id);
   COrder*           GetHistoryOrderByTicket(CArrayObj* list,const ulong order_ticket);
   COrder*           GetPositionByID(CArrayObj* list,const ulong position_id);
//--- Return (1) the control order by a ticket, (2) the type of the opening order by the position ticket (MQL4)
   COrderControl*    GetOrderControlByTicket(CArrayObj* list,const ulong ticket);
   ENUM_ORDER_TYPE   GetTypeFirst(CArrayObj* list,const ulong ticket);
//--- Return the flag of the event object presence in the event list
   bool              IsPresentEventInList(CEvent* compared_event);
//--- The handler of an existing order/position change event
   void              OnChangeEvent(CArrayObj* list_changes,const int index);

public:
//--- Return itself
   CEventsCollection*GetObject(void)                                                                     { return &this;                                                         }
//--- Select events from the collection with time within the range from begin_time to end_time
   CArrayObj        *GetListByTime(const datetime begin_time=0,const datetime end_time=0);
//--- Return the full event collection list "as is"
   CArrayObj        *GetList(void)                                                                       { return &this.m_list_trade_events;                                     }
//--- Return the list by selected (1) integer, (2) real and (3) string properties meeting the compared criterion
   CArrayObj        *GetList(ENUM_EVENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL)  { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_EVENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_EVENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
//--- Update the list of events
   void              Refresh(CArrayObj* list_history,
                             CArrayObj* list_market,
                             CArrayObj* list_changes,
                             CArrayObj* list_control,
                             const bool is_history_event,
                             const bool is_market_event,
                             const int  new_history_orders,
                             const int  new_market_pendings,
                             const int  new_market_positions,
                             const int  new_deals,
                             const double changed_volume);
//--- Return (1) the last trading event on an account, (2) base event object by index and (3) number of new events
   ENUM_TRADE_EVENT  GetLastTradeEvent(void)                const { return this.m_trade_event;                 }
   CEventBaseObj    *GetTradeEventByIndex(const int index)        { return this.GetEvent(index,false);         }
   int               GetTradeEventsTotal(void)              const { return this.m_list_events.Total();         }
//--- Reset the last trading event
   void              ResetLastTradeEvent(void)                    { this.m_trade_event=TRADE_EVENT_NO_EVENT;   }
//--- Constructor
                     CEventsCollection(void);
  };
//+------------------------------------------------------------------+

Agora a classe CEventsCollection pode retornar um ponteiro para si mesma. Mais tarde precisaremos disso.

Anteriormente, eu disse que a classe básica de negociação passou por alguma otimização de código dos métodos de negociação. Vejamos isso com a ajuda do método de abertura de posição. As alterações principalmente dizem respeito ao bloco para enviar ordens de negociação para o servidor.

Anteriormente, o código era assim:

//+------------------------------------------------------------------+
//| Open a position                                                  |
//+------------------------------------------------------------------+
bool CTradeObj::OpenPosition(const ENUM_POSITION_TYPE type,
                             const double volume,
                             const double sl=0,
                             const double tp=0,
                             const ulong magic=ULONG_MAX,
                             const string comment=NULL,
                             const ulong deviation=ULONG_MAX,
                             const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   ::ResetLastError();
   //--- If failed to get the current prices, write the error code and description, send the message to the journal and return 'false'
   if(!::SymbolInfoTick(this.m_symbol,this.m_tick))
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_GET_PRICE),CMessage::Text(this.m_result.retcode));
      return false;
     }
   //--- Clear the structures
   ::ZeroMemory(this.m_request);
   ::ZeroMemory(this.m_result);
   //--- Fill in the request structure
   this.m_request.action   =  TRADE_ACTION_DEAL;
   this.m_request.symbol   =  this.m_symbol;
   this.m_request.magic    =  (magic==ULONG_MAX ? this.m_magic : magic);
   this.m_request.type     =  (ENUM_ORDER_TYPE)type;
   this.m_request.price    =  (type==POSITION_TYPE_BUY ? this.m_tick.ask : this.m_tick.bid);
   this.m_request.volume   =  volume;
   this.m_request.sl       =  sl;
   this.m_request.tp       =  tp;
   this.m_request.deviation=  (deviation==ULONG_MAX ? this.m_deviation : deviation);
   this.m_request.comment  =  (comment==NULL ? this.m_comment : comment);
   //--- Return the result of sending a request to the server
#ifdef __MQL5__
   return(!this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result));
#else 
   ::ResetLastError();
   int ticket=::OrderSend(m_request.symbol,m_request.type,m_request.volume,m_request.price,(int)m_request.deviation,m_request.sl,m_request.tp,m_request.comment,(int)m_request.magic,m_request.expiration,clrNONE);
   ::SymbolInfoTick(this.m_symbol,this.m_tick);
   if(ticket!=WRONG_VALUE)
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.ask=this.m_tick.ask;
      this.m_result.bid=this.m_tick.bid;
      this.m_result.deal=ticket;
      this.m_result.price=(::OrderSelect(ticket,SELECT_BY_TICKET) ? ::OrderOpenPrice() : this.m_request.price);
      this.m_result.volume=(::OrderSelect(ticket,SELECT_BY_TICKET) ? ::OrderLots() : this.m_request.volume);
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      return true;
     }
   else
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.ask=this.m_tick.ask;
      this.m_result.bid=this.m_tick.bid;
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      return false;
     }
#endif 
  }
//+------------------------------------------------------------------+

Se olharmos atentamente, veremos muitas construções de código repetitivas. Todas elas foram colocadas fora do bloco de verificação de ticket. Também foi cometido um erro lógico ao redefinir o último código de erro em MQL4, pois ele é redefinido antes de enviar a ordem de negociação para o servidor, e acontece que, antes de receber o código de erro, inserimos uma função para obter preços, função essa que também pode retornar um erro. Neste caso, o código do último erro não pertencerá mais ao código de retorno do servidor de negociação em MQL4.

Agora, em vista do exposto,
o bloco para o envio de uma ordem de negociação para o servidor no método que permite abrir uma posição fica assim:

//+------------------------------------------------------------------+
//| Open a position                                                  |
//+------------------------------------------------------------------+
bool CTradeObj::OpenPosition(const ENUM_POSITION_TYPE type,
                             const double volume,
                             const double sl=0,
                             const double tp=0,
                             const ulong magic=ULONG_MAX,
                             const string comment=NULL,
                             const ulong deviation=ULONG_MAX,
                             const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   ::ResetLastError();
   //--- If failed to get the current prices, write the error code and description, send the message to the journal and return 'false'
   if(!::SymbolInfoTick(this.m_symbol,this.m_tick))
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_GET_PRICE),CMessage::Text(this.m_result.retcode));
      return false;
     }
   //--- Clear the structures
   ::ZeroMemory(this.m_request);
   ::ZeroMemory(this.m_result);
   //--- Fill in the request structure
   this.m_request.action   =  TRADE_ACTION_DEAL;
   this.m_request.symbol   =  this.m_symbol;
   this.m_request.magic    =  (magic==ULONG_MAX ? this.m_magic : magic);
   this.m_request.type     =  (ENUM_ORDER_TYPE)type;
   this.m_request.price    =  (type==POSITION_TYPE_BUY ? this.m_tick.ask : this.m_tick.bid);
   this.m_request.volume   =  volume;
   this.m_request.sl       =  sl;
   this.m_request.tp       =  tp;
   this.m_request.deviation=  (deviation==ULONG_MAX ? this.m_deviation : deviation);
   this.m_request.comment  =  (comment==NULL ? this.m_comment : comment);
   //--- Return the result of sending a request to the server
#ifdef __MQL5__
   return(!this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result));
#else 
   ::ResetLastError();
   int ticket=::OrderSend(m_request.symbol,m_request.type,m_request.volume,m_request.price,(int)m_request.deviation,m_request.sl,m_request.tp,m_request.comment,(int)m_request.magic,m_request.expiration,clrNONE);
   this.m_result.retcode=::GetLastError();
   ::SymbolInfoTick(this.m_symbol,this.m_tick);
   this.m_result.ask=this.m_tick.ask;
   this.m_result.bid=this.m_tick.bid;
   this.m_result.comment=CMessage::Text(this.m_result.retcode);
   if(ticket!=WRONG_VALUE)
     {
      this.m_result.deal=ticket;
      this.m_result.price=(::OrderSelect(ticket,SELECT_BY_TICKET) ? ::OrderOpenPrice() : this.m_request.price);
      this.m_result.volume=(::OrderSelect(ticket,SELECT_BY_TICKET) ? ::OrderLots() : this.m_request.volume);
      return true;
     }
   else
     {
      return false;
     }
#endif 
  }
//+------------------------------------------------------------------+

Da mesma forma, foram corrigidos todos os outros métodos de negociação da classe, com pequenas diferenças de método para método devido à sua especificidade.
Todas as alterações podem ser visualizadas independentemente nos códigos anexados no final do artigo.

Agora, abordaremos diretamente a criação de métodos para trabalhar com ordens pendentes para fechamento de posições/exclusão de ordens e para modificar os parâmetros de posições e ordens.

Solicitações pendentes para fechar/excluir/modificar posições e ordens pendentes


Primeiro de tudo, no arquivo da classe básica de negociação Trading.mqh anexamos a classe da coleção de eventos de negociação da conta:

//+------------------------------------------------------------------+
//|                                                      Trading.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/pt/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/pt/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <Arrays\ArrayInt.mqh>
#include "Objects\Trade\TradeObj.mqh"
#include "Collections\AccountsCollection.mqh"
#include "Collections\SymbolsCollection.mqh"
#include "Collections\MarketCollection.mqh"
#include "Collections\HistoryCollection.mqh"
#include "Collections\EventsCollection.mqh"
//+------------------------------------------------------------------+

À classe do objeto da ordem pendente CPendingReq (cuja listagem está no mesmo arquivo)
adicionamos os métodos de retorno de ticket de ordem, de ticket de posição e de tipo de operação:

//+------------------------------------------------------------------+
//| Pending request object class                                     |
//+------------------------------------------------------------------+
class CPendingReq : public CObject
  {
private:
   MqlTradeRequest      m_request;                       // Trade request structure
   uchar                m_id;                            // Trading request ID
   int                  m_type;                          // Pending request type
   int                  m_retcode;                       // Result a request is based on
   double               m_price_create;                  // Price at the moment of a request generation
   ulong                m_time_create;                   // Request generation time
   ulong                m_time_activate;                 // Next attempt activation time
   ulong                m_waiting_msc;                   // Waiting time between requests
   uchar                m_current_attempt;               // Current attempt index
   uchar                m_total_attempts;                // Number of attempts
//--- Copy trading request data
   void                 CopyRequest(const MqlTradeRequest &request)  { this.m_request=request;        }
//--- Compare CPendingReq objects by IDs
   virtual int          Compare(const CObject *node,const int mode=0) const;

public:
//--- Return (1) the request structure, (2) the price at the moment of the request generation,
//--- (3) request generation time, (4) next attempt activation time,
//--- (5) waiting time between requests, (6) current attempt index,
//--- (7) number of attempts, (8) request ID
//--- (9) result a request is based on,
//--- (10) order ticket, (11) position ticket, (12) trading operation type
   MqlTradeRequest      MqlRequest(void)                       const { return this.m_request;         }
   double               PriceCreate(void)                      const { return this.m_price_create;    }
   ulong                TimeCreate(void)                       const { return this.m_time_create;     }
   ulong                TimeActivate(void)                     const { return this.m_time_activate;   }
   ulong                WaitingMSC(void)                       const { return this.m_waiting_msc;     }
   uchar                CurrentAttempt(void)                   const { return this.m_current_attempt; }
   uchar                TotalAttempts(void)                    const { return this.m_total_attempts;  }
   uchar                ID(void)                               const { return this.m_id;              }
   int                  Retcode(void)                          const { return this.m_retcode;         }
   ulong                Order(void)                            const { return this.m_request.order;   }
   ulong                Position(void)                         const { return this.m_request.position;}
   ENUM_TRADE_REQUEST_ACTIONS Action(void)                     const { return this.m_request.action;  }


E também adicionamos os métodos para definir o ticket da ordem e o ticket da posição:

//--- Set (1) the price when creating a request, (2) request creation time,
//--- (3) current attempt time, (4) waiting time between requests,
//--- (5) current attempt index, (6) number of attempts, (7) ID,
//--- (8) order ticket, (9) position ticket
   void                 SetPriceCreate(const double price)           { this.m_price_create=price;     }
   void                 SetTimeCreate(const ulong time)              { this.m_time_create=time;       }
   void                 SetTimeActivate(const ulong time)            { this.m_time_activate=time;     }
   void                 SetWaitingMSC(const ulong miliseconds)       { this.m_waiting_msc=miliseconds;}
   void                 SetCurrentAttempt(const uchar number)        { this.m_current_attempt=number; }
   void                 SetTotalAttempts(const uchar number)         { this.m_total_attempts=number;  }
   void                 SetID(const uchar id)                        { this.m_id=id;                  }
   void                 SetOrder(const ulong ticket)                 { this.m_request.order=ticket;   }
   void                 SetPosition(const ulong ticket)              { this.m_request.position=ticket;}
   

O método Compare() para comparar objetos da classe CPendingReq entre si, de acordo com as propriedades que sejam especificadas, sofreu alterações.
Anteriormente, ele era assim:

//+------------------------------------------------------------------+
//| Compare CPendingReq objects by properties                        |
//+------------------------------------------------------------------+
int CPendingReq::Compare(const CObject *node,const int mode=0) const
  {
   const CPendingReq *compared_req=node;
   return
     (
      //--- Compare by ID
      mode==0  ?  
      (this.ID()>compared_req.ID() ? 1 : this.ID()<compared_req.ID() ? -1 : 0)   :
      //--- Compare by type
      (this.Type()>compared_req.Type() ? 1 : this.Type()<compared_req.Type() ? -1 : 0)
     );
  }
//+------------------------------------------------------------------+

Quer dizer, a comparação era feita apenas com base em duas propriedades do objeto-ordem pendente.
Agora que, para comparação, foi adicionada uma terceira propriedade, o método ficou assim:

//+------------------------------------------------------------------+
//| Compare CPendingReq objects by properties                        |
//+------------------------------------------------------------------+
int CPendingReq::Compare(const CObject *node,const int mode=0) const
  {
   const CPendingReq *compared_req=node;
   return
     (
      //--- Compare by ID
      mode==SORT_BY_PEND_REQ_ID        ?  
      (this.ID()>compared_req.ID()     ? 1 : this.ID()<compared_req.ID() ? -1 : 0)     :
      //--- Compare by type
      mode==SORT_BY_PEND_REQ_TYPE      ?  
      (this.Type()>compared_req.Type() ? 1 : this.Type()<compared_req.Type() ? -1 : 0) :
      //--- Compare by ticket
      (
       //--- modifying position sl, tp, opening/closing a position or closing by an opposite one
       this.m_request.action==TRADE_ACTION_SLTP    || this.m_request.action==TRADE_ACTION_DEAL     || this.m_request.action==TRADE_ACTION_CLOSE_BY ?
       (this.m_request.position>compared_req.m_request.position ? 1 : this.m_request.position<compared_req.m_request.position ? -1 : 0)            :
       //--- modifying parameters, placing/removing a pending order
       this.m_request.action==TRADE_ACTION_MODIFY  || this.m_request.action==TRADE_ACTION_PENDING  || this.m_request.action==TRADE_ACTION_REMOVE   ?
       (this.m_request.order>compared_req.m_request.order ? 1 : this.m_request.order<compared_req.m_request.order ? -1 : 0)                        : 
       //--- otherwise
       0
      )
     );
  }
//+------------------------------------------------------------------+

  • Se o modo de comparação, transferido ao método, for igual ao valor da constante SORT_BY_PEND_REQ_ID da enumeração ENUM_SORT_PEND_REQ_MODE, significa que a comparação é realizada de acordo com o identificador do objeto da ordem pendente;
  • Se o modo de comparação for igual ao de SORT_BY_PEND_REQ_TYPE, significa que a comparação é realizada de acordo com o tipo de objeto da ordem pendente;
  • O terceiro modo de comparação (SORT_BY_PEND_REQ_TICKET) é realizado da seguinte maneira:
    - verificamos o tipo de operação de negociação, e
    • se ela for uma modificação do stop da posição, uma abertura/fechamento de posição ou fechamento usando a posição oposta, a comparação será realizada de acordo com o valor dos campos position da estrutura da ordem de negociação, pois neles são armazenados os tickets das posições;
    • se ela for uma modificação de parâmetros, definição ou exclusão de ordem pendente, a comparação será realizada de acordo com o valor dos campos order da estrutura da ordem de negociação, pois neles são armazenados os tickets das ordens;
    • caso contrário, será retornado zero.

Na classe de negociação CTrading, em sua seção privada, declaramos um ponteiro para uma classe-coleção de eventos de negociação da conta:

//+------------------------------------------------------------------+
//| Trading class                                                    |
//+------------------------------------------------------------------+
class CTrading
  {
private:
   CAccount            *m_account;                       // Pointer to the current account object
   CSymbolsCollection  *m_symbols;                       // Pointer to the symbol collection list
   CMarketCollection   *m_market;                        // Pointer to the list of the collection of market orders and positions
   CHistoryCollection  *m_history;                       // Pointer to the list of the collection of historical orders and deals
   CEventsCollection   *m_events;                        // Pointer to the event collection list
   CArrayObj            m_list_request;                  // List of pending requests
   CArrayInt            m_list_errors;                   // Error list
   bool                 m_is_trade_disable;              // Flag disabling trading
   bool                 m_use_sound;                     // The flag of using sounds of the object trading events
   uchar                m_total_try;                     // Number of trading attempts
   ENUM_LOG_LEVEL       m_log_level;                     // Logging level
   MqlTradeRequest      m_request;                       // Trading request prices
   ENUM_TRADE_REQUEST_ERR_FLAGS m_error_reason_flags;    // Flags of error source in a trading method
   ENUM_ERROR_HANDLING_BEHAVIOR m_err_handling_behavior; // Behavior when handling error
   

Na mesma seção, declaramos os métodos que retornam o índice de um objeto-ordem pendente de acordo com o ticket da ordem e segundo o ticket da posição:

//--- Return the request object index in the list by (1) ID,
//--- (2) order ticket, (3) position ticket in the request
   int                  GetIndexPendingRequestByID(const uchar id);
   int                  GetIndexPendingRequestByOrder(const ulong ticket);
   int                  GetIndexPendingRequestByPosition(const ulong ticket);

public:

Fora do corpo da classe, escrevemos sua implementação:

//+------------------------------------------------------------------+
//| Return the request object index in the list by the order ticket  |
//+------------------------------------------------------------------+
int CTrading::GetIndexPendingRequestByOrder(const ulong ticket)
  {
   CPendingReq *req=new CPendingReq();
   if(req==NULL)
      return WRONG_VALUE;
   req.SetOrder(ticket);
   this.m_list_request.Sort(SORT_BY_PEND_REQ_TICKET);
   int index=this.m_list_request.Search(req);
   delete req;
   return index;
  }
//+-------------------------------------------------------------------+
//| Return the request object index in the list by the position ticket|
//+-------------------------------------------------------------------+
int CTrading::GetIndexPendingRequestByPosition(const ulong ticket)
  {
   CPendingReq *req=new CPendingReq();
   if(req==NULL)
      return WRONG_VALUE;
   req.SetPosition(ticket);
   this.m_list_request.Sort(SORT_BY_PEND_REQ_TICKET);
   int index=this.m_list_request.Search(req);
   delete req;
   return index;
  }
//+------------------------------------------------------------------+

No último artigo vimos um método idêntico para retornar o índice do objeto-ordem de acordo com o seu identificador, por isso, podemos simplesmente ver novamente sua descrição e compreender seu funcionamento. Aqui, tudo é exatamente o mesmo.

Na seção pública da classe, complementamos o método de inicialização de classe, no qual à classe de negociação são transferidos os ponteiros de todas as listas de coleções necessárias para seu funcionamento.

A ele adicionamos a transferência de ponteiro para coleção de eventos de negociação, bem como o registro deste ponteiro no valor da variável m_events:

public:
//--- Constructor
                        CTrading();
//--- Timer
   void                 OnTimer(void);
//--- Get the pointers to the lists (make sure to call the method in program's OnInit() since the symbol collection list is created there)
   void                 OnInit(CAccount *account,CSymbolsCollection *symbols,CMarketCollection *market,CHistoryCollection *history,CEventsCollection *events)
                          {
                           this.m_account=account;
                           this.m_symbols=symbols;
                           this.m_market=market;
                           this.m_history=history;
                           this.m_events=events;
                          }

Ao método de verificação de limitações e de erros adicionamos a transferência de mais um parâmetro, nomeadamente a transmissão do ticket da ordem ou da posição:

//--- Check limitations and errors
   ENUM_ERROR_CODE_PROCESSING_METHOD CheckErrors(const double volume,
                                                 const double price,
                                                 const ENUM_ACTION_TYPE action,
                                                 const ENUM_ORDER_TYPE order_type,
                                                 CSymbol *symbol_obj,
                                                 CTradeObj *trade_obj,
                                                 const string source_method,
                                                 const double limit=0,
                                                 double sl=0,
                                                 double tp=0,
                                                 ulong ticket=0);

De acordo com o ticket, vamos detectar se, para a ordem ou posição com o ticket em questão, no método existe um objeto de ordem pendente criado anteriormente. Para que é necessário isso? Para não exibir no log a mesma mensagem sobre o mesmo erro. Em outras palavras, quando o servidor retorna o erro, imprimimos no log uma mensagem sobre o erro, criamos uma ordem pendente e saímos do método de negociação. Se o erro acontecer novamente, vemos "se, para a ordem ou posição com o ticket em questão, já existia um objeto de ordem pendente", e, caso exista, significa que já havia uma mensagem sobre este erro e não precisa ser repetido.

Vejamos a implementação de um método complementar:

//+------------------------------------------------------------------+
//| Check limitations and errors                                     |
//+------------------------------------------------------------------+
ENUM_ERROR_CODE_PROCESSING_METHOD CTrading::CheckErrors(const double volume,
                                                        const double price,
                                                        const ENUM_ACTION_TYPE action,
                                                        const ENUM_ORDER_TYPE order_type,
                                                        CSymbol *symbol_obj,
                                                        CTradeObj *trade_obj,
                                                        const string source_method,
                                                        const double limit=0,
                                                        double sl=0,
                                                        double tp=0,
                                                        ulong ticket=0)
  {
//--- Check the previously set flag disabling trading for an EA
   if(this.IsTradingDisable())
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_FATAL_ERROR;
      this.AddErrorCodeToList(MSG_LIB_TEXT_TRADING_DISABLE);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE));
      return ERROR_CODE_PROCESSING_METHOD_DISABLE;
     }
//--- result of all checks and error flags
   this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR;
   bool res=true;
//--- Clear the error list
   this.m_list_errors.Clear();
   this.m_list_errors.Sort();
//--- Check trading limitations
   res &=this.CheckTradeConstraints(volume,action,symbol_obj,source_method,sl,tp);
//--- Check the funds sufficiency for opening positions/placing orders
   if(action<ACTION_TYPE_CLOSE_BY)
      res &=this.CheckMoneyFree(volume,price,order_type,symbol_obj,source_method);
//--- Check parameter values by StopLevel and FreezeLevel
   res &=this.CheckLevels(action,order_type,price,limit,sl,tp,symbol_obj,source_method);
   
//--- If there are limitations and errors, display the header and the error list
   if(!res)
     {
      //--- Declare the pending request index
      int index=WRONG_VALUE;
      //--- Request was rejected before sending to the server due to:
      int total=this.m_list_errors.Total();
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
        {
         //--- in case of closing by an opposite position or opening/closing a position, the index is received by the position ticket
         if(action==ACTION_TYPE_CLOSE_BY || action<ACTION_TYPE_BUY_LIMIT)
            index=this.GetIndexPendingRequestByPosition(ticket);
         //--- if a trading operation is closing a position, removing an order or modifying it...
         else if(action>ACTION_TYPE_CLOSE_BY)
           {
            //--- if this is a position, receive the index by a position ticket
            if(order_type<ORDER_TYPE_BUY_LIMIT)
               index=this.GetIndexPendingRequestByPosition(ticket);
            //--- otherwise, receive the index by an order ticket
            else
               index=this.GetIndexPendingRequestByOrder(ticket);
           }
         //--- otherwise, if a trading operation is placing a pending order, receive the index by an order ticket
         else index=this.GetIndexPendingRequestByOrder(ticket);
                                                            
         //--- if no index is received, there is no such pending request object, display the error message
         if(index==WRONG_VALUE)
           {
            //--- For MQL5, first display the list header followed by the error list
            #ifdef __MQL5__
            ::Print(source_method,CMessage::Text(this.m_err_handling_behavior==ERROR_HANDLING_BEHAVIOR_BREAK ? MSG_LIB_TEXT_REQUEST_REJECTED_DUE : MSG_LIB_TEXT_INVALID_REQUEST));
            for(int i=0;i<total;i++)
               ::Print((total>1 ? string(i+1)+". " : ""),CMessage::Text(m_list_errors.At(i)));
            //--- For MQL4, the journal messages are displayed in the reverse order: the error list in the reverse loop is followed by the list header
            #else    
            for(int i=total-1;i>WRONG_VALUE;i--)
               ::Print((total>1 ? string(i+1)+". " : ""),CMessage::Text(m_list_errors.At(i)));
            ::Print(source_method,CMessage::Text(this.m_err_handling_behavior==ERROR_HANDLING_BEHAVIOR_BREAK ? MSG_LIB_TEXT_REQUEST_REJECTED_DUE : MSG_LIB_TEXT_INVALID_REQUEST));
            #endif 
           }
        }
      //--- If the action is performed at the "abort trading operation" error
      if(this.m_err_handling_behavior==ERROR_HANDLING_BEHAVIOR_BREAK)
         return ERROR_CODE_PROCESSING_METHOD_EXIT;
      //--- If the action is performed at the "correct parameters" error
      if(this.m_err_handling_behavior==ERROR_HANDLING_BEHAVIOR_CORRECT)
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG && index==WRONG_VALUE)
            ::Print(CMessage::Text(MSG_LIB_TEXT_CORRECTED_TRADE_REQUEST));
         //--- Return the result of an attempt to correct the request parameters
         return this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj);
        }
     }
//--- No limitations and errors
   trade_obj.SetResultRetcode(0);
   trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
   return ERROR_CODE_PROCESSING_METHOD_OK;
  }
//+------------------------------------------------------------------+

Toda lógica está escrita nos comentários do código. Acho que eles são claros, e dispensamos mais explicações.

O trabalho com ordens pendentes de negociação é implementado no temporizador da classe.
Foram feitas muitas alterações, eu tentei descrever toda a sua lógica de funcionamento nos comentários do código:

//+------------------------------------------------------------------+
//| Timer                                                            |
//+------------------------------------------------------------------+
void CTrading::OnTimer(void)
  {
   //--- In a loop by the list of pending requests
   int total=this.m_list_request.Total();
   for(int i=total-1;i>WRONG_VALUE;i--)
     {
      //--- receive the next request object
      CPendingReq *req_obj=this.m_list_request.At(i);
      if(req_obj==NULL)
         continue;
      
      //--- get the request structure and the symbol object a trading operation should be performed for
      MqlTradeRequest request=req_obj.MqlRequest();
      CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(request.symbol);
      if(symbol_obj==NULL || !symbol_obj.RefreshRates())
         continue;
      
      //--- if the current attempt exceeds the defined number of trading attempts,
      //--- or the current time exceeds the waiting time of all attempts
      //--- remove the current request object and move on to the next one
      if(req_obj.CurrentAttempt()>req_obj.TotalAttempts() || req_obj.CurrentAttempt()>=UCHAR_MAX || 
         (long)symbol_obj.Time()>long(req_obj.TimeCreate()+req_obj.WaitingMSC()*req_obj.TotalAttempts()))
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED));
         this.m_list_request.Delete(i);
         continue;
        }
      
      //--- If this is a position opening or placing a pending order
      if((req_obj.Action()==TRADE_ACTION_DEAL && req_obj.Position()==0) || req_obj.Action()==TRADE_ACTION_PENDING)
        {
         //--- Get the pending request ID
         uchar id=this.GetPendReqID((uint)request.magic);
         //--- Get the list of orders/positions containing the order/position with the pending request ID
         CArrayObj *list=this.m_market.GetList(ORDER_PROP_PEND_REQ_ID,id,EQUAL);
         if(::CheckPointer(list)==POINTER_INVALID)
            continue;
         //--- If the order/position is present, the request is handled: remove it and proceed to the next
         if(list.Total()>0)
           {
            if(this.m_log_level>LOG_LEVEL_NO_MSG)
               ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED));
            this.m_list_request.Delete(i);
            continue;
           }
        }
      //--- Otherwise: full and partial position closure, removing an order, modifying order parameters and position stop orders
      else
        {
         CArrayObj *list=NULL;
         //--- if this is a position closure, including a closure by an opposite one
         if((req_obj.Action()==TRADE_ACTION_DEAL && req_obj.Position()>0) || req_obj.Action()==TRADE_ACTION_CLOSE_BY)
           {
            //--- Get a position with the necessary ticket from the list of open positions
            list=this.m_market.GetList(ORDER_PROP_TICKET,req_obj.Position(),EQUAL);
            if(::CheckPointer(list)==POINTER_INVALID)
               continue;
            //--- If the market has no such position - the request is handled: remove it and proceed to the next one
            if(list.Total()==0)
              {
               if(this.m_log_level>LOG_LEVEL_NO_MSG)
                  ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED));
               this.m_list_request.Delete(i);
               continue;
              }
            //--- Otherwise, if the position still exists, this is a partial closure
            else
              {
               //--- Get the list of all account trading events
               list=this.m_events.GetList();
               if(list==NULL)
                  continue;
               //--- In the loop from the end of the account trading event list
               int events_total=list.Total();
               for(int j=events_total-1; j>WRONG_VALUE; j--)
                 {
                  //--- get the next trading event
                  CEvent *event=list.At(j);
                  if(event==NULL)
                     continue;
                  //--- If this event is a partial closure or there was a partial closure when closing by an opposite one
                  if(event.TypeEvent()==TRADE_EVENT_POSITION_CLOSED_PARTIAL || event.TypeEvent()==TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_POS)
                    {
                     //--- If a position ticket in a trading event coincides with the ticket in a pending trading request -
                     //--- the request is handled: remove it and break the loop by the list of account trading events
                     if(event.TicketFirstOrderPosition()==req_obj.Position())
                       {
                        if(this.m_log_level>LOG_LEVEL_NO_MSG)
                           ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED));
                        this.m_list_request.Delete(i);
                        break;
                       }
                    }
                 }
               //--- If a handled pending request object was removed by the trading event list in the loop, move on to the next one
               if(::CheckPointer(req_obj)==POINTER_INVALID)
                  continue;
              }
           }
         //--- If this is a modification of position stop orders
         if(req_obj.Action()==TRADE_ACTION_SLTP)
           {
            //--- Get the list of all account trading events
            list=this.m_events.GetList();
            if(list==NULL)
               continue;
            //--- In the loop from the end of the account trading event list
            int events_total=list.Total();
            for(int j=events_total-1; j>WRONG_VALUE; j--)
              {
               //--- get the next trading event
               CEvent *event=list.At(j);
               if(event==NULL)
                  continue;
               //--- If this is a change of the position's stop orders
               if(event.TypeEvent()>TRADE_EVENT_MODIFY_ORDER_TAKE_PROFIT)
                 {
                  //--- If a position ticket in a trading event coincides with the ticket in a pending trading request -
                  //--- the request is handled: remove it and break the loop by the list of account trading events
                  if(event.TicketFirstOrderPosition()==req_obj.Position())
                    {
                     if(this.m_log_level>LOG_LEVEL_NO_MSG)
                        ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED));
                     this.m_list_request.Delete(i);
                     break;
                    }
                 }
              }
            //--- If a handled pending request object was removed by the trading event list in the loop, move on to the next one
            if(::CheckPointer(req_obj)==POINTER_INVALID)
               continue;
           }
         //--- If this is a pending order removal
         if(req_obj.Action()==TRADE_ACTION_REMOVE)
           {
            //--- Get the list of removed pending orders
            list=this.m_history.GetList(ORDER_PROP_STATUS,ORDER_STATUS_HISTORY_PENDING,EQUAL);
            if(::CheckPointer(list)==POINTER_INVALID)
               continue;
            //--- Leave a single order with the necessary ticket in the list
            list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,req_obj.Order(),EQUAL);
            //--- If the order is present, the request is handled: remove it and proceed to the next
            if(list.Total()>0)
              {
               if(this.m_log_level>LOG_LEVEL_NO_MSG)
                  ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED));
               this.m_list_request.Delete(i);
               continue;
              }
           }
         //--- If this is a pending order modification
         if(req_obj.Action()==TRADE_ACTION_MODIFY)
           {
            //--- Get the list of all account trading events
            list=this.m_events.GetList();
            if(list==NULL)
               continue;
            //--- In the loop from the end of the account trading event list
            int events_total=list.Total();
            for(int j=events_total-1; j>WRONG_VALUE; j--)
              {
               //--- get the next trading event
               CEvent *event=list.At(j);
               if(event==NULL)
                  continue;
               //--- If this event involves any change of modified pending order parameters
               if(event.TypeEvent()>TRADE_EVENT_TRIGGERED_STOP_LIMIT_ORDER && event.TypeEvent()<TRADE_EVENT_MODIFY_POSITION_STOP_LOSS_TAKE_PROFIT)
                 {
                  //--- If an order ticket in a trading event coincides with the ticket in a pending trading request -
                  //--- the request is handled: remove it and break the loop by the list of account trading events
                  if(event.TicketOrderEvent()==req_obj.Order())
                    {
                     if(this.m_log_level>LOG_LEVEL_NO_MSG)
                        ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED));
                     this.m_list_request.Delete(i);
                     break;
                    }
                 }
              }
           }
        }
      //--- Exit if the pending request object has been removed after checking its operation
      if(::CheckPointer(req_obj)==POINTER_INVALID)
         return;
      //--- Set the request activation time in the request object
      req_obj.SetTimeActivate(req_obj.TimeCreate()+req_obj.WaitingMSC()*(req_obj.CurrentAttempt()+1));
      
      //--- If the current time is less than the request activation time,
      //--- this is not the request time - move on to the next request in the list
      if((long)symbol_obj.Time()<(long)req_obj.TimeActivate())
         continue;
      
      //--- Set the attempt number in the request object
      req_obj.SetCurrentAttempt(uchar(req_obj.CurrentAttempt()+1));
      
      //--- Display the number of a trading attempt in the journal

      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(CMessage::Text(MSG_LIB_TEXT_RE_TRY_N)+(string)req_obj.CurrentAttempt());
      
      //--- Depending on the type of action performed in the trading request 
      switch(request.action)
        {
         //--- Opening/closing a position
         case TRADE_ACTION_DEAL :
            //--- If no ticket is present in the request structure - this is opening a position
            if(request.position==0)
               this.OpenPosition((ENUM_POSITION_TYPE)request.type,request.volume,request.symbol,request.magic,request.sl,request.tp,request.comment,request.deviation,request.type_filling);
            //--- If the ticket is present in the request structure - this is a position closure
            else
               this.ClosePosition(request.position,request.volume,request.comment,request.deviation);
            break;
         //--- Modify StopLoss/TakeProfit position
         case TRADE_ACTION_SLTP :
            this.ModifyPosition(request.position,request.sl,request.tp);
            break;
         //--- Close by an opposite one
         case TRADE_ACTION_CLOSE_BY :
            this.ClosePositionBy(request.position,request.position_by);
            break;
         //---
         //--- Place a pending order
         case TRADE_ACTION_PENDING :
            this.PlaceOrder(request.type,request.volume,request.symbol,request.price,request.stoplimit,request.sl,request.tp,request.magic,request.comment,request.expiration,request.type_time,request.type_filling);
            break;
         //--- Modify a pending order
         case TRADE_ACTION_MODIFY :
            this.ModifyOrder(request.order,request.price,request.sl,request.tp,request.stoplimit,request.expiration,request.type_time,request.type_filling);
            break;
         //--- Remove a pending order
         case TRADE_ACTION_REMOVE :
            Print(DFUN,RequestActionDescription(req_obj.MqlRequest()));
            this.DeleteOrder(request.order);
            break;
         //---
         default:
            break;
        }
     }
  }
//+------------------------------------------------------------------+

É aqui que precisamos da lista contendo todos os eventos de negociação, para definir a ativação/exclusão da ordem pendente. Sem isso, a ordem pendente existiria até que todas as tentativas de negociação designadas para ela terminassem. Por exemplo, com o fechamento parcial da posição, tal ordem pendente fecharia gradualmente parte da posição, ou seja, ininterruptamente, até que toda a posição tenhas sido fechada completamente ou suas tentativas de negociação tenham sido concluídas. Isso não deveria ser assim. Por essa razão, determinamos o evento de negociação ocorrido e o comparamos com o objeto da ordem de negociação pendente. Se corresponder, excluiremos este objeto como executado, enquanto a mensagem correspondente será exibida no log.

No método que retorna como processar erros, transferimos o erro da falta de permissão para realizar operações de negociação por parte do terminal para o bloco que retorna uma espera:

//+------------------------------------------------------------------+
//| Return the error handling method                                 |
//+------------------------------------------------------------------+
ENUM_ERROR_CODE_PROCESSING_METHOD CTrading::ResultProccessingMethod(const uint result_code)
  {
   switch(result_code)
     {
   #ifdef __MQL4__
      //--- Malfunctional trade operation
      case 9   :
      //--- Account disabled
      case 64  :
      //--- Invalid account number
      case 65  :  return ERROR_CODE_PROCESSING_METHOD_DISABLE;
      
      //--- No error but result is unknown
      case 1   :
      //--- General error
      case 2   :
      //--- Old client terminal version
      case 5   :
      //--- Not enough rights
      case 7   :
      //--- Market closed
      case 132 :
      //--- Trading disabled
      case 133 :
      //--- Order is locked and being processed
      case 139 :
      //--- Buy only
      case 140 :
      //--- The number of open and pending orders has reached the limit set by the broker
      case 148 :
      //--- Attempt to open an opposite order if hedging is disabled
      case 149 :
      //--- Attempt to close a position on a symbol contradicts the FIFO rule
      case 150 :  return ERROR_CODE_PROCESSING_METHOD_EXIT;
      
      //--- Invalid trading request parameters
      case 3   :
      //--- Invalid price
      case 129 :
      //--- Invalid stop levels
      case 130 :
      //--- Invalid volume
      case 131 :
      //--- Not enough money to perform the operation
      case 134 :
      //--- Expirations are denied by broker
      case 147 :  return ERROR_CODE_PROCESSING_METHOD_CORRECT;
      
      //--- Trade server is busy
      case 4   :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)5000;    // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 5 seconds
      //--- No connection to the trade server
      case 6   :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)20000;   // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 20 seconds
      //--- Too frequent requests
      case 8   :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)10000;   // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 10 seconds
      //--- No price
      case 136 :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)5000;    // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 5 seconds
      //--- Broker is busy
      case 137 :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)15000;   // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 15 seconds
      //--- Too many requests
      case 141 :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)10000;   // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 10 seconds
      //--- Modification denied because the order is too close to market
      case 145 :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)10000;   // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 10 seconds
      //--- Trade context is busy
      case 146 :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)5000;    // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 5 seconds
      
      //--- Trade timeout
      case 128 :
      //--- Price has changed
      case 135 :
      //--- New prices
      case 138 :  return ERROR_CODE_PROCESSING_METHOD_REFRESH;

   //--- MQL5
   #else
      //--- Auto trading disabled by the server
      case 10026  :  return ERROR_CODE_PROCESSING_METHOD_DISABLE;
      
      //--- Request canceled by a trader
      case 10007  :
      //--- Request handling error
      case 10011  :
      //--- Request expired
      case 10012  :
      //--- Trading disabled
      case 10017 :
      //--- Market closed
      case 10018  :
      //--- Order status changed
      case 10023  :
      //--- Request unchanged
      case 10025  :
      //--- Request blocked for handling
      case 10028  :
      //--- Transaction is allowed for live accounts only
      case 10032  :
      //--- The maximum number of pending orders is reached
      case 10033  :
      //--- Reached the maximum order and position volume for this symbol
      case 10034  :
      //--- Invalid or prohibited order type
      case 10035  :
      //--- Position with the specified ID already closed
      case 10036  :
      //--- A close order is already present for a specified position
      case 10039  :
      //--- The maximum number of open positions is reached
      case 10040  :
      //--- Request to activate a pending order is rejected, the order is canceled
      case 10041  :
      //--- Request is rejected, because the rule "Only long positions are allowed" is set for the symbol
      case 10042  :
      //--- Request is rejected, because the rule "Only short positions are allowed" is set for the symbol
      case 10043  :
      //--- Request is rejected, because the rule "Only closing of existing positions is allowed" is set for the symbol
      case 10044  :
      //--- Request is rejected, because the rule "Only closing of existing positions by FIFO rule is allowed" is set for the symbol
      case 10045  :  return ERROR_CODE_PROCESSING_METHOD_EXIT;

      //--- Requote
      case 10004  :
      //--- Prices changed
      case 10020  :  return ERROR_CODE_PROCESSING_METHOD_REFRESH;

      //--- Invalid request
      case 10013  :
      //--- Invalid request volume
      case 10014  :
      //--- Invalid request price
      case 10015  :
      //--- Invalid request stop levels
      case 10016  :
      //--- Insufficient funds for request execution
      case 10019  :
      //--- Invalid order expiration in a request
      case 10022  :
      //--- The specified type of order execution by residue is not supported
      case 10030  :
      //--- Closed volume exceeds the current position volume
      case 10038  :  return ERROR_CODE_PROCESSING_METHOD_CORRECT;

      //--- Request rejected
      case 10006  :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)15000;   // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 15 seconds
      //--- No quotes to handle the request
      case 10021  :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)5000;    // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 5 seconds
      //--- Too frequent requests
      case 10024  :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)10000;   // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 10 seconds
      //--- Auto trading disabled by the client terminal
      case 10027  :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)20000;   // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 20 seconds
      //--- An order or a position is frozen
      case 10029  :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)10000;   // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 10 seconds
      //--- No connection to the trade server
      case 10031  :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)20000;   // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 20 seconds

      //--- Order placed
      case 10008  :
      //--- Request executed
      case 10009  :
      //--- Request executed partially
      case 10010  :
   #endif 
      //--- "OK"
      default:
        break;
     }
   return ERROR_CODE_PROCESSING_METHOD_OK;
  }
//+------------------------------------------------------------------+

Assim, se desativarmos o botão "Autotrading" no terminal e tentar enviar uma ordem de negociação, será gerada uma ordem pendente. Já após ativar o botão "Autotrading", deverá funcionar esta solicitação pendente. E, de fato, este erro deve ser resolvido pela espera da ativação da negociação automática. Mas somente se ainda não tiver terminado o tempo total de espera designado para todas as tentativas de negociação.

No método de correção de erros, removemos o bloco de código que retorna do método com o código "sair do método de negociação":

//+------------------------------------------------------------------+
//| Correct errors                                                   |
//+------------------------------------------------------------------+
ENUM_ERROR_CODE_PROCESSING_METHOD CTrading::RequestErrorsCorrecting(MqlTradeRequest &request,
                                                                    const ENUM_ORDER_TYPE order_type,
                                                                    const uint spread_multiplier,
                                                                    CSymbol *symbol_obj,
                                                                    CTradeObj *trade_obj)
  {
//--- The empty error list means no errors are detected, return success
   int total=this.m_list_errors.Total();
   if(total==0)
      return ERROR_CODE_PROCESSING_METHOD_OK;

//--- Trading is disabled for the current account
//--- write the error code to the base trading class object and return "exit from the trading method"
   if(this.IsPresentErorCode(MSG_LIB_TEXT_ACCOUNT_NOT_TRADE_ENABLED))
     {
      trade_obj.SetResultRetcode(MSG_LIB_TEXT_ACCOUNT_NOT_TRADE_ENABLED);
      trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
      return ERROR_CODE_PROCESSING_METHOD_EXIT;
     }
//--- Trading on the trading server side is disabled for EAs on the current account
//--- write the error code to the base trading class object and return "exit from the trading method"
   if(this.IsPresentErorCode(MSG_LIB_TEXT_ACCOUNT_EA_NOT_TRADE_ENABLED))
     {
      trade_obj.SetResultRetcode(MSG_LIB_TEXT_ACCOUNT_EA_NOT_TRADE_ENABLED);
      trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
      return ERROR_CODE_PROCESSING_METHOD_EXIT;
     }
//--- Trading operations are disabled in the terminal
//--- write the error code to the base trading class object and return "exit from the trading method"
   if(this.IsPresentErorCode(MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED))
     {
      trade_obj.SetResultRetcode(MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED);
      trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
      return ERROR_CODE_PROCESSING_METHOD_EXIT;
     }
//--- Trading operations are disabled for the EA
//--- write the error code to the base trading class object and return "exit from the trading method"
   if(this.IsPresentErorCode(MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED))
     {
      trade_obj.SetResultRetcode(MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED);
      trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
      return ERROR_CODE_PROCESSING_METHOD_EXIT;
     }
//--- Disable trading on a symbol

No bloco de processamento da lista de erros encontrado, adicionamos um retorno - a partir do método - de um código de espera de 20 segundos se não houver permissão de negociação no terminal ou no EA:

//--- View the list of remaining errors and correct trading request parameters
   for(int i=0;i<total;i++)
     {
      int err=this.m_list_errors.At(i);
      if(err==NULL)
         continue;
      switch(err)
        {
         //--- Correct an invalid volume and disabling stop levels in a trading request
         case MSG_LIB_TEXT_REQ_VOL_LESS_MIN_VOLUME    :
         case MSG_LIB_TEXT_REQ_VOL_MORE_MAX_VOLUME    :
         case MSG_LIB_TEXT_INVALID_VOLUME_STEP        :  request.volume=symbol_obj.NormalizedLot(request.volume);                      break;
         case MSG_SYM_SL_ORDER_DISABLED               :  request.sl=0;                                                                 break;
         case MSG_SYM_TP_ORDER_DISABLED               :  request.tp=0;                                                                 break;
         
         //--- If unable to select the position lot, return "abort trading attempt" since the funds are insufficient even for the minimum lot
         case MSG_LIB_TEXT_NOT_ENOUTH_MONEY_FOR       :  request.volume=this.CorrectVolume(request.price,order_type,symbol_obj,DFUN);
                                                         if(request.volume==0)
                                                           {
                                                            trade_obj.SetResultRetcode(MSG_LIB_TEXT_NOT_POSSIBILITY_CORRECT_LOT);
                                                            trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
                                                            return ERROR_CODE_PROCESSING_METHOD_EXIT;                                                                                      break;
                                                           }
         //--- No quotes to handle the request
         case 10021                                   :  trade_obj.SetResultRetcode(10021);
                                                         trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
                                                         return (ENUM_ERROR_CODE_PROCESSING_METHOD)5000;    // ERROR_CODE_PROCESSING_METHOD_WAIT - wait 5 seconds
         //--- No connection to the trade server
         case 10031                                   :  trade_obj.SetResultRetcode(10031);
                                                         trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
                                                         return (ENUM_ERROR_CODE_PROCESSING_METHOD)20000;   // ERROR_CODE_PROCESSING_METHOD_WAIT - wait 20 seconds
                                                      
         //--- Proximity to the order activation level is handled by five-second waiting - during this time, the price may go beyond the freeze level
         case MSG_LIB_TEXT_SL_LESS_FREEZE_LEVEL       :
         case MSG_LIB_TEXT_TP_LESS_FREEZE_LEVEL       :
         case MSG_LIB_TEXT_PR_LESS_FREEZE_LEVEL       :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)5000;    // ERROR_CODE_PROCESSING_METHOD_WAIT - wait 5 seconds
        
         //--- Trading operations are disabled in the terminal
         case MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED :
         //--- Trading operations are disabled for the EA
         case MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED       :  return (ENUM_ERROR_CODE_PROCESSING_METHOD)20000;   // ERROR_CODE_PROCESSING_METHOD_WAIT - wait 20 seconds
        
         default:
           break;
        }
     }
//--- No errors - return ОК
   trade_obj.SetResultRetcode(0);
   trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
   return ERROR_CODE_PROCESSING_METHOD_OK;
  }
//+------------------------------------------------------------------+

Nos dois primeiros artigos que descreviam a criação de solicitações pendentes para abrir posições e definir ordens pendentes, processávamos apenas os erros recebidos do servidor de negociação, isto é, ao receber erros após a primeira solicitação, criávamos um objeto de ordem pendente, enquanto outras tentativas de negociação eram feitas a partir do objeto-ordem pendente. Mas também nos métodos de negociação tínhamos uma verificação preliminar das permissões de negociação e a correção de parâmetros, pois eles são verificados antes de enviar a ordem de negociação para o servidor. Nós não processávamos os erros encontrados em estas verificações, usando ordens pendentes.

Neste artigo, aos métodos de negociação adicionaremos a criação de ordens pendentes após a determinação preliminar de erros antes de enviar a ordem de negociação. Além disso, adicionaremos a geração de ordens pendentes a todos os métodos de negociação que ainda não a possuem, isto é, aos métodos para fechar posições/excluir ordens pendentes e aos métodos para modificar posições e ordens pendentes.

Consideremos o método de negociação para abrir uma posição:

//+------------------------------------------------------------------+
//| Open a position                                                  |
//+------------------------------------------------------------------+
template<typename SL,typename TP> 
bool CTrading::OpenPosition(const ENUM_POSITION_TYPE type,
                            const double volume,
                            const string symbol,
                            const ulong magic=ULONG_MAX,
                            const SL sl=0,
                            const TP tp=0,
                            const string comment=NULL,
                            const ulong deviation=ULONG_MAX,
                            const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
//--- Set the trading request result as 'true' and the error flag as "no errors"
   bool res=true;
   this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR;
   ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)type;
   ENUM_ACTION_TYPE action=(ENUM_ACTION_TYPE)order_type;
//--- Get a symbol object by a symbol name. If failed to get
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
//--- If failed to get - write the "internal error" flag, display the message in the journal and return 'false'
   if(symbol_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
//--- If failed to get - write the "internal error" flag, display the message in the journal and return 'false'
   if(trade_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
//--- Set the prices
//--- If failed to set - write the "internal error" flag, set the error code in the return structure,
//--- display the message in the journal and return 'false'
   if(!this.SetPrices(order_type,0,sl,tp,0,DFUN,symbol_obj))
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      trade_obj.SetResultRetcode(10021);
      trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(10021));   // No quotes to process the request
      return false;
     }

//--- Write the volume, deviation, comment and filling type to the request structure
   this.m_request.volume=volume;
   this.m_request.deviation=(deviation==ULONG_MAX ? trade_obj.GetDeviation() : deviation);
   this.m_request.comment=(comment==NULL ? trade_obj.GetComment() : comment);
   this.m_request.type_filling=(type_filling>WRONG_VALUE ? type_filling : trade_obj.GetTypeFilling());
//--- Get the method of handling errors from the CheckErrors() method while checking for errors in the request parameters
   double pr=(type==POSITION_TYPE_BUY ? symbol_obj.AskLast() : symbol_obj.BidLast());
   ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(this.m_request.volume,pr,action,order_type,symbol_obj,trade_obj,DFUN,0,this.m_request.sl,this.m_request.tp);
//--- In case of trading limitations, funds insufficiency,
//--- if there are limitations by StopLevel or FreezeLevel ...
   if(method!=ERROR_CODE_PROCESSING_METHOD_OK)
     {
      //--- If trading is completely disabled, set the error code to the return structure,
      //--- display a journal message, play the error sound and exit
      if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
        {
         trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE);
         trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type);
         return false;
        }
      //--- If the check result is "abort trading operation" - set the last error code to the return structure,
      //--- display a journal message, play the error sound and exit
      if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
        {
         int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
         if(code!=NULL)
           {
            trade_obj.SetResultRetcode(code);
            trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
           }
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type);
         return false;
        }
      //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal,
      //--- create a pending request and return 'false'
      if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
        {
         //--- If the trading request magic number, has no pending request ID
         if(this.GetPendReqID((uint)magic)==0)
           {
            //--- Play the error sound
            if(this.IsUseSounds())
               trade_obj.PlaySoundError(action,order_type);
            //--- set the last error code to the return structure
            int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
            if(code!=NULL)
              {
               if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED)
                  code=10027;
               trade_obj.SetResultRetcode(code);
               trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
              }
            //--- Waiting time in milliseconds:
            //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
            ulong wait=method;
            //--- Look for the least of the possible IDs. If failed to find
            //--- or in case of an error while updating the current symbol data, return 'false'
            int id=this.GetFreeID();
            if(id<1 || !symbol_obj.RefreshRates())
               return false;
            //--- Write the pending request object ID to the magic number and fill in the remaining unfilled fields of the trading request structure
            uint mn=(magic==ULONG_MAX ? (uint)trade_obj.GetMagic() : (uint)magic);
            this.SetPendReqID((uchar)id,mn);
            this.m_request.magic=mn;
            this.m_request.action=TRADE_ACTION_DEAL;
            this.m_request.symbol=symbol_obj.Name();
            this.m_request.type=order_type;
            //--- Set the number of trading attempts and create a pending request
            uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
            this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj);
           }
         return false;
        }
     }
   
//--- In the loop by the number of attempts
   for(int i=0;i<this.m_total_try;i++)
     {                
      //--- Send the request
      res=trade_obj.OpenPosition(type,this.m_request.volume,this.m_request.sl,this.m_request.tp,magic,comment,deviation,type_filling);
      //--- If the request is executed successfully or the asynchronous order sending mode is set, play the success sound
      //--- set for a symbol trading object for this type of trading operation and return 'true'
      if(res || trade_obj.IsAsyncMode())
        {
         if(this.IsUseSounds())
            trade_obj.PlaySoundSuccess(action,order_type);
         return true;
        }
      //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation
      else
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRY_N),string(i+1),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type);
         
         //--- Get the error handling method
         method=this.ResultProccessingMethod(trade_obj.GetResultRetcode());
         //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
           {
            this.SetTradingDisableFlag(true);
            break;
           }
         //--- If "Exit the trading method" is received as a result of sending a request, end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
           {
            break;
           }
         //--- If "Correct the parameters and repeat" is received as a result of sending a request -
         //--- correct the parameters and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT)
           {
            this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj);
            continue;
           }
         //--- If "Update data and repeat" is received as a result of sending a request -
         //--- update data and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            symbol_obj.Refresh();
            continue;
           }
         //--- If "Wait and repeat" is received as a result of sending a request - create a pending request and end the loop
         if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            //--- If the trading request magic number, has no pending request ID
            if(this.GetPendReqID((uint)magic)==0)
              {
               //--- Waiting time in milliseconds:
               //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
               //--- for the "Create a pending request" handling method - till there is a zero waiting time
               ulong wait=method;
               //--- Look for the least of the possible IDs. If failed to find
               //--- or in case of an error while updating the current symbol data, return 'false'
               int id=this.GetFreeID();
               if(id<1 || !symbol_obj.RefreshRates())
                  return false;
               //--- Write the pending request object ID to the magic number and fill in the remaining unfilled fields of the trading request structure
               uint mn=(magic==ULONG_MAX ? (uint)trade_obj.GetMagic() : (uint)magic);
               this.SetPendReqID((uchar)id,mn);
               this.m_request.magic=mn;
               this.m_request.action=TRADE_ACTION_DEAL;
               this.m_request.symbol=symbol_obj.Name();
               this.m_request.type=order_type;
               //--- Set the number of trading attempts, create a pending request and break the loop
               uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
               this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj);
               break;
              }
           }
        }
     }
//--- Return the result of sending a trading request in a symbol trading object
   return res;
  }
//+------------------------------------------------------------------+

Como vemos na listagem do método, neste caso, após verificações preliminares de permissões e de erros na ordem de negociação e após retornado o código "esperar e tentar novamente" a partir do método de verificação de erros, criamos uma ordem pendente com os parâmetros que estão atualmente na estrutura da ordem de negociação e saímos do método de negociação. Em seguida, já irá funcionar o objeto-ordem pendente, reenviando novamente as ordens de negociação especificadas em seus parâmetros segundo o número de tentativas indicadas.

Se a verificação inicial for concluída com êxito, a ordem de negociação será enviada ao servidor. Em seguida, é verificado o código de retorno do servidor de negociação, se o resultado da verificação do código de retorno for o requisito "esperar e tentar novamente", da mesma maneira será gerada uma ordem pendente e será realizada a saída do método de negociação, já as seguintes tentativas de negociação serão realizadas a partir do objeto-ordem pendente criado.

Toda a lógica de funcionamento quanto à criação de objetos-ordens pendentes é descrita em todos os métodos de negociação, portanto, apenas precisamos ver as listagens de tais métodos, nelas são destacados a cores o bloco de criação de ordem pendente após verificação inicial e o bloco de criação de ordem pendente após receber um erro do servidor de negociação. Para estudo pessoal:

Método de modificação de stops de ordens abertas:

//+------------------------------------------------------------------+
//| Modify a position                                                |
//+------------------------------------------------------------------+
template<typename SL,typename TP> 
bool CTrading::ModifyPosition(const ulong ticket,const SL sl=WRONG_VALUE,const TP tp=WRONG_VALUE)
  {
   bool res=true;
   this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR;
   ENUM_ACTION_TYPE action=ACTION_TYPE_MODIFY;
//--- Get an order object by ticket
   COrder *order=this.GetOrderObjByTicket(ticket);
   if(order==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ));
      return false;
     }
   ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)order.TypeOrder();
//--- Get a symbol object by a position ticket
   CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   if(symbol_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
//--- Set the prices
//--- If failed to set - write the "internal error" flag, set the error code in the return structure,
//--- display the message in the journal and return 'false'
   if(!this.SetPrices(order_type,0,(sl==WRONG_VALUE ? order.StopLoss() : sl),(tp==WRONG_VALUE ? order.TakeProfit() : tp),0,DFUN,symbol_obj))
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      trade_obj.SetResultRetcode(10021);
      trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(10021));   // No quotes to process the request
      return false;
     }
     
//--- If there are trading limitations, there are StopLevel/FreezeLevel limitations - play the error sound and exit
   ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(0,0,action,order_type,symbol_obj,trade_obj,DFUN,0,this.m_request.sl,this.m_request.tp,ticket);
   if(method!=ERROR_CODE_PROCESSING_METHOD_OK)
     {
      //--- If trading is completely disabled
      if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
        {
         trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE);
         trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true));
         return false;
        }
      //--- If the check result is "abort trading operation" - set the last error code to the return structure,
      //--- display a journal message, play the error sound and exit
      if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
        {
         int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
         if(code!=NULL)
           {
            trade_obj.SetResultRetcode(code);
            trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
           }
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED));
         if(this.IsUseSounds() && trade_obj.GetResultRetcode()!=10025)
            trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true));
         return false;
        }
      //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal,
      //--- create a pending request and return 'false'
      if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
        {
         //--- If the pending request object with the position ticket is not present in the list
         if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE)
           {
            //--- Play the error sound
            if(this.IsUseSounds())
               trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true));
            //--- set the last error code to the return structure
            int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
            if(code!=NULL)
              {
               if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED)
                  code=10027;
               trade_obj.SetResultRetcode(code);
               trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
              }
            //--- Waiting time in milliseconds:
            //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
            //--- for the "Create a pending request" handling method - till there is a zero waiting time
            ulong wait=method;
            //--- Look for the least of the possible IDs. If failed to find
            //--- or in case of an error while updating the current symbol data, return 'false'
            int id=this.GetFreeID();
            if(id<1 || !symbol_obj.RefreshRates())
               return false;
            //--- Write a type of a conducted operation, as well as a symbol and a ticket of a modified position to the request structure
            this.m_request.action=TRADE_ACTION_SLTP;
            this.m_request.symbol=symbol_obj.Name();
            this.m_request.position=ticket;
            //--- Set the number of trading attempts and create a pending request
            uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
            this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj);
           }
         return false;
        }
     }

//--- In the loop by the number of attempts
   for(int i=0;i<this.m_total_try;i++)
     {                
      //--- Send the request
      res=trade_obj.ModifyPosition(ticket,this.m_request.sl,this.m_request.tp);
      //--- If the request is executed successfully or the asynchronous order sending mode is set, play the success sound
      //--- set for a symbol trading object for this type of trading operation and return 'true'
      if(res || trade_obj.IsAsyncMode())
        {
         if(this.IsUseSounds())
            trade_obj.PlaySoundSuccess(action,(int)order.TypeOrder(),(sl<0 ? false : true),(tp<0 ? false : true));
         return true;
        }
      //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation
      else
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRY_N),string(i+1),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.IsUseSounds() && trade_obj.GetResultRetcode()!=10025)
            trade_obj.PlaySoundError(action,(int)order.TypeOrder(),(sl<0 ? false : true),(tp<0 ? false : true));
         
         method=this.ResultProccessingMethod(trade_obj.GetResultRetcode());
         //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
           {
            this.SetTradingDisableFlag(true);
            break;
           }
         //--- If "Exit the trading method" is received as a result of sending a request -
         //--- set the last error code to the return structure and end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
           {
            break;
           }
         //--- If "Correct the parameters and repeat" is received as a result of sending a request -
         //--- correct the parameters and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT)
           {
            this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj);
            continue;
           }
         //--- If "Update data and repeat" is received as a result of sending a request -
         //--- update data and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            symbol_obj.Refresh();
            continue;
           }
         //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal,
         //--- create a pending request and break the loop
         if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            //--- If the pending request object with the order ticket is not present in the list
            if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE)
              {
               //--- Waiting time in milliseconds:
               //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
               //--- for the "Create a pending request" handling method - till there is a zero waiting time
               ulong wait=method;
               //--- Look for the least of the possible IDs. If failed to find
               //--- or in case of an error while updating the current symbol data, return 'false'
               int id=this.GetFreeID();
               if(id<1 || !symbol_obj.RefreshRates())
                  return false;
               //--- Write a type of a conducted operation, as well as a symbol and a ticket of a modified position to the request structure
               this.m_request.action=TRADE_ACTION_SLTP;
               this.m_request.symbol=symbol_obj.Name();
               this.m_request.position=ticket;
               //--- Set the number of trading attempts, create a pending request and break the loop
               uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
               this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj);
               break;
              }
           }
        }
     }
//--- Return the result of sending a trading request in a symbol trading object
   return res;
  }
//+------------------------------------------------------------------+

Método para fechar uma posição:

//+------------------------------------------------------------------+
//| Close a position in full                                         |
//+------------------------------------------------------------------+
bool CTrading::ClosePosition(const ulong ticket,const double volume=WRONG_VALUE,const string comment=NULL,const ulong deviation=ULONG_MAX)
  {
   bool res=true;
   this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR;
   ENUM_ACTION_TYPE action=ACTION_TYPE_CLOSE;
//--- Get an order object by ticket
   COrder *order=this.GetOrderObjByTicket(ticket);
   if(order==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ));
      return false;
     }
   ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)order.TypeOrder();
//--- Get a symbol object by a position ticket
   CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   //--- If failed to get the symbol object, display the message and return 'false'
   if(symbol_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- get a trading object from a symbol object

   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
//--- Update symbol quotes
   if(!symbol_obj.RefreshRates())
     {
      trade_obj.SetResultRetcode(10021);
      trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
      this.AddErrorCodeToList(10021);  // No quotes to handle the request
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(10021));
      return false;
     }
     
//--- Write a deviation and a comment to the request structure
   this.m_request.deviation=(deviation==ULONG_MAX ? trade_obj.GetDeviation() : deviation);
   this.m_request.comment=(comment==NULL ? trade_obj.GetComment() : comment);
//--- If there are trading limitations,
//--- there are limitations on FreezeLevel - play the error sound and exit
   ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(0,0,action,order_type,symbol_obj,trade_obj,DFUN,0,0,0,ticket);
   if(method!=ERROR_CODE_PROCESSING_METHOD_OK)
     {
      //--- If trading is completely disabled
      if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
        {
         trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE);
         trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type);
         return false;
        }
      //--- If the check result is "abort trading operation" - set the last error code to the return structure,
      //--- display a journal message, play the error sound and exit
      if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
        {
         int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
         if(code!=NULL)
           {
            trade_obj.SetResultRetcode(code);
            trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
           }
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type);
         return false;
        }
      //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal,
      //--- create a pending request and return 'false'
      if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
        {
         //--- If the pending request object with the position ticket is not present in the list
         if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE)
           {
            //--- Play the error sound
            if(this.IsUseSounds())
               trade_obj.PlaySoundError(action,order_type);
            //--- set the last error code to the return structure
            int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
            if(code!=NULL)
              {
               if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED)
                  code=10027;
               trade_obj.SetResultRetcode(code);
               trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
              }
            //--- Waiting time in milliseconds:
            //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
            ulong wait=method;
            //--- Look for the least of the possible IDs. If failed to find
            //--- or in case of an error while updating the current symbol data, return 'false'
            int id=this.GetFreeID();
            if(id<1 || !symbol_obj.RefreshRates())
               return false;
            //--- Write the trading operation type, symbol, ticket and volume to the request structure
            this.m_request.action=TRADE_ACTION_DEAL;
            this.m_request.symbol=symbol_obj.Name();
            this.m_request.position=ticket;
            this.m_request.volume=volume;
            //--- Set the number of trading attempts and create a pending request
            uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
            this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj);
           }
         return false;
        }
     }

//--- In the loop by the number of attempts
   for(int i=0;i<this.m_total_try;i++)
     {                
      //--- Send the request
      res=(volume==WRONG_VALUE ? trade_obj.ClosePosition(ticket,comment,deviation) : trade_obj.ClosePositionPartially(ticket,volume,comment,deviation));
      //--- If the request is executed successfully or the asynchronous order sending mode is set, play the success sound
      //--- set for a symbol trading object for this type of trading operation and return 'true'
      if(res || trade_obj.IsAsyncMode())
        {
         if(this.IsUseSounds())
            trade_obj.PlaySoundSuccess(action,(int)order.TypeOrder());
         return true;
        }
      //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation
      else
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRY_N),string(i+1),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,(int)order.TypeOrder());
         
         method=this.ResultProccessingMethod(trade_obj.GetResultRetcode());
         //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
           {
            this.SetTradingDisableFlag(true);
            break;
           }
         //--- If "Exit the trading method" is received as a result of sending a request, end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
           {
            break;
           }
         //--- If "Correct the parameters and repeat" is received as a result of sending a request -
         //--- correct the parameters and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT)
           {
            this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj);
            continue;
           }
         //--- If "Update data and repeat" is received as a result of sending a request -
         //--- update data and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            symbol_obj.Refresh();
            continue;
           }
         //--- If "Wait and repeat" is received as a result of sending a request -
         //--- create a pending request and break the loop
         if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            //--- If the pending request object with the position ticket is not present in the list
            if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE)
              {
               //--- Waiting time in milliseconds:
               //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
               ulong wait=method;
               //--- Look for the least of the possible IDs. If failed to find
               //--- or in case of an error while updating the current symbol data, return 'false'
               int id=this.GetFreeID();
               if(id<1 || !symbol_obj.RefreshRates())
                  return false;
               //--- Write the trading operation type, symbol, ticket and volume to the request structure
               this.m_request.action=TRADE_ACTION_DEAL;
               this.m_request.symbol=symbol_obj.Name();
               this.m_request.position=ticket;
               this.m_request.volume=volume;
               //--- Set the number of trading attempts, create a pending request and break the loop
               uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
               this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj);
               break;
              }
           }
        }
     }
//--- Return the result of sending a trading request in a symbol trading object
   return res;
  }
//+------------------------------------------------------------------+

Método para fechar uma posição usando uma oposta:

//+------------------------------------------------------------------+
//| Close a position by an opposite one                              |
//+------------------------------------------------------------------+
bool CTrading::ClosePositionBy(const ulong ticket,const ulong ticket_by)
  {
   bool res=true;
   this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR;
   ENUM_ACTION_TYPE action=ACTION_TYPE_CLOSE_BY;
//--- Get an order object by ticket
   COrder *order=this.GetOrderObjByTicket(ticket);
   if(order==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ));
      return false;
     }
   ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)order.TypeOrder();
//--- Get a symbol object by a position ticket
   CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN);
   if(symbol_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- trading object of a closed position
   CTradeObj *trade_obj_pos=this.GetTradeObjByPosition(ticket,DFUN);
   if(trade_obj_pos==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   if(!this.m_account.IsHedge())
     {
      trade_obj_pos.SetResultRetcode(MSG_ACC_UNABLE_CLOSE_BY);
      trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode()));
      return false;
     }
//--- check the presence of an opposite position
   if(!this.CheckPositionAvailablity(ticket_by,DFUN))
     {
      trade_obj_pos.SetResultRetcode(MSG_LIB_SYS_ERROR_POSITION_BY_ALREADY_CLOSED);
      trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode()));
      return false;
     }
//--- trading object of an opposite position
   CTradeObj *trade_obj_pos_by=this.GetTradeObjByPosition(ticket_by,DFUN);
   if(trade_obj_pos_by==NULL)
     {
      trade_obj_pos.SetResultRetcode(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ);
      trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode()));
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
//--- If a symbol of a closed position is not equal to an opposite position's one, inform of that and exit
   if(symbol_obj.Name()!=trade_obj_pos_by.GetSymbol())
     {
      trade_obj_pos.SetResultRetcode(MSG_LIB_TEXT_CLOSE_BY_SYMBOLS_UNEQUAL);
      trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode()));
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_CLOSE_BY_SYMBOLS_UNEQUAL));
      return false;
     }
//--- Update symbol quotes
   if(!symbol_obj.RefreshRates())
     {
      trade_obj_pos.SetResultRetcode(10021);
      trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode()));
      this.AddErrorCodeToList(10021);  // No quotes to handle the request
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(10021));
      return false;
     }
     
//--- If there are trading limitations, there are FreezeLevel limitations - play the error sound and exit
   ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(0,0,action,order_type,symbol_obj,trade_obj_pos,DFUN,0,0,0,ticket);
   if(method!=ERROR_CODE_PROCESSING_METHOD_OK)
     {
      //--- If trading is completely disabled
      if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
        {
         trade_obj_pos.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE);
         trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode()));
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE));
         if(this.IsUseSounds())
            trade_obj_pos.PlaySoundError(action,order_type);
         return false;
        }
      //--- If the check result is "abort trading operation" - set the last error code to the return structure,
      //--- display a journal message, play the error sound and exit
      if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
        {
         int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
         if(code!=NULL)
           {
            trade_obj_pos.SetResultRetcode(code);
            trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode()));
           }
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED));
         if(this.IsUseSounds())
            trade_obj_pos.PlaySoundError(action,order_type);
         return false;
        }
      //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal,
      //--- create a pending request and return 'false'
      if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
        {
         //--- If the pending request object with the position ticket is not present in the list
         if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE)
           {
            //--- Play the error sound
            if(this.IsUseSounds())
               trade_obj_pos.PlaySoundError(action,order_type);
            //--- set the last error code to the return structure
            int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
            if(code!=NULL)
              {
               if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED)
                  code=10027;
               trade_obj_pos.SetResultRetcode(code);
               trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode()));
              }
            //--- Waiting time in milliseconds:
            //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
            ulong wait=method;
            //--- Look for the least of the possible IDs. If failed to find
            //--- or in case of an error while updating the current symbol data, return 'false'
            int id=this.GetFreeID();
            if(id<1 || !symbol_obj.RefreshRates())
               return false;
            //--- Write the trading operation type, symbol and tickets of two positions to the request structure
            this.m_request.action=TRADE_ACTION_CLOSE_BY;
            this.m_request.symbol=symbol_obj.Name();
            this.m_request.position=ticket;
            this.m_request.position_by=ticket_by;
            //--- Set the number of trading attempts and create a pending request
            uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
            this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj_pos.GetResultRetcode(),symbol_obj);
           }
         return false;
        }
     }

//--- In the loop by the number of attempts
   for(int i=0;i<this.m_total_try;i++)
     {                
      //--- Send the request
      res=trade_obj_pos.ClosePositionBy(ticket,ticket_by);
      //--- If the request is successful, play the success sound set for a symbol trading object for this type of trading operation
      if(res || trade_obj_pos.IsAsyncMode())
        {
         if(this.IsUseSounds())
            trade_obj_pos.PlaySoundSuccess(action,(int)order.TypeOrder());
         return true;
        }
      //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation
      else
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj_pos.GetResultRetcode()));
         if(this.IsUseSounds())
            trade_obj_pos.PlaySoundError(action,(int)order.TypeOrder());
         
         method=this.ResultProccessingMethod(trade_obj_pos.GetResultRetcode());
         //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
           {
            this.SetTradingDisableFlag(true);
            break;
           }
         //--- If "Exit the trading method" is received as a result of sending a request, end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
           {
            break;
           }
         //--- If "Correct the parameters and repeat" is received as a result of sending a request -
         //--- correct the parameters and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT)
           {
            this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj_pos.SpreadMultiplier(),symbol_obj,trade_obj_pos);
            continue;
           }
         //--- If "Update data and repeat" is received as a result of sending a request -
         //--- update data and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            symbol_obj.Refresh();
            continue;
           }
         //--- If "Wait and repeat" is received as a result of sending a request -
         //--- create a pending request and break the loop
         if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            //--- If the pending request object with the position ticket is not present in the list
            if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE)
              {
               //--- Waiting time in milliseconds:
               //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
               ulong wait=method;
               //--- Look for the least of the possible IDs. If failed to find
               //--- or in case of an error while updating the current symbol data, return 'false'
               int id=this.GetFreeID();
               if(id<1 || !symbol_obj.RefreshRates())
                  return false;
               //--- Write the trading operation type, symbol and tickets of two positions to the request structure
               this.m_request.action=TRADE_ACTION_CLOSE_BY;
               this.m_request.symbol=symbol_obj.Name();
               this.m_request.position=ticket;
               this.m_request.position_by=ticket_by;
               //--- Set the number of trading attempts, create a pending request and break the loop
               uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
               this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj_pos.GetResultRetcode(),symbol_obj);
               break;
              }
           }
        }
     }
   //--- Return the result of sending a trading request in a symbol trading object
   return res;
  }
//+------------------------------------------------------------------+

Método para definir uma ordem pendente:

//+------------------------------------------------------------------+
//| Place a pending order                                            |
//+------------------------------------------------------------------+
template<typename PS,typename PL,typename SL,typename TP>
bool CTrading::PlaceOrder(const ENUM_ORDER_TYPE order_type,
                          const double volume,
                          const string symbol,
                          const PS price_stop,
                          const PL price_limit=0,
                          const SL sl=0,
                          const TP tp=0,
                          const ulong magic=ULONG_MAX,
                          const string comment=NULL,
                          const datetime expiration=0,
                          const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                          const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   bool res=true;
   this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR;
   ENUM_ACTION_TYPE action=(ENUM_ACTION_TYPE)order_type;
//--- Get a symbol object by a symbol name
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   if(symbol_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false; 
     }
//--- Set the prices
//--- If failed to set - write the "internal error" flag, set the error code in the return structure,
//--- display the message in the journal and return 'false'
   if(!this.SetPrices(order_type,price_stop,sl,tp,price_limit,DFUN,symbol_obj))
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      trade_obj.SetResultRetcode(10021);
      trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(10021));   // No quotes to process the request
      return false;
     }
     
//--- Write the volume, comment, as well as expiration and filling types to the request structure
   this.m_request.volume=volume;
   this.m_request.comment=(comment==NULL ? trade_obj.GetComment() : comment);
   this.m_request.type_time=(type_time>WRONG_VALUE ? type_time : trade_obj.GetTypeExpiration());
   this.m_request.type_filling=(type_filling>WRONG_VALUE ? type_filling : trade_obj.GetTypeFilling());
//--- In case of trading limitations, funds insufficiency,
//--- there are limitations on StopLevel - play the error sound and exit
   ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(this.m_request.volume,
                                                             this.m_request.price,
                                                             action,
                                                             order_type,
                                                             symbol_obj,
                                                             trade_obj,
                                                             DFUN,
                                                             this.m_request.stoplimit,
                                                             this.m_request.sl,
                                                             this.m_request.tp);
   if(method!=ERROR_CODE_PROCESSING_METHOD_OK)
     {
      //--- If trading is completely disabled
      if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
        {
         trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE);
         trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type);
         return false;
        }
      //--- If the check result is "abort trading operation" - set the last error code to the return structure,
      //--- display a journal message, play the error sound and exit
      if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
        {
         int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
         if(code!=NULL)
           {
            trade_obj.SetResultRetcode(code);
            trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
           }
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type);
         return false;
        }
      //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal,
      //--- create a pending request and return 'false'
      if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
        {
         //--- If the trading request magic number, has no pending request ID
         if(this.GetPendReqID((uint)magic)==0)
           {
            //--- Play the error sound
            if(this.IsUseSounds())
               trade_obj.PlaySoundError(action,order_type);
            //--- set the last error code to the return structure
            int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
            if(code!=NULL)
              {
               if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED)
                  code=10027;
               trade_obj.SetResultRetcode(code);
               trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
              }
            //--- Waiting time in milliseconds:
            //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
            //--- for the "Create a pending request" handling method - till there is a zero waiting time
            ulong wait=method;
            //--- Look for the least of the possible IDs. If failed to find
            //--- or in case of an error while updating the current symbol data, return 'false'
            int id=this.GetFreeID();
            if(id<1 || !symbol_obj.RefreshRates())
               return false;
            //--- Write the request ID to the magic number, while a symbol name is set in the request structure,
            //--- trading operation and order types
            uint mn=(magic==ULONG_MAX ? (uint)trade_obj.GetMagic() : (uint)magic);
            this.SetPendReqID((uchar)id,mn);
            this.m_request.magic=mn;
            this.m_request.symbol=symbol_obj.Name();
            this.m_request.action=TRADE_ACTION_PENDING;
            this.m_request.type=order_type;
               //--- Set the number of trading attempts and create a pending request
            uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
            this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj);
           }
         return false;
        }
     }

//--- In the loop by the number of attempts
   for(int i=0;i<this.m_total_try;i++)
     {                
      //--- Send the request
      res=trade_obj.SetOrder(order_type,
                             this.m_request.volume,
                             this.m_request.price,
                             this.m_request.sl,
                             this.m_request.tp,
                             this.m_request.stoplimit,
                             magic,
                             comment,
                             this.m_request.expiration,
                             this.m_request.type_time,
                             this.m_request.type_filling);
      //--- If the request is executed successfully or the asynchronous order sending mode is set, play the success sound
      //--- set for a symbol trading object for this type of trading operation and return 'true'
      if(res || trade_obj.IsAsyncMode())
        {
         if(this.IsUseSounds())
            trade_obj.PlaySoundSuccess(action,order_type);
         return true;
        }
      //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation
      else
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRY_N),string(i+1),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type);
         
         method=this.ResultProccessingMethod(trade_obj.GetResultRetcode());
         //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
           {
            this.SetTradingDisableFlag(true);
            break;
           }
         //--- If "Exit the trading method" is received as a result of sending a request, end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
           {
            break;
           }
         //--- If "Correct the parameters and repeat" is received as a result of sending a request -
         //--- correct the parameters and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT)
           {
            this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj);
            continue;
           }
         //--- If "Update data and repeat" is received as a result of sending a request -
         //--- update data and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            symbol_obj.Refresh();
            continue;
           }
         //--- If "Wait and repeat" is received as a result of sending a request - create a pending request and end the loop
         if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            //--- If the trading request magic number, has no pending request ID
            if(this.GetPendReqID((uint)magic)==0)
              {
               //--- Waiting time in milliseconds:
               //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
               //--- for the "Create a pending request" handling method - till there is a zero waiting time
               ulong wait=method;
               //--- Look for the least of the possible IDs. If failed to find
               //--- or in case of an error while updating the current symbol data, return 'false'
               int id=this.GetFreeID();
               if(id<1 || !symbol_obj.RefreshRates())
                  return false;
               //--- Write the request ID to the magic number, while a symbol name is set in the request structure,
               //--- trading operation and order types
               uint mn=(magic==ULONG_MAX ? (uint)trade_obj.GetMagic() : (uint)magic);
               this.SetPendReqID((uchar)id,mn);
               this.m_request.magic=mn;
               this.m_request.symbol=symbol_obj.Name();
               this.m_request.action=TRADE_ACTION_PENDING;
               this.m_request.type=order_type;
               //--- Set the number of trading attempts, create a pending request and break the loop
               uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
               this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj);
               break;
              }
           }
        }
     }
//--- Return the result of sending a trading request in a symbol trading object
   return res;
  }
//+------------------------------------------------------------------+

Método para modificar uma ordem pendente:

//+------------------------------------------------------------------+
//| Modify a pending order                                           |
//+------------------------------------------------------------------+
template<typename PS,typename PL,typename SL,typename TP>
bool CTrading::ModifyOrder(const ulong ticket,
                           const PS price=WRONG_VALUE,
                           const SL sl=WRONG_VALUE,
                           const TP tp=WRONG_VALUE,
                           const PL limit=WRONG_VALUE,
                           datetime expiration=WRONG_VALUE,
                           const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                           const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   bool res=true;
   this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR;
   ENUM_ACTION_TYPE action=ACTION_TYPE_MODIFY;
//--- Get an order object by ticket
   COrder *order=this.GetOrderObjByTicket(ticket);
   if(order==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ));
      return false;
     }
   ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)order.TypeOrder();
//--- Get a symbol object by an order ticket
   CSymbol *symbol_obj=this.GetSymbolObjByOrder(ticket,DFUN);
   if(symbol_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
//--- Set the prices
//--- If failed to set - write the "internal error" flag, set the error code in the return structure,
//--- display the message in the journal and return 'false'
   if(!this.SetPrices(order_type,
                      (price>0 ? price : order.PriceOpen()),
                      (sl>0 ? sl : sl<0 ? order.StopLoss() : 0),
                      (tp>0 ? tp : tp<0 ? order.TakeProfit() : 0),
                      (limit>0 ? limit : order.PriceStopLimit()),
                      DFUN,symbol_obj))
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      trade_obj.SetResultRetcode(10021);
      trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(10021));   // No quotes to process the request
      return false;
     }
     
//--- Write the filling type, as well as expiration date and type to the request structure
   this.m_request.type_filling=(type_filling>WRONG_VALUE ? type_filling : order.TypeFilling());
   this.m_request.expiration=(expiration>WRONG_VALUE ? expiration : order.TimeExpiration());
   this.m_request.type_time=(type_time>WRONG_VALUE ? type_time : order.TypeTime());
//--- If there are trading limitations,
//--- StopLevel or FreezeLevel limitations, play the error sound and exit
   ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(0,this.m_request.price,action,order_type,symbol_obj,trade_obj,DFUN,this.m_request.stoplimit,this.m_request.sl,this.m_request.tp,ticket);
   if(method!=ERROR_CODE_PROCESSING_METHOD_OK)
     {
      //--- If trading is completely disabled
      if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
        {
         trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE);
         trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true),(price>0 || limit>0 ? true : false));
         return false;
        }
      //--- If the check result is "abort trading operation" - set the last error code to the return structure,
      //--- display a journal message, play the error sound and exit
      if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
        {
         int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
         if(code!=NULL)
           {
            trade_obj.SetResultRetcode(code);
            trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
           }
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED));
         if(this.IsUseSounds() && trade_obj.GetResultRetcode()!=10025)
            trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true),(price>0 || limit>0 ? true : false));
         return false;
        }
      //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal,
      //--- create a pending request and return 'false'
      if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
        {
         //--- If the pending request object with the order ticket is not present in the list
         if(this.GetIndexPendingRequestByOrder(ticket)==WRONG_VALUE)
           {
            //--- Play the error sound
            if(this.IsUseSounds())
               trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true),(price>0 || limit>0 ? true : false));
            //--- set the last error code to the return structure
            int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
            if(code!=NULL)
              {
               if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED)
                  code=10027;
               trade_obj.SetResultRetcode(code);
               trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
              }
            //--- Waiting time in milliseconds:
            //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
            //--- for the "Create a pending request" handling method - till there is a zero waiting time
            ulong wait=method;
            //--- Look for the least of the possible IDs. If failed to find
            //--- or in case of an error while updating the current symbol data, return 'false'
            int id=this.GetFreeID();
            if(id<1 || !symbol_obj.RefreshRates())
               return false;
            //--- Set the trading operation type, as well as modified order's symbol and ticket in the request structure
            this.m_request.action=TRADE_ACTION_MODIFY;
            this.m_request.symbol=symbol_obj.Name();
            this.m_request.order=ticket;
            //--- Set the number of trading attempts and create a pending request
            uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
            this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj);
           }
         return false;
        }
     }

//--- In the loop by the number of attempts
   for(int i=0;i<this.m_total_try;i++)
     {                
      //--- Send the request
      res=trade_obj.ModifyOrder(ticket,price,sl,tp,limit,expiration,type_time,type_filling);
      //--- If the request is executed successfully or the asynchronous order sending mode is set, play the success sound
      //--- set for a symbol trading object for this type of trading operation and return 'true'
      if(res || trade_obj.IsAsyncMode())
        {
         if(this.IsUseSounds())
            trade_obj.PlaySoundSuccess(action,(int)order.TypeOrder(),(sl<0 ? false : true),(tp<0 ? false : true),(price>0 || limit>0 ? true : false));
         return true;
        }
      //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation
      else
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRY_N),string(i+1),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,(int)order.TypeOrder(),(sl<0 ? false : true),(tp<0 ? false : true),(price>0 || limit>0 ? true : false));
         
         //--- Get the error handling method
         method=this.ResultProccessingMethod(trade_obj.GetResultRetcode());
         //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
           {
            this.SetTradingDisableFlag(true);
            break;
           }
         //--- If "Exit the trading method" is received as a result of sending a request, end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
           {
            break;
           }
         //--- If "Correct the parameters and repeat" is received as a result of sending a request -
         //--- correct the parameters and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT)
           {
            this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj);
            continue;
           }
         //--- If "Update data and repeat" is received as a result of sending a request -
         //--- update data and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            symbol_obj.Refresh();
            continue;
           }
         //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal,
         //--- create a pending request and break the loop
         if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            //--- If the pending request object with the order ticket is not present in the list
            if(this.GetIndexPendingRequestByOrder(ticket)==WRONG_VALUE)
              {
               //--- Waiting time in milliseconds:
               //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
               //--- for the "Create a pending request" handling method - till there is a zero waiting time
               ulong wait=method;
               //--- Look for the least of the possible IDs. If failed to find
               //--- or in case of an error while updating the current symbol data, return 'false'
               int id=this.GetFreeID();
               if(id<1 || !symbol_obj.RefreshRates())
                  return false;
               //--- Set the trading operation type, as well as modified order's symbol and ticket in the request structure
               this.m_request.action=TRADE_ACTION_MODIFY;
               this.m_request.symbol=symbol_obj.Name();
               this.m_request.order=ticket;
               //--- Set the number of trading attempts, create a pending request and break the loop
               uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
               this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj);
               break;
              }
           }
        }
     }
//--- Return the result of sending a trading request in a symbol trading object
   return res;
  }
//+------------------------------------------------------------------+

Método para excluir uma ordem pendente:

//+------------------------------------------------------------------+
//| Remove a pending order                                           |
//+------------------------------------------------------------------+
bool CTrading::DeleteOrder(const ulong ticket)
  {
   bool res=true;
   this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR;
   ENUM_ACTION_TYPE action=ACTION_TYPE_CLOSE;
//--- Get an order object by ticket
   COrder *order=this.GetOrderObjByTicket(ticket);
   if(order==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ));
      return false;
     }
   ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)order.TypeOrder();
//--- Get a symbol object by an order ticket
   CSymbol *symbol_obj=this.GetSymbolObjByOrder(ticket,DFUN);
   if(symbol_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
//--- Update symbol quotes
   if(!symbol_obj.RefreshRates())
     {
      trade_obj.SetResultRetcode(10021);
      trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
      this.AddErrorCodeToList(10021);  // No quotes to handle the request
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(10021));
      return false;
     }
     
//--- If there are trading limitations,
//--- there are limitations on FreezeLevel - play the error sound and exit
   ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(0,0,action,order_type,symbol_obj,trade_obj,DFUN,0,0,0,ticket);
   if(method!=ERROR_CODE_PROCESSING_METHOD_OK)
     {
      //--- If trading is completely disabled
      if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
        {
         trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE);
         trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type);
         return false;
        }
      //--- If the check result is "abort trading operation" - set the last error code to the return structure,
      //--- display a journal message, play the error sound and exit
      if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
        {
         int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
         if(code!=NULL)
           {
            trade_obj.SetResultRetcode(code);
            trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
           }
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type);
         return false;
        }
      //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal,
      //--- create a pending request and return 'false'
      if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
        {
         //--- If the pending request object with the order ticket is not present in the list
         if(this.GetIndexPendingRequestByOrder(ticket)==WRONG_VALUE)
           {
            //--- Play the error sound
            if(this.IsUseSounds())
               trade_obj.PlaySoundError(action,order_type);
            //--- set the last error code to the return structure
            int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
            if(code!=NULL)
              {
               if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED)
                  code=10027;
               trade_obj.SetResultRetcode(code);
               trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
              }
            //--- Waiting time in milliseconds:
            //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
            //--- for the "Create a pending request" handling method - till there is a zero waiting time
            ulong wait=method;
            //--- Look for the least of the possible IDs. If failed to find
            //--- or in case of an error while updating the current symbol data, return 'false'
            int id=this.GetFreeID();
            if(id<1 || !symbol_obj.RefreshRates())
               return false;
            //--- Set the trading operation type, as well as deleted order's symbol and ticket in the request structure
            this.m_request.action=TRADE_ACTION_REMOVE;
            this.m_request.symbol=symbol_obj.Name();
            this.m_request.order=ticket;
            //--- Set the number of trading attempts and create a pending request
            uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
            this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj);
           }
         return false;
        }
     }

//--- In the loop by the number of attempts
   for(int i=0;i<this.m_total_try;i++)
     {                
      //--- Send the request
      res=trade_obj.DeleteOrder(ticket);
      //--- If the request is executed successfully or the asynchronous order sending mode is set, play the success sound
      //--- set for a symbol trading object for this type of trading operation and return 'true'
      if(res || trade_obj.IsAsyncMode())
        {
         if(this.IsUseSounds())
            trade_obj.PlaySoundSuccess(action,(int)order.TypeOrder());
         return true;
        }
      //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation
      else
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRY_N),string(i+1),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,(int)order.TypeOrder());
         
         //--- Get the error handling method
         method=this.ResultProccessingMethod(trade_obj.GetResultRetcode());
         //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
           {
            this.SetTradingDisableFlag(true);
            break;
           }
         //--- If "Exit the trading method" is received as a result of sending a request, end the attempt loop
         if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
           {
            break;
           }
         //--- If "Correct the parameters and repeat" is received as a result of sending a request -
         //--- correct the parameters and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT)
           {
            this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj);
            continue;
           }
         //--- If "Update data and repeat" is received as a result of sending a request -
         //--- update data and start the next iteration
         if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            symbol_obj.Refresh();
            continue;
           }
         //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal,
         //--- create a pending request and break the loop
         if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH)
           {
            //--- If the pending request object with the order ticket is not present in the list
            if(this.GetIndexPendingRequestByOrder(ticket)==WRONG_VALUE)
              {
               //--- Waiting time in milliseconds:
               //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value,
               //--- for the "Create a pending request" handling method - till there is a zero waiting time
               ulong wait=method;
               //--- Look for the least of the possible IDs. If failed to find
               //--- or in case of an error while updating the current symbol data, return 'false'
               int id=this.GetFreeID();
               if(id<1 || !symbol_obj.RefreshRates())
                  return false;
               //--- Set the trading operation type, as well as deleted order's symbol and ticket in the request structure
               this.m_request.action=TRADE_ACTION_REMOVE;
               this.m_request.symbol=symbol_obj.Name();
               this.m_request.order=ticket;
               //--- Set the number of trading attempts, create a pending request and break the loop
               uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try);
               this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj);
               break;
              }
           }
        }
     }
//--- Return the result of sending a trading request in a symbol trading object
   return res;
  }
//+------------------------------------------------------------------+

Como se pode ver na listagem de métodos, praticamente todos os blocos para criar ordens pendentes são os mesmos para os diferentes métodos: são preenchidos os campos da estrutura da ordem de negociação, é definido o número de tentativas de negociação, é criada a ordem pendente e é realizada a saída do método de negociação. Em seguida, já começam a trabalhar os objetos das ordens pendentes vindos do temporizador da classe mencionada acima.

Essas são todas as alterações na classe de negociação necessárias para implementar ordens pendentes.

Como, na classe de negociação, o método OnInit() agora adota um parâmetro adicional (ponteiro para o objeto da classe-coleção de eventos de negociação), é necessário enviá-lo para lá.
Isso é feito na classe do objeto básico da biblioteca CEngine.
Abrimos o arquivo Engine.mqh e fazemos alterações adicionais no seu método TradingOnInit():

//--- Pass the pointers to all the necessary collections to the trading class
   void                 TradingOnInit(void)
                          {
                           this.m_trading.OnInit(this.GetAccountCurrent(),m_symbols.GetObject(),m_market.GetObject(),m_history.GetObject(),m_events.GetObject());
                          }

Aqui, chamamos o método OnInit() da classe de negociação CTrading, onde com a ajuda do último parâmetro transferimos à classe de negociação o ponteiro para o objeto da classe-coleção de eventos de negociação da conta.

Teste

Para testar o funcionamento de objetos de ordens pendentes, basta usarmos o EA do artigo anterior sem nenhuma alteração.
Mas, para manter a ordem, vamos salvá-lo na nova pasta \MQL5\Experts\TestDoEasy\Part28\ usando o novo nome TestDoEasyPart28.mq5.

O que faremos para verificar o funcionamento de ordens pendentes:
Desativamos o botão "Autotrading" no terminal e clicamos no botão para abrir uma posição no painel de negociação do EA de teste. Obtemos o erro de envio de ordem de negociação e o registro no log sobre o erro e sobre a criação da ordem de negociação.
Em seguida, ativamos de volta o botão "Autotrading" no terminal e aguardamos até chegar o momento da segunda tentativa de negociação (para ausência de permissões de negociação no terminal temos definido uma espera de 20 segundos). Após chegar o momento da seguinte tentativa, teremos uma posição aberta, serão exibidos uma entrada no log acerca disso e, adicionalmente, um registro dizendo que a ordem pendente fez seu trabalho e foi excluída:

2019.12.12 15:36:17.878 automated trading is disabled
2019.12.12 15:36:23.206 CTrading::OpenPosition<uint,uint>: Invalid request:
2019.12.12 15:36:23.206 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled)
2019.12.12 15:36:23.206 Correction of trade request parameters ...
2019.12.12 15:36:23.207 Pending request created #1:
2019.12.12 15:36:23.207 ================== Pending trade request's parameters ==================
2019.12.12 15:36:23.207  - Pending request type: Pending request that was created as a result of the server code
2019.12.12 15:36:23.207  - Trade request ID: #1
2019.12.12 15:36:23.207  - Return code based on which the request was created: 10027 "Autotrading disabled by client terminal"
2019.12.12 15:36:23.207  - Request creation time: 2019.12.12 10:36:23.006
2019.12.12 15:36:23.207  - Price at time of request create: : 1.11353
2019.12.12 15:36:23.207  - Request activation time: 2019.12.12 10:36:43.006
2019.12.12 15:36:23.207  - Waiting time between trading attempts: 20000 (00:00:20)
2019.12.12 15:36:23.207  - Current trading attempt: Waiting for the onset time of the first trading attempt
2019.12.12 15:36:23.207  - Total trade attempts: 5
2019.12.12 15:36:23.207 ================== Trade request's parameters ==================
2019.12.12 15:36:23.207  - Trade operation type: Place market order
2019.12.12 15:36:23.207  - Trade symbol: EURUSD
2019.12.12 15:36:23.207  - Requested volume for a deal in lots: 0.10
2019.12.12 15:36:23.207  - Price: 1.11356
2019.12.12 15:36:23.207  - Stop Loss level of the order: 1.11206
2019.12.12 15:36:23.207  - Take Profit level of the order: 1.11506
2019.12.12 15:36:23.207  - Maximal deviation from the price: 5
2019.12.12 15:36:23.207  - Order type: Market-order Buy
2019.12.12 15:36:23.207  - Order execution type: The order is executed exclusively in the specified volume, otherwise it is canceled (FOK)
2019.12.12 15:36:23.207  - Magic number: 25821307
2019.12.12 15:36:23.207  - Order comment: "TestDoEasyPart28 by DoEasy"
2019.12.12 15:36:23.207 ==================
2019.12.12 15:36:23.207  
2019.12.12 15:36:26.845 automated trading is enabled
2019.12.12 15:36:43.536 Retry trading attempt #1
2019.12.12 15:36:43.883 - Position is open: 2019.12.12 10:36:43.797 -
2019.12.12 15:36:43.883 EURUSD Opened 0.10 Buy #494348590 [0.10 Market-order Buy #494348590] at price 1.11354, sl 1.11206, tp 1.11506, Magic number 25821307 (123), G1: 10, G2: 8, ID: 1
2019.12.12 15:36:43.883 OnDoEasyEvent: Position is open
2019.12.12 15:36:44.101 Trade request ID: #1: Pending request deleted due to execution

Logo, após abrir uma posição novamente desativamos o botão "Autotrading" no terminal e pressionamos o botão de fechamento de posição no painel de negociação do EA de teste. Recebemos o erro e as entradas no log sobre um erro de criação de ordem pendente.
Posteriormente, ativamos de volta o botão "Autotrading" no terminal e aguardamos até chegar o momento da segunda tentativa de negociação. Após chegar o momento da seguinte tentativa, a posição que abrimos anteriormente será fechada, serão exibidos uma entrada no log acerca disso e, adicionalmente, um registro dizendo que a ordem pendente fez seu trabalho e foi excluída:

2019.12.12 15:37:02.347 automated trading is disabled
2019.12.12 15:37:06.566 CTrading::ClosePosition: Invalid request:
2019.12.12 15:37:06.566 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled)
2019.12.12 15:37:06.566 Correction of trade request parameters ...
2019.12.12 15:37:06.566 Pending request created #1:
2019.12.12 15:37:06.566 ================== Pending trade request's parameters ==================
2019.12.12 15:37:06.566  - Pending request type: Pending request that was created as a result of the server code
2019.12.12 15:37:06.566  - Trade request ID: #1
2019.12.12 15:37:06.566  - Return code based on which the request was created: 10027 "Autotrading disabled by client terminal"
2019.12.12 15:37:06.566  - Request creation time: 2019.12.12 10:37:03.586
2019.12.12 15:37:06.566  - Price at time of request create: : 1.11351
2019.12.12 15:37:06.566  - Request activation time: 2019.12.12 10:37:23.586
2019.12.12 15:37:06.566  - Waiting time between trading attempts: 20000 (00:00:20)
2019.12.12 15:37:06.566  - Current trading attempt: Waiting for the onset time of the first trading attempt
2019.12.12 15:37:06.566  - Total trade attempts: 5
2019.12.12 15:37:06.566 ================== Trade request's parameters ==================
2019.12.12 15:37:06.566  - Trade operation type: Place market order
2019.12.12 15:37:06.566  - Trade symbol: EURUSD
2019.12.12 15:37:06.566  - Requested volume for a deal in lots: Value not set
2019.12.12 15:37:06.566  - Price: 1.11354
2019.12.12 15:37:06.566  - Stop Loss level of the order: 1.11206
2019.12.12 15:37:06.566  - Take Profit level of the order: 1.11506
2019.12.12 15:37:06.566  - Maximal deviation from the price: 5
2019.12.12 15:37:06.566  - Order type: Market-order Buy
2019.12.12 15:37:06.566  - Order execution type: The order is executed exclusively in the specified volume, otherwise it is canceled (FOK)
2019.12.12 15:37:06.566  - Magic number: 0
2019.12.12 15:37:06.566  - Order comment: "TestDoEasyPart28 by DoEasy"
2019.12.12 15:37:06.566 ==================
2019.12.12 15:37:06.566 
2019.12.12 15:37:11.611 automated trading is enabled
2019.12.12 15:37:25.196 Retry trading attempt #1
2019.12.12 15:37:25.679 - Position closed: 2019.12.12 10:36:43.797 -
2019.12.12 15:37:25.679 EURUSD Closed Buy #494348590 [0.10 Market-order Sell #494348941] at price 1.11349, sl 1.11206, tp 1.11506, Magic number 25821307 (123), G1: 10, G2: 8, ID: 1, Profit -0.50 USD
2019.12.12 15:37:25.679 OnDoEasyEvent: Position closed
2019.12.12 15:37:25.838 Trade request ID: #1: Pending request deleted due to execution

Agora verifiquemos o processamento de várias ordens de negociação ao mesmo tempo.
Desativamos a negociação automática, pressionamos alternadamente os botões para definir ordens pendentes. Após cada tentativa para definir uma ordem, recebemos uma mensagem de erro, um registro de criação de ordem pendente e seus parâmetros.
Em seguida, ativamos a negociação automática no terminal. Assim que chegar a próxima tentativa vinda de cada uma das ordens de negociação pendentes, será exibida uma mensagem sobre o número da tentativa de cada solicitação e uma mensagem sobre a definição bem-sucedida de cada ordem.
Em seguida, cada ordem de negociação pendente será excluída e aparecerá a mensagem correspondente no log
:

2019.12.12 17:47:16.774 automated trading is disabled
2019.12.12 17:47:20.297 CTrading::PlaceOrder<uint,int,uint,uint>: Invalid request:
2019.12.12 17:47:20.297 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled)
2019.12.12 17:47:20.298 Correction of trade request parameters ...
2019.12.12 17:47:20.298 Pending request created #1:
2019.12.12 17:47:20.298 ================== Pending trade request's parameters ==================
2019.12.12 17:47:20.298  - Pending request type: Pending request that was created as a result of the server code
2019.12.12 17:47:20.298  - Trade request ID: #1
2019.12.12 17:47:20.298  - Return code based on which the request was created: 10027 "Autotrading disabled by client terminal"
2019.12.12 17:47:20.298  - Request creation time: 2019.12.12 12:47:18.719
2019.12.12 17:47:20.298  - Price at time of request create: : 1.11293
2019.12.12 17:47:20.298  - Request activation time: 2019.12.12 12:47:38.719
2019.12.12 17:47:20.298  - Waiting time between trading attempts: 20000 (00:00:20)
2019.12.12 17:47:20.298  - Current trading attempt: Waiting for the onset time of the first trading attempt
2019.12.12 17:47:20.298  - Total trade attempts: 5
2019.12.12 17:47:20.298 ================== Trade request's parameters ==================
2019.12.12 17:47:20.298  - Trade operation type: Place pending order
2019.12.12 17:47:20.298  - Trade symbol: EURUSD
2019.12.12 17:47:20.298  - Requested volume for a deal in lots: 0.10
2019.12.12 17:47:20.298  - Price: 1.11343
2019.12.12 17:47:20.298  - StopLimit level of the order: Value not set
2019.12.12 17:47:20.298  - Stop Loss level of the order: 1.11493
2019.12.12 17:47:20.298  - Take Profit level of the order: 1.11193
2019.12.12 17:47:20.298  - Order type: Pending order Sell Limit
2019.12.12 17:47:20.298  - Order execution type: The order is executed exclusively in the specified volume, otherwise it is canceled (FOK)
2019.12.12 17:47:20.298  - Order expiration type: Good till cancel order
2019.12.12 17:47:20.298  - Order expiration time: Value not set
2019.12.12 17:47:20.298  - Magic number: 27525243
2019.12.12 17:47:20.298  - Order comment: "Pending order SellLimit"
2019.12.12 17:47:20.298  ==================
2019.12.12 17:47:20.298 
2019.12.12 17:47:24.514 Pending request created #2:
2019.12.12 17:47:24.514 ================== Pending trade request's parameters ==================
2019.12.12 17:47:24.514  - Pending request type: Pending request that was created as a result of the server code
2019.12.12 17:47:24.514  - Trade request ID: #2
2019.12.12 17:47:24.514  - Return code based on which the request was created: 10027 "Autotrading disabled by client terminal"
2019.12.12 17:47:24.514  - Request creation time: 2019.12.12 12:47:23.638
2019.12.12 17:47:24.514  - Price at time of request create: : 1.11296
2019.12.12 17:47:24.514  - Request activation time: 2019.12.12 12:47:43.638
2019.12.12 17:47:24.514  - Waiting time between trading attempts: 20000 (00:00:20)
2019.12.12 17:47:24.514  - Current trading attempt: Waiting for the onset time of the first trading attempt
2019.12.12 17:47:24.514  - Total trade attempts: 5
2019.12.12 17:47:24.514 ================== Trade request's parameters ==================
2019.12.12 17:47:24.514  - Trade operation type: Place pending order
2019.12.12 17:47:24.514  - Trade symbol: EURUSD
2019.12.12 17:47:24.514  - Requested volume for a deal in lots: 0.10
2019.12.12 17:47:24.514  - Price: 1.11251
2019.12.12 17:47:24.514  - StopLimit level of the order: Value not set
2019.12.12 17:47:24.514  - Stop Loss level of the order: 1.11101
2019.12.12 17:47:24.514  - Take Profit level of the order: 1.11401
2019.12.12 17:47:24.514  - Order type: Pending order Buy Limit
2019.12.12 17:47:24.514  - Order execution type: The order is executed exclusively in the specified volume, otherwise it is canceled (FOK)
2019.12.12 17:47:24.514  - Order expiration type: Good till cancel order
2019.12.12 17:47:24.514  - Order expiration time: Value not set
2019.12.12 17:47:24.514  - Magic number: 39387259
2019.12.12 17:47:24.514  - Order comment: "Pending order BuyLimit"
2019.12.12 17:47:24.514  ==================
2019.12.12 17:47:24.514 
2019.12.12 17:47:29.167 automated trading is enabled
2019.12.12 17:47:45.796 Retry trading attempt #1
2019.12.12 17:47:46.045 Retry trading attempt #1
2019.12.12 17:47:46.256 - Pending order placed: 2019.12.12 12:47:46.319 -
2019.12.12 17:47:46.256 EURUSD Placed 0.10 Pending order Sell Limit #494419747 at price 1.11343, sl 1.11493, tp 1.11193, Magic number 27525243 (123), G1: 4, G2: 10, ID: 1
2019.12.12 17:47:46.256 - Pending order placed: 2019.12.12 12:47:46.162 -
2019.12.12 17:47:46.256 EURUSD Placed 0.10 Pending order Buy Limit #494419742 at price 1.11251, sl 1.11101, tp 1.11401, Magic number 39387259 (123), G1: 9, G2: 5, ID: 2
2019.12.12 17:47:46.256 OnDoEasyEvent: Pending order placed
2019.12.12 17:47:46.256 OnDoEasyEvent: Pending order placed
2019.12.12 17:47:46.505 Trade request ID: #2: Pending request deleted due to execution
2019.12.12 17:47:46.505 Trade request ID: #1: Pending request deleted due to execution

Agora tentemos excluir duas ordens pendentes ao mesmo tempo.
Desativamos a negociação automática no terminal e pressionamos o botão para excluir todas as ordens pendentes no painel de negociação do EA de teste (Delete pending). Recebemos uma mensagem de erro e, em seguida, as entradas sobre a criação de ordem pendente e seus parâmetros para cada uma das ordens excluídas.
Em seguida, ativamos a negociação automática no terminal. Assim que chegar a próxima tentativa vinda de cada uma das ordens de negociação pendentes, será exibida uma mensagem sobre o número da tentativa de cada solicitação e uma mensagem sobre a remoção bem-sucedida de cada ordem.
Em seguida, cada ordem de negociação pendente será excluída e aparecerá a mensagem correspondente no log:

2019.12.12 17:47:57.310 automated trading is disabled
2019.12.12 17:48:03.105 CTrading::DeleteOrder: Invalid request:
2019.12.12 17:48:03.105 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled)
2019.12.12 17:48:03.105 Correction of trade request parameters ...
2019.12.12 17:48:03.105 Pending request created #1:
2019.12.12 17:48:03.106 ================== Pending trade request's parameters ==================
2019.12.12 17:48:03.106  - Pending request type: Pending request that was created as a result of the server code
2019.12.12 17:48:03.106  - Trade request ID: #1
2019.12.12 17:48:03.106  - Return code based on which the request was created: 10027 "Autotrading disabled by client terminal"
2019.12.12 17:48:03.106  - Request creation time: 2019.12.12 12:48:00.305
2019.12.12 17:48:03.106  - Price at time of request create: : 1.11300
2019.12.12 17:48:03.106  - Request activation time: 2019.12.12 12:48:20.305
2019.12.12 17:48:03.106  - Waiting time between trading attempts: 20000 (00:00:20)
2019.12.12 17:48:03.106  - Current trading attempt: Waiting for the onset time of the first trading attempt
2019.12.12 17:48:03.106  - Total trade attempts: 5
2019.12.12 17:48:03.106 ================== Trade request's parameters ==================
2019.12.12 17:48:03.106  - Trade operation type: Delete the pending order placed previously
2019.12.12 17:48:03.106  - Order ticket: 494419747
2019.12.12 17:48:03.106  ==================
2019.12.12 17:48:03.106 
2019.12.12 17:48:03.106 CTrading::DeleteOrder: Invalid request:
2019.12.12 17:48:03.106 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled)
2019.12.12 17:48:03.106 Correction of trade request parameters ...
2019.12.12 17:48:03.106 Pending request created #2:
2019.12.12 17:48:03.106 ================== Pending trade request's parameters ==================
2019.12.12 17:48:03.106  - Pending request type: Pending request that was created as a result of the server code
2019.12.12 17:48:03.106  - Trade request ID: #2
2019.12.12 17:48:03.106  - Return code based on which the request was created: 10027 "Autotrading disabled by client terminal"
2019.12.12 17:48:03.106  - Request creation time: 2019.12.12 12:48:00.305
2019.12.12 17:48:03.106  - Price at time of request create: : 1.11300
2019.12.12 17:48:03.106  - Request activation time: 2019.12.12 12:48:20.305
2019.12.12 17:48:03.106  - Waiting time between trading attempts: 20000 (00:00:20)
2019.12.12 17:48:03.106  - Current trading attempt: Waiting for the onset time of the first trading attempt
2019.12.12 17:48:03.106  - Total trade attempts: 5
2019.12.12 17:48:03.106 ================== Trade request's parameters ==================
2019.12.12 17:48:03.106  - Trade operation type: Delete the pending order placed previously
2019.12.12 17:48:03.106  - Order ticket: 494419742
2019.12.12 17:48:03.106  ==================
2019.12.12 17:48:03.106 
2019.12.12 17:48:09.073 automated trading is enabled
2019.12.12 17:48:24.428 Retry trading attempt #1
2019.12.12 17:48:24.428 CTrading::OnTimer: Trade operation type: Delete the pending order placed previously
2019.12.12 17:48:24.593 Retry trading attempt #1
2019.12.12 17:48:24.593 CTrading::OnTimer: Trade operation type: Delete the pending order placed previously
2019.12.12 17:48:24.771 - Pending order removed: 2019.12.12 12:47:46.319 -
2019.12.12 17:48:24.771 EURUSD Deleted 0.10 Pending order Sell Limit #494419747 at price 1.11343, sl 1.11493, tp 1.11193, Magic number 27525243 (123), G1: 4, G2: 10, ID: 1
2019.12.12 17:48:24.771 - Pending order removed: 2019.12.12 12:47:46.162 -
2019.12.12 17:48:24.771 EURUSD Deleted 0.10 Pending order Buy Limit #494419742 at price 1.11251, sl 1.11101, tp 1.11401, Magic number 39387259 (123), G1: 9, G2: 5, ID: 2
2019.12.12 17:48:24.771 OnDoEasyEvent: Pending order removed
2019.12.12 17:48:24.771 OnDoEasyEvent: Pending order removed
2019.12.12 17:48:25.024 Trade request ID: #2: Pending request deleted due to execution
2019.12.12 17:48:25.024 Trade request ID: #1: Pending request deleted due to execution

Como vemos nas mensagens de depuração no log, as ordens de negociação pendentes são ativadas conforme planejamos e, após a conclusão bem-sucedida de sua tarefa, elas são excluídas.

Esta não é versão definitiva e final dos objetos-ordens pendentes.
Esta é apenas uma verificação do conceito proposto para MQL5, em contas do tipo "hedge".

Lembre-se:

Chamo bastante a atenção para o fato de que o resultado da classe de negociação com as ordens pendentes descritas neste artigo e o EA de teste anexado ao artigo não devem, em caso algum, ser usados para negociação real!
Todos os testes, até o momento, são realizados em contas do tipo "hedge" e ainda não foram testados em contas do tipo "netting".
Este artigo, seus materiais e o resultado são apenas uma continuação da ideia de teste de ordens pendentes e, nesta apresentação, não são um produto acabado para uso em contas reais
, mas, sim, para uso somente em modo de demonstração ou no testador.

O que vem agora?

No próximo artigo, recapitularemos a ideia de teste sobre trabalhar com ordens pendentes de negociação: criaremos um objeto de ordem pendente em classes separadas, o que tornará possível expandir simplesmente a funcionalidade para trabalhar com ordens de negociação pendentes.

Abaixo estão anexados todos os arquivos da versão atual da biblioteca e os arquivos do EA de teste. Você pode baixá-los e testar tudo sozinho.
Se você tiver perguntas, comentários e sugestões, poderá expressá-los nos comentários do artigo.

Complementos

Artigos desta série:

Parte 1. Conceito, gerenciamento de dados e primeiros resultados
Parte 2. Coleção do histórico de ordens e negócios
Parte 3. Coleção de ordens e posições de mercado, busca e ordenação
Parte 4. Eventos de Negociação. Conceito
Parte 5. Classes e coleções de eventos de negociação. Envio de eventos para o programa
Parte 6. Eventos da conta netting
Parte 7. Eventos de ativação da ordem stoplimit, preparação da funcionalidade para os eventos de modificação de ordens e posições
Parte 8. Eventos de modificação de ordens e posições
Parte 9. Compatibilidade com a MQL4 — preparação dos dados
Parte 10. Compatibilidade com a MQL4 — eventos de abertura de posição e ativação de ordens pendentes
Parte 11. Compatibilidade com a MQL4 — eventos de encerramento de posição
Parte 12. Implementação da classe de objeto "conta" e da coleção de objetos da conta
Parte 13. Eventos do objeto conta
Parte 14. O objeto símbolo
Parte 15. Coleção de objetos-símbolos
Parte 16. Eventos de coleção de símbolos
Parte 17. Interatividade de objetos de biblioteca
Parte 18. Interatividade do objeto-conta e quaisquer de outros objetos da biblioteca
Parte 19. Classe de mensagens de biblioteca
Parte 20. Criação e armazenamento de recursos de programas
Parte 21 Classes de negociação - objeto básico de negociação multiplataforma
Parte 22. Classes de negociação - classe básica de negociação, controle de restrições
Parte 23. Classes de negociação - classe básica de negociação, controle de parâmetros válidos
Parte 24. Classes de negociação - classe básica de negociação, correção automática de parâmetros errados
Parte 25. Classes de negociação - classe básica de negociação, processamento de erros retornados pelo servidor de negociação
Parte 26. Trabalho com ordens pendentes, primeira implementação (abertura de posições)
Parte 27. Trabalho com ordens pendentes, posicionamento de ordens pendentes

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/7438

Arquivos anexados |
MQL5.zip (3620.21 KB)
MQL4.zip (3620.22 KB)
Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXIX): ordens de negociação pendentes, classes de objetos-ordens Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXIX): ordens de negociação pendentes, classes de objetos-ordens
Em artigos anteriores, verificamos a ideia de ordens de negociação pendentes. Uma ordem pendente é, em essência, uma ordem de negociação, mas, executada com base numa determinada condição. Hoje, criaremos classes completas de objetos-ordens pendentes, isto é, geraremos um objeto-ordem base com seus descendentes.
Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXVII): trabalho com ordens de negociação - posicionamento de ordens pendentes Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXVII): trabalho com ordens de negociação - posicionamento de ordens pendentes
Neste artigo continuaremos a tratar do trabalho com ordens de negociação, implementaremos o posicionamento de ordens pendentes, corrigiremos erros encontrados no funcionamento da classe de negociação.
Redes Neurais de Maneira Fácil Redes Neurais de Maneira Fácil
A inteligência artificial é frequentemente associada a algo fantasticamente complexo e incompreensível. Ao mesmo tempo, a inteligência artificial é cada vez mais mencionada na vida cotidiana. Notícias sobre conquistas relacionadas ao uso de redes neurais geralmente aparecem em diferentes mídias. O objetivo deste artigo é mostrar que qualquer pessoa pode criar facilmente uma rede neural e usar as conquistas da IA na negociação.
Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXVI): trabalho com ordens de negociação pendentes - primeira implementação (abertura de posições) Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXVI): trabalho com ordens de negociação pendentes - primeira implementação (abertura de posições)
No artigo, abordaremos o armazenamento de alguns dados no valor do número mágico de ordens e posições, e implementaremos ordens pendentes. Para examinar a ideia, criaremos a primeira ordem pendente de teste para abrir posições a mercado quando recebermos um erro do servidor requerendo aguardar e enviar uma segunda solicitação.