English Русский 中文 Deutsch 日本語 Português
Por dónde comenzar a crear un robot comercial para la Bolsa de Moscú MOEX

Por dónde comenzar a crear un robot comercial para la Bolsa de Moscú MOEX

MetaTrader 5Ejemplos | 16 junio 2016, 13:19
1 615 0
MetaQuotes
MetaQuotes

Muchos tráders de la Bolsa de Moscú querrían automatizar sus algoritmos comerciales, pero no saben por dónde empezar. El lenguaje MQL5 propone no solo un conjunto enorme de funciones comerciales, sino también clases preparadas, que facilitan al máximo los primeros pasos en el trading automático. En este artículo mostraremos qué herramientas preparadas propone el lenguaje de estrategias comerciales MQL5 a los tráders del comercio algorítmico en la Bolsa de Moscú.

Dos tipos de solicitudes comerciales en la Bolsa de Moscú MOEX

  La Bolsa de Moscú MOEX da soporte a dos tipos de solicitudes comerciales: de mercado y límite.
  • Las solicitudes de mercado llegan de inmediato a la bolsa y se ejecutan al precio de la mejor oferta. Para enviar estas solicitudes en MQL5 se usan órdenes de mercado del tipo ORDER_TYPE_BUY y ORDER_TYPE_SELL.
  • Las solicitudes límite se guardan en el servidor de la bolsa y se ejecutan en cuanto aparezca una solicitud opuesta adecuada. En el lenguaje MQL5 a estas solicitudes les corresponden las órdenes del tipo ORDER_TYPE_BUY_LIMIT y ORDER_TYPE_SELL_LIMIT.

La solicitud de mercado garantiza (pero no siempre) la realización de la operación, sin embargo, no garantiza el precio. Esto significa que como resultado de una operación comercial usted podrá ejecutar una operación a un precio que se diferencia significativamente de la oferta actual. Al mismo tiempo, la solicitud límite garantiza el precio, pero no garantiza que la operación a este precio se llegue a ejecutar. Como resultado, usted puede quedarse fuera del mercado, sin llegar a conseguir la ejecución de la solicitud.

Todos los demás tipos de solicitudes que se proponen a los tráders de la Bolsa de Moscú son parte del complejo programático a través del cual los tráders interactúan con la bolsa. En otras palabras: el resto de las solicitudes son algorítmicas. Las solicitudes se guardan y procesan fuera de la Bolsa de Moscú, y se envían a esta en forma de solicitud de mercado o límite como resultado del procesamiento interno.

La plataforma MetaTrader 5 propone a los tráders los siguientes tipos de solicitudes comerciales, que se pueden usar para comerciar en la Bolsa de Moscú:

Identificador Descripción Guardado y ejecución

ORDER_TYPE_BUY

Orden de mercado de compra

Se envía a la bolsa en forma de solicitud de mercado de compra al mejor precio de venta actual

ORDER_TYPE_SELL

Orden de mercado de venta

Se envía a la bolsa en forma de solicitud de mercado de venta al mejor precio de compra actual

ORDER_TYPE_BUY_LIMIT

Orden pendiente Buy Limit

Se envía a la bolsa en forma de solicitud límite de compra y se ejecuta al aparecer una oferta de venta al precio indicado o al mejor precio.

ORDER_TYPE_SELL_LIMIT

Orden pendiente Sell Limit

Se envía a la bolsa en forma de solicitud límite de venta y se ejecuta al aparecer una oferta de compra al precio indicado o al mejor precio.

ORDER_TYPE_BUY_STOP

Orden pendiente Buy Stop

Se guarda en el servidor de MetaTrader 5, y al activarse, se envía a la bolsa:
  • para la sección de valores y divisas, en forma de solicitud de mercado de compra
  • para FORTS, en forma de solicitud límite de compra al peor precio del límite del pasillo

ORDER_TYPE_SELL_STOP

Orden pendiente Sell Stop

Se guarda en el servidor de MetaTrader 5, y al activarse, se envía a la bolsa:
  • para la sección de valores y divisas, en forma de solicitud de mercado de venta
  • para FORTS, en forma de solicitud límite de venta al peor precio del límite del pasillo

ORDER_TYPE_BUY_STOP_LIMIT

Orden pendiente BUY STOP LIMIT

Se guarda en el servidor de MetaTrader 5, y al activarse, se envía a la bolsa en forma de solicitud límite de compra

ORDER_TYPE_SELL_STOP_LIMIT

Orden pendiente SELL STOP LIMIT

Se guarda en el servidor de MetaTrader 5, y al activarse, se envía a la bolsa en forma de solicitud límite de venta

Para las posiciones abiertas, la plataforma MetaTrader 5 permite definir los niveles de TakeProfit y StopLoss, que se guardan en el servidor comercial de MetaTrader 5 y se activan de forma automática incluso sin estar conectado a la cuenta comercial:

  • El nivel de TakeProfit indica el precio para el cierre de la posición en la dirección adecuada, y al activarse en la bolsa, se envía una solicitud límite al precio de TakeProfit;
  • el nivel de StopLoss sirve para implementar un stop defensivo en una dirección poco conveniente, y al activarse se envía a la bolsa una solicitud de mercado al precio StopLoss para la sección de valores y divisas, para FORTS se envía una solicitud límite al peor precio del límite del pasillo.

Además, la plataforma MetaTrader 5 permite establecer y modificar los niveles de StopLoss/TakeProfit para las órdenes pendientes, así como modificar los niveles de activación de todas las órdenes pendientes.



Operaciones comerciales en MetaTrader 5

MetaTrader 5 propone varios tipos principales de operaciones comerciales, que pueden serle necesarias en el robot comercial:

  1. compra/venta al precio actual;
  2. esteblecer una orden pendiente de compra/venta según una condición concreta;
  3. modificación/eliminación de una orden pendiente;
  4. cierre/incremento/disminución/viraje de la posición.

Todas las operaciones comerciales en MQL5 se realizan con la ayuda de la función OrderSend(), que retorna el control al programa en el momento que la orden comercial se haya enviado con éxito a la Bolsa de Moscú. El estado de la orden en ese momento adopta el valor ORDER_STATE_PLACED, y eso significa que su orden se ha ejecutado con éxito (estado de la orden ORDER_STATE_FILLED o ORDER_STATE_PARTIAL). El resultado final de la ejecución de su orden comercial depende del mercado actual, y la orden puede ser rechazada por la bolsa (estado ORDER_STATE_REJECTED) por diferentes motivos.

Existe también una variedad asincrónica de esta función: OrderSendAsync(), que funciona con mucha mayor rapidez que OrderSend(), puesto que no espera al envío de la orden al sistema comercial de la bolsa. La respuesta a esta función se envía de inmediato, en cuanto la solicitud ha sido enviada por el terminal MetaTrader 5 al exterior. Esto significa que su solicitud comercial ha superado la comprobación en el propio terminal y ahora ha sido enviada para su procesamiento en el servidor comercial de MetaTrader 5. Cuánto tiempo se tardará en poner su orden en la cola de la bolsa y cuándo se ejecutará o será rechazada, todo ello depende solo de la carga de trabajo de la bolsa y de la velocidad de su conexión a internet.

Toda la variedad de operaciones comerciales se explica con la estructura MqlTradeRequest, que contiene la descripción de la solicitud comercial. Por eso, las únicas dificultades con las operaciones comerciales pueden relacionarse con el rellenado de la estructura MqlTradeRequest y el procesamiento del resultado de la ejecución de la solicitud.

De acuerdo con las reglas de su sistema comercial, usted puede realizar la compra o la venta al precio del mercado (BUY o SELL), y puede ubicar una orden pendiente de compra/venta a una cierta distancia del precio de mercado actual:

  • BUY STOP, SELL STOP — compra o venta al atravesar el nivel indicado (peor que el precio actual). Las órdenes de este tipo se guardan en el servidor comercial de MetaTrader 5 y se envían a la Bolsa de Moscú en el momento de la activación de la condición en forma de orden de mercado (sección de fondos y de divisas) o solicitud límite (FORTS).
  • BUY LIMIT, SELL LIMIT — compra o venta al alcanzar el nivel indicado (mejor que el precio actual). Las órdenes de este tipo se envían de inmediato a la Bolsa de Moscú en forma de solicitud límite. Conviene destacar que en el Bolsa de Moscú en una solicitud límite se puede indicar un nivel dentro del spread o incluso en el lado contrario del spread. De esta forma se limita el deslizamiento al realizar una operación.
  • BUY STOP LIMIT, SELL STOP LIMIT — establecer una orden BUY LIMIT o SELL LIMIT al alcanzar el precio indicado. Las órdenes se guardan en el servidor comercial MetaTrader 5, y en el momento de activación de la condición en la Bolsa de Moscú, se envía una solicitud límite normal. El nivel de apertura de esta solicitud límite puede ser tanto mayor como menor al precio de activación de la propia orden.

El principio de ejecución de las órdenes BUY STOP, SELL STOP y BUY LIMIT, SELL LIMIT, así como sus métodos de colocación directamente desde la profundidad de mercado se muestra más abajo.


Además, puede que le sea necesario a usted modificar o directamente eliminar una orden pendiente. Esto también se hace con la ayuda de las funciones OrderSend()/OrderSendAsync(). El trabajo con una posición abierta tampoco representa ninguna dificultad, puesto que tiene lugar como resultado de la ejecución de las propias operaciones comerciales.

En este artículo mostraremos lo fácil y simple que es programar la compra y la venta en MQL5, y demostraremos cómo trabajar con una cuenta comercial y las propiedades de los símbolos. En esto nos ayudarán las clases comerciales de la Biblioteca estándar.



Comerciar en la bolsa con ayuda de robots es muy sencillo

El lenguaje MQL5 desde el principio da soporte a todas las posibilidades comerciales de la plataforma MetaTrader 5: en él están presentes multitud de funciones comerciales para trabajar con órdenes, posiciones y solicitudes comerciales. Además, no importa el mercado en el que usted comercie: futuros, acciones opciones, etc.

Con los recursos de MQL5 usted podrá crear una solicitud comercial y enviarla al servidor con la ayuda de la función OrderSend() o OrderSendAsync(), obtener el resultado de su ejecución, ver la historia comercial, conocer las especificaciones del contrato para un instrumento, procesar un evento comercial y obtener toda la información imprescindible.

Para los desarrolladores de robots es importante comprender una circunstancia muy importante: cada operación comercial, sea una apertura de posición, la colocación de un StopLoss o un TakeProfit, o el cierre de posición de una operación opuesta, siempre consta de multitud de transacciones realizadas en el servidor de MetaTrader 5 y en la Bolsa de Moscú. Para ver cómo sucede esto, usted puede iniciar en su cuenta el asesor TradeTransactionListener.mql5, que simplemente oye los eventos de TradeTransaction y muestra una breve información sobre ellos:

//+------------------------------------------------------------------+
//|                                     TradeTransactionListener.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   PrintFormat("LAST PING=%.f ms",
               TerminalInfoInteger(TERMINAL_PING_LAST)/1000.);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result)
  {
//---
   static int counter=0;   // contador de llamadas de OnTradeTransaction()
   static uint lasttime=0; // hora de la última llamada de OnTradeTransaction()
//---
   uint time=GetTickCount();
//--- si la última transacción se ha realizado hace más de 1 segundo
   if(time-lasttime>1000)
     {
      counter=0; // significa que se trata de una nueva operación comercial y se puede resetear el contador
      if(IS_DEBUG_MODE)
         Print(" Nueva operación comercial");
     }
   lasttime=time;
   counter++;
   Print(counter,". ",__FUNCTION__);
//--- resultado de la ejecución de la solicitud comercial
   ulong            lastOrderID   =trans.order;
   ENUM_ORDER_TYPE  lastOrderType =trans.order_type;
   ENUM_ORDER_STATE lastOrderState=trans.order_state;
//--- nombre del símbolo del que ha tenido lugar la transacción
   string trans_symbol=trans.symbol;
//--- tipo de transacción
   ENUM_TRADE_TRANSACTION_TYPE  trans_type=trans.type;
   switch(trans.type)
     {
      case  TRADE_TRANSACTION_POSITION:   // cambio de la posición
        {
         ulong pos_ID=trans.position;
         PrintFormat("MqlTradeTransaction: Position #%I64u %s modified: SL=%.5f TP=%.5f",
                     pos_ID,trans_symbol,trans.price_sl,trans.price_tp);
        }
      break;
      case TRADE_TRANSACTION_REQUEST:     // envío de la solicitud comercial
         PrintFormat("MqlTradeTransaction: TRADE_TRANSACTION_REQUEST");
         break;
      case TRADE_TRANSACTION_DEAL_ADD:    // adición de una operación
        {
         ulong          lastDealID   =trans.deal;
         ENUM_DEAL_TYPE lastDealType =trans.deal_type;
         double        lastDealVolume=trans.volume;
         //--- el identificador de la operación en el sistema externo es un ticket asignado a la Bolsa de Moscú
         string Exchange_ticket="";
         if(HistoryDealSelect(lastDealID))
            Exchange_ticket=HistoryDealGetString(lastDealID,DEAL_EXTERNAL_ID);
         if(Exchange_ticket!="")
            Exchange_ticket=StringFormat("(MOEX deal=%s)",Exchange_ticket);

         PrintFormat("MqlTradeTransaction: %s deal #%I64u %s %s %.2f lot   %s",EnumToString(trans_type),
                     lastDealID,EnumToString(lastDealType),trans_symbol,lastDealVolume,Exchange_ticket);
        }
      break;
      case TRADE_TRANSACTION_HISTORY_ADD: // adición de una orden a la historia
        {
         //--- el identificador de la orden en el sistema externo es un ticket asignado a la Bolsa de Moscú
         string Exchange_ticket="";
         if(lastOrderState==ORDER_STATE_FILLED)
           {
            if(HistoryOrderSelect(lastOrderID))
               Exchange_ticket=HistoryOrderGetString(lastOrderID,ORDER_EXTERNAL_ID);
            if(Exchange_ticket!="")
               Exchange_ticket=StringFormat("(MOEX ticket=%s)",Exchange_ticket);
           }
         PrintFormat("MqlTradeTransaction: %s order #%I64u %s %s %s   %s",EnumToString(trans_type),
                     lastOrderID,EnumToString(lastOrderType),trans_symbol,EnumToString(lastOrderState),Exchange_ticket);
        }
      break;
      default: // otras transacciones  
        {
         //--- el identificador de la orden en el sistema externo es un ticket asignado a la Bolsa de Moscú
         string Exchange_ticket="";
         if(lastOrderState==ORDER_STATE_PLACED)
           {
            if(OrderSelect(lastOrderID))
               Exchange_ticket=OrderGetString(ORDER_EXTERNAL_ID);
            if(Exchange_ticket!="")
               Exchange_ticket=StringFormat("MOEX ticket=%s",Exchange_ticket);
           }
         PrintFormat("MqlTradeTransaction: %s order #%I64u %s %s   %s",EnumToString(trans_type),
                     lastOrderID,EnumToString(lastOrderType),EnumToString(lastOrderState),Exchange_ticket);
        }
      break;
     }
//--- ticket de la orden    
   ulong orderID_result=result.order;
   string retcode_result=GetRetcodeID(result.retcode);
   if(orderID_result!=0)
      PrintFormat("MqlTradeResult: order #%d retcode=%s ",orderID_result,retcode_result);
//---   
  }
//+------------------------------------------------------------------+
//| pasa los códigos numéricos de las respuestas a códigos mnemónicos de línea          |
//+------------------------------------------------------------------+
string GetRetcodeID(int retcode)
  {
   switch(retcode)
     {
      case 10004: return("TRADE_RETCODE_REQUOTE");             break;
      case 10006: return("TRADE_RETCODE_REJECT");              break;
      case 10007: return("TRADE_RETCODE_CANCEL");              break;
      case 10008: return("TRADE_RETCODE_PLACED");              break;
      case 10009: return("TRADE_RETCODE_DONE");                break;
      case 10010: return("TRADE_RETCODE_DONE_PARTIAL");        break;
      case 10011: return("TRADE_RETCODE_ERROR");               break;
      case 10012: return("TRADE_RETCODE_TIMEOUT");             break;
      case 10013: return("TRADE_RETCODE_INVALID");             break;
      case 10014: return("TRADE_RETCODE_INVALID_VOLUME");      break;
      case 10015: return("TRADE_RETCODE_INVALID_PRICE");       break;
      case 10016: return("TRADE_RETCODE_INVALID_STOPS");       break;
      case 10017: return("TRADE_RETCODE_TRADE_DISABLED");      break;
      case 10018: return("TRADE_RETCODE_MARKET_CLOSED");       break;
      case 10019: return("TRADE_RETCODE_NO_MONEY");            break;
      case 10020: return("TRADE_RETCODE_PRICE_CHANGED");       break;
      case 10021: return("TRADE_RETCODE_PRICE_OFF");           break;
      case 10022: return("TRADE_RETCODE_INVALID_EXPIRATION");  break;
      case 10023: return("TRADE_RETCODE_ORDER_CHANGED");       break;
      case 10024: return("TRADE_RETCODE_TOO_MANY_REQUESTS");   break;
      case 10025: return("TRADE_RETCODE_NO_CHANGES");          break;
      case 10026: return("TRADE_RETCODE_SERVER_DISABLES_AT");  break;
      case 10027: return("TRADE_RETCODE_CLIENT_DISABLES_AT");  break;
      case 10028: return("TRADE_RETCODE_LOCKED");              break;
      case 10029: return("TRADE_RETCODE_FROZEN");              break;
      case 10030: return("TRADE_RETCODE_INVALID_FILL");        break;
      case 10031: return("TRADE_RETCODE_CONNECTION");          break;
      case 10032: return("TRADE_RETCODE_ONLY_REAL");           break;
      case 10033: return("TRADE_RETCODE_LIMIT_ORDERS");        break;
      case 10034: return("TRADE_RETCODE_LIMIT_VOLUME");        break;
      case 10035: return("TRADE_RETCODE_INVALID_ORDER");       break;
      case 10036: return("TRADE_RETCODE_POSITION_CLOSED");     break;
      default:
         return("TRADE_RETCODE_UNKNOWN="+IntegerToString(retcode));
         break;
     }
//---
  }
//+------------------------------------------------------------------+

Ejemplo de funcionamiento de este "oyente":

2016.06.09 14:51:19.763 TradeTransactionListener (Si-6.16,M15)  LAST PING=14 ms
Compra
2016.06.09 14:51:24.856 TradeTransactionListener (Si-6.16,M15)  1. OnTradeTransaction
2016.06.09 14:51:24.856 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_ORDER_ADD order #49118594 ORDER_TYPE_BUY ORDER_STATE_STARTED   
2016.06.09 14:51:24.859 TradeTransactionListener (Si-6.16,M15)  2. OnTradeTransaction
2016.06.09 14:51:24.859 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_REQUEST
2016.06.09 14:51:24.859 TradeTransactionListener (Si-6.16,M15)  MqlTradeResult: order #49118594 retcode=TRADE_RETCODE_PLACED 
2016.06.09 14:51:24.859 TradeTransactionListener (Si-6.16,M15)  3. OnTradeTransaction
2016.06.09 14:51:24.859 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_ORDER_UPDATE order #49118594 ORDER_TYPE_BUY ORDER_STATE_REQUEST_ADD   
2016.06.09 14:51:24.881 TradeTransactionListener (Si-6.16,M15)  4. OnTradeTransaction
2016.06.09 14:51:24.881 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_ORDER_UPDATE order #49118594 ORDER_TYPE_BUY ORDER_STATE_PLACED   
2016.06.09 14:51:24.881 TradeTransactionListener (Si-6.16,M15)  5. OnTradeTransaction
2016.06.09 14:51:24.881 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_ORDER_DELETE order #49118594 ORDER_TYPE_BUY ORDER_STATE_PLACED   
2016.06.09 14:51:24.884 TradeTransactionListener (Si-6.16,M15)  6. OnTradeTransaction
2016.06.09 14:51:24.884 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_HISTORY_ADD order #49118594 ORDER_TYPE_BUY Si-6.16 ORDER_STATE_FILLED   (MOEX ticket=3377179723)
2016.06.09 14:51:24.884 TradeTransactionListener (Si-6.16,M15)  7. OnTradeTransaction
2016.06.09 14:51:24.885 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_DEAL_ADD deal #6945344 DEAL_TYPE_BUY Si-6.16 1.00 lot   (MOEX deal=185290434)
Colocación de SL/TP
2016.06.09 14:51:50.872 TradeTransactionListener (Si-6.16,M15)  1. OnTradeTransaction
2016.06.09 14:51:50.872 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_REQUEST
2016.06.09 14:51:50.872 TradeTransactionListener (Si-6.16,M15)  2. OnTradeTransaction
2016.06.09 14:51:50.872 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: Position  #0 Si-6.16 modified: SL=62000.00000 TP=67000.00000
Cierre de posición (venta)
2016.06.09 14:52:24.063 TradeTransactionListener (Si-6.16,M15)  1. OnTradeTransaction
2016.06.09 14:52:24.063 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_ORDER_ADD order #49118750 ORDER_TYPE_SELL ORDER_STATE_STARTED   
2016.06.09 14:52:24.067 TradeTransactionListener (Si-6.16,M15)  2. OnTradeTransaction
2016.06.09 14:52:24.067 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_REQUEST
2016.06.09 14:52:24.067 TradeTransactionListener (Si-6.16,M15)  MqlTradeResult: order #49118750 retcode=TRADE_RETCODE_PLACED 
2016.06.09 14:52:24.067 TradeTransactionListener (Si-6.16,M15)  3. OnTradeTransaction
2016.06.09 14:52:24.067 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_ORDER_UPDATE order #49118750 ORDER_TYPE_SELL ORDER_STATE_REQUEST_ADD   
2016.06.09 14:52:24.071 TradeTransactionListener (Si-6.16,M15)  4. OnTradeTransaction
2016.06.09 14:52:24.071 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_ORDER_UPDATE order #49118750 ORDER_TYPE_SELL ORDER_STATE_PLACED   
2016.06.09 14:52:24.073 TradeTransactionListener (Si-6.16,M15)  5. OnTradeTransaction
2016.06.09 14:52:24.073 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_DEAL_ADD deal #6945378 DEAL_TYPE_SELL Si-6.16 1.00 lot   (MOEX deal=185290646)
2016.06.09 14:52:24.075 TradeTransactionListener (Si-6.16,M15)  6. OnTradeTransaction
2016.06.09 14:52:24.075 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_ORDER_DELETE order #49118750 ORDER_TYPE_SELL ORDER_STATE_PLACED   
2016.06.09 14:52:24.077 TradeTransactionListener (Si-6.16,M15)  7. OnTradeTransaction
2016.06.09 14:52:24.077 TradeTransactionListener (Si-6.16,M15)  MqlTradeTransaction: TRADE_TRANSACTION_HISTORY_ADD order #49118750 ORDER_TYPE_SELL Si-6.16 ORDER_STATE_FILLED   (MOEX ticket=3377182821)

Ahora es el momento de proceder al análisis de los ejemplos del código fuente.



Trabajo con la cuenta comercial

Para comenzar, al iniciar el robot comercial es necesario obtener información sobre la cuenta en la que va a comerciar.

Para trabajar con la cuenta existe la clase CAccountInfo, que ha sido desarrollada especialmente con estos fines. Añadimos a nuestro código la conexión del archivo AccountInfo.mqh y declaramos la variable de esta clase account:

#include <Trade\AccountInfo.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- objeto para trabajar con la cuenta
CAccountInfo account;
//--- obtenemos el número de la cuenta en la que ha sido iniciado el asesor
   long login=account.Login();
   Print("Login=",login);
//--- mostramos la divisa de la cuenta    
   Print("Divisa de la cuenta: ",account.Currency());   
//--- mostramos el balance y el beneficio actual de la cuenta
   Print("Balance=",account.Balance(),"  Profit=",account.Profit(),"   Equity=",account.Equity());
//--- mostramos el tipo de cuenta    
   Print("Tipo de cuenta: ",account.TradeModeDescription());
//--- aclaramos si se puede comerciar en general en esta cuenta
   if(account.TradeAllowed())
      Print("El comercio en esta cuenta está permitido");
   else
      Print("El comercio en la cuenta está prohibido: quizá la entrada se realizó con la contraseña de inversor");
//--- modo de cálculo del margen
   Print("Modo de cálculo del margen: ",account.MarginModeDescription());
//--- aclaramos si está permitido comerciar en la cuenta con la ayuda de un experto
   if(account.TradeExpert())
      Print("El comercio automático en la cuenta está permitido");
   else
      Print("El comercio automático con la ayuda de expertos y scripts está prohibido");
//--- la cantidad de órdenes permitidas se ha definido o no
   int orders_limit=account.LimitOrders();
   if(orders_limit!=0)Print("Número máximo permitido de órdenes pendientes activas: ",orders_limit);
//--- mostramos el nombre de la compañía y el servidor
   Print(account.Company(),": server ",account.Server());
   Print(__FUNCTION__,"  completed"); //---   
  }

Como podemos ver por el código mostrado, con la ayuda de la variable account en la función OnInit() se puede obtener mucha información útil. Puede añadir este código a su experto y le resultará bastante más sencillo descifrar el registro (log) al analizar su funcionamiento.

El resultado del inicio del experto se muestra en la imagen.


Obtener las propiedades de un instrumento financiero

Ya hemos obtenido la información sobre la cuenta, pero para realizar operaciones comerciales debemos conocer además las propiedades del activo con el que tenemos intención de comerciar. Para ello tenemos otra clase muy cómoda, CSymbolInfo que posee una gran cantidad de métodos. Mostraremos como ejemplo solo una pequeña parte.

#include<Trade\SymbolInfo.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- objeto para obtener las propiedades del símbolo
CSymbolInfo symbol_info;
//--- indicamos el nombre del símbolo para el que vamos a recibir información
   symbol_info.Name(_Symbol);
//--- obtenemos las cotizaciones actuales y las mostramos
   symbol_info.RefreshRates();
   Print(symbol_info.Name()," (",symbol_info.Description(),")",
         "  Bid=",symbol_info.Bid(),"   Ask=",symbol_info.Ask());
//--- obtenemos el número de dígitos tras la coma y el tamaño del punto
   Print("Digits=",symbol_info.Digits(),
         ", Point=",DoubleToString(symbol_info.Point(),symbol_info.Digits()));
//--- solicitamos el tipo de ejecución de las órdenes y si hay limitaciones
   Print("Limitaciones en las operaciones comerciales: ",EnumToString(symbol_info.TradeMode()),
         " (",symbol_info.TradeModeDescription(),")");
//--- aclaramos el modo de ejecución de las operaciones
   Print("Modo de ejecución de las operaciones: ",EnumToString(symbol_info.TradeExecution()),
         " (",symbol_info.TradeExecutionDescription(),")");
//--- aclaramos el modo de cálculo del coste de los contratos
   Print("Cálculo del coste del contrato: ",EnumToString(symbol_info.TradeCalcMode()),
         " (",symbol_info.TradeCalcModeDescription(),")");
//--- tamaño del contrato
   Print("Tamaño del contrato estándar: ",symbol_info.ContractSize());
//--- tamaño del margen inicial para 1 contrato
   Print("Margen inicial para un contrato estándar: ",symbol_info.MarginInitial()," ",symbol_info.CurrencyBase());
//--- tamaños mínimo, máximo del volumen en las operaciones comerciales
   Print("Volume info: LotsMin=",symbol_info.LotsMin(),"  LotsMax=",symbol_info.LotsMax(),
         "  LotsStep=",symbol_info.LotsStep());
//--- 
   Print(__FUNCTION__,"  completed");   
  }

En la imagen se muestran las propiedades del símbolo Si-6.16 de la sección del mercado urgente de la Bolsa de Moscú (FORTS). Ahora usted está preparado para pasar directamente al comercio.



Programación de operaciones comerciales

Para enviar órdenes comerciales en el lenguaje MQL5 existen dos funciones: OrderSend() y OrderSendAsync(). En realidad son dos implementaciones de la misma función. Mientras que OrderSend() envía una solicitud comercial y espera el resultado de su ejecución, la OrderSendAsync() asincrónica simplemente lanza la solicitud y permite al programa seguir trabajando sin esperar la respuesta del servidor comercial. De esta forma, trabajar en MQL5 es realmente sencillo, basta con usar solo una función para todas las operaciones comerciales

Ambas funciones reciben como primer parámetro la estructura MqlTradeRequest, que contiene más de una decena de campos. Los componentes de los campos necesarios dependen del tipo de operación comercial, por eso no es necesario rellenar todos los campos. En caso de que se dé un valor incorrecto o no haya campo en absoluto, la solicitud no superará la revisión en el propio terminal y sencillamente no se enviará al servidor. Además, los valores de las enumeraciones predeterminadas de los 5 campos deben ser correctamente indicados.

Semejante cantidad de campos en la solicitud comercial es necesaria debido a la necesidad de describir la multitud de propiedades de la orden, que pueden cambiar dependiendo de la política de ejecución, el tiempo de expiración y otros parámetros. Usted no estará obligado a aprenderse de memoria todas estas sutilezas, solo tendrá que usar la clase CTrade. Este será el aspecto aproximado que tendrá el uso de esta clase en nuestro robot comercial:

#include<Trade\Trade.mqh>
//--- objeto para la realización de operaciones comerciales
CTrade  trade;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicamos el Número Mágico para identificar nuestras órdenes
   int MagicNumber=123456;
   trade.SetExpertMagicNumber(MagicNumber);
//--- establecemos el deslizamiento permisible en puntos al realizar una compra/venta
   int deviation=10;
   trade.SetDeviationInPoints(deviation);
//--- modo de rellenado de una orden, hay que usar el modo que esté permitido por el servidor
   trade.SetTypeFilling(ORDER_FILLING_RETURN);
//--- modo de registro (logueo): mejor no llamar a este método en absoluto, la clase pondrá ella misma el modo óptimo
   trade.LogLevel(1); 
//--- qué función usar para el comercio: true - OrderSendAsync(), false - OrderSend()
   trade.SetAsyncMode(true);
//---
   return(0);
  }

Para comerciar en la bolsa, normalmente se usa el modo de ejecución ORDER_FILLING_RETURN. La guía dice:

Este modo se usa dolo en los modos "Ejecución por mercado" y "Ejecución bursátil": para las órdenes de mercado (ORDER_TYPE_BUY y ORDER_TYPE_SELL), las órdenes límite y límite stop (ORDER_TYPE_BUY_LIMIT, ORDER_TYPE_SELL_LIMIT, ORDER_TYPE_BUY_STOP_LIMIT y ORDER_TYPE_SELL_STOP_LIMIT). En caso de ejecución parcial, una orden limitada con el volumen no cubierto no se anula, sino que sigue estando vigente.

Para las órdenes ORDER_TYPE_BUY_STOP_LIMIT y ORDER_TYPE_SELL_STOP_LIMIT, al activarse se creará la orden límite correspondiente ORDER_TYPE_BUY_LIMIT/ORDER_TYPE_SELL_LIMIT con el tipo de ejecución ORDER_FILLING_RETURN.

Ha llegado el momento de ver cómo CTrade ayuda en las operaciones comerciales.

Compra/venta al precio actual

Con frecuencia en las estrategias comerciales es necesario realizar la compra o venta al precio actual en el mismo instante. CTrade está familiarizado con esa situación y solo pide el volumen necesario de la operación comercial. Todos los demás parámetros: el precio de apertura y el nombre del símbolo, los niveles de Stop Loss y Take Profit, los comentarios a la orden, no será necesario indicarlos.

//--- 1. ejemplo de compra con el símbolo actual
   if(!trade.Buy(1))
     {
      //--- comunicamos el fracaso
      Print("El método Buy() ha fracasado. Código de retorno=",trade.ResultRetcode(),
            ". Descripción del código: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("El método Buy() ha sido ejecutado con éxito. Código de retorno=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Por defecto, si no se indica el nombre del instrumento, CTrade utilizará el nombre del símbolo en cuyo gráfico ha sido iniciado. Esto es muy cómodo para las estrategias sencillas. Para un robot que comercia directamente con varios instrumentos, usted necesitará indicar claramente cada vez el símbolo con el que se realizará la operación comercial.

//--- 2. ejemplo de compra con el símbolo indicado
   if(!trade.Buy(1,"Si-6.16"))
     {
      //--- comunicamos el fracaso
      Print("El método Buy() ha fracasado. Código de retorno=",trade.ResultRetcode(),
            ". Descripción del código: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("El método Buy() ha sido ejecutado con éxito. Código de retorno=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Es posible indicar todos los parámetros de la orden: los niveles de Stop Loss/Take Profit, el precio de apertura y los comentarios.

//--- 3. ejemplo de compra con el símbolo indicado, con los SL y TP definidos
   double volume=1;           // indicamos el volumen de la operación comercial
   string symbol="Si-6.16";   // indicacmos el símbolo en el que se realiza la operación
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // cantidad de dígitos tras la coma
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // punto
   double bid=SymbolInfoDouble(symbol,SYMBOL_BID);             // precio actual para el cierre de LONG
   double SL=bid-100*point;                                    // valor no normalizado de SL
   SL=NormalizeDouble(SL,digits);                              // normalizamos el Stop Loss
   double TP=bid+100*point;                                    // valor no normalizado de TP
   TP=NormalizeDouble(TP,digits);                              // normalizamos el Take Profit
//--- obtenemos el precio de apertura actual para la posición LONG
   double open_price=SymbolInfoDouble(symbol,SYMBOL_ASK);
   string comment=StringFormat("Buy %s %G lots at %s, SL=%s TP=%s",
                               symbol,volume,
                               DoubleToString(open_price,digits),
                               DoubleToString(SL,digits),
                               DoubleToString(TP,digits));
   if(!trade.Buy(volume,symbol,open_price,SL,TP,comment))
     {
      //--- comunicamos el fracaso
      Print("El método Buy() ha fracasado. Código de retorno=",trade.ResultRetcode(),
            ". Descripción del código: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("El método Buy() ha sido ejecutado con éxito. Código de retorno=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Recordemos que el Número Mágico y el deslizamiento permisible los hemos establecido durante la inicialización del ejemplar CTrade, por eso no serán necesarios. Aunque también podemos definirlos antes de cada operación comercial, en el caso de que sean necesarios.

Colocar una orden límite

Para enviar una orden límite se usa el método correspondiente de la clase BuyLimit() o SellLimit(). Para la mayoría de los casos, puede bastar con la versión abreviada, cuando se indican solo el precio de apertura y el volumen. El precio de apertura para BuyLimit deberá ser inferior al precio actual, y para SellLimit deberá ser superior. Es decir, estas órdenes se usan para la entrada en el mercado al mejor precio, por ejemplo, en las estrategias con cálculo de retroceso con respecto al nivel de apoyo. Además, se usa el símbolo en el que se haya iniciado el experto.

//--- 1. ejemplo de colocación de una orden pendiente BuyLimit
   string symbol="Si-6.16";                                    // indicamos el símbolo en el que se coloca la orden
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // cantidad de dígitos tras la coma
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // punto
   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);             // precio de compra actual
   double price=ask-100*point;                                 // precio de apertura no normalizado
   price=NormalizeDouble(price,digits);                        // normalizamos el precio de apertura
//--- todo está listo, enviamos al servidor la orden pendiente Buy Limit
   if(!trade.BuyLimit(1,price))
     {
      //--- comunicamos el fracaso
      Print("El método BuyLimit() ha fracasado. Código de retorno=",trade.ResultRetcode(),
            ". Descripción del código: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("El método BuyLimit() se ha ejecutado con éxito. Código de retorno=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Se puede usar una versión más detallada con la indicación de todos los parámetros: los niveles de SL/TP, el tiempo de expiración, el nombre del instrumento y los comentarios a la orden.

//--- 2. ejemplo de colocación de una orden pendiente BuyLimit con todos los parámetros
   double volume=1;
   string symbol="Si-6.16";                                    // indicamos el símbolo en el que se coloca la orden
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // cantidad de dígitos tras la coma
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // punto
   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);             // precio de compra actual
   double price=ask-100*point;                                 // precio de apertura no normalizado
   price=NormalizeDouble(price,digits);                        // normalizamos el precio de apertura
   int SL_pips=100;                                            // Stop Loss en puntos
   int TP_pips=100;                                            // Take Profit en puntos
   double SL=price-SL_pips*point;                              // valor no normalizado de SL
   SL=NormalizeDouble(SL,digits);                              // normalizamos el Stop Loss
   double TP=price+TP_pips*point;                              // valor no normalizado de TP
   TP=NormalizeDouble(TP,digits);                              // normalizamos el Take Profit
   datetime expiration=TimeTradeServer()+PeriodSeconds(PERIOD_D1);
   string comment=StringFormat("Buy Limit %s %G lots at %s, SL=%s TP=%s",
                               symbol,volume,
                               DoubleToString(price,digits),
                               DoubleToString(SL,digits),
                               DoubleToString(TP,digits));
//--- todo está listo, enviamos al servidor la orden pendiente Buy Limit
   if(!trade.BuyLimit(volume,price,symbol,SL,TP,ORDER_TIME_DAY,expiration,comment))
     {
      //--- comunicamos el fracaso
      Print("El método BuyLimit() ha fracasado. Código de retorno=",trade.ResultRetcode(),
            ". Descripción del código: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("El método BuyLimit() se ha ejecutado con éxito. Código de retorno=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

En esta variante es necesario indicar correctamente los niveles de SL y TP. No olvide que para la compra, el nivel de Take Profit debe estar por encima del precio de apertura, y el nivel de Stop Loss, por debajo del precio de apertura. Para las órdenes SellLimit todo es al revés. Usted podrá saber fácilmente si se ha equivocado al simular con el experto en los datos históricos, la clase CTrade automáticamente mostrará mensajes en estos casos (si usted mismo no ha llamado la función LogLevel).

Colocar una orden stop

Para enviar una orden stop se usan los métodos análogos BuyStop() y SellStop(). El precio de apertura para Buy Stop deberá ser superior al precio actual, y para SellStop, inferior. Las órdenes stop se usan en las estrategias que entran en la ruptura de un cierto nivel de resistencia, así como para la limitación de pérdidas. Variante sencilla:

//--- 1. ejemplo de colocación de una orden pendiente Buy Stop
   string symbol="RTS-6.16";    // indicaremos el símbolo en el que se coloca la orden
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // cantidad de dígitos tras la coma
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // punto
   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);             // precio de compra actual
   double price=ask+100*point;                                 // precio de apertura no normalizado
   price=NormalizeDouble(price,digits);                        // normalizamos el precio de apertura
//--- todo está listo, enviamos al servidor la orden pendiente Buy Stop 
   if(!trade.BuyStop(1,price))
     {
      //--- comunicamos el fracaso
      Print("El método BuyStop() ha fracasado. Código de retorno=",trade.ResultRetcode(),
            ". Descripción del código: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("El método BuyStop() ha sido ejecutado con éxito. Código de retorno=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Ahora con más detalle, en el caso en que haya que indicar el máximo de parámetros para una ordenpendiente BuyStop:

//--- 2. ejemplo de colocación de una orden pendiente Buy Stop con todos los parámetros
   double volume=1;
   string symbol="RTS-6.16";    // indicaremos el símbolo en el que se coloca la orden
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // cantidad de dígitos tras la coma
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // punto
   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);             // precio de compra actual
   double price=ask+100*point;                                 // precio de apertura no normalizado
   price=NormalizeDouble(price,digits);                        // normalizamos el precio de apertura
   int SL_pips=100;                                            // Stop Loss en puntos
   int TP_pips=100;                                            // Take Profit en puntos
   double SL=price-SL_pips*point;                              // valor no normalizado de SL
   SL=NormalizeDouble(SL,digits);                              // normalizamos el Stop Loss
   double TP=price+TP_pips*point;                              // valor no normalizado de TP
   TP=NormalizeDouble(TP,digits);                              // normalizamos el Take Profit
   datetime expiration=TimeTradeServer()+PeriodSeconds(PERIOD_D1);
   string comment=StringFormat("Buy Stop %s %G lots at %s, SL=%s TP=%s",
                               symbol,volume,
                               DoubleToString(price,digits),
                               DoubleToString(SL,digits),
                               DoubleToString(TP,digits));
//--- todo está listo, enviamos al servidor la orden pendiente Buy Stop 
   if(!trade.BuyStop(volume,price,symbol,SL,TP,ORDER_TIME_DAY,expiration,comment))
     {
      //--- comunicamos el fracaso
      Print("El método BuyStop() ha fracasado. Código de retorno=",trade.ResultRetcode(),
            ". Descripción del código: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("El método BuyStop() ha sido ejecutado con éxito. Código de retorno=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Para enviar un orden SellStop se aplica el método correspondiente de la clase CTrade, lo más importante es indicar el precio correctamente.

Trabajar con una posición

Usted puede utilizar, en lugar de los métodos Buy() y Sell(), los métodos de apertura de posiciones. Sí es cierto que en este caso deberá indicar más detalles:

//--- número de dígitos tras la coma
   int    digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
//--- valor del punto
   double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
//--- obtenemos el precio de compra
   double price=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
//--- calculamos y normalizamos los niveles de SL y TP
   double SL=NormalizeDouble(price-100*point,digits);
   double TP=NormalizeDouble(price+100*point,digits);
//--- rellenamos los comentarios
   string comment="Buy "+_Symbol+" 1 at "+DoubleToString(price,digits);
//--- todo está listo, intentamos abrir una posición de compra
   if(!trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,1,price,SL,TP,comment))
     {
      //--- comunicamos el fracaso
      Print("El método PositionOpen() ha fracasado. Código de retorno=",trade.ResultRetcode(),
            ". Descripción del código: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("El método PositionOpen() ha sido ejecutado con éxito. Código de retorno=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Para cerrar una posición basta con indicar el nombre del instrumento, el resto lo hará la clase CTrade.

//--- cerramos la posición del símbolo actual
   if(!trade.PositionClose(_Symbol))
     {
      //--- comunicamos el fracaso
      Print("El método PositionClose() ha fracasado. Código de retorno=",trade.ResultRetcode(),
            ". Descripción del código: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("El método PositionClose() ha sido ejecutado con éxito. Código de retorno=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

A una posición abierta se le pueden cambiar los niveles de StopLoss y TakeProfit. Esto se hace con la ayuda del método ModifyPosition().

//--- número de dígitos tras la coma
   int    digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
//--- valor del punto
   double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
//--- obtenemos el precio Bid actual
   double price=SymbolInfoDouble(_Symbol,SYMBOL_BID);
//--- calculamos y normalizamos los niveles de SL y TP
   double SL=NormalizeDouble(price-100*point,digits);
   double TP=NormalizeDouble(price+100*point,digits);
//--- todo está listo, intentamos modificar la posición de compra
   if(!trade.PositionModify(_Symbol,SL,TP))
     {
      //--- comunicamos el fracaso
      Print("El método PositionModify() ha fracasado. Código de retorno=",trade.ResultRetcode(),
            ". Descripción del código: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("El método PositionModify() ha sido ejecutado con éxito. Código de retorno=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Modificación y eliminación de una orden

Para cambiar los parámetros de una orden pendiente en la clase CTrade se ha pensado el método OrderModify(), al que se le deben transmitir todos los parámetros necesarios.

//--- comprobamos si hay una orden  
   if(!OrderSelect(ticket))
     {
      Print("Orden #",ticket," no encontrada");
      return;

     }
//--- símbolo 
   string symbol=OrderGetString(ORDER_SYMBOL);
//--- número de dígitos tras la coma
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
//--- valor del punto
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
//--- obtenemos el precio de apertura
   double price=OrderGetDouble(ORDER_PRICE_OPEN);
//--- calculamos y normalizamos los niveles de SL y TP
   double SL=NormalizeDouble(price-200*point,digits);
   double TP=NormalizeDouble(price+200*point,digits);
//--- todo está listo, intentamos modificar la orden 
   if(!trade.OrderModify(ticket,price,SL,TP,ORDER_TIME_DAY,0))
     {
      //--- comunicamos el fracaso
      Print("El método OrderModify() ha fracasado. Código de retorno=",trade.ResultRetcode(),
            ". Descripción del código: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("El método OrderModify() ha sido ejecutado con éxito. Código de retorno=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

Es imprescindible que obtenga el ticket de la orden a modificar y que, dependiendo de su tipo, indique los niveles correctos de StopLoss y TakeProfit. Además, el nuevo precio de apertura deberá ser igualmente correcto con respecto al precio actual.

Para eliminar una orden pendiente basta con conocer su ticket:

//--- comprobamos si hay una orden  
   if(!OrderSelect(ticket))
     {
      Print("Orden #",ticket," no encontrada");
      return;
     }
//--- todo está listo, intentamos eliminar la orden
   if(!trade.OrderDelete(ticket))
     {
      //--- comunicamos el fracaso
      Print("El método OrderDelete() ha fracasado. Código de retorno=",trade.ResultRetcode(),
            ". Descripción del código: ",trade.ResultRetcodeDescription());
     }
   else
     {
      Print("El método OrderDelete() ha sido ejecutado con éxito. Código de retorno=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     }

En la clase también está el método universal OrderOpen(), que puede colocar órdenes pendientes de cualquier tipo. A diferencia de los métodos especializados BuyLimit, BuyStop, SellLimit y SellStop, necesita que se indiquen más parámetros obligatorios. Puede ser que a alguien le parezca más cómodo.



Qué más podemos ver en las clases comerciales

En este artículo hemos mostrado métodos sencillos para programar operaciones comerciales de compra y venta, así como el trabajo con órdenes pendientes. Pero en el apartado Clases comerciales hay también otros cómodos ayudantes para los desarrolladores de robots en MQL5:

  • COrderInfo — para trabajar con órdenes;
  • CHistoryOrderInfo — para trabajar con las órdenes procesadas que han entrado en la historia comercial;
  • CPositionInfo — para trabajar con las posiciones;
  • CDealInfo — para trabajar con las operaciones;
  • CTerminalInfo — para obtener información sobre el propio terminal.

Con la ayuda de estas clases usted podrá concentrarse solo en la parte comercial de su estrategia, reduciendo al mínimo todas las cuestiones técnicas. Además, la clase CTrade se puede usar para estudiar los requerimientos comerciales, por ejemplo, para la depuración. Con el tiempo, usted también creará sobre su base sus propias clases, en las que implementará la lógica que necesite del procesamiento de los resultados de la ejecución del requerimiento comercial.

Comience su camino en el trading algorítmico con scripts sencillos

Los métodos propuestos en el artículo sobre el desarrollo de robots comerciales en MQL5 han sido pensados, en primer lugar, para los principiantes, aunque muchos desarrolladores con experiencia podrán encontrar cosas nuevas y útiles en ellos. Empiece ejecutando los scripts de este artículo y comprenderá que crear un robot coercial es bastante más sencillo de lo que piensa.

Para aquellos que hayan decidido ir un poco más allá, les proponemos otros dos artículos sobre este tema:

  1. Principios de formación de precios en el mercado bursátil tomando como ejemplo la sección de derivados de la Bolsa de Moscú
  2. Cómo proteger su asesor experto cuando tradea en la Bolsa de Moscú

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

Archivos adjuntos |
accountinfo.mq5 (4.6 KB)
expert_sample.mq5 (37.09 KB)
limit_sample.mq5 (12.86 KB)
symbolinfo.mq5 (4.91 KB)
Interfaces gráficas V: Control "Lista" (Capítulo 2) Interfaces gráficas V: Control "Lista" (Capítulo 2)
En el primer capítulo de la quinta parte de la serie hemos desarrollado las clases para la creación de los controles como la barra de desplazamiento vertical y horizontal. En este artículo vamos a aplicarlas en la práctica. Esta vez diseñaremos la clase para la creación del control “Lista”, y la barra de desplazamiento vertical será su parte integrante.
¿Cómo copiar señales con la ayuda de un asesor según sus propias normas? ¿Cómo copiar señales con la ayuda de un asesor según sus propias normas?
Al suscribirse a una señal puede darse la situación siguiente: su cuenta comercial tiene un apalancamiento de 1:100, el proveedor tiene un apalancamiento de 1:500 y comercia con un lote mínimo, y sus balances comerciales son prácticamente iguales, además, el coeficiente de copiado es del 10% al 15%. En este artículo hablaremos de cómo aumentar el coeficiente de copiado en ese caso.
Cómo mejorar el simulador de estrategias para optimizar indicadores usando ejemplos de los mercados de tendencia y flat Cómo mejorar el simulador de estrategias para optimizar indicadores usando ejemplos de los mercados de tendencia y flat
Al comerciar con diferentes estrategias a veces se requiere determinar si el mercado se encuentra en tendencia o en flat. Con este objetivo se desarrollan multitud de indicadores. ¿Pero cómo evaluar si el indicador cumple o no con la tarea indicada? ¿Cómo aclarar cuál es el diapasón medio del estado del flat o de la tendencia para definir nuestros stops y objetivos? En este artículo se propone usar para ello el simulador de estrategias, demostrando al mismo tiempo que no solo sirve para la optimización de robots para determinadas necesidades. Como indicador de prueba vamos a usar a nuestro viejo conocido ADX.
Creando un ayudante para el comercio manual Creando un ayudante para el comercio manual
El número de robots comerciales para trabajar en los mercados de divisas está creciendo últimamente como una bola de nieve. En ellos se implementan diferentes conceptos y estrategias, pero nadie ha conseguido hasta el momento crear una muestra perfecta de inteligencia artificial que nunca tenga pérdidas. Por eso, muchos tráders se mantienen fieles al comercio manual. Precisamente para esos especialistas se crean los ayudantes robotizados, los llamados paneles comerciales. Este artículo es otro ejemplo más de la creación de un panel comercial partiendo "desde cero".