English Русский 中文 Deutsch 日本語 Português
preview
Transacciones comerciales. Estructuras de solicitud y respuesta, descripción y registro.

Transacciones comerciales. Estructuras de solicitud y respuesta, descripción y registro.

MetaTrader 5Ejemplos | 17 enero 2024, 04:57
389 0
Artyom Trishkin
Artyom Trishkin

Contenido


Introducción

En MQL5, para colocar órdenes pendientes, abrir posiciones, cambiar órdenes y posiciones, existe la función OrderSend(). El primer parámetro de entrada de la función es la estructura de la solicitud comercial MqlTradeRequest. El campo de acción de la estructura indica el tipo de acción a realizar, mientras que los campos restantes se completan dependiendo de la acción seleccionada en el campo de acción. Por consiguiente, transmitiendo a la función los parámetros necesarios para una solicitud comercial, enviaremos varias solicitudes al servidor.

Estructura de la solicitud comercial (MqlTradeRequest)

La interacción entre el terminal del cliente y el servidor comercial para realizar operaciones de colocación de órdenes se efectúa a través de solicitudes comerciales. La solicitud está representada por la estructura especial predefinida MqlTradeRequest, que contiene todos los campos necesarios para realizar transacciones comerciales:

struct MqlTradeRequest
  {
   ENUM_TRADE_REQUEST_ACTIONS    action;           // Type of a performed action
   ulong                         magic;            // EA stamp (magic number ID)
   ulong                         order;            // Order ticket
   string                        symbol;           // Symbol name
   double                        volume;           // Requested volume of a deal in lots
   double                        price;            // Price 
   double                        stoplimit;        // StopLimit order level
   double                        sl;               // Stop Loss order level
   double                        tp;               // Take Profit order level
   ulong                         deviation;        // Maximum acceptable deviation from the requested price
   ENUM_ORDER_TYPE               type;             // Order type
   ENUM_ORDER_TYPE_FILLING       type_filling;     // Order filling type
   ENUM_ORDER_TYPE_TIME          type_time;        // Order lifetime type
   datetime                      expiration;       // Order expiration time (for ORDER_TIME_SPECIFIED type orders)
   string                        comment;          // Order comment
   ulong                         position;         // Position ticket
   ulong                         position_by;      // Opposite position ticket
  };

El primer campo de acción indica el tipo de acción a realizar.

Tipo de operación comercial. El valor puede ser uno de los valores de enumeración ENUM_TRADE_REQUEST_ACTIONS:

Identificador
Descripción
TRADE_ACTION_DEAL
Coloca una orden comercial para ejecutar inmediatamente una transacción con los parámetros especificados (coloca una orden de mercado)
TRADE_ACTION_PENDING
Establece una orden comercial para completar una transacción bajo condiciones específicas (orden pendiente)
TRADE_ACTION_SLTP
Cambia los valores de Stop Loss y Take Profit para una posición abierta
TRADE_ACTION_MODIFY
Cambia los parámetros de una orden comercial previamente establecida
TRADE_ACTION_REMOVE
Elimina una orden comercial pendiente colocada anteriormente
TRADE_ACTION_CLOSE_BY
Cierra una posición con otra opuesta

Para cada tipo de acción, los campos de la estructura deberán rellenarse individualmente.

Tras completar los campos obligatorios de la estructura, se podrá enviar una orden comercial al servidor. Pero primero podemos verificar que la estructura se ha rellenado con exactitud usando la función OrderCheck(), con la que se transmite la propia consulta comprobada y la variable del tipo de estructura MqlTradeCheckResult. El resultado de la verificación se escribirá en esta variable:

struct MqlTradeCheckResult
  {
   uint         retcode;             // Response code
   double       balance;             // Balance after performing a deal
   double       equity;              // Equity after performing a deal
   double       profit;              // Floating profit
   double       margin;              // Margin requirements
   double       margin_free;         // Free margin
   double       margin_level;        // Margin level
   string       comment;             // Comment on the response code (error description)
  };

Si los fondos resultan insuficientes como resultado de la verificación de la orden o los parámetros se han completado incorrectamente, la función retornará false. Si la verificación básica de estructuras (comprobación de punteros) tiene éxito, se retornará true: esto no indica que la operación comercial solicitada se completará con éxito.. Para obtener una descripción detallada del resultado de la ejecución de una función, deberemos analizar los campos de la estructura result presentada anteriormente.

Tras comprobar con éxito que se han rellenado los campos de la estructura de la orden comercial, la podremos enviar al servidor. El éxito al rellenar la función OrderSend() no significa que la orden se haya ejecutado. Simplemente entenderemos que la orden ha sido procesada y aceptada por el servidor. Como resultado del envío de una orden comercial al servidor, se rellenarán los campos de la estructura MqlTradeResult, que contiene la respuesta del servidor comercial a la solicitud enviada por la función OrderSend().

El resultado de la operación comercial se retornará a una variable del tipo MqlTradeResult, que se transmitirá como segundo parámetro a la función OrderSend() para realizar operaciones comerciales.

El terminal escribe el identificador de la solicitud en el campo request_id cuando se envía al servidor comercial utilizando las funciones OrdersSend() y OrderSendAsync(). Desde el servidor comercial, el terminal recibe los mensajes sobre las transacciones comerciales completadas y los transmite para su procesamiento a la función OnTradeTransaction(), que contiene como parámetros:

  • la descripción de la transacción comercial en sí en la estructura MqlTradeTransaction;
  • la descripción de la solicitud comercial enviada desde la función OrderSend() o OrdersSendAsync(). El identificador de la solicitud es enviado por el terminal al servidor comercial, mientras que la solicitud en sí y su request_id se almacenan en la memoria del terminal;
  • el resultado de la ejecución de la solicitud comercial en forma de estructura MqlTradeResult, en la que el campo request_id contiene el identificador de esta solicitud en sí.

La función OnTradeTransaction() recibe tres parámetros de entrada, pero los dos últimos solo tienen sentido para analizar transacciones comerciales de tipo TRADE_TRANSACTION_REQUEST. En todos los demás casos, no se completarán los datos sobre la solicitud comercial y el resultado de su ejecución. En la sección estructura de la transacción comercial se ofrece un ejemplo de análisis de parámetros.

La configuración del identificador request_id por parte del terminal para la solicitud comercial (al enviar esta al servidor) se introduce principalmente para trabajar con la función asíncrona OrderSendAsync(). Este identificador le permite asociar la acción realizada (la llamada a las funciones OrderSend o OrderSendAsync) con el resultado de dicha acción transmitido a OnTradeTransaction().

De esta forma, podremos controlar la recepción de una orden (orden comercial) por parte del servidor, su colocación en el sistema comercial y su ejecución en la función OnTradeTransaction(). Hoy escribiremos funciones para enviar al registro los campos de todas las estructuras implicadas en la solicitud comercial, desde el rellenado de la estructura de una orden comercial hasta el análisis de eventos en OnTradeTransaction(). El resultado del artículo será un pequeño asesor-informante que imprimirá todos los eventos comerciales en el registro.

De forma abreviada, el proceso de trabajo con las órdenes comerciales será el siguiente:

  1. Rellenamos la estructura de la solicitud comercial,
  2. Verificamos que la estructura se haya rellenado correctamente, así como la posibilidad de realizar dicha orden,
  3. Enviamos la orden comercial al servidor,
  4. De ser necesario, analizaremos la estructura del resultado del envío de la orden al servidor,
  5. Obtenemos los eventos y, de ser necesario, analizaremos los mensajes en el registro del manejador OnTradeTransaction().
Pero antes de comenzar a escribir las funciones para enviar las descripciones de los campos estructurales al registro, escribiremos varias funciones auxiliares que retornan las descripciones de ciertos tipos de órdenes presentadas en forma de constantes de enumeración, así como otras funciones útiles y necesarias.

Funciones auxiliares

El asesor que se presentará al final del artículo se controlará presionando atajos de teclado. Para determinar las pulsaciones de las teclas Ctrl y Shift, vamos a escribir dos funciones:

//+------------------------------------------------------------------+
//| Return the state of the Ctrl key                                 |
//+------------------------------------------------------------------+
bool IsCtrlKeyPressed(void) 
  { 
   return(::TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL)<0);
  }
//+------------------------------------------------------------------+
//| Return the state of the Shift key                                |
//+------------------------------------------------------------------+
bool IsShiftKeyPressed(void) 
  { 
   return(::TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT)<0);
  }

Ahora, al detectar que se ha presionado una tecla, podremos marcar la bandera para mantener presionada la tecla Ctrl o Shift, o mantenerlas simultáneamente para responder a una combinación de teclas de control y alfanuméricas.


Al retornar las descripciones de los campos de estructura, necesitaremos imprimir los códigos de retorno del servidor comercial. Vamos a crear una función que retornará la descripción del código de respuesta del servidor:

//+------------------------------------------------------------------+
//| Return a description of the trade server return code             |
//+------------------------------------------------------------------+
string RetcodeDescription(const uint retcode,bool ext_descr=false)
  {
   switch(retcode)
     {
      //--- Done
      case 0                                 :  return "OK (0)";
      //--- Requote
      case TRADE_RETCODE_REQUOTE             :  return "10004 REQUOTE"+(ext_descr ? " (Requote)" : "");
      //--- Request rejected
      case TRADE_RETCODE_REJECT              :  return "10006 REJECT"+(ext_descr ? " (Request rejected)" : "");
      //--- Request canceled by trader
      case TRADE_RETCODE_CANCEL              :  return "10007 CANCEL"+(ext_descr ? " (Request canceled by trader)" : "");
      //--- Order placed
      case TRADE_RETCODE_PLACED              :  return "10008 PLACED"+(ext_descr ? " (Order placed)" : "");
      //--- Request completed
      case TRADE_RETCODE_DONE                :  return "10009 DONE"+(ext_descr ? " (Request completed)" : "");
      //--- Request completed partially
      case TRADE_RETCODE_DONE_PARTIAL        :  return "10010 DONE_PARTIAL"+(ext_descr ? " (Only part of the request was completed)" : "");
      //--- Request processing error
      case TRADE_RETCODE_ERROR               :  return "10011 ERROR"+(ext_descr ? " (Request processing error)" : "");
      //--- Request canceled by timeout
      case TRADE_RETCODE_TIMEOUT             :  return "10012 TIMEOUT"+(ext_descr ? " (Request canceled by timeout)" : "");
      //--- Invalid request
      case TRADE_RETCODE_INVALID             :  return "10013 INVALID"+(ext_descr ? " (Invalid request)" : "");
      //--- Invalid volume in the request
      case TRADE_RETCODE_INVALID_VOLUME      :  return "10014 INVALID_VOLUME"+(ext_descr ? " (Invalid volume in the request)" : "");
      //--- Invalid price in the request
      case TRADE_RETCODE_INVALID_PRICE       :  return "10015 INVALID_PRICE"+(ext_descr ? " (Invalid price in the request)" : "");
      //--- Invalid stops in the request
      case TRADE_RETCODE_INVALID_STOPS       :  return "10016 INVALID_STOPS"+(ext_descr ? " (Invalid stops in the request)" : "");
      //--- Trading disabled
      case TRADE_RETCODE_TRADE_DISABLED      :  return "10017 TRADE_DISABLED"+(ext_descr ? " (Trade is disabled)" : "");
      //--- Market is closed
      case TRADE_RETCODE_MARKET_CLOSED       :  return "10018 MARKET_CLOSED"+(ext_descr ? " (Market is closed)" : "");
      //--- There is not enough money to complete the request
      case TRADE_RETCODE_NO_MONEY            :  return "10019 NO_MONEY"+(ext_descr ? " (There is not enough money to complete the request)" : "");
      //--- Prices changed
      case TRADE_RETCODE_PRICE_CHANGED       :  return "10020 PRICE_CHANGED"+(ext_descr ? " (Prices changed)" : "");
      //--- There are no quotes to process the request
      case TRADE_RETCODE_PRICE_OFF           :  return "10021 PRICE_OFF"+(ext_descr ? " (There are no quotes to process the request)" : "");
      //--- Invalid order expiration date in the request
      case TRADE_RETCODE_INVALID_EXPIRATION  :  return "10022 INVALID_EXPIRATION"+(ext_descr ? " (Invalid order expiration date in the request)" : "");
      //--- Order state changed
      case TRADE_RETCODE_ORDER_CHANGED       :  return "10023 ORDER_CHANGED"+(ext_descr ? " (Order state changed)" : "");
      //--- Too frequent requests
      case TRADE_RETCODE_TOO_MANY_REQUESTS   :  return "10024 TOO_MANY_REQUESTS"+(ext_descr ? " (Too frequent requests)" : "");
      //--- No changes in request
      case TRADE_RETCODE_NO_CHANGES          :  return "10025 NO_CHANGES"+(ext_descr ? " (No changes in request)" : "");
      //--- Autotrading disabled by server
      case TRADE_RETCODE_SERVER_DISABLES_AT  :  return "10026 SERVER_DISABLES_AT"+(ext_descr ? " (Autotrading disabled by server)" : "");
      //--- Autotrading disabled by client terminal
      case TRADE_RETCODE_CLIENT_DISABLES_AT  :  return "10027 CLIENT_DISABLES_AT"+(ext_descr ? " (Autotrading disabled by client terminal)" : "");
      //--- Request locked for processing
      case TRADE_RETCODE_LOCKED              :  return "10028 LOCKED"+(ext_descr ? " (Request locked for processing)" : "");
      //--- Order or position frozen
      case TRADE_RETCODE_FROZEN              :  return "10029 FROZEN"+(ext_descr ? " (Order or position frozen)" : "");
      //--- Invalid order filling type
      case TRADE_RETCODE_INVALID_FILL        :  return "10030 INVALID_FILL"+(ext_descr ? " (Invalid order filling type)" : "");
      //--- No connection with the trade server
      case TRADE_RETCODE_CONNECTION          :  return "10031 CONNECTION"+(ext_descr ? " (No connection with the trade server)" : "");
      //--- Operation allowed only for live accounts
      case TRADE_RETCODE_ONLY_REAL           :  return "10032 ONLY_REAL"+(ext_descr ? " (Operation is allowed only for live accounts)" : "");
      //--- Number of pending orders reached the limit
      case TRADE_RETCODE_LIMIT_ORDERS        :  return "10033 LIMIT_ORDERS"+(ext_descr ? " (The number of pending orders has reached the limit)" : "");
      //--- Volume of orders and positions for the symbol reached the limit
      case TRADE_RETCODE_LIMIT_VOLUME        :  return "10034 LIMIT_VOLUME"+(ext_descr ? " (The volume of orders and positions for the symbol has reached the limit)" : "");
      //--- Incorrect or prohibited order type
      case TRADE_RETCODE_INVALID_ORDER       :  return "10035 INVALID_ORDER"+(ext_descr ? " (Incorrect or prohibited order type)" : "");
      //--- Position with specified POSITION_IDENTIFIER already closed
      case TRADE_RETCODE_POSITION_CLOSED     :  return "10036 POSITION_CLOSED"+(ext_descr ? " (Position with the specified POSITION_IDENTIFIER has already been closed)" : "");
      //--- Close volume exceeds the current position volume
      case TRADE_RETCODE_INVALID_CLOSE_VOLUME:  return "10038 INVALID_CLOSE_VOLUME"+(ext_descr ? " (A close volume exceeds the current position volume)" : "");
      //--- Close order already exists for specified position
      case TRADE_RETCODE_CLOSE_ORDER_EXIST   :  return "10039 CLOSE_ORDER_EXIST"+(ext_descr ? " (A close order already exists for a specified position)" : "");
      //--- Number of positions reached the limit
      case TRADE_RETCODE_LIMIT_POSITIONS     :  return "10040 LIMIT_POSITIONS"+(ext_descr ? " (The number of positions has reached the limit)" : "");
      //--- Pending order activation request is rejected, order is canceled
      case TRADE_RETCODE_REJECT_CANCEL       :  return "10041 REJECT_CANCEL"+(ext_descr ? " (The pending order activation request is rejected, the order is canceled)" : "");
      //--- Request rejected, only long positions are allowed on symbol
      case TRADE_RETCODE_LONG_ONLY           :  return "10042 LONG_ONLY"+(ext_descr ? " (Only long positions are allowed)" : "");
      //--- Request rejected, only short positions are allowed on symbol
      case TRADE_RETCODE_SHORT_ONLY          :  return "10043 SHORT_ONLY"+(ext_descr ? " (Only short positions are allowed)" : "");
      //--- Request rejected, only position closing is allowed on symbol
      case TRADE_RETCODE_CLOSE_ONLY          :  return "10044 CLOSE_ONLY"+(ext_descr ? " (Only position closing is allowed)" : "");
      //--- Request rejected, position closing for trading account is allowed only by FIFO rule
      case TRADE_RETCODE_FIFO_CLOSE          :  return "10045 FIFO_CLOSE"+(ext_descr ? " (Position closing is allowed only by FIFO rule)" : "");
      //--- Request rejected, opposite positions on a single symbol are disabled for trading account
      case TRADE_RETCODE_HEDGE_PROHIBITED    :  return "10046 HEDGE_PROHIBITED"+(ext_descr ? " (Opposite positions on a single symbol are disabled)" : "");
      //--- Unknown return code 
      default                                :  return "Undefined ("+(string)retcode+")";
     }
  }

A la función se le transmite el código de respuesta del servidor y la bandera que indica la necesidad de retornar la descripción ampliada. La función retorna un código numérico con una descripción de la constante:

10034 LIMIT_VOLUME

o bien una descripción detallada del código de respuesta del servidor:

10034 LIMIT_VOLUME (The volume of orders and positions for the symbol has reached the limit)


Función que retorna la descripción del tipo de orden:

//+------------------------------------------------------------------+
//| Return the order type description                                |
//+------------------------------------------------------------------+
string OrderTypeDescription(const ENUM_ORDER_TYPE type,const bool ext_descr=false)
  {
//--- "Cut out" the order type from the string obtained from enum
   string res=StringSubstr(EnumToString(type),11);
//--- Convert all received characters to lowercase and
   if(res.Lower())
     {
      //--- replace the first letter from small to capital
      res.SetChar(0,ushort(res.GetChar(0)-0x20));
      int total=(int)res.Length();  // Text length
      int index=0;                  // index to start searching for "_" in a text
      //--- Search for underscores in a loop through all characters
      for(int i=0;i<total;i++)
        {
         int pos=StringFind(res,"_",index);
         //--- If an underscore is found,
         if(pos>0)
           {
            //--- replace it with space and convert the next letter to uppercase 
            res.SetChar(pos,' ');
            res.SetChar(pos+1,ushort(res.GetChar(pos+1)-0x20));
            //--- Set a new index for starting the search for "_"
            index=pos;
           }
        }
     }
   string descr="";
   switch(type)
     {
      case ORDER_TYPE_BUY              :  descr=" (Market Buy order)";                                                                          break;
      case ORDER_TYPE_SELL             :  descr=" (Market Sell order)";                                                                         break;
      case ORDER_TYPE_BUY_LIMIT        :  descr=" (Buy Limit pending order)";                                                                   break;
      case ORDER_TYPE_SELL_LIMIT       :  descr=" (Sell Limit pending order)";                                                                  break;
      case ORDER_TYPE_BUY_STOP         :  descr=" (Buy Stop pending order)";                                                                    break;
      case ORDER_TYPE_SELL_STOP        :  descr=" (Sell Stop pending order)";                                                                   break;
      case ORDER_TYPE_BUY_STOP_LIMIT   :  descr=" (Upon reaching the order price, a pending Buy Limit order is placed at the StopLimit price)"; break;
      case ORDER_TYPE_SELL_STOP_LIMIT  :  descr=" (Upon reaching the order price, a pending Sell Limit order is placed at the StopLimit price)";break;
      case ORDER_TYPE_CLOSE_BY         :  descr=" (Order to close a position by an opposite one)";                                              break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Sample output:
      Sell Limit (Sell Limit pending order)
   */
  }

Al enviar una solicitud comercial utilizando la función OrderSend(), para algunas operaciones será necesario especificar el tipo de orden. El tipo de pedido se indicará en el campo type de la estructura MqlTradeRequest y podrá tomar los valores de la enumeración ENUM_ORDER_TYPE:

Identificador
Descripción
ORDER_TYPE_BUY
Orden de mercado de compra
ORDER_TYPE_SELL
Orden de mercado de venta
ORDER_TYPE_BUY_LIMIT
Orden pendiente Buy Limit
ORDER_TYPE_SELL_LIMIT
Orden pendiente Sell Limit
ORDER_TYPE_BUY_STOP
Orden pendiente Buy Stop
ORDER_TYPE_SELL_STOP
Orden pendiente Sell Stop
ORDER_TYPE_BUY_STOP_LIMIT
Al alcanzarse el precio de la orden, se colocará una orden pendiente Buy Limit al precio StopLimit
ORDER_TYPE_SELL_STOP_LIMIT
Al alcanzarse el precio de la orden, se colocará una orden pendiente Sell Limit al precio StopLimit
ORDER_TYPE_CLOSE_BY
Orden para cerrar una posición con una posición opuesta


Función que retorna la descripción del tipo de orden para su ejecución:

//+------------------------------------------------------------------+
//| Return the order type description by execution                   |
//+------------------------------------------------------------------+
string OrderTypeFillingDescription(const ENUM_ORDER_TYPE_FILLING type_filling,const bool ext_descr=false)
  {
   string res=StringSubstr(EnumToString(type_filling),14);
//--- Convert all obtained symbols to lower case and replace the first letter from small to capital (for ORDER_FILLING_RETURN)
   if(type_filling==ORDER_FILLING_RETURN && res.Lower())
      res.SetChar(0,ushort(res.GetChar(0)-0x20));
   string descr="";
   switch(type_filling)
     {
      case ORDER_FILLING_FOK     :  descr=" (Fill or Kill. An order can be executed in the specified volume only)";                                               break;
      case ORDER_FILLING_IOC     :  descr=" (Immediate or Cancel. A deal with the volume maximally available in the market within that indicated in the order)";  break;
      case ORDER_FILLING_BOC     :  descr=" (Passive (Book or Cancel). The order can only be placed in the Depth of Market and cannot be immediately executed)";  break;
      case ORDER_FILLING_RETURN  :  descr=" (In case of partial filling, an order with remaining volume is not canceled but processed further)";                  break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Sample output:
      Type filling: Return (In case of partial filling, an order with remaining volume is not canceled but processed further)
   */
  }

Al enviar una solicitud comercial utilizando la función OrderSend(), la política de ejecución de volumen deseada se podrá configurar en el campo type_filling en la estructura MqlTradeRequest se permiten los valores de la enumeración ENUM_ORDER_TYPE_FILLING. Para obtener el valor de esta propiedad en una orden activa/procesada específica, use la función OrderGetInteger() o HistoryOrderGetInteger() con el modificador ORDER_TYPE_FILLING.

Antes de enviar una orden con ejecución en el momento actual, para establecer correctamente el valor ORDER_TYPE_FILLING (tipo de ejecución por volumen), para cada instrumento financiero, utilizando la función SymbolInfoInteger(), podemos obtener el valor de la propiedad SYMBOL_FILLING_MODE, que muestra los tipos de rellenado de volumen permitidos para este símbolo en forma de combinaciones de banderas. Cabe señalar que el tipo de rellenado ORDER_FILLING_RETURN siempre está permitido, salvo para el modo “Ejecución de mercado” (SYMBOL_TRADE_EXECUTION_MARKET).


Función que retorna la descripción del tipo de transacción comercial:

//+------------------------------------------------------------------+
//| Return a description of the trade transaction type               |
//+------------------------------------------------------------------+
string TradeTransactionTypeDescription(const ENUM_TRADE_TRANSACTION_TYPE transaction,const bool ext_descr=false)
  {
//--- "Cut out" the transaction type from the string obtained from enum
   string res=StringSubstr(EnumToString(transaction),18);
//--- Convert all obtained symbols to lower case and replace the first letter from small to capital
   if(res.Lower())
      res.SetChar(0,ushort(res.GetChar(0)-0x20));
//--- Replace all underscore characters with space in the resulting line
   StringReplace(res,"_"," ");
   string descr="";
   switch(transaction)
     {
      case TRADE_TRANSACTION_ORDER_ADD       :  descr=" (Adding a new open order)";                                                                   break;
      case TRADE_TRANSACTION_ORDER_UPDATE    :  descr=" (Updating an open order)";                                                                    break;
      case TRADE_TRANSACTION_ORDER_DELETE    :  descr=" (Removing an order from the list of the open ones)";                                          break;
      case TRADE_TRANSACTION_DEAL_ADD        :  descr=" (Adding a deal to the history)";                                                              break;
      case TRADE_TRANSACTION_DEAL_UPDATE     :  descr=" (Updating a deal in the history)";                                                            break;
      case TRADE_TRANSACTION_DEAL_DELETE     :  descr=" (Deleting a deal from the history)";                                                          break;
      case TRADE_TRANSACTION_HISTORY_ADD     :  descr=" (Adding an order to the history as a result of execution or cancellation)";                   break;
      case TRADE_TRANSACTION_HISTORY_UPDATE  :  descr=" (Changing an order located in the orders history)";                                           break;
      case TRADE_TRANSACTION_HISTORY_DELETE  :  descr=" (Deleting an order from the orders history)";                                                 break;
      case TRADE_TRANSACTION_POSITION        :  descr=" (Changing a position not related to a deal execution)";                                       break;
      case TRADE_TRANSACTION_REQUEST         :  descr=" (The trade request has been processed by a server and processing result has been received)";  break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Sample output:
      Order add (Adding a new open order)
   */
  }

La función retorna las descripciones de los tipos de transacciones comerciales realizadas en la cuenta.


Función que retorna la descripción del estado de la orden:

//+------------------------------------------------------------------+
//| Return an order state description                                |
//+------------------------------------------------------------------+
string OrderStateDescription(const ENUM_ORDER_STATE state,const bool ext_descr=false)
  {
//--- "Cut out" the order status from the string obtained from enum
   string res=StringSubstr(EnumToString(state),12);
//--- Convert all obtained symbols to lower case and replace the first letter from small to capital
   if(res.Lower())
      res.SetChar(0,ushort(res.GetChar(0)-0x20));
//--- Replace all underscore characters with space in the resulting line
   StringReplace(res,"_"," ");
   string descr="";
   switch(state)
     {
      case ORDER_STATE_STARTED         :  descr=" (Order checked, but not yet accepted by broker)";            break;
      case ORDER_STATE_PLACED          :  descr=" (Order accepted)";                                           break;
      case ORDER_STATE_CANCELED        :  descr=" (Order canceled by client)";                                 break;
      case ORDER_STATE_PARTIAL         :  descr=" (Order partially executed)";                                 break;
      case ORDER_STATE_FILLED          :  descr=" (Order fully executed)";                                     break;
      case ORDER_STATE_REJECTED        :  descr=" (Order rejected)";                                           break;
      case ORDER_STATE_EXPIRED         :  descr=" (Order expired)";                                            break;
      case ORDER_STATE_REQUEST_ADD     :  descr=" (Order is being registered (placing to the trading system))";break;
      case ORDER_STATE_REQUEST_MODIFY  :  descr=" (Order is being modified (changing its parameters))";        break;
      case ORDER_STATE_REQUEST_CANCEL  :  descr=" (Order is being deleted (deleting from the trading system))";break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Sample output:
      Placed (Order accepted)
   */
  }

Cada orden tiene un estado que describe su condición. Para obtener la información, utilizaremos las funciones OrderGetInteger() o HistoryOrderGetInteger() con el modificador ORDER_STATE. Los valores válidos se almacenan en la enumeración ENUM_ORDER_STATE. Al enviar una solicitud comercial al servidor, el estado de la orden cambiará gradualmente. Primero, el servidor la verificará, luego la colocará en el sistema comercial y luego la activará, generando una transacción, o bien será cancelada. La lista contiene todos los estados posibles de las órdenes y deberán considerarse al trabajar con órdenes comerciales.


Función que retorna la descripción del tipo de transacción:

//+------------------------------------------------------------------+
//| Return the deal type description                                 |
//+------------------------------------------------------------------+
string DealTypeDescription(const ENUM_DEAL_TYPE type,const bool ext_descr=false)
  {
//--- "Cut out" the deal type from the string obtained from enum
   string res=StringSubstr(EnumToString(type),(type==DEAL_DIVIDEND || type==DEAL_DIVIDEND_FRANKED || type==DEAL_TAX ? 5 : 10));
//--- Convert all obtained symbols to lower case and replace the first letter from small to capital
   if(res.Lower())
      res.SetChar(0,ushort(res.GetChar(0)-0x20));
//--- Replace all underscore characters with space in the resulting line
   StringReplace(res,"_"," ");
   string descr="";
//--- Extended descriptions are added only to the deals whose description obtained from enum does not match the extended one
   switch(type)
     {
      case DEAL_TYPE_CHARGE                  : descr=" (Additional charge)";                          break;
      case DEAL_TYPE_COMMISSION              : descr=" (Additional commission)";                      break;
      case DEAL_TYPE_COMMISSION_DAILY        : descr=" (Daily commission)";                           break;
      case DEAL_TYPE_COMMISSION_MONTHLY      : descr=" (Monthly commission)";                         break;
      case DEAL_TYPE_COMMISSION_AGENT_DAILY  : descr=" (Daily agent commission)";                     break;
      case DEAL_TYPE_COMMISSION_AGENT_MONTHLY: descr=" (Monthly agent commission)";                   break;
      case DEAL_TYPE_INTEREST                : descr=" (Interest rate)";                              break;
      case DEAL_TYPE_BUY_CANCELED            : descr=" (Canceled buy deal)";                          break;
      case DEAL_TYPE_SELL_CANCELED           : descr=" (Canceled sell deal)";                         break;
      case DEAL_DIVIDEND                     : descr=" (Dividend operations)";                        break;
      case DEAL_DIVIDEND_FRANKED             : descr=" (Franked (non-taxable) dividend operations)";  break;
      case DEAL_TAX                          : descr=" (Tax charges)";                                break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Sample output:
      Comission (Additional commission)
   */
  }

Cada transacción se caracteriza por un tipo, los valores posibles se enumeran en ENUM_DEAL_TYPE. Para obtener información sobre el tipo de transacción, utilice la función HistoryDealGetInteger() con el modificador DEAL_TYPE.


Función que retorna la descripción del tipo de orden según el vencimiento:

//+------------------------------------------------------------------+
//| Return an order type description by expiration                   |
//+------------------------------------------------------------------+
string OrderTypeTimeDescription(const ENUM_ORDER_TYPE_TIME type_time,const bool ext_descr=false)
  {
//--- "Cut out" the order type by expiration from the string obtained from enum
   string res=StringSubstr(EnumToString(type_time),6);
//--- If the type by expiration is ORDER_TIME_GTC, add "Time GTC" to res
   if(type_time==ORDER_TIME_GTC)
      res="Time GTC";
//--- Otherwise, convert all obtained symbols to lower case and replace the first letter from small to capital
   else
     {
      if(res.Lower())
         res.SetChar(0,ushort(res.GetChar(0)-0x20));
      //--- Replace all underscore characters with space in the resulting line
      StringReplace(res,"_"," ");
     }
   string descr="";
   switch(type_time)
     {
      case ORDER_TIME_GTC           : descr=" (Good till cancel order)";                                          break;
      case ORDER_TIME_DAY           : descr=" (Good till current trade day order)";                               break;
      case ORDER_TIME_SPECIFIED     : descr=" (Good till expired order)";                                         break;
      case ORDER_TIME_SPECIFIED_DAY : descr=" (The order will be effective till 23:59:59 of the specified day)";  break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Sample output:
      Time GTC (Good till cancel order)
   */
  }

La fecha de vencimiento de la orden se puede configurar en el campo type_time de la estructura MqlTradeRequest al enviar una solicitud comercial utilizando la función OrderSend(). Los valores válidos provienen de la enumeración ENUM_ORDER_TYPE_TIME. Para obtener el valor de esta propiedad, utilizaremos las funciones OrderGetInteger() o HistoryOrderGetInteger() con el modificador ORDER_TYPE_TIME.

Las transacciones comerciales pueden suceder con órdenes, transacciones y posiciones. En cada categoría de dichas transacciones puede haber diferentes tipos: adición, modificación y eliminación, pero a veces solo necesitamos saber con qué se ha realizado exactamente la transacción, sin especificar detalles: con una orden, transacción o posición. Para conseguir esto, crearemos una función que retorne la propiedad de la transacción:

//+------------------------------------------------------------------+
//| Define and set transaction affiliation values                    |
//+------------------------------------------------------------------+
void SetTransactionBelong(const ENUM_TRADE_TRANSACTION_TYPE type,bool &request_flag,bool &order_flag,bool &deal_flag,bool &position_flag)
  {
   switch(type)
     {
      //--- Request
      case TRADE_TRANSACTION_REQUEST         : request_flag=true; order_flag=false; deal_flag=false; position_flag=false; break;
      //--- Order
      case TRADE_TRANSACTION_ORDER_ADD       :
      case TRADE_TRANSACTION_ORDER_UPDATE    :
      case TRADE_TRANSACTION_ORDER_DELETE    :
      case TRADE_TRANSACTION_HISTORY_ADD     :
      case TRADE_TRANSACTION_HISTORY_UPDATE  :
      case TRADE_TRANSACTION_HISTORY_DELETE  : request_flag=false; order_flag=true; deal_flag=false; position_flag=false; break;
      //--- Deal
      case TRADE_TRANSACTION_DEAL_ADD        :
      case TRADE_TRANSACTION_DEAL_UPDATE     :
      case TRADE_TRANSACTION_DEAL_DELETE     : request_flag=false; order_flag=false; deal_flag=true; position_flag=false; break;
      //--- Position
      case TRADE_TRANSACTION_POSITION        : request_flag=false; order_flag=false; deal_flag=false; position_flag=true; break;
      //---
      default: break;
     }
  }

A la función se transmiten el tipo de transacción y tres variables de bandera por referencia, que se configuran/restablecen dependiendo de con qué se haya realizado exactamente la transacción.


Función que retorna la descripción del tipo de solicitud comercial:

//+------------------------------------------------------------------+
//| Return the trade request type description                        |
//+------------------------------------------------------------------+
string TradeActionDescription(const ENUM_TRADE_REQUEST_ACTIONS action,const bool ext_descr=false)
  {
//--- "Cut out" the operation type from the string obtained from enum
   string res=StringSubstr(EnumToString(action),13);
//--- Convert all obtained symbols to lower case and replace the first letter from small to capital (except for TRADE_ACTION_SLTP)
   if(action!=TRADE_ACTION_SLTP && res.Lower())
      res.SetChar(0,ushort(res.GetChar(0)-0x20));
   string descr="";
   switch(action)
     {
      case TRADE_ACTION_DEAL     : descr=" (Place a trade order for an immediate execution with the specified parameters (market order))";break;
      case TRADE_ACTION_PENDING  : descr=" (Place a trade order for the execution under specified conditions (pending order))";           break;
      case TRADE_ACTION_SLTP     : descr=" (Modify Stop Loss and Take Profit values of an opened position)";                              break;
      case TRADE_ACTION_MODIFY   : descr=" (Modify the parameters of the order placed previously)";                                       break;
      case TRADE_ACTION_REMOVE   : descr=" (Delete the pending order placed previously)";                                                 break;
      case TRADE_ACTION_CLOSE_BY : descr=" (Close a position by an opposite one)";                                                        break;
      default: break;
     }
   return res+(!ext_descr ? "" : descr);
   /* Sample output:
      Pending (Place a trade order for the execution under specified conditions (pending order)):
   */
  }


Bien, ahora veremos la estructura de la solicitud comercial y el resultado de la descripción de sus campos; asimismo, crearemos algunas funciones comerciales que explicarán cómo trabajar con esta estructura.

Estructura MqlTradeRequest en la creación de una solicitud al realizar operaciones comerciales

La interacción entre el terminal del cliente y el servidor comercial para realizar operaciones de colocación de órdenes se efectúa a través de solicitudes comerciales. La solicitud está representada por la estructura especial predefinida MqlTradeRequest, que contiene todos los campos necesarios para realizar transacciones comerciales.:

struct MqlTradeRequest
  {
   ENUM_TRADE_REQUEST_ACTIONS    action;           // Type of a performed action
   ulong                         magic;            // EA stamp (magic number ID)
   ulong                         order;            // Order ticket
   string                        symbol;           // Symbol name
   double                        volume;           // Requested volume of a deal in lots
   double                        price;            // Price 
   double                        stoplimit;        // StopLimit order level
   double                        sl;               // Stop Loss order level
   double                        tp;               // Take Profit order level
   ulong                         deviation;        // Maximum acceptable deviation from the requested price
   ENUM_ORDER_TYPE               type;             // Order type
   ENUM_ORDER_TYPE_FILLING       type_filling;     // Order filling type
   ENUM_ORDER_TYPE_TIME          type_time;        // Order lifetime type
   datetime                      expiration;       // Order expiration time (for ORDER_TIME_SPECIFIED type orders)
   string                        comment;          // Order comment
   ulong                         position;         // Position ticket
   ulong                         position_by;      // Opposite position ticket
  };

Para enviar una orden comercial al servidor, deberemos rellenar los campos de la estructura de la forma correspondiente para la orden. El campo action deberá rellenarse obligatoriamente, y dependiendo de qué acción se escriba en este campo, solo se rellenarán los demás campos de la estructura necesarios para esta acción. Como consecuencia, los campos no utilizados contendrán ceros (siempre que los campos de la estructura se restablezcan a cero antes de rellenarla). Al mostrar la descripción de los campos de una estructura, deberemos considerar que algunos campos no se utilizan y contienen ceros. Esto debería mostrarse al enviar un campo no utilizado al registro, por ejemplo, en lugar de usar el número de decimales para el valor (1,12345), usar solo uno (0,0); esto dejaría más claro que este campo simplemente no ha sido rellenado.

Pero en la muestra final de la estructura en el registro, consideraremos los campos no utilizados según la transacción y simplemente no los mostraremos.


Tipo de acción realizada

Tipo de operación comercial. El valor puede ser uno de los valores de la enumeración ENUM_TRADE_REQUEST_ACTIONS.

//+------------------------------------------------------------------+
//| Return the type of a performed action as a string                |
//+------------------------------------------------------------------+
string MqlTradeRequestAction(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Action:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,TradeActionDescription(req.action,ext_descr));
   /* Sample output:
      Action: Pending (Place a trade order for the execution under specified conditions (pending order)):
   */
  }


Sello del experto (identificador magic number)

Identificador del experto. Nos permite organizar el procesamiento analítico de las órdenes comerciales. Cada experto puede establecer su propio identificador único al enviar una solicitud comercial.
//+------------------------------------------------------------------+
//| Return the EA stamp (magic number) as a string                   |
//+------------------------------------------------------------------+
string MqlTradeRequestMagic(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Magic:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,req.magic);
   /* Sample output:
      Magic: 1024
   */
  }


Ticket de la orden

Ticket de la orden. Se necesita para modificar las órdenes pendientes.

//+------------------------------------------------------------------+
//| Return the order ticket as a string                              |
//+------------------------------------------------------------------+
string MqlTradeRequestOrder(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Order:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,req.order);
   /* Sample output:
      Order: 1835982676
   */
  }


Nombre del instrumento comercial

Nombre del instrumento comercial para el que se establece la orden. No es necesario para las operaciones de modificación de órdenes y cierre de posiciones..

//+------------------------------------------------------------------+
//| Return a trading instrument name                                 |
//+------------------------------------------------------------------+
string MqlTradeRequestSymbol(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Symbol:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,req.symbol);
   /* Sample output:
      Symbol: EURUSD
   */
  }


Volumen de las transacciones solicitado en lotes

Volumen de las transacciones solicitado en lotes. El valor real del volumen al abrir una transacción dependerá del tipo de orden de ejecución.

//+------------------------------------------------------------------+
//| Return the requested volume of a deal in lots as a string        |
//+------------------------------------------------------------------+
string MqlTradeRequestVolume(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Volume:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the number of decimal places in the lot value. If the character is not specified, use 1
   int dg=(int)ceil(fabs(log10(SymbolInfoDouble(req.symbol,SYMBOL_VOLUME_STEP))));
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,req.volume);
   /* Sample output:
      Volume: 0.10
   */
  }


Precio

Precio al que se debe ejecutar la orden. Para las órdenes de mercado de los instrumentos con el tipo de ejecución "Ejecución de mercado" (SYMBOL_TRADE_EXECUTION_MARKET), que tengan el tipo TRADE_ACTION_DEAL, no se requerirá el precio.

//+------------------------------------------------------------------+
//| Return the price as a string                                     |
//+------------------------------------------------------------------+
string MqlTradeRequestPrice(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Price:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the number of decimal places
   int dg=(req.price!=0 ? (int)SymbolInfoInteger(req.symbol,SYMBOL_DIGITS) : 1);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,req.price);
   /* Sample output:
      Price: 1.09586
   */
  }


Nivel StopLimit de la orden

Para las órdenes pendientes BuyStopLimit y SellStopLimit. Precio al que se colocará una orden límite pendiente cuando el precio alcance el valor price (esta condición es obligatoria). Hasta ese momento, la orden pendiente no se mostrará en el sistema comercial..

//+------------------------------------------------------------------+
//| Return the StopLimit order level as a string                     |
//+------------------------------------------------------------------+
string MqlTradeRequestStopLimit(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="StopLimit:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the number of decimal places
   int dg=(req.stoplimit!=0 ? (int)SymbolInfoInteger(req.symbol,SYMBOL_DIGITS) : 1);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,req.stoplimit);
   /* Sample output:
      StopLimit: 0.0
   */
  }


Nivel Stop Loss de la orden

Precio al que se activará una orden Stop Loss cuando el precio se mueva en una dirección desfavorable.

//+------------------------------------------------------------------+
//| Return the Stop Loss order level as a string                     |
//+------------------------------------------------------------------+
string MqlTradeRequestStopLoss(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="SL:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the number of decimal places
   int dg=(req.sl!=0 ? (int)SymbolInfoInteger(req.symbol,SYMBOL_DIGITS) : 1);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,req.sl);
   /* Sample output:
      SL: 0.0
   */
  }


Nivel Take Profit de la orden

Precio al que se activará la orden Take Profit cuando el precio se mueva en una dirección favorable.

//+------------------------------------------------------------------+
//| Return the Take Profit order level as a string                   |
//+------------------------------------------------------------------+
string MqlTradeRequestTakeProfit(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="TP:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the number of decimal places
   int dg=(req.tp!=0 ? (int)SymbolInfoInteger(req.symbol,SYMBOL_DIGITS) : 1);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,req.tp);
   /* Sample output:
      TP: 0.0
   */
  }


Desviación respecto al precio solicitado

Desviación máxima aceptable del precio de venta, especificada en puntos.

//+------------------------------------------------------------------+
//| Return the maximum acceptable                                    |
//| deviation from the requested price                               |
//+------------------------------------------------------------------+
string MqlTradeRequestDeviation(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Deviation:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,req.deviation);
   /* Sample output:
      Deviation: 5
   */
  }


Tipo de orden

Tipo de orden. El valor puede ser uno de los valores de la enumeración ENUM_ORDER_TYPE.

//+------------------------------------------------------------------+
//| Return the order type as a string                                |
//+------------------------------------------------------------------+
string MqlTradeRequestType(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0,bool ext_descr=false)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Type:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,OrderTypeDescription(req.type,ext_descr));
   /* Sample output:
      Type: Buy Limit (Buy Limit pending order)
   */
  }


Tipo de orden según la ejecución

Tipo de orden según la ejecución. El valor puede ser uno de los valores de ENUM_ORDER_TYPE_FILLING.

//+------------------------------------------------------------------+
//| Return the order type by execution as a string                   |
//+------------------------------------------------------------------+
string MqlTradeRequestTypeFilling(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0,bool ext_descr=false)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Type filling:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,OrderTypeFillingDescription(req.type_filling,ext_descr));
   /* Sample output:
      Type filling: Return (In case of partial filling, an order with remaining volume is not canceled but processed further)
   */
  }


Tipo de orden por duración

Tipo de orden según el vencimiento. El valor puede ser uno de los valores de ENUM_ORDER_TYPE_TIME.

//+------------------------------------------------------------------+
//| Return the order type by expiration time as a string             |
//+------------------------------------------------------------------+
string MqlTradeRequestTypeTime(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0,bool ext_descr=false)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Type time:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,OrderTypeTimeDescription(req.type_time,ext_descr));
   /* Sample output:
      Type time: Time GTC (Good till cancel order)
   */
  }


Fecha de vencimiento de la orden

Fecha de vencimiento de una orden pendiente (para órdenes del tipo ORDER_TIME_SPECIFIED).

//+------------------------------------------------------------------+
//| Return the order expiration time as a string                     |
//+------------------------------------------------------------------+
string MqlTradeRequestExpiration(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Expiration:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,(req.type_time==ORDER_TIME_SPECIFIED || req.type_time==ORDER_TIME_SPECIFIED_DAY ? (string)req.expiration : "0"));
   /* Sample output:
      Expiration: 0
   */
  }


Comentarios a la orden

//+------------------------------------------------------------------+
//| Return the order comment                                         |
//+------------------------------------------------------------------+
string MqlTradeRequestComment(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Comment:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,req.comment);
   /* Sample output:
      Comment: TestMqlTradeTransaction
   */
  }


Ticket de la posición

Ticket de la posición. Deberá rellenarse al cambiar y cerrar una posición para su identificación inequívoca. Por regla general, se corresponde con el ticket de la orden que ha dado lugar a la apertura de la posición.

//+------------------------------------------------------------------+
//| Return the position ticket as a string                           |
//+------------------------------------------------------------------+
string MqlTradeRequestPosition(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Position:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,req.position);
   /* Sample output:
      Position: 1835982676
   */
  }


Ticket de la posición opuesta

Ticket de la posición opuesta. Se utiliza al cerrar una posición con otra opuesta: se abrirá en el mismo instrumento, pero en la dirección opuesta.

//+------------------------------------------------------------------+
//| Return the opposite position ticket as a string                  |
//+------------------------------------------------------------------+
string MqlTradeRequestPositionBy(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Position by:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,req.position_by);
   /* Sample output:
      Position by: 1835987626
   */
  }


Ejemplos de uso

Para diferentes tipos de órdenes comerciales, los campos de estructura se rellenarán individualmente según la orden. Veamos ejemplos reales: primero crearemos una función que muestre las descripciones de los campos de estructura dependiendo de la acción que se realice y las funciones comerciales para abrir/cerrar posiciones y para configurar/eliminar órdenes pendientes.

Función que muestra la descripción de una solicitud comercial:

//+------------------------------------------------------------------+
//| Display the trading request description in the journal           |
//+------------------------------------------------------------------+
void TradeRequestPrint(const MqlTradeRequest &req,const uint header_width=0,const uint indent=0,bool ext_descr=false)
  {
//--- Get execution type by symbol
   ENUM_SYMBOL_TRADE_EXECUTION exemode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(req.symbol,SYMBOL_TRADE_EXEMODE);
//--- Header
   PrintFormat("Request %s:",TradeActionDescription(req.action,ext_descr));
//--- Place an order for an instant deal with the specified parameters (set a market order)
   if(req.action==TRADE_ACTION_DEAL)
     {
      //--- Depending on the transaction mode 
      switch(exemode)
        {
         //--- Trade order to open a position in the Request Execution mode
         //--- Trade order to open a position in the Instant Execution mode
         case SYMBOL_TRADE_EXECUTION_REQUEST    :
         case SYMBOL_TRADE_EXECUTION_INSTANT    :
            Print(MqlTradeRequestSymbol(req,header_width,indent));
            Print(MqlTradeRequestVolume(req,header_width,indent));
            Print(MqlTradeRequestPrice(req,header_width,indent));
            if(req.position==0)  // Only for opening a position 
               Print(MqlTradeRequestStopLoss(req,header_width,indent));
            if(req.position==0)  // Only for opening a position 
               Print(MqlTradeRequestTakeProfit(req,header_width,indent));
            Print(MqlTradeRequestDeviation(req,header_width,indent));
            Print(MqlTradeRequestType(req,header_width,indent,ext_descr));
            Print(MqlTradeRequestTypeFilling(req,header_width,indent,ext_descr));
            Print(MqlTradeRequestMagic(req,header_width,indent));
            if(req.position==0)  // Only for opening a position 
               Print(MqlTradeRequestComment(req,header_width,indent));
            //--- Closing
            if(req.position!=0)
               Print(MqlTradeRequestPosition(req,header_width,indent));
           break;
         //--- Trade order to open a position in the Market Execution mode
         //--- Trade order to open a position in the Exchange Execution mode
         case SYMBOL_TRADE_EXECUTION_MARKET     :
         case SYMBOL_TRADE_EXECUTION_EXCHANGE   :
            Print(MqlTradeRequestSymbol(req,header_width,indent));
            Print(MqlTradeRequestVolume(req,header_width,indent));
            Print(MqlTradeRequestType(req,header_width,indent,ext_descr));
            Print(MqlTradeRequestTypeFilling(req,header_width,indent,ext_descr));
            Print(MqlTradeRequestMagic(req,header_width,indent));
            if(req.position==0)  // Only for opening a position 
               Print(MqlTradeRequestComment(req,header_width,indent));
            //--- Closing
            if(req.position!=0)
               Print(MqlTradeRequestPosition(req,header_width,indent));
           break;
         default:
           break;
        }
     }
//--- Trading order to close a position by an opposite one
   if(req.action==TRADE_ACTION_CLOSE_BY)
     {
      Print(MqlTradeRequestSymbol(req,header_width,indent));
      Print(MqlTradeRequestPosition(req,header_width,indent));
      Print(MqlTradeRequestMagic(req,header_width,indent));
      Print(MqlTradeRequestComment(req,header_width,indent));
      Print(MqlTradeRequestPositionBy(req,header_width,indent));
     }
//--- Trading order to modify StopLoss and/or TakeProfit levels
   if(req.action==TRADE_ACTION_SLTP)
     {
      Print(MqlTradeRequestSymbol(req,header_width,indent));
      Print(MqlTradeRequestStopLoss(req,header_width,indent));
      Print(MqlTradeRequestTakeProfit(req,header_width,indent));
      Print(MqlTradeRequestPosition(req,header_width,indent));
     }
//--- Trading order to place a pending order
   if(req.action==TRADE_ACTION_PENDING)
     {
      Print(MqlTradeRequestSymbol(req,header_width,indent));
      Print(MqlTradeRequestVolume(req,header_width,indent));
      Print(MqlTradeRequestPrice(req,header_width,indent));
      if(req.type==ORDER_TYPE_BUY_STOP_LIMIT || req.type==ORDER_TYPE_SELL_STOP_LIMIT)
         Print(MqlTradeRequestStopLimit(req,header_width,indent));
      Print(MqlTradeRequestStopLoss(req,header_width,indent));
      Print(MqlTradeRequestTakeProfit(req,header_width,indent));
      Print(MqlTradeRequestType(req,header_width,indent,ext_descr));
      Print(MqlTradeRequestTypeFilling(req,header_width,indent,ext_descr));
      Print(MqlTradeRequestTypeTime(req,header_width,indent,ext_descr));
      Print(MqlTradeRequestExpiration(req,header_width,indent));
      Print(MqlTradeRequestMagic(req,header_width,indent));
      Print(MqlTradeRequestComment(req,header_width,indent));
     }
//--- Trading order to modify the price levels of a pending order
   if(req.action==TRADE_ACTION_MODIFY)
     {
      Print(MqlTradeRequestOrder(req,header_width,indent));
      Print(MqlTradeRequestPrice(req,header_width,indent));
      if(req.stoplimit!=0)
         Print(MqlTradeRequestStopLimit(req,header_width,indent));
      Print(MqlTradeRequestStopLoss(req,header_width,indent));
      Print(MqlTradeRequestTakeProfit(req,header_width,indent));
      Print(MqlTradeRequestTypeTime(req,header_width,indent,ext_descr));
      Print(MqlTradeRequestExpiration(req,header_width,indent));
     }
//--- Trading order to remove a pending order
   if(req.action==TRADE_ACTION_REMOVE)
     {
      Print(MqlTradeRequestOrder(req,header_width,indent));
     }
   /* Sample output:
      Request Pending (Place a trade order for the execution under specified conditions (pending order)):
        Symbol: EURUSD
        Volume: 0.10
        Price: 1.09586
        SL: 0.0
        TP: 0.0
        Type: Buy Limit (Buy Limit pending order)
        Type filling: Return (In case of partial filling, an order with remaining volume is not canceled but processed further)
        Type time: Time GTC (Good till cancel order)
        Expiration: 0
        Magic: 1024
        Comment: TestMqlTradeTransaction
   */
  }


OpenBuy para abrir una posición de compra:

//+------------------------------------------------------------------+
//| Open Buy position                                                |
//+------------------------------------------------------------------+
bool OpenBuy(const string symbol,const double lots,const uint magic,const ulong deviation=5,const string comment="")
  {
//--- Set a symbol for a request
   string symbol_name=(symbol==NULL ? Symbol() : symbol);
//--- Declare and initialize the request and result structures
   MqlTradeRequest request={};
   MqlTradeResult  result={};
//--- Get the normalized price
   double price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_ASK),(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS));
//--- request parameters
   request.action    =  TRADE_ACTION_DEAL;                        // trading operation type
   request.symbol    =  symbol_name;                              // symbol
   request.volume    =  lots;                                     // position volume
   request.type      =  ORDER_TYPE_BUY;                           // order type
   request.price     =  price;                                    // open price
   request.deviation =  deviation;                                // allowed deviation from the price
   request.magic     =  magic;                                    // order MagicNumber
   request.comment   =  comment;                                  // Order comment
//--- If failed to send a request, inform of that and return 'false'
   if(!OrderSend(request,result))
     {
      PrintFormat("%s: OrderSend for %s %s error: %s",__FUNCTION__,
                  TradeActionDescription(request.action),OrderTypeDescription(request.type),RetcodeDescription(result.retcode,true)
                 );
      return false;
     }
//--- OrderSend OK, return 'true'
   return true;
  }


OpenSell para abrir una posición de venta:

//+------------------------------------------------------------------+
//| Open a Sell position                                             |
//+------------------------------------------------------------------+
bool OpenSell(const string symbol,const double lots,const uint magic,const ulong deviation=5,const string comment="")
  {
//--- Set a symbol for a request
   string symbol_name=(symbol==NULL ? Symbol() : symbol);
//--- Declare and initialize the request and result structures
   MqlTradeRequest request={};
   MqlTradeResult  result={};
//--- Get the normalized price
   double price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_BID),(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS));
//--- request parameters
   request.action    =  TRADE_ACTION_DEAL;                        // trading operation type
   request.symbol    =  symbol_name;                              // symbol
   request.volume    =  lots;                                     // position volume
   request.type      =  ORDER_TYPE_SELL;                          // order type
   request.price     =  price;                                    // open price
   request.deviation =  deviation;                                // allowed deviation from the price
   request.magic     =  magic;                                    // order MagicNumber
   request.comment   =  comment;                                  // Order comment
//--- If failed to send a request, inform of that and return 'false'
   if(!OrderSend(request,result))
     {
      PrintFormat("%s: OrderSend for %s %s error: %s",__FUNCTION__,
                  TradeActionDescription(request.action),OrderTypeDescription(request.type),RetcodeDescription(result.retcode,true)
                 );
      return false;
     }
//--- OrderSend OK, return 'true'
   return true;
  }


ClosePosition para cerrar la posición indicada:

//+------------------------------------------------------------------+
//| Close position by ticket                                         |
//+------------------------------------------------------------------+
bool ClosePosition(const ulong ticket,const ulong deviation=5)
  {
//--- Declare request and result structures
   MqlTradeRequest request;
   MqlTradeResult  result;
//--- If failed to select a position by ticket, inform of the error and leave
   ResetLastError();
   if(!PositionSelectByTicket(ticket))
     {
      Print("PositionSelectByTicket failed, error: ",(string)GetLastError());
      return false;
     }
//--- Get the data on the closed position
   string position_symbol=PositionGetString(POSITION_SYMBOL);                       // symbol 
   int    digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);             // number of decimal places
   double volume=PositionGetDouble(POSITION_VOLUME);                                // position volume
   ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);   // position type
   ulong magic=PositionGetInteger(POSITION_MAGIC);                                  // position MagicNumber
//--- Set request and result values to zero
   ZeroMemory(request);
   ZeroMemory(result);
//--- Set operation parameters
   request.action    =  TRADE_ACTION_DEAL;   // trading operation type
   request.position  =  ticket;              // position ticket
   request.symbol    =  position_symbol;     // symbol 
   request.volume    =  volume;              // position volume
   request.deviation =  deviation;           // allowed deviation from the price
   request.magic     =  magic;               // position MagicNumber
//--- Set order price and type depending on the position type
   if(type==POSITION_TYPE_BUY)
     {
      request.price=NormalizeDouble(SymbolInfoDouble(position_symbol,SYMBOL_BID),digits);
      request.type =ORDER_TYPE_SELL;
     }
   else
     {
      request.price=NormalizeDouble(SymbolInfoDouble(position_symbol,SYMBOL_ASK),digits);
      request.type =ORDER_TYPE_BUY;
     }
//--- If failed to send a request, inform of that and return 'false'
   if(!OrderSend(request,result))
     {
      PrintFormat("%s: OrderSend for %s %s #%llu error: %s",__FUNCTION__,
                  TradeActionDescription(request.action),OrderTypeDescription(request.type),ticket,RetcodeDescription(result.retcode,true)
                 );
      return false;
     }
//--- OrderSend OK, return 'true'
   return true;
  }


ClosePositionsAll para cerrar todas las posiciones:

//+------------------------------------------------------------------+
//| Close all positions on a symbol                                  |
//+------------------------------------------------------------------+
uint ClosePositionsAll(const string symbol,const ulong magic=0)
  {
//--- Declare the variable for storing the result and the number of closed positions
   bool res=true;
   uint num=0;
//--- iterate over open positions
   int total=PositionsTotal();                     // number of open positions
   for(int i=total-1; i>=0; i--)
     {
      ulong  position_ticket=PositionGetTicket(i); // position ticket
      if(position_ticket==0)
         continue;
      if(PositionGetInteger(POSITION_MAGIC)!=magic)
         continue;
      //--- If MagicNumber is not specified (zero) or position magic number matches the specified one
      if(magic==0 || PositionGetInteger(POSITION_MAGIC)==magic)
        {
         //--- if the position symbol matches the one passed or NULL is passed, close the position on the ticket 
         if(symbol==NULL || PositionGetString(POSITION_SYMBOL)==symbol)
           {
            //--- Get the result of closing a position on a ticket and increase the counter of closed positions if successful 
            res &=ClosePosition(position_ticket);
            if(res)
               num++;
           }
        }
     }
   if(!res)
      PrintFormat("%s: Not all positions were able to close without errors",__FUNCTION__);
   return num;
  }


SetPending para establecer una orden pendiente:

//+------------------------------------------------------------------+
//| Place a specified pending order                                  |
//+------------------------------------------------------------------+
bool SetPending(const string symbol,const ENUM_ORDER_TYPE order_type,const double lots,const uint magic,const int distance,const int stoplimit=0,const string comment="")
  {
//--- Set a symbol for a request
   string symbol_name=(symbol==NULL ? Symbol() : symbol);
//--- Declare and initialize the request and result structures
   MqlTradeRequest request={};
   MqlTradeResult  result={};
//--- Set operation parameters
   request.action    =  TRADE_ACTION_PENDING;                     // trading operation type
   request.type      =  order_type;                               // order type
   request.symbol    =  symbol_name;                              // symbol
   request.volume    =  lots;                                     // volume
   request.magic     =  magic;                                    // order MagicNumber
   request.comment   =  comment;                                  // Order comment
//--- Get Point and Digits
   double point=SymbolInfoDouble(symbol_name,SYMBOL_POINT);
   int digits=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS);
//--- Calculate the distance from the price depending on the order type
//--- Buy order
   if(order_type==ORDER_TYPE_BUY_STOP)
      request.price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_ASK)+distance*point,digits);  // normalized setting price 
   if(order_type==ORDER_TYPE_BUY_LIMIT)
      request.price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_ASK)-distance*point,digits);  // normalized setting price 
   if(order_type==ORDER_TYPE_BUY_STOP_LIMIT)
     {
      request.price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_ASK)+distance*point,digits);  // normalized Stop order trigger price 
      request.stoplimit=NormalizeDouble(request.price-stoplimit*point,digits);                        // normalized Limit order setting price
     }
//--- Sell order
   if(order_type==ORDER_TYPE_SELL_STOP)
      request.price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_BID)-distance*point,digits);  // normalized setting price 
   if(order_type==ORDER_TYPE_SELL_LIMIT)
      request.price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_BID)+distance*point,digits);  // normalized setting price 
   if(order_type==ORDER_TYPE_SELL_STOP_LIMIT)
     {
      request.price=NormalizeDouble(SymbolInfoDouble(symbol_name,SYMBOL_BID)-distance*point,digits);  // normalized Stop order trigger price 
      request.stoplimit=NormalizeDouble(request.price+stoplimit*point,digits);                        // normalized Limit order setting price
     }
//--- If failed to send a request, inform of that and return 'false'
   if(!OrderSend(request,result))
     {
      PrintFormat("%s: OrderSend for %s %s error: %s",__FUNCTION__,
                  TradeActionDescription(request.action),OrderTypeDescription(request.type),RetcodeDescription(result.retcode,true)
                 );
      return false;
     }
//--- OrderSend OK, return 'true'
   return true;
  }


Usando como base la función presentada anteriormente, podemos crear funciones que establezcan un tipo específico de orden pendiente:

SetBuyStop para establecer una orden BuyStop pendiente:

//+------------------------------------------------------------------+
//| Place BuyStop pending order                                      |
//+------------------------------------------------------------------+
bool SetBuyStop(const string symbol,const double lots,const uint magic,const int distance,const string comment="")
  {
//--- Call the SetPending function with BuyStop parameters
   return SetPending(symbol,ORDER_TYPE_BUY_STOP,lots,magic,distance,0,comment);
  }


SetBuyLimit para establecer una orden BuyLimit pendiente:

//+------------------------------------------------------------------+
//| Place BuyLimit pending order                                     |
//+------------------------------------------------------------------+
bool SetBuyLimit(const string symbol,const double lots,const uint magic,const int distance,const string comment="")
  {
//--- Call the SetPending function with BuyLimit parameters
   return SetPending(symbol,ORDER_TYPE_BUY_LIMIT,lots,magic,distance,0,comment);
  }


SetBuyStopLimit para establecer una orden BuyStopLimit pendiente:

//+------------------------------------------------------------------+
//| Place BuyStopLimit pending order                                 |
//+------------------------------------------------------------------+
bool SetBuyStopLimit(const string symbol,const double lots,const uint magic,const int distance,const int stoplimit,const string comment="")
  {
//--- Call the SetPending function with BuyStopLimit parameters
   return SetPending(symbol,ORDER_TYPE_BUY_STOP_LIMIT,lots,magic,distance,stoplimit,comment);
  }


SetSellStop para establecer una orden SellStop pendiente:

//+------------------------------------------------------------------+
//| Place SellStop pending order                                     |
//+------------------------------------------------------------------+
bool SetSellSellStop(const string symbol,const double lots,const uint magic,const int distance,const string comment="")
  {
//--- Call the SetPending function with SellStop parameters
   return SetPending(symbol,ORDER_TYPE_SELL_STOP,lots,magic,distance,0,comment);
  }


SetSellLimit para establecer una orden SellLimit pendiente:

//+------------------------------------------------------------------+
//| Place SellLimit pending order                                    |
//+------------------------------------------------------------------+
bool SetSellLimit(const string symbol,const double lots,const uint magic,const int distance,const string comment="")
  {
//--- Call the SetPending function with SellLimit parameters
   return SetPending(symbol,ORDER_TYPE_SELL_LIMIT,lots,magic,distance,0,comment);
  }


SetSellStopLimit para establecer una orden SellStopLimit pendiente:

//+------------------------------------------------------------------+
//| Place SellStopLimit pending order                                |
//+------------------------------------------------------------------+
bool SetSellStopLimit(const string symbol,const double lots,const uint magic,const int distance,const int stoplimit,const string comment="")
  {
//--- Call the SetPending function with SellStopLimit parameters
   return SetPending(symbol,ORDER_TYPE_SELL_STOP_LIMIT,lots,magic,distance,stoplimit,comment);
  }


DeleteOrder para eliminar el orden pendiente especificada:

//+------------------------------------------------------------------+
//| Delete a pending order by ticket                                 |
//+------------------------------------------------------------------+
bool DeleteOrder(const ulong ticket)
  {
//--- declare and initialize the trade request and result
   MqlTradeRequest request={};
   MqlTradeResult  result={};
   ResetLastError();
//--- If failed to select an order by ticket, inform of the error and leave
   if(!OrderSelect(ticket))
     {
      PrintFormat("%s: OrderSelect failed, error: %d",__FUNCTION__,GetLastError());
      return false;
     }
//--- Set request and result values to zero
   ZeroMemory(request);
   ZeroMemory(result);
//--- Set operation parameters
   request.action=TRADE_ACTION_REMOVE;                   // trading operation type
   request.order = ticket;                               // order ticket
//--- If failed to send a request, inform of that and return 'false'
   if(!OrderSend(request,result))
     {
      PrintFormat("%s: OrderSend for %s %s #%llu error: %s",__FUNCTION__,
                  TradeActionDescription(request.action),OrderTypeDescription((ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE)),ticket,RetcodeDescription(result.retcode,true)
                 );
      return false;
     }
//--- OrderSend OK, return 'true'
   return true;
  }


DeleteOrdersAll para eliminar todas las órdenes pendientes:

//+------------------------------------------------------------------+
//| Delete all pending orders by symbol                              |
//+------------------------------------------------------------------+
uint DeleteOrdersAll(const string symbol,const long magic=WRONG_VALUE)
  {
//--- Declare the variable for storing the result and the number of removed orders
   bool res=true;
   uint num=0;
//--- iterate over all placed pending orders
   int total=OrdersTotal(); // number of pending orders
   for(int i=total-1; i>=0; i--)
     {
      ulong  order_ticket=OrderGetTicket(i);             // order ticket
      if(order_ticket==0)
         continue;
      //--- If MagicNumber is not specified (zero) or order magic number matches the specified one
      if(magic==WRONG_VALUE || OrderGetInteger(ORDER_MAGIC)==magic)
        {
         //--- if the order symbol matches the one passed or NULL is passed, remove order by ticket
         if(symbol==NULL || OrderGetString(ORDER_SYMBOL)==symbol)
           {
            res &=DeleteOrder(order_ticket);
            if(res)
               num++;
           }
        }
     }
   if(!res)
      PrintFormat("%s: Not all orders were able to close without errors",__FUNCTION__);
   return num;
  }

Todas las funciones comerciales anteriormente presentadas son funciones de ejemplo simples. No gestionan ni corrigen errores según el código de error y el código de retorno del servidor. Podremos crear dichas funciones basándonos en ellas, pero esto queda más allá del alcance de este artículo.

Tras completar la estructura de la orden comercial, podremos verificar su exactitud. Esto se puede lograr usando la función OrderCheck(), que verifica si hay fondos suficientes para completar la operación comercial requerida.

Si los fondos son insuficientes o los parámetros se han rellenado incorrectamente, la función retornará false. Si la verificación básica de las estructuras (comprobación de punteros) tiene éxito, se retornará true: esto no indica que la operación comercial solicitada se vaya a realizar con éxito.. Para obtener una descripción detallada del resultado de la ejecución de una función, deberemos analizar los campos de la estructura result.

Los resultados de la verificación se colocarán en los campos de la estructura MqlTradeCheckResult. Para mostrar las descripciones de los campos de esta estructura, escribiremos las funciones correspondientes.


La estructura MqlTradeCheckResult para comprobar una solicitud preparada antes de enviarla

Antes de enviar una solicitud de operación comercial al servidor comercial, se recomienda verificarla. La verificación la realiza la función OrderCheck(), a la que se le transmite la solicitud que se está verificando y una variable del tipo de estructura MqlTradeCheckResult. El resultado de la verificación se escribirá en esta variable.

struct MqlTradeCheckResult
  {
   uint         retcode;             // Response code
   double       balance;             // Balance after performing a deal
   double       equity;              // Equity after performing a deal
   double       profit;              // Floating profit
   double       margin;              // Margin requirements
   double       margin_free;         // Free margin
   double       margin_level;        // Margin level
   string       comment;             // Comment on the response code (error description)
  };


Código de respuesta

Código de retornoTodas las órdenes para realizar operaciones comerciales se envían en forma de estructura de solicitud comercial MqlTradeRequest usando la función OrderSend(). El resultado de la ejecución de esta función se colocará en la estructura MqlTradeResult, el campo retcode que contiene el código de retorno del servidor comercial. Lo mismo sucede aquí: tras verificar una orden comercial, el código de respuesta se podrá leer en el campo retcode de la estructura MqlTradeCheckResult.

//+------------------------------------------------------------------+
//| Return the response code as a string                             |
//+------------------------------------------------------------------+
string MqlTradeCheckResultRetcode(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Retcode:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,RetcodeDescription(result.retcode,ext_descr));
   /* Sample output:
      Retcode: OK (0)
   */
  }


Balance después de una transacción

Valor de balance presente tras completarse la operación comercial.

//+----------------------------------------------------------------------+
//| Returns the balance as a string after a trade operation is performed |
//+----------------------------------------------------------------------+
string MqlTradeCheckResultBalance(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Balance:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the account currency
   string currency=AccountInfoString(ACCOUNT_CURRENCY);
//--- Get the number of decimal places
   int dg=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f %s",indent,"",w,header,dg,result.balance,currency);
   /* Sample output:
      Balance: 10016.80 USD
   */
  }


Equidad después de una transacción

Valor de equidad que quedará tras ejecutar una operación comercial.

//+--------------------------------------------------------------------+
//| Return the equity as a string after a trade operation is performed |
//+--------------------------------------------------------------------+
string MqlTradeCheckResultEquity(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Equity:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the account currency
   string currency=AccountInfoString(ACCOUNT_CURRENCY);
//--- Get the number of decimal places
   int dg=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f %s",indent,"",w,header,dg,result.equity,currency);
   /* Sample output:
      Equity: 10016.80 USD
   */
  }


Beneficio flotante

Valor del beneficio flotante que quedará después de la ejecución de la operación comercial.

//+---------------------------------------------------------------------------+
//|Return the floating profit as a string after a trade operation is performed|
//+---------------------------------------------------------------------------+
string MqlTradeCheckResultProfit(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Profit:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the account currency
   string currency=AccountInfoString(ACCOUNT_CURRENCY);
//--- Get the number of decimal places
   int dg=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f %s",indent,"",w,header,dg,result.profit,currency);
   /* Sample output:
      Profit: 0.00 USD
   */
  }


Requisitos de margen

Cantidad de margen requerido para la operación comercial necesaria.

//+------------------------------------------------------------------+
//| Return the margin,                                               |
//| required for the necessary trading operation, as a string        |
//+------------------------------------------------------------------+
string MqlTradeCheckResultMargin(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Margin:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the account currency
   string currency=AccountInfoString(ACCOUNT_CURRENCY);
//--- Get the number of decimal places
   int dg=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f %s",indent,"",w,header,dg,result.margin,currency);
   /* Sample output:
      Margin: 128.66 USD
   */
  }


Margen libre

Cantidad de capital libre que quedará tras completar la operación comercial requerida.

//+------------------------------------------------------------------+
//| Return the value of equity                                       |
//| to be left after conducting a trading operation as a string      |
//+------------------------------------------------------------------+
string MqlTradeCheckResultMarginFree(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Margin free:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the account currency
   string currency=AccountInfoString(ACCOUNT_CURRENCY);
//--- Get the number of decimal places
   int dg=(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f %s",indent,"",w,header,dg,result.margin_free,currency);
   /* Sample output:
      Margin free: 9888.14 USD
   */
  }


Nivel de margen

Nivel de margen que se establecerá tras completar la operación comercial requerida.

//+-----------------------------------------------------------------------+
//| Return the margin level                                               |
//| to be set after completing the required trading operation as a string |
//+-----------------------------------------------------------------------+
string MqlTradeCheckResultMarginLevel(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Margin level:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.2f %%",indent,"",w,header,result.margin_level);
   /* Sample output:
      Margin level: 7785.48 %
   */
  }


Comentarios sobre el código de respuesta

Comentario al código de respuesta, descripción del error.

//+------------------------------------------------------------------+
//| Return comment on the response code, error description           |
//+------------------------------------------------------------------+
string MqlTradeCheckResultComment(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Comment:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,result.comment);
   /* Sample output:
      Comment: Done
   */
  }


Ejemplos de uso

Función que registra todos los campos de la estructura MqlTradeCheckResult:

//+------------------------------------------------------------------+
//| Display the MqlTradeCheckResult structure fields in the journal  |
//| as a result of OrderCheck                                        |
//+------------------------------------------------------------------+
void OrderCheckResultPrint(const MqlTradeCheckResult &result,const uint header_width=0,const uint indent=0,bool ext_descr=false)
  {
   Print("OrderCheck result:");
   Print(MqlTradeCheckResultRetcode(result,header_width,indent,ext_descr));
   Print(MqlTradeCheckResultBalance(result,header_width,indent));
   Print(MqlTradeCheckResultEquity(result,header_width,indent));
   Print(MqlTradeCheckResultProfit(result,header_width,indent));
   Print(MqlTradeCheckResultMargin(result,header_width,indent));
   Print(MqlTradeCheckResultMarginFree(result,header_width,indent));
   Print(MqlTradeCheckResultMarginLevel(result,header_width,indent));
   Print(MqlTradeCheckResultComment(result,header_width,indent));
   /* Sample output:
      OrderCheck result:
        Retcode:      Undefined (0)
        Balance:      10016.80 USD
        Equity:       10016.80 USD
        Profit:       0.00 USD
        Margin:       128.66 USD
        Margin free:  9888.14 USD
        Margin level: 7785.48 %
        Comment:      Done
   */
  }

Tras verificar una orden comercial rellenada, y si se obtiene un error, podremos imprimir la estructura MqlTradeCheckResult rellenada en el registro para analizar el error que ha sucedido.


Estructura MqlTradeResult con la respuesta del servidor a la solicitud enviada por la función OrderSend()

En respuesta a una solicitud comercial para realizar una orden en el sistema comercial, el servidor comercial retornará datos que contendrán información sobre el resultado del procesamiento de la solicitud comercial en forma de estructura especial MqlTradeResult.

struct MqlTradeResult
  {
   uint     retcode;          // Operation result code
   ulong    deal;             // Deal ticket if executed
   ulong    order;            // Order ticket if placed
   double   volume;           // Deal volume confirmed by a broker
   double   price;            // Deal price confirmed by a broker
   double   bid;              // The current market Bid price (requote price)
   double   ask;              // The current market Ask price (requote price)
   string   comment;          // Broker comment to operation (by default, it is filled by the trade server return code description)
   uint     request_id;       // Request ID set by the terminal when sending 
   int      retcode_external; // Response code of an external trading system
  };

El resultado de la operación comercial se retornará a una variable del tipo MqlTradeResult, que se transmitirá como segundo parámetro a la función OrderSend() para realizar operaciones comerciales.

Para mostrar la descripción de los campos de la estructura, escribiremos las siguientes funciones:

Código de resultado de la operación

Código de retorno del servidor comercial
//+------------------------------------------------------------------+
//| Return the operation result code as a string                     |
//+------------------------------------------------------------------+
string MqlTradeResultRetcode(const MqlTradeResult &result,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Retcode:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,RetcodeDescription(result.retcode,ext_descr));
   /* Sample output:
      Retcode: 10009 DONE (Request completed)
   */
  }


Ticket de la transacción

Ticket de la transacción, si se completa. Se notifica al realizarse una operación comercial TRADE_ACTION_DEAL.
//+------------------------------------------------------------------+
//| Return the deal ticket if it is completed                        |
//+------------------------------------------------------------------+
string MqlTradeResultDeal(const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Deal:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,result.deal);
   /* Sample output:
      Deal: 0
   */
  }


Ticket de la orden

Ticket de la orden, si se ha colocado. Se notifica al realizarse una operación comercial TRADE_ACTION_PENDING.
//+------------------------------------------------------------------+
//| Return the order ticket as a string if the order is set          |
//+------------------------------------------------------------------+
string MqlTradeResultOrder(const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Order:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,result.order);
   /* Sample output:
      Order: 1821552382
   */
  }


Volumen de la transacción

Volumen de la transacción confirmado por el bróker. Dependerá del tipo de orden a ejecutar.
//+------------------------------------------------------------------+
//| Return the deal volume confirmed by a broker as a string         |
//+------------------------------------------------------------------+
string MqlTradeResultVolume(const string symbol,const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Volume:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the number of decimal places in the lot value
   int dg=(int)ceil(fabs(log10(SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP))));
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,result.volume);
   /* Sample output:
      Volume: 0.10
   */
  }


Precio de la transacción

Precio de la transacción confirmado por el bróker. Dependerá del campo deviation en la solicitud comercial y/o del tipo de operación comercial.

//+------------------------------------------------------------------+
//| Return a deal price, confirmed by a broker, as a string          |
//+------------------------------------------------------------------+
string MqlTradeResultPrice(const string symbol,const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Price:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the number of decimal places
   int dg=(result.price!=0 ? (int)SymbolInfoInteger(symbol,SYMBOL_DIGITS) : 1);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,result.price);
   /* Sample output:
      Price: 0.0
   */
  }


Precio de mercado Bid actual

Precio de oferta de mercado actual (precio de recotización).
//+------------------------------------------------------------------+
//| Return the current market Bid price as a string                  |
//+------------------------------------------------------------------+
string MqlTradeResultBid(const string symbol,const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Bid:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the number of decimal places
   int dg=(result.bid!=0 ? (int)SymbolInfoInteger(symbol,SYMBOL_DIGITS) : 1);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,result.bid);
   /* Sample output:
      Bid: 0.0
   */
  }


Precio de mercado Ask actual

Precio de demanda actual del mercado (precio de recotización).
//+------------------------------------------------------------------+
//| Return the current market Ask price as a string                  |
//+------------------------------------------------------------------+
string MqlTradeResultAsk(const string symbol,const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Ask:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the number of decimal places
   int dg=(result.ask!=0 ? (int)SymbolInfoInteger(symbol,SYMBOL_DIGITS) : 1);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,result.ask);
   /* Sample output:
      Ask: 0.0
   */
  }

Al colocar una orden pendiente, los precios Bid y Ask en la estructura permanecerán vacíos. Si la orden no ha sido aceptada debido a una recotización, en los campos Bid y Ask podremos ver los precios que existían en el momento en que la orden fue rechazada para su colocación.


Comentarios del bróker sobre la transacción

Comentario del bróker sobre la operación (por defecto, se rellenará con la aclaración del código de retorno del servidor comercial).
//+------------------------------------------------------------------+
//| Return broker's comment on a deal                                |
//+------------------------------------------------------------------+
string MqlTradeResultComment(const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Comment:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,result.comment);
   /* Sample output:
      Comment: Request executed
   */
  }


Identificación de la solicitud

Identificación de la solicitud ingresada por el terminal al realizarse el envío al servidor comercial.
//+------------------------------------------------------------------+
//| Return request ID as a string                                    |
//+------------------------------------------------------------------+
string MqlTradeResultRequestID(const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Request ID:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-lu",indent,"",w,header,result.request_id);
   /* Sample output:
      Request ID: 3768213261
   */
  }

Colocación del identificador request_id por parte del terminal para una solicitud comercial al enviar esta al servidor; está principalmente destinada a trabajar con la función asincrónica OrderSendAsync(). Este identificador permite vincular la acción realizada (llamar a las funciones OrderSend o OrderSendAsync) con el resultado de la misma transmitido en el manejador OnTradeTransaction().


Código de respuesta del sistema comercial externo

Código de error retornado por el sistema comercial externo. La ubicación y los tipos de estos errores dependerán del bróker y del sistema comercial externo en el que se generan las transacciones comerciales..
//+--------------------------------------------------------------------+
//| Return the response code of an external trading system as a string |
//+--------------------------------------------------------------------+
string MqlTradeResultRetcodeExternal(const MqlTradeResult &result,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Retcode External:";
   uint w=(header_width==0 ? header.Length()+1 : header_width-1);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%- ld",indent,"",w,header,result.retcode_external);
   /* Sample output:
      Retcode External:  0
   */
  }


Ejemplos de uso

Función que registra todos los campos de la estructura de resultados de la solicitud comercial:

//+------------------------------------------------------------------+
//| Display MqlTradeResult structure fields in the journal           |
//| as a result of a trade request                                   |
//+------------------------------------------------------------------+
void TradeResultPrint(const string symbol,const MqlTradeResult &result,const uint header_width=0,const uint indent=0,bool ext_descr=false)
  {
   string symbol_name=(symbol==NULL ? Symbol() : symbol);
   Print("OrderSend result:");
   Print(MqlTradeResultRetcode(result,header_width,indent,ext_descr));
   Print(MqlTradeResultDeal(result,header_width,indent));
   Print(MqlTradeResultOrder(result,header_width,indent));
   Print(MqlTradeResultVolume(symbol_name,result,header_width,indent));
   Print(MqlTradeResultPrice(symbol_name,result,header_width,indent));
   Print(MqlTradeResultBid(symbol_name,result,header_width,indent));
   Print(MqlTradeResultAsk(symbol_name,result,header_width,indent));
   Print(MqlTradeResultComment(result,header_width,indent));
   Print(MqlTradeResultRequestID(result,header_width,indent));
   Print(MqlTradeResultRetcodeExternal(result,header_width,indent));
   /* Sample output:
      OrderSend result:
        Retcode:          10009 DONE (Request completed)
        Deal:             0
        Order:            1821671230
        Volume:           0.10
        Price:            0.0
        Bid:              0.0
        Ask:              0.0
        Comment:          Request executed
        Request ID:       3768213265
        Retcode External: 0
   */
  }


Estructura MqlTradeTransaction con una descripción de la transacción comercial

Como resultado de la ejecución de determinadas acciones con una cuenta comercial, su estado cambiará. Estas acciones incluyen:

  • El envío de una solicitud comercial mediante cualquier aplicación MQL5 en el terminal del cliente utilizando las funciones OrderSend y OrderSendAsync y su posterior ejecución;
  • El envío de una solicitud comercial a través de la interfaz gráfica del terminal y su posterior ejecución;
  • La activación de órdenes pendientes y órdenes stop en el servidor;
  • La ejecución de operaciones en el lado del servidor comercial.

Como resultado de estas acciones, se realizarán transacciones comerciales para la cuenta:

  • procesamiento de una solicitud comercial;
  • cambio de órdenes abiertas;
  • cambio de la historia de órdenes;
  • cambio de la historia de transacciones;
  • cambio de las posiciones.

Por ejemplo, al enviar una orden de mercado de compra, esta se procesa; para la cuenta se crea la orden de compra correspondiente, se ejecuta, se elimina de la lista de abiertas, se añade a la historia de órdenes y luego se envía la orden correspondiente; a continuación, la transacción se añade a la historia y se crea una nueva posición. Todas estas acciones son transacciones comerciales.

Para obtener las transacciones comerciales aplicadas a una cuenta, MQL5 ofrece el manejador especial OnTradeTransaction(). Al primer parámetro de este manejador se le transmite la estructura MqlTradeTransaction, que describe las transacciones comerciales.

struct MqlTradeTransaction
  {
   ulong                         deal;             // Deal ticket
   ulong                         order;            // Order ticket
   string                        symbol;           // Symbol name
   ENUM_TRADE_TRANSACTION_TYPE   type;             // Trading transaction type
   ENUM_ORDER_TYPE               order_type;       // Order type
   ENUM_ORDER_STATE              order_state;      // Order state
   ENUM_DEAL_TYPE                deal_type;        // Deal type
   ENUM_ORDER_TYPE_TIME          time_type;        // Order lifetime type
   datetime                      time_expiration;  // Order expiration time
   double                        price;            // Price 
   double                        price_trigger;    // Stop limit order trigger price
   double                        price_sl;         // Stop Loss level
   double                        price_tp;         // Take Profit level
   double                        volume;           // Volume in lots
   ulong                         position;         // Position ticket
   ulong                         position_by;      // Opposite position ticket
  };


Para retornar las descripciones de todos los campos de la estructura, escribiremos varias funciones.

Ticket de la transacción

//+------------------------------------------------------------------+
//| Return the deal ticket as a string                               |
//+------------------------------------------------------------------+
string MqlTradeTransactionDeal(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Deal:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,trans.deal);
   /* Sample output:
      Deal: 0
   */
  }


Ticket de la orden

//+------------------------------------------------------------------+
//| Return the order ticket as a string                              |
//+------------------------------------------------------------------+
string MqlTradeTransactionOrder(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Order:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,trans.order);
   /* Sample output:
      Order: 1825990224
   */
  }


Nombre del instrumento comercial

Nombre del instrumento comercial para el cual se ha realizado la transacción.

//+------------------------------------------------------------------+
//| Return an order symbol as a string                               |
//+------------------------------------------------------------------+
string MqlTradeTransactionSymbol(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Symbol:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,trans.symbol);
   /* Sample output:
      Symbol: EURUSD
   */
  }


Tipo de transacción comercial

Tipo de transacción comercial. El valor puede ser uno de los valores de la enumeración ENUM_TRADE_TRANSACTION_TYPE.

//+------------------------------------------------------------------+
//| Return the trading transaction type as a string                  |
//+------------------------------------------------------------------+
string MqlTradeTransactionType(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Type:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,TradeTransactionTypeDescription(trans.type,ext_descr));
   /* Sample output:
      Type: Order delete (Removing an order from the list of the open ones)
   */
  }


Tipo de orden

Tipo de orden comercial. El valor puede ser uno de los valores de la enumeración ENUM_ORDER_TYPE.

//+------------------------------------------------------------------+
//| Return the order type as a string                                |
//+------------------------------------------------------------------+
string MqlTradeTransactionOrderType(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Declare variables to indicate transaction affiliation
   bool trans_req=false;   // Request
   bool trans_order=false; // Order
   bool trans_deal=false;  // Deal
   bool trans_pos=false;   // Position
//--- Set transaction affiliation
   SetTransactionBelong(trans.type,trans_req,trans_order,trans_deal,trans_pos);
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Order type:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,(trans_order ? OrderTypeDescription(trans.order_type,ext_descr) : "0"));
   /* Sample output:
      Order type: Sell Limit (Sell Limit pending order)
   */
  }

La función determina la pertenencia de la transacción comercial y, si la transacción se ha realizado con una orden, entonces se retornará su tipo; en caso contrario, se devolverá '0'.


Estado de la orden

Estado de la orden comercial. El valor puede ser uno de los valores de la enumeración ENUM_ORDER_STATE.

//+------------------------------------------------------------------+
//| Return the order status as a string                              |
//+------------------------------------------------------------------+
string MqlTradeTransactionOrderState(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Declare variables to indicate transaction affiliation
   bool trans_req=false;   // Request
   bool trans_order=false; // Order
   bool trans_deal=false;  // Deal
   bool trans_pos=false;   // Position
//--- Set transaction affiliation
   SetTransactionBelong(trans.type,trans_req,trans_order,trans_deal,trans_pos);
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Order state:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,(trans_order ? OrderStateDescription(trans.order_state,ext_descr) : "0"));
   /* Sample output:
      Order state: Started (Order checked, but not yet accepted by broker)
   */
  }

La función determina la pertenencia de la transacción comercial y, si la transacción se ha realizado con una orden, se retornará su estado; en caso contrario, se devolverá '0'.


Tipo de transacción

Tipo de transacción. El valor puede ser uno de los valores de la enumeración ENUM_DEAL_TYPE.

//+------------------------------------------------------------------+
//| Return the deal type as a string                                 |
//+------------------------------------------------------------------+
string MqlTradeTransactionDealType(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Declare variables to indicate transaction affiliation
   bool trans_req=false;   // Request
   bool trans_order=false; // Order
   bool trans_deal=false;  // Deal
   bool trans_pos=false;   // Position
//--- Set transaction affiliation
   SetTransactionBelong(trans.type,trans_req,trans_order,trans_deal,trans_pos);
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Deal type:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,(trans_deal || trans_pos ? DealTypeDescription(trans.deal_type,ext_descr) : "0"));
   /* Sample output:
      Deal type: Buy
   */
  }

La función determina la pertenencia de la transacción comercial y, si se ha realizado con una transacción, entonces se retornará su tipo; en caso contrario, se devolverá '0'.


Tipo de orden por duración

Tipo de orden según el vencimiento. El valor puede ser uno de los valores de ENUM_ORDER_TYPE_TIME.

//+------------------------------------------------------------------+
//| Return the order type by expiration time as a string             |
//+------------------------------------------------------------------+
string MqlTradeTransactionTimeType(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Declare variables to indicate transaction affiliation
   bool trans_req=false;   // Request
   bool trans_order=false; // Order
   bool trans_deal=false;  // Deal
   bool trans_pos=false;   // Position
//--- Set transaction affiliation
   SetTransactionBelong(trans.type,trans_req,trans_order,trans_deal,trans_pos);
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Time type:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,(trans_order ? OrderTypeTimeDescription(trans.time_type,ext_descr) : "0"));
   /* Sample output:
      Order type time: Time GTC (Good till cancel order)
   */
  }

La función determina la pertenencia de la transacción comercial y, si la transacción se ha realizado con una orden, entonces se retornará su tipo según el plazo de vencimiento; en caso contrario, se devolverá '0'.


Fecha de vencimiento de la orden

Fecha de vencimiento de la orden pendiente (para órdenes del tipo ORDER_TIME_SPECIFIED y ORDER_TIME_SPECIFIED_DAY).

//+------------------------------------------------------------------+
//| Return the order expiration time as a string                     |
//+------------------------------------------------------------------+
string MqlTradeTransactionTimeExpiration(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Time expiration:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Set the expiration time as a string. If 0, then set 0
   string tm=(trans.time_expiration==0 ? "0" : (string)trans.time_expiration);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s",indent,"",w,header,tm);
   /* Sample output:
      Time expiration: 0
   */
  }

Si el plazo de vencimiento en el campo de la estructura se escribe como cero, entonces mostraremos '0'; de lo contrario, mostraremos el plazo de vencimiento en formato de fecha. Si no marcamos el valor del campo como cero, entonces el valor cero se mostrará como la fecha 01/01/1970 00:00:00, lo cual no parece muy estético debido a la ausencia de la hora de vencimiento de la orden.


Precio

Precio. Dependiendo del tipo de transacción comercial, puede tratarse del precio de una orden, transacción o posición.

//+------------------------------------------------------------------+
//| Return the order/deal/position price as a string                 |
//+------------------------------------------------------------------+
string MqlTradeTransactionPrice(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Price:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Receive symbol's Digits. If the character is not specified, use 1
   int dg=(trans.symbol!="" ? (int)SymbolInfoInteger(trans.symbol,SYMBOL_DIGITS) : 1);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,trans.price);
   /* Sample output:
      Price: 1.10331
   */
  }


Precio de activación de la orden stop limit

Precio stop (precio de activación) de una orden stop limit (ORDER_TYPE_BUY_STOP_LIMIT y ORDER_TYPE_SELL_STOP_LIMIT).

//+------------------------------------------------------------------+
//| Return the stop limit order trigger price as a string            |
//+------------------------------------------------------------------+
string MqlTradeTransactionPriceTrigger(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Price trigger:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Receive symbol's Digits. If a symbol is not specified or there is no stop price, use 1
   int dg=(trans.symbol!="" ? (int)SymbolInfoInteger(trans.symbol,SYMBOL_DIGITS) : 1);
   if(trans.price_trigger==0)
      dg=1;
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,trans.price_trigger);
   /* Sample output:
      Price trigger: 0.0
   */
  }

Si no se indica el precio de la orden stop-limit, mostraremos '0.0'; de lo contrario, se mostrará el precio de la orden.


Nivel de Stop Loss

Precio de Stop Loss. Dependiendo del tipo de transacción comercial, puede referirse a una orden, una transacción o una posición.

//+------------------------------------------------------------------+
//| Return Stop Loss price as a string                               |
//+------------------------------------------------------------------+
string MqlTradeTransactionPriceSL(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Price SL:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Receive symbol's Digits. If a symbol is not specified or a Stop Loss price is absent, use 1
   int dg=(trans.symbol!="" ? (int)SymbolInfoInteger(trans.symbol,SYMBOL_DIGITS) : 1);
   if(trans.price_sl==0)
      dg=1;
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,trans.price_sl);
   /* Sample output:
      Price SL: 0.0
   */
  }

Si no se especifica el precio de Stop Loss, mostraremos '0.0'; de lo contrario, el se mostrará el precio de Stop Loss.


Nivel de take profit

Precio de Take Profit. Dependiendo del tipo de transacción comercial, puede referirse a una orden, una transacción o una posición.

//+------------------------------------------------------------------+
//| Return a Take Profit price as a string                           |
//+------------------------------------------------------------------+
string MqlTradeTransactionPriceTP(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Price TP:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Receive symbol's Digits. If a symbol is not specified or a Take Profit price is absent, use 1
   int dg=(trans.symbol!="" ? (int)SymbolInfoInteger(trans.symbol,SYMBOL_DIGITS) : 1);
   if(trans.price_tp==0)
      dg=1;
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,trans.price_tp);
   /* Sample output:
      Price TP: 0.0
   */
  }

Si no se especifica el precio de Take Profit, mostraremos '0.0'; de lo contrario, se mostrará el precio de Take Profit.


Volumen en lotes

Volumen en lotes. Dependiendo del tipo de transacción comercial, puede indicar el volumen de la orden actual, el volumen comercial o el volumen de la posición.

//+------------------------------------------------------------------+
//| Return volume in lots as a string                                |
//+------------------------------------------------------------------+
string MqlTradeTransactionVolume(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Volume:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get the number of decimal places in the lot value. If the character is not specified, use 1
   int dg=(trans.symbol!="" ? (int)ceil(fabs(log10(SymbolInfoDouble(trans.symbol,SYMBOL_VOLUME_STEP)))) : 1);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,trans.volume);
   /* Sample output:
      Volume: 0.10
   */
  }


Ticket de la posición

Ticket de la posición afectada por la transacción.

//+------------------------------------------------------------------+
//| Return the position ticket as a string                           |
//+------------------------------------------------------------------+
string MqlTradeTransactionPosition(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Position:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,trans.position);
   /* Sample output:
      Position: 0
   */
  }


Ticket de la posición opuesta

Ticket de la posición opuesta. Se utiliza al cerrar una posición con otra opuesta: se abre en el mismo instrumento, pero en la dirección opuesta.

//+------------------------------------------------------------------+
//| Return the opposite position ticket as a string                  |
//+------------------------------------------------------------------+
string MqlTradeTransactionPositionBy(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Position by:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-llu",indent,"",w,header,trans.position_by);
   /* Sample output:
      Position by: 0
   */
  }


Ejemplos de uso

Usando las funciones presentadas anteriormente, podemos mostrar en el registro todos los campos de la estructura MqlTradeTransaction:

//+------------------------------------------------------------------+
//| Display the MqlTradeTransaction structure fields in the journal  |
//+------------------------------------------------------------------+
void MqlTradeTransactionPrint(const MqlTradeTransaction &trans,const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
   Print(MqlTradeTransactionDeal(trans,header_width,indent));
   Print(MqlTradeTransactionOrder(trans,header_width,indent));
   Print(MqlTradeTransactionSymbol(trans,header_width,indent));
   Print(MqlTradeTransactionType(trans,header_width,indent,ext_descr));
   Print(MqlTradeTransactionOrderType(trans,header_width,indent,ext_descr));
   Print(MqlTradeTransactionOrderState(trans,header_width,indent,ext_descr));
   Print(MqlTradeTransactionDealType(trans,header_width,indent,ext_descr));
   Print(MqlTradeTransactionTimeType(trans,header_width,indent,ext_descr));
   Print(MqlTradeTransactionTimeExpiration(trans,header_width,indent));
   Print(MqlTradeTransactionPrice(trans,header_width,indent));
   Print(MqlTradeTransactionPriceTrigger(trans,header_width,indent));
   Print(MqlTradeTransactionPriceSL(trans,header_width,indent));
   Print(MqlTradeTransactionPriceTP(trans,header_width,indent));
   Print(MqlTradeTransactionVolume(trans,header_width,indent));
   Print(MqlTradeTransactionPosition(trans,header_width,indent));
   Print(MqlTradeTransactionPositionBy(trans,header_width,indent));
   /* Sample output:
      Deal:             0
      Order:            1829189788
      Symbol:           EURUSD
      Type:             Order add
      Order type:       Buy Limit
      Order state:      Started
      Deal type:        0
      Time type:        Time GTC
      Time expiration:  0
      Price:            1.09861
      Price trigger:    0.0
      Price SL:         0.0
      Price TP:         0.0
      Volume:           0.10
      Position:         0
      Position by:      0
   */
  }

La función presentada muestra todos los campos de la estructura MqlTradeTransaction. Pero si miramos la guía de ayuda, veremos que para diferentes eventos comerciales los campos de la estructura se rellenan de manera diferente:

El parámetro determinante para analizar una transacción entrante es su tipo, que se transmite en el campo type. Por ejemplo, si una transacción es del tipo TRADE_TRANSACTION_REQUEST (el resultado del procesamiento de la solicitud comercial es obtenido por parte del servidor), entonces la estructura tendrá solo un campo type rellenado, no será necesario analizar los campos restantes. En este caso, podemos analizar los dos parámetros adicionales request y result, que se transmiten al manejador OnTradeTransaction(), como se muestra en el siguiente ejemplo.

Conociendo el tipo de operación comercial, podemos decidir analizar el estado actual de las órdenes, posiciones y transacciones en la cuenta comercial. Eso sí, deberemos considerar que la solicitud comercial enviada desde el terminal al servidor puede generar varias transacciones comerciales, cuyo orden de llegada al terminal no estará garantizado.

La estructura MqlTradeTransaction se rellenará de forma diferente según el tipo de transacción comercial (ENUM_TRADE_TRANSACTION_TYPE):

TRADE_TRANSACTION_ORDER_* y TRADE_TRANSACTION_HISTORY_*

Para las transacciones comerciales relacionadas con el procesamiento de órdenes abiertas (TRADE_TRANSACTION_ORDER_ADD, TRADE_TRANSACTION_ORDER_UPDATE y TRADE_TRANSACTION_ORDER_DELETE) y la historia de órdenes (TRADE_TRANSACTION_HISTORY_ADD, TRADE_TRANSACTION_HISTORY_UPDATE, TRADE_TRANSACTION_HISTORY_DELETE), en la estructura MqlTradeTransaction se rellenarán los campos siguientes:

  • orden — ticket de la orden;
  • symbol — nombre del instrumento financiero en la orden;
  • type — tipo de transacción comercial;
  • order_type — tipo de orden;
  • orders_state — estado actual de la orden;
  • time_type — tipo de vencimiento de la orden;
  • time_expiration — hora de vencimiento de la orden (para órdenes con tipos de vencimiento ORDER_TIME_SPECIFIED y ORDER_TIME_SPECIFIED_DAY);
  • price — precio en la orden especificado por el cliente;
  • price_trigger — precio stop para activar una orden stop limit (solo para ORDER_TYPE_BUY_STOP_LIMIT y ORDER_TYPE_SELL_STOP_LIMIT);
  • price_sl — precio Stop Loss de la orden (se rellenará si se especifica en la orden);
  • price_tp — precio Take Profit de la orden (se rellenerá si se especifica en la orden);
  • volume — volumen de la orden actual (no ejecutado). El volumen inicial de la orden se puede encontrar en la historia de órdenes utilizando las funciones HistoryOrders*.
  • position — ticket de la posición abierta, modificada o cerrada como resultado de la ejecución de la orden. Se rellena únicamente para las órdenes de mercado. Nose rellena para TRADE_TRANSACTION_ORDER_ADD.
  • position_by — ticket de la posición opuesta. Se rellena únicamente para las órdenes de cierre de posición mediante otra opuesta (close by).

TRADE_TRANSACTION_DEAL_*

Para las transacciones comerciales relacionadas con el procesamiento de transacciones (TRADE_TRANSACTION_DEAL_ADD, TRADE_TRANSACTION_DEAL_UPDATE y TRADE_TRANSACTION_DEAL_DELETE), en la estructura MqlTradeTransaction se completarán los campos siguientes:

  • deal — ticket de la transacción;
  • order — ticket de la orden en base a la cual se ha realizado la transacción;
  • symbol — nombre del instrumento financiero en la transacción;
  • type — tipo de transacción comercial;
  • trato_tipo — tipo de transacción;
  • precio — precio al que se ha realizado la transacción;
  • price_sl — precio Stop Loss (se rellena si se especifica en la orden en base a la cual se ha realizado la transacción);
  • price_tp — precio Take Profit (se rellena si se especifica en la orden en base a la cual se ha realizado la transacción);
  • volume — volumen de la transacción en lotes.
  • position — ticket de la posición abierta, modificada o cerrada como resultado de la ejecución de la transacción.
  • position_by — ticket de la posición opuesta. Se rellena únicamente para las órdenes de cierre de posición mediante otra opuesta (out by).

TRADE_TRANSACTION_POSITION

Para las transacciones comerciales relacionadas con los cambios en las posiciones no vinculadas con la ejecución de transacciones (TRADE_TRANSACTION_POSITION), se rellenarán los siguientes campos en la estructura MqlTradeTransaction:

  • symbol — nombre del instrumento financiero de la posición;
  • type — tipo de transacción comercial;
  • deal_type — tipo de la posición (DEAL_TYPE_BUY o DEAL_TYPE_SELL);
  • price — precio medio ponderado para abrir una posición;
  • price_sl — precio Stop Loss;
  • price_tp — precio Take Profit;
  • volume — volumen de la posición en lotes, si se ha modificado.
  • position — ticket de la posición.

La modificación de una posición (adición, cambio o eliminación) como resultado de una transacción no implica la aparición de la transacción TRADE_TRANSACTION_POSITION.

TRADE_TRANSACTION_REQUEST

Para las transacciones comerciales que describen el procesamiento de una solicitud comercial por parte del servidor y la obtención del resultado de su procesamiento (TRADE_TRANSACTION_REQUEST), solo se rellenará un campo en la estructura MqlTradeTransaction:

  • type — tipo de la transacción comercial;
Para las transacciones de este tipo, se deberá analizar solo un campo — type (el tipo de transacción comercial). Para obtener información adicional, deberemos analizar el segundo y tercer parámetro de la función OnTradeTransaction (request y result).

En consecuencia, podremos crear una función que tenga en cuenta los eventos comerciales entrantes y muestre solo aquellos campos de la estructura MqlTradeTransaction que sean necesarios para cada tipo de transacción:

//+------------------------------------------------------------------+
//| Trading transaction informer                                     |
//+------------------------------------------------------------------+
void TradeTransactionInformer(const MqlTradeTransaction &trans,const MqlTradeRequest& request,const MqlTradeResult& result,
                              const uint header_width=0,const uint indent=0,const bool ext_descr=false)
  {
//--- Declare variables to indicate transaction affiliation
   bool trans_req=false;   // Request
   bool trans_order=false; // Order
   bool trans_deal=false;  // Deal
   bool trans_pos=false;   // Position
//--- Set transaction affiliation
   SetTransactionBelong(trans.type,trans_req,trans_order,trans_deal,trans_pos);
//--- Depending on the transaction affiliation, display descriptions of the corresponding structure fields
   //--- Trading request
   if(trans_req)
     {
      //--- Inform of the "trading request" transaction type and indicate that it is necessary to analyze the fields of the trading request and server response structure
      PrintFormat("Transaction %s\n%*sThe second and third parameters of OnTradeTransaction function (request and result) must be analyzed for additional data:",
         MqlTradeTransactionType(trans,0,0,true),indent,"");
      //--- Display the description of the trade request and the request result received from the server
      TradeRequestPrint(request,header_width,indent,ext_descr);
      TradeResultPrint(trans.symbol,result,header_width,indent,ext_descr);
     }
   //--- Otherwise, if the order/deal/position 
   else
     {
      //--- Display the transaction type in the journal
      PrintFormat("Transaction %s",MqlTradeTransactionType(trans,0,0,true));
      //--- Order
      if(trans_order)
        {
         Print(MqlTradeTransactionOrder(trans,header_width,indent));
         Print(MqlTradeTransactionSymbol(trans,header_width,indent));
         Print(MqlTradeTransactionOrderType(trans,header_width,indent,ext_descr));
         Print(MqlTradeTransactionOrderState(trans,header_width,indent,ext_descr));
         Print(MqlTradeTransactionTimeType(trans,header_width,indent,ext_descr));
         if(trans.time_type==ORDER_TIME_SPECIFIED || trans.time_type==ORDER_TIME_SPECIFIED_DAY)
            Print(MqlTradeTransactionTimeExpiration(trans,header_width,indent));
         Print(MqlTradeTransactionPrice(trans,header_width,indent));
         if(trans.order_type==ORDER_TYPE_BUY_STOP_LIMIT || trans.order_type==ORDER_TYPE_SELL_STOP_LIMIT)
            Print(MqlTradeTransactionPriceTrigger(trans,header_width,indent));
         Print(MqlTradeTransactionPriceSL(trans,header_width,indent));
         Print(MqlTradeTransactionPriceTP(trans,header_width,indent));
         Print(MqlTradeTransactionVolume(trans,header_width,indent));
         if(trans.type!=TRADE_TRANSACTION_ORDER_ADD && (trans.order_type==ORDER_TYPE_BUY || trans.order_type==ORDER_TYPE_SELL))
            Print(MqlTradeTransactionPosition(trans,header_width,indent));
         if(trans.order_type==ORDER_TYPE_CLOSE_BY)
            Print(MqlTradeTransactionPositionBy(trans,header_width,indent));
        }
      //--- Deal
      if(trans_deal)
        {
         Print(MqlTradeTransactionDeal(trans,header_width,indent));
         Print(MqlTradeTransactionOrder(trans,header_width,indent));
         Print(MqlTradeTransactionSymbol(trans,header_width,indent));
         Print(MqlTradeTransactionDealType(trans,header_width,indent,ext_descr));
         Print(MqlTradeTransactionPrice(trans,header_width,indent));
         Print(MqlTradeTransactionPriceSL(trans,header_width,indent));
         Print(MqlTradeTransactionPriceTP(trans,header_width,indent));
         Print(MqlTradeTransactionVolume(trans,header_width,indent));
         Print(MqlTradeTransactionPosition(trans,header_width,indent));
        }
      //--- Position
      if(trans_pos)
        {
         Print(MqlTradeTransactionSymbol(trans,header_width,indent));
         Print(MqlTradeTransactionDealType(trans,header_width,indent,ext_descr));
         Print(MqlTradeTransactionPrice(trans,header_width,indent));
         Print(MqlTradeTransactionPriceSL(trans,header_width,indent));
         Print(MqlTradeTransactionPriceTP(trans,header_width,indent));
         Print(MqlTradeTransactionVolume(trans,header_width,indent));
         Print(MqlTradeTransactionPosition(trans,header_width,indent));
        }
     }
   /* Sample output when setting the Sell Limit order:
      Transaction Type: Order add (Adding a new open order)
        Order: 1833072954
        Symbol: EURUSD
        Order type: Sell Limit (Sell Limit pending order)
        Order state: Started (Order checked, but not yet accepted by broker)
        Time type: Time GTC (Good till cancel order)
        Price: 1.10516
        Price SL: 0.0
        Price TP: 0.0
        Volume: 0.10
      Transaction Type: Order update (Updating an open order)
        Order: 1833072954
        Symbol: EURUSD
        Order type: Sell Limit (Sell Limit pending order)
        Order state: Placed (Order accepted)
        Time type: Time GTC (Good till cancel order)
        Price: 1.10516
        Price SL: 0.0
        Price TP: 0.0
        Volume: 0.10
      Transaction Type: Request (The trade request has been processed by a server and processing result has been received)
        The second and third parameters of OnTradeTransaction function (request and result) must be analyzed for additional data:
      Request Pending (Place a trade order for the execution under specified conditions (pending order)):
        Symbol: EURUSD
        Volume: 0.10
        Price: 1.10516
        SL: 0.0
        TP: 0.0
        Type: Sell Limit (Sell Limit pending order)
        Type filling: Return (In case of partial filling, an order with remaining volume is not canceled but processed further)
        Type time: Time GTC (Good till cancel order)
        Expiration: 0
        Magic: 1024
        Comment: TestMqlTradeTransaction
      OrderSend result:
        Retcode: 10009 DONE (Request completed)
        Deal: 0
        Order: 1833072954
        Volume: 0.10
        Price: 0.0
        Bid: 0.0
        Ask: 0.0
        Comment: 
        Request ID: 3768213464
        Retcode External:  0
      //---
      Here, when placing a Buy Limit pending order, we received three transactions:
         1. Request - a request to place a pending order was accepted by the server and a response was received. 
            To clarify information, it is necessary to analyze the fields of the MqlTradeRequest trade request structure 
            and the MqlTradeResult server response – 'request' and 'result', respectively.
         2. Adding a new pending order with the ticket #1829788294. Its status - Started.
         3. Changing an open order with the ticket #1829788294. Its status changed from Started to Placed.
      The order of transactions is not respected, but this is clearly indicated in the Help section concerning the OnTradeTransaction handler: 
      https://www.mql5.com/en/docs/event_handlers/ontradetransaction.
   */
  }


Asesor-informante de transacciones comerciales

Para verificar el funcionamiento de las funciones anteriormente mencionadas, escribiremos un asesor que monitoree todas las transacciones comerciales, las respuestas del servidor y muestre las descripciones de las transacciones comerciales entrantes. Lo haremos así para que sea posible colocar órdenes pendientes (BuyStop, SellStop, BuyLimit y SellLimit) y abrir posiciones (Buy, Sell) presionando las teclas seleccionadas en la configuración. Por defecto, se asignarán las siguientes teclas para la gestión comercial:

Tipo de orden
Atajos de teclado para abrir/colocar
Atajos de teclado para cerrar/eliminar
 Buy
 B
 X
 Sell
 S
 X
 Buy Stop
 Shift+B
 Shift+X, Ctrl+Shift+X
 Buy Limit
 Ctrl+Shift+B
 Shift+X, Ctrl+Shift+X
 Sell Stop
 Shift+S
 Shift+X, Ctrl+Shift+X
 Sell Limit
 Ctrl+Shift+S
 Shift+X, Ctrl+Shift+X

Las teclas se pueden asignar tanto en mayúsculas como en minúsculas en la configuración, el asesor las convertirá a mayúsculas automáticamente. Podemos configurar tres teclas: para la compra, para la venta y para cerrar posiciones/eliminar órdenes. Las teclas de control Ctrl y Shift para cambiar el tipo de órdenes pendientes en una solicitud estarán asignadas por defecto y no se podrán cambiar. Presionando la tecla 'B', se abrirá una posición de Compra; manteniendo presionado Shift y presionando la tecla 'B', se colocará una orden Buy Stop pendiente, y manteniendo simultáneamente Ctrl y Shift y presionando 'B', se colocará una orden Buy Limit pendiente. Lo mismo se aplica a la venta: presionando simplemente 'S', se abrirá una posición de venta, y manteniendo presionadas las teclas de control se colocarán Sell Stop y Sell Limit. El cierre de todas las posiciones abiertas se realizará presionando el botón 'X', y manteniendo presionada la tecla Mayús o Ctrl+Shift (no importa) y presionando 'X' se eliminarán todas las órdenes pendientes.

//+------------------------------------------------------------------+
//|                                      TestMqlTradeTransaction.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//--- input parameters
input double   InpLots        =  0.1;     /* Lots                       */ // Requested volume
input int      InpMagic       =  1024;    /* Magic number               */ // EA ID
input int      InpDistance    =  300;     /* Orders placement distance  */ // Distance for setting pending orders
input uint     InpDeviation   =  5;       /* Price deviation            */ // Allowed deviation from the price
input string   InpKeyBuy      =  "B";     /* Key to open Buy            */ // Key to open a Buy position (with Shift - Stop, with Ctrl+Shift - Limit)
input string   InpKeySell     =  "S";     /* Key to open Sell           */ // Key to open Sell (with Shift - Stop, with Ctrl+Shift - Limit)
input string   InpKeyClose    =  "X";     /* Key to close/delete        */ // Key for closing a position (without control keys) or deleting an order (with Shift or Shift+Ctrl)
//--- Global variables
ushort         key_buy;                   // Key to send a buy order 
ushort         key_sell;                  // Key to send a sell order
ushort         key_close;                 // Key to close or delete
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Convert the text assigned to Buy to uppercase and get the code of the first character
   string tmp=InpKeyBuy;
   tmp.Upper();
   key_buy=StringGetCharacter(tmp,0);
//--- Convert the text assigned to Sell to uppercase and get the code of the first character
   tmp=InpKeySell;
   tmp.Upper();
   key_sell=StringGetCharacter(tmp,0);
//--- Convert the text assigned to Close to uppercase and get the code of the first character
   tmp=InpKeyClose;
   tmp.Upper();
   key_close=StringGetCharacter(tmp,0);

//--- If the keys assigned to Buy and Sell match, report this and exit with an error
   if(key_sell==key_buy)
     {
      PrintFormat("The key assigned to Sell ('%c') is the same as the key assigned to Buy ('%c')",key_sell,key_buy);
      return INIT_PARAMETERS_INCORRECT;
     }
//--- If the keys assigned to Close and Buy match, report this and exit with an error
   if(key_close==key_buy)
     {
      PrintFormat("The key assigned to Close ('%c') is the same as the key assigned to Buy ('%c')",key_close,key_buy);
      return INIT_PARAMETERS_INCORRECT;
     }
//--- If the keys assigned to Close and Sell match, report this and exit with an error
   if(key_close==key_sell)
     {
      PrintFormat("The key assigned to Close ('%c') is the same as the key assigned to Sell ('%c')",key_close,key_sell);
      return INIT_PARAMETERS_INCORRECT;
     }
//--- Successful initialization. Display the assigned keys in the journal and return successful execution
   string kb="Key assigned to Buy: ";
   string ks="Key assigned to Sell: ";
   string kc="Key assigned to Close: ";
   PrintFormat("%-23s%c (key code %lu)\n%-23s%c (key code %lu)\n%-23s%c (key code %lu)",kb,key_buy,key_buy,ks,key_sell,key_sell,kc,key_close,key_close);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- If a key is pressed
   if(id==CHARTEVENT_KEYDOWN)
     {
      //--- If neither Ctrl nor Shift are held 
      if(!IsCtrlKeyPressed() && !IsShiftKeyPressed())
        {
         //--- If the button is assigned to the Buy position, open Buy
         if(lparam==key_buy)
            OpenBuy(NULL,InpLots,InpMagic,InpDeviation,"TestMqlTradeTransaction");
         //--- If the button is assigned to the Sell position, open Sell
         if(lparam==key_sell)
            OpenSell(NULL,InpLots,InpMagic,InpDeviation,"TestMqlTradeTransaction");
         //--- If the button is assigned to closing positions, close all positions 
         if(lparam==key_close)
            ClosePositionsAll(Symbol());
        }
      //--- If only Shift is held 
      if(IsShiftKeyPressed() && !IsCtrlKeyPressed())
        {
         //--- If the button is assigned to Buy order, open Buy Stop order
         if(lparam==key_buy)
            SetBuyStop(NULL,InpLots,InpMagic,InpDistance,"TestMqlTradeTransaction");
         //--- If the button is assigned to Sell order, open Sell Stop order
         if(lparam==key_sell)
            SetSellSellStop(NULL,InpLots,InpMagic,InpDistance,"TestMqlTradeTransaction");
         //--- If the button is assigned to delete orders, delete all orders 
         if(lparam==key_close)
            DeleteOrdersAll(NULL);
        }
         //--- If Shift is held together with Ctrl
      if(IsShiftKeyPressed() && IsCtrlKeyPressed())
        {
         //--- If the button is assigned to Buy order, open Buy Limit order
         if(lparam==key_buy)
            SetBuyLimit(NULL,InpLots,InpMagic,InpDistance,"TestMqlTradeTransaction");
         //--- If the button is assigned to Sell order, open Sell Limit order
         if(lparam==key_sell)
            SetSellLimit(NULL,InpLots,InpMagic,InpDistance,"TestMqlTradeTransaction");
         //--- If the button is assigned to delete orders, delete all orders 
         if(lparam==key_close)
            DeleteOrdersAll(Symbol());
        }
     }
  }
//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
  {
//--- Set all incoming trade transactions to the journal
   TradeTransactionInformer(trans,request,result,18,2,true);
  }

La colocación de órdenes y la apertura de posiciones se implementará en el manejador OnChartEvent() del asesor. En el manejador OnTradeTransaction(), se llamará a la función TradeTransactionInformer() analizada anteriormente, que mostrará cada transacción entrante en el registro. El asesor utilizará en su trabajo todas las funciones comentadas en el artículo, por lo que estas deberán incluirse en el archivo del asesor para que se compile sin errores.

Al colocar una orden BuyLimit, en el registro se mostrarán las siguientes entradas de todas las transacciones procesadas:

Transaction Type: Order add (Adding a new open order)
  Order:            1838106218
  Symbol:           EURUSD
  Order type:       Buy Limit (Buy Limit pending order)
  Order state:      Started (Order checked, but not yet accepted by broker)
  Time type:        Time GTC (Good till cancel order)
  Price:            1.09449
  Price SL:         0.0
  Price TP:         0.0
  Volume:           0.10
Transaction Type: Order update (Updating an open order)
  Order:            1838106218
  Symbol:           EURUSD
  Order type:       Buy Limit (Buy Limit pending order)
  Order state:      Placed (Order accepted)
  Time type:        Time GTC (Good till cancel order)
  Price:            1.09449
  Price SL:         0.0
  Price TP:         0.0
  Volume:           0.10
Transaction Type: Request (The trade request has been processed by a server and processing result has been received)
  The second and third parameters of OnTradeTransaction function (request and result) must be analyzed for additional data:
Request Pending (Place a trade order for the execution under specified conditions (pending order)):
  Symbol:           EURUSD
  Volume:           0.10
  Price:            1.09449
  SL:               0.0
  TP:               0.0
  Type:             Buy Limit (Buy Limit pending order)
  Type filling:     Return (In case of partial filling, an order with remaining volume is not canceled but processed further)
  Type time:        Time GTC (Good till cancel order)
  Expiration:       0
  Magic:            1024
  Comment:          TestMqlTradeTransaction
OrderSend result:
  Retcode:          10009 DONE (Request completed)
  Deal:             0
  Order:            1838106218
  Volume:           0.10
  Price:            0.0
  Bid:              0.0
  Ask:              0.0
  Comment:          
  Request ID:       930808478
  Retcode External: 0

Cuando posteriormente eliminemos una orden colocada, veremos las siguientes entradas en el registro del terminal:

Transaction Type: Order update (Updating an open order)
  Order:            1838106218
  Symbol:           EURUSD
  Order type:       Buy Limit (Buy Limit pending order)
  Order state:      Request cancel (Order is being deleted (deleting from the trading system))
  Time type:        Time GTC (Good till cancel order)
  Price:            1.09449
  Price SL:         0.0
  Price TP:         0.0
  Volume:           0.10
Transaction Type: Order delete (Removing an order from the list of the open ones)
  Order:            1838106218
  Symbol:           EURUSD
  Order type:       Buy Limit (Buy Limit pending order)
  Order state:      Canceled (Order canceled by client)
  Time type:        Time GTC (Good till cancel order)
  Price:            1.09449
  Price SL:         0.0
  Price TP:         0.0
  Volume:           0.10
Transaction Type: History add (Adding an order to the history as a result of execution or cancellation)
  Order:            1838106218
  Symbol:           EURUSD
  Order type:       Buy Limit (Buy Limit pending order)
  Order state:      Canceled (Order canceled by client)
  Time type:        Time GTC (Good till cancel order)
  Price:            1.09449
  Price SL:         0.0
  Price TP:         0.0
  Volume:           0.10
Transaction Type: Request (The trade request has been processed by a server and processing result has been received)
  The second and third parameters of OnTradeTransaction function (request and result) must be analyzed for additional data:
Request Remove (Delete the pending order placed previously):
  Order:            1838106218
OrderSend result:
  Retcode:          10009 DONE (Request completed)
  Deal:             0
  Order:            1838106218
  Volume:           0.00
  Price:            0.0
  Bid:              0.0
  Ask:              0.0
  Comment:          
  Request ID:       930808479
  Retcode External: 0


Conclusión

Hoy hemos considerado todas las estructuras necesarias para crear una orden comercial, verificarla y enviarla al servidor. También hemos obtenido una descripción completa de todas las transacciones comerciales que ocurren en la cuenta como resultado de las operaciones comerciales.

Todas las funciones propuestas se pueden utilizar "tal cual", o podemos modificarlas para adaptarlas a nuestras propia visión de su aplicación y uso.

En el archivo adjunto se incluye el archivo del asesor con todas las funciones comentadas en el artículo. Podrá descargarlo y probarlo todo por sí mismo.

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/13052

Archivos adjuntos |
Teoría de categorías en MQL5 (Parte 15): Funtores con grafos Teoría de categorías en MQL5 (Parte 15): Funtores con grafos
El artículo continúa la serie sobre la implementación de la teoría de categorías en MQL5, analizando los funtores como un puente entre grafos y conjuntos. Volveremos nuevamente a los datos del calendario y, a pesar de sus limitaciones en el uso de un simulador de estrategias, justificaremos el uso de funtores para predecir la volatilidad mediante la correlación.
La técnica comercial RSI Deep Three Move La técnica comercial RSI Deep Three Move
El presente artículo muestra la técnica comercial RSI Deep Three Move en MetaTrader 5. El artículo se basa en una nueva serie de estudios que demuestran varias técnicas comerciales basadas en el RSI, así como un indicador técnico para medir la fuerza y el impulso de los valores, incluidas las acciones, las divisas y las materias primas.
Redes neuronales: así de sencillo (Parte 52): Exploración con optimismo y corrección de la distribución Redes neuronales: así de sencillo (Parte 52): Exploración con optimismo y corrección de la distribución
A medida que el modelo se entrena con el búfer de reproducción de experiencias, la política actual del Actor se aleja cada vez más de los ejemplos almacenados, lo cual reduce la eficacia del entrenamiento del modelo en general. En este artículo, analizaremos un algoritmo para mejorar la eficiencia del uso de las muestras en los algoritmos de aprendizaje por refuerzo.
Redes neuronales: así de sencillo (Parte 51): Actor-crítico conductual (BAC) Redes neuronales: así de sencillo (Parte 51): Actor-crítico conductual (BAC)
Los dos últimos artículos han considerado el algoritmo SAC (Soft Actor-Critic), que incorpora la regularización de la entropía en la función de la recompensa. Este enfoque equilibra la exploración del entorno y la explotación del modelo, pero solo es aplicable a modelos estocásticos. El presente material analizará un enfoque alternativo aplicable tanto a modelos estocásticos como deterministas.