English Русский 中文 Deutsch 日本語 Português
preview
Características del Wizard MQL5 que debe conocer (Parte 3): Entropía de Shannon

Características del Wizard MQL5 que debe conocer (Parte 3): Entropía de Shannon

MetaTrader 5Probador | 11 enero 2023, 15:08
473 0
Stephen Njuki
Stephen Njuki

1.0. Introducción

En 1948, Claude Shannon presentó su artículo "Teoría matemática de la comunicación", que planteaba la idea de la entropía de la información. La entropía es un concepto procedente de la física, y es una medida del grado de actividad de las partículas dentro de un objeto. Por ejemplo, si consideramos los tres estados del agua: hielo, líquido y gas, veremos que la energía cinética de la partícula es mayor en estado gaseoso y menor en el hielo. Este concepto se aplica en matemáticas a la probabilidad. Vamos a considerar los tres conjuntos siguientes.

Conjunto 1: 

Conjunto 1


Conjunto 2: 

Conjunto 2


Conjunto 3: 

Conjunto 3


¿Cuál de estos conjuntos posee la entropía más alta? 
Si usted ha elegido la última opción, tendrá razón, pero ¿cómo podemos confirmar que la respuesta es correcta? La forma más simple de responder a esta pregunta es tomar el número de formas de reorganizar cada conjunto como una estimación de la entropía, ignorando las coincidencias de color. Así, para el primer conjunto, solo habrá una manera de "reorganizarlo". No obstante, si observamos los conjuntos después, veremos que el número de permutaciones en relación con el color aumentará significativamente, por lo que podemos afirmar que el último conjunto posee la entropía más alta. 

Hay una forma más precisa de determinar la entropía, y se basa en la información. Si eligiera al azar una bola del primer conjunto antes de tomarla, ¿qué sabría sobre ella? Como solo hay bolas azules en el juego, puede estar seguro de que será una bola azul. Así que podemos decir que tenemos información completa sobre lo que vamos a elegir en el conjunto 1. En el caso de los conjuntos 2 y 3, nuestra información será cada vez menos completa. Así, en matemáticas, la entropía resulta inversamente proporcional a la información. Cuanto mayor sea la entropía, más incógnitas habrá.  

¿Cómo obtenemos la fórmula para calcular la entropía? Si echamos otro vistazo a los conjuntos, veremos que cuanto mayor sea la variedad de tipos de bolas en el conjunto, mayor será la entropía. El factor más sensible para medir la información disponible sobre una bola antes de seleccionarla puede ser la probabilidad de elegir cada bola del conjunto. Así, si debemos considerar cada conjunto como un todo y hallar la probabilidad de seleccionar 8 bolas con cada color elegido tantas veces como aparezca en su conjunto, suponiendo que la elección de cada bola sea un suceso independiente, entonces la probabilidad (y por tanto la "información conocida") de cada conjunto será el producto de las probabilidades individuales de cada bola.  

Conjunto 1: 

(1,0 x 1,0 x 1,0 x 1,0 x 1,0 x 1,0 x 1,0 x 1,0) = 1,0 


Conjunto 2: 

(0,625 x 0,625 x 0,625 x 0,625 x 0,625 x 0,375 x 0,375 x 0,375) ~ 0,0050 


Conjunto 3: 

(0,375 x 0,375 x 0,375 x 0,25 x 0,25 x 0,25 x 0,25 x 0,125) ~ 0,000025 


A medida que aumente el tamaño y la diversidad del conjunto, los valores de probabilidad se volverán demasiado pequeños para trabajar con ellos, por lo que los logaritmos, en particular los logaritmos negativos de estas probabilidades, se tendrán en cuenta a la hora de medir la entropía, ya que esta es inversamente proporcional a la información conocida. Esta ecuación de identidad es la base de la normalización: 


ecuación_1


El logaritmo se multiplica por el negativo porque el logaritmo de los números menores que uno es negativo. La fórmula de la entropía, de acuerdo con la Wikipedia, tiene el aspecto siguiente: 


ecuación_2


que es la suma de los productos de las probabilidades y sus logaritmos. Por consiguiente, para calcular nuestra entropía dada: 


Conjunto 1: 

-(8 x 0,125 x log2(1,0)) = 0,0 


Conjunto 2: 

(-(0,625 x log2(0,625)) - (0,375 x log2(0,375))) ~ 0,9544 


Conjunto 3: 

(- (0,375 x log2(0,375)) - (2 x 0,25 x log2(0,25)) - (0,125 x log2(0,125))) ~ 1,906 


Como se ha demostrado, el número medio de preguntas binarias necesarias para determinar el color de una bola seleccionada al azar de un conjunto es la entropía del conjunto. Además, la entropía máxima para un conjunto de n valores:

ecuación_3

Este valor máximo resultará útil para normalizar los valores de entropía cuando se generen señales entre 0,0 y 1,0. Para el tráder, la entropía de la historia de precios puede servir de precursor para saber si de esa historia puede extraerse una señal comercial fiable. Sin embargo, supongamos que queremos usar la propia entropía para generar señales. Y supongamos que consideramos la idea de que la entropía de las barras bajistas es mayor que la entropía de las barras alcistas en un conjunto fijo de barras recientes, lo cual implica una señal de compra y viceversa. Veamos como esta idea puede ser implementada en el código de una señal para un asesor en el Wizard MQL5.


2.0. Creando la clase

En el presente artículo, usaremos la clase Decision Forest (Árbol de Decisión) de la biblioteca MQL5. Concretamente, nos abstraeremos de la idea de bosques aleatorios al examinar la efectividad de la señal de entropía de Shannon. Nuestro artículo no trata de los bosques aleatorios, sino de la entropía de Shannon. 

Regresemos una vez más a la clase Decision Forest, ya que es la base del modelo de bosque aleatorio. Todos, consciente o inconscientemente, usamos de forma periódica un árbol de decisión, por lo que el concepto en sí no nos resulta extraño.

f_d




Veamos un ejemplo para ilustrar mejor cómo funciona dicho concepto.

Supongamos que nuestro conjunto de datos está formado por barras de precios como las anteriormente mencionadas. Tenemos tres velas bajistas y cinco alcistas (tomaremos los mercados bajistas y alcistas como clases para nuestro experimento) y queremos separar las clases usando sus atributos. Los atributos son la dirección de los precios y las comparaciones de la longitud de la cabeza y la cola, ya que pueden actuar como precursoras de un cambio de dirección. Bien, ¿y cómo podemos hacer esto?

La dirección del precio parece ser un atributo sencillo de separar, ya que el color blanco representa las velas bajistas y el color azul representa las velas alcistas. Así, podemos usar la pregunta "¿Está bajando el precio?" para separar el primer nodo. El nodo del árbol es el punto en el que la rama se divide en dos: la rama del "Sí" y la rama del "No".

Todas las ramas del "No" (velas ascendentes) tienen las colas más largas que las cabezas, pero el panorama resulta distinto en la rama del "Sí", por lo que hay más trabajo por hacer. Al usar el segundo atributo, preguntamos: "¿Es la cabeza más larga que la cola?" para realizar una segunda separación.

Las dos velas descendentes con las cabezas más largas pertenecen a la subrama del Sí, mientras que la vela descendente con la cola más larga pertenece a la subrama de la derecha. Este árbol de decisión pudo usar dos atributos para separar perfectamente los datos según nuestros criterios. 

En los sistemas comerciales reales, podemos utilizar el volumen de ticks, la hora del día y muchos otros indicadores comerciales para construir un árbol de decisión más completo. No obstante, la premisa central de cada pregunta del nodo consiste en encontrar un atributo que divida (o clasifique) los datos anteriores en dos conjuntos no similares, siendo similares los elementos creados de cada conjunto.

Como su nombre indica, los bosques aleatorios están formados por un gran número de árboles de decisión individuales que actúan como un grupo. Para cada árbol del bosque aleatorio, se realiza una predicción de clase, y la clase con el mayor número de votos es seleccionada como predicción del modelo. Es fácil pasar por alto el concepto básico de un bosque aleatorio, pero resulta muy poderoso porque expresa la sabiduría de las masas. Al realizar predicciones, los árboles no correlacionados superan a los árboles individuales, independientemente de la cantidad de datos con los que sean entrenados. La esencia reside en una correlación baja. La razón es que los árboles se protegen mutuamente de los errores individuales según Ton (siempre que no se equivoquen constantemente en la misma dirección). Para que los bosques aleatorios funcionen, la señal de predicción deberá ser mejor que la media, y las predicciones/errores de cada árbol deberán tener una baja correlación entre sí.

Por ejemplo, si tenemos dos sistemas comerciales, y el primero de ellos puede colocar hasta mil órdenes de margen a un dólar al año, mientras que el otro solo puede colocar una orden de margen por 1000 dólares, ¿cuál preferiría, considerando la misma esperanza matemática? La mayoría elegirá el primer sistema porque ofrece "más control" al tráder. 

Entonces, ¿cómo pueden garantizar los algoritmos de bosque aleatorio que la característica de cada árbol individual no esté demasiado correlacionada con la de cualquier otro árbol del bosque? La respuesta a esta pregunta puede reducirse a dos características:

2.0.1. El bagging

Los árboles de decisión son muy sensibles a los datos de entrenamiento, y cualquier pequeño cambio puede provocar cambios significativos en el bosque. Los bosques aleatorios usan esta característica, haciendo que cada árbol muestree aleatoriamente el conjunto de datos al realizar el reemplazo, lo cual da como resultado árboles distintos. Este proceso se conoce como bagging (abreviatura de bootstrap aggregating).

Al realizar el bagging, no sustituimos los datos de entrenamiento por conjuntos más pequeños, sino que tomamos una muestra aleatoria de tamaño N con algunas sustituciones en lugar de los datos de entrenamiento originales. El tamaño inicial del conjunto N se mantiene. Por ejemplo, si nuestros datos de entrenamiento son [U, V, W, X, Y, Z], podemos dar a uno de nuestros árboles la siguiente lista [U, U, V, X, X, Z]. En ambas listas, se mantiene el tamaño N (seis) y "U" y "X" se repiten en los datos aleatoriamente elegidos.


2.0.2. Aleatoriedad de las características (Feature Randomness)

Normalmente, en un árbol de decisión, la división de nodos consiste en analizar todas las características posibles y elegir la que ofrezca la mayor diferencia entre las observaciones del nodo final izquierdo y las del nodo final derecho. En cambio, en un bosque aleatorio, cada árbol solo puede elegir entre un subconjunto aleatorio de características. Esto tiende a provocar una mayor variabilidad dentro del bosque, lo que, a la larga, provoca una menor correlación entre los árboles y una mayor diversificación.

Veamos un ejemplo ilustrativo: en la imagen anterior, el árbol de decisión tradicional (indicado en azul) puede elegir entre las cuatro características a la hora de decidir cómo dividir un nodo. El árbol decide utilizar la Característica 1 (negra y subrayada), ya que divide los datos en grupos separados al máximo.

Ahora vamos a echar un vistazo a nuestro bosque aleatorio. En este ejemplo, solo examinaremos dos árboles del bosque. Cuando comprobamos el Árbol 1, descubrimos que solo puede tener en cuenta las Características 2 y 3 (elegidas al azar) a la hora de decidir dividir los nodos. De nuestro árbol de decisión tradicional (indicado en azul) sabemos que la Característica 1 es el mejor para la separación, pero el Árbol 1 no puede ver la Característica 1, por lo que se ve obligado a utilizar la Característica 2 (en negro y subrayada). El Árbol 2, por su parte, solo puede ver las Características 1 y 3, por lo que puede seleccionar la Característica 1.

Así, en los bosques aleatorios, los árboles no solo aprenden de los conjuntos de datos (gracias al bagging), sino que también utilizan distintas funciones a la hora de tomar decisiones.



s_d



Al utilizar bosques aleatorios, nuestro asesor procesa los resultados de las operaciones y las señales del mercado anteriores para tomar una decisión de compra o venta. Para obtener una señal, en lugar de una simple captura de la entropía, observaremos por separado la entropía de las barras de precio positivas y la entropía de las barras de precio negativas dentro de un conjunto reciente. 

La construcción y el entrenamiento de bosques aleatorios solo tendrán lugar durante la optimización de hilo único.

2.1. Clase de señal del asesor 

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals of'Shannon Entropy'                                |
//| Type=SignalAdvanced                                              |
//| Name=Shannon Entropy                                             |
//| ShortName=SE                                                     |
//| Class=CSignalSE                                                  |
//| Page=signal_se                                                   |
//| Parameter=Reset,bool,false,Reset Training                        |
//| Parameter=Trees,int,50,Trees number                              |
//| Parameter=Regularization,double,0.15,Regularization Threshold    |
//| Parameter=Trainings,int,21,Trainings number                      |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CSignalSE.                                                 |
//| Purpose: Class of generator of trade signals based on            |
//|          the 'Shannon Entropy' signals.                          |
//| Is derived from the CExpertSignal class.                         |
//+------------------------------------------------------------------+
class CSignalSE : public CExpertSignal
   {
      public:
         
         //Decision Forest objects.
         CDecisionForest               DF;                                                   //Decision Forest
         CMatrixDouble                 DF_SIGNAL;                                            //Decision Forest Matrix for inputs and output
         CDFReport                     DF_REPORT;                                            //Decision Forest Report for results
         int                           DF_INFO;                                              //Decision Forest feedback

         double                        m_out_calculations[2], m_in_calculations[__INPUTS];   //Decision Forest calculation arrays

         //--- adjusted parameters
         bool                          m_reset;
         int                           m_trees;
         double                        m_regularization;
         int                           m_trainings;
         //--- methods of setting adjustable parameters
         void                          Reset(bool value){ m_reset=value; }
         void                          Trees(int value){ m_trees=value; }
         void                          Regularization(double value){ m_regularization=value; }
         void                          Trainings(int value){ m_trainings=value; }
         
         //Decision Forest FUZZY system objects
         CMamdaniFuzzySystem           *m_fuzzy;
         
         CFuzzyVariable                *m_in_variables[__INPUTS];
         CFuzzyVariable                *m_out_variable;

         CDictionary_Obj_Double        *m_in_text[__INPUTS];
         CDictionary_Obj_Double        *m_out_text;

         CMamdaniFuzzyRule             *m_rule[__RULES];
         CList                         *m_in_list;

         double                        m_signals[][__INPUTS];
         
         CNormalMembershipFunction     *m_update;
         
         datetime                      m_last_time;
         double                        m_last_signal;
         double                        m_last_condition;

                                       CSignalSE(void);
                                       ~CSignalSE(void);
         //--- method of verification of settings
         virtual bool                  ValidationSettings(void);
         //--- method of creating the indicator and timeseries
         virtual bool                  InitIndicators(CIndicators *indicators);
         //--- methods of checking if the market models are formed
         virtual int                   LongCondition(void);
         virtual int                   ShortCondition(void);

         bool                          m_random;
         bool                          m_read_forest;
         int                           m_samples;

         //--- method of initialization of the oscillator
         bool                          InitSE(CIndicators *indicators);
         
         double                        Data(int Index){ return(Close(StartIndex()+Index)-Close(StartIndex()+Index+1)); }
         
         void                          ReadForest();
         void                          WriteForest();
         
         void                          SignalUpdate(double Signal);
         void                          ResultUpdate(double Result);
         
         double                        Signal(void);
         double                        Result(void);
         
         bool                          IsNewBar(void);
  };

 

2.1.1. Señales

Esta entropía se ponderará usando un índice para determinar la novedad. 

            if(_data>0.0)
            {
               _long_entropy-=((1.0/__SIGNALS[i])*((__SIGNALS[i]-s)/__SIGNALS[i])*(fabs(_data)/_range)*(log10(1.0/__SIGNALS[i])/log10(2.0)));
            }
            else if(_data<0.0)
            {
               _short_entropy-=((1.0/__SIGNALS[i])*((__SIGNALS[i]-s)/__SIGNALS[i])*(fabs(_data)/_range)*(log10(1.0/__SIGNALS[i])/log10(2.0)));
            }

También se ponderará según el tamaño de las barras de precio.

            if(_data>0.0)
            {
               _long_entropy-=((1.0/__SIGNALS[i])*((__SIGNALS[i]-s)/__SIGNALS[i])*(fabs(_data)/_range)*(log10(1.0/__SIGNALS[i])/log10(2.0)));
            }
            else if(_data<0.0)
            {
               _short_entropy-=((1.0/__SIGNALS[i])*((__SIGNALS[i]-s)/__SIGNALS[i])*(fabs(_data)/_range)*(log10(1.0/__SIGNALS[i])/log10(2.0)));
            }

La señal generada será la entropía de barra negativa menos la entropía de barra positiva. El razonamiento aquí es que si la entropía de las barras negativas supera la de las barras positivas, entonces tendremos menos información sobre las barras negativas y, por lo tanto, una posición más corta respecto a las barras positivas, que también implican una posición larga. A primera vista, parece que se trata de un sistema de seguimiento de tendencias "peligroso". Sin embargo, debido a las ponderaciones aplicadas anteriormente al calcular la entropía, esta impresión podría no ser correcta.

Las señales se actualizarán cuando el estado de una posición larga o corta supere el umbral de apertura, ya que esto indicará la apertura de una posición. Esto ocurrirá según un temporizador, por lo que modificaremos el asesor montado por el Wizard para tenerlo en cuenta.

//+------------------------------------------------------------------+
//| "Timer" event handler function                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(PositionSelect(Symbol()) && Signal_ThresholdClose<=fabs(filter0.m_last_condition))
     {
      filter0.ResultUpdate(filter0.Result());
     }
   //
   if(!PositionSelect(Symbol()) && Signal_ThresholdOpen<=fabs(filter0.m_last_condition))
     {
      filter0.SignalUpdate(filter0.m_last_signal);
     }
   ExtExpert.OnTimer();
  }

Como ya hemos mencionado, la función original de la clase solo funcionará cuando esté optimizada.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+  
void CSignalSE::SignalUpdate(double Signal)
   {
      if(MQLInfoInteger(MQL_OPTIMIZATION))
      {
         m_samples++;
         DF_SIGNAL.Resize(m_samples,__INPUTS+2);
         
         for(int i=0;i<__INPUTS;i++)
         {
            DF_SIGNAL[m_samples-1].Set(i,m_signals[0][i]);
         }
         //
         DF_SIGNAL[m_samples-1].Set(__INPUTS,Signal);
         DF_SIGNAL[m_samples-1].Set(__INPUTS+1,1-Signal);    
      }
   }

 

2.1.2. Resultados

Los resultados se basarán en el beneficio de la última posición cerrada,  

      if(HistorySelect(0,m_symbol.Time()))
      {
         int _deals=HistoryDealsTotal();
         
         for(int d=_deals-1;d>=0;d--)
         {
            ulong _deal_ticket=HistoryDealGetTicket(d);
            if(HistoryDealSelect(_deal_ticket))
            {
               if(HistoryDealGetInteger(_deal_ticket,DEAL_ENTRY)==DEAL_ENTRY_OUT)
               {
                  _result=HistoryDealGetDouble(_deal_ticket,DEAL_PROFIT);
                  break;
               }
            }
         }
      }
   
      return(_result);

y se actualizarán cuando el estado de la posición larga o corta supere el umbral de cierre, ya que esto indicará el cierre de la posición. Esto también sucederá según un temporizador. Además, la función de la clase solo actualizará los archivos del bosque de decisión durante la optimización.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+  
void CSignalSE::ResultUpdate(double Result)
   {
      if(MQLInfoInteger(MQL_OPTIMIZATION))
      {
         int _err;
         if(Result<0.0) 
         {
            double _odds = MathRandomUniform(0,1,_err);
            //
            DF_SIGNAL[m_samples-1].Set(__INPUTS,_odds);
            DF_SIGNAL[m_samples-1].Set(__INPUTS+1,1-_odds);
         }
      }
   }


2.1.3. Escritura del bosque

El bosque se registrará en el tick antes de la lectura, por lo que modificaremos el asesor montado por el Wizard para tener esto en cuenta. 

//+------------------------------------------------------------------+
//| "Tick" event handler function                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!signal_se.m_read_forest) signal_se.WriteForest();
   
   ExtExpert.OnTick();
  }


2.1.4. Lectura del bosque

El bosque se registrará en el simulador al final de la ejecución, por lo que modificaremos el asesor montado por el Wizard para tener esto en cuenta. 

//+------------------------------------------------------------------+
//| "Tester" event handler function                                  |
//+------------------------------------------------------------------+  
double OnTester()
   {
    signal_se.ReadForest();
    return(0.0);
   }


2.2. Clase de dinero del asesor

En este artículo, también veremos cómo crear una clase personalizada de cambio de tamaño para utilizarla con el Wizard. Utilizaremos la clase Money Size Optimized y la modificaremos para normalizar el tamaño de la posición según la entropía de Shannon. Nuestra nueva interfaz tendrá el aspecto siguiente: 

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Trading with 'Shannon Entropy' optimized trade volume      |
//| Type=Money                                                       |
//| Name=SE                                                          |
//| Class=CMoneySE                                                   |
//| Page=money_se                                                    |
//| Parameter=ScaleFactor,int,3,Scale factor                         |
//| Parameter=Percent,double,10.0,Percent                            |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CMoneySE.                                                  |
//| Purpose: Class of money management with 'Shannon Entropy' optimized volume.          |
//|              Derives from class CExpertMoney.                    |
//+------------------------------------------------------------------+
class CMoneySE : public CExpertMoney
  {
protected:
   int               m_scale_factor;

public:
   double            m_absolute_condition;
   
                     CMoneySE(void);
                    ~CMoneySE(void);
   //---
   void              ScaleFactor(int scale_factor) { m_scale_factor=scale_factor; }
   void              AbsoluteCondition(double absolute_condition) { m_absolute_condition=absolute_condition; }
   virtual bool      ValidationSettings(void);
   //---
   virtual double    CheckOpenLong(double price,double sl);
   virtual double    CheckOpenShort(double price,double sl);

protected:
   double            Optimize(double lots);
  };

La variable m_absolute_condition es un valor absoluto de números enteros retornado por las funciones LongCondition y ShortCondition. Como se trata de un valor normalizado, podemos usar su tamaño para determinar el tamaño de nuestra posición. Esta variable se transmitirá de la clase de señal a la clase de dinero con la ayuda de las modificaciones del asesor construido por el Wizard.

//+------------------------------------------------------------------+
//| Global expert object                                             |
//+------------------------------------------------------------------+
CExpert ExtExpert;
CSignalSE *signal_se;
CMoneySE *money_se;

Haremos lo mismo en la función de tick:

//+------------------------------------------------------------------+
//| "Tick" event handler function                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!signal_se.m_read_forest) signal_se.WriteForest();
   
   money_se.AbsoluteCondition(fabs(signal_se.m_last_condition));
   
   ExtExpert.OnTick();
  }

Los principales cambios afectarán a la función Optimize: 

//+------------------------------------------------------------------+
//| Optimizing lot size for open.                                    |
//+------------------------------------------------------------------+
double CMoneySE::Optimize(double lots)
  {
   double lot=lots;
   
      //--- normalize lot size based on magnitude of condition
      lot*=(20*m_scale_factor/fmax(20.0,((100.0-m_absolute_condition)/100.0)*20.0*m_scale_factor*m_scale_factor));
      
      //--- reduce lot based on number of losses orders without a break
      if(m_scale_factor>0)
      {
         //--- select history for access
         HistorySelect(0,TimeCurrent());
         //---
         int       orders=HistoryDealsTotal();  // total history deals
         int       losses=0;                    // number of consequent losing orders
         CDealInfo deal;
         //---
         for(int i=orders-1;i>=0;i--)
         {
            deal.Ticket(HistoryDealGetTicket(i));
            if(deal.Ticket()==0)
            {
               Print("CMoneySE::Optimize: HistoryDealGetTicket failed, no trade history");
               break;
            }
            //--- check symbol
            if(deal.Symbol()!=m_symbol.Name())
               continue;
            //--- check profit
            double profit=deal.Profit();
            if(profit>0.0)
               break;
            if(profit<0.0)
               losses++;
         }
         //---
         if(losses>1){
         lot*=m_scale_factor;
         lot/=(losses+m_scale_factor);
         lot=NormalizeDouble(lot,2);}
      }
      //--- normalize and check limits
      double stepvol=m_symbol.LotsStep();
      lot=stepvol*NormalizeDouble(lot/stepvol,0);
      //---
      double minvol=m_symbol.LotsMin();
      if(lot<minvol){ lot=minvol; }
      //---
      double maxvol=m_symbol.LotsMax();
      if(lot>maxvol){ lot=maxvol; }
//---
   return(lot);
  }

 

3.0. Wizard MQL5

Montaremos dos asesores: uno que tendrá solo la clase de señal creada más un volumen mínimo de transacciones para la gestión de dinero, y otro con las clases de señal y la gestión de dinero que hemos creado.


4.0. Simulador de estrategias

La optimización del primer asesor ofrece un factor de beneficio de 2,89 y un ratio de Sharpe de 4,87. Al optimizar el segundo asesor, obtenemos un factor de beneficio de 3,65 y un ratio de Sharpe de 5,79.

 

Primer informe

 

s_r

 

Primera curva de equidad


s_c

 

Segundo informe

 

m_r

 

Segunda curva de equidad

 

m_c


5.0. Conclusión

Los asesores adjuntos han sido optimizados según los precios de apertura del marco temporal de 4 horas para niveles ideales de take profit y stop loss. Esto significa que no podremos reproducir estos resultados en una cuenta real o incluso en el simulador de estrategias en el modo de todos los ticks. Pero ese no es el objetivo del presente artículo. En lugar de intentar dar con un grial que todo el mundo debería reproducir, esta serie de artículos pretende descubrir diferentes ideas que cada tráder pueda adaptar a sus necesidades. Los mercados en general siguen estando demasiado correlacionados, por lo que encontrar una ventaja puede resultarle útil en entornos tan volátiles. ¡Gracias por su atención!

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

Archivos adjuntos |
expert_se.mq5 (7.48 KB)
se.mq5 (7.75 KB)
SignalSE.mqh (24.84 KB)
MoneySE.mqh (6.55 KB)
Gestión de riesgos y capital con ayuda de asesores Gestión de riesgos y capital con ayuda de asesores
Este artículo trata sobre aquello que no encontrará en el informe de simulación, sobre qué esperar al usar un asesor, cómo administrar su dinero usando robots y cómo cubrir una pérdida significativa para seguir comerciando con el trading automatizado.
Aprendiendo a diseñar un sistema de trading con Accelerator Oscillator Aprendiendo a diseñar un sistema de trading con Accelerator Oscillator
Aquí tenemos un nuevo artículo de nuestra serie dedicada a la creación de sistemas comerciales basados en indicadores técnicos populares. Esta vez analizaremos el indicador Accelerator Oscillator: aprenderemos a utilizarlo y a crear sistemas comerciales basados en él.
DoEasy. Elementos de control (Parte 20): El objeto WinForms SplitContainer DoEasy. Elementos de control (Parte 20): El objeto WinForms SplitContainer
Hoy comenzaremos a desarrollar el control SplitContainer del conjunto de elementos de MS Visual Studio. Este elemento constará de dos paneles separados por un divisor móvil vertical u horizontal.
Redes neuronales: así de sencillo (Parte 30): Algoritmos genéticos Redes neuronales: así de sencillo (Parte 30): Algoritmos genéticos
En el artículo de hoy, hablaremos de un método de aprendizaje ligeramente distinto. Podríamos decir que lo hemos tomado de la teoría de la evolución de Darwin. Probablemente resulte menos controlable que los métodos anteriormente mencionados, pero también nos permite entrenar modelos indiferenciados.