English Русский Deutsch 日本語 Português
preview
Desarrollamos un Asesor Experto multidivisas (Parte 5): Tamaños de posición variables

Desarrollamos un Asesor Experto multidivisas (Parte 5): Tamaños de posición variables

MetaTrader 5Probador | 27 agosto 2024, 10:25
62 0
Yuriy Bykov
Yuriy Bykov

Introducción

En la parte anterior, añadimos la capacidad de restaurar el estado del EA después de un reinicio. No importa cuál fue la razón - reiniciar el terminal, cambiar el marco de tiempo en el gráfico con el EA, lanzar una versión más reciente del EA - en todos los casos, restaurar el estado permitió que el EA no comenzara a trabajar desde cero y no perdiera las posiciones ya abiertas, sino que continuara manejándolas.

Sin embargo, el tamaño de las posiciones abiertas permaneció invariable para cada instancia de la estrategia durante todo el periodo de prueba. Su tamaño se fijó en el lanzamiento de EA. Si, como resultado del funcionamiento del EA, el saldo de la cuenta de operaciones aumentara, entonces esto permitiría utilizar un tamaño de posición mayor sin aumentar el riesgo. Sería razonable aprovechar esto, así que empecemos a implementar el uso de tamaños de posición variables.


Conceptos

En primer lugar, debemos ponernos de acuerdo sobre los conceptos basados en un objetivo común: lograr una colaboración óptima entre múltiples instancias de estrategias comerciales.

Tamaño fijo de la estrategia (Lote fijo): Un tamaño determinado que se utiliza para calcular los tamaños de todas las posiciones abiertas en una estrategia de negociación. En el caso más sencillo, todas las posiciones abiertas pueden tener un tamaño igual a este valor. Al utilizar cualquier truco para aumentar o reducir el tamaño de la segunda posición abierta y las siguientes de una serie, se puede establecer un tamaño fijo para la primera posición de la serie, y las siguientes se calculan en función de ella y del número de posiciones ya abiertas. No se considera una buena técnica.

Balance normalizado de la estrategia (Balance ajustado): Balance inicial en el cual el retroceso durante todo el período de prueba alcanza, pero no excede, el 10% del balance inicial para el tamaño de estrategia fija seleccionado. ¿Por qué exactamente el 10%? Este número aún no es una reducción muy grande, lo que psicológicamente parece aceptable y resulta más conveniente para cálculos mentales rápidos y aproximados. En general, podemos tomar cualquier valor: 1%, 5% o incluso 50%. No es más que un parámetro de normalización.

Estrategia de negociación normalizada: Estrategia de negociación para la que se ha seleccionado un tamaño de estrategia fijo y un balance de estrategia normalizado. Por lo tanto, al lanzar una estrategia de este tipo en el periodo de prueba seleccionado, deberíamos obtener un valor de reducción máximo de aproximadamente el 10% del saldo normalizado de la estrategia.

Teniendo una estrategia de negociación, podemos convertirla en una estrategia de negociación normalizada realizando las siguientes acciones:

  • Seleccione un tamaño de estrategia fijo, por ejemplo, 0.01.
  • Seleccione el periodo de prueba (fecha de inicio y fin).
  • Inicie la estrategia en el periodo de prueba seleccionado con un saldo inicial elevado y observe el valor de la máxima reducción absoluta por capital.
  • Encuentra el valor del balance normalizado de la estrategia multiplicando el drawdown absoluto máximo del capital por 10.

Veamos el siguiente ejemplo. Supongamos que obtenemos una reducción absoluta máxima de 440 USD para el tamaño de estrategia fijo de 0.01. Si queremos que este valor sea exactamente el 10% del saldo inicial, podemos dividir 440 USD por 0.10 o multiplicar por 10 (que viene a ser lo mismo):

USD 440 / 0.10 = USD 440 * 10 = USD 4400

Establecemos estos dos valores (0.01 y 4400) en los parámetros para crear una instancia de estrategia de negociación y obtenemos una estrategia de negociación normalizada.

Ahora, para una estrategia de negociación normalizada, podemos calcular el tamaño de las posiciones abiertas para cualquier valor de saldo, manteniendo la reducción relativa máxima por renta variable igual al 10%. Para hacer esto, es suficiente con cambiar el tamaño de las posiciones abiertas en proporción a la relación entre el balance total actual (Balance Total) y el balance normalizado (Balance Ajustado).

Lote Actual = Lote Fijo * (Balance Total / Balance Ajustado)

Por ejemplo, para los valores de 0.01 y 4400 utilizados en el ejemplo anterior, con un valor de saldo de 10.000 USD, el tamaño de las posiciones abiertas debe calcularse en función del valor base:

Lote Actual = 0.01 * (10,000 / 4400) = 0.0227

No será posible abrir exactamente este tamaño. Tendremos que redondearlo a 0.02, por lo que la reducción en este caso puede ser ligeramente inferior al 10% en la prueba. Si redondeamos (a 0.03), la reducción puede ser ligeramente superior al 10%. A medida que aumente el saldo, disminuirán los errores de redondeo.

Si hemos introducido el concepto de un tamaño de posición fijo para una estrategia, entonces podemos confiar cualquier opción para gestionar el tamaño de las posiciones de la estrategia a la propia estrategia. Por lo tanto, sólo necesitamos implementar tres opciones posibles para una estrategia de gestión monetaria a nivel del EA que combina varias instancias de estrategias de negociación:

  • Tamaño fijo o la ausencia de una estrategia de gestión monetaria. El tamaño fijo especificado en la estrategia se aplica independientemente del saldo de la cuenta de negociación. La estrategia se utilizará al probar una instancia separada de la estrategia para determinar el saldo normalizado de la estrategia.

  • Tamaño constante para un saldo fijo especificado. Al inicio, el tamaño proporcional al saldo fijo para la estrategia se calcula a partir del saldo normalizado de la estrategia y del tamaño fijo. Este tamaño se utiliza durante todo el periodo de pruebas. Esta estrategia se utilizará para comprobar la uniformidad (linealidad) de la curva de crecimiento de los fondos a lo largo de todo el periodo de prueba, con sujeción a la detracción absoluta máxima establecida.

  • Tamaño variable para el balance actual. Para cada apertura de posición, el tamaño se determina en proporción al saldo actual de la cuenta basándose en el saldo normalizado de la estrategia y el tamaño fijo. La estrategia se utilizará para el trabajo real proporcionando el valor esperado de la máxima detracción relativa.

Pongamos ejemplos del uso de estas tres opciones. Tomemos el EA con una copia de la estrategia, establezcamos un gran saldo inicial de USD 100,000 y comencemos a probar para el período de 2018-2022 con el tamaño fijo de las posiciones abiertas de 0.01 lotes. Obtenemos los siguientes resultados:

Fig. 1. Resultados con el tamaño fijo y el saldo de 100.000 USD


Como podemos ver, durante este periodo de prueba se produjo una reducción máxima absoluta del capital de unos 153 USD, lo que supuso aproximadamente el 0,15% del saldo de la cuenta. Más concretamente, nos resulta más correcto evaluar la reducción relativa con respecto al saldo inicial de la cuenta. Pero como la diferencia entre el saldo inicial y el final es pequeña (en torno al 1% del saldo inicial), una detracción del 0,15% equivaldrá, con buena precisión, al valor absoluto de 150 USD en cualquier momento del periodo de prueba en que se produzca.

Calculemos qué tamaño del saldo inicial puede fijarse para que la reducción máxima absoluta sea del 10% del saldo inicial:

Balance Ajustado = Máximo Drawdown / 10% = 153 / 0.10 = 153 * 10 = 1530 USD

Comprobemos nuestros cálculos:

Fig. 2. Resultados con el tamaño fijo y el balance de 1530 USD.


Podemos ver que la reducción absoluta de la renta variable ascendió al mismo valor de 153 USD, pero la reducción relativa no fue del 10%, sino sólo del 7,2%. Esto es normal, ya que sólo significa que la mayor detracción se produjo cuando el saldo de la cuenta ya había crecido algo desde su valor inicial, y el valor de 153 USD ya era inferior al 10% del saldo actual.

Comprobemos ahora la segunda opción: Un tamaño constante para un saldo fijo dado. Establezca un gran saldo inicial de 100.000 USD, permitiendo utilizar, por ejemplo, sólo la décima parte del mismo, es decir, 10.000 USD. Este es el valor del Balance Actual, que permanece igual durante todo el período de prueba. En estas condiciones, el tamaño de las posiciones abiertas debería ser:

Balance Actual = Balance Total * 0.1 = 10.000

Lote Actual = Lote Fijo * (Balance Actual / Balance Ajustado) = 0,01 * (10.000 / 1530) = 0,0653

Durante el funcionamiento, este valor se redondeará a un múltiplo del paso de cambio de lote. Obtenemos los siguientes resultados:

Fig. 3. Resultados con el tamaño fijo para el saldo fijo de 10.000 USD de los 100.000 USD disponibles


Como puede ver, la reducción absoluta fue de 1016 USD, que con suficiente precisión es el 10% de los 10.000 USD asignados a esta estrategia. Sin embargo, esto supuso sólo el 1% en relación con el saldo total.

Finalmente, veamos la tercera opción: Tamaño variable para el balance actual. Fije el saldo inicial en 10.000 USD y permita que se utilice en su totalidad. Esto es lo que ocurre:


Fig. 4. Resultados con el tamaño variable para el balance actual

Aquí vemos que la reducción absoluta máxima ya supera el 10% del saldo inicial, pero la reducción relativa sigue manteniéndose dentro del 10% aceptable. Hemos obtenido una estrategia de trading normalizada, para la que el valor de Balance Ajustado = 1530, y ahora podemos calcular fácilmente los tamaños de las posiciones abiertas para asegurar un drawdown dado del 10%.


Cálculo del tamaño de la posición

Al considerar las siguientes opciones de gestión monetaria, cabe hacer las siguientes observaciones:

  • Si estamos hablando de una copia de la estrategia, ¿podrían ser útiles las opciones con un lote variable? Parece que no. Sólo tenemos que utilizar la primera opción. Podemos utilizar la segunda y la tercera un par de veces para demostrar el rendimiento, pero luego no las necesitaremos.

  • Si estamos trabajando con un EA que ya combina varias instancias de estrategias de trading, ¿puede ser útil operar con un lote fijo? Parece que no. En este caso, la segunda opción puede sernos útil en la fase de pruebas, y la tercera será la que utilicemos principalmente.

Esto nos permite llegar a la siguiente conclusión: Las órdenes virtuales siempre tienen un tamaño fijo calculado a partir del parámetro tamaño fijo de la estrategia. En las estrategias analizadas aquí, basta con utilizar el lote mínimo como tamaño fijo, que para la mayoría de los instrumentos es igual a 0.01.

Según el flujo de trabajo, resulta que el objeto receptor o los receptores simbólicos deberán recalcularse en la posición real tamaño abierto. Para ello, deberán recibir el valor del saldo normalizado, que garantiza una detracción del 10% de este saldo, de la estrategia, o más exactamente, de una orden virtual.

Pero, ¿y si queremos ofrecer una reducción menor o mayor? Para ello, basta con modificar el tamaño de las posiciones abiertas de una forma u otra en proporción a las veces que queramos modificar la reducción máxima esperada respecto al valor del 10%.

Uno de estos métodos es la introducción explícita de un multiplicador de ponderación, que muestra qué parte de la balanza por cuenta corriente puede utilizar el EA.

Balance Asignado (Balance Actual): Es una parte del balance total de la cuenta asignada a este EA para el trading.

Multiplicador de Balance (Parte del Depósito): Proporción del balance asignado de la estrategia al balance total de la cuenta.

Parte del Depósito = Balance Actual / Balance Total

A continuación, el tamaño de la posición inicial puede calcularse del siguiente modo:

Lote Actual = Lote Fijo * (Balance Actual / Balance Ajustado)

Lote Actual = Lote Fijo * (Parte del Depósito * Balance Total / Balance Ajustado)

Aquí podemos hacer una observación importante, que será muy útil para nuestra aplicación. Si recalculamos el balance normalizado después de crear una instancia de la estrategia, el balance total se utilizará en la ecuación de cálculo del tamaño de la posición en lugar del balance actual de la estrategia.

Balance Ajustado = Balance Ajustado / Parte del Depósito

Lote Actual = Lote Fijo * (Saldo Total / Saldo Fijado)

Realizaremos el recálculo del saldo normalizado una vez al inicializar el EA. No necesitaremos el multiplicador Parte del Depósito después de eso. 


Combinar múltiples estrategias

Las discusiones anteriores se hicieron para el caso de utilizar una instancia de una estrategia en un EA. Pensemos ahora en lo que tenemos que hacer en caso de que queramos tomar varias estrategias estandarizadas y combinarlas en un EA que permita un Drawdown no superior al 10% (u otro valor especificado de antemano) durante todo el periodo de prueba. Por ahora, consideraremos el valor de reducción especificado de exactamente el 10%.

Si nos centramos en el peor caso que puede darse al combinar estrategias, se trata del caso de que todas las instancias de la estrategia alcancen simultáneamente la reducción máxima del 10%. En este caso, tendremos que reducir el tamaño de posición de cada estrategia en proporción al número de instancias. Por ejemplo, si combinamos tres copias de una estrategia, tendremos que reducir tres veces el tamaño de las posiciones. 

Esto puede lograrse reduciendo el saldo asignado a la estrategia un número determinado de veces, o aumentando el saldo normalizado de las estrategias un número determinado de veces. Utilizaremos la segunda opción. 

Si denotamos el número de estrategias en un grupo como Cantidad de Estrategias, entonces la ecuación para recalcular el balance normalizado es la siguiente:

Balance Ajustado = Cantidad de Estrategias * Balance Ajustado

Sin embargo, la probabilidad de que se produzca el peor de los casos se reduce mucho a medida que aumenta el número de instancias de la estrategia, si se seleccionan de forma que sean lo más distintas posible entre sí. En este caso, las detracciones se producen en momentos diferentes, y no simultáneamente. Esto puede verse durante la prueba. A continuación, podemos introducir otro factor de escala (Escala), que será igual a uno por defecto, pero si se desea, se puede hacer mayor para aumentar el tamaño de las posiciones reduciendo el saldo normalizado de las estrategias:

Balance Ajustado = Cantidad de Estrategias * Balance Ajustado

Balance Ajustado = Balance Ajustado / Escala

Gracias a la selección del multiplicador Escala, podemos garantizar de nuevo que un grupo de estrategias proporcione una reducción especificada durante todo el periodo de prueba. En este caso, obtendremos un grupo normalizado de estrategias.

Grupo normalizado de estrategias: Un grupo de estrategias de negociación normalizadas, para las que se ha seleccionado un factor de escala que garantiza una reducción máxima no superior al 10% cuando el grupo trabaja conjuntamente.

Entonces, si hemos hecho varios grupos normalizados de estrategias, todos ellos pueden combinarse de nuevo en un nuevo grupo normalizado según el mismo principio utilizado al combinar estrategias normalizadas. En otras palabras, debemos elegir un multiplicador para el grupo de grupos, de modo que la reducción máxima no supere el 10% cuando todas las estrategias de todos los grupos funcionen simultáneamente. Este proceso de unificación puede continuar a cualquier número de niveles. En este caso, el saldo inicial normalizado de cada estrategia simplemente se multiplicará por el número de estrategias o grupos del grupo en cada nivel de asociación y se dividirá por los factores de escala de cada nivel:

Balance Ajustado = Cantidad de Estrategias1 * Balance Ajustado

Balance Ajustado = Cantidad de Estrategias2 * Balance Ajustado

...

Balance Ajustado = Balance Ajustado / Escala1

Balance Ajustado = Balance Ajustado / Escala2

...

Entonces, la ecuación final para recalcular el saldo normalizado de cada estrategia tendrá este aspecto:

Balance Ajustado = (Cantidad de Estrategias1 * Cantidad de Estrategias1 * ... ) * Balance Ajustado / (Escala1 * Escala2 * ... )

Finalmente, aplica el último multiplicador de escala de Parte del Depósito en la ecuación de cálculo del tamaño de la posición para la posible transformación del grupo normalizado de estrategias, que está en el nivel más alto de la combinación, en un grupo con un drawdown diferente especificado en lugar del 10%.

Lote Actual = Lote Fijo * (Parte del Depósito * Balance Total / Balance Ajustado)

Hay dos nuevas clases de aplicación. La primera clase CVirtualStrategyGroup se encargará de recalcular los saldos normalizados de las estrategias al combinarlas en grupos. La segunda clase CMoney se encargará de calcular los volúmenes reales de apertura basándose en el tamaño fijo de la estrategia, el saldo normalizado y el saldo asignado. 


Grupo de estrategias de negociación

Esta clase se utilizará para crear objetos que representen un grupo de estrategias o un grupo de grupos de estrategias. En ambos casos, al crear un grupo, se aplicará un factor de escala mediante la llamada al método único Scale().

//+------------------------------------------------------------------+
//| Class of trading strategies group(s)                             |
//+------------------------------------------------------------------+
class CVirtualStrategyGroup {
protected:
   void              Scale(double p_scale); // Scale normalized balance 
public:
   CVirtualStrategyGroup(CVirtualStrategy *&p_strategies[],
                         double p_scale = 1);   // Constructor for a group of strategies
   CVirtualStrategyGroup(CVirtualStrategyGroup *&p_groups[],
                         double p_scale = 1);   // Constructor for a group of strategy groups

   CVirtualStrategy      *m_strategies[];       // Array of strategies
   CVirtualStrategyGroup *m_groups[];           // Array of strategy groups
};

Los constructores tomarán como parámetros un factor de escala y una matriz de punteros a estrategias o una matriz de punteros a grupos de estrategias. La matriz resultante se copia en la propiedad correspondiente del objeto creado, y se aplica el método Scale() a cada elemento de la matriz. Tendremos que añadir este método a la clase de estrategia para los objetos de estrategia.

//+------------------------------------------------------------------+
//| Constructor for strategy groups                                  |
//+------------------------------------------------------------------+
CVirtualStrategyGroup::CVirtualStrategyGroup(
   CVirtualStrategy *&p_strategies[],
   double p_scale
) {
   ArrayCopy(m_strategies, p_strategies);
   Scale(p_scale / ArraySize(m_strategies));
}

//+------------------------------------------------------------------+
//| Constructor for a group of strategy groups                       |
//+------------------------------------------------------------------+
CVirtualStrategyGroup::CVirtualStrategyGroup(
   CVirtualStrategyGroup *&p_groups[],
   double p_scale
) {
   ArrayCopy(m_groups, p_groups);
   Scale(p_scale / ArraySize(m_groups));
}

//+------------------------------------------------------------------+
//| Scale normalized balance                                         |
//+------------------------------------------------------------------+
void CVirtualStrategyGroup::Scale(double p_scale) {
   FOREACH(m_groups,     m_groups[i].Scale(p_scale));
   FOREACH(m_strategies, m_strategies[i].Scale(p_scale));
}

Guarda el código en el archivo VirtualStrategyGroup.mqh de la carpeta actual.

Hagamos las adiciones necesarias a la clase de estrategia virtual. Necesitaremos añadir dos nuevas propiedades de clase para almacenar el saldo normalizado de la estrategia y el tamaño fijo. Dado que deben instalarse, ahora se necesita un constructor que antes era innecesario. El método público FittedBalance() simplemente devolverá el valor del balance normalizado de la estrategia, mientras que el método Scale() lo escalará por un multiplicador especificado.

//+------------------------------------------------------------------+
//| Class of a trading strategy with virtual positions               |
//+------------------------------------------------------------------+
class CVirtualStrategy : public CStrategy {
protected:
   ...
   double            m_fittedBalance;  // Strategy normalized balance
   double            m_fixedLot;       // Strategy fixed size
   ...
public:
   CVirtualStrategy(double p_fittedBalance = 0, double p_fixedLot = 0.01); // Constructor
   ...
   double            FittedBalance() {    // Strategy normalized balance
      return m_fittedBalance;
   }

   void              Scale(double p_scale) { // Scale normalized balance
      m_fittedBalance /= p_scale;
   }
};

Guarda este código en el archivo VirtualStrategy.mqh de la carpeta actual.

Además, tenemos que hacer cambios menores en la clase CSimpleVolumesStrategy. Deberíamos implementar un parámetro adicional al constructor para el balance normalizado de la estrategia y eliminar el parámetro para establecer los tamaños de las posiciones virtuales. Ahora será siempre el mismo e igual al lote mínimo de 0.01.

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSimpleVolumesStrategy::CSimpleVolumesStrategy(
   string           p_symbol,
   ENUM_TIMEFRAMES  p_timeframe,
   int              p_signalPeriod,
   double           p_signalDeviation,
   double           p_signaAddlDeviation,
   int              p_openDistance,
   double           p_stopLevel,
   double           p_takeLevel,
   int              p_ordersExpiration,
   int              p_maxCountOfOrders,
   double           p_fittedBalance = 0) :
// Initialization list
   CVirtualStrategy(p_fittedBalance, 0.01),
   m_symbol(p_symbol),
   m_timeframe(p_timeframe),
   m_signalPeriod(p_signalPeriod),
   m_signalDeviation(p_signalDeviation),
   m_signaAddlDeviation(p_signaAddlDeviation),
   m_openDistance(p_openDistance),
   m_stopLevel(p_stopLevel),
   m_takeLevel(p_takeLevel),
   m_ordersExpiration(p_ordersExpiration),
   m_maxCountOfOrders(p_maxCountOfOrders) {
   ...
}

Guarda los cambios en el archivo SimpleVolumesStrategy.mqh de la carpeta actual.

Necesitamos la capacidad de añadir un grupo de estrategias, es decir, las instancias de nuestra nueva clase CVirtualStrategyGroup, al objeto EA. Así que vamos a implementar el método sobrecargado Add() a la clase EA, que hará exactamente eso:

//+------------------------------------------------------------------+
//| Class of the EA handling virtual positions (orders)              |
//+------------------------------------------------------------------+
class CVirtualAdvisor : public CAdvisor {
   ...
public:
   ...
   virtual void      Add(CVirtualStrategyGroup &p_group);  // Method for adding a group of strategies
   ...
};

//+------------------------------------------------------------------+
//| Method for adding a group of strategies                          |
//+------------------------------------------------------------------+
void CVirtualAdvisor::Add(CVirtualStrategyGroup &p_group) {
   FOREACH(p_group.m_groups, {
      CVirtualAdvisor::Add(p_group.m_groups[i]);
      delete p_group.m_groups[i];
   });
   FOREACH(p_group.m_strategies, CAdvisor::Add(p_group.m_strategies[i]));
}

Dado que los grupos de estrategias ya no son necesarios después de ser añadidos al EA, los eliminamos inmediatamente de la zona de memoria dinámica en este método. Guarda los cambios realizados en el archivo VirtualAdvisor.mqh en la carpeta actual.


Clases de gestión monetaria

Esta clase se encargará de determinar el tamaño real de las posiciones virtuales en función de las tres opciones posibles de estrategia de gestión monetaria.

El objeto de clase debe ser único. Así que podemos utilizar el patrón de diseño Singleton para ello, o, como finalmente se implementó, la clase puede contener sólo campos estáticos y métodos accesibles a cualquier objeto.

El método principal de esta clase es el método para determinar el tamaño real para la posición virtual Volume() (orden). Otros dos métodos nos permiten fijar los valores de dos parámetros que determinan qué parte del saldo de la cuenta de negociación participa en la negociación.

//+------------------------------------------------------------------+
//| Basic money management class                                     |
//+------------------------------------------------------------------+
class CMoney {
   static double     s_depoPart;       // Used part of the total balance
   static double     s_fixedBalance;   // Total balance used
public:
   CMoney() = delete;                  // Disable the constructor
   static double     Volume(CVirtualOrder *p_order); // Determine the real size of the virtual position

   static void       DepoPart(double p_depoPart) {
      s_depoPart = p_depoPart;
   }
   static void       FixedBalance(double p_fixedBalance) {
      s_fixedBalance = p_fixedBalance;
   }
};

double CMoney::s_depoPart = 1.0;
double CMoney::s_fixedBalance = 0;

//+------------------------------------------------------------------+
//| Determine the real size of the virtual position                  |
//+------------------------------------------------------------------+
double CMoney::Volume(CVirtualOrder *p_order) {
   // Request the normalized strategy balance for the virtual position  
   double fittedBalance = p_order.FittedBalance();
   
   // If it is 0, then the real volume is equal to the virtual one
   if(fittedBalance == 0.0) {
      return p_order.Volume();
   }
   
   // Otherwise, find the value of the total balance for trading
   double totalBalance = s_fixedBalance > 0 ? s_fixedBalance : AccountInfoDouble(ACCOUNT_BALANCE);
   
   // Return the calculated real volume based on the virtual one
   return p_order.Volume() * totalBalance * s_depoPart / fittedBalance ;
}
//+------------------------------------------------------------------+

Guarda este código en el archivo Money.mqh de la carpeta actual.


Probar EAs

Vamos a hacer cambios en los archivos de EA para la prueba. En el archivo SimpleVolumesExpertSingle.mq5, solo necesitamos eliminar el parámetro del tamaño de la posición de la lista de parámetros del constructor de la estrategia en la función de inicialización del EA.

int OnInit() {
// Create an EA handling virtual positions
   expert = new CVirtualAdvisor(magic_, "SimpleVolumesSingle");

   expert.Add(new CSimpleVolumesStrategy(
                 symbol_, timeframe_,
                 fixedLot_,
                 signalPeriod_, signalDeviation_, signaAddlDeviation_,
                 openDistance_, stopLevel_, takeLevel_, ordersExpiration_,
                 maxCountOfOrders_)
             );       // Add one strategy instance

   return(INIT_SUCCEEDED);
}

Ahora no utilizaremos el EA para buscar nuevas buenas combinaciones de parámetros para instancias de estrategias individuales, ya que utilizaremos las combinaciones encontradas anteriormente. Pero si es necesario, el EA estará listo para una optimización.

Hagamos adiciones más significativas al archivo SimpleVolumesExpert.mq5. Los necesitamos principalmente para demostrar las capacidades de las clases añadidas, por lo que no debemos considerar esto como código final.

En primer lugar, crearemos una enumeración para representar diferentes formas de agrupar instancias de estrategias de negociación:

enum ENUM_VA_GROUP {
   VAG_EURGBP,          // Only EURGBP (3 items)
   VAG_EURUSD,          // Only EURUSD (3 items)
   VAG_GBPUSD,          // Only GBPUSD (3 items)
   VAG_EURGBPUSD_9,     // EUR-GBP-USD (9 items)
   VAG_EURGBPUSD_3_3_3  // EUR-GBP-USD (3+3+3 items)
};

Los tres primeros valores corresponderán a la utilización de tres copias de estrategias comerciales para uno de los símbolos (EURGBP, EURUSD o GBPUSD). El cuarto valor corresponderá al uso de un grupo de las nueve instancias de estrategia. El quinto valor corresponderá al uso de un grupo de tres grupos normalizados, que incluirá tres copias de estrategias de negociación para un símbolo específico.

Ampliemos un poco la lista de parámetros de entrada:

//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
input group "::: Strategy groups"
input ENUM_VA_GROUP group_ = VAG_EURGBP;  // - Strategy group

input group "::: Money management"
input double expectedDrawdown_ = 10;      // - Maximum risk (%)
input double fixedBalance_ = 0;           // - Used deposit (0 - use all) in the account currency
input double scale_ = 1.0;                // - Group scaling multiplier

input group "::: Other parameters"
input ulong  magic_        = 27183;       // - Magic

En la función de inicialización del EA, configure los parámetros de gestión monetaria teniendo en cuenta la normalización de la reducción máxima permitida del 10%, cree nueve copias de estrategias, organícelas de acuerdo con la agrupación seleccionada y añádalas al EA:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
   // Set parameters in the money management class
   CMoney::DepoPart(expectedDrawdown_ / 10.0);
   CMoney::FixedBalance(fixedBalance_);

   // Create an EA handling virtual positions
   expert = new CVirtualAdvisor(magic_, "SimpleVolumes_" + EnumToString(group_));

   // Create and fill the array of all strategy instances
   CVirtualStrategy *strategies[] = {
      new CSimpleVolumesStrategy("EURGBP", PERIOD_H1,  13, 0.3, 1.0, 0, 10500,  465,  1000, 3, 1600),
      new CSimpleVolumesStrategy("EURGBP", PERIOD_H1,  17, 1.7, 0.5, 0, 16500,  220,  1000, 3,  900),
      new CSimpleVolumesStrategy("EURGBP", PERIOD_H1,  51, 0.5, 1.1, 0, 19500,  370, 22000, 3, 1600),

      new CSimpleVolumesStrategy("EURUSD", PERIOD_H1,  24, 0.1, 0.3, 0,  7500, 2400, 24000, 3, 2300),
      new CSimpleVolumesStrategy("EURUSD", PERIOD_H1,  18, 0.2, 0.4, 0, 19500, 1480,  6000, 3, 2000),
      new CSimpleVolumesStrategy("EURUSD", PERIOD_H1, 128, 0.7, 0.3, 0,  3000,  170, 42000, 3, 2200),

      new CSimpleVolumesStrategy("GBPUSD", PERIOD_H1,  80, 1.1, 0.2, 0,  6000, 1190,  1000, 3, 2500),
      new CSimpleVolumesStrategy("GBPUSD", PERIOD_H1, 128, 2.0, 0.9, 0,  2000, 1170,  1000, 3,  900),
      new CSimpleVolumesStrategy("GBPUSD", PERIOD_H1,  13, 1.5, 0.8, 0,  2500, 1375,  1000, 3, 1400),
   };

   // Create arrays of pointers to strategies, one symbol at a time, from the available strategies
   CVirtualStrategy *strategiesEG[] = {strategies[0], strategies[1], strategies[2]};
   CVirtualStrategy *strategiesEU[] = {strategies[3], strategies[4], strategies[5]};
   CVirtualStrategy *strategiesGU[] = {strategies[6], strategies[7], strategies[8]};

   // Create and add selected groups of strategies to the EA
   switch(group_) {
   case VAG_EURGBP: {
      expert.Add(CVirtualStrategyGroup(strategiesEG, scale_));
      FOREACH(strategiesEU, delete strategiesEU[i]);
      FOREACH(strategiesGU, delete strategiesGU[i]);
      break;
   }
   case VAG_EURUSD: {
      expert.Add(CVirtualStrategyGroup(strategiesEU, scale_));
      FOREACH(strategiesEG, delete strategiesEG[i]);
      FOREACH(strategiesGU, delete strategiesGU[i]);
      break;
   }
   case VAG_GBPUSD: {
      expert.Add(CVirtualStrategyGroup(strategiesGU, scale_));
      FOREACH(strategiesEU, delete strategiesEU[i]);
      FOREACH(strategiesEG, delete strategiesEG[i]);
      break;
   }
   case VAG_EURGBPUSD_9: {
      expert.Add(CVirtualStrategyGroup(strategies, scale_));
      break;
   }
   case VAG_EURGBPUSD_3_3_3: {
      // Create a group of three strategy groups
      CVirtualStrategyGroup *groups[] = {
         new CVirtualStrategyGroup(strategiesEG, 1.25),
         new CVirtualStrategyGroup(strategiesEU, 2.24),
         new CVirtualStrategyGroup(strategiesGU, 2.64)
      };

      expert.Add(CVirtualStrategyGroup(groups, scale_));
      break;
   }
   default:
      return(INIT_FAILED);
   }

// Load the previous state if available
   expert.Load();

   return(INIT_SUCCEEDED);
}

Guarda los cambios realizados en el archivo SimpleVolumesExpert.mq5 en la carpeta actual..


Prueba

Vamos a probar el primer grupo - tres copias de la estrategia de trabajo en el símbolo EURGBP. Obtenemos los siguientes resultados:


Fig. 5. Resultados para el EURGBP con tres estrategias, Escala=1


Como podemos ver, cuando se combinaron, la reducción relativa máxima fue del 8% en lugar del 10% para cada instancia individual de la estrategia normalizada. Esto significa que podemos aumentar un poco el tamaño de nuestra posición. Para conseguir una reducción del 10%, fijaremos Escala = 10% / 8% = 1,25.


Fig. 6. Resultados para EURGBP con tres estrategias, Escala=1,25


Ahora la reducción es de aproximadamente el 10%. Realicemos una operación similar para seleccionar un multiplicador de escala para el segundo y el tercer grupo. Obtenemos los siguientes resultados:

Fig. 7. Resultados para EURUSD con tres estrategias, Escala=2,24


Fig. 8. Resultados para GBPUSD con tres estrategias, Escala=2,64


Utilizamos los valores seleccionados de multiplicadores de escala en el código para crear un grupo normalizado de tres grupos normalizados de estrategias:

// Create a group of three strategy groups
CVirtualStrategyGroup *groups[] = {
     new CVirtualStrategyGroup(strategiesEG, 1.25),
     new CVirtualStrategyGroup(strategiesEU, 2.24),
     new CVirtualStrategyGroup(strategiesGU, 2.64)
 };

Ahora vamos a seleccionar un multiplicador de escala para el cuarto grupo. Si combinamos las 9 instancias en un grupo, obtenemos los siguientes resultados:


Fig. 9. Resultados para EURGBP, EURUSD, GBPUSD (9 estrategias en total), Escala=1


Esto nos permite aumentar el factor de escala a 3,3 y mantenernos dentro del 10% de la reducción relativa:


Fig. 10. Resultados para EURGBP, EURUSD y GBPUSD (9 estrategias en total), Escala=3,3


Por último, lo más interesante. Combinemos las mismas 9 estrategias normalizadas, pero de otra manera: normalicemos por separado grupos de tres estrategias para símbolos individuales y luego combinemos los tres grupos normalizados resultantes en un grupo. Obtenemos lo siguiente:


Fig. 11. Resultados para EURGBP, EURUSD y GBPUSD (3 + 3 + 3 estrategias), Escala=1


El saldo final ha resultado ser mayor que el del cuarto grupo con la misma Escala=1, pero la detracción también ha sido mayor: 4,57% en lugar de 3%. Llevemos el quinto grupo a la reducción del 10% y comparemos el resultado final:


Fig. 12. Resultados para EURGBP, EURUSD, GBPUSD (3 + 3 + 3 estrategias), Escala=2.18


Ahora está claro que la quinta opción de agrupación de estrategias da resultados mucho mejores, manteniendo la reducción relativa máxima dentro del 10%. Durante el periodo de prueba seleccionado, el beneficio se duplicó con creces en comparación con la cuarta opción de agrupación.

Por último, veamos la linealidad del crecimiento del saldo para la quinta opción de agrupación. Esto nos permitirá evaluar si hay periodos internos en los que la EA funcione notablemente peor que en otros periodos internos a lo largo del periodo de pruebas. Para hacer esto, establece el valor del parámetro FixedBalance = 10.000, de modo que el EA siempre use solo esta cantidad del balance de la cuenta para calcular los tamaños de las posiciones.



Fig. 13. Resultados para EURGBP, EURUSD, GBPUSD (3 + 3 + 3 estrategias), FixedBalance = 10000, Escala=2.18


En el gráfico de prueba, he marcado con rectángulos verdes los periodos internos, durante los cuales el crecimiento del saldo era próximo a cero. Su duración oscila entre uno y seis meses. Eso significa que hay algo por lo que luchar. La forma más sencilla de hacer frente a estos periodos es una mayor diversificación: Utilizar más instancias de estrategias de negociación que funcionen en diferentes símbolos y plazos.

En términos absolutos, la pérdida máxima de fondos propios fue de 995 USD, es decir, apenas un 10% del saldo de 10.000 USD utilizado para operar. Esto confirma que el sistema de gestión monetaria implantado se comporta correctamente.


Conclusión

Ahora podemos ejecutar nuestro EA en cuentas de trading con diferentes valores de saldo inicial y controlar cómo se distribuirá el saldo para diferentes instancias de estrategias de trading. Algunos recibirán más y abrirán posiciones más grandes. Otros recibirán menos, y el tamaño de sus posiciones será menor. Por lo general, con la ayuda de las pruebas, podemos seleccionar los parámetros que se ajustarán a la reducción máxima permitida preseleccionada.

Cabe señalar que sólo podemos ver si se cumple la reducción mediante pruebas. No podemos garantizar si la adherencia se mantiene cuando el EA se lanza en un periodo no utilizado para la optimización. Puede cambiar tanto hacia arriba como (curiosamente) hacia abajo. Por lo tanto, aquí cada uno debe tomar una decisión independiente sobre cuánto puede confiar y cómo utilizar los resultados obtenidos durante las pruebas.

Seguiré desarrollando el proyecto. Gracias por su lectura.


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

Utilizando redes neuronales en MetaTrader Utilizando redes neuronales en MetaTrader
En el artículo se muestra la aplicación de las redes neuronales en los programas de MQL, usando la biblioteca de libre difusión FANN. Usando como ejemplo una estrategia que utiliza el indicador MACD se ha construido un experto que usa el filtrado con red neuronal de las operaciones. Dicho filtrado ha mejorado las características del sistema comercial.
Puntuación de propensión (Propensity score) en la inferencia causal Puntuación de propensión (Propensity score) en la inferencia causal
Este artículo trata el tema del emparejamiento en la inferencia causal. El emparejamiento se usa para emparejar observaciones similares en un conjunto de datos. Esto es necesario para identificar correctamente los efectos causales, eliminando el sesgo. Hoy explicaremos cómo esto ayuda a crear sistemas comerciales basados en el aprendizaje automático que se vuelven más robustos con nuevos datos en los que no se ha entrenado. El papel principal lo asignaremos a la puntuación de propensión, ampliamente utilizada en la inferencia causal.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Filtrado de estacionalidad y período de tiempo para modelos de Deep Learning ONNX con Python para EA Filtrado de estacionalidad y período de tiempo para modelos de Deep Learning ONNX con Python para EA
¿Podemos beneficiarnos de la estacionalidad al crear modelos para Deep Learning con Python? ¿Ayuda el filtrado de datos para los modelos ONNX a obtener mejores resultados? ¿Qué periodo de tiempo debemos utilizar? Trataremos todo esto a lo largo de este artículo.