Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XXVII): Arbeiten mit Handelsanfragen - platzieren von Pending-Orders

25 Februar 2020, 10:49
Artyom Trishkin
0
324

Inhalt

Im vorherigen Artikel haben wir mit der Implementierung von schwebenden Handelsanfragen begonnen und die erste schwebende Anfrage zur Eröffnung einer Position für den Fall erstellt, dass nach dem Senden einer Anfrage an den Server ein Fehler in der Handelsklasse auftritt. In diesem Artikel werden wir die Entwicklung der schwebenden Anfrage wieder aufnehmen und die Erstellung einer schwebenden Anfrage für den Fall implementieren, dass beim Setzen von Pending-Orders Fehler aufgetreten sind.

Beim Testen der Handelsklasse hatte ich einige Unzulänglichkeiten festgestellt. Insbesondere bei der Initialisierung der Handelsobjekte des Symbols im Klassenkonstruktor wurden für diese fest eingestellte Standardwerte gesetzt. Möglicherweise wurden nicht alle diese Werte in der Symbolspezifikation unterstützt. Dies führte zu Serverfehlern beim Versuch, Pending-Orders zu platzieren — der Server aktivierte den nicht unterstützten Fehler vom Typ Ablauf der Order. Dieser Fehler wurde nirgendwo korrigiert und führte schließlich zur Unfähigkeit, eine Pending-Order aufzugeben. Beim Senden einer Handelsanforderung mit Standardwerten wurden auch einige nicht unterstützte Daten an die Handelsanforderung gesendet. Um dieses Problem zu lösen, musste ich die korrekten Daten entsprechend der entsprechenden Symbolspezifikation direkt in der Handelsanfrage angeben.

Dies erforderte die Kenntnis einer Symbolspezifikation und die manuelle Eingabe genauer Werte direkt in den Programmcode, statt der automatischen Korrektur von Werten durch die Bibliothek selbst. Zur Vereinfachung werden wir kleinere Änderungen in der Logik der Handelsklasse vornehmen. Alle Symbol-Handelsobjekte sollen durch automatische Auswahl der richtigen Werte im OnInit() des EA initialisiert werden. Die Werte -1 werden standardmäßig an die Handelsmethoden der Handelsklasse für die Orderausfüllung und die Ablauftypen übergeben, um anzuzeigen, dass es an der Zeit ist, voreingestellte korrekte Standardwerte zu verwenden. Wenn ein anderer Wert aus dem Programm übergeben wird, wird dieser stattdessen verwendet. Wenn sich der Wert als ungültig herausstellt, wird er bei der Behandlung von Fehlern in der Handelsklasse korrigiert.

Daten vorbereiten

Abgesehen von der Festlegung der Handelsklasse werden wir auch die Beschreibung der Anfrage (die alle ihre Parameter im Journal anzeigt) zur Objektklasse der ausstehenden Anfrage hinzufügen. Dies erleichtert das Testen der Arbeit mit den Objekten der schwebenden Anfragen.
Fügen Sie zunächst alle erforderlichen Nachrichten zum Nachrichtenarray der Bibliothek hinzu.

Öffnen Sie die Datei Datas.mqh und fügen Sie die Indizes der neuen Nachrichten hinzu:

//+------------------------------------------------------------------+
//| List of the library's text message indices                       |
//+------------------------------------------------------------------+
enum ENUM_MESSAGES_LIB
  {
   MSG_LIB_PARAMS_LIST_BEG=ERR_USER_ERROR_FIRST,      // Beginning of the parameter list
   MSG_LIB_PARAMS_LIST_END,                           // End of the parameter list
   MSG_LIB_PROP_NOT_SUPPORTED,                        // Property not supported
   MSG_LIB_PROP_NOT_SUPPORTED_MQL4,                   // Property not supported in MQL4
   MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155,          // Property not supported in MetaTrader 5 versions lower than 2155
   MSG_LIB_PROP_NOT_SUPPORTED_POSITION,               // Property not supported for position
   MSG_LIB_PROP_NOT_SUPPORTED_PENDING,                // Property not supported for pending order
   MSG_LIB_PROP_NOT_SUPPORTED_MARKET,                 // Property not supported for market order
   MSG_LIB_PROP_NOT_SUPPORTED_MARKET_HIST,            // Property not supported for historical market order
   MSG_LIB_PROP_NOT_SET,                              // Value not set
   MSG_LIB_PROP_EMPTY,                                // Not set
   MSG_LIB_PROP_AS_IN_ORDER,                          // According to the order expiration mode
   
   MSG_LIB_SYS_ERROR,                                 // Error


...

   MSG_LIB_TEXT_FAILING_CREATE_PENDING_REQ,           // Failed to create a pending request
   MSG_LIB_TEXT_TRY_N,                                // Trading attempt #
   MSG_LIB_TEXT_RE_TRY_N,                             // Repeated trading attempt #
   
   MSG_LIB_TEXT_REQUEST_ACTION,                       // Type of a performed action
   MSG_LIB_TEXT_REQUEST_MAGIC,                        // EA stamp (magic number)
   MSG_LIB_TEXT_REQUEST_ORDER,                        // Order ticket
   MSG_LIB_TEXT_REQUEST_SYMBOL,                       // Name of a trading instrument
   MSG_LIB_TEXT_REQUEST_VOLUME,                       // Requested volume of a deal in lots
   MSG_LIB_TEXT_REQUEST_PRICE,                        // Price
   MSG_LIB_TEXT_REQUEST_STOPLIMIT,                    // StopLimit
   MSG_LIB_TEXT_REQUEST_SL,                           // Stop Loss
   MSG_LIB_TEXT_REQUEST_TP,                           // Take Profit
   MSG_LIB_TEXT_REQUEST_DEVIATION,                    // Maximum price deviation
   MSG_LIB_TEXT_REQUEST_TYPE,                         // Order type
   MSG_LIB_TEXT_REQUEST_TYPE_FILLING,                 // Order filling type
   MSG_LIB_TEXT_REQUEST_TYPE_TIME,                    // Order lifetime type
   MSG_LIB_TEXT_REQUEST_EXPIRATION,                   // Order expiration date
   MSG_LIB_TEXT_REQUEST_COMMENT,                      // Order comment
   MSG_LIB_TEXT_REQUEST_POSITION,                     // Position ticket
   MSG_LIB_TEXT_REQUEST_POSITION_BY,                  // Opposite position ticket
   
   MSG_LIB_TEXT_REQUEST_ACTION_DEAL,                  // Place a market order
   MSG_LIB_TEXT_REQUEST_ACTION_PENDING,               // Place a pending order
   MSG_LIB_TEXT_REQUEST_ACTION_SLTP,                  // Change open position Stop Loss and Take Profit
   MSG_LIB_TEXT_REQUEST_ACTION_MODIFY,                // Change parameters of the previously placed trading order
   MSG_LIB_TEXT_REQUEST_ACTION_REMOVE,                // Remove previously placed pending order
   MSG_LIB_TEXT_REQUEST_ACTION_CLOSE_BY,              // Close a position by an opposite one
   MSG_LIB_TEXT_REQUEST_ACTION_UNCNOWN,               // Unknown trading operation type
   
   MSG_LIB_TEXT_REQUEST_ORDER_FILLING_FOK,            // Order is executed in the specified volume only, otherwise it is canceled
   MSG_LIB_TEXT_REQUEST_ORDER_FILLING_IOK,            // Order is filled within an available volume, while the unfilled one is canceled
   MSG_LIB_TEXT_REQUEST_ORDER_FILLING_RETURN,         // Order is filled within an available volume, while the unfilled one remains
   
   MSG_LIB_TEXT_REQUEST_ORDER_TIME_GTC,               // Order is valid till explicitly canceled
   MSG_LIB_TEXT_REQUEST_ORDER_TIME_DAY,               // Order is valid only during the current trading day
   MSG_LIB_TEXT_REQUEST_ORDER_TIME_SPECIFIED,         // Order is valid till the expiration date
   MSG_LIB_TEXT_REQUEST_ORDER_TIME_SPECIFIED_DAY,     // Order is valid till 23:59:59 of a specified day
   
   MSG_LIB_TEXT_REQUEST_DATAS,                        // Trading request parameters
   MSG_LIB_TEXT_PEND_REQUEST_DATAS,                   // Pending trading request parameters
   MSG_LIB_TEXT_PEND_REQUEST_CREATED,                 // Pending request created
   MSG_LIB_TEXT_PEND_REQUEST_DELETED,                 // Pending request is removed due to its expiration

   MSG_LIB_TEXT_PEND_REQUEST_PRICE_CREATE,            // Price at the moment of request generation
   MSG_LIB_TEXT_PEND_REQUEST_TIME_CREATE,             // Request creation time
   MSG_LIB_TEXT_PEND_REQUEST_TIME_ACTIVATE,           // Request activation time
   MSG_LIB_TEXT_PEND_REQUEST_WAITING,                 // Waiting time between trading attempts
   MSG_LIB_TEXT_PEND_REQUEST_CURRENT_ATTEMPT,         // Current trading attempt
   MSG_LIB_TEXT_PEND_REQUEST_TOTAL_ATTEMPTS,          // Total number of trading attempts
   MSG_LIB_TEXT_PEND_REQUEST_ID,                      // Trading request ID
   MSG_LIB_TEXT_PEND_REQUEST_RETCODE,                 // Return code a request is based on
   MSG_LIB_TEXT_PEND_REQUEST_TYPE,                    // Pending request type
   
   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
   
  };


und die Nachrichtentexte, die den Indizes entsprechen:

//+------------------------------------------------------------------+
string messages_library[][TOTAL_LANG]=
  {
   {"Начало списка параметров","Beginning of event parameter list"},
   {"Конец списка параметров","End of parameter list"},
   {"Свойство не поддерживается","Property not supported"},
   {"Свойство не поддерживается в MQL4","Property not supported in MQL4"},
   {"Свойство не поддерживается в MetaTrader5 версии ниже 2155","Property not supported in MetaTrader 5, build lower than 2155"},
   {"Свойство не поддерживается у позиции","Property not supported for position"},
   {"Свойство не поддерживается у отложенного ордера","Property not supported for pending order"},
   {"Свойство не поддерживается у маркет-ордера","Property not supported for market order"},
   {"Свойство не поддерживается у исторического маркет-ордера","Property not supported for historical market order"},
   {"Значение не задано","Value not set"},
   {"Отсутствует","Not set"},
   {"В соответствии с режимом истечения ордера","In accordance with the order expiration mode"},
   
   {"Ошибка ","Error"},


...

   {"Не удалось создать отложенный запрос","Failed to create pending request"},
   {"Торговая попытка #","Trading attempt #"},
   {"Повторная торговая попытка #","Retry trading attempt #"},
   
   {"Тип выполняемого действия","Trade operation type"},
   {"Штамп эксперта (magic number)","Expert Advisor ID (magic number)"},
   {"Тикет ордера","Order ticket"},
   {"Имя торгового инструмента","Trade symbol"},
   {"Запрашиваемый объем сделки в лотах","Requested volume for a deal in lots"},
   {"Цена","Price"},
   {"Уровень StopLimit ордера","StopLimit level of the order"},
   {"Уровень Stop Loss ордера","Stop Loss level of the order"},
   {"Уровень Take Profit ордера","Take Profit level of the order"},
   {"Максимальное отклонение от цены","Maximal deviation from the price"},
   {"Тип ордера","Order type"},
   {"Тип ордера по исполнению","Order execution type"},
   {"Тип ордера по времени действия","Order expiration type"},
   {"Срок истечения ордера","Order expiration time"},
   {"Комментарий к ордеру","Order comment"},
   {"Тикет позиции","Position ticket"},
   {"Тикет встречной позиции","Opposite position ticket"},
   
   {"Поставить рыночный ордер","Place market order"},
   {"Установить отложенный ордер","Place pending order"},
   {"Изменить значения Stop Loss и Take Profit у открытой позиции","Modify Stop Loss and Take Profit values of an opened position"},
   {"Изменить параметры ранее установленного торгового ордера","Modify the parameters of the order placed previously"},
   {"Удалить ранее выставленный отложенный ордер","Delete the pending order placed previously"},
   {"Закрыть позицию встречной","Close a position by an opposite one"},
   {"Неизвестный тип торговой операции","Unknown trade action type"},
   
   {"Ордер исполняется исключительно в указанном объеме, иначе отменяется (FOK)","The order is executed exclusively in the specified volume, otherwise it is canceled (FOK)"},
   {"Ордер исполняется на доступный объем, неисполненный отменяется (IOK)","The order is executed on the available volume, the unfulfilled is canceled (IOK)"},
   {"Ордер исполняется на доступный объем, неисполненный остаётся (Return)","The order is executed at an available volume, unfulfilled remains in the market (Return)"},
   
   {"Ордер действителен до явной отмены","Good till cancel order"},
   {"Ордер действителен только в течение текущего торгового дня","Good till current trade day order"},
   {"Ордер действителен до даты истечения","Good till expired order"},
   {"Ордер действителен до 23:59:59 указанного дня","The order will be effective till 23:59:59 of the specified day"},
   {"Параметры торгового запроса","Trade request's parameters"},
   {"Параметры отложенного торгового запроса","Pending trade request's parameters"},
   {"Создан отложенный запрос","Pending request created"},
   {"Отложенный запрос удалён в связи с окончанием времени его действия","Pending request deleted due to expiration"},
   
   {"Цена в момент создания запроса: ","Price at time of request create: "},
   {"Время создания запроса: ","Request creation time: "},
   {"Время активации запроса: ","Request activation time: "},
   {"Время ожидания между торговыми попытками: ","Waiting time between trading attempts: "},
   {"Текущая торговая попытка: ","Current trading attempt: "},
   {"Общее количество торговых попыток: ","Total trade attempts: "},
   {"Идентификатор торгового запроса: ","Trade request ID: "},
   {"Код возврата, на основании которого создан запрос: ","Return code based on which the request was created: "},
   {"Тип отложенного запроса: ","Pending request type: "},
   {"Отложенный запрос, созданный по коду возврата сервера","Pending request that was created as a result of the server code"},
   {"Отложенный запрос, созданный по запросу","Pending request created by request"},
   {"Ожидание наступления времени первой торговой попытки","Waiting for the onset time of the first trading attempt"},
   
  };
//+---------------------------------------------------------------------+


Abgesehen von den oben genannten Unzulänglichkeiten habe ich festgestellt, dass sich die Kollektion der IDs mit den IDs der Objekttypen in der Standardbibliothek überschneiden. Insbesondere entspricht die ID von COLLECTION_HISTORY_ID (Kollektion historischer Aufträge und Geschäfte) 0x7779 dem Typ der Standardbibliothek der dynamische Liste CList der CO-Objektklasseninstanzen und ihrer Nachkommen. Es wäre nicht sinnvoll, wenn die Objekt-IDs gleiche Werte haben.

Nachfolgend finden Sie eine Liste von Standard-Bibliotheksobjekt-IDs und die entsprechenden hexadezimalen Werte:

Basisklasse          CObject
                        Type = 0
Datenkollektion    CArrayChar
                        Type = 0x77
Datenkollektion    CArrayShort
                        Type = 0x82
Datenkollektion    CArrayInt
                        Type = 0x82
Datenkollektion    CArrayLong
                        Type = 0x84
Datenkollektion    CArrayFloat
                        Type = 0x87
Datenkollektion    CArrayDouble
                        Type = 0x87
Datenkollektion    CArrayString
                        Type = 0x89
Datenkollektion    CArrayObj
                        Type = 0x7778
Datenkollektion    CList
                        Type = 0x7779
Basisklasse grafischer Objekte CChartObject
                        Type = 0x8888
Preischarts     CChart
                        Type = 0x1111

Die Liste ist höchstwahrscheinlich unvollständig. Wie wir sehen können, entspricht der Listenobjekttyp der ID der Kollektion mit historischen Aufträgen und Geschäften, die für die Bibliothek festgelegt wurde.
Korrigieren wir dies in der Datei Defines.mqh durch das Erhöhen der Werte aller Kollektions-IDs um 1:

//--- Collection list IDs
#define COLLECTION_HISTORY_ID          (0x777A)                   // Historical collection list ID
#define COLLECTION_MARKET_ID           (0x777B)                   // Market collection list ID
#define COLLECTION_EVENTS_ID           (0x777C)                   // Event collection list ID
#define COLLECTION_ACCOUNT_ID          (0x777D)                   // Account collection list ID
#define COLLECTION_SYMBOLS_ID          (0x777E)                   // Symbol collection list ID
//--- Data parameters for file operations


Da ich die Fähigkeit zum Handel mit schwebenden Anfragen umsetzen möchte, sollen die beiden Arten von schwebenden Anfrage umgesetzt werden:

  • eine Anfrage, die auf der Grundlage des Fehlercodes des Handelsservers generiert wird (dies sind die Anfragen, die wir derzeit implementieren);
  • eine schwebende Anfrage, die auf Anfrage eines Programms erstellt wird (Handel über hängige Anforderungen, die später implementiert werden soll).

Daher werde ich das Konzept des "Anfrage-Typs" und die IDs, die diesem entsprechen, einführen, um die Anfrage-Typen zu trennen:

//--- Symbol parameters
#define CLR_DEFAULT                    (0xFF000000)               // Default color
#define SYMBOLS_COMMON_TOTAL           (1000)                     // Total number of working symbols
//--- Pending request type IDs
#define PENDING_REQUEST_ID_TYPE_ERR    (1)                        // Type of a pending request created based on the server return code
#define PENDING_REQUEST_ID_TYPE_REQ    (2)                        // Type of a pending request created by request
//+------------------------------------------------------------------+


Ganz am Ende der Datei Defines.mqh wird die Enumeration der Typen schwebender Anfragen hinzugefügt:

//+------------------------------------------------------------------+
//| Pending request type                                             |
//+------------------------------------------------------------------+
enum ENUM_PENDING_REQUEST_TYPE
  {
   PENDING_REQUEST_TYPE_ERROR=PENDING_REQUEST_ID_TYPE_ERR,  // Pending request created based on the return code or error
   PENDING_REQUEST_TYPE_REQUEST=PENDING_REQUEST_ID_TYPE_REQ,// Pending request created by request
  };
//+------------------------------------------------------------------+

Um die Beschreibungen der Handelsanfragen im Journal anzuzeigen, müssen wir die entsprechenden Funktionen vorbereiten.
Wir fügen in der Datei DELib.mqh der Dienstfunktionen alle notwendigen Funktionen hinzu, um eine Nachricht aus den vordefinierten Texten, die in der Datei Datas.mqh gesetzt sind, und den Werten der von den Funktionen angezeigten Eigenschaften zu erzeugen.

Die Funktionen für die Anzeige des Ausfüllmodus der Order und den Typ der Ablaufzeit:

//+------------------------------------------------------------------+
//| Return the order filling mode description                        |
//+------------------------------------------------------------------+
string OrderTypeFillingDescription(const ENUM_ORDER_TYPE_FILLING type)
  {
   return
     (
      type==ORDER_FILLING_FOK    ?  CMessage::Text(MSG_LIB_TEXT_REQUEST_ORDER_FILLING_FOK)   :
      type==ORDER_FILLING_IOC    ?  CMessage::Text(MSG_LIB_TEXT_REQUEST_ORDER_FILLING_IOK)   :
      type==ORDER_FILLING_RETURN ?  CMessage::Text(MSG_LIB_TEXT_REQUEST_ORDER_FILLING_RETURN): 
      type==WRONG_VALUE          ? "WRONG_VALUE"   :  EnumToString(type)
     );
  }
//+------------------------------------------------------------------+
//| Return the order expiration type description                     |
//+------------------------------------------------------------------+
string OrderTypeTimeDescription(const ENUM_ORDER_TYPE_TIME type)
  {
   return
     (
      type==ORDER_TIME_GTC             ?  CMessage::Text(MSG_LIB_TEXT_REQUEST_ORDER_TIME_GTC)            :
      type==ORDER_TIME_DAY             ?  CMessage::Text(MSG_LIB_TEXT_REQUEST_ORDER_TIME_DAY)            :
      type==ORDER_TIME_SPECIFIED       ?  CMessage::Text(MSG_LIB_TEXT_REQUEST_ORDER_TIME_SPECIFIED)      :
      type==ORDER_TIME_SPECIFIED_DAY   ?  CMessage::Text(MSG_LIB_TEXT_REQUEST_ORDER_TIME_SPECIFIED_DAY)  :
      type==WRONG_VALUE                ? "WRONG_VALUE"   :  EnumToString(type)
     );
  }
//+------------------------------------------------------------------+


Die Funktionen zur Darstellung der Beschreibung von Struktur der Handelsanforderung (MqlTradeRequest):

//+------------------------------------------------------------------+
//| Display the trading request description in the journal           |
//+------------------------------------------------------------------+
void PrintRequestDescription(const MqlTradeRequest &request)
  {
   string datas=
     (
      " - "+RequestActionDescription(request)+"\n"+
      " - "+RequestMagicDescription(request)+"\n"+
      " - "+RequestOrderDescription(request)+"\n"+
      " - "+RequestSymbolDescription(request)+"\n"+
      " - "+RequestVolumeDescription(request)+"\n"+
      " - "+RequestPriceDescription(request)+"\n"+
      " - "+RequestStopLimitDescription(request)+"\n"+
      " - "+RequestStopLossDescription(request)+"\n"+
      " - "+RequestTakeProfitDescription(request)+"\n"+
      " - "+RequestDeviationDescription(request)+"\n"+
      " - "+RequestTypeDescription(request)+"\n"+
      " - "+RequestTypeFillingDescription(request)+"\n"+
      " - "+RequestTypeTimeDescription(request)+"\n"+
      " - "+RequestExpirationDescription(request)+"\n"+
      " - "+RequestCommentDescription(request)+"\n"+
      " - "+RequestPositionDescription(request)+"\n"+
      " - "+RequestPositionByDescription(request)
     );
   Print("================== ",CMessage::Text(MSG_LIB_TEXT_REQUEST_DATAS)," ==================\n",datas,"\n");
  }
//+------------------------------------------------------------------+
//| Return the executed action type description                      |
//+------------------------------------------------------------------+
string RequestActionDescription(const MqlTradeRequest &request)
  {
   int code_descr=
     (
      request.action==TRADE_ACTION_DEAL      ?  MSG_LIB_TEXT_REQUEST_ACTION_DEAL       :
      request.action==TRADE_ACTION_PENDING   ?  MSG_LIB_TEXT_REQUEST_ACTION_PENDING    :
      request.action==TRADE_ACTION_SLTP      ?  MSG_LIB_TEXT_REQUEST_ACTION_SLTP       :
      request.action==TRADE_ACTION_MODIFY    ?  MSG_LIB_TEXT_REQUEST_ACTION_MODIFY     :
      request.action==TRADE_ACTION_REMOVE    ?  MSG_LIB_TEXT_REQUEST_ACTION_REMOVE     :
      request.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 RequestMagicDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_ORD_MAGIC)+": "+(string)request.magic;
  }
//+------------------------------------------------------------------+
//| Return the order ticket value description                        |
//+------------------------------------------------------------------+
string RequestOrderDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_ORDER)+": "+(request.order>0 ? (string)request.order : CMessage::Text(MSG_LIB_PROP_NOT_SET));
  }
//+------------------------------------------------------------------+
//| Return the trading instrument name description                   |
//+------------------------------------------------------------------+
string RequestSymbolDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_SYMBOL)+": "+request.symbol;
  }
//+------------------------------------------------------------------+
//| Return the request volume description                            |
//+------------------------------------------------------------------+
string RequestVolumeDescription(const MqlTradeRequest &request)
  {
   int dg=(int)DigitsLots(request.symbol);
   int dgl=(dg==0 ? 1 : dg);
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_VOLUME)+": "+(request.volume>0 ? DoubleToString(request.volume,dgl) : CMessage::Text(MSG_LIB_PROP_NOT_SET));
  }
//+------------------------------------------------------------------+
//| Return the request price value description                       |
//+------------------------------------------------------------------+
string RequestPriceDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+": "+(request.price>0 ? DoubleToString(request.price,(int)SymbolInfoInteger(request.symbol,SYMBOL_DIGITS)) : CMessage::Text(MSG_LIB_PROP_NOT_SET));
  }
//+------------------------------------------------------------------+
//| Return the request StopLimit order price description             |
//+------------------------------------------------------------------+
string RequestStopLimitDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_STOPLIMIT)+": "+(request.stoplimit>0 ? DoubleToString(request.stoplimit,(int)SymbolInfoInteger(request.symbol,SYMBOL_DIGITS)) : CMessage::Text(MSG_LIB_PROP_NOT_SET));
  }
//+------------------------------------------------------------------+
//| Return the request StopLoss order price description              |
//+------------------------------------------------------------------+
string RequestStopLossDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_SL)+": "+(request.sl>0 ? DoubleToString(request.sl,(int)SymbolInfoInteger(request.symbol,SYMBOL_DIGITS)) : CMessage::Text(MSG_LIB_PROP_NOT_SET));
  }
//+------------------------------------------------------------------+
//| Return the request TakeProfit order price description            |
//+------------------------------------------------------------------+
string RequestTakeProfitDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_TP)+": "+(request.tp>0 ? DoubleToString(request.tp,(int)SymbolInfoInteger(request.symbol,SYMBOL_DIGITS)) : CMessage::Text(MSG_LIB_PROP_NOT_SET));
  }
//+------------------------------------------------------------------+
//| Return the request deviation size description                    |
//+------------------------------------------------------------------+
string RequestDeviationDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_DEVIATION)+": "+(string)request.deviation;
  }
//+------------------------------------------------------------------+
//| Return the request order type description                        |
//+------------------------------------------------------------------+
string RequestTypeDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_TYPE)+": "+OrderTypeDescription(request.type);
  }
//+------------------------------------------------------------------+
//| Return the request order filling mode description                |
//+------------------------------------------------------------------+
string RequestTypeFillingDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_TYPE_FILLING)+": "+OrderTypeFillingDescription(request.type_filling);
  }
//+------------------------------------------------------------------+
//| Return the request order lifetime type description               |
//+------------------------------------------------------------------+
string RequestTypeTimeDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_TYPE_TIME)+": "+OrderTypeTimeDescription(request.type_time);
  }
//+------------------------------------------------------------------+
//| Return the request order expiration time description             |
//+------------------------------------------------------------------+
string RequestExpirationDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_EXPIRATION)+": "+(request.expiration>0 ? TimeToString(request.expiration) : CMessage::Text(MSG_LIB_PROP_NOT_SET));
  }
//+------------------------------------------------------------------+
//| Return the request order comment description                     |
//+------------------------------------------------------------------+
string RequestCommentDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_COMMENT)+": "+(request.comment!="" && request.comment!=NULL ? "\""+request.comment+"\"" : CMessage::Text(MSG_LIB_PROP_NOT_SET));
  }
//+------------------------------------------------------------------+
//| Return the request position ticket description                   |
//+------------------------------------------------------------------+
string RequestPositionDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_POSITION)+": "+(request.position>0 ? (string)request.position : CMessage::Text(MSG_LIB_PROP_NOT_SET));
  }
//+------------------------------------------------------------------+
//| Return the request opposite position ticket description          |
//+------------------------------------------------------------------+
string RequestPositionByDescription(const MqlTradeRequest &request)
  {
   return CMessage::Text(MSG_LIB_TEXT_REQUEST_POSITION_BY)+": "+(request.position_by>0 ? (string)request.position_by : CMessage::Text(MSG_LIB_PROP_NOT_SET));
  }
//+------------------------------------------------------------------+

Lassen Sie uns nun die festgestellten Nachteile der Handelsklasse beheben und die Erstellung eines Objekts für schwebende Anfragen zur Einstellung von Pending-Orders vorbereiten.

Beseitigung von Mängeln in der Handelsklasse und Erstellung einer schwebenden Anfrage für das Erteilen von Aufträgen

Mir ist eine interessante Eigenschaft einiger Symbole aufgefallen, deren Charts auf den letzten Kursen basieren. Manchmal fehlen Ask- oder Bid-Preise oder beide. Um den Preis trotzdem zu erhalten, musste ich der abstrakten Objektklasse CSymbol zusätzliche Methoden hinzufügen (und vorhandene ändern), um den Chart-Konstruktionstyp zu überprüfen. Wenn das Diagramm auf den letzten Preisen basiert, wird das Vorhandensein von Ask- und Bid-Preisen geprüft. Falls vorhanden, werden diese Preise verwendet, andernfalls wird der letzte Kurs Last verwendet.

Im Block der Methoden für einen vereinfachten Zugriff auf die Objekteigenschaften der Symbole in der Datei Symbol.mqh ändern wir den Typ der Methode, die die Zeit zurückgibt. Da die Zeit in Millisekunden zurückgegeben wird, sollte der Typ 'ulong' anstelle von 'datetime' sein.
Wir geben auch die drei zusätzlichen Methoden an, deren Zweck oben beschrieben wurde:

//+------------------------------------------------------------------+
//| Methods of a simplified access to the order object properties    |
//+------------------------------------------------------------------+
//--- Integer properties
   long              Status(void)                                 const { return this.GetProperty(SYMBOL_PROP_STATUS);                                      }
   int               IndexInMarketWatch(void)                     const { return (int)this.GetProperty(SYMBOL_PROP_INDEX_MW);                               }
   bool              IsCustom(void)                               const { return (bool)this.GetProperty(SYMBOL_PROP_CUSTOM);                                }
   color             ColorBackground(void)                        const { return (color)this.GetProperty(SYMBOL_PROP_BACKGROUND_COLOR);                     }
   ENUM_SYMBOL_CHART_MODE ChartMode(void)                         const { return (ENUM_SYMBOL_CHART_MODE)this.GetProperty(SYMBOL_PROP_CHART_MODE);          }
   bool              IsExist(void)                                const { return (bool)this.GetProperty(SYMBOL_PROP_EXIST);                                 }
   bool              IsExist(const string name)                   const { return this.SymbolExists(name);                                                   }
   bool              IsSelect(void)                               const { return (bool)this.GetProperty(SYMBOL_PROP_SELECT);                                }
   bool              IsVisible(void)                              const { return (bool)this.GetProperty(SYMBOL_PROP_VISIBLE);                               }
   long              SessionDeals(void)                           const { return this.GetProperty(SYMBOL_PROP_SESSION_DEALS);                               }
   long              SessionBuyOrders(void)                       const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS);                          }
   long              SessionSellOrders(void)                      const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS);                         }
   long              Volume(void)                                 const { return this.GetProperty(SYMBOL_PROP_VOLUME);                                      }
   long              VolumeHigh(void)                             const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH);                                  }
   long              VolumeLow(void)                              const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW);                                   }
   long              Time(void)                                   const { return (datetime)this.GetProperty(SYMBOL_PROP_TIME);                              }
   int               Digits(void)                                 const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS);                                 }
   int               DigitsLot(void)                              const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS_LOTS);                            }
   int               Spread(void)                                 const { return (int)this.GetProperty(SYMBOL_PROP_SPREAD);                                 }
   bool              IsSpreadFloat(void)                          const { return (bool)this.GetProperty(SYMBOL_PROP_SPREAD_FLOAT);                          }
   int               TicksBookdepth(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_TICKS_BOOKDEPTH);                        }
   ENUM_SYMBOL_CALC_MODE TradeCalcMode(void)                      const { return (ENUM_SYMBOL_CALC_MODE)this.GetProperty(SYMBOL_PROP_TRADE_CALC_MODE);      }
   ENUM_SYMBOL_TRADE_MODE TradeMode(void)                         const { return (ENUM_SYMBOL_TRADE_MODE)this.GetProperty(SYMBOL_PROP_TRADE_MODE);          }
   datetime          StartTime(void)                              const { return (datetime)this.GetProperty(SYMBOL_PROP_START_TIME);                        }
   datetime          ExpirationTime(void)                         const { return (datetime)this.GetProperty(SYMBOL_PROP_EXPIRATION_TIME);                   }
   int               TradeStopLevel(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_STOPS_LEVEL);                      }
   int               TradeFreezeLevel(void)                       const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_FREEZE_LEVEL);                     }
   ENUM_SYMBOL_TRADE_EXECUTION TradeExecutionMode(void)           const { return (ENUM_SYMBOL_TRADE_EXECUTION)this.GetProperty(SYMBOL_PROP_TRADE_EXEMODE);  }
   ENUM_SYMBOL_SWAP_MODE SwapMode(void)                           const { return (ENUM_SYMBOL_SWAP_MODE)this.GetProperty(SYMBOL_PROP_SWAP_MODE);            }
   ENUM_DAY_OF_WEEK  SwapRollover3Days(void)                      const { return (ENUM_DAY_OF_WEEK)this.GetProperty(SYMBOL_PROP_SWAP_ROLLOVER3DAYS);        }
   bool              IsMarginHedgedUseLeg(void)                   const { return (bool)this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED_USE_LEG);                 }
   int               ExpirationModeFlags(void)                    const { return (int)this.GetProperty(SYMBOL_PROP_EXPIRATION_MODE);                        }
   int               FillingModeFlags(void)                       const { return (int)this.GetProperty(SYMBOL_PROP_FILLING_MODE);                           }
   int               OrderModeFlags(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_ORDER_MODE);                             }
   ENUM_SYMBOL_ORDER_GTC_MODE OrderModeGTC(void)                  const { return (ENUM_SYMBOL_ORDER_GTC_MODE)this.GetProperty(SYMBOL_PROP_ORDER_GTC_MODE);  }
   ENUM_SYMBOL_OPTION_MODE OptionMode(void)                       const { return (ENUM_SYMBOL_OPTION_MODE)this.GetProperty(SYMBOL_PROP_OPTION_MODE);        }
   ENUM_SYMBOL_OPTION_RIGHT OptionRight(void)                     const { return (ENUM_SYMBOL_OPTION_RIGHT)this.GetProperty(SYMBOL_PROP_OPTION_RIGHT);      }
//--- Real properties
   double            Bid(void)                                    const { return this.GetProperty(SYMBOL_PROP_BID);                                         }
   double            BidHigh(void)                                const { return this.GetProperty(SYMBOL_PROP_BIDHIGH);                                     }
   double            BidLow(void)                                 const { return this.GetProperty(SYMBOL_PROP_BIDLOW);                                      }
   double            Ask(void)                                    const { return this.GetProperty(SYMBOL_PROP_ASK);                                         }
   double            AskHigh(void)                                const { return this.GetProperty(SYMBOL_PROP_ASKHIGH);                                     }
   double            AskLow(void)                                 const { return this.GetProperty(SYMBOL_PROP_ASKLOW);                                      }
   double            Last(void)                                   const { return this.GetProperty(SYMBOL_PROP_LAST);                                        }
   double            LastHigh(void)                               const { return this.GetProperty(SYMBOL_PROP_LASTHIGH);                                    }
   double            LastLow(void)                                const { return this.GetProperty(SYMBOL_PROP_LASTLOW);                                     }
   double            VolumeReal(void)                             const { return this.GetProperty(SYMBOL_PROP_VOLUME_REAL);                                 }
   double            VolumeHighReal(void)                         const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH_REAL);                             }
   double            VolumeLowReal(void)                          const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW_REAL);                              }
   double            OptionStrike(void)                           const { return this.GetProperty(SYMBOL_PROP_OPTION_STRIKE);                               }
   double            Point(void)                                  const { return this.GetProperty(SYMBOL_PROP_POINT);                                       }
   double            TradeTickValue(void)                         const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE);                            }
   double            TradeTickValueProfit(void)                   const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT);                     }
   double            TradeTickValueLoss(void)                     const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS);                       }
   double            TradeTickSize(void)                          const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_SIZE);                             }
   double            TradeContractSize(void)                      const { return this.GetProperty(SYMBOL_PROP_TRADE_CONTRACT_SIZE);                         }
   double            TradeAccuredInterest(void)                   const { return this.GetProperty(SYMBOL_PROP_TRADE_ACCRUED_INTEREST);                      }
   double            TradeFaceValue(void)                         const { return this.GetProperty(SYMBOL_PROP_TRADE_FACE_VALUE);                            }
   double            TradeLiquidityRate(void)                     const { return this.GetProperty(SYMBOL_PROP_TRADE_LIQUIDITY_RATE);                        }
   double            LotsMin(void)                                const { return this.GetProperty(SYMBOL_PROP_VOLUME_MIN);                                  }
   double            LotsMax(void)                                const { return this.GetProperty(SYMBOL_PROP_VOLUME_MAX);                                  }
   double            LotsStep(void)                               const { return this.GetProperty(SYMBOL_PROP_VOLUME_STEP);                                 }
   double            VolumeLimit(void)                            const { return this.GetProperty(SYMBOL_PROP_VOLUME_LIMIT);                                }
   double            SwapLong(void)                               const { return this.GetProperty(SYMBOL_PROP_SWAP_LONG);                                   }
   double            SwapShort(void)                              const { return this.GetProperty(SYMBOL_PROP_SWAP_SHORT);                                  }
   double            MarginInitial(void)                          const { return this.GetProperty(SYMBOL_PROP_MARGIN_INITIAL);                              }
   double            MarginMaintenance(void)                      const { return this.GetProperty(SYMBOL_PROP_MARGIN_MAINTENANCE);                          }
   double            MarginLongInitial(void)                      const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_INITIAL);                         }
   double            MarginBuyStopInitial(void)                   const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL);                     }
   double            MarginBuyLimitInitial(void)                  const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL);                    }
   double            MarginBuyStopLimitInitial(void)              const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL);                }
   double            MarginLongMaintenance(void)                  const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE);                     }
   double            MarginBuyStopMaintenance(void)               const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE);                 }
   double            MarginBuyLimitMaintenance(void)              const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE);                }
   double            MarginBuyStopLimitMaintenance(void)          const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE);            }
   double            MarginShortInitial(void)                     const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_INITIAL);                        }
   double            MarginSellStopInitial(void)                  const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL);                    }
   double            MarginSellLimitInitial(void)                 const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL);                   }
   double            MarginSellStopLimitInitial(void)             const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL);               }
   double            MarginShortMaintenance(void)                 const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE);                    }
   double            MarginSellStopMaintenance(void)              const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE);                }
   double            MarginSellLimitMaintenance(void)             const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE);               }
   double            MarginSellStopLimitMaintenance(void)         const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE);           }
   double            SessionVolume(void)                          const { return this.GetProperty(SYMBOL_PROP_SESSION_VOLUME);                              }
   double            SessionTurnover(void)                        const { return this.GetProperty(SYMBOL_PROP_SESSION_TURNOVER);                            }
   double            SessionInterest(void)                        const { return this.GetProperty(SYMBOL_PROP_SESSION_INTEREST);                            }
   double            SessionBuyOrdersVolume(void)                 const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME);                   }
   double            SessionSellOrdersVolume(void)                const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME);                  }
   double            SessionOpen(void)                            const { return this.GetProperty(SYMBOL_PROP_SESSION_OPEN);                                }
   double            SessionClose(void)                           const { return this.GetProperty(SYMBOL_PROP_SESSION_CLOSE);                               }
   double            SessionAW(void)                              const { return this.GetProperty(SYMBOL_PROP_SESSION_AW);                                  }
   double            SessionPriceSettlement(void)                 const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT);                    }
   double            SessionPriceLimitMin(void)                   const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN);                     }
   double            SessionPriceLimitMax(void)                   const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX);                     }
   double            MarginHedged(void)                           const { return this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED);                               }
   double            NormalizedPrice(const double price)          const;
   double            NormalizedLot(const double volume)           const;
   double            BidLast(void)                                const;
   double            BidLastHigh(void)                            const;
   double            BidLastLow(void)                             const;
   double            AskLast(void)                                const;
   double            AskLastHigh(void)                            const;
   double            AskLastLow(void)                             const;
//--- String properties
   string            Name(void)                                   const { return this.GetProperty(SYMBOL_PROP_NAME);                                        }
   string            Basis(void)                                  const { return this.GetProperty(SYMBOL_PROP_BASIS);                                       }
   string            CurrencyBase(void)                           const { return this.GetProperty(SYMBOL_PROP_CURRENCY_BASE);                               }
   string            CurrencyProfit(void)                         const { return this.GetProperty(SYMBOL_PROP_CURRENCY_PROFIT);                             }
   string            CurrencyMargin(void)                         const { return this.GetProperty(SYMBOL_PROP_CURRENCY_MARGIN);                             }
   string            Bank(void)                                   const { return this.GetProperty(SYMBOL_PROP_BANK);                                        }
   string            Description(void)                            const { return this.GetProperty(SYMBOL_PROP_DESCRIPTION);                                 }
   string            Formula(void)                                const { return this.GetProperty(SYMBOL_PROP_FORMULA);                                     }
   string            ISIN(void)                                   const { return this.GetProperty(SYMBOL_PROP_ISIN);                                        }
   string            Page(void)                                   const { return this.GetProperty(SYMBOL_PROP_PAGE);                                        }
   string            Path(void)                                   const { return this.GetProperty(SYMBOL_PROP_PATH);                                        }
   string            Category(void)                               const { return this.GetProperty(SYMBOL_PROP_CATEGORY);                                    }
   string            Exchange(void)                               const { return this.GetProperty(SYMBOL_PROP_EXCHANGE);                                    }
   
//+------------------------------------------------------------------+


Wir haben bereits die drei ähnlichen Methoden für den Angebotspreis, wenn auch ohne die Prüfung der Preispräsenz. Ändern wir es:

//+------------------------------------------------------------------+
//| Return Bid or Last price                                         |
//| depending on the chart construction method and price availability|
//+------------------------------------------------------------------+
double CSymbol::BidLast(void) const
  {
   return
     (
      this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetProperty(SYMBOL_PROP_BID)  : 
     (this.GetProperty(SYMBOL_PROP_BID)==0    ? this.GetProperty(SYMBOL_PROP_LAST) : this.GetProperty(SYMBOL_PROP_BID))
     );
  }  
//+------------------------------------------------------------------+
//| Return maximum Bid or Last price for a day                       |
//| depending on the chart construction method and price availability|
//+------------------------------------------------------------------+
double CSymbol::BidLastHigh(void) const
  {
   return
     (
      this.ChartMode()==SYMBOL_CHART_MODE_BID   ? this.GetProperty(SYMBOL_PROP_BIDHIGH)   : 
     (this.GetProperty(SYMBOL_PROP_BIDHIGH)==0  ? this.GetProperty(SYMBOL_PROP_LASTHIGH)  : this.GetProperty(SYMBOL_PROP_BIDHIGH))
     );
  }  
//+------------------------------------------------------------------+
//| Return minimum Bid or Last price for a day                       |
//| depending on the chart construction method and price availability|
//+------------------------------------------------------------------+
double CSymbol::BidLastLow(void) const
  {
   return
     (
      this.ChartMode()==SYMBOL_CHART_MODE_BID   ? this.GetProperty(SYMBOL_PROP_BIDLOW)  : 
     (this.GetProperty(SYMBOL_PROP_BIDLOW)==0   ? this.GetProperty(SYMBOL_PROP_LASTLOW) : this.GetProperty(SYMBOL_PROP_BIDLOW))
     );
  }
//+------------------------------------------------------------------+


Wie oben erwähnt, überprüfen wir hier die Art der Chartkonstruktion. Wenn das Chart auf Bid-Preisen basiert, geben wir die entsprechenden Bid-Preise zurück. Wenn das Chart auf den letzten Preisen basiert, prüfen wir bei einer zurückgegebenen Symboleigenschaft zusätzlich den Bid-Preis auf Null. Ist er gleich Null, verwenden wir den entsprechenden Letztpreis, andernfalls den entsprechenden Bid-Preis.

Schreiben wir dieselbe Implementierung für die Methoden, die den Ask-Preis zurückgeben:

//+------------------------------------------------------------------+
//| Return Ask or Last price                                         |
//| depending on the chart construction method and price availability|
//+------------------------------------------------------------------+
double CSymbol::AskLast(void) const
  {
   return
     (
      this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetProperty(SYMBOL_PROP_ASK)  : 
     (this.GetProperty(SYMBOL_PROP_ASK)==0    ? this.GetProperty(SYMBOL_PROP_LAST) : this.GetProperty(SYMBOL_PROP_ASK))
     );
  }  
//+------------------------------------------------------------------+
//| Return maximum Ask or Last price for a day                       |
//| depending on the chart construction method and price availability|
//+------------------------------------------------------------------+
double CSymbol::AskLastHigh(void) const
  {
   return
     (
      this.ChartMode()==SYMBOL_CHART_MODE_BID   ? this.GetProperty(SYMBOL_PROP_ASKHIGH)   : 
     (this.GetProperty(SYMBOL_PROP_ASKHIGH)==0  ? this.GetProperty(SYMBOL_PROP_LASTHIGH)  : this.GetProperty(SYMBOL_PROP_ASKHIGH))
     );
  }  
//+------------------------------------------------------------------+
//| Return minimum Ask or Last price for a day                       |
//| depending on the chart construction method and price availability|
//+------------------------------------------------------------------+
double CSymbol::AskLastLow(void) const
  {
   return
     (
      this.ChartMode()==SYMBOL_CHART_MODE_BID   ? this.GetProperty(SYMBOL_PROP_ASKLOW)  : 
     (this.GetProperty(SYMBOL_PROP_ASKLOW)==0   ? this.GetProperty(SYMBOL_PROP_LASTLOW) : this.GetProperty(SYMBOL_PROP_ASKLOW))
     );
  }
//+------------------------------------------------------------------+


Dies sind die Methoden, die in der Bibliothek bei der Berechnung des Preisniveaus für die Erlangung von "Ask"- oder "Last"-Preisen sowie von "Bid"- oder "Last"-Preisen zu verwenden sind.

Bei der Darstellung von Nachrichten über Handelsereignisse im Journal gibt es nun zusätzliche Notationen für die Magicnummer-IDs und zwei Gruppen, vorausgesetzt, dass zusätzliche Daten im Wert der Magicnummer gespeichert sind (im vorherigen Artikel implementiert). Wenn die Magicnummer jedoch auch die ID der schwebenden Anfrage enthält, wurde sie im Journal nicht angezeigt. Bringen wir das in Ordnung. Fügen wir ein paar Zeichenfolgen zur entsprechenden kurzen Ereignisbeschreibungsmethode jeder der Ereignisklassen in den Dateien EventModify.mqh, EventOrderPlaced.mqh, EventOrderRemoved.mqh, EventPositionClose.mqh und EventPositionOpen.mqh hinzu.
Ersetzen wir die folgende Zeichenfolge in jeder der Dateien:

string magic=(this.Magic()!=0 ? ", "+CMessage::Text(MSG_ORD_MAGIC)+" "+(string)this.Magic()+magic_id+group_id1+group_id2 : "");


mit folgender Zeichenkette:

string pend_req_id=(this.GetPendReqID()>0 ? ", ID: "+(string)this.GetPendReqID() : "");
string magic=(this.Magic()!=0 ? ", "+CMessage::Text(MSG_ORD_MAGIC)+" "+(string)this.Magic()+magic_id+group_id1+group_id2+pend_req_id : "");


Daher haben wir die Beschreibung der ausstehenden Ereignis-ID (falls vorhanden) der Beschreibung der magischen Zahl hinzugefügt.

Fügen wir die Methoden, die die Beschreibungen der Felder der Handelsanforderungsstruktur MqlTradeRequest zurückgeben, dem 'public' Abschnitt der Handelsobjektklasse CTradeObj des Symbols in der Datei TradeObj.mqh hinzu:

//--- Return the description of the (1) executed action type, (2) magic number, (3) order ticket, (4) volume,
//--- (5) open, (6) StopLimit order, (7) StopLoss, (8) TakeProfit price, (9) deviation,
//--- type of (10) order, (11) execution, (12) lifetime, (13) order expiration date,
//--- (14) comment, (15) position ticket, (16) opposite position ticket
   string                     GetRequestActionDescription(void)                  const { return RequestActionDescription(this.m_request);       }
   string                     GetRequestMagicDescription(void)                   const { return RequestMagicDescription(this.m_request);        }
   string                     GetRequestOrderDescription(void)                   const { return RequestOrderDescription(this.m_request);        }
   string                     GetRequestSymbolDescription(void)                  const { return RequestSymbolDescription(this.m_request);       }
   string                     GetRequestVolumeDescription(void)                  const { return RequestVolumeDescription(this.m_request);       }
   string                     GetRequestPriceDescription(void)                   const { return RequestPriceDescription(this.m_request);        }
   string                     GetRequestStopLimitDescription(void)               const { return RequestStopLimitDescription(this.m_request);    }
   string                     GetRequestStopLossDescription(void)                const { return RequestStopLossDescription(this.m_request);     }
   string                     GetRequestTakeProfitDescription(void)              const { return RequestTakeProfitDescription(this.m_request);   }
   string                     GetRequestDeviationDescription(void)               const { return RequestDeviationDescription(this.m_request);    }
   string                     GetRequestTypeDescription(void)                    const { return RequestTypeDescription(this.m_request);         }
   string                     GetRequestTypeFillingDescription(void)             const { return RequestTypeFillingDescription(this.m_request);  }
   string                     GetRequestTypeTimeDescription(void)                const { return RequestTypeTimeDescription(this.m_request);     }
   string                     GetRequestExpirationDescription(void)              const { return RequestExpirationDescription(this.m_request);   }
   string                     GetRequestCommentDescription(void)                 const { return RequestCommentDescription(this.m_request);      }
   string                     GetRequestPositionDescription(void)                const { return RequestPositionDescription(this.m_request);     }
   string                     GetRequestPositionByDescription(void)              const { return RequestPositionByDescription(this.m_request);   }

//--- Positionseröffnung


Die Methoden rufen einfach die entsprechenden Funktionen auf, die wir zuvor in der Datei der Bibliotheksdienstfunktionen erstellt haben.

Bisher habe ich übersehen, dass den Methoden zur Eröffnung der Positionen der Typ der Auftragsausführung übergeben werden muss.
Fügen wir diesen Parameter der Deklaration der Methode, die die Klassenpositionen öffnet, hinzu:

//--- Positionseröffnung
   bool                       OpenPosition(const ENUM_POSITION_TYPE type,
                                           const double volume,
                                           const double sl=0,
                                           const double tp=0,
                                           const ulong magic=ULONG_MAX,
                                           const string comment=NULL,
                                           const ulong deviation=ULONG_MAX,
                                           const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);


und der Implementation der Methode:

//+------------------------------------------------------------------+
//| Open a position                                                  |
//+------------------------------------------------------------------+
bool CTradeObj::OpenPosition(const ENUM_POSITION_TYPE type,
                             const double volume,
                             const double sl=0,
                             const double tp=0,
                             const ulong magic=ULONG_MAX,
                             const string comment=NULL,
                             const ulong deviation=ULONG_MAX,
                             const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {


Da ich in Zukunft die Möglichkeit des Handels mit schwebenden Anfragen einführen werde, habe ich das Konzept eines Typs von schwebenden Anfragen eingeführt.

In der Datei der Handelsklassen Trading.mqh (nämlich in der Klasse der schwebenden Anfragen CPendingReq ), fügen wir die Klassenvariablen zum 'private' Abschnitt hinzu, um den schwebenden Anfragetyp zu speichern:

//+------------------------------------------------------------------+
//| 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


Im Abschnitt der 'public' Klasse fügen wir die Methode hinzu, die den Server-Rückgabecode zurückgibt, auf dem die schwebende Anfrage basiert, die Methoden, die die Beschreibungen der Eigenschaften der schwebenden Anfrage zurückgeben und den Anfragetyp, sowie die Methode, die alle Daten der Handelsanfrage an die Zeitschrift zurückgibt:

public:
//--- Return (1) the 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
   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;         }
//--- 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) request ID
   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;                  }
   
//--- 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);
  };
//+------------------------------------------------------------------+


Die Methoden, die die Beschreibungen der Objekteigenschaften der schwebenden Anfrage zurückgeben, erzeugen einfach eine zusammengesetzte Beschreibung aus dem Kopf, der die Eigenschaft beschreibt, und ihren Wert. Die Methode Type(), die den Typ der schwebenden Anfrage zurückgibt, wird virtuell gemacht, da dieselbe virtuelle Methode bereits definiert wurde für das Basisobjekt COObjekt, von dem das ausstehende Anforderungsobjekt abgeleitet ist. Um die Rückgabe des abgeleiteten Objekttyps zu implementieren, sollte die Methode im abgeleiteten Objekt neu definiert werden. Genau das habe ich getan, und jetzt gibt diese Methode den in der Klasse der schwebenden Anfrage definierten Variablenwert m_type zurück.

Setzen wir im Klassenkonstruktor den Wert für einen schwebenden Anfragetyp :

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+


Da schwebenden Anfragen durch einen Server-Return-Code und eine Programmanforderung erzeugt werden, reicht es aus, den Server-Antwortcode zu kennen, um den Typ einer schwebenden Anfrage zu definieren. Genau das tun wir hier: Wenn der Rückgabecode größer als Null ist (der Server hat einen Fehler zurückgegeben), ist diese Anfrage durch den Server-Rückgabecode erzeugt worden. Wenn der Code Null ist, wurde ein schwebendes Anfrageobjekt durch eine Programmanforderung erzeugt.

Verbessern Sie die virtuelle Methode Compare() des schwebenden Anfrageobjekts.
Bisher wurden Objekte immer nach einer einzigen Eigenschaft verglichen — der Anforderungs-ID:

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


Nach der Einführung der Typen von schwebenden Anfragen müssen wir die Objekte nach zwei Eigenschaften vergleichen — ID und Typ.
Um dies zu implementieren, ändern wir die Methode zum Vergleich zweier Objekte:

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


Die verglichenen Eigenschaften der Variable mode werden hier ausgewählt. Wenn 0, werden die Objekte mit IDs verglichen. Wenn nicht 0, werden sie nach Typen der Objekte verglichen.

Ebenfalls jenseits des Klassenkörpers schreiben wir die Methode, die die vollständige Beschreibung aller ausstehenden Anforderungsobjekteigenschaften anzeigt, in das Journal:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+


In der Methode werden die Beschreibungen aller Objekteigenschaften in String-Variablen gesammelt, einschließlich der Feldbeschreibungen für die Struktur der Handelsanfrage des Objekts. Die Anzahl der angezeigten Daten hängt von der Art der Aktion in der Handelsanforderung ab, da verschiedene Aktionen eine unterschiedliche Anzahl von Feldern der Struktur der Handelsanforderung erfordern. Daher wird der Wert des Feldes 'action' überprüft und nur die entsprechenden Felder angezeigt. Die Beschreibung der Objektvariablen wird zuerst angezeigt, gefolgt von der Beschreibung der Felder der Anforderungsstruktur. Somit werden alle Objekteigenschaften der schwebenden Anfragen im Journal entsprechend dem Handelsaktionstyp (Aktion) der Anfrage angezeigt.

Zuvor haben wir die zusätzliche Eigenschaft — Typ der Auftragsfüllung — zur Positionseröffnungsmethode in der Klasse CTradeObj hinzugefügt.
Jetzt fügen wir die gleiche Eigenschaft zur Definition der Methode zur Eröffnung einer privaten Position in der Klasse CTrading hinzu:

//--- (1) Open a position, (2) place a pending order
   template<typename SL,typename TP> 
   bool                 OpenPosition(const ENUM_POSITION_TYPE type,
                                    const double volume,
                                    const string symbol,
                                    const ulong magic=ULONG_MAX,
                                    const SL sl=0,
                                    const TP tp=0,
                                    const string comment=NULL,
                                    const ulong deviation=ULONG_MAX,
                                    const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);


Fügen wir die gleichen Eigenschaften zur Definition der Methoden zur Eröffnung öffentlicher Kauf- und Verkaufspositionen hinzu:

//--- Open (1) Buy, (2) Sell position
   template<typename SL,typename TP> 
   bool                 OpenBuy(const double volume,
                                const string symbol,
                                const ulong magic=ULONG_MAX,
                                const SL sl=0,
                                const TP tp=0,
                                const string comment=NULL,
                                const ulong deviation=ULONG_MAX,
                                const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);
   
   template<typename SL,typename TP> 
   bool                 OpenSell(const double volume,
                                 const string symbol,
                                 const ulong magic=ULONG_MAX,
                                 const SL sl=0,
                                 const TP tp=0,
                                 const string comment=NULL,
                                 const ulong deviation=ULONG_MAX,
                                 const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);


Fügen wir außerdem die gleichen Parameter hinzu, wenn diese Methoden außerhalb des Klassenkörpers implementiert werden:

//+------------------------------------------------------------------+
//| Open a position                                                  |
//+------------------------------------------------------------------+
template<typename SL,typename TP> 
bool CTrading::OpenPosition(const ENUM_POSITION_TYPE type,
                            const double volume,
                            const string symbol,
                            const ulong magic=ULONG_MAX,
                            const SL sl=0,
                            const TP tp=0,
                            const string comment=NULL,
                            const ulong deviation=ULONG_MAX,
                            const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {

//+------------------------------------------------------------------+
//| Open Buy position                                                |
//+------------------------------------------------------------------+
template<typename SL,typename TP> 
bool CTrading::OpenBuy(const double volume,
                       const string symbol,
                       const ulong magic=ULONG_MAX,
                       const SL sl=0,
                       const TP tp=0,
                       const string comment=NULL,
                       const ulong deviation=ULONG_MAX,
                       const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
//--- Return the result of sending a trading request from the OpenPosition() method
   return this.OpenPosition(POSITION_TYPE_BUY,volume,symbol,magic,sl,tp,comment,deviation,type_filling);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Open a Sell position                                             |
//+------------------------------------------------------------------+
template<typename SL,typename TP> 
bool CTrading::OpenSell(const double volume,
                        const string symbol,
                        const ulong magic=ULONG_MAX,
                        const SL sl=0,
                        const TP tp=0,
                        const string comment=NULL,
                        const ulong deviation=ULONG_MAX,
                        const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
//--- Return the result of sending a trading request from the OpenPosition() method
   return this.OpenPosition(POSITION_TYPE_SELL,volume,symbol,magic,sl,tp,comment,deviation,type_filling);
  }
//+------------------------------------------------------------------+


In der 'private' Sektion der Klasse deklarieren wir die Methode, die den Objektindex der Anfrage in der Liste nach der ID zurückgibt:

//--- Look for the first free pending request ID
   int                  GetFreeID(void);
//--- Return the request object index in the list by ID
   int                  GetIndexPendingRequestByID(const uchar id);

public:


Ich habe die Implementierung des Klassenzeitgebers leicht geändert.
Unten ist der vollständige Timer-Implementierungscode mit der in den Kommentaren beschriebenen Logik:

//+------------------------------------------------------------------+
//| Timer                                                            |
//+------------------------------------------------------------------+
void CTrading::OnTimer(void)
  {
   //--- In a loop by the list of pending requests
   int total=this.m_list_request.Total();
   for(int i=total-1;i>WRONG_VALUE;i--)
     {
      //--- receive the next request object
      CPendingReq *req_obj=this.m_list_request.At(i);
      if(req_obj==NULL)
         continue;
      
      //--- get the request structure and the symbol object a trading operation should be performed for
      MqlTradeRequest request=req_obj.MqlRequest();
      CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(request.symbol);
      if(symbol_obj==NULL || !symbol_obj.RefreshRates())
         continue;
      
      //--- if the current attempt exceeds the defined number of trading attempts,
      //--- or the current time exceeds the waiting time of all attempts
      //--- remove the current request object and move on to the next one
      if(req_obj.CurrentAttempt()>req_obj.TotalAttempts() || req_obj.CurrentAttempt()>=UCHAR_MAX || 
         (long)symbol_obj.Time()>long(req_obj.TimeCreate()+req_obj.WaitingMSC()*req_obj.TotalAttempts()))
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
           {
            ::Print(CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_DELETED));
            req_obj.Print();
           }
         this.m_list_request.Delete(i);
         continue;
        }
      
      //--- Get the pending request ID
      uchar id=this.GetPendReqID((uint)request.magic);
      //--- Get the list of orders/positions containing the order/position with the pending request ID
      CArrayObj *list=this.m_market.GetList(ORDER_PROP_PEND_REQ_ID,id,EQUAL);
      if(::CheckPointer(list)==POINTER_INVALID)
         continue;
      //--- If the order/position is present, the request is handled: remove it and proceed to the next
      if(list.Total()>0)
        {
         this.m_list_request.Delete(i);
         continue;
        }

      //--- Set the request activation time in the request object
      req_obj.SetTimeActivate(req_obj.TimeCreate()+req_obj.WaitingMSC()*(req_obj.CurrentAttempt()+1));
      
      //--- If the current time is less than the request activation time,
      //--- this is not the request time - move on to the next request in the list
      if((long)symbol_obj.Time()<(long)req_obj.TimeActivate())
         continue;
      
      //--- Set the attempt number in the request object
      req_obj.SetCurrentAttempt(uchar(req_obj.CurrentAttempt()+1));
      
      //--- Display the number of the trading attempt in the journal
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(CMessage::Text(MSG_LIB_TEXT_RE_TRY_N)+(string)req_obj.CurrentAttempt());
      
      //--- Depending on the type of action performed in the trading request 
      switch(request.action)
        {
         //--- Positionseröffnung
         case TRADE_ACTION_DEAL :
            this.OpenPosition((ENUM_POSITION_TYPE)request.type,request.volume,request.symbol,request.magic,request.sl,request.tp,request.comment,request.deviation,request.type_filling);
            break;
         //--- Place a pending order
         case TRADE_ACTION_PENDING :
            this.PlaceOrder(request.type,request.volume,request.symbol,request.price,request.stoplimit,request.sl,request.tp,request.magic,request.comment,request.expiration,request.type_time,request.type_filling);
            break;
         //---
         default:
            break;
        }
     }
  }
//+------------------------------------------------------------------+


Ich hoffe, hier ist alles klar.

In der Fehlerkorrekturmethode RequestErrorsCorrecting() fügen wir die Korrektur des Ablauftyps bei Erhalt des Fehlers "ungültige Verfallszeit" (nur ein Teil des Codes mit Korrekturen):

//--- The specified type of order execution by balance is not supported
   if(this.IsPresentErorCode(10030))
      request.type_filling=symbol_obj.GetCorrectTypeFilling();
//--- Invalid order expiration in a request -
   if(this.IsPresentErorCode(10022))
     {
      //--- Set a correct order expiration type
      request.type_time=symbol_obj.GetCorrectTypeExpiration();
      //--- if the expiration type is not supported as set by the expiration date and the expiration data is defined, reset the expiration date
      if(!symbol_obj.IsExpirationModeSpecified() && request.expiration>0)
         request.expiration=0;
     }
//--- View the list of remaining errors and correct trading request parameters


Zuvor haben wir dem Symbolobjekt die neuen Methoden zur Erlangung von Ask-Preisen hinzugefügt und die Methoden zur Erlangung von Bid-Preisen angepasst. Jetzt müssen wir alle Vorkommen der Zeichenfolgen "Ask()" und "Bid()" in dem gesamten aufgelisteten Code durch "AskLast()" bzw. "BidLast()" ersetzen. Die bequemste Art, dies zu tun, ist die Anwendung der Such- und Ersetzungsfunktion (Strg+H) über den gesamten Code. Daher werden wir die automatische Auswahl geeigneter Preise überall dort verwenden, wo wir die Ask- und Bid-Preise der Symbolobjekte benötigen.

Zum Beispiel sieht die Methode zur Festlegung des Angebotspreises jetzt wie folgt aus mit den ersetzten Preisen:

//+------------------------------------------------------------------+
//| Set trading request prices                                       |
//+------------------------------------------------------------------+
template <typename PS,typename SL,typename TP,typename PL> 
bool CTrading::SetPrices(const ENUM_ORDER_TYPE action,const PS price,const SL sl,const TP tp,const PL limit,const string source_method,CSymbol *symbol_obj)
  {
//--- Reset prices
   ::ZeroMemory(this.m_request);
//--- Update all data by symbol
   if(!symbol_obj.RefreshRates())
     {
      this.AddErrorCodeToList(10021);  // No quotes to handle the request
      return false;
     }
//--- Open/close price
   if(price>0)
     {
      //--- price parameter type (double) - normalize the price up to Digits(), since the price has been passed
      if(typename(price)=="double")
         this.m_request.price=::NormalizeDouble(price,symbol_obj.Digits());
      //--- price parameter type (int) - the distance has been passed
      else if(typename(price)=="int" || typename(price)=="uint" || typename(price)=="long" || typename(price)=="ulong")
        {
         //--- Calculate the order price
         switch((int)action)
           {
            //--- Pending order
            case ORDER_TYPE_BUY_LIMIT       :   this.m_request.price=::NormalizeDouble(symbol_obj.AskLast()-price*symbol_obj.Point(),symbol_obj.Digits()); break;
            case ORDER_TYPE_BUY_STOP        :
            case ORDER_TYPE_BUY_STOP_LIMIT  :   this.m_request.price=::NormalizeDouble(symbol_obj.AskLast()+price*symbol_obj.Point(),symbol_obj.Digits()); break;
            
            case ORDER_TYPE_SELL_LIMIT      :   this.m_request.price=::NormalizeDouble(symbol_obj.BidLast()+price*symbol_obj.Point(),symbol_obj.Digits()); break;
            case ORDER_TYPE_SELL_STOP       :
            case ORDER_TYPE_SELL_STOP_LIMIT :   this.m_request.price=::NormalizeDouble(symbol_obj.BidLast()-price*symbol_obj.Point(),symbol_obj.Digits()); break;
            //--- Default - current position open prices
            default  :  this.m_request.price=
              (
               this.DirectionByActionType((ENUM_ACTION_TYPE)action)==ORDER_TYPE_BUY ? ::NormalizeDouble(symbol_obj.AskLast(),symbol_obj.Digits()) : 
               ::NormalizeDouble(symbol_obj.BidLast(),symbol_obj.Digits())
              ); break;
           }
        }
      //--- unsupported price types - display the message and return 'false'
      else
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_UNSUPPORTED_PR_TYPE));
         return false;
        }
     }
   //--- If no price is specified, use the current prices
   else
     {
      this.m_request.price=
        (
         this.DirectionByActionType((ENUM_ACTION_TYPE)action)==ORDER_TYPE_BUY ? 
         ::NormalizeDouble(symbol_obj.AskLast(),symbol_obj.Digits())          : 
         ::NormalizeDouble(symbol_obj.BidLast(),symbol_obj.Digits())
        );
     }
   
//--- StopLimit order price or distance
   if(limit>0)
     {
      //--- limit order price parameter type (double) - normalize the price up to Digits(), since the price has been passed
      if(typename(limit)=="double")
         this.m_request.stoplimit=::NormalizeDouble(limit,symbol_obj.Digits());
      //--- limit order price parameter type (int) - the distance has been passed
      else if(typename(limit)=="int" || typename(limit)=="uint" || typename(limit)=="long" || typename(limit)=="ulong")
        {
         //--- Calculate a limit order price
         if(this.DirectionByActionType((ENUM_ACTION_TYPE)action)==ORDER_TYPE_BUY)
            this.m_request.stoplimit=::NormalizeDouble(this.m_request.price-limit*symbol_obj.Point(),symbol_obj.Digits());
         else
            this.m_request.stoplimit=::NormalizeDouble(this.m_request.price+limit*symbol_obj.Point(),symbol_obj.Digits());
        }
      //--- unsupported limit order price types - display the message and return 'false'
      else
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_UNSUPPORTED_PL_TYPE));
         return false;
        }
     }  
     
//--- Order price stop order prices are calculated from
   double price_open=
     (
      (action==ORDER_TYPE_BUY_STOP_LIMIT || action==ORDER_TYPE_SELL_STOP_LIMIT) && limit>0 ? this.m_request.stoplimit : this.m_request.price
     );
     
//--- StopLoss
   if(sl>0)
     {
      //--- StopLoss parameter type (double) - normalize the price up to Digits(), since the price has been passed
      if(typename(sl)=="double")
         this.m_request.sl=::NormalizeDouble(sl,symbol_obj.Digits());
      //--- StopLoss parameter type (int) - calculate the placement distance
      else if(typename(sl)=="int" || typename(sl)=="uint" || typename(sl)=="long" || typename(sl)=="ulong")
        {
         //--- Calculate the StopLoss price
         if(this.DirectionByActionType((ENUM_ACTION_TYPE)action)==ORDER_TYPE_BUY)
            this.m_request.sl=::NormalizeDouble(price_open-sl*symbol_obj.Point(),symbol_obj.Digits());
         else
            this.m_request.sl=::NormalizeDouble(price_open+sl*symbol_obj.Point(),symbol_obj.Digits());
        }
      //--- unsupported StopLoss types - display the message and return 'false'
      else
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_UNSUPPORTED_SL_TYPE));
         return false;
        }
     }
     
//--- TakeProfit
   if(tp>0)
     {
      //--- TakeProfit parameter type (double) - normalize the price up to Digits(), since the price has been passed
      if(typename(tp)=="double")
         this.m_request.tp=::NormalizeDouble(tp,symbol_obj.Digits());
      //--- TakeProfit parameter type (int) - calculate the placement distance
      else if(typename(tp)=="int" || typename(tp)=="uint" || typename(tp)=="long" || typename(tp)=="ulong")
        {
         if(this.DirectionByActionType((ENUM_ACTION_TYPE)action)==ORDER_TYPE_BUY)
            this.m_request.tp=::NormalizeDouble(price_open+tp*symbol_obj.Point(),symbol_obj.Digits());
         else
            this.m_request.tp=::NormalizeDouble(price_open-tp*symbol_obj.Point(),symbol_obj.Digits());
        }
      //--- unsupported TakeProfit types - display the message and return 'false'
      else
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_UNSUPPORTED_TP_TYPE));
         return false;
        }
     }
      
//--- All prices are recorded
   return true;
  }
//+------------------------------------------------------------------+


Es hat keinen Sinn, hier alle Codezeilen mit den durchgeführten Ersetzungen anzuzeigen. Sie sind alle bereits korrigiert und unten angehängt.

Bei der Implementierung der privaten Methode für die Platzierung einer Pending Order fügen Sie den Block für die Erstellung einer Pending Trading Order für den Fall eines Serverfehlers hinzu:

//+------------------------------------------------------------------+
//| Place a pending order                                            |
//+------------------------------------------------------------------+
template<typename PS,typename PL,typename SL,typename TP>
bool CTrading::PlaceOrder(const ENUM_ORDER_TYPE order_type,
                          const double volume,
                          const string symbol,
                          const PS price_stop,
                          const PL price_limit=0,
                          const SL sl=0,
                          const TP tp=0,
                          const ulong magic=ULONG_MAX,
                          const string comment=NULL,
                          const datetime expiration=0,
                          const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                          const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   bool res=true;
   this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR;
   ENUM_ACTION_TYPE action=(ENUM_ACTION_TYPE)order_type;
//--- Get a symbol object by a symbol name
   CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol);
   if(symbol_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return false;
     }
//--- Get a trading object from a symbol object
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false; 
     }
//--- Set the prices
//--- If failed to set - write the "internal error" flag, set the error code in the return structure,
//--- display the message in the journal and return 'false'
   if(!this.SetPrices(order_type,price_stop,sl,tp,price_limit,DFUN,symbol_obj))
     {
      this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR;
      trade_obj.SetResultRetcode(10021);
      trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(10021));   // No quotes to process the request
      return false;
     }
     
//--- In case of trading limitations, funds insufficiency,
//--- there are limitations on StopLevel - play the error sound and exit
   this.m_request.volume=volume;
   this.m_request.type_filling=type_filling;
   this.m_request.type_time=type_time;
   this.m_request.expiration=expiration;
   ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(this.m_request.volume,
                                                             this.m_request.price,
                                                             action,
                                                             order_type,
                                                             symbol_obj,
                                                             trade_obj,
                                                             DFUN,
                                                             this.m_request.stoplimit,
                                                             this.m_request.sl,
                                                             this.m_request.tp);
   if(method!=ERROR_CODE_PROCESSING_METHOD_OK)
     {
      //--- If trading is completely disabled
      if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE)
        {
         trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE);
         trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type);
         return false;
        }
      //--- If the check result is "abort trading operation" - set the last error code to the return structure,
      //--- display a journal message, play the error sound and exit
      if(method==ERROR_CODE_PROCESSING_METHOD_EXIT)
        {
         int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
         if(code!=NULL)
           {
            trade_obj.SetResultRetcode(code);
            trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
           }
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED));
         if(this.IsUseSounds())
            trade_obj.PlaySoundError(action,order_type);
         return false;
        }
      //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal
      if(method==ERROR_CODE_PROCESSING_METHOD_WAIT)
        {
         int code=this.m_list_errors.At(this.m_list_errors.Total()-1);
         if(code!=NULL)
           {
            trade_obj.SetResultRetcode(code);
            trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode()));
           }
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_CREATE_PENDING_REQUEST));
         //--- Instead of creating a pending request, we temporarily wait the required time period (the CheckErrors() method result is returned)
         ::Sleep(method);           
         symbol_obj.Refresh();
        }
      //--- If the check result is "create a pending request", do nothing temporarily
      if(this.m_err_handling_behavior==ERROR_HANDLING_BEHAVIOR_PENDING_REQUEST)
        {
         if(this.m_log_level>LOG_LEVEL_NO_MSG)
            ::Print(CMessage::Text(MSG_LIB_TEXT_CREATE_PENDING_REQUEST));
        }
     }

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


Ich glaube, dass alle Maßnahmen im Zusammenhang mit der Entwicklung des anhängigen Antrags in den Kommentaren zum Kodex beschrieben werden und leicht verständlich sind. In jedem Fall können Sie gerne den Abschnitt Kommentare verwenden.

Um das Debuggen in der Methode zur Erzeugung des Objekts der schwebenden Anfragen zu vereinfachen (d.h. um das Ergebnis der Erzeugung einer schwebenden Anfrage sehen zu können), ergänzen wir die Darstellung der Eigenschaften einer neu erzeugten Anforderung im Journal:

//+------------------------------------------------------------------+
//| Create a pending request                                         |
//+------------------------------------------------------------------+
bool CTrading::CreatePendingRequest(const uchar id,const uchar attempts,const ulong wait,const MqlTradeRequest &request,const int retcode,CSymbol *symbol_obj)
  {
   //--- Create a new pending request object
   CPendingReq *req_obj=new CPendingReq(id,symbol_obj.BidLast(),symbol_obj.Time(),request,retcode);
   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);
   
   if(this.m_log_level>LOG_LEVEL_NO_MSG)
     {
      ::Print(CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_CREATED)," #",req_obj.ID(),":");
      req_obj.Print();
     }
   
   return true;
  }
//+------------------------------------------------------------------+


Ganz am Ende der Auflistung der Handelsklassen implementieren wir die Methode, die den Index des Anforderungsobjekts in der Liste nach ID zurückgibt:

//+------------------------------------------------------------------+
//| Return the request object index in the list by ID                |
//+------------------------------------------------------------------+
int CTrading::GetIndexPendingRequestByID(const uchar id)
  {
   CPendingReq *req=new CPendingReq();
   if(req==NULL)
      return WRONG_VALUE;
   req.SetID(id);
   this.m_list_request.Sort();
   int index=this.m_list_request.Search(req);
   delete req;
   return index;
  }
//+------------------------------------------------------------------+

Die Methode erhält die notwendige ID, ein temporäres Anfrageobjekt wird erzeugt und die der Methode übergebene ID wird dafür gesetzt.

Als Nächstes wird das Flag für sortierte Liste für die Liste mit Anfrageobjekten gesetzt. Standardmäßig ist der Sortiermodus gleich Null. Dies ist der Modus, der verwendet wird, um die Objekte nach der ID in der virtuellen Methode Compare() der Klasse CPendingReq zu vergleichen. Daher ist es nun möglich, die Objektsuchmethode Search() im dynamischen Array von Pointern auf Objekte zu verwenden. Die Methode gibt den erhaltenen Objektindex in der Liste zurück oder -1, wenn das Objekt nicht gefunden wurde. Bevor die Methode verlassen wird, entfernt das temporäre Anforderungsobjekt und gibt den erhaltenen Index des gefundenen Objekts oder -1 zurück.

Jetzt müssen wir nur noch die Basisobjektklasse der Bibliothek CEngine um einen zusätzlichen Parameter ergänzen, der die Art der Auftragsfüllung angibt. Der Parameter wird zu den Definitionen der Klassenmethoden für das Senden von Handelsanfragen hinzugefügt.

//--- Open (1) Buy, (2) Sell position
   template<typename SL,typename TP>
   bool                 OpenBuy(const double volume,
                                 const string symbol,
                                 const ulong magic=ULONG_MAX,
                                 SL sl=0,
                                 TP tp=0,
                                 const string comment=NULL,
                                 const ulong deviation=ULONG_MAX,
                                 const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);
   template<typename SL,typename TP>
   bool                 OpenSell(const double volume,
                                 const string symbol,
                                 const ulong magic=ULONG_MAX,
                                 SL sl=0,
                                 TP tp=0,
                                 const string comment=NULL,
                                 const ulong deviation=ULONG_MAX,
                                 const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);

//--- Set (1) BuyStop, (2) BuyLimit, (3) BuyStopLimit pending order
   template<typename PR,typename SL,typename TP>
   bool                 PlaceBuyStop(const double volume,
                                     const string symbol,
                                     const PR price,
                                     const SL sl=0,
                                     const TP tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                                     const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);
   template<typename PR,typename SL,typename TP>
   bool                 PlaceBuyLimit(const double volume,
                                     const string symbol,
                                     const PR price,
                                     const SL sl=0,
                                     const TP tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                                     const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);
   template<typename PR,typename PL,typename SL,typename TP>
   bool                 PlaceBuyStopLimit(const double volume,
                                     const string symbol,
                                     const PR price_stop,
                                     const PL price_limit,
                                     const SL sl=0,
                                     const TP tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                                     const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);
//--- Set (1) SellStop, (2) SellLimit, (3) SellStopLimit pending order
   template<typename PR,typename SL,typename TP>
   bool                 PlaceSellStop(const double volume,
                                     const string symbol,
                                     const PR price,
                                     const SL sl=0,
                                     const TP tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                                     const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);
   template<typename PR,typename SL,typename TP>
   bool                 PlaceSellLimit(const double volume,
                                     const string symbol,
                                     const PR price,
                                     const SL sl=0,
                                     const TP tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                                     const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);
   template<typename PR,typename PL,typename SL,typename TP>
   bool                 PlaceSellStopLimit(const double volume,
                                     const string symbol,
                                     const PR price_stop,
                                     const PL price_limit,
                                     const SL sl=0,
                                     const TP tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                                     const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);


Wenn der Standardwert -1 ist, werden die korrekten Werte der Auftragsfüllarten von Symbolhandelsobjekten übernommen, mit denen ein Handelsvorgang durchgeführt werden soll.

Fügen wir die gleichen Parameter zu den Implementierungscodes dieser Handelsmethoden hinzu:

//+------------------------------------------------------------------+
//| Open Buy position                                                |
//+------------------------------------------------------------------+
template<typename SL,typename TP>
bool CEngine::OpenBuy(const double volume,
                      const string symbol,
                      const ulong magic=ULONG_MAX,
                      SL sl=0,TP tp=0,
                      const string comment=NULL,
                      const ulong deviation=ULONG_MAX,
                      const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   return this.m_trading.OpenBuy(volume,symbol,magic,sl,tp,comment,deviation,type_filling);
  }
//+------------------------------------------------------------------+
//| Open a Sell position                                             |
//+------------------------------------------------------------------+
template<typename SL,typename TP>
bool CEngine::OpenSell(const double volume,
                       const string symbol,
                       const ulong magic=ULONG_MAX,
                       SL sl=0,TP tp=0,
                       const string comment=NULL,
                       const ulong deviation=ULONG_MAX,
                       const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   return this.m_trading.OpenSell(volume,symbol,magic,sl,tp,comment,deviation,type_filling);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Place BuyStop pending order                                      |
//+------------------------------------------------------------------+
template<typename PR,typename SL,typename TP>
bool CEngine::PlaceBuyStop(const double volume,
                           const string symbol,
                           const PR price,
                           const SL sl=0,
                           const TP tp=0,
                           const ulong magic=WRONG_VALUE,
                           const string comment=NULL,
                           const datetime expiration=0,
                           const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                           const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   return this.m_trading.PlaceBuyStop(volume,symbol,price,sl,tp,magic,comment,expiration,type_time,type_filling);
  }
//+------------------------------------------------------------------+
//| Place BuyLimit pending order                                     |
//+------------------------------------------------------------------+
template<typename PR,typename SL,typename TP>
bool CEngine::PlaceBuyLimit(const double volume,
                            const string symbol,
                            const PR price,
                            const SL sl=0,
                            const TP tp=0,
                            const ulong magic=WRONG_VALUE,
                            const string comment=NULL,
                            const datetime expiration=0,
                            const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                            const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   return this.m_trading.PlaceBuyLimit(volume,symbol,price,sl,tp,magic,comment,expiration,type_time,type_filling);
  }
//+------------------------------------------------------------------+
//| Place BuyStopLimit pending order                                 |
//+------------------------------------------------------------------+
template<typename PR,typename PL,typename SL,typename TP>
bool CEngine::PlaceBuyStopLimit(const double volume,
                                const string symbol,
                                const PR price_stop,
                                const PL price_limit,
                                const SL sl=0,
                                const TP tp=0,
                                const ulong magic=WRONG_VALUE,
                                const string comment=NULL,
                                const datetime expiration=0,
                                const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                                const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   return this.m_trading.PlaceBuyStopLimit(volume,symbol,price_stop,price_limit,sl,tp,magic,comment,expiration,type_time,type_filling);
  }
//+------------------------------------------------------------------+
//| Place SellStop pending order                                     |
//+------------------------------------------------------------------+
template<typename PR,typename SL,typename TP>
bool CEngine::PlaceSellStop(const double volume,
                            const string symbol,
                            const PR price,
                            const SL sl=0,
                            const TP tp=0,
                            const ulong magic=WRONG_VALUE,
                            const string comment=NULL,
                            const datetime expiration=0,
                            const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                            const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   return this.m_trading.PlaceSellStop(volume,symbol,price,sl,tp,magic,comment,expiration,type_time,type_filling);
  }
//+------------------------------------------------------------------+
//| Place SellLimit pending order                                    |
//+------------------------------------------------------------------+
template<typename PR,typename SL,typename TP>
bool CEngine::PlaceSellLimit(const double volume,
                             const string symbol,
                             const PR price,
                             const SL sl=0,
                             const TP tp=0,
                             const ulong magic=WRONG_VALUE,
                             const string comment=NULL,
                             const datetime expiration=0,
                             const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                             const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   return this.m_trading.PlaceSellLimit(volume,symbol,price,sl,tp,magic,comment,expiration,type_time,type_filling);
  }
//+------------------------------------------------------------------+
//| Place SellStopLimit pending order                                |
//+------------------------------------------------------------------+
template<typename PR,typename PL,typename SL,typename TP>
bool CEngine::PlaceSellStopLimit(const double volume,
                                 const string symbol,
                                 const PR price_stop,
                                 const PL price_limit,
                                 const SL sl=0,
                                 const TP tp=0,
                                 const ulong magic=WRONG_VALUE,
                                 const string comment=NULL,
                                 const datetime expiration=0,
                                 const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                                 const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
  {
   return this.m_trading.PlaceSellStopLimit(volume,symbol,price_stop,price_limit,sl,tp,magic,comment,expiration,type_time,type_filling);
  }
//+------------------------------------------------------------------+


Dies alles sind die notwendigen Anpassungen und Änderungen für den Augenblick.

Tests

Um schwebenden Anfragen für das Platzieren von Pending-Order zu testen, nehmen wir den EA aus dem vorherigen Artikel und speichern ihn in \MQL5\Experts\TestDoEasy\Part27\ unter dem Namen TestDoEasyPart27.mq5.

In der Bibliotheksinitialisierungsfunktion des EA fügen wir die Einstellung der korrekten Werte der Orderfüll- und Ablauftypen für alle Handelsobjekte aller im EA verwendeten Symbole hinzu:

//+------------------------------------------------------------------+
//| Initializing DoEasy library                                      |
//+------------------------------------------------------------------+
void OnInitDoEasy()
  {
//--- Check if working with the full list is selected
   used_symbols_mode=InpModeUsedSymbols;
   if((ENUM_SYMBOLS_MODE)used_symbols_mode==SYMBOLS_MODE_ALL)
     {
      int total=SymbolsTotal(false);
      string ru_n="\nКоличество символов на сервере "+(string)total+".\nМаксимальное количество: "+(string)SYMBOLS_COMMON_TOTAL+" символов.";
      string en_n="\nNumber of symbols on server "+(string)total+".\nMaximum number: "+(string)SYMBOLS_COMMON_TOTAL+" symbols.";
      string caption=TextByLanguage("Внимание!","Attention!");
      string ru="Выбран режим работы с полным списком.\nВ этом режиме первичная подготовка списка коллекции символов может занять длительное время."+ru_n+"\nПродолжить?\n\"Нет\" - работа с текущим символом \""+Symbol()+"\"";
      string en="Full list mode selected.\nIn this mode, the initial preparation of the collection symbols list may take a long time."+en_n+"\nContinue?\n\"No\" - working with the current symbol \""+Symbol()+"\"";
      string message=TextByLanguage(ru,en);
      int flags=(MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2);
      int mb_res=MessageBox(message,caption,flags);
      switch(mb_res)
        {
         case IDNO : 
           used_symbols_mode=SYMBOLS_MODE_CURRENT; 
           break;
         default:
           break;
        }
     }
//--- Fill in the array of used symbols
   used_symbols=InpUsedSymbols;
   CreateUsedSymbolsArray((ENUM_SYMBOLS_MODE)used_symbols_mode,used_symbols,array_used_symbols);

//--- Set the type of the used symbol list in the symbol collection
   engine.SetUsedSymbols(array_used_symbols);
//--- Displaying the selected mode of working with the symbol object collection
   Print(engine.ModeSymbolsListDescription(),TextByLanguage(". Number of used symbols: ",". Number of symbols used: "),engine.GetSymbolsCollectionTotal());
   
//--- Create resource text files
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_01",TextByLanguage("Звук упавшей монетки 1","Falling coin 1"),sound_array_coin_01);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_02",TextByLanguage("Звук упавших монеток","Falling coins"),sound_array_coin_02);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_03",TextByLanguage("Звук монеток","Coins"),sound_array_coin_03);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_04",TextByLanguage("Звук упавшей монетки 2","Falling coin 2"),sound_array_coin_04);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_01",TextByLanguage("Звук щелчка по кнопке 1","Button click 1"),sound_array_click_01);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_02",TextByLanguage("Звук щелчка по кнопке 2","Button click 2"),sound_array_click_02);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_03",TextByLanguage("Звук щелчка по кнопке 3","Button click 3"),sound_array_click_03);
   engine.CreateFile(FILE_TYPE_WAV,"sound_array_cash_machine_01",TextByLanguage("Звук кассового аппарата","Cash machine"),sound_array_cash_machine_01);
   engine.CreateFile(FILE_TYPE_BMP,"img_array_spot_green",TextByLanguage("Изображение \"Зелёный светодиод\"","Image \"Green Spot lamp\""),img_array_spot_green);
   engine.CreateFile(FILE_TYPE_BMP,"img_array_spot_red",TextByLanguage("Изображение \"Красный светодиод\"","Image \"Red Spot lamp\""),img_array_spot_red);

//--- Pass all existing collections to the trading class
   engine.TradingOnInit();

//--- Set the default magic number for all used symbols
   engine.TradingSetMagic(engine.SetCompositeMagicNumber(magic_number));
//--- Set synchronous passing of orders for all used symbols
   engine.TradingSetAsyncMode(false);
//--- Set the number of trading attempts in case of an error
   engine.TradingSetTotalTry(InpTotalAttempts);
//--- Set correct order expiration and filling types to all trading objects
   engine.TradingSetCorrectTypeExpiration();
   engine.TradingSetCorrectTypeFilling();

//--- Set standard sounds for trading objects of all used symbols
   engine.SetSoundsStandart();
//--- Set the general flag of using sounds
   engine.SetUseSounds(InpUseSounds);
//--- Set the spread multiplier for symbol trading objects in the symbol collection
   engine.SetSpreadMultiplier(InpSpreadMultiplier);
      
//--- Set controlled values for symbols
   //--- Get the list of all collection symbols
   CArrayObj *list=engine.GetListAllUsedSymbols();
   if(list!=NULL && list.Total()!=0)
     {
      //--- In a loop by the list, set the necessary values for tracked symbol properties
      //--- By default, the LONG_MAX value is set to all properties, which means "Do not track this property" 
      //--- It can be enabled or disabled (by setting the value less than LONG_MAX or vice versa - set the LONG_MAX value) at any time and anywhere in the program
      /*
      for(int i=0;i<list.Total();i++)
        {
         CSymbol* symbol=list.At(i);
         if(symbol==NULL)
            continue;
         //--- Set control of the symbol price increase by 100 points
         symbol.SetControlBidInc(100000*symbol.Point());
         //--- Set control of the symbol price decrease by 100 points
         symbol.SetControlBidDec(100000*symbol.Point());
         //--- Set control of the symbol spread increase by 40 points
         symbol.SetControlSpreadInc(400);
         //--- Set control of the symbol spread decrease by 40 points
         symbol.SetControlSpreadDec(400);
         //--- Set control of the current spread by the value of 40 points
         symbol.SetControlSpreadLevel(400);
        }
      */
     }
//--- Set controlled values for the current account
   CAccount* account=engine.GetAccountCurrent();
   if(account!=NULL)
     {
      //--- Set control of the profit increase to 10
      account.SetControlledValueINC(ACCOUNT_PROP_PROFIT,10.0);
      //--- Set control of the funds increase to 15
      account.SetControlledValueINC(ACCOUNT_PROP_EQUITY,15.0);
      //--- Set profit control level to 20
      account.SetControlledValueLEVEL(ACCOUNT_PROP_PROFIT,20.0);
     }
  }
//+------------------------------------------------------------------+


Merkwürdigerweise sind das bereits alle Änderungen des EAs. Alle anderen Änderungen wurden an den Bibliothekscodes vorgenommen.

Zum Testen von schwebenden Anfragen für die Erteilung von Bestellungen werden wir genau dasselbe wie beim letzten Mal tun — das Internet deaktivieren, versuchen, eine ausstehende Bestellung zu erteilen, den Fehler bei der Verbindung zum Handelsserver erhalten und die Meldung des Journals erhalten, die über die Erzeugung einer ausstehenden Anfrage und deren Parameter informiert. Dann aktivieren wir das Internet wieder und erhalten die Aktivierung einer schwebenden Anfrage sowie die Platzierung der angeforderten Pending-Order.

Überprüfen wir das.

Kompilieren und starten wir den EA. Trennen wir die Internetverbindung und warten, bis das folgende Bild in der unteren rechten Ecke des Terminals erscheint:


Nachdem das Internet deaktiviert und auf Verkaufen geklickt wurde, gibt der Handelsserver den Fehler zurück, und der folgende Fehler und ausstehende Anforderungseinträge werden im Journal angezeigt.

Stellen wir nun die Internetverbindung und die Verbindung zum Handelsserver wieder her:


Sobald die Verbindung wiederhergestellt ist, beginnt die Bibliothek mit der Bearbeitung einer schwebenden Anfrage, die an den Server gesendet wird.
Daraufhin wird die Pending-Order platziert und die folgenden Journaleinträge erscheinen:

2019.12.05 16:38:32.591 CTrading::PlaceOrder<uint,int,uint,uint>: Invalid request:
2019.12.05 16:38:32.591 No connection with the trade server
2019.12.05 16:38:32.591 Correction of trade request parameters ...
2019.12.05 16:38:32.610 Trading attempt #1. Error: No connection with the trade server
2019.12.05 16:38:32.610 Pending request created #1:
2019.12.05 16:38:32.610 ================== Pending trade request's parameters ==================
2019.12.05 16:38:32.610  - Pending request type: Pending request that was created as a result of the server code
2019.12.05 16:38:32.610  - Trade request ID: 1
2019.12.05 16:38:32.610  - Return code based on which the request was created: 10031 "No connection with the trade server"
2019.12.05 16:38:32.610  - Request creation time: 2019.12.05 11:37:39.054
2019.12.05 16:38:32.610  - Price at time of request create: : 1.10913
2019.12.05 16:38:32.610  - Request activation time: 2019.12.05 11:37:59.054
2019.12.05 16:38:32.610  - Waiting time between trading attempts: 20000 (00:00:20)
2019.12.05 16:38:32.610  - Current trading attempt: Waiting for the onset time of the first trading attempt
2019.12.05 16:38:32.610  - Total trade attempts: 5
2019.12.05 16:38:32.610 ================== Trade request's parameters ==================
2019.12.05 16:38:32.610  - Trade operation type: Place pending order
2019.12.05 16:38:32.610  - Trade symbol: EURUSD
2019.12.05 16:38:32.610  - Requested volume for a deal in lots: 0.10
2019.12.05 16:38:32.610  - Price: 1.10963
2019.12.05 16:38:32.610  - StopLimit level of the order: Value not set
2019.12.05 16:38:32.610  - Stop Loss level of the order: 1.11113
2019.12.05 16:38:32.610  - Take Profit level of the order: 1.10813
2019.12.05 16:38:32.610  - Order type: Pending order Sell Limit
2019.12.05 16:38:32.610  - Order execution type: The order is executed exclusively in the specified volume, otherwise it is canceled (FOK)
2019.12.05 16:38:32.610  - Order expiration type: Good till cancel order
2019.12.05 16:38:32.610  - Order expiration time: Value not set
2019.12.05 16:38:32.610  - Magic number: 24379515
2019.12.05 16:38:32.610  - Order comment: "Pending order SellLimit"
2019.12.05 16:38:32.610  ==================
2019.12.05 16:38:32.610 
2019.12.05 16:38:45.185 Retry trading attempt #1
2019.12.05 16:38:45.185 CTrading::PlaceOrder<double,double,double,double>: Invalid request:
2019.12.05 16:38:45.185 Trading is prohibited for the current account
2019.12.05 16:38:45.185 Correction of trade request parameters ...
2019.12.05 16:38:45.185 Trading operation aborted
2019.12.05 16:38:45.512 Retry trading attempt #2
2019.12.05 16:38:45.512 CTrading::PlaceOrder<double,double,double,double>: Invalid request:
2019.12.05 16:38:45.512 Trading is prohibited for the current account
2019.12.05 16:38:45.512 Correction of trade request parameters ...
2019.12.05 16:38:45.512 Trading operation aborted
2019.12.05 16:38:45.852 Retry trading attempt #3
2019.12.05 16:38:46.405 - Pending order placed: 2019.12.05 11:38:45.933 -
2019.12.05 16:38:46.405 EURUSD Placed 0.10 Pending order Sell Limit #491179168 at price 1.10963, sl 1.11113, tp 1.10813, Magic number 24379515 (123), G1: 4, G2: 7, ID: 1
2019.12.05 16:38:46.472 OnDoEasyEvent: Pending order placed

Zuerst erhalten wir den Fehler "Keine Verbindung mit dem Handelsserver".
Als Nächstes erhalten wir die Nachricht über die Erstellung einer schwebenden Handelsanfrage mit der ID #1, die alle Objektparameter und Anforderungsstrukturparameter innerhalb dieses Objekts enthält.
Danach werden zwei wiederholte Handelsversuche #1 und #2 unternommen. Die Versuche werden von einer schwebenden Handelsanfrage aus gesendet und es folgt der Fehler des deaktivierten Handels auf dem Konto (der Handel auf dem Konto ist nach der Wiederherstellung der Verbindung noch nicht aktiviert).
Der dritte Versuch, der vom Objekt der schwebenden Handelsanfrage aus gesendet wurde, hat sich als erfolgreich erwiesen, und der schwebende Auftrag wurde erteilt.

In der Beschreibung der Magicnummer der Pending-Order haben wir die Magicnummer Zahl 24379515, gefolgt von der ID der Magicnummer, die in den EA-Parametern (123) festgelegt ist, der ersten Gruppen-ID "G1: 4", der zweiten Gruppen-ID "G2: 7" und der schwebenden Aunfrage-ID "ID: 1".

Bitte beachten Sie:

Verwenden Sie die Ergebnisse der Handelsklasse mit den im Artikel beschriebenen schwebenden Anträgen und dem beigefügten Test EA nicht im realen Handel!
Der Artikel, die Begleitmaterialien und die Ergebnisse sind nur als Test für das Konzept der schwebenden Anträge gedacht. In seinem gegenwärtigen Zustand ist er kein fertiges Produkt und in keiner Weise für den realen Handel bestimmt.
Stattdessen ist er nur für den Demo-Modus oder den Tester bestimmt.

Was kommt als Nächstes?

Im nächsten Artikel werden wir die Arbeit an den grundlegenden Funktionen für schwebenden Anfragen — Ändern, Löschen und Schließen von Orders/Positionen — fortsetzen.

Alle Dateien der aktuellen Version der Bibliothek sind unten zusammen mit den Dateien der Test-EAs angehängt, die Sie testen und herunterladen können.
Stellen Sie Ihre Fragen, Kommentare und Vorschläge in den Kommentaren.

Zurück zum Inhalt

Frühere Artikel dieser Serie:

Teil 1. Konzept, Datenverwaltung.
Teil 2. Erhebung (Collection) historischer Aufträge und Deals.
Teil 3. Erhebung (Collection) von Marktorders und Positionen, Organisieren der Suche
Teil 4. Handelsereignisse. Konzept
Teil 5. Klassen und Kollektionen von Handelsereignissen. Senden von Ereignissen an das Programm
Teil 6. Ereignisse auf Netting-Konten
Teil 7. Ereignis der Aktivierung einer StopLimit-Order, Vorbereiten der Funktionsweise bei Änderungen von Orders und Positionen
Teil 8. Ereignisse von Änderungen von Orders und Positionen
Teil 9. Kompatibilität mit MQL4 — Datenvorbereitung
Teil 10. Kompatibilität mit MQL4 - Ereignisse der Positionseröffnung und Aktivierung von Pending-Orders
Teil 11. Kompatibilität mit MQL4 - Ereignisse des Schließens von Positionen
Teil 12. Objektklasse "Account" und die Kollektion von Konto-Objekten
Teil 13. Das Objekt der Kontoereignisse
Teil 14. Das Symbolobjekt
Teil 15. Die Kollektion der Symbolobjekte
Teil 16. Ereignisse der Kollektionssymbole
Teil 17. Interaktivität von Bibliotheksobjekten
Teil 18. Interaktivität des Kontos und aller anderen Bibliotheksobjekt
Teil 19. Klassenbibliothek für Nachrichten
Teil 20. Erstellen und Speichern von Programmressourcen
Teil 21. Handelsklassen - Plattformübergreifendes Basis-Handelsobjekt
Teil 22. Handelsklassen - Basisklasse des Handels, Verifikation der Einschränkungen
Teil 23. Handelsklasse - Basisklasse des Handels, Verifikation der Parameter
Teil 24. Trading classes - Handelsklassen, automatische Korrektur ungültiger Parametern
Teil 25. Handelsklassen - Basisklasse des Handels, Behandlung der Fehlermeldungen vom Server
Teil 26. Arbeiten mit schwebenden Handelsanfragen - erste Implementation

Übersetzt aus dem Russischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/ru/articles/7418

Beigefügte Dateien |
MQL5.zip (3617 KB)
MQL4.zip (3617.01 KB)
SQLite: Natives Arbeiten mit SQL-Datenbanken in MQL5 SQLite: Natives Arbeiten mit SQL-Datenbanken in MQL5

Die Entwicklung von Handelsstrategien ist mit dem Umgang mit großen Datenmengen verbunden. Jetzt können Sie mit Datenbanken mit SQL-Abfragen auf der Basis von SQLite direkt in MQL5 arbeiten. Ein wichtiges Merkmal dieser Engine ist, dass die gesamte Datenbank in einer einzigen Datei auf dem PC des Benutzers abgelegt wird.

Kontinuierliche Rolloptimierung (Teil 2): Mechanismus zur Erstellung eines Optimierungsberichts für einen beliebigen Roboter Kontinuierliche Rolloptimierung (Teil 2): Mechanismus zur Erstellung eines Optimierungsberichts für einen beliebigen Roboter

Der erste Artikel innerhalb der rollenden Optimierungsreihe beschrieb die Erstellung einer DLL, die in unserem Autooptimierer verwendet werden soll. Diese Fortsetzung ist vollständig der Sprache MQL5 gewidmet.

Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XXVIII): Schließen, Entfernen und Ändern von schwebenden Handelsanfragen Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil XXVIII): Schließen, Entfernen und Ändern von schwebenden Handelsanfragen

Dies ist der dritte Artikel über das Konzept der schwebenden Anfragen. Wir werden die Tests von schwebenden Anfragen abschließen, indem wir die Methoden für das Schließen von Positionen, die Entfernung von schwebenden Anfragen und die Änderung der Parameter von Positionen und den Parametern von Pending-Orders erstellen.

Neuronale Netze leicht gemacht Neuronale Netze leicht gemacht

Künstliche Intelligenz wird oft mit etwas phantastisch Komplexem und Unverständlichem assoziiert. Gleichzeitig wird die künstliche Intelligenz im Alltag immer häufiger erwähnt. Nachrichten über Errungenschaften im Zusammenhang mit dem Einsatz neuronaler Netze erscheinen oft in verschiedenen Medien. Der Zweck dieses Artikels ist es zu zeigen, dass jeder leicht ein neuronales Netz erstellen und die Errungenschaften der künstlichen Intelligenz im Handel nutzen kann.