Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXIX): ordens de negociação pendentes, classes de objetos-ordens
Sumário
- Ideia
- Objeto base de uma ordem de negociação pendente abstrata
- Objetos-herdeiros do objeto base-ordem pendente
- Teste
- O que vem agora?
Ideia
Nos três artigos anteriores, testamos o conceito de gerenciamento de métodos de negociação de uma classe de negociação com a ajuda ordens
pendentes.
Uma ordem pendente é, em essência, uma ordem de negociação,
mas, executada com base numa determinada condição. Verificamos a condição de atraso para o envio de uma ordem de negociação nos métodos de
negociação ao receber um erro do servidor, erro esse cujo processamento requer alguma espera antes de enviar a ordem ao servidor novamente.
Certamente, essa não é a única condição para usar ordens pendentes. O níveis de preços para envio de ordens de negociação também podem ser uma
condição. Mesmo uma combinação de condições pode se tornar numa condição: alguns valores limite das propriedades do símbolo que ao serem
atingidos podem desencadear o envio de uma ordem de negociação ao servidor (ordens stop-limit são um exemplo claro de ordens de negociação
para posicionar uma ordem limite quando o preço atingir o nível de uma ordem stop).
Porém, para incluir tudo isso no código do objeto-ordem pendente, precisamos aplicar-lhe o conceito
geral de objetos de biblioteca, fazendo com que tais objetos se tornem facilmente extensíveis para introduzir novas propriedades
neles. Agora, nesta etapa de trabalho com ordens de negociação pendentes, nós, para verificar o conceito em questão, escreveremos o código
para trabalhar com elas diretamente na listagem da ordem de negociação, o
que não é algo conceitualmente verdadeiro se quisermos usá-las mais para frente (no entanto, foi planejado, primeiro, verificar
rapidamente tudo e, em seguida, dar a formatação correta).
Hoje, criaremos uma classe base de um objeto abstrato-ordem de negociação
pendente e classes de objetos-herdeiros do objeto-ordem base. O objeto base conterá propriedades comuns para todos os objetos-ordens,
enquanto os objetos-herdeiros conterão propriedades individuais inerentes aos status de cada objeto filho - faremos isso para todos os
objetos da biblioteca.
Mas, para começar, como habitual, criaremos as mensagens de biblioteca necessárias para trabalhar com objetos.
No arquivo Datas.mqh, inserimos os índices das novas mensagens de biblioteca:
...
MSG_LIB_TEXT_AND_PAUSE, // and pause MSG_LIB_TEXT_ALREADY_EXISTS, // already exists MSG_LIB_TEXT_CREATED, // Created MSG_LIB_TEXT_ATTEMPTS, // Attempts MSG_LIB_TEXT_WAIT, // Wait MSG_LIB_TEXT_END, // End
...
MSG_LIB_TEXT_REQUEST, // Pending request # MSG_LIB_TEXT_REQUEST_DATAS, // Trading request parameters MSG_LIB_TEXT_PEND_REQUEST_DATAS, // Pending trading request parameters
...
MSG_LIB_TEXT_PEND_REQUEST_BY_ERROR, // Pending request generated based on the server return code MSG_LIB_TEXT_PEND_REQUEST_BY_REQUEST, // Pending request created by request MSG_LIB_TEXT_PEND_REQUEST_WAITING_ONSET, // Wait for the first trading attempt MSG_LIB_TEXT_PEND_REQUEST_STATUS, // Pending request status MSG_LIB_TEXT_PEND_REQUEST_STATUS_OPEN, // Pending request to open a position MSG_LIB_TEXT_PEND_REQUEST_STATUS_CLOSE, // Pending request to close a position MSG_LIB_TEXT_PEND_REQUEST_STATUS_SLTP, // Pending request to modify position stop orders MSG_LIB_TEXT_PEND_REQUEST_STATUS_PLACE, // Pending request to place a pending order MSG_LIB_TEXT_PEND_REQUEST_STATUS_REMOVE, // Pending request to delete a pending order MSG_LIB_TEXT_PEND_REQUEST_STATUS_MODIFY, // Pending request to modify pending order parameters };
and the messages corresponding to the new indices:
{" и паузой "," and pause "}, {" уже существует"," already exists"}, {"Создан","Created"}, {"Попыток","Attempts"}, {"Ожидание","Wait"}, {"Окончание","End"},
...
{"Отложенный запрос #","Pending request #"}, {"Параметры торгового запроса","Trade request parameters"}, {"Параметры отложенного торгового запроса","Pending trade request parameters"},
...
{"Отложенный запрос, созданный по коду возврата сервера","Pending request created as a result of server code"}, {"Отложенный запрос, созданный по запросу","Pending request created by request"}, {"Ожидание наступления времени первой торговой попытки","Waiting for onset time of the first trading attempt"}, {"Статус отложенного запроса","Pending request status"}, {"Отложенный запрос на открытие позиции","Pending request to open position"}, {"Отложенный запрос на закрытие позиции","Pending request to close position"}, {"Отложенный запрос на модификацию стоп-приказов позиции","Pending request to modify position stop orders"}, {"Отложенный запрос на установку отложенного ордера","Pending request to place pending order"}, {"Отложенный запрос на удаление отложенного ордера","Pending request to remove pending order"}, {"Отложенный запрос на модификацию параметров отложенного ордера","Pending request to modify pending order parameters"}, };
Como já mencionado acima, o objeto base de uma ordem de negociação pendente é um tipo de ordem abstrata geral que contém as propriedades
inerentes a todas as ordens de negociação, enquanto a especificação das propriedades é atribuída aos objeto-herdeiros do objeto base.
Assim, teremos um objeto-ordem base e seis objetos-herdeiros que especificam as propriedades da ordem pendente de acordo com o tipo de
operação de negociação:
- abertura de posição (nova numa conta 'hedge', adição de volume e reversão numa conta 'netting');
- modificação de stops de uma posição aberta;
- fechamento de posição, isto é, fechamento total e parcial, bem como fechamento com uma ordem oposta (em contas 'hedge');
- colocação de ordem pendente;
- modificação das propriedades da ordem pendente, isto é, os preços de ordens stop, o preço de colocação da ordem, preço da ordem StopLimit, a vida
útil da ordem, o tipo de preenchimento e o tipo de expiração;
- exclusão de ordem pendente colocada anteriormente.
Objeto base de uma ordem de negociação pendente abstrata
Como para todos os objetos de biblioteca anteriores, criaremos enumerações das propriedades do objeto da ordem de negociação pendente.
No arquivo Defines.mqh inserimos enumerações de status, bem como propriedades de objeto inteiras, reais e de string:
//+------------------------------------------------------------------+ //| Data for working with pending trading requests | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Pending request status | //+------------------------------------------------------------------+ enum ENUM_PEND_REQ_STATUS { PEND_REQ_STATUS_OPEN, // Pending request to open a position PEND_REQ_STATUS_CLOSE, // Pending request to close a position PEND_REQ_STATUS_SLTP, // Pending request to modify open position stop orders PEND_REQ_STATUS_PLACE, // Pending request to place a pending order PEND_REQ_STATUS_REMOVE, // Pending request to delete a pending order PEND_REQ_STATUS_MODIFY // Pending request to modify a placed pending order }; //+------------------------------------------------------------------+ //| Pending request type | //+------------------------------------------------------------------+ enum ENUM_PEND_REQ_TYPE { PEND_REQ_TYPE_ERROR=PENDING_REQUEST_ID_TYPE_ERR, // Pending request created based on the return code or error PEND_REQ_TYPE_REQUEST=PENDING_REQUEST_ID_TYPE_REQ, // Pending request created by request }; //+------------------------------------------------------------------+ //| Integer properties of a pending trading request | //+------------------------------------------------------------------+ enum ENUM_PEND_REQ_PROP_INTEGER { PEND_REQ_PROP_STATUS = 0, // Trading request status (from the ENUM_PEND_REQ_STATUS enumeration) PEND_REQ_PROP_TYPE, // Trading request type (from the ENUM_PEND_REQ_TYPE enumeration) PEND_REQ_PROP_ID, // Trading request ID PEND_REQ_PROP_RETCODE, // Result a request is based on PEND_REQ_PROP_TIME_CREATE, // Request creation time PEND_REQ_PROP_TIME_ACTIVATE, // Next attempt activation time PEND_REQ_PROP_WAITING, // Waiting time between requests PEND_REQ_PROP_CURENT, // Current attempt index PEND_REQ_PROP_TOTAL, // Number of attempts //--- MqlTradeRequest PEND_REQ_PROP_MQL_REQ_ACTION, // Type of a performed action in the request structure PEND_REQ_PROP_MQL_REQ_TYPE, // Order type in the request structure PEND_REQ_PROP_MQL_REQ_MAGIC, // EA stamp (magic number ID) in the request structure PEND_REQ_PROP_MQL_REQ_ORDER, // Order ticket in the request structure PEND_REQ_PROP_MQL_REQ_POSITION, // Position ticket in the request structure PEND_REQ_PROP_MQL_REQ_POSITION_BY, // Opposite position ticket in the request structure PEND_REQ_PROP_MQL_REQ_DEVIATION, // Maximum acceptable deviation from a requested price in the request structure PEND_REQ_PROP_MQL_REQ_EXPIRATION, // Order expiration time (for ORDER_TIME_SPECIFIED type orders) in the request structure PEND_REQ_PROP_MQL_REQ_TYPE_FILLING, // Order filling type in the request structure PEND_REQ_PROP_MQL_REQ_TYPE_TIME, // Order lifetime type in the request structure }; #define PEND_REQ_PROP_INTEGER_TOTAL (19) // Total number of integer event properties #define PEND_REQ_PROP_INTEGER_SKIP (0) // Number of request properties not used in sorting //+------------------------------------------------------------------+ //| Real properties of a pending trading request | //+------------------------------------------------------------------+ enum ENUM_PEND_REQ_PROP_DOUBLE { PEND_REQ_PROP_PRICE_CREATE = PEND_REQ_PROP_INTEGER_TOTAL,// Price at the moment of a request generation //--- MqlTradeRequest PEND_REQ_PROP_MQL_REQ_VOLUME, // Requested volume of a deal in lots in the request structure PEND_REQ_PROP_MQL_REQ_PRICE, // Price in the request structure PEND_REQ_PROP_MQL_REQ_STOPLIMIT, // StopLimit level in the request structure PEND_REQ_PROP_MQL_REQ_SL, // Stop Loss level in the request structure PEND_REQ_PROP_MQL_REQ_TP, // Take Profit level in the request structure }; #define PEND_REQ_PROP_DOUBLE_TOTAL (6) // Total number of event's real properties #define PEND_REQ_PROP_DOUBLE_SKIP (0) // Number of order properties not used in sorting //+------------------------------------------------------------------+ //| String properties of a pending trading request | //+------------------------------------------------------------------+ enum ENUM_PEND_REQ_PROP_STRING { //--- MqlTradeRequest PEND_REQ_PROP_MQL_REQ_SYMBOL = (PEND_REQ_PROP_INTEGER_TOTAL+PEND_REQ_PROP_DOUBLE_TOTAL), // Trading instrument name in the request structure PEND_REQ_PROP_MQL_REQ_COMMENT // Order comment in the request structure }; #define PEND_REQ_PROP_STRING_TOTAL (2) // Total number of event's string properties //+------------------------------------------------------------------+
Para calcular a indexação de propriedades nas matrizes de propriedades do objeto, são usadas substituições
de macro indicando a quantidade de cada tipo de propriedade.
Nós já estudamos isso no
primeiro artigo que descreve a criação da biblioteca.
Como pode ser visto na lista, as propriedades do objeto são aquelas que pertencem aos parâmetros de criação da ordem pendente, bem como aquelas
especificadas na estrutura da ordem de negociação MqlTradeRequest,
na qual são registrados todos os parâmetros da solicitação enviada ao servidor.
Como queremos classificar e procurar objetos na lista
de acordo com qualquer um de seus parâmetros (como todos os objetos anteriores da biblioteca), copiamos todo o conteúdo da estrutura da
ordem de negociação nas propriedades correspondentes do objeto, que repetem a finalidade dos campos da estrutura, nesse caso, podemos
pesquisar e classificar solicitações pendentes na lista para qualquer propriedade.
Para pesquisar e classificar objetos-ordens pendentes, listamos todos os critérios possíveis para classificar tais objetos:
//+------------------------------------------------------------------+ //| Possible pending request sorting criteria | //+------------------------------------------------------------------+ #define FIRST_PREQ_DBL_PROP (PEND_REQ_PROP_INTEGER_TOTAL-PEND_REQ_PROP_INTEGER_SKIP) #define FIRST_PREQ_STR_PROP (PEND_REQ_PROP_INTEGER_TOTAL-PEND_REQ_PROP_INTEGER_SKIP+PEND_REQ_PROP_DOUBLE_TOTAL-PEND_REQ_PROP_DOUBLE_SKIP) enum ENUM_SORT_PEND_REQ_MODE { //--- Sort by integer properties SORT_BY_PEND_REQ_STATUS = 0, // Sort by a trading request status (from the ENUM_PEND_REQ_STATUS enumeration) SORT_BY_PEND_REQ_TYPE, // Sort by a trading request type (from the ENUM_PEND_REQ_TYPE enumeration) SORT_BY_PEND_REQ_ID, // Sort by a trading request ID SORT_BY_PEND_REQ_RETCODE, // Sort by a result a request is based on SORT_BY_PEND_REQ_TIME_CREATE, // Sort by a request generation time SORT_BY_PEND_REQ_TIME_ACTIVATE, // Sort by next attempt activation time SORT_BY_PEND_REQ_WAITING, // Sort by a waiting time between requests SORT_BY_PEND_REQ_CURENT, // Sort by the current attempt index SORT_BY_PEND_REQ_TOTAL, // Sort by a number of attempts //--- MqlTradeRequest SORT_BY_PEND_REQ_MQL_REQ_ACTION, // Sort by a type of a performed action in the request structure SORT_BY_PEND_REQ_MQL_REQ_TYPE, // Sort by an order type in the request structure SORT_BY_PEND_REQ_MQL_REQ_MAGIC, // Sort by an EA stamp (magic number ID) in the request structure SORT_BY_PEND_REQ_MQL_REQ_ORDER, // Sort by an order ticket in the request structure SORT_BY_PEND_REQ_MQL_REQ_POSITION, // Sort by a position ticket in the request structure SORT_BY_PEND_REQ_MQL_REQ_POSITION_BY, // Sort by an opposite position ticket in the request structure SORT_BY_PEND_REQ_MQL_REQ_DEVIATION, // Sort by a maximum acceptable deviation from a requested price in the request structure SORT_BY_PEND_REQ_MQL_REQ_EXPIRATION, // Sort by an order expiration time (for ORDER_TIME_SPECIFIED type orders) in the request structure SORT_BY_PEND_REQ_MQL_REQ_TYPE_FILLING, // Sort by an order filling type in the request structure SORT_BY_PEND_REQ_MQL_REQ_TYPE_TIME, // Sort by order lifetime type in the request structure //--- Sort by real properties SORT_BY_PEND_REQ_PRICE_CREATE = FIRST_PREQ_DBL_PROP, // Sort by a price at the moment of a request generation //--- MqlTradeRequest SORT_BY_PEND_REQ_MQL_REQ_VOLUME, // Sort by a requested volume of a deal in lots in the request structure SORT_BY_PEND_REQ_MQL_REQ_PRICE, // Sort by a price in the request structure SORT_BY_PEND_REQ_MQL_REQ_STOPLIMIT, // Sort by StopLimit order level in the request structure SORT_BY_PEND_REQ_MQL_REQ_SL, // Sort by StopLoss order level in the request structure SORT_BY_PEND_REQ_MQL_REQ_TP, // Sort by TakeProfit order level in the request structure //--- Sort by string properties //--- MqlTradeRequest SORT_BY_PEND_REQ_MQL_SYMBOL = FIRST_PREQ_STR_PROP, // Sort by a trading instrument name in the request structure SORT_BY_PEND_REQ_MQL_COMMENT // Sort by an order comment in the request structure }; //+------------------------------------------------------------------+
Agora, num arquivo separado, criamos uma nova classe do objeto base da ordem pendente abstrata.
No diretório da biblioteca \MQL5\Include\DoEasy\Objects\ criamos uma nova subpasta PendRequest\, nela armazenaremos os arquivos das classes das ordens de negociação pendentes.
Na pasta PendRequest, criaremos uma nova classe do objeto base da ordem pendente abstrata no arquivo PendRequest.mqh:
//+------------------------------------------------------------------+ //| PendRequest.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" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include <Object.mqh> #include "..\..\Services\DELib.mqh" //+------------------------------------------------------------------+ //| Abstract pending trading request class | //+------------------------------------------------------------------+ class CPendRequest : public CObject { private: MqlTradeRequest m_request; // Trade request structure //--- Copy trading request data void CopyRequest(const MqlTradeRequest &request); //--- Return the index of the array the request (1) double and (2) string properties are actually located at int IndexProp(ENUM_PEND_REQ_PROP_DOUBLE property)const { return(int)property-PEND_REQ_PROP_INTEGER_TOTAL; } int IndexProp(ENUM_PEND_REQ_PROP_STRING property)const { return(int)property-PEND_REQ_PROP_INTEGER_TOTAL-PEND_REQ_PROP_DOUBLE_TOTAL; } protected: int m_digits; // Number of decimal places in a quote int m_digits_lot; // Number of decimal places in the symbol lot value bool m_is_hedge; // Hedging account flag long m_long_prop[PEND_REQ_PROP_INTEGER_TOTAL]; // Request integer properties double m_double_prop[PEND_REQ_PROP_DOUBLE_TOTAL]; // Request real properties string m_string_prop[PEND_REQ_PROP_STRING_TOTAL]; // Request string properties //--- Protected parametric constructor CPendRequest(const ENUM_PEND_REQ_STATUS status, const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode); //--- Return (1) the magic number specified in the settings, (2) hedging account flag ushort GetMagicID(void) const { return ushort(this.GetProperty(PEND_REQ_PROP_MQL_REQ_MAGIC) & 0xFFFF);} bool IsHedge(void) const { return this.m_is_hedge; } public: //--- Default constructor CPendRequest(){;} //--- Set request (1) integer, (2) real and (3) string properties void SetProperty(ENUM_PEND_REQ_PROP_INTEGER property,long value) { this.m_long_prop[property]=value; } void SetProperty(ENUM_PEND_REQ_PROP_DOUBLE property,double value){ this.m_double_prop[this.IndexProp(property)]=value; } void SetProperty(ENUM_PEND_REQ_PROP_STRING property,string value){ this.m_string_prop[this.IndexProp(property)]=value; } //--- Return (1) integer, (2) real and (3) string request properties from the properties array long GetProperty(ENUM_PEND_REQ_PROP_INTEGER property) const { return this.m_long_prop[property]; } double GetProperty(ENUM_PEND_REQ_PROP_DOUBLE property) const { return this.m_double_prop[this.IndexProp(property)]; } string GetProperty(ENUM_PEND_REQ_PROP_STRING property) const { return this.m_string_prop[this.IndexProp(property)]; } //--- Return the flag of the request supporting the property virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { return true; } virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { return true; } virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //--- Compare CPendRequest objects by a specified property (to sort the lists by a specified request object property) virtual int Compare(const CObject *node,const int mode=0) const; //--- Compare CPendRequest objects by all properties (to search for equal request objects) bool IsEqual(CPendRequest* compared_obj); //+------------------------------------------------------------------+ //| Methods of a simplified access to the request object properties | //+------------------------------------------------------------------+ //--- Return (1) request structure, (2) status, (3) type, (4) price at the moment of the request generation, //--- (5) request generation time, (6) next attempt activation time, //--- (7) waiting time between requests, (8) current attempt index, //--- (9) number of attempts, (10) request ID //--- (11) result a request is based on, //--- (12) order ticket, (13) position ticket, (14) trading operation type MqlTradeRequest MqlRequest(void) const { return this.m_request; } ENUM_PEND_REQ_STATUS Status(void) const { return (ENUM_PEND_REQ_STATUS)this.GetProperty(PEND_REQ_PROP_STATUS); } ENUM_PEND_REQ_TYPE TypeRequest(void) const { return (ENUM_PEND_REQ_TYPE)this.GetProperty(PEND_REQ_PROP_TYPE); } double PriceCreate(void) const { return this.GetProperty(PEND_REQ_PROP_PRICE_CREATE); } ulong TimeCreate(void) const { return this.GetProperty(PEND_REQ_PROP_TIME_CREATE); } ulong TimeActivate(void) const { return this.GetProperty(PEND_REQ_PROP_TIME_ACTIVATE); } ulong WaitingMSC(void) const { return this.GetProperty(PEND_REQ_PROP_WAITING); } uchar CurrentAttempt(void) const { return (uchar)this.GetProperty(PEND_REQ_PROP_CURENT); } uchar TotalAttempts(void) const { return (uchar)this.GetProperty(PEND_REQ_PROP_TOTAL); } uchar ID(void) const { return (uchar)this.GetProperty(PEND_REQ_PROP_ID); } int Retcode(void) const { return (int)this.GetProperty(PEND_REQ_PROP_RETCODE); } ulong Order(void) const { return this.GetProperty(PEND_REQ_PROP_MQL_REQ_ORDER); } ulong Position(void) const { return this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION); } ENUM_TRADE_REQUEST_ACTIONS Action(void) const { return (ENUM_TRADE_REQUEST_ACTIONS)this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION);} //--- 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.SetProperty(PEND_REQ_PROP_PRICE_CREATE,price); } void SetTimeCreate(const ulong time) { this.SetProperty(PEND_REQ_PROP_TIME_CREATE,time); } void SetTimeActivate(const ulong time) { this.SetProperty(PEND_REQ_PROP_TIME_ACTIVATE,time); } void SetWaitingMSC(const ulong miliseconds) { this.SetProperty(PEND_REQ_PROP_WAITING,miliseconds); } void SetCurrentAttempt(const uchar number) { this.SetProperty(PEND_REQ_PROP_CURENT,number); } void SetTotalAttempts(const uchar number) { this.SetProperty(PEND_REQ_PROP_TOTAL,number); } void SetID(const uchar id) { this.SetProperty(PEND_REQ_PROP_ID,id); } void SetOrder(const ulong ticket) { this.SetProperty(PEND_REQ_PROP_MQL_REQ_ORDER,ticket); } void SetPosition(const ulong ticket) { this.SetProperty(PEND_REQ_PROP_MQL_REQ_POSITION,ticket); } //+------------------------------------------------------------------+ //| Descriptions of request object properties | //+------------------------------------------------------------------+ //--- Get description of a request (1) integer, (2) real and (3) string property string GetPropertyDescription(ENUM_PEND_REQ_PROP_INTEGER property); string GetPropertyDescription(ENUM_PEND_REQ_PROP_DOUBLE property); string GetPropertyDescription(ENUM_PEND_REQ_PROP_STRING property); //--- Return the names of pending request object parameters string StatusDescription(void) const; string TypeRequestDescription(void) const; string IDDescription(void) const; string RetcodeDescription(void) const; string TimeCreateDescription(void) const; string TimeActivateDescription(void) const; string TimeWaitingDescription(void) const; string CurrentAttemptDescription(void) const; string TotalAttemptsDescription(void) const; string PriceCreateDescription(void) const; //--- Return the names of trading request structures parameters in the request object string MqlReqActionDescription(void) const; string MqlReqMagicDescription(void) const; string MqlReqOrderDescription(void) const; string MqlReqSymbolDescription(void) const; string MqlReqVolumeDescription(void) const; string MqlReqPriceDescription(void) const; string MqlReqStopLimitDescription(void) const; string MqlReqStopLossDescription(void) const; string MqlReqTakeProfitDescription(void) const; string MqlReqDeviationDescription(void) const; string MqlReqTypeOrderDescription(void) const; string MqlReqTypeFillingDescription(void) const; string MqlReqTypeTimeDescription(void) const; string MqlReqExpirationDescription(void) const; string MqlReqCommentDescription(void) const; string MqlReqPositionDescription(void) const; string MqlReqPositionByDescription(void) const; //--- Display (1) description of request properties (full_prop=true - all properties, false - only supported ones), //--- (2) short event message (implementation in the class descendants) in the journal void Print(const bool full_prop=false); virtual void PrintShort(void){;} }; //+------------------------------------------------------------------+
Já criamos objetos idênticos muitas vezes com uma descrição detalhada de suas estruturas. Penso que aqui não vamos nos debruçar sobre os princípios da estrutura do objeto, pois, nela, como em outros similares, existem três matrizes para armazenar propriedades inteiras, reais e de string. Além disso, existem métodos para acessar essas propriedades, especificando a constante da propriedade como GetProperty(), e há métodos simplificados que têm um nome "falante". Também existem métodos que exibem descrições de todas as propriedades do objeto. Em geral, tudo é padrão para objetos de biblioteca. No primeiro artigo podemos ler novamente sobre a estrutura dos objetos de biblioteca.
Fora do corpo da classe, escrevemos um construtor de classe privado:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CPendRequest::CPendRequest(const ENUM_PEND_REQ_STATUS status, const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) { this.CopyRequest(request); this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif; this.m_digits=(int)::SymbolInfoInteger(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL),SYMBOL_DIGITS); int dg=(int)DigitsLots(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)); this.m_digits_lot=(dg==0 ? 1 : dg); this.SetProperty(PEND_REQ_PROP_STATUS,status); this.SetProperty(PEND_REQ_PROP_ID,id); this.SetProperty(PEND_REQ_PROP_RETCODE,retcode); this.SetProperty(PEND_REQ_PROP_TYPE,this.GetProperty(PEND_REQ_PROP_RETCODE)>0 ? PEND_REQ_TYPE_ERROR : PEND_REQ_TYPE_REQUEST); this.SetProperty(PEND_REQ_PROP_TIME_CREATE,time); this.SetProperty(PEND_REQ_PROP_PRICE_CREATE,price); } //+------------------------------------------------------------------+
Bem, o que temos aqui:
Primeiro, copiamos os dados da estrutura da
ordem de negociação para matrizes de propriedades inteiras, reais e de string usando o método CopyRequest(), que discutiremos
abaixo.
Em seguida, definimos o sinalizador da conta de tipo 'hedge', definimos o
número de casas decimais na cotação do símbolo e no valor do lote do símbolo (isso é necessário para a exibição correta das
informações no log). Além disso, se no valor do lote o número de casas decimais for zero, o resultado será uma casa decimal. Assim, o valor do
lote será mais claro: em vez de "1", será exibido "1,0".
Logo, simplesmente configuramos os valores transferidos de algumas
propriedades ao construtor da classe quando criado o objeto da ordem com os valores das propriedades do objeto correspondentes.
Assim, preenchemos todas as propriedades do objeto-ordem pendente imediatamente após sua criação.
Método para comparar dois objetos-ordens de negociação de acordo com a propriedade especificada (mode):
//+------------------------------------------------------------------+ //| Compare CPendRequest objects by a specified property | //+------------------------------------------------------------------+ int CPendRequest::Compare(const CObject *node,const int mode=0) const { const CPendRequest *compared_obj=node; //--- compare integer properties of two events if(mode<PEND_REQ_PROP_INTEGER_TOTAL) { long value_compared=compared_obj.GetProperty((ENUM_PEND_REQ_PROP_INTEGER)mode); long value_current=this.GetProperty((ENUM_PEND_REQ_PROP_INTEGER)mode); return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0); } //--- compare integer properties of two objects if(mode<PEND_REQ_PROP_DOUBLE_TOTAL+PEND_REQ_PROP_INTEGER_TOTAL) { double value_compared=compared_obj.GetProperty((ENUM_PEND_REQ_PROP_DOUBLE)mode); double value_current=this.GetProperty((ENUM_PEND_REQ_PROP_DOUBLE)mode); return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0); } //--- compare string properties of two objects else if(mode<PEND_REQ_PROP_DOUBLE_TOTAL+PEND_REQ_PROP_INTEGER_TOTAL+PEND_REQ_PROP_STRING_TOTAL) { string value_compared=compared_obj.GetProperty((ENUM_PEND_REQ_PROP_STRING)mode); string value_current=this.GetProperty((ENUM_PEND_REQ_PROP_STRING)mode); return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0); } return 0; } //+------------------------------------------------------------------+
Método para comparar completamente dois objetos-ordens pendentes de acordo com todas as suas propriedades:
//+------------------------------------------------------------------+ //| Compare CPendRequest objects by all properties | //+------------------------------------------------------------------+ bool CPendRequest::IsEqual(CPendRequest *compared_obj) { int beg=0, end=PEND_REQ_PROP_INTEGER_TOTAL; for(int i=beg; i<end; i++) { ENUM_PEND_REQ_PROP_INTEGER prop=(ENUM_PEND_REQ_PROP_INTEGER)i; if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; } beg=end; end+=PEND_REQ_PROP_DOUBLE_TOTAL; for(int i=beg; i<end; i++) { ENUM_PEND_REQ_PROP_DOUBLE prop=(ENUM_PEND_REQ_PROP_DOUBLE)i; if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; } beg=end; end+=PEND_REQ_PROP_STRING_TOTAL; for(int i=beg; i<end; i++) { ENUM_PEND_REQ_PROP_STRING prop=(ENUM_PEND_REQ_PROP_STRING)i; if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; } //--- All properties are equal return true; } //+------------------------------------------------------------------+
Esses métodos também foram abordados mais de uma vez durante a criação de objetos de biblioteca anteriores.
Repito apenas que o método virtual Compare() do objeto-solicitação (que serve para comparar com base na propriedade
especificada) compara as propriedades especificadas do objeto atual da classe CPendRequest e o objeto da mesma classe transferido ao
método. Se o valor do objeto atual for maior que o valor do objeto comparado, o método retornará 1, se for menor, retornará -1, caso contrário,
0. Isso é necessário para trabalhar com listas de ponteiros para objetos, pois, com seu método Searsh(),
que para comparação rápida, usa o método virtual Compare()
do objeto base da biblioteca padrão. Como o método é virtual, ele deve ser redefinido nos descendentes da classe CObject, já fizemos isso
aqui.
Já o método IsEqual() compara alternadamente cada propriedade de dois objetos comparados, e se algum objeto não for
igual, retornará false. Concluídos três ciclos por todas as propriedades dos dois
objetos comparados, será retornado true , indicando que todas as propriedades dos
objetos são iguais.
Método para copiar a estrutura de uma ordem de negociação nas matrizes de propriedades de um objeto de ordem pendente:
//+------------------------------------------------------------------+ //| Copy trading request data | //+------------------------------------------------------------------+ void CPendRequest::CopyRequest(const MqlTradeRequest &request) { //--- Copy a passed structure to an object structure this.m_request=request; //--- Integer properties of a trading request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_ACTION,request.action); // Type of a performed action in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_TYPE,request.type); // Order type in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_MAGIC,request.magic); // EA stamp (magic number ID) in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_ORDER,request.order); // Order ticket in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_POSITION,request.position); // Position ticket in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_POSITION_BY,request.position_by); // Opposite position ticket in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_DEVIATION,request.deviation); // Maximum acceptable deviation from a requested price in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_EXPIRATION,request.expiration); // Order expiration time (for ORDER_TIME_SPECIFIED type orders) in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_TYPE_FILLING,request.type_filling); // Order filling type in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_TYPE_TIME,request.type_time); // Order lifetime type in the request structure //--- Real properties of a trading request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME,request.volume); // Requested volume of a deal in lots in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_PRICE,request.price); // Price in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT,request.stoplimit); // StopLimit level in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_SL,request.sl); // Stop Loss level in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_TP,request.tp); // Take Profit level in the request structure //--- String properties of a trading request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL,request.symbol); // Trading instrument name in the request structure this.SetProperty(PEND_REQ_PROP_MQL_REQ_COMMENT,request.comment); // Order comment in the request structure } //+------------------------------------------------------------------+
Neste caso, primeiro copiamos os valores de todos os campos transferidos para o
método da estrutura da ordem de negociação na mesma estrutura do
objeto-ordem, e, em seguida, definimos os valores de todos os campos da estrutura para as propriedades do objeto usando os métodos de
configuração de propriedades SetProperty().
Métodos que retornam descrições de propriedades inteiras, reais e de string do objeto-ordem pendente:
//+------------------------------------------------------------------+ //| Return the description of the request integer property | //+------------------------------------------------------------------+ string CPendRequest::GetPropertyDescription(ENUM_PEND_REQ_PROP_INTEGER property) { return ( property==PEND_REQ_PROP_STATUS ? this.StatusDescription() : property==PEND_REQ_PROP_TYPE ? this.TypeRequestDescription() : property==PEND_REQ_PROP_ID ? this.IDDescription() : property==PEND_REQ_PROP_RETCODE ? this.RetcodeDescription() : property==PEND_REQ_PROP_TIME_CREATE ? this.TimeCreateDescription() : property==PEND_REQ_PROP_TIME_ACTIVATE ? this.TimeActivateDescription() : property==PEND_REQ_PROP_WAITING ? this.TimeWaitingDescription() : property==PEND_REQ_PROP_CURENT ? this.CurrentAttemptDescription() : property==PEND_REQ_PROP_TOTAL ? this.TotalAttemptsDescription() : //--- MqlTradeRequest property==PEND_REQ_PROP_MQL_REQ_ACTION ? this.MqlReqActionDescription() : property==PEND_REQ_PROP_MQL_REQ_TYPE ? this.MqlReqTypeOrderDescription() : property==PEND_REQ_PROP_MQL_REQ_MAGIC ? this.MqlReqMagicDescription() : property==PEND_REQ_PROP_MQL_REQ_ORDER ? this.MqlReqOrderDescription() : property==PEND_REQ_PROP_MQL_REQ_POSITION ? this.MqlReqPositionDescription() : property==PEND_REQ_PROP_MQL_REQ_POSITION_BY ? this.MqlReqPositionByDescription() : property==PEND_REQ_PROP_MQL_REQ_DEVIATION ? this.MqlReqDeviationDescription() : property==PEND_REQ_PROP_MQL_REQ_EXPIRATION ? this.MqlReqExpirationDescription() : property==PEND_REQ_PROP_MQL_REQ_TYPE_FILLING ? this.MqlReqTypeFillingDescription() : property==PEND_REQ_PROP_MQL_REQ_TYPE_TIME ? this.MqlReqTypeTimeDescription() : ::EnumToString(property) ); } //+------------------------------------------------------------------+ //| Return the description of the request real property | //+------------------------------------------------------------------+ string CPendRequest::GetPropertyDescription(ENUM_PEND_REQ_PROP_DOUBLE property) { return ( property==PEND_REQ_PROP_PRICE_CREATE ? this.PriceCreateDescription() : //--- MqlTradeRequest property==PEND_REQ_PROP_MQL_REQ_VOLUME ? this.MqlReqVolumeDescription() : property==PEND_REQ_PROP_MQL_REQ_PRICE ? this.MqlReqPriceDescription() : property==PEND_REQ_PROP_MQL_REQ_STOPLIMIT ? this.MqlReqStopLimitDescription() : property==PEND_REQ_PROP_MQL_REQ_SL ? this.MqlReqStopLossDescription() : property==PEND_REQ_PROP_MQL_REQ_TP ? this.MqlReqTakeProfitDescription() : ::EnumToString(property) ); } //+------------------------------------------------------------------+ //| Return the description of the request string property | //+------------------------------------------------------------------+ string CPendRequest::GetPropertyDescription(ENUM_PEND_REQ_PROP_STRING property) { return ( property==PEND_REQ_PROP_MQL_REQ_SYMBOL ? this.MqlReqSymbolDescription() : property==PEND_REQ_PROP_MQL_REQ_COMMENT ? this.MqlReqCommentDescription() : ::EnumToString(property) ); } //+------------------------------------------------------------------+
Ao método é transferida a propriedade, e, dependendo do seu
valor, é retornada sua descrição de string
com a ajuda de métodos que retornam uma descrição desta propriedade:
//+------------------------------------------------------------------+ //| Return the pending request status name | //+------------------------------------------------------------------+ string CPendRequest::StatusDescription(void) const { int code_descr= ( this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_OPEN ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_OPEN : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_CLOSE ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_CLOSE : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_SLTP ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_SLTP : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_PLACE ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_PLACE : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_REMOVE ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_REMOVE : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_MODIFY ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_MODIFY : MSG_EVN_STATUS_UNKNOWN ); return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS)+": "+CMessage::Text(code_descr); } //+------------------------------------------------------------------+ //| Return the pending request type name | //+------------------------------------------------------------------+ string CPendRequest::TypeRequestDescription(void) const { int code_descr= ( this.GetProperty(PEND_REQ_PROP_TYPE)==PEND_REQ_TYPE_ERROR ? MSG_LIB_TEXT_PEND_REQUEST_BY_ERROR : this.GetProperty(PEND_REQ_PROP_TYPE)==PEND_REQ_TYPE_REQUEST ? MSG_LIB_TEXT_PEND_REQUEST_BY_REQUEST : MSG_SYM_MODE_UNKNOWN ); return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TYPE)+": "+CMessage::Text(code_descr); } //+------------------------------------------------------------------+ //| Return the pending request ID description | //+------------------------------------------------------------------+ string CPendRequest::IDDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_ID)+": #"+(string)this.GetProperty(PEND_REQ_PROP_ID); } //+------------------------------------------------------------------+ //| Return the description of an error code a request is based on | //+------------------------------------------------------------------+ string CPendRequest::RetcodeDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_RETCODE)+": "+ CMessage::Text((int)this.GetProperty(PEND_REQ_PROP_RETCODE))+ " ("+(string)this.GetProperty(PEND_REQ_PROP_RETCODE)+")"; } //+------------------------------------------------------------------+ //| Return the description of a pending request creation time | //+------------------------------------------------------------------+ string CPendRequest::TimeCreateDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TIME_CREATE)+": "+::TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); } //+------------------------------------------------------------------+ //| Return the description of a pending request activation time | //+------------------------------------------------------------------+ string CPendRequest::TimeActivateDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TIME_ACTIVATE)+": "+::TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_ACTIVATE)); } //+----------------------------------------------------------------------+ //| Return the description of a time spent waiting for a pending request | //+----------------------------------------------------------------------+ string CPendRequest::TimeWaitingDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_WAITING)+": "+ (string)this.GetProperty(PEND_REQ_PROP_WAITING)+ " ("+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_MINUTES|TIME_SECONDS)+")"; } //+------------------------------------------------------------------+ //| Return the description of the current pending request attempt | //+------------------------------------------------------------------+ string CPendRequest::CurrentAttemptDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_CURRENT_ATTEMPT)+": "+(string)this.GetProperty(PEND_REQ_PROP_CURENT); } //+------------------------------------------------------------------+ //| Return the description of a number of pending request attempts | //+------------------------------------------------------------------+ string CPendRequest::TotalAttemptsDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TOTAL_ATTEMPTS)+": "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); } //+------------------------------------------------------------------+ //| Return the description of a price when creating a request | //+------------------------------------------------------------------+ string CPendRequest::PriceCreateDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_PRICE_CREATE)+": "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_PRICE_CREATE),this.m_digits); } //+------------------------------------------------------------------+ //| Return the executed action type description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqActionDescription(void) const { int code_descr= ( this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION)==TRADE_ACTION_DEAL ? MSG_LIB_TEXT_REQUEST_ACTION_DEAL : this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION)==TRADE_ACTION_PENDING ? MSG_LIB_TEXT_REQUEST_ACTION_PENDING : this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION)==TRADE_ACTION_SLTP ? MSG_LIB_TEXT_REQUEST_ACTION_SLTP : this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION)==TRADE_ACTION_MODIFY ? MSG_LIB_TEXT_REQUEST_ACTION_MODIFY : this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION)==TRADE_ACTION_REMOVE ? MSG_LIB_TEXT_REQUEST_ACTION_REMOVE : this.GetProperty(PEND_REQ_PROP_MQL_REQ_ACTION)==TRADE_ACTION_CLOSE_BY ? MSG_LIB_TEXT_REQUEST_ACTION_CLOSE_BY : MSG_LIB_TEXT_REQUEST_ACTION_UNCNOWN ); return CMessage::Text(MSG_LIB_TEXT_REQUEST_ACTION)+": "+CMessage::Text(code_descr); } //+------------------------------------------------------------------+ //| Return the magic number value description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqMagicDescription(void) const { return CMessage::Text(MSG_ORD_MAGIC)+": "+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_MAGIC)+ (this.GetMagicID()!=this.GetProperty(PEND_REQ_PROP_MQL_REQ_MAGIC) ? " ("+(string)this.GetMagicID()+")" : ""); } //+------------------------------------------------------------------+ //| Return the order ticket value description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqOrderDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_ORDER)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_ORDER)>0 ? "#"+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_ORDER) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Return the request position ticket description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqPositionDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_POSITION)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION)>0 ? (string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Return the request opposite position ticket description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqPositionByDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_POSITION_BY)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION_BY)>0 ? (string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION_BY) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Return the request deviation size description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqDeviationDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_DEVIATION)+": "+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_DEVIATION); } //+------------------------------------------------------------------+ //| Return the request order type description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqTypeOrderDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_TYPE)+": "+OrderTypeDescription((ENUM_ORDER_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE)); } //+------------------------------------------------------------------+ //| Return the request order filling mode description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqTypeFillingDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_TYPE_FILLING)+": "+OrderTypeFillingDescription((ENUM_ORDER_TYPE_FILLING)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE_FILLING)); } //+------------------------------------------------------------------+ //| Return the request order lifetime type description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqTypeTimeDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_TYPE_TIME)+": "+OrderTypeTimeDescription((ENUM_ORDER_TYPE_TIME)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE_TIME)); } //+------------------------------------------------------------------+ //| Return the request order expiration time description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqExpirationDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_EXPIRATION)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_EXPIRATION)>0 ? ::TimeToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_EXPIRATION)) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Return the request volume description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqVolumeDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_VOLUME)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME)>0 ? ::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Return the request price value description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqPriceDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE)>0 ? ::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE),this.m_digits) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Return the request StopLimit order price description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqStopLimitDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_STOPLIMIT)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT)>0 ? ::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT),this.m_digits) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Return the request StopLoss order price description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqStopLossDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL)>0 ? ::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL),this.m_digits) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Return the request TakeProfit order price description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqTakeProfitDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP)>0 ? ::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP),this.m_digits) : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+ //| Return the description of a trading instrument name in a request | //+------------------------------------------------------------------+ string CPendRequest::MqlReqSymbolDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_SYMBOL)+": "+this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL); } //+------------------------------------------------------------------+ //| Return the request order comment description | //+------------------------------------------------------------------+ string CPendRequest::MqlReqCommentDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_REQUEST_COMMENT)+": "+ (this.GetProperty(PEND_REQ_PROP_MQL_REQ_COMMENT)!="" && this.GetProperty(PEND_REQ_PROP_MQL_REQ_COMMENT)!=NULL ? "\""+this.GetProperty(PEND_REQ_PROP_MQL_REQ_COMMENT)+"\"" : CMessage::Text(MSG_LIB_PROP_NOT_SET)); } //+------------------------------------------------------------------+
Nos métodos, é verificado o valor da propriedade transferida, é criada sua descrição de texto e é retornada a linha de texto criada.
O método Print() serve para exibir todas as propriedades do objeto no log:
//+------------------------------------------------------------------+ //| Display the pending request properties in the journal | //+------------------------------------------------------------------+ void CPendRequest::Print(const bool full_prop=false) { int header_code= ( this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_OPEN ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_OPEN : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_CLOSE ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_CLOSE : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_SLTP ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_SLTP : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_PLACE ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_PLACE : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_REMOVE ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_REMOVE : this.GetProperty(PEND_REQ_PROP_STATUS)==PEND_REQ_STATUS_MODIFY ? MSG_LIB_TEXT_PEND_REQUEST_STATUS_MODIFY : WRONG_VALUE ); ::Print("============= \"",CMessage::Text(header_code),"\" ============="); int beg=0, end=PEND_REQ_PROP_INTEGER_TOTAL; for(int i=beg; i<end; i++) { ENUM_PEND_REQ_PROP_INTEGER prop=(ENUM_PEND_REQ_PROP_INTEGER)i; if(!full_prop && !this.SupportProperty(prop)) continue; ::Print(this.GetPropertyDescription(prop)); } ::Print("------"); beg=end; end+=PEND_REQ_PROP_DOUBLE_TOTAL; for(int i=beg; i<end; i++) { ENUM_PEND_REQ_PROP_DOUBLE prop=(ENUM_PEND_REQ_PROP_DOUBLE)i; if(!full_prop && !this.SupportProperty(prop)) continue; ::Print(this.GetPropertyDescription(prop)); } ::Print("------"); beg=end; end+=PEND_REQ_PROP_STRING_TOTAL; for(int i=beg; i<end; i++) { ENUM_PEND_REQ_PROP_STRING prop=(ENUM_PEND_REQ_PROP_STRING)i; if(!full_prop && !this.SupportProperty(prop)) continue; ::Print(this.GetPropertyDescription(prop)); } ::Print("================== ",CMessage::Text(MSG_LIB_PARAMS_LIST_END),": \"",CMessage::Text(header_code),"\" ==================\n"); } //+------------------------------------------------------------------+
Nós criamos tais métodos para todos os objetos anteriores da biblioteca e analisamos sua estrutura desde o início da descrição da
biblioteca, por isso, aqui vamos nos restringir a uma breve descrição dele:
Realizamos três ciclos percorrendo as três matrizes das
propriedades do objeto, obtemos cada propriedade do objeto e exibimos sua descrição no log, dependendo do sinalizador que exibe apenas as
propriedades suportadas do objeto.
O método PrintShort(), projetado para exibir uma descrição breve do objeto-ordem, é feito como virtual. No objeto base, ele não
faz nada, ele deve ser redefinido nos objetos-herdeiros para que cada objeto-herdeiro possa exibir no log exclusivamente suas
propriedades pertencentes apenas a ele.
Criamos o objeto base da ordem pendente abstrata.
Em seguida, para esclarecer qual ordem específica deve ser criada,
precisamos criar seis objetos-herdeiros a partir do objeto-ordem abstrata. Eles serão criados nos métodos de negociação da classe de
negociação ao processar erros que exigem espera. Além disso, eles serão gerados assim como ordens de negociação independentes ao criar a
lógica de negociação com a ajuda de ordens de negociação pendentes.
Objetos-herdeiros do objeto base-ordem pendente
Em cada método de negociação da classe de negociação, temos blocos para criar ordens pendentes. Com base na operação realizada pelo método de negociação, criaremos as ordens pendentes correspondentes. Mas, por enquanto, só temos uma ordem pendente abstrata base. Para, com base nela, criar várias ordens de negociação segundo seu tipo de operação, precisamos criar seis de seus herdeiros, onde cada classe herdada enviará apenas sua própria operação de negociação para o servidor. Anteriormente, já dei uma lista desses objetos:
- abertura de posição
- modificação de stops de uma posição aberta
- fechamento da posição
- colocação de ordem pendente
- modificação/exclusão de uma ordem pendente
- exclusão de ordem pendente colocada anteriormente
Como lembramos, no construtor protegido da ordem pendente abstrata base há um parâmetro que indica o status da ordem criada:
//--- Protected parametric constructor CPendRequest(const ENUM_PEND_REQ_STATUS status, const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode);
Indicaremos este status (transferiremos do construtor do objeto herdado ao construtor do objeto base) ao criar uma nova ordem pendente. Assim,
indicaremos o tipo de ordem estamos criando com base na operação executada. Já analisamos esse comportamento no segundo artigo ao criar
objetos de ordens e transações históricas. Por isso, em vez de falar disso, vamos considerar todos os seis objetos de ordens
pendentes com base no tipo de operação de negociação.
Criaremos todas as classes de objetos-herdeiros da ordem de negociação base na
mesma pasta em que está localizado o objeto base:
\MQL5\Include\DoEasy\Objects\ PendRequest\
Classe de objeto de uma ordem pendente para abrir uma posição (arquivo de classe PendReqOpen.mqh):
//+------------------------------------------------------------------+ //| PendReqOpen.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 "PendRequest.mqh" //+------------------------------------------------------------------+ //| Pending request for opening a position | //+------------------------------------------------------------------+ class CPendReqOpen : public CPendRequest { public: //--- Constructor CPendReqOpen(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_OPEN,id,price,time,request,retcode) {} //--- Supported deal properties (1) real, (2) integer virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property); //--- Display a brief message with request data in the journal virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| inteira; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqOpen::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { if(property==PEND_REQ_PROP_MQL_REQ_ORDER || property==PEND_REQ_PROP_MQL_REQ_POSITION || property==PEND_REQ_PROP_MQL_REQ_POSITION_BY || property==PEND_REQ_PROP_MQL_REQ_EXPIRATION || property==PEND_REQ_PROP_MQL_REQ_TYPE_TIME ) return false; return true; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| real; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqOpen::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { return(property==PEND_REQ_PROP_MQL_REQ_STOPLIMIT ? false : true); } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| string; retorna false caso contrário | //+------------------------------------------------------------------+ bool CPendReqOpen::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Display a brief message with request data in the journal | //+------------------------------------------------------------------+ void CPendReqOpen::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ OrderTypeDescription((ENUM_ORDER_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE)); string price=CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE),this.m_digits); string sl=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL),this.m_digits) : ""; string tp=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP),this.m_digits) : ""; string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_OPEN)+": "+ "\n- "+params+", "+price+sl+tp+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
O método é bastante primitivo. Tudo o que ele faz é, no seu construtor na lista de inicialização, transferir ao construtor do objeto base o status do objeto criado (abertura de posição) e todos os parâmetros de entrada do seu construtor:
//--- Constructor CPendReqOpen(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_OPEN,id,price,time,request,retcode) {}
Métodos virtuais que retornam o sinalizador para suportar o objeto de algumas propriedades inteiras, reais e de string:
//+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| inteira; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqOpen::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { if(property==PEND_REQ_PROP_MQL_REQ_ORDER || property==PEND_REQ_PROP_MQL_REQ_POSITION || property==PEND_REQ_PROP_MQL_REQ_POSITION_BY || property==PEND_REQ_PROP_MQL_REQ_EXPIRATION || property==PEND_REQ_PROP_MQL_REQ_TYPE_TIME ) return false; return true; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| real; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqOpen::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { return(property==PEND_REQ_PROP_MQL_REQ_STOPLIMIT ? false : true); } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| string; retorna false caso contrário | //+------------------------------------------------------------------+ bool CPendReqOpen::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+
Se alguma propriedade não for suportada pelo objeto-herdeiro da ordem de negociação abstrata base, o método retornará false, caso contrário, true. Vamos ver como funciona tudo isso no segundo artigo da descrição da biblioteca ao considerar a criação de objetos de ordens e transações históricas.
Método virtual para criar e exibir uma breve descrição de uma ordem:
//+------------------------------------------------------------------+ //| Display a brief message with request data in the journal | //+------------------------------------------------------------------+ void CPendReqOpen::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ OrderTypeDescription((ENUM_ORDER_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE)); string price=CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE),this.m_digits); string sl=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL),this.m_digits) : ""; string tp=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP),this.m_digits) : ""; string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_OPEN)+": "+ "\n- "+params+", "+price+sl+tp+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
No método, são criadas as linhas de descrição de alguns parâmetros usados pelo objeto e a partir deles é gerada uma mensagem final, que é
exibida no log. O método é virtual é implementado de maneira própria em cada um dos objetos-herdeiros do objeto base da ordem pendente.
Classe de objeto de uma ordem pendente para modificar ordens stop de uma posição aberta (arquivo de classe PendReqSLTP.mqh):
//+------------------------------------------------------------------+ //| PendReqSLTP.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 "PendRequest.mqh" //+------------------------------------------------------------------+ //| Pending request to modify position stop orders | //+------------------------------------------------------------------+ class CPendReqSLTP : public CPendRequest { public: //--- Constructor CPendReqSLTP(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_SLTP,id,price,time,request,retcode) {} //--- Supported deal properties (1) real, (2) integer virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property); //--- Display a brief message with request data in the journal virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| inteira; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqSLTP::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { if(property==PEND_REQ_PROP_MQL_REQ_POSITION_BY || property==PEND_REQ_PROP_MQL_REQ_ORDER || property==PEND_REQ_PROP_MQL_REQ_EXPIRATION || property==PEND_REQ_PROP_MQL_REQ_DEVIATION || property==PEND_REQ_PROP_MQL_REQ_TYPE_FILLING || property==PEND_REQ_PROP_MQL_REQ_TYPE_TIME ) return false; return true; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| real; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqSLTP::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { if(property==PEND_REQ_PROP_PRICE_CREATE || property==PEND_REQ_PROP_MQL_REQ_SL || property==PEND_REQ_PROP_MQL_REQ_TP ) return true; return false; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| string; retorna false caso contrário | //+------------------------------------------------------------------+ bool CPendReqSLTP::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Display a brief message with request data in the journal | //+------------------------------------------------------------------+ void CPendReqSLTP::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ PositionTypeDescription((ENUM_POSITION_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE))+" #"+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION); string sl=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL),this.m_digits) : ""; string tp=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP),this.m_digits) : ""; string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_SLTP)+": "+ "\n- "+params+sl+tp+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
Classe de objeto de uma ordem pendente para fechar uma posição (arquivo de classe PendReqClose.mqh):
//+------------------------------------------------------------------+ //| PendReqClose.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 "PendRequest.mqh" //+------------------------------------------------------------------+ //| Pending request to close a position | //+------------------------------------------------------------------+ class CPendReqClose : public CPendRequest { public: //--- Constructor CPendReqClose(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_CLOSE,id,price,time,request,retcode) {} //--- Supported deal properties (1) real, (2) integer virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property); //--- Display a brief message with request data in the journal virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| inteira; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqClose::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { if(( property==PEND_REQ_PROP_MQL_REQ_POSITION_BY && this.GetProperty(property)==0) || property==PEND_REQ_PROP_MQL_REQ_ORDER || property==PEND_REQ_PROP_MQL_REQ_EXPIRATION || property==PEND_REQ_PROP_MQL_REQ_TYPE_TIME ) return false; return true; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| real; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqClose::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { if(property==PEND_REQ_PROP_MQL_REQ_STOPLIMIT || property==PEND_REQ_PROP_MQL_REQ_SL || property==PEND_REQ_PROP_MQL_REQ_TP ) return false; return true; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| string; retorna false caso contrário | //+------------------------------------------------------------------+ bool CPendReqClose::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Display a brief message with request data in the journal | //+------------------------------------------------------------------+ void CPendReqClose::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ PositionTypeDescription((ENUM_POSITION_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE))+" #"+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION); string pos_by=(this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION_BY)>0 ? ", "+CMessage::Text(MSG_ORD_DEAL_OUT_BY)+" #"+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_POSITION_BY) : ""); string price=CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_PRICE_CREATE),this.m_digits); string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_CLOSE)+": "+ "\n- "+params+", "+price+pos_by+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
Classe de objeto de uma ordem pendente para colocar uma ordem pendente (arquivo de classe PendReqPlace.mqh):
//+------------------------------------------------------------------+ //| PendReqPlace.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 "PendRequest.mqh" //+------------------------------------------------------------------+ //| Pending request to place a pending order | //+------------------------------------------------------------------+ class CPendReqPlace : public CPendRequest { public: //--- Constructor CPendReqPlace(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_PLACE,id,price,time,request,retcode) {} //--- Supported deal properties (1) real, (2) integer virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property); //--- Display a brief message with request data in the journal virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| inteira; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqPlace::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { if(property==PEND_REQ_PROP_MQL_REQ_ORDER || property==PEND_REQ_PROP_MQL_REQ_POSITION || property==PEND_REQ_PROP_MQL_REQ_POSITION_BY || property==PEND_REQ_PROP_MQL_REQ_DEVIATION ) return false; return true; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| real; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqPlace::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { return true; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| string; retorna false caso contrário | //+------------------------------------------------------------------+ bool CPendReqPlace::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Display a brief message with request data in the journal | //+------------------------------------------------------------------+ void CPendReqPlace::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ OrderTypeDescription((ENUM_ORDER_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE)); string price=CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE),this.m_digits); string stoplimit=this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_STOPLIMIT)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT),this.m_digits) : ""; string sl=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL),this.m_digits) : ""; string tp=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP),this.m_digits) : ""; string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_PLACE)+": "+ "\n- "+params+", "+price+stoplimit+sl+tp+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
Classe de objeto de ordem pendente para modificar os parâmetros de uma ordem pendente colocada (arquivo de classe PendReqModify.mqh):
//+------------------------------------------------------------------+ //| PendReqModify.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 "PendRequest.mqh" //+------------------------------------------------------------------+ //| Pending request to modify pending order parameters | //+------------------------------------------------------------------+ class CPendReqModify : public CPendRequest { public: //--- Constructor CPendReqModify(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_MODIFY,id,price,time,request,retcode) {} //--- Supported deal properties (1) real, (2) integer virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property); //--- Display a brief message with request data in the journal virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| inteira; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqModify::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { if(property==PEND_REQ_PROP_MQL_REQ_POSITION || property==PEND_REQ_PROP_MQL_REQ_POSITION_BY || property==PEND_REQ_PROP_MQL_REQ_DEVIATION ) return false; return true; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| real; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqModify::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { return(property==PEND_REQ_PROP_MQL_REQ_VOLUME ? false : true); } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| string; retorna false caso contrário | //+------------------------------------------------------------------+ bool CPendReqModify::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Display a brief message with request data in the journal | //+------------------------------------------------------------------+ void CPendReqModify::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ OrderTypeDescription((ENUM_ORDER_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE))+" #"+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_ORDER); string price=CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE),this.m_digits); string stoplimit=this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_STOPLIMIT)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT),this.m_digits) : ""; string sl=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_SL),this.m_digits) : ""; string tp=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_TP),this.m_digits) : ""; string expiration=this.GetProperty(PEND_REQ_PROP_MQL_REQ_EXPIRATION)>0 ? this.MqlReqExpirationDescription() : ""; string type_filling=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE_FILLING)>WRONG_VALUE ? "\n- "+this.MqlReqTypeFillingDescription() : ""; string type_time=this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE_TIME)>WRONG_VALUE ? "\n- "+this.MqlReqTypeTimeDescription() : ""; string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_MODIFY)+": "+ "\n- "+params+", "+price+stoplimit+sl+tp+expiration+type_filling+type_time+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
Classe de objeto de uma ordem pendente para excluir uma ordem pendente (arquivo de classe PendReqRemove.mqh):
//+------------------------------------------------------------------+ //| PendReqRemove.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 "PendRequest.mqh" //+------------------------------------------------------------------+ //| Pending request to remove a pending order | //+------------------------------------------------------------------+ class CPendReqRemove : public CPendRequest { public: //--- Constructor CPendReqRemove(const uchar id, const double price, const ulong time, const MqlTradeRequest &request, const int retcode) : CPendRequest(PEND_REQ_STATUS_REMOVE,id,price,time,request,retcode) {} //--- Supported deal properties (1) real, (2) integer virtual bool SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_PEND_REQ_PROP_STRING property); //--- Display a brief message with request data in the journal virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| inteira; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqRemove::SupportProperty(ENUM_PEND_REQ_PROP_INTEGER property) { return(property>PEND_REQ_PROP_MQL_REQ_ORDER ? false : true); } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| real; caso contrário, retorna false | //+------------------------------------------------------------------+ bool CPendReqRemove::SupportProperty(ENUM_PEND_REQ_PROP_DOUBLE property) { return(property==PEND_REQ_PROP_PRICE_CREATE || property==PEND_REQ_PROP_MQL_REQ_PRICE ? true : false); } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| string; retorna false caso contrário | //+------------------------------------------------------------------+ bool CPendReqRemove::SupportProperty(ENUM_PEND_REQ_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Display a brief message with request data in the journal | //+------------------------------------------------------------------+ void CPendReqRemove::PrintShort(void) { string params=this.GetProperty(PEND_REQ_PROP_MQL_REQ_SYMBOL)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_VOLUME),this.m_digits_lot)+" "+ OrderTypeDescription((ENUM_ORDER_TYPE)this.GetProperty(PEND_REQ_PROP_MQL_REQ_TYPE))+" #"+(string)this.GetProperty(PEND_REQ_PROP_MQL_REQ_ORDER); string price=CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_PRICE),this.m_digits); string stoplimit=this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT)>0 ? ", "+CMessage::Text(MSG_LIB_TEXT_REQUEST_STOPLIMIT)+" "+::DoubleToString(this.GetProperty(PEND_REQ_PROP_MQL_REQ_STOPLIMIT),this.m_digits) : ""; string time=this.IDDescription()+", "+CMessage::Text(MSG_LIB_TEXT_CREATED)+" "+TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)); string attempts=CMessage::Text(MSG_LIB_TEXT_ATTEMPTS)+" "+(string)this.GetProperty(PEND_REQ_PROP_TOTAL); string wait=CMessage::Text(MSG_LIB_TEXT_WAIT)+" "+::TimeToString(this.GetProperty(PEND_REQ_PROP_WAITING)/1000,TIME_SECONDS); string end=CMessage::Text(MSG_LIB_TEXT_END)+" "+ TimeMSCtoString(this.GetProperty(PEND_REQ_PROP_TIME_CREATE)+this.GetProperty(PEND_REQ_PROP_WAITING)*this.GetProperty(PEND_REQ_PROP_TOTAL)); //--- string message=CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_STATUS_REMOVE)+": "+ "\n- "+params+", "+price+stoplimit+ "\n- "+time+", "+attempts+", "+wait+", "+end+"\n"; ::Print(message); } //+------------------------------------------------------------------+
A característica distintiva mais importante de todas essas classes é a transferência
do status da ordem
pendente para o construtor do objeto pai. É esse status que determina que tipo de operação de negociação realizará
cada um desses objetos. Os métodos de classe restantes servem apenas para fins auxiliares e não afetam o resultado da negociação.
Terminamos aqui a criação de novas de ordens de negociação pendentes.
Agora é preciso remover a classe de ordem pendente
que criamos temporariamente do arquivo da classe de negociação e fazer correções adicionais para trabalhar com novos objetos de ordens de
negociação pendentes.
Abrimos o arquivo Trading.mqh e removemos de sua listagem a classe completamente antiga da ordem pendente:
//+------------------------------------------------------------------+ //| 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" //+-----------------------------------------------------------------+ //| 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; } //--- 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;} //--- Return the description of the (1) request structure, (2) the price at the moment of the request generation, //--- (3) request generation time, (4) current attempt time, //--- (5) waiting time between requests, (6) current attempt index, //--- (7) number of attempts, (8) request ID string MqlRequestDescription(void) const { return RequestActionDescription(this.m_request); } string TypeDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TYPE) + (this.Type()==PENDING_REQUEST_ID_TYPE_ERR ? CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_BY_ERROR) : CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_BY_REQUEST) ); } string PriceCreateDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_PRICE_CREATE)+": "+ ::DoubleToString(this.PriceCreate(),(int)::SymbolInfoInteger(this.m_request.symbol,SYMBOL_DIGITS)); } string TimeCreateDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TIME_CREATE)+TimeMSCtoString(this.TimeCreate()); } string TimeActivateDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TIME_ACTIVATE)+TimeMSCtoString(this.TimeActivate());} string WaitingMSCDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_WAITING)+(string)this.WaitingMSC(); } string CurrentAttemptDescription(void) const { return (CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_CURRENT_ATTEMPT)+ (this.CurrentAttempt()==0 ? CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_WAITING_ONSET) : (string)this.CurrentAttempt()) ); } string TotalAttemptsDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_TOTAL_ATTEMPTS)+(string)this.TotalAttempts(); } string IdDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_ID)+"#"+(string)this.ID(); } string RetcodeDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_RETCODE)+(string)this.Retcode(); } string ReasonDescription(void) const { return CMessage::Text(this.m_retcode); } //--- Return a request type virtual int Type(void) const { return this.m_type; } //--- Display request data in the journal void Print(void); //--- Constructors CPendingReq(void){;} CPendingReq(const uchar id,const double price,const ulong time,const MqlTradeRequest &request,const int retcode); }; //+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CPendingReq::CPendingReq(const uchar id,const double price,const ulong time,const MqlTradeRequest &request,const int retcode) : m_price_create(price), m_time_create(time), m_id(id), m_retcode(retcode) { this.CopyRequest(request); this.m_type=(retcode>0 ? PENDING_REQUEST_ID_TYPE_ERR : PENDING_REQUEST_ID_TYPE_REQ); } //+------------------------------------------------------------------+ //| 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 ) ); } //+------------------------------------------------------------------+ //| Display request data in the journal | //+------------------------------------------------------------------+ void CPendingReq::Print(void) { string action=" - "+RequestActionDescription(this.m_request)+"\n"; string symbol="",order="",volume="",price="",stoplimit="",sl="",tp="",deviation="",type="",type_filling=""; string type_time="",expiration="",position="",position_by="",magic="",comment="",request_data=""; string type_req=" - "+this.TypeDescription()+"\n"; if(this.m_request.action==TRADE_ACTION_DEAL) { symbol=" - "+RequestSymbolDescription(this.m_request)+"\n"; volume=" - "+RequestVolumeDescription(this.m_request)+"\n"; price=" - "+RequestPriceDescription(this.m_request)+"\n"; sl=" - "+RequestStopLossDescription(this.m_request)+"\n"; tp=" - "+RequestTakeProfitDescription(this.m_request)+"\n"; deviation=" - "+RequestDeviationDescription(this.m_request)+"\n"; type=" - "+RequestTypeDescription(this.m_request)+"\n"; type_filling=" - "+RequestTypeFillingDescription(this.m_request)+"\n"; magic=" - "+RequestMagicDescription(this.m_request)+"\n"; comment=" - "+RequestCommentDescription(this.m_request)+"\n"; request_data= ("================== "+ CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)+" ==================\n"+ action+symbol+volume+price+sl+tp+deviation+type+type_filling+magic+comment+ " ==================\n" ); } else if(this.m_request.action==TRADE_ACTION_SLTP) { symbol=" - "+RequestSymbolDescription(this.m_request)+"\n"; sl=" - "+RequestStopLossDescription(this.m_request)+"\n"; tp=" - "+RequestTakeProfitDescription(this.m_request)+"\n"; position=" - "+RequestPositionDescription(this.m_request)+"\n"; request_data= ("================== "+ CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)+" ==================\n"+ action+symbol+sl+tp+position+ " ==================\n" ); } else if(this.m_request.action==TRADE_ACTION_PENDING) { symbol=" - "+RequestSymbolDescription(this.m_request)+"\n"; volume=" - "+RequestVolumeDescription(this.m_request)+"\n"; price=" - "+RequestPriceDescription(this.m_request)+"\n"; stoplimit=" - "+RequestStopLimitDescription(this.m_request)+"\n"; sl=" - "+RequestStopLossDescription(this.m_request)+"\n"; tp=" - "+RequestTakeProfitDescription(this.m_request)+"\n"; type=" - "+RequestTypeDescription(this.m_request)+"\n"; type_filling=" - "+RequestTypeFillingDescription(this.m_request)+"\n"; type_time=" - "+RequestTypeTimeDescription(this.m_request)+"\n"; expiration=" - "+RequestExpirationDescription(this.m_request)+"\n"; magic=" - "+RequestMagicDescription(this.m_request)+"\n"; comment=" - "+RequestCommentDescription(this.m_request)+"\n"; request_data= ("================== "+ CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)+" ==================\n"+ action+symbol+volume+price+stoplimit+sl+tp+type+type_filling+type_time+expiration+magic+comment+ " ==================\n" ); } else if(this.m_request.action==TRADE_ACTION_MODIFY) { order=" - "+RequestOrderDescription(this.m_request)+"\n"; price=" - "+RequestPriceDescription(this.m_request)+"\n"; sl=" - "+RequestStopLossDescription(this.m_request)+"\n"; tp=" - "+RequestTakeProfitDescription(this.m_request)+"\n"; type_time=" - "+RequestTypeTimeDescription(this.m_request)+"\n"; expiration=" - "+RequestExpirationDescription(this.m_request)+"\n"; request_data= ("================== "+ CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)+" ==================\n"+ action+order+price+sl+tp+type_time+expiration+ " ==================\n" ); } else if(this.m_request.action==TRADE_ACTION_REMOVE) { order=" - "+RequestOrderDescription(this.m_request)+"\n"; request_data= ("================== "+ CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)+" ==================\n"+ action+order+ " ==================\n" ); } else if(this.m_request.action==TRADE_ACTION_CLOSE_BY) { position=" - "+RequestPositionDescription(this.m_request)+"\n"; position_by=" - "+RequestPositionByDescription(this.m_request)+"\n"; magic=" - "+RequestMagicDescription(this.m_request)+"\n"; request_data= ("================== "+ CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)+" ==================\n"+ action+position+position_by+magic+ " ==================\n" ); } string datas= ( " - "+this.TypeDescription()+"\n"+ " - "+this.IdDescription()+"\n"+ " - "+this.RetcodeDescription()+" \""+this.ReasonDescription()+"\"\n"+ " - "+this.TimeCreateDescription()+"\n"+ " - "+this.PriceCreateDescription()+"\n"+ " - "+this.TimeActivateDescription()+"\n"+ " - "+this.WaitingMSCDescription()+" ("+TimeToString(this.WaitingMSC()/1000,TIME_MINUTES|TIME_SECONDS)+")"+"\n"+ " - "+this.CurrentAttemptDescription()+"\n"+ " - "+this.TotalAttemptsDescription()+"\n" ); ::Print("================== ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_DATAS)," ==================\n",datas,request_data); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Trading class | //+------------------------------------------------------------------+ class CTrading {
Para que a classe de negociação veja objetos das novas classes de ordens pendentes, vamos anexá-los
à listagem do arquivo da classe de negociação:
//+------------------------------------------------------------------+ //| 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 "Objects\PendRequest\PendReqOpen.mqh" #include "Objects\PendRequest\PendReqSLTP.mqh" #include "Objects\PendRequest\PendReqClose.mqh" #include "Objects\PendRequest\PendReqPlace.mqh" #include "Objects\PendRequest\PendReqModify.mqh" #include "Objects\PendRequest\PendReqRemove.mqh" #include "Collections\AccountsCollection.mqh" #include "Collections\SymbolsCollection.mqh" #include "Collections\MarketCollection.mqh" #include "Collections\HistoryCollection.mqh" #include "Collections\EventsCollection.mqh" //+------------------------------------------------------------------+
Agora, ao método de criação de uma nova ordem pendente transferimos adicionalmente o status da ordem de negociação criada.
Inserimos o status
na declaração do método:
//--- Create a pending request bool CreatePendingRequest(const ENUM_PEND_REQ_STATUS status, const uchar id, const uchar attempts, const ulong wait, const MqlTradeRequest &request, const int retcode, CSymbol *symbol_obj);
Ajustamos a implementação do método para criar uma nova ordem pendente:
//+------------------------------------------------------------------+ //| Create a pending request | //+------------------------------------------------------------------+ bool CTrading::CreatePendingRequest(const ENUM_PEND_REQ_STATUS status, const uchar id, const uchar attempts, const ulong wait, const MqlTradeRequest &request, const int retcode, CSymbol *symbol_obj) { //--- Create a new pending request object depending on a request status CPendRequest *req_obj=NULL; switch(status) { case PEND_REQ_STATUS_OPEN : req_obj=new CPendReqOpen(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode); break; case PEND_REQ_STATUS_CLOSE : req_obj=new CPendReqClose(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode); break; case PEND_REQ_STATUS_SLTP : req_obj=new CPendReqSLTP(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode); break; case PEND_REQ_STATUS_PLACE : req_obj=new CPendReqPlace(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode); break; case PEND_REQ_STATUS_REMOVE : req_obj=new CPendReqRemove(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode); break; case PEND_REQ_STATUS_MODIFY : req_obj=new CPendReqModify(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode); break; default: req_obj=NULL; break; } if(req_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_FAILING_CREATE_PENDING_REQ)); return false; } //--- If failed to add the request to the list, display the appropriate message, //--- remove the created object and return 'false' if(!this.m_list_request.Add(req_obj)) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_FAILING_CREATE_PENDING_REQ)); delete req_obj; return false; } //--- Filled in the fields of a successfully created object by the values passed to the method req_obj.SetTimeActivate(symbol_obj.Time()+wait); req_obj.SetWaitingMSC(wait); req_obj.SetCurrentAttempt(0); req_obj.SetTotalAttempts(attempts); //--- Display a brief description of a created pending request if(this.m_log_level>LOG_LEVEL_NO_MSG) { ::Print(CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_CREATED)," #",req_obj.ID(),":"); req_obj.PrintShort(); } //--- successful return true; } //+------------------------------------------------------------------+
Agora ao método adicionalmente é transferido o status do
objeto de ordem pendente a ser criado.
Anteriormente, nosso objeto de ordem pendente tinha o tipo de classe CPendingReq. Agora,
excluímos completamente esta classe e agora ficamos com uma nova classe de objeto de ordem pendente CPendRequest e seus herdeiros.
Por isso, neste caso, ao criar um objeto vazio, usamos o novo objeto de ordem abstrata base CPendRequest.
Em seguida, dependendo do status transferido ao método, criamos o novo objeto de ordem
pendente correspondente a ele.
Após a criação bem-sucedida do objeto, no
logo é exibida uma pequena mensagem contendo os parâmetros da ordem de negociação pendente criada.
Como agora temos um novo objeto da classe de ordem pendente, na listagem da classe de negociação substituiremos todas as ocorrências da classe CPendingReq anterior por CPendRequest. Isso é simples de fazer usando "search by" e Ctrl+H.
Durante a criação de novos objetos de ordens pendentes, aos eles transferiremos um pouco mais de informações sobre a operação de negociação a ser realizada. Basicamente, isso é necessário para exibição correta no log. Transferiremos escrevendo dados adicionais na estrutura da ordem de negociação ao criar um novo objeto de ordem pendente.
No método de abertura de posição no bloco para criar uma ordem pendente indicamos o status da ordem criada:
//--- 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(PEND_REQ_STATUS_OPEN,(uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; }
No método de modificação de ordens stop de uma posição aberta no
bloco para criar uma solicitação pendente
adicionamos a transferência
através da estrutura ao objeto-ordem do tipo de solicitação, o volume
da posição, e especificamos o status da ordem a ser criada:
//--- 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; this.m_request.type=order_type; this.m_request.volume=order.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(PEND_REQ_STATUS_SLTP,(uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; }
No método de fechamento de posição ao seu bloco de criação de ordem
pendente
adicionamos a transferência
através da estrutura ao objeto-ordem
do tipo de ordem, o volume da posição, e especificamos
o status da ordem a ser criada:
//--- 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==WRONG_VALUE || volume>order.Volume() ? order.Volume() : volume); 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(PEND_REQ_STATUS_CLOSE,(uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false;
O volume da posição pode ser especificado no método como negativo (-1), o que
indica o completo fechamento da posição, ou pode ser especificado com um valor, o que indica o fechamento parcial da posição. Tudo isso é
processado no objeto de negociação base do símbolo ao enviar uma ordem de negociação para o servidor.
Aqui, verificamos imediatamente
o valor do volume transferido ao método e configuramos o volume necessário na estrutura da ordem de negociação.
No método de fechamento da posição com a ajuda de uma posição oposta no
seu bloco de criação de ordem pendente
adicionamos a
transferência
através da estrutura ao objeto-ordem
do tipo de ordem, o volume da posição, e especificamos
o status da ordem a ser criada:
//--- 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; this.m_request.type=order_type; this.m_request.volume=order.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(PEND_REQ_STATUS_CLOSE,(uchar)id,attempts,wait,this.m_request,trade_obj_pos.GetResultRetcode(),symbol_obj); } return false; }
No método de definição de ordem pendente no bloco para criar uma ordem pendente indicamos o status da ordem criada:
//--- 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(PEND_REQ_STATUS_PLACE,(uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; }
No método de modificação de parâmetros da ordem pendente no bloco
para criar uma ordem pendente
adicionamos
a transferência
através da estrutura ao objeto-ordem
do tipo de ordem, e especificamos o status da ordem a ser criada:
//--- 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; 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(PEND_REQ_STATUS_MODIFY,(uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; }
No método de exclusão da ordem pendente no bloco para criar uma ordem
pendente
adicionamos a transferência
através da estrutura ao objeto-ordem
do tipo , o volume da ordem, o seu preço
de posicionamento, e especificamos o status da ordem a ser criada:
//--- 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; this.m_request.type=order_type; this.m_request.volume=order.Volume(); this.m_request.price=order.PriceOpen(); //--- 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(PEND_REQ_STATUS_REMOVE,(uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; }
Temos dois desses blocos em cada método de negociação. Por isso, precisamos fazer alterações em cada um deles.
Nos métodos para localizar um identificador livre e retornar índices de objetos-ordens especificamos
os tipos de classificação:
//+------------------------------------------------------------------+ //| Look for the first free pending request ID | //+------------------------------------------------------------------+ int CTrading::GetFreeID(void) { int id=WRONG_VALUE; CPendRequest *element=new CPendRequest(); if(element==NULL) return 0; for(int i=1;i<256;i++) { element.SetID((uchar)i); this.m_list_request.Sort(SORT_BY_PEND_REQ_ID); if(this.m_list_request.Search(element)==WRONG_VALUE) { id=i; break; } } delete element; return id; } //+------------------------------------------------------------------+ //| Return the request object index in the list by ID | //+------------------------------------------------------------------+ int CTrading::GetIndexPendingRequestByID(const uchar id) { CPendRequest *req=new CPendRequest(); if(req==NULL) return WRONG_VALUE; req.SetID(id); this.m_list_request.Sort(SORT_BY_PEND_REQ_ID); int index=this.m_list_request.Search(req); delete req; return index; } //+------------------------------------------------------------------+ //| Return the request object index in the list by the order ticket | //+------------------------------------------------------------------+ int CTrading::GetIndexPendingRequestByOrder(const ulong ticket) { CPendRequest *req=new CPendRequest(); if(req==NULL) return WRONG_VALUE; req.SetOrder(ticket); this.m_list_request.Sort(SORT_BY_PEND_REQ_MQL_REQ_ORDER); 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) { CPendRequest *req=new CPendRequest(); if(req==NULL) return WRONG_VALUE; req.SetPosition(ticket); this.m_list_request.Sort(SORT_BY_PEND_REQ_MQL_REQ_POSITION); int index=this.m_list_request.Search(req); delete req; return index; } //+------------------------------------------------------------------+
Para pesquisa do objeto, nas lista, segundo a propriedade especificada, com a ajuda do método Searsh() da classe de uma matriz dinâmica de ponteiros para instâncias da classe CObject, primeiro é necessário, com a ajuda do método Sort() da classe base de uma matriz dinâmica de variáveis CArray, especificar o tipo de classificação de lista na qual é realizada a lista, uma vez que a pesquisa é realizada apenas em matrizes classificadas. É o que estamos fazendo aqui.
Agora, no temporizador da classe, corrigiremos a exibição de mensagens sobre o número da tentativa de negociação no log.
Devemos
substituir este código
//--- 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_REQUEST)+(string)req_obj.GetProperty(PEND_REQ_PROP_ID)+" "+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) {
por este:
//--- 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()+":"); req_obj.PrintShort(); } //--- Depending on the type of action performed in the trading request switch(request.action) {
Isso nos dará uma mensagem mais informativa no log sobre qual objeto da ordem pendente é a próxima tentativa de negociação.
Essas são todas as alterações necessárias para a biblioteca trabalhar com objetos-ordens de negociação pendentes.
Teste
Para testar novos objetos-ordens pendentes, usamos o EA do artigo anterior
e o salvamos na nova pasta
\MQL5\Experts\TestDoEasy\ Part29\ usando o novo nome TestDoEasyPart29.mq5.
Todas as alterações que precisam ser feitas dizem respeito a remover verificações desnecessárias nos blocos para fechar metade da posição Buy e metade da posição Sell, uma vez que já tudo é feito nos métodos de negociação da classe de negociação.
No bloco para fechamento parcial da posição Buy em vez deste código:
//--- If the BUTT_CLOSE_BUY2 button is pressed: Close the half of the Buy with the maximum profit else if(button==EnumToString(BUTT_CLOSE_BUY2)) { //--- Get the list of all open positions CArrayObj* list=engine.GetListMarketPosition(); //--- Select only Buy positions from the list list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_BUY,EQUAL); //--- Sort the list by profit considering commission and swap list.Sort(SORT_BY_ORDER_PROFIT_FULL); //--- Get the index of the Buy position with the maximum profit int index=CSelect::FindOrderMax(list,ORDER_PROP_PROFIT_FULL); if(index>WRONG_VALUE) { COrder* position=list.At(index); if(position!=NULL) { //--- If this is a hedge account, close the half of the Buy position by the ticket if(engine.IsHedge()) engine.ClosePositionPartially((ulong)position.Ticket(),position.Volume()/2.0); //--- If this is a netting account, open a Sell position with the half of the Buy position volume else engine.OpenSell(NormalizeLot(position.Symbol(),position.Volume()/2.0),position.Symbol(),position.Magic(),position.StopLoss(),position.TakeProfit(),"Частичное закрытие Buy #"+(string)position.Ticket()); } } }
escrevemos este:
//--- If the BUTT_CLOSE_BUY2 button is pressed: Close the half of the Buy with the maximum profit else if(button==EnumToString(BUTT_CLOSE_BUY2)) { //--- Get the list of all open positions CArrayObj* list=engine.GetListMarketPosition(); //--- Select only Buy positions from the list list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_BUY,EQUAL); //--- Sort the list by profit considering commission and swap list.Sort(SORT_BY_ORDER_PROFIT_FULL); //--- Get the index of the Buy position with the maximum profit int index=CSelect::FindOrderMax(list,ORDER_PROP_PROFIT_FULL); if(index>WRONG_VALUE) { COrder* position=list.At(index); //--- Close the Buy position partially if(position!=NULL) engine.ClosePositionPartially((ulong)position.Ticket(),position.Volume()/2.0); } }
Da mesma maneira, reescrevemos o fechamento parcial da posição Sell:
//--- If the BUTT_CLOSE_SELL2 button is pressed: Close the half of the Sell with the maximum profit else if(button==EnumToString(BUTT_CLOSE_SELL2)) { //--- Get the list of all open positions CArrayObj* list=engine.GetListMarketPosition(); //--- Select only Sell positions from the list list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_SELL,EQUAL); //--- Sort the list by profit considering commission and swap list.Sort(SORT_BY_ORDER_PROFIT_FULL); //--- Get the index of the Sell position with the maximum profit int index=CSelect::FindOrderMax(list,ORDER_PROP_PROFIT_FULL); if(index>WRONG_VALUE) { COrder* position=list.At(index); //--- Close the Sell position partially if(position!=NULL) engine.ClosePositionPartially((ulong)position.Ticket(),position.Volume()/2.0); } }
Compilamos e iniciamos o EA.
No momento, tenho quatro ordens pendentes posicionadas. Desativo a botão "Autotrading" e clico no botão do EA de teste "Delete pending" para excluir todas as ordens pendentes. No log são exibidas as mensagens:
2019.12.19 04:25:04.385 CTrading::DeleteOrder: Invalid request: 2019.12.19 04:25:04.385 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.19 04:25:04.385 Correction of trade request parameters ... 2019.12.19 04:25:04.385 Pending request created #1: 2019.12.19 04:25:04.385 Pending request to remove a pending order: 2019.12.19 04:25:04.385 - EURUSD 0.10 Pending order Buy Limit #497568391, Price 1.11076 2019.12.19 04:25:04.385 - Pending request ID: #1, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:04.385 2019.12.19 04:25:04.386 CTrading::DeleteOrder: Invalid request: 2019.12.19 04:25:04.386 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.19 04:25:04.386 Correction of trade request parameters ... 2019.12.19 04:25:04.386 Pending request created #2: 2019.12.19 04:25:04.386 Pending request to remove a pending order: 2019.12.19 04:25:04.386 - EURUSD 0.10 Pending order Buy Limit #497563913, Price 1.11099 2019.12.19 04:25:04.386 - Pending request ID: #2, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:04.386 2019.12.19 04:25:04.386 CTrading::DeleteOrder: Invalid request: 2019.12.19 04:25:04.386 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.19 04:25:04.386 Correction of trade request parameters ... 2019.12.19 04:25:04.386 Pending request created #3: 2019.12.19 04:25:04.386 Pending request to remove a pending order: 2019.12.19 04:25:04.386 - EURUSD 0.10 Pending order Sell Limit #496816788, Price 1.11829 2019.12.19 04:25:04.386 - Pending request ID: #3, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:04.386 2019.12.19 04:25:04.386 CTrading::DeleteOrder: Invalid request: 2019.12.19 04:25:04.386 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.19 04:25:04.386 Correction of trade request parameters ... 2019.12.19 04:25:04.387 Pending request created #4: 2019.12.19 04:25:04.387 Pending request to remove a pending order: 2019.12.19 04:25:04.387 - EURUSD 0.10 Pending order Sell Limit #496816707, Price 1.11784 2019.12.19 04:25:04.387 - Pending request ID: #4, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:04.387
Aqui pode ser visto que o EA fez quatro tentativas para excluir quatro ordens pendentes e, ao encontrar um erro de proibição de negociação da parte do terminal, criou quatro ordens pendentes sobre as quais exibia mensagens curtas com seus parâmetros.
Em seguida, não fazemos nada, apenas aguardamos.
Após algum tempo (20 segundos de espera, mas depende da chegada de ticks),
são exibidas no log as mensagens de objetos-ordens pendentes sobre tentativas repetidas de excluir quatro ordens:
2019.12.19 04:25:38.780 Retry trading attempt #1: 2019.12.19 04:25:38.780 Pending request to remove a pending order: 2019.12.19 04:25:38.780 - EURUSD 0.10 Pending order Sell Limit #496816707, Price 1.11784 2019.12.19 04:25:38.780 - Pending request ID: #4, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:38.780 2019.12.19 04:25:38.780 Retry trading attempt #1: 2019.12.19 04:25:38.780 Pending request to remove a pending order: 2019.12.19 04:25:38.780 - EURUSD 0.10 Pending order Buy Limit #497563913, Price 1.11099 2019.12.19 04:25:38.780 - Pending request ID: #2, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:38.780 2019.12.19 04:25:38.781 Retry trading attempt #1: 2019.12.19 04:25:38.781 Pending request to remove a pending order: 2019.12.19 04:25:38.781 - EURUSD 0.10 Pending order Sell Limit #496816788, Price 1.11829 2019.12.19 04:25:38.781 - Pending request ID: #3, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:38.781 2019.12.19 04:25:39.103 Retry trading attempt #1: 2019.12.19 04:25:39.103 Pending request to remove a pending order: 2019.12.19 04:25:39.103 - EURUSD 0.10 Pending order Buy Limit #497568391, Price 1.11076 2019.12.19 04:25:39.103 - Pending request ID: #1, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:39.103 2019.12.19 04:25:42.006 Retry trading attempt #2: 2019.12.19 04:25:42.006 Pending request to remove a pending order: 2019.12.19 04:25:42.006 - EURUSD 0.10 Pending order Buy Limit #497568391, Price 1.11076 2019.12.19 04:25:42.006 - Pending request ID: #1, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:42.006 2019.12.19 04:25:42.007 Retry trading attempt #2: 2019.12.19 04:25:42.007 Pending request to remove a pending order: 2019.12.19 04:25:42.007 - EURUSD 0.10 Pending order Buy Limit #497563913, Price 1.11099 2019.12.19 04:25:42.007 - Pending request ID: #2, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:42.007 2019.12.19 04:25:42.007 Retry trading attempt #2: 2019.12.19 04:25:42.007 Pending request to remove a pending order: 2019.12.19 04:25:42.007 - EURUSD 0.10 Pending order Sell Limit #496816788, Price 1.11829 2019.12.19 04:25:42.007 - Pending request ID: #3, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:42.007 2019.12.19 04:25:42.008 Retry trading attempt #2: 2019.12.19 04:25:42.008 Pending request to remove a pending order: 2019.12.19 04:25:42.008 - EURUSD 0.10 Pending order Sell Limit #496816707, Price 1.11784 2019.12.19 04:25:42.008 - Pending request ID: #4, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:25:42.008 2019.12.19 04:26:03.026 Retry trading attempt #3: 2019.12.19 04:26:03.026 Pending request to remove a pending order: 2019.12.19 04:26:03.026 - EURUSD 0.10 Pending order Buy Limit #497568391, Price 1.11076 2019.12.19 04:26:03.026 - Pending request ID: #1, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:03.026 2019.12.19 04:26:03.027 Retry trading attempt #3: 2019.12.19 04:26:03.027 Pending request to remove a pending order: 2019.12.19 04:26:03.027 - EURUSD 0.10 Pending order Buy Limit #497563913, Price 1.11099 2019.12.19 04:26:03.027 - Pending request ID: #2, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:03.027 2019.12.19 04:26:03.027 Retry trading attempt #3: 2019.12.19 04:26:03.028 Pending request to remove a pending order: 2019.12.19 04:26:03.028 - EURUSD 0.10 Pending order Sell Limit #496816788, Price 1.11829 2019.12.19 04:26:03.028 - Pending request ID: #3, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:03.028 2019.12.19 04:26:03.028 Retry trading attempt #3: 2019.12.19 04:26:03.028 Pending request to remove a pending order: 2019.12.19 04:26:03.028 - EURUSD 0.10 Pending order Sell Limit #496816707, Price 1.11784 2019.12.19 04:26:03.028 - Pending request ID: #4, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:03.028 2019.12.19 04:26:22.357 Retry trading attempt #4: 2019.12.19 04:26:22.357 Pending request to remove a pending order: 2019.12.19 04:26:22.357 - EURUSD 0.10 Pending order Buy Limit #497568391, Price 1.11076 2019.12.19 04:26:22.357 - Pending request ID: #1, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:22.357 2019.12.19 04:26:22.358 Retry trading attempt #4: 2019.12.19 04:26:22.358 Pending request to remove a pending order: 2019.12.19 04:26:22.358 - EURUSD 0.10 Pending order Buy Limit #497563913, Price 1.11099 2019.12.19 04:26:22.358 - Pending request ID: #2, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:22.358 2019.12.19 04:26:22.358 Retry trading attempt #4: 2019.12.19 04:26:22.358 Pending request to remove a pending order: 2019.12.19 04:26:22.358 - EURUSD 0.10 Pending order Sell Limit #496816788, Price 1.11829 2019.12.19 04:26:22.358 - Pending request ID: #3, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920 2019.12.19 04:26:22.358 2019.12.19 04:26:22.359 Retry trading attempt #4: 2019.12.19 04:26:22.359 Pending request to remove a pending order: 2019.12.19 04:26:22.359 - EURUSD 0.10 Pending order Sell Limit #496816707, Price 1.11784 2019.12.19 04:26:22.359 - Pending request ID: #4, Created 2019.12.18 23:25:01.920, Attempts 5, Wait 00:00:20, End 2019.12.18 23:26:41.920
E, novamente, esperamos a próxima tentativa de negociação. Quando chegar a hora, os objetos-ordens pendentes serão excluídas devido à expiração do tempo alocado para todas as tentativas de negociação:
2019.12.19 04:26:44.004 Pending request ID: #1: Deleted due to expiration 2019.12.19 04:26:44.004 Pending request ID: #2: Deleted due to expiration 2019.12.19 04:26:44.004 Pending request ID: #3: Deleted due to expiration 2019.12.19 04:26:44.004 Pending request ID: #4: Deleted due to expiration
Se o botão "Autotrading" for pressionado para todas as tentativas de negociação no tempo previsto, os objetos de ordens pendentes enviarão uma ordem ao servidor para excluir as ordens pendentes e elas serão removidas.
Exatamente da mesma maneira, verifiquei o funcionamento de objetos de ordens de negociação pendentes para abrir/fechar posições, colocar ordens, modificar ordens stop e parâmetros de ordens pendentes; bem como para o fechamento de posições usando uma posição oposta. E como resultado notei que as ordens de negociação pendentes funcionam corretamente na maioria dos casos. Porém, há um 'mas': se, primeiro, modificarmos, por exemplo, uma ordem pendente e, em seguida, tentarmos novamente fazer alguma modificação, já não será possível fazer isso. É como criar duas ou mais operações de negociação com o mesmo ticket. As ordens pendentes serão simplesmente excluídas imediatamente após serem criadas com a causa "Concluídas". Acontece que, nos artigos anteriores, as verificações de processamento de solicitações pendentes eram realizadas apenas por ticket no temporizador da classe de negociação. E o método de verificação descobriu que no histórico da conta uma operação com certo ticket havia acabado de ser realizada. Dessa forma, acreditava-se que tudo funcionou bem e valia a pena excluir esse objeto-ordem. Vamos corrigir essa situação em seguida.
Lembre-se:
Chamo bastante a atenção para o fato de que trabalho com a classe de objeto-ordem pendente ainda não está totalmente concluído, por isso, os resultados descritos neste artigo e no EA de teste anexado ao artigo não devem, em caso algum, ser usados para negociação real!Este artigo, seus materiais e o resultado, 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, criaremos uma classe para gerenciar ordens de negociação pendentes e nos livraremos da incapacidade de executar a mesma
operação de negociação com a mesma ordem ou posição várias vezes seguidas.
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.
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 base 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 Parte 28.
Trabalho com ordens pendentes de negociação - fechamento, exclusão, modificações
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/7454
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso