English Русский 中文 Deutsch 日本語 Português
Asesor experto multiplataforma: Órdenes

Asesor experto multiplataforma: Órdenes

MetaTrader 5Integración | 8 noviembre 2016, 09:59
2 802 0
Enrico Lambino
Enrico Lambino

Índice


Introducción

MetaTrader 4 y MetaTrader 5 usan reglas diferentes en el procesamiento de solicitudes comerciales. En este artículo se discutirá la posibilidad de usar un objeto de clase para representar las operaciones procesadas por el servidor, para que en lo sucesivo el asesor pueda trabajar con ellas independientemente de la versión de la plataforma comercial y del modo ejecutado.

Condiciones

Existen muchas diferencias en la forma en la que MetaTrader 4 y MetaTrader 5 procesan las solicitudes comerciales desde el terminal. A la hora de juzgar los detalles del procesamiento de las solicitudes por parte de los servidores, deberemos analizar tres modos diferentes de ambas plataformas comerciales: (1) MetaTrader 4, (2) el modo de compensación de MetaTrader 5, y (3) el modo de cobertura en MetaTrader 5.

MetaTrader 4

En MetaTrader 4, cuando el experto envía una orden con éxito, recibe un número de ticket que se convierte en su identificador numérico. Cuando la orden se cierra o modifica, normalmente se usa este mismo ticket hasta que no se produzca la salida del mercado.

Una situación más complicada se da cuando la orden se cierra parcialmente. Esta operación se realiza con la ayuda de la función OrderClose, e indica un tamaño de lote menor que el de la solicitud. Cuando se envía esta solicitud comercial, la orden se cierra en una determinada magnitud de tamaño de lote, indicada en la llamada de la función. Después de esto, el volumen restante del lote permanecerá en el mercado como una nueva orden del mismo tipo que la parcialmente cerrada. Puesto que la función OrderClose solo retorna una variable booleana, no existe otro método rápido de obtener un nuevo ticket, aparte de revisar la lista de órdenes activas en la cuenta en este momento. Preste atención a que no es posible obtener un nuevo ticket usando solo la función OrderClose. La función retorna una variable booleana, mientras que las funciones semejantes a OrderSend en MQL4 retornan un ticket válido después de una transacción con éxito.

MetaTrader 5 (compensación)

El procesamiento de datos comerciales en MetaTrader 5 parece bastante complicado a primera vista, pero es más sencillo de usar que en MetaTrader 4. Bien es cierto que esta afirmación es justa para los tráders, pero no para los programadores.

El modo por defecto en MetaTrader 5 es el de compensación. En este modo, los resultados del procesamiento de la orden están consolidados en el servidor en una posición única. El volumen de este tipo concreto puede cambiar con el paso del tiempo, dependiendo del volumen y los tipos de las órdenes abiertas. Desde el punto de vista del programador, esto es un poco complicado. A diferencia MQL4, donde solo existe el concepto de órdenes, el programador se las verá con tres entidades diferentes usadas en el trading. El recuadro que viene a continuación muestra la comparación entre el modo de compensación en MQL5 y su equivalente aproximado en MQL4:

 Artifact
 MQL5 (Compensación)
MQL4 (Equivalente aproximado)
OrdenSolicitud comercial (pendiente o de mercado)Solicitud comercial (pendiente o de mercado)
 Transacción Transacción (transacciones), ejecutada en base a una orden (de mercado u orden pendiente activada)  Única orden de mercado que se muestra en el terminal comercial
 Posición Transacciones (unidas) Suma de todas las órdenes de mercado en el terminal comercial (tipos de orden aplicados)

En MQL5, las órdenes después de la ejecución permanecen inalteradas lado del cliente, mientras que en MQL4, ciertas propiedades de la orden pueden modificarse, incluso cuando ya se encuentra el mercado. Es decir, en el priemer caso, la orden representa simplemente una solicitud comercial enviada al servidor. En el segundo caso, puede ser usada para presentar una solicitud comercial, así como el resultado de dicha solicitud. En este aspecto, en MQL5 el proceso completo se ha complicado para hacerlo menos ambiguo, puesto que existe una diferencia obvia entre solicitud comercial y el resultado comercial. En MQL4 al entrar al mercado y salir del mismo, la orden puede tener diferentes parámetros, al tiempo que en MQL5 se puede realizar un seguimiento de la orden o solicitud comercial cuya ejecución ha llevado a que se efectúe la operación.

Si se ha enviado una solicitud comercial, solo puede tener dos destinos: o bien se procesa, o bien no se procesa. Si el trade no ha sido procesado, esto significa que la operación no ha tenido lugar, dado que el servidor no ha podido procesar la solicitud por algún motivo (normalmente como resultado de errores). Y al contrario, si el trade se procesa, en MQL5 se realiza una transacción entre el cliente y el terminal. En este caso, la orden puede ejecutarse total o parcialmente.

En MetaTrader 4 no existe esta opción: la orden o bien se ejecuta completamente o no se ejecuta en absoluto (fill or kill).

Uno de los defectos esenciales de este modo en MetaTrader 5 reside en que no permite el uso de cobertura. El tipo de posición en este instrumento puede cambiar. Por ejemplo, si tenemos una posición larga con un volumen de 0,1 de lote, introduciendo una orden de compra con un volumen de 1 lote, transformaremos la posición de este instrumento en corta y con un volumen de 0,9 de lote.

MetaTrader 5 (Cobertura)

El modo de cobertura en MetaTrader 5 recuerda al modo usado en MetaTrader 4. En lugar de unir todos los trades procesados en una posición única, el modo de cobertura permite tener más de una posición por símbolo. La posición se genera cada vez que se activa una orden pendiente o se procesa una solicitud comercial de mercado en el servidor comercial.

Artifact
MQL5 (Compensación)
MQL4 (Equivalente aproximado)
OrdenSolicitud comercial (pendiente o de mercado)Solicitud comercial (pendiente o de mercado)
TransaccionesLa transacción (transacciones) se basa en una orden únicaLas órdenes de mercado se muestran en el terminal comercial
PosiciónLos trades (unificados) se basan en una solicitud comercial única.La orden se muestra en el terminal comercial

Para adaptar el asesor multiplataforma a esas diferencias, una de las posibles soluciones será tener un asesor que guarde la información sobre las transacciones individuales colocadas por él en el mercado. Cada vez que se ejecuta una transacción, una copia de la información se guardará en un objeto de la clase COrder. El código que se muestra más abajo muestra la declaración de su clase base:

class COrderBase : public CObject
  {
protected:
   bool              m_closed;
   bool              m_suspend;
   long              m_order_flags;
   int               m_magic;
   double            m_price;
   ulong             m_ticket;
   ENUM_ORDER_TYPE   m_type;
   double            m_volume;
   double            m_volume_initial;
   string            m_symbol;
public:
                     COrderBase(void);
                    ~COrderBase(void);
   //--- getters and setters     
   void              IsClosed(const bool);
   bool              IsClosed(void) const;
   void              IsSuspended(const bool);
   bool              IsSuspended(void) const;
   void              Magic(const int);
   int               Magic(void) const;
   void              Price(const double);
   double            Price(void) const;
   void              OrderType(const ENUM_ORDER_TYPE);
   ENUM_ORDER_TYPE   OrderType(void) const;
   void              Symbol(const string);
   string            Symbol(void) const;
   void              Ticket(const ulong);
   ulong             Ticket(void) const;
   void              Volume(const double);
   double            Volume(void) const;
   void              VolumeInitial(const double);
   double            VolumeInitial(void) const;
   //--- output
   virtual string    OrderTypeToString(void) const;
   //--- static methods
   static bool       IsOrderTypeLong(const ENUM_ORDER_TYPE);
   static bool       IsOrderTypeShort(const ENUM_ORDER_TYPE);
  };

Puesto que el ЕА recuerda sus operaciones, puede trabajar independientemente de los acuerdos comerciales usados en la plataforma en la que ha sido iniciado. Sin embargo, su desventaja consiste en que los ejemplares de esta clase se guardarán solo durante la actividad del asesor. Si el asesor o la propia plataforma deben ser reiniciados, todos los datos guardados se perderán, a no ser que se encuentre un modo de guardar y cargar la información.

Identificador de la operación (ticket)

Otro posible obstáculo a la hora de usar los ejemplares COrder al crear un asesor multiplataforma, puede ser el modo de guardado de los tickets de la orden (o posición). Las diferencias se recogen en el siguiente recuadro:

Operación
 MQL4MQL5 (Compensación)
 MQL5 (Cobertura)
Envío de la ordenTicekt de la nueva orden
Nuevo ticket de la posición (para una recién abierta) o Ticket de una posición existente (para una posición que ya existe).
Ticket de una nueva posición
Cierre parcialTicekt de la nueva orden
El mismo ticket (si hay un resto), en caso contrario, N/A
El mismo ticket

Al enviar una orden, las tres versiones tienen diferentes caminos de representación de la operación abierta. En MQL4, cuando la solicitud comercial tiene éxito, se abrirá una nueva orden. Esta nueva orden se representará en forma de identificador (del ticket de la orden). En el modo de compensación de MQL5, para cada solicitud comercial de entrada en el mercado se representa un ticket. No obstante, el ticket de la orden puede ser el mejor método de representación, no de una operación abierta, sino de la posición resultante en sí misma. El motivo es que, a diferencia de MQL4, el ticket de la orden no puede ser usado directamente en el trabajo posterior con la operación resultante, con la cual el asesor ha entrado en el mercado. Sin embargo, obtener el número del ticket puede resultar útil en los casos en los que hay que obtener la posición formada como resultado de la ejecución de una orden determinada. Lo que es más, cuando existe una posición del mismo tipo, el ticket de la posición seguirá siendo el mismo (a diferencia de MQL4). Por otra parte, en el modo de cobertura de MQL5, cada nueva operación crea una nueva posición (un equivalente tosco del ticket de la orden en MQL4). No obstante, la diferencia con respecto a MQL4 reside en que una solicitud comercial siempre dará como resultado una orden, mientras que en MQL5 (en el modo de cobertura) es posible obtener más de una operación (si la política de ejecución indicada no es SYMBOL_FILLING_FOK).

Existe otro prolema relacionado con el cierre parcial de una orden de mercado (en MQL4) o una posición (en MQL5). Como ya se ha dicho con anterioridad, en MQL4, cuando un ticket no se cierra por completo (OrderLots), el ticket que representa el trade se cierra, y al volumen restante se le designará un nuevo ticket del mismo tipo que el parcialmente cerrado. En MQL5 existe una pequeña diferencia. En el modo de compensación, para cerrar una posición (de forma parcial o total), el trade se da en la dirección opuesta (buy para sell, o sell para buy). En el modo de cobertura, el proceso es más parecido a MQL4 (OrderClose contra PositionClose en CTrade), pero a diferencia de MQL4, el cierre parcial no conlleva ningún cambio en el identificador que la representa.

Uno de los métodos para solucionar este problema es dividir la implementación de la representación de los identificadores de determinadas operaciones en las dos plataformas. Puesto que el ticket de la orden no cambia MetaTrader 5, podemos sencillamente adjudicarle una variable numérica típica. Para la versión de MetaTrader 4 usaremos un ejemplar de la clase CArrayInt para guardar los números de los tickets. Para COrderBase (y por consiguiente, para las versiones de MQL5 COrder), se usará el código siguiente del método Ticket:

COrderBase::Ticket(const ulong value)
  {
   m_ticket=value;
  }

En la versión para MQL4, este método será redefinido con el siguiente código:

COrder::Ticket(const ulong ticket)
  {
   m_ticket_current.InsertSort((int)ticket);   
  }

Estados

Para las órdenes en el asesor multiplataforma son posibles, como mínimo, dos estados:

  • Cerrado

  • Suspenso

Son muy parecidos, pero entre ellos existe una diferencia fundamental. El estado cerrado de la orden demuestra que ya está cerrada, y que el asesor debe archivarla en sus datos internos. Un equivalente tosco de este proceso en MQL4 es el envío de una orden a la historia. El estado suspenso significa solo que el asesor no ha logrado cerrar la orden o una de las órdenes stop relacionadas con él. En este caso, el asesor puede intentar cerrar la orden (y sus stops) de nuevo, hasta que no se cierre por completo.

Volumen

En MQL4 el cálculo del volumen tiene lugar de forma simple. Cada vez que el asesor envía una solicitud comercial, en ella también se incluye el volumen. Por consiguiente, esta solicitud o bien será rechazada, o bien aceptada. Se trata del equivalente de la política de ejecución Fill or Kill (FOK) en MQL5, que constituye el ajuste por defecto para los objetos comerciales (CTrade y CExpertTrade). Obtener la función general nos puede proporcionar precisamente esta política. Y para lograr el procesamiento de volumen conjunto entre MQL4 y MQL5, una de las formas será obtener el volumen del ejemplar COrder en base al volumen de la propia solicitud comercial. Esto significará que en la versión de MQL5 deberemos respetar la política de FOK. Es posible usar también otras políticas de ejecución, pero los resultados se diferenciarán un poco (es decir, el número de ejemplares de COrder en la versión MQL5 en esta prueba del mismo EA puede ser mayor).

Almacén de órdenes

Si el asesor procesa más de un ejemplar de COrder, podríamos necesitar algún método de organización. Una de las clases que puede servirnos de ayuda es el almacén de órdenes, o COrders. La clase se hereda de CArrayObj y guarda dentro de sí los ejemplares COrder. Hace posible guardar y buscar los trades realizados por los asesores de forma cómoda. La principal plantilla para describir la clase se muestra más abajo:

#include <Arrays\ArrayObj.mqh>
#include "OrderBase.mqh"
class CExpertAdvisor;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class COrdersBase : public CArrayObj
  {
public:
                     COrdersBase(void);
                    ~COrdersBase(void);
   virtual bool      NewOrder(const ulong,const string,const int,const ENUM_ORDER_TYPE,const double,const double);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
COrdersBase::COrdersBase(void)
  {
   if(!IsSorted())
      Sort();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
COrdersBase::~COrdersBase(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool COrdersBase::NewOrder(const ulong ticket,const string symbol,const int magic,const ENUM_ORDER_TYPE type,const double volume,const double price)
  {
   COrder *order=new COrder(ticket,symbol,type,volume,price);
   if(CheckPointer(order)==POINTER_DYNAMIC)
      if(InsertSort(GetPointer(order)))
         order.Magic(magic);
   return false;
  }
//+------------------------------------------------------------------+
#ifdef __MQL5__
#include "..\..\MQL5\Order\Orders.mqh"
#else
#include "..\..\MQL4\Order\Orders.mqh"
#endif
//+------------------------------------------------------------------+

Dado que su función principal consiste en guardar los ejemplares de la clase COrder, debe tener métodos para añadir estos ejemplares de la clase indicada. Por defecto, para ello se usa el método Add de la clase CArrayObj. Sin embargo, esta no siempre es ideal, puesto que el ejemplar COrder debe ser instalado. Para ello podríamos tener el método NewOrder, que crearía un nuevo ejemplar de la clase COrder y lo añadiría de forma automática como elemento de la matriz:

bool COrdersBase::NewOrder(const ulong ticket,const string symbol,const int magic,const ENUM_ORDER_TYPE type,const double volume,const double price)
  {
   COrder *order=new COrder(ticket,symbol,type,volume,price);
   if(CheckPointer(order)==POINTER_DYNAMIC)
      if(InsertSort(GetPointer(order)))
         order.Magic(magic);
   return false;
  }

Ahora que ya hemos creado la plantilla principal, podemos añadir a esta clase otros métodos. Uno de los ejemplos es el método OnTick. En este método, la clase-almacén (contenedor) simplemente iterará por los elementos guardados en ella. Otra posibilidad es hacer que la clase COrder contenga también el método OnTick. A continuación, puede ser codificado de tal forma que este método en COrders sea llamado en cada tick.

Ejemplo

Nuestro ejemplo de código intentará abrir una posición larga. Después de que la posición sea introducida en el mercado, la información sobre la transacción se guardará después en el ejemplar COrder. Esto se logra llamadno el método NewOrder de la clase COrders (su tarea es crear un ejemplar de COrder).

Ambas versiones usarán ejemplares del objeto comercial (CExpertTradeX), del objeto de la orden (COrders) y del objeto del símbolo. (CSymbolInfo). En el manejador OnTick del asesor comercial, el objeto intenta entrar en la posición larga, usando el método Buy. La única diferencia entre las dos versiones (MQL4 y MQL5) reside en cómo se va a extraer la información de las operaciones. En la versión MQL5, los detalles se extraen mediante el uso de HistoryOrderSelect y otras funciones relacionadas. El ticket de la orden se obtiene con la ayuda del método ResultOrder del objeto comercial. La implementación de esta versión se muestra más abajo:

ulong retcode=trade.ResultRetcode();
ulong order = trade.ResultOrder();
 if(retcode==TRADE_RETCODE_DONE)
 {
  if(HistoryOrderSelect(order))
  {
   ulong ticket=HistoryOrderGetInteger(order,ORDER_TICKET);
   ulong magic=HistoryOrderGetInteger(order,ORDER_MAGIC);
   string symbol = HistoryOrderGetString(order,ORDER_SYMBOL);
   double volume = HistoryOrderGetDouble(order,ORDER_VOLUME_INITIAL);
   double price=HistoryOrderGetDouble(order,ORDER_PRICE_OPEN);
   ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)HistoryOrderGetInteger(order,ORDER_TYPE);
   orders.NewOrder((int)ticket,symbol,(int)magic,order_type,volume,price);
  }
 }

El objeto comercial en MQL4 tiene menos funciones que en MQL5. Podemos ampliar el objeto comercial para esta versión, o sencillamente iterar todas las órdenes activas en la cuenta para obtener la orden recién abierta:

for(int i=0;i<OrdersTotal();i++)
{
 if(!OrderSelect(i,SELECT_BY_POS))
  continue;
 if(OrderMagicNumber()==12345)
  orders.NewOrder(OrderTicket(),OrderSymbol(),OrderMagicNumber(),(ENUM_ORDER_TYPE)OrderType(),OrderLots(),OrderOpenPrice());
}

El código completo del archivo de encabezamiento principal se muestra abajo:

(test_orders.mqh)

#include <MQLx-Orders\Base\Trade\ExpertTradeXBase.mqh>
#include <MQLx-Orders\Base\Order\OrdersBase.mqh>
CExpertTradeX trade;
COrders orders;
CSymbolInfo symbolinfo;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!symbolinfo.Name(Symbol()))
     {
      Print("failed to initialize symbol");
      return INIT_FAILED;
     }
   trade.SetSymbol(GetPointer(symbolinfo));
   trade.SetExpertMagicNumber(12345);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   if(!symbolinfo.RefreshRates())
   {
      Print("cannot refresh symbol");
      return;
   }   
   if(trade.Buy(1.0,symbolinfo.Ask(),0,0))
     {
#ifdef __MQL5__
      int retcode=trade.ResultRetCode();
      ulong order = trade.ResultOrder();
      if(retcode==TRADE_RETCODE_DONE)
        {
         if(HistoryOrderSelect(order))
           {
            ulong ticket=HistoryOrderGetInteger(order,ORDER_TICKET);;
            ulong magic=HistoryOrderGetInteger(order,ORDER_MAGIC);
            string symbol = HistoryOrderGetString(order,ORDER_SYMBOL);
            double volume = HistoryOrderGetDouble(order,ORDER_VOLUME_INITIAL);
            double price=HistoryOrderGetDouble(order,ORDER_PRICE_OPEN);
            ENUM_ORDER_TYPE order_type=order_type;
            m_orders.NewOrder((int)ticket,symbol,(int)magic,order_type,volume,price);
           }
        }
#else
      for(int i=0;i<OrdersTotal();i++)
        {
         if(!OrderSelect(i,SELECT_BY_POS))
            continue;
         if(OrderMagicNumber()==12345)
            orders.NewOrder(OrderTicket(),OrderSymbol(),OrderMagicNumber(),(ENUM_ORDER_TYPE)OrderType(),OrderLots(),OrderOpenPrice());
        }
#endif
     }
   Sleep(5000);
   ExpertRemove();
  }
//+------------------------------------------------------------------+


El archivo de encabezamiento contiene todo el código necesario. De esta forma, los archivos fuente principales tendrán al menos la directiva del pre-procesador para incluir test_orders.mqh:

(test_orders.mq4 y test_orders.mq5)

#include "test_orders.mqh"

El inicio del asesor en las plataformas dará las siguientes entradas en el registro.

En MetaTrader 4 :

Expert test_orders EURUSD,H1: loaded successfully
test_orders EURUSD,H1: initialized
test_orders EURUSD,H1: open #125001338 buy 1.00 EURUSD at 1.10684 ok
test_orders EURUSD,H1: ExpertRemove function called
test_orders EURUSD,H1: uninit reason 0
Expert test_orders EURUSD,H1: removed

Las capturas de pantalla que siguen más abajo muestran cómo funciona el asesor en la plataforma. Preste atención: dado que el asesor llama la función ExpertRemove, el propio asesor se elimina automáticamente del gráfico al finalizar la ejecución del código (solo la ejecución única del manejador OnTick). 

En MetaTrader 5 se genera un archivo de logs casi idéntico:

Experts    expert test_orders (EURUSD,M1) loaded successfully
Trades    '3681006': instant buy 1.00 EURUSD at 1.10669 (deviation: 10)
Trades    '3681006': accepted instant buy 1.00 EURUSD at 1.10669 (deviation: 10)
Trades    '3681006': deal #75334196 buy 1.00 EURUSD at 1.10669 done (based on order #90114599)
Trades    '3681006': order #90114599 buy 1.00 / 1.00 EURUSD at 1.10669 done in 275 ms
Experts    expert test_orders (EURUSD,M1) removed

A diferencia de MetaTrader 4, las entradas del registro se encuentran en la pestaña "Diario" de la ventana "Terminal" (y no en la pestaña "Expertos").

Asimismo, el asesor imprime el mensaje en la pestaña "Expertos". No obstante, no se trata de mensajes sobre la ejecución de una transacción: solo anuncian que se ha realizado la llamada de la función ExpertRemove.

Extensiones

En nuestra implementación actual faltan algunas funciones que se usan con frecuencia en asesores reales, tales como por ejemplo:

1. Stop-loss y Take-profit iniciales para las operaciones.

2. Modificaciones de los niveles de stop (por ejemplo, ausencia de pérdidas, Trailing-Stop o cualquier método de usario).

3. Almacenado de datos: existen diferencias en la forma en la que las plataformas guardan la información sobre las operaciones y sobre sus niveles stop. Nuestro objeto de clase une métodos de ambas plataformas, pero almacena solo en la memoria. De esta forma, necesitamos un método para hacer el almacenamiento de datos más permanente. Es decir, necesitamos para nuestros asesores un método de guardado y carga de información de las órdenes después del reinicio del terminal, o bien al pasar de un gráfico en el que el asesor multidivisa aún sigue iniciado a otro. Estos métodos serán analizados en los siguientes artículos.

Conclusión

En este artículo hemos analizado uno de los métodos con cuya ayuda el asesor comercial multiplataforma obtiene la posibilidad de guardar los detalles de las operaciones procesadas con éxito por el servidor comercial. Este método se guarda como ejemplar de objeto de clase. Este ejemplar de objeto puede ser usado también por el asesor para continuar el trabajo con la estrategia elegida. Para este objeto de clase ha sido desarrollada una plantilla principal que se puede perfeccionar en lo sucesivo para su uso en estrategias comerciales más complejas.

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/2590

Archivos adjuntos |
Orders.zip (208.87 KB)
Principios de programación en MQL5: Variables globales del terminal  MetaTrader 5 Principios de programación en MQL5: Variables globales del terminal MetaTrader 5
Las variables globales del terminal es un medio imprescindible durante la programación de los Asesores Expertos complejos y seguros. Después de aprender a trabajar con las variables globales, ya no podrá imaginar la creación de los asesores expertos en MQL5 sin usarlas.
Principios de programación en MQL5: Archivos Principios de programación en MQL5: Archivos
Artículo y estudio práctico sobre el trabajo con archivos en MQL5. Lea el artículo, ejecute las sencillas tareas, y al final usted conseguirá no solo conocimientos teóricos, sino también habilidades prácticas para trabajar con archivos en MQL5.
Interfaces gráficas X: Campo de edición del texto, slider de imágenes y controles simples (build 5) Interfaces gráficas X: Campo de edición del texto, slider de imágenes y controles simples (build 5)
En este artículo vamos a analizar los controles nuevos, tales como: «Campo de edición del texto», «Slider de imágenes», así como los controles simples adicionales, «Etiqueta de texto» e «Imagen». La librería sigue desarrollándose, y además de la aparición de controles nuevos, se van mejorando los que ya han sido creados anteriormente.
LifeHack para tráders: Optimización "silenciosa" o Trazando la distribución de trades LifeHack para tráders: Optimización "silenciosa" o Trazando la distribución de trades
Análisis de la historia comercial y la construcción de los gráficos HTML de distribuciónde de los resultados comerciales dependiendo de la hora de entrada en la posición. Los gráficos se representan en tres segmentos, por horas, días y meses.