English Русский Deutsch 日本語
preview
Características del Wizard MQL5 que debe conocer (Parte 17): Negociación con multidivisas

Características del Wizard MQL5 que debe conocer (Parte 17): Negociación con multidivisas

MetaTrader 5Ejemplos | 12 septiembre 2024, 09:30
65 0
Stephen Njuki
Stephen Njuki

Prólogo

Este artículo continúa la serie sobre cómo el asistente MQL5 es ideal para probar rápidamente y crear prototipos de ideas para los operadores. Para muchas personas que desarrollan asesores expertos y sistemas de negociación, es importante seguir aprendiendo y estar al día de las tendencias no sólo en el aprendizaje automático, sino también en la gestión de operaciones y riesgos en general. Por lo tanto, dentro de estas series consideramos cómo el IDE MQL5 es útil en este sentido, no sólo ahorrando tiempo, sino también minimizando los errores de codificación.

Tenía la intención de analizar la búsqueda de arquitectura neuronal (NAS, Neural Architecture Search) para este artículo, pero me di cuenta de que hay algunos principios básicos que aún no he cubierto y que vale la pena considerar, siendo el principal de ellos el comercio de múltiples valores en un asesor experto ensamblado por un asistente. Por lo tanto, nos desviaremos del análisis de nuevas configuraciones comerciales y consideraremos algunos de los aspectos básicos de este artículo. NAS se estudiará en el próximo artículo.


Introducción

La negociación multidivisas, a diferencia de la negociación con una sola divisa, reduce la concentración de riesgos. Dado que cada cuenta tiene un nivel de apalancamiento establecido y, por lo tanto, una cantidad de margen libre definida, cuando se enfrenta a una situación en la que tiene que operar con más de un símbolo, la cantidad de margen libre que debe asignarse tiene que dividirse entre todas las divisas disponibles. Si estas divisas no están correlacionadas o lo están a la inversa, el riesgo de depender en exceso de una sola de ellas puede mitigarse en gran medida.

Además, si se utiliza un sistema de negociación en el que la apertura de posiciones en varias divisas no se realiza en paralelo para minimizar el riesgo, como se ha mencionado, sino que es secuencial, en el que cada par de divisas se considera en un momento distinto, se pueden aprovechar las oportunidades de mercado cruzado. Lo que esto implicaría es abrir posiciones secuenciales o de seguimiento cuyos pares de divisas se correlacionen inversamente con las posiciones ya abiertas si las posiciones abiertas están bajando, o hacer lo contrario si las posiciones ya abiertas tienen una flotación. El emparejamiento de divisas como margen o beneficio en cualquier par hace que este proceso sea especialmente interesante cuando se está seleccionando una oportunidad de mercado cruzado, además de considerar únicamente las correlaciones.

El emparejamiento del margen de beneficio en cada par de divisas también presenta una ventaja de la negociación multidivisas, que es la cobertura. Bordeando el arbitraje, una práctica no sólo mal vista por la mayoría de los corredores, sino también muy difícil de implementar en la práctica, la cobertura con múltiples pares de divisas en función de su margen o divisas de beneficio puede ser contratada con órdenes pendientes, especialmente en situaciones en las que un operador podría estar buscando mantener posiciones durante eventos de alto impacto de noticias o incluso el fin de semana.

Más allá de estas estrategias, el comercio multidivisas permite al trader o al asesor experto observar y aprovechar las tendencias específicas de cada moneda en muchos de los pares negociables en el mercado. Por ejemplo, si una moneda en particular está generando un interés favorable, podrías comprar y mantener varios pares en los que tenga una tasa superior bajo el arbitraje de interés no cubierto , obteniendo ganancias no solo por los cambios en el precio, sino también por el interés acumulado. La capacidad de realizar un análisis en varios pares de divisas y ejecutar operaciones que aprovechen estas configuraciones de cruce de monedas solo es factible si el asesor experto está diseñado para el comercio multidivisas, algo que los asesores expertos ensamblados por asistentes que hemos analizado no son capaces de hacer.

Entonces, para este artículo, nos centraremos en construir plantillas que modifiquen las clases utilizadas en el asistente MQL5 para ensamblar un asesor experto en dos escenarios generales. En primer lugar, buscaremos contar con un asistente experto que simplemente analice y abra posiciones paralelas en varios pares de divisas con el objetivo de mitigar la exposición al riesgo. Este enfoque probablemente requerirá la mayor personalización, ya que modificaremos un archivo importante utilizado en el ensamblaje del asistente. Finalmente, en el segundo enfoque, consideraremos la posibilidad de tener asesores expertos ensamblados por el asistente que tomen en cuenta las correlaciones relativas entre pares de divisas y que puedan abrir posiciones en secuencia basadas en un análisis independiente.


Plantilla para el Asistente MQL5 (Opción-1):

Los asesores expertos ensamblados con el asistente tienen 3 clases principales, cada una en un archivo separado. Se trata de 'ExpertBase', 'ExpertTrade' y 'Expert'. Además de estas 3 clases principales, hay otras 3 clases auxiliares, a saber, 'ExpertSignal', 'ExpertMoney' y 'ExpertTrailing', que se heredan respectivamente al construir las clases de señales del experto, gestión del dinero o trailing. En todas estas clases, es la clase 'ExpertBase' la que define el objeto de la clase símbolo que se utiliza para acceder a la información del mercado del símbolo negociado por defecto ('m_symbol'). Como se mencionó anteriormente, por defecto, todos los asesores expertos ensamblados por el asistente solo negocian un símbolo, por lo que la clase símbolo inicializada dentro de 'ExpertBase' está diseñada para manejar solo un símbolo.

Para hacer esto multisímbolo, una posible solución podría ser convertir esta instancia de clase en un array. Si bien esto es posible, las clases que acceden a esta instancia de clase de símbolos, utilizan muchas funciones para hacerlo y esta conectividad siempre está esperando un array none lo que significa que habría que hacer muchos cambios inviables en el código. Por lo tanto, esta no es una buena solución para convertir los asesores expertos ensamblados por el asistente en sistemas multidivisas.

Un enfoque más factible y similar que consideraremos es convertir la instancia de la clase general 'Expert' en un arreglo cuyo tamaño coincida con el número de símbolos de negociación que estaríamos probando. Una instancia de esta clase siempre se declara en el archivo ‘*.mq5’ del asesor experto ensamblado por el asistente, y simplemente convertir esto en un arreglo esencialmente marca toda la personalización importante que debemos realizar posteriormente.

//+------------------------------------------------------------------+
//| Global expert object                                             |
//+------------------------------------------------------------------+
CExpert ExtExpert[__FOLIO];
CExpertSignal *signals[__FOLIO];

Para convertir la instancia de la clase experta en un array será necesario que hayamos predefinido un array de pares de divisas para operar. Esto es lo que hacemos en el siguiente código:

//+------------------------------------------------------------------+
//| 'Commodity' Currency folio                                       |
//+------------------------------------------------------------------+
#define                          __FOLIO 9
string                           __F[__FOLIO] 

                                 = 
         
                                 {
                                 "AUDNZD","AUDUSD","AUDCAD","AUDJPY",
                                 "NZDUSD","NZDCAD","NZDJPY",
                                 "USDCAD",
                                 "CADJPY"
                                 };
input string                     __prefix="";
input string                     __suffix="";


El código anterior se modifica a una versión personalizada de la clase Experto. Como estamos modificando esta clase, tenemos que guardar una instancia de la misma con un nuevo nombre para mantener la configuración predeterminada de los ensamblajes típicos. El nombre que utilizamos es 'ExpertFolio.mqh' a partir del nombre original 'Expert.mqh'. Además del cambio de nombre y del código modificado en la cabecera, también tenemos que cambiar el listado de la función 'Init' para que se adapte mejor a los símbolos que no coinciden con el símbolo del gráfico al que está vinculado el experto. Esto es lo que hacemos en el siguiente código:

//+------------------------------------------------------------------+
//| Initialization and checking for input parameters                 |
//+------------------------------------------------------------------+
bool CExpert::Init(string symbol,ENUM_TIMEFRAMES period,bool every_tick,ulong magic)
  {
//--- returns false if the EA is initialized on a timeframe different from the current one
   if(period!=::Period())
     {
      PrintFormat(__FUNCTION__+": wrong timeframe (must be: %s)",EnumToString(period));
      return(false);
     }
     
   if(m_on_timer_process && !EventSetTimer(PeriodSeconds(period)))
      {
      PrintFormat(__FUNCTION__+": cannot set timer at: ",EnumToString(period));
      return(false);
      }
//--- initialize common information
   if(m_symbol==NULL)
     {
      if((m_symbol=new CSymbolInfo)==NULL)
         return(false);
     }
   if(!m_symbol.Name(symbol))
      return(false);
   
....
....


//--- ok
   return(true);
  }

Los cambios anteriores se pueden hacer a una réplica del archivo de clase experto que luego vamos a renombrar como se indicó anteriormente, o podemos crear una nueva clase que hereda de la clase experto en 'Expert.mqh' y luego añadir una función 'override' 'Init' en esta nueva clase. Esta nueva clase y el archivo será lo que se hará referencia en el archivo principal de expertos. A continuación, se muestra una lista de esto:

#include "Expert.mqh"
//+------------------------------------------------------------------+
//| Class CExfolio.                                                  |
//| Purpose: Base class expert advisor.                              |
//| Derives from class CExpertBase.                                  |
//+------------------------------------------------------------------+
class CExfolio : public CExpert
  {
protected:

   
public:

                     CExfolio(void);
                    ~CExfolio(void);
                    
   //--- initialization
   virtual bool      Init(string symbol,ENUM_TIMEFRAMES period,bool every_tick,ulong magic=0) override;
   
   //...

  };

Como puede verse en el código anterior, el comando 'override' se ha añadido al final de la declaración de la interfaz, pero como la función 'Init' no es "virtual" por defecto, la función 'Init' de la clase experta original debe modificarse añadiendo este comando. Así que sólo esa línea quedaría así:

//+------------------------------------------------------------------+
//| Initialization and checking for input parameters                 |
//+------------------------------------------------------------------+
bool CExfolio::Init(string symbol,ENUM_TIMEFRAMES period,bool every_tick,ulong magic)
  {
//--- returns false if the EA is initialized on a symbol/timeframe different from the current one
      
      bool _init=true;
      
      if(!CExpert::Init(symbol,period,every_tick,magic))
      {
         _init=false;
         //
         if(symbol!=_Symbol)
         {
            if(Reinit(symbol,period,every_tick,magic)){ _init=true; }
         }
      }
      
      CExpert::OnTimerProcess(true);
      
      if(CExpert::m_on_timer_process && !EventSetTimer(PeriodSeconds(_Period)))
      {
         printf(__FUNCTION__+": cannot set timer at: ",EnumToString(period));
         _init=false;
      }
      
//--- ok
      return(_init);
  }

Los principales cambios aquí garantizan que la inicialización no falle si el símbolo del gráfico no coincide con el símbolo de la cartera. Esta sería sin duda una opción más «ordenada» ya que nuestro archivo de clase creado es considerablemente más pequeño, lo que significa que tenemos menos duplicidad que en el primer caso, sin embargo, tendríamos que modificar el archivo experto incorporado y esto significa que para cada actualización del terminal tendríamos que añadir el especificador de función virtual a la función 'Init'.

Además de estos cambios en la clase experta, el archivo del asesor experto generado por el asistente también deberá tener modificadas cada una de las funciones OnInit, OnTick, OnTimer, OnDeInit y Trade. Lo que se añadiría sería un bucle 'for' que iterase a través de todas las divisas pre-declaradas en la clase experta personalizada. Su declaración está acompañada de parámetros de entrada de prefijo y sufijo que aseguran que sus nombres estén bien formados y aparezcan en la lista de 'Observación del Mercado'. En lugar de nombrar explícitamente los símbolos y gestionar los nombres prefijados/sufijados el enfoque adecuado en el acceso a los símbolos disponibles se pone de relieve aquí, pero incluso entonces usted tendría que tener una lista predefinida de los símbolos que le interesan, con el fin de filtrar adecuadamente la lista a menudo muy larga de los símbolos que disponibles en 'Observación del Mercado'.

Los símbolos seleccionados en la clase experta personalizada son lo que solía denominarse «materias primas», especialmente en la pasada época de la Guerra Fría, ya que su impulso estaba excesivamente influido por el precio de las materias primas. Así, nuestra lista utiliza las divisas AUD, NZD y CAD como principales «materias primas». El USD y el JPY se añaden para exponerse a la volatilidad, pero no formaban parte del grupo de «materias primas».

La clase de señal utilizada para el asesor experto en el Asistente puede ser cualquiera de las clases incorporadas. Esto se debe a que, en la primera implementación, los símbolos se ejecutan en paralelo para minimizar la exposición al riesgo. Las decisiones de negociación de cualquiera no se ven influidas por lo que ocurra con otro símbolo, por lo que los ajustes de la señal seleccionada se aplicarán a todos los símbolos. A partir de las pruebas, esto implica que nuestras ejecuciones de prueba tendrán más posibilidades de obtener buenos resultados en los paseos hacia delante o en la validación cruzada, ya que los distintos símbolos comparten la misma configuración y, por lo tanto, hay menos ajuste de curvas. Utilizamos la clase de señal RSI que requiere relativamente pocos parámetros de entrada, a saber: periodo del indicador y precio aplicado.


Plantilla para el Asistente MQL5 (Opción-2):

Para la segunda implementación de la negociación multidivisas, modificaremos el archivo del asesor experto creado por el asistente añadiéndole una función «Select». Esta función, al basarse en las correlaciones de los símbolos dentro de la cartera de negociación, trata de capitalizar las oportunidades de mercado cruzado, negociando sólo más de un símbolo si existen estas oportunidades. En esencia, se trata de un filtro a partir del planteamiento que hemos considerado en la primera opción anterior.

Para conseguirlo, en primer lugar debemos activar el comercio con temporizador, que sorprendentemente no está activado por defecto. Lo hacemos con una línea en la función 'OnInit', como se indica a continuación:

//
ExtExpert[f].OnTimerProcess(true);

Una vez hecho esto, podemos centrarnos en la función «Select», que consta de dos secciones principales. El primero se ocupa de situaciones en las que no hay posiciones abiertas y es necesario seleccionar una señal de confirmación de correlación entre todos los símbolos comerciales de la cartera. Esta señal está confirmando porque, recuerda, aún dependemos de la señal RSI de la clase de señales como la principal para todos los símbolos. Así, la confirmación en nuestro caso se obtendrá vía Autocorrelación del buffer de precios de cierre para cada uno de los símbolos. Se seleccionará el símbolo con el mayor valor positivo de la cartera.

Utilizamos el mayor valor positivo y no simplemente la magnitud porque nos dirigimos a símbolos con tendencia o al símbolo con la tendencia más fuerte de la cartera. Una vez que tenemos esto, determinamos su dirección de tendencia mirando el cambio de precio del tope de cierre entre el último valor y el último valor. Un cambio positivo sería alcista, mientras que un cambio negativo sería bajista. Esto se procesa en el siguiente listado:

//+------------------------------------------------------------------+
//| Symbol Selector via Correlation                                  |
//+------------------------------------------------------------------+
bool  Select(double Direction, int &Index, ENUM_POSITION_TYPE &Type)
{  if(PositionsTotal() == 0)
   {  double _max = 0.0;
      int _index = -1;
      Type = INVALID_HANDLE;
      for(int f = 0; f < __FOLIO; f++)
      {  vector _v_0, _v_1;
         _v_0.CopyRates(__F[f], Period(), 8, 0, 30);
         _v_1.CopyRates(__F[f], Period(), 8, 30, 30);
         double _corr = _v_0.CorrCoef(_v_1);
         if(_max < _corr && ((Direction > 0.0 && _v_0[0] > _v_0[29]) || (Direction < 0.0 && _v_0[0] < _v_0[29])))
         {  _max = _corr;
            _index = f;
            if(_v_0[0] > _v_0[29])
            {  Type = POSITION_TYPE_BUY;
            }
            else if(_v_0[0] < _v_0[29])
            {  Type = POSITION_TYPE_SELL;
            }
         }
      }
      Index = _index;
      return(true);
   }
   else if(PositionsTotal() == 1)
   {  

//...
//...

   }
   return(false);
}


Así pues, la lista anterior es la parte «por defecto» de la función de selección, y se ocupa de las situaciones en las que todavía no se ha abierto ninguna posición. Una vez abierta una posición, procederíamos a buscar oportunidades de mercado cruzado en función del rendimiento de la posición abierta. Si la posición inicial abierta está en retroceso, entonces examinamos los símbolos restantes de la cartera e intentamos encontrar uno con una correlación «inversa» efectiva. 'Inversa' en el sentido de que sólo nos interesa la magnitud, y seguiremos la tendencia de este símbolo siempre que su magnitud de correlación con el símbolo abierto actual sea la más alta en comparación con la posición ya abierta. El código que se encarga de esto está más abajo:

//+------------------------------------------------------------------+
//| Symbol Selector via Correlation                                  |
//+------------------------------------------------------------------+
bool  Select(double Direction, int &Index, ENUM_POSITION_TYPE &Type)
{  if(PositionsTotal() == 0)
   {  
//...
//...

   }
   else if(PositionsTotal() == 1)
   {  ulong _ticket = PositionGetTicket(0);
      if(PositionSelectByTicket(_ticket))
      {  double _float = PositionGetDouble(POSITION_PROFIT);
         ENUM_POSITION_TYPE _type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
         int _index = ArrayBsearch(__F, PositionGetString(POSITION_SYMBOL));
         double _max = 0.0;
         Type = INVALID_HANDLE;
         for(int f = 0; f < __FOLIO; f++)
         {  if(f == _index)
            {  continue;
            }
            else
            {  vector _v_0, _v_1;
               _v_0.CopyRates(__F[_index], Period(), 8, 0, 30);
               _v_1.CopyRates(__F[f], Period(), 8, 0, 30);
               double _corr = fabs(_v_0.CorrCoef(_v_1));
               if(_float < 0.0 && _max < _corr)
               {  _max = _corr;
                  Index = f;
                  if(_v_1[0] > _v_1[29])
                  {  Type = POSITION_TYPE_BUY;
                  }
                  else  if(_v_1[0] < _v_1[29])
                  {  Type = POSITION_TYPE_SELL;
                  }
               }
            }
         }
      }
      return(true);
   }
   return(false);
}

Para poder utilizar esta función «Select» en el entorno de un asesor experto ensamblado por un Asistente, tenemos que realizar algunos cambios más en la clase de experto. Por eso, crear una instancia duplicada de la clase experta y cambiarle el nombre, por muy aparatoso que parezca, sería más pragmático. El primer cambio que tenemos que hacer es que la función «Refresh» sea accesible públicamente. Esto significa trasladarla de la sección «Protected» de la interfaz de la clase a la parte «Public». Del mismo modo, la función «Process» también debería ser de acceso público. Este cambio aparecería como se indica a continuación:

//+------------------------------------------------------------------+
//| Class CExpert.                                                   |
//| Purpose: Base class expert advisor.                              |
//| Derives from class CExpertBase.                                  |
//+------------------------------------------------------------------+
class CExpert : public CExpertBase
  {
protected:
   
   //...
   //...

public:
                     CExpert(void);
                    ~CExpert(void);
   
   //...

   //--- refreshing 
   virtual bool      Refresh(void);
   //--- processing (main method)
   virtual bool      Processing(void);
   
protected:
   
   //...
   //...

  };


Estas dos funciones clave necesitan ser movidas a público porque tenemos que llamarlas manualmente dentro de nuestro asesor experto alterado. Normalmente, son llamadas internamente por las funciones 'OnTick' u 'OnTimer', dependiendo de cuál de las dos esté activada. Y cuando se les llama, realizan un procesamiento completo de la señal, el seguimiento y la gestión monetaria del símbolo por el que se les llama. En nuestro caso, queremos procesar sólo determinados símbolos en función de a) sus correlaciones relativas, y b) si ya tenemos una posición abierta. Esto exigiría claramente que «tomáramos el mando» de cómo y cuándo se les convoca. Lo haríamos en la función 'OnTimer' como se indica a continuación:

//+------------------------------------------------------------------+
//| "Timer" event handler function                                   |
//+------------------------------------------------------------------+
void OnTimer()
{  for(int f = 0; f < __FOLIO; f++)
   {  ExtExpert[f].Refresh();
   }
   for(int f = 0; f < __FOLIO; f++)
   {  int _index = -1;
      ENUM_POSITION_TYPE _type = INVALID_HANDLE;
      ExtExpert[f].Magic(f);
      if(Select(signals[f].Direction(), _index, _type))
      {  ExtExpert[f].OnTimer();
         ExtExpert[f].Processing();
      }
   }
}


Al seleccionar el símbolo para negociar, lo rastreamos asignándole su índice dentro de la matriz de la cartera de origen como su número mágico. Esto significa que en cada bucle for dentro de todas las funciones de procesamiento por defecto de 'OnTick', 'OnTrade', y 'OnTimer' necesitaríamos actualizar el número mágico utilizado por la clase trade antes de procesar. Además, dado que para esta prueba se utilizaron símbolos personalizados, por razones de calidad de los datos, era necesario incluir el nombre de los símbolos en la matriz de la cartera con su sufijo (o prefijo, en su caso). Por alguna razón, el comprobador de estrategias no puede sincronizar los símbolos personalizados aunque todos los datos estén presentes en el ordenador de prueba si está añadiendo el prefijo y el sufijo al inicializar.

Además, queremos negociar 'OnTimer' no en el valor por defecto 'OnTick' y esto en teoría debería establecerse ajustando fácilmente los parámetros 'OnProcessTimer' y 'OnProcessTick', sin embargo cambiándolos o bien resulta en ninguna negociación o en negociación en tick. Esto ha significado que los cambios más invasivos dentro de la función OnTick y la función OnTimer de la clase de expertos fueron necesarios de tal manera que la función 'OnProcess' fue desactivada dentro de 'OnTick' y la función 'OnProcess' que se hizo pública anteriormente, ahora se llama de forma independiente dentro de la función 'OnTimer' del asesor experto como se muestra en el código 'OnTimer' de arriba. Esto es necesario de nuevo porque por una razón desconocida, en el momento de escribir esto, la función 'Process' dentro de 'OnTimer' en la clase 'ExpertFolio' no se ejecuta. Podemos actualizar los precios y los valores de los indicadores de todos los símbolos, pero la función «Process» debe llamarse de forma independiente. Y también el temporizador necesita ser declarado y matado manualmente como en asesores expertos ordinarios.


Pruebas y optimización

Realizamos ejecuciones de prueba en el cruce de «materias primas» AUDJPY en el marco temporal de 4 horas de 2023 a 2024. Nuestros asesores expertos de prueba no utilizan stop loss porque en la segunda opción, como se ha indicado anteriormente, las posiciones perdedoras se gestionan mediante oportunidades de mercado cruzado. Optimizamos sólo para el período de RSI, ya que es el indicador de clase de señal, y los umbrales de apertura y cierre, la expiración de las órdenes limitadas y la brecha de entrada para las órdenes limitadas. La gestión monetaria utilizada fue para lotes fijos al tamaño mínimo. A continuación se presentan los informes y las curvas de equidad de ambas opciones:

r1

c1


r2

c2

Como puede verse en los informes anteriores, se realizan muchas más operaciones de las que cabría esperar con una configuración de una sola divisa. Resulta interesante la configuración utilizada para realizar estas operaciones múltiples al tiempo que se gestionan las detracciones hasta límites razonables, lo que apunta a una aplicación y un potencial ampliados. Además, como era de esperar, la segunda opción realizó menos operaciones que la primera porque a) no había un filtro secundario para la señal de entrada y b) se utilizan reglas de cruce de mercado (cobertura) en la segunda opción para minimizar los drawdowns y gestionar el riesgo.

Además de las oportunidades de cruce de mercado, también se pueden explorar las oportunidades de arbitraje de interés no cubierto, como se mencionó en la introducción. En este caso, sería necesario extraer datos de noticias económicas del calendario económico de MQL5. Las pruebas de estrategia con estos valores aún son limitadas, pero recientemente se publicó un artículo interesante sobre cómo almacenar datos de noticias económicas en una base de datos mientras se utiliza el IDE de MQL5 aquí. Vale la pena leerlo si este es un camino que te gustaría explorar.


Conclusión

Para concluir, hemos explorado cómo se puede introducir el comercio multidivisas en asesores expertos ensamblados a través del asistente MQL5. Estos se pueden codificar fácilmente sin el asistente; sin embargo, el asistente MQL5 no solo permite el desarrollo rápido de asesores con menos repetición, sino que también permite probar más de una idea simultáneamente a través de un sistema de ponderación. Como siempre, los nuevos lectores pueden consultar las guías aquí y aquí sobre cómo utilizar el asistente.

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

Archivos adjuntos |
ExpertFolio_1.mqh (121.5 KB)
ExpertFolio_2.mqh (121.49 KB)
opt_17_1.mq5 (7.04 KB)
opt_17_2.mq5 (10.18 KB)
Variables y tipos de datos extendidos en MQL5 Variables y tipos de datos extendidos en MQL5
Las variables y los tipos de datos son temas muy importantes no solo en la programación MQL5, sino también en cualquier lenguaje de programación. Las variables y los tipos de datos de MQL5 pueden dividirse en simples y extendidos. Aquí veremos las variables y los tipos de datos extendidos. Ya analizamos los sencillos en un artículo anterior.
Desarrollando un cliente MQTT para MetaTrader 5: metodología TDD (Parte 6) Desarrollando un cliente MQTT para MetaTrader 5: metodología TDD (Parte 6)
Este artículo supone la sexta parte de la serie que describe las etapas de desarrollo de un cliente MQL5 nativo para el protocolo MQTT 5.0. En esta parte, describiremos los principales cambios en nuestra primera refactorización, obteniendo un borrador de trabajo de nuestras clases de construcción de paquetes, creando los paquetes PUBLISH y PUBACK y la semántica de los códigos de motivo PUBACK.
Indicadores personalizados (Parte 1): Guía introductoria paso a paso para desarrollar indicadores personalizados simples en MQL5 Indicadores personalizados (Parte 1): Guía introductoria paso a paso para desarrollar indicadores personalizados simples en MQL5
Aprenda a crear indicadores personalizados utilizando MQL5. Este artículo introductorio le guiará a través de los fundamentos de la construcción de indicadores personalizados simples y demostrar un enfoque práctico para la codificación de diferentes indicadores personalizados para cualquier programador MQL5 nuevo en este interesante tema.
El método de manejo de datos en grupo: implementación del algoritmo combinatorio en MQL5 El método de manejo de datos en grupo: implementación del algoritmo combinatorio en MQL5
En este artículo continuamos nuestra exploración de la familia de algoritmos del método de manejo de datos en grupo, con la implementación del algoritmo combinatorio junto con su encarnación refinada, el algoritmo combinatorio selectivo en MQL5.