English Русский 中文 Deutsch 日本語 Português
preview
Comprobando la informatividad de distintos tipos de medias móviles

Comprobando la informatividad de distintos tipos de medias móviles

MetaTrader 5Probador | 29 enero 2024, 10:56
347 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Introducción

En uno de nuestros artículos anteriores, vimos los tipos más populares de medias móviles (simple, ponderada, exponencial): "Cómo diseñar sistemas basados en medias móviles". Aquí continuaremos con este tema y compararemos los resultados de una media móvil simple con los resultados de otros tipos de medias móviles. Muchos tráders utilizan medias móviles de diferentes tipos según sus preferencias. Así pues, en este artículo analizaremos con detalle los distintos tipos de medias móviles, comprobaremos su eficacia y compararemos los resultados para determinar qué tipo funciona mejor.

Para lograr nuestro objetivo, crearemos una sencilla aplicación para probar las medias móviles en el simulador de estrategias incorporado en MetaTrader 5. Para entender a qué prestar atención al estudiar los resultados de la prueba, le recomiendo mi artículo anterior "Comprensión y uso eficaz del simulador de estrategias MQL5". Podrá encontrar muchas cosas útiles en él.

Abarcaremos los siguientes temas:

Tenga en cuenta que, aunque hemos intentado optimizar los ajustes de cada media móvil para obtener los mejores resultados, tendrá que realizar algunas comprobaciones y pruebas adicionales usted mismo. Este artículo se ha escrito únicamente con fines ilustrativos. Por lo tanto, deberá probar, optimizar y encontrar los mejores ajustes que puedan ofrecerle los mejores resultados. Podría resultar que algunos tipos (o incluso todos) no se adapten a su estilo de negociación. Pero espero que encuentre ideas que le ayuden a mejorar sus operaciones. Pruebe siempre la eficacia de cualquier estrategia comercial antes de utilizarla en una cuenta real.

¡Atención! Toda la información del presente artículo se ofrece «tal cual», únicamente con fines ilustrativos, y no supone ningún tipo de recomendación. El artículo no garantiza ningún resultado en absoluto. Todo lo que ponga en práctica usando este artículo como base, lo hará bajo su propia cuenta y riesgo; el autor no garantiza resultado alguno.

Probando un sistema basado en la media móvil simple (SMA)

En esta parte, compartiremos los resultados de un sistema simple basado únicamente en una media móvil simple. Esta encuentra el cruce entre el precio y la línea media móvil, generando señales de compra y venta. Crearemos un sistema que puede ejecutar automáticamente transacciones basadas en estas señales.

Para realizar operaciones comerciales, realizaremos las siguientes señales:


Señal de compra:

El precio de cierre se encuentra por encima del valor de la media móvil simple.

Asimismo: el precio de cierre anterior será inferior al valor anterior de la media móvil simple.

Señal de venta:

El precio de cierre se encuentra por debajo del valor de la media móvil simple.

Asimismo: el precio de cierre anterior será superior al valor anterior de la media móvil simple.

Podrá obtener más información sobre la media móvil simple y otros tipos de este popular indicador en uno de mis artículos anteriores, "Cómo desarrollar sistemas basados ​​en medias móviles".

A continuación le detallaremos los pasos necesarios para crear este tipo de sistema comercial, que será capaz de ejecutar automáticamente órdenes de compra y venta en base a las señales mencionadas.

A nivel global, añadiremos el archivo Trade al programa para ejecutar órdenes basadas en nuestras señales utilizando el preprocesador #include. En el artículo "Todo lo que necesita saber sobre la estructura de un programa MQL5", encontrará más información sobre el preprocesador.

#include <Trade\Trade.mqh>

Vamos a crear tres entradas personalizadas para la variable double lotSize, la variable ENUM_TIMEFRAMES timeFrame, y la variable integer MAPeriod, que se modificarán según los deseos del usuario, estableciendo valores por defecto para ellas:

input double lotSize = 1;
input ENUM_TIMEFRAMES timeFrame = PERIOD_H1;
input int MAPeriod= 50;

Crearemos dos variables enteras simpleMA y barTotal sin asignación, ya que las definiremos más adelante en la parte OnInit().

int simpleMA;
int barsTotal;

Vamos a implementar el trading como un objeto de la clase CTrade para un acceso rápido a las funciones de trading.

CTrade trade;

En OnInit(), definiremos simpleMA usando la función iMA para retornar el manejador del indicador de media móvil, y sus parámetros:

  • symbol - nombre del símbolo; para el símbolo actual - _Symbol
  • period - marco temporal utilizado. Por defecto será 1 hora
  • ma_period - periodo de la media móvil simple. Por defecto será 50
  • ma_shift - para desplazamiento horizontal, se usará 0 
  • applied_price - tipo de precio; el precio de cierre se utilizará para calcular una media móvil simple.
simpleMA = iMA(_Symbol, timeFrame, MAPeriod, 0, MODE_SMA, PRICE_CLOSE);

Y barsTotal usando la función iBars para retornar el número de barras. Aquí tenemos sus parámetros:

  • symbol - símbolo. Símbolo actual - (_Symbol)
  • timeframe - marco temporal utilizado. Por defecto será 1 hora
   barsTotal=iBars(_Symbol,timeFrame);

En OnTick() crearemos dos arrays: uno para los precios utilizando MqlRates para almacenar la información sobre los precios, los volúmenes y el spread, y otro para la media móvil simple:

   MqlRates priceArray[];
   double mySMAArray[];

Si establecemos el indicador AS_SERIES para estos dos arrays creados utilizando la función ArraySetAsSeries, sus parámetros serán los siguientes:

  • array[] - indicar un array por referencia
  • flag - indicar la dirección de indexación del array
   ArraySetAsSeries(priceArray,true);
   ArraySetAsSeries(mySMAArray,true);

Determinación de los precios Ask y Bid tras crear dos variables double a partir de ellos

   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

Luego obtendremos los datos históricos de MqlRates usando la función CopyRates. Aquí tenemos sus parámetros:

  • symbol_name - nombre del símbolo
  • timeframe - marco temporal
  • start_pos - posición inicial
  • count - número de datos a copiar
  • rates_array[] - array de destino para copiar
int Data=CopyRates(_Symbol,_Period,0,3,priceArray);

Obtendremos los datos del búfer de indicador utilizando la función CopyBuffer. Aquí tenemos sus parámetros:

  • indicator_handle - manejador del indicador, aquí - simpleMA
  • buffer_num - número del búfer indicador, igual a 0
  • start_pos - posición inicial de cálculo, 0 - vela actual
  • count - volumen a copiar, será igual a 3
  • buffer[]: array de destino que necesitamos copiar, es decir, mySMAArray
CopyBuffer(simpleMA,0,0,3,mySMAArray);

Determinaremos el último precio de cierre y el valor de la media móvil simple de la misma vela tras crear las dos variables dobles de estos dos valores.

   double lastClose=(priceArray[1].close);
   double SMAVal = NormalizeDouble(mySMAArray[1],_Digits);

Determinaremos el precio de cierre anterior y el valor de la media móvil simple de la misma vela tras crear las dos variables dobles de estos dos valores

   double prevClose=(priceArray[2].close);
   double prevSMAVal = NormalizeDouble(mySMAArray[2],_Digits);

Crearemos la variable entera bars para compararla con la variable barsTotal creada

int bars=iBars(_Symbol,timeFrame);

Luego verificaremos si hay una nueva barra comprobando el valor de barsTotal, si no es igual a bars.

if(barsTotal != bars)

Si el valor de barsTotal no es igual a bars, necesitaremos actualizar el valor de BarsTotal con el valor de bars.

barsTotal=bars;

Si barsTotal no es igual a bars, también deberemos comprobar las condiciones de nuestra estrategia si el cierre anterior se encuentra por debajo del valor de la media móvil simple de la misma vela y al mismo tiempo el último precio de cierre está por encima de la media móvil simple de la misma vela. Necesitaremos que el programa cierre la posición abierta actual y abra una posición de compra.

      if(prevClose<prevSMAVal && lastClose>SMAVal)
        {
         trade.PositionClose(_Symbol);
         trade.Buy(lotSize,_Symbol,Ask,0,0,NULL);
        }

Si el cierre anterior se encuentra por encima de la media móvil simple de la misma vela y al mismo tiempo el último precio de cierre está por debajo de la media móvil simple de la misma vela. Necesitaremos que el programa cierre la posición abierta actual y abra una posición de venta.

      if(prevClose>prevSMAVal && lastClose<SMAVal)
        {
         trade.PositionClose(_Symbol);
         trade.Sell(lotSize,_Symbol,Bid,0,0,NULL);
        }

A continuación, compilaremos el código y comprobaremos que este se compila sin errores ni advertencias.

Después se mostrará todo el código en un bloque:

//+------------------------------------------------------------------+
//|                                                   SMA_System.mq5 |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
input double lotSize = 1;
input ENUM_TIMEFRAMES timeFrame = PERIOD_H1;
input int MAPeriod= 50;
int simpleMA;
int barsTotal;
CTrade trade;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   simpleMA = iMA(_Symbol, timeFrame, MAPeriod, 0, MODE_SMA, PRICE_CLOSE);
   barsTotal=iBars(_Symbol,timeFrame);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   MqlRates priceArray[];
   double mySMAArray[];
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
   ArraySetAsSeries(priceArray,true);
   ArraySetAsSeries(mySMAArray,true);
   int Data=CopyRates(_Symbol,_Period,0,3,priceArray);
   CopyBuffer(simpleMA,0,0,3,mySMAArray);
   double lastClose=(priceArray[1].close);
   double SMAVal = NormalizeDouble(mySMAArray[1],_Digits);
   double prevClose=(priceArray[2].close);
   double prevSMAVal = NormalizeDouble(mySMAArray[2],_Digits);
   int bars=iBars(_Symbol,timeFrame);
   if(barsTotal != bars)
     {
      barsTotal=bars;
      if(prevClose<prevSMAVal && lastClose>SMAVal)
        {
         trade.PositionClose(_Symbol);
         trade.Buy(lotSize,_Symbol,Ask,0,0,NULL);
        }
      if(prevClose>prevSMAVal && lastClose<SMAVal)
        {
         trade.PositionClose(_Symbol);
         trade.Sell(lotSize,_Symbol,Bid,0,0,NULL);
        }
     }
  }
//+------------------------------------------------------------------+

Vamos a compilar el asesor y ejecutarlo en EURUSD para probar la estrategia con la historia. El periodo de prueba es del 1 de enero al 30 de junio de 2022, al igual que para todos los tipos de medias móviles mencionados. Nuestra configuración para SMA será la siguiente:

  • Tamaño del lote: 1
  • Marco temporal: 1 hora
  • Periodo de MA: 50

Resultados de las pruebas:

Resultados de la SMA

Nos interesarán especialmente las siguientes lecturas:

  • Beneficio neto: 2700.30 (27%)
  • Reducción relativa del balance: 37.07%
  • Reducción relativa de los fondos: 41.76%
  • Factor de beneficio: 1.10
  • Esperanza de beneficio: 12.68
  • Factor de recuperación: 0.45
  • Ratio de Sharpe: 0.57

Media móvil adaptativa (iAMA)

La media móvil adaptativa (iAMA, también KAMA) fue desarrollada por Perry Kaufman: su idea básica consiste en reducir el ruido en los movimientos de los precios. Sigue los movimientos de los precios y se adapta a ellos, independientemente de la volatilidad. Es un indicador de tendencia, por lo que puede utilizarse para identificar tendencias y puntos de viraje.

El indicador se calcula en unos pocos pasos.

Primer paso: Cálculo de AMA o KAMA

paso 1

Segundo paso: Cálculo del coeficiente de suavizado (SC)

paso 2

Tercer paso: cálculo del coeficiente de efectividad (ER)

paso 3

Ahora hemos aprendido a calcular el indicador AMA manualmente, pero esto en realidad no es tan necesario, ya que podemos insertarlo automáticamente en MetaTrader 5 seleccionándolo entre los indicadores ya disponibles y listos para usar. Ha llegado el momento de crear un sistema comercial que ejecute órdenes de compra y venta basándose en el cruce entre el precio de cierre y el indicador AMA. Para nuestra estrategia, usaremos las siguientes señales.

Señal de compra:

El precio de cierre se encuentra por encima de la media móvil adaptativa.

Además: el precio de cierre anterior es inferior al valor anterior de la media móvil adaptativa.

Señal de venta:

El precio de cierre se encuentra por debajo del valor de la media móvil adaptativa.

Además: el precio de cierre anterior es superior al valor anterior de la media móvil adaptativa

A continuación le mostraremos el código completo para crear este tipo de sistema comercial:

//+------------------------------------------------------------------+
//|                                                  iAMA_System.mq5 |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
input double lotSize = 1;
input ENUM_TIMEFRAMES timeFrame = PERIOD_H1;
input int MAPeriod= 50;
input int fastMAPeriod= 5;
input int slowMAPeriod= 100;
int adaptiveMA;
int barsTotal;
CTrade trade;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   adaptiveMA = iAMA(_Symbol, timeFrame, MAPeriod,fastMAPeriod,slowMAPeriod, 0, PRICE_CLOSE);
   barsTotal=iBars(_Symbol,timeFrame);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   MqlRates priceArray[];
   double myAMAArray[];
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
   ArraySetAsSeries(priceArray,true);
   ArraySetAsSeries(myAMAArray,true);
   int Data=CopyRates(_Symbol,timeFrame,0,3,priceArray);
   CopyBuffer(adaptiveMA,0,0,3,myAMAArray);
   double lastClose=(priceArray[1].close);
   double AMAVal = NormalizeDouble(myAMAArray[1],_Digits);
   double prevClose=(priceArray[2].close);
   double prevAMAVal = NormalizeDouble(myAMAArray[2],_Digits);
   int bars=iBars(_Symbol,timeFrame);
   if(barsTotal != bars)
     {
      barsTotal=bars;
      if(lastClose>AMAVal && prevClose<prevAMAVal)
        {
         trade.PositionClose(_Symbol);
         trade.Buy(lotSize,_Symbol,Ask,0,0,NULL);
        }
      if(lastClose<AMAVal && prevClose>prevAMAVal)
        {
         trade.PositionClose(_Symbol);
         trade.Sell(lotSize,_Symbol,Bid,0,0,NULL);
        }
     }
  }
//+------------------------------------------------------------------+

La diferencia en este código reside en el uso de la función iAMA, que retorna el manejador del indicador de media móvil adaptativa. Sus parámetros serán:

  • symbol - nombre del símbolo; para el símbolo actual - _Symbol
  • period - marco temporal utilizado. Por defecto será 1 hora
  • ama_period - periodo de la media móvil adaptativa
  • fast_ma_period - periodo de la media móvil rápida
  • slow_ma_period - periodo de la media móvil lenta
  • ama_shift - utilizar 0 para desplazamiento horizontal
  • applied_price - tipo de precio utilizado para el cálculo; usaremos el precio de cierre

Probaremos el indicador AMA en el mismo periodo para ver sus resultados:

  • Tamaño del lote =1
  • Marco temporal = 1 hora
  • MAperiod = 50
  • MA rápida = 5
  • MA lenta = 100

Resultados:

Resultados de AMA

Nos interesarán especialmente las siguientes lecturas:

  • Beneficio neto: 3638.20 (36.39%)
  • Reducción relativa del balance: 22.48%
  • Reducción relativa de los fondos: 35.53%
  • Factor de beneficio: 1.31
  • Esperanza de beneficio: 35.67
  • Factor de recuperación: 0.65
  • Ratio de Sharpe: 0.86.

Media móvil exponencial doble (iDEMA)

Este tipo de media móvil fue desarrollado por Patrick Malloy. El objetivo principal de este indicador es reducir el retraso de la EMA, pero hacerla más sensible a los movimientos del mercado.

Este indicador se puede usar para identificar los puntos de inflexión de la tendencia o la tendencia mediante la determinación de la posición de los precios en relación con esta media móvil. A continuación le mostraremos los pasos para calcular el indicador:

1. Cálculo de la primera media móvil exponencial (EMA)

EMA one = EMA del n-ésimo periodo del precio.

2. Cálculo de la EMA a partir de la EMA one

EMA two = EMA de EMA one

3. Cálculo de DEMA

DEMA = (2 * EMA one) - EMA two

No tendremos que realizar estos cálculos manualmente. Serán necesarios para una mejor comprensión del indicador, pero este indicador es el mismo que muchos indicadores técnicos en MetaTrader 5. Ahora deberemos crear el mismo sistema comercial que creamos anteriormente, pero utilizando DEMA. Este sistema comercial ejecutará las mismas órdenes de compra y venta basadas en el cruce, pero esta vez será el cruce del precio y el indicador DEMA.

Señal de compra:

El precio de cierre está por encima del valor de la media móvil exponencial doble

Además: el precio de cierre anterior es inferior al valor DEMA anterior

Señal de venta:

El precio de cierre está por debajo del valor DEMA.

Además: el precio de cierre anterior es superior al valor DEMA anterior

A continuación le mostraremos el código completo del sistema comercial con una ligera diferencia en el uso de la función iDEMA para retornar el manejador del indicador de media móvil exponencial doble. Aquí tenemos sus parámetros:

  • symbol - nombre del símbolo; para el símbolo actual será (_Symbol)
  • period - marco temporal utilizado. Por defecto será 1 hora
  • ma_period - periodo de promediación de la media móvil. El valor por defecto será 50
  • ma_shift - especificaremos 0 para el desplazamiento horizontal, ya que no es necesario
  • applied_price - tipo de precio; el precio de cierre se usará para calcular la media móvil

El código se muestra a continuación:

//+------------------------------------------------------------------+
//|                                                 iDEMA_System.mq5 |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
input double lotSize = 1;
input ENUM_TIMEFRAMES timeFrame = PERIOD_H1;
input int MAPeriod= 50;
int DEMA;
int barsTotal;
CTrade trade;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   DEMA = iDEMA(_Symbol, timeFrame, MAPeriod,0, PRICE_CLOSE);
   barsTotal=iBars(_Symbol,timeFrame);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   MqlRates priceArray[];
   double myDEMAArray[];
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
   ArraySetAsSeries(priceArray,true);
   ArraySetAsSeries(myDEMAArray,true);
   int Data=CopyRates(_Symbol,timeFrame,0,3,priceArray);
   CopyBuffer(DEMA,0,0,3,myDEMAArray);
   double lastClose=(priceArray[1].close);
   double DEMAVal = NormalizeDouble(myDEMAArray[1],_Digits);
   double prevClose=(priceArray[2].close);
   double prevDEMAVal = NormalizeDouble(myDEMAArray[2],_Digits);
   int bars=iBars(_Symbol,timeFrame);
   if(barsTotal != bars)
     {
      barsTotal=bars;
      if(lastClose>DEMAVal && prevClose<prevDEMAVal)
        {
         trade.PositionClose(_Symbol);
         trade.Buy(lotSize,_Symbol,Ask,0,0,NULL);
        }
      if(lastClose<DEMAVal && prevClose>prevDEMAVal)
        {
         trade.PositionClose(_Symbol);
         trade.Sell(lotSize,_Symbol,Bid,0,0,NULL);
        }
     }
  }
//+------------------------------------------------------------------+

Tras realizar la compilación, probaremos el código en el mismo periodo que los anteriores. Los ajustes del indicador serán los que siguen:

  • Tamaño del lote = 1
  • Marco temporal = 1 hora
  • Periodo de MA = 50

Tras ejecutar la prueba, obtendremos los siguientes resultados:

Resultados de DEMA

Nos interesarán especialmente las siguientes lecturas:

  • Beneficio neto: - 961,60 (- 9,62%)
  • Reducción relativa del balance: 39.62%
  • Reducción relativa de los fondos: 41.15%
  • Factor de beneficio: 0.97
  • Esperanza de beneficio: - 3,12
  • Factor de recuperación: - 0,18
  • Ratio de Sharpe: - 0,21

Media móvil exponencial triple (iTEMA)

Este tipo de media móvil fue desarrollado por Patrick Malloy para que el indicador resultara más sensible y adecuado para las operaciones a corto plazo. El indicador usa medias móviles exponenciales con suavizado triple, doble y simple. Así, este indicador estará más cerca del precio, lo cual lo hará más sensible. De la misma forma que usábamos una media móvil exponencial doble, podemos aplicar la TEMA, pero su respuesta al precio será incluso más rápida. Además, podrá utilizarse para identificar puntos de tendencia y pivote o cambios de tendencia.

A continuación le mostraremos los pasos para calcular el indicador TEMA:

1. Cálculo de la primera media móvil exponencial (EMA)

EMA one = EMA del n-ésimo periodo del precio.

2. Cálculo de la EMA a partir de la EMA one

EMA two = EMA de EMA one

3. Cálculo de EMA a partir de EMA dos

EMA three = EMA de EMA two

4. Cálculo de TEMA

DEMA = (3 * EMA one) - (3 * EMA two) + (EMA3)

Podemos insertar este indicador a partir de los indicadores técnicos ya hechos disponibles en MetaTrader 5 sin cálculo manual, después de lo cual, deberemos crear nuestro sistema comercial utilizando este indicador TEMA para probarlo y comparar sus resultados con otros tipos. A continuación le mostraremos el código completo para crear este sistema comercial. Resulta similar a los anteriores con la diferencia de que la función iTEMA se utiliza para retornar el manejador del indicador Triple Exponential Moving Average, pero sus parámetros son iguales a los mencionados en DEMA y SMA.

//+------------------------------------------------------------------+
//|                                                 iTEMA_System.mq5 |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
input double lotSize = 1;
input ENUM_TIMEFRAMES timeFrame = PERIOD_H1;
input int MAPeriod= 50;
int TEMA;
int barsTotal;
CTrade trade;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   TEMA = iTEMA(_Symbol, timeFrame, MAPeriod,0, PRICE_CLOSE);
   barsTotal=iBars(_Symbol,timeFrame);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   MqlRates priceArray[];
   double myTEMAArray[];
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
   ArraySetAsSeries(priceArray,true);
   ArraySetAsSeries(myTEMAArray,true);
   int Data=CopyRates(_Symbol,timeFrame,0,3,priceArray);
   CopyBuffer(TEMA,0,0,3,myTEMAArray);
   double lastClose=(priceArray[1].close);
   double TEMAVal = NormalizeDouble(myTEMAArray[1],_Digits);
   double prevClose=(priceArray[2].close);
   double prevTEMAVal = NormalizeDouble(myTEMAArray[2],_Digits);
   int bars=iBars(_Symbol,timeFrame);
   if(barsTotal != bars)
     {
      barsTotal=bars;
      if(lastClose>TEMAVal && prevClose<prevTEMAVal)
        {
         trade.PositionClose(_Symbol);
         trade.Buy(lotSize,_Symbol,Ask,0,0,NULL);
        }
      if(lastClose<TEMAVal && prevClose>prevTEMAVal)
        {
         trade.PositionClose(_Symbol);
         trade.Sell(lotSize,_Symbol,Bid,0,0,NULL);
        }
     }
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar este software podemos probar el mismo periodo para comparar sus resultados con otros tipos de medias móviles. A continuación les presentaremos los ajustes o entradas que se utilizarán para tratar de captar todos los parámetros en este proceso de prueba:

  • Tamaño del lote = 1
  • Marco temporal = 1 hora
  • Periodo de MA = 50

Después de ejecutar y completar esta prueba, podremos obtener los siguientes resultados:

Resultados de TEMA

Nos interesarán especialmente las siguientes lecturas:

  • Beneficio neto: - 3973,10 (- 39,74%)
  • Reducción relativa del balance: 63.98%
  • Reducción relativa de los fondos: 66.06%
  • Factor de beneficio: 0.90
  • Esperanza de beneficio: - 10,59
  • Factor de recuperación: - 0,52
  • Ratio de Sharpe: - 0,83

Media móvil adaptativa fractal (iFrAMA)

Este tipo de media móvil fue desarrollado por John Ehlers, y parte del supuesto de que los precios de mercado son fractales. También puede utilizarse para identificar tendencias y puntos de viraje. A continuación se indicarán las etapas necesarias para su cálculo:

FrAMA

Podemos utilizar un indicador técnico ya preparado del paquete MetaTrader 5. Crearemos la estrategia comercial que ya conocemos. La estrategia representa el cruce entre el precio y el indicador FrAMA. Cuando el precio cruce por encima del FrAMA, será una señal de compra y cuando el precio cruce por debajo del FrAMA, tendremos una señal de venta.

Señal de compra:

El precio de cierre se encuentra por encima de la media móvil adaptativa fractal (FrAMA).

Además: el precio de cierre anterior será inferior al valor FrAMA anterior

Señal de venta:

El precio de cierre se encontrará por debajo del valor FraMA.

Además: el precio de cierre anterior será superior al valor FrAMA anterior

A continuación le mostraremos el código completo del sistema comercial con una ligera diferencia en el uso de la función (iFrAMA) para retornar el manejador de la media móvil adaptativa fractal. Aquí tenemos sus parámetros:

  • symbol - nombre del símbolo; para el símbolo actual - _Symbol
  • period - marco temporal utilizado. Por defecto será 1 hora
  • ma_period - periodo de promediación de la media móvil. El valor por defecto será 50
  • ma_shift - para desplazamiento horizontal, se usará 0 
  • applied_price - tipo de precio utilizado para el cálculo; usaremos el precio de cierre
//+------------------------------------------------------------------+
//|                                                iFrAMA_System.mq5 |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
input double lotSize = 1;
input ENUM_TIMEFRAMES timeFrame = PERIOD_H1;
input int MAPeriod= 50;
int FrAMA;
int barsTotal;
CTrade trade;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   FrAMA = iFrAMA(_Symbol, timeFrame, MAPeriod,0, PRICE_CLOSE);
   barsTotal=iBars(_Symbol,timeFrame);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   MqlRates priceArray[];
   double myFrAMAArray[];
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
   ArraySetAsSeries(priceArray,true);
   ArraySetAsSeries(myFrAMAArray,true);
   int Data=CopyRates(_Symbol,timeFrame,0,3,priceArray);
   CopyBuffer(FrAMA,0,0,3,myFrAMAArray);
   double lastClose=(priceArray[1].close);
   double FrAMAVal = NormalizeDouble(myFrAMAArray[1],_Digits);
   double prevClose=(priceArray[2].close);
   double prevFrAMAVal = NormalizeDouble(myFrAMAArray[2],_Digits);
   int bars=iBars(_Symbol,timeFrame);
   if(barsTotal != bars)
     {
      barsTotal=bars;
      if(lastClose>FrAMAVal && prevClose<prevFrAMAVal)
        {
         trade.PositionClose(_Symbol);
         trade.Buy(lotSize,_Symbol,Ask,0,0,NULL);
        }
      if(lastClose<FrAMAVal && prevClose>prevFrAMAVal)
        {
         trade.PositionClose(_Symbol);
         trade.Sell(lotSize,_Symbol,Bid,0,0,NULL);
        }
     }
  }
//+------------------------------------------------------------------+

Después de compilar el código y ejecutar el asesor, probaremos la estrategia utilizando el indicador FrAMA con la siguiente configuración:

  • Tamaño del lote: 1
  • Marco temporal: 1 hora
  • Periodo de MA: 50

Probaremos este asesor en el mismo periodo que todas las medias móviles mencionadas anteriormente y obtendremos los siguientes resultados:

Resultados de FrAMA

Nos interesarán especialmente las siguientes lecturas:

  • Beneficio neto: - 2993,70 (- 29,94%)
  • Reducción relativa del balance: 73.28%
  • Reducción relativa de los fondos: 74.81%
  • Factor de beneficio: 0.93
  • Esperanza de beneficio: - 6,45
  • Factor de recuperación: - 0,33
  • Ratio de Sharpe: - 0,46

Comparación de los resultados con los de la AME

Vamos a comparar los resultados de cada tipo de media móvil mencionado. No obstante, cada media móvil puede ofrecer resultados diferentes si la optimizamos y cambiamos los periodos. Además, la media móvil puede dar resultados distintos según los ajustes y las condiciones del mercado.

El objetivo principal aquí es proporcionar tantas condiciones iguales como sea posible para valorar objetivamente las variedades de medias móviles basándonos en lo que creemos que son las mejores configuraciones. Veamos las lecturas más importantes:

  • Beneficio neto: cuanto más alto, mejor
  • Reducción (DD): cuanto más baja, mejor
  • Factor de beneficio: cuanto más alto, mejor
  • Esperanza de beneficio: cuanto más alta, mejor
  • Factor de recuperación: cuanto más alto, mejor
  • Ratio de Sharpe: cuanto más alto, mejor

Ahora compararemos los resultados de la media móvil simple con otros tipos de medias móviles según estos parámetros utilizando la siguiente tabla:

Parámetro SMA AMA DEMA TEMA FrAMA
Beneficio neto 2700.30 (27%) 3638.20 (36.39%) - 961.60 (- 9.62%) - 3973.10 (- 39.74%) - 2993.70 (- 29.94%)
Reducción relativa del balance 37.07% 22.48% 39.62% 63.98% 73.28%
Reducción relativa de los fondos  41.76% 35.53% 41.15% 66.06% 74.81%
Rentabilidad 1.10 1.31 0.97 0.90 0.93
Esperanza de beneficio 12.68 35.67 - 3.12 - 10.59 - 6.45
Factor de recuperación 0.45 0.65 - 0.18 - 0.52 - 0.33
Ratio de Sharpe 0.57 0.86. - 0.21 - 0.83 - 0.46

Según nuestras pruebas, tenemos dos tipos con el mejor rendimiento según la configuración y el periodo de prueba. Hablamos de la media móvil simple y la media móvil adaptativa. La mejor de ellas es la media móvil adaptativa. En ella podemos observar:

  • El mayor beneficio neto
  • La menor reducción relativa del balance
  • La menor reducción relativa de los fondos
  • El mejor factor de beneficio
  • La mayor esperanza de beneficio
  • Un alto factor de recuperación
  • Un alto ratio de Sharpe

Como ya hemos mencionado, podemos obtener mejores resultados con configuraciones y estrategias más optimizadas, pero el objetivo aquí era comprender y aplicar el proceso de prueba a un ejemplo del mundo real para que luego podamos utilizar el mismo proceso para cualquier otro objetivo de prueba.

Conclusión

En este artículo, hemos analizado los resultados de los siguientes tipos de medias móviles:

  • Media móvil adaptativa (AMA)
  • Media móvil exponencial doble (DEMA)
  • Media móvil exponencial triple (TEMA)
  • Media móvil adaptativa fractal (FrAMA)

Asimismo, hemos creado sistemas comerciales para cada tipo y comparado sus resultados con los de una media móvil simple. Según los resultados de las pruebas, los mejores resultados se han obtenido con las medias móviles simple y adaptativa. En este sentido, la media móvil adaptativa (AMA) ha sido la mejor. Para determinar el ganador, hemos analizado y comparado las siguientes métricas:

  • Beneficio neto
  • Reducción (DD)
  • Rentabilidad
  • Esperanza de beneficio
  • Factor de recuperación
  • Ratio de Sharpe

Las pruebas son un tema muy importante en el trading. Así que le animo a realizar más pruebas con un mayor número de estrategias. Además de valorar las estrategias en sí, las pruebas pueden dar lugar a conocimientos inesperados, pues cada prueba nos ayuda a profundizar nuestra comprensión de la materia.

Muchas gracias por su atención. Espero que el artículo le haya resultado de utilidad y haya ampliado sus conocimientos. En la sección "Publicaciones" podrá leer mis otros artículos, incluidos los dedicados a la creación de sistemas comerciales basados en indicadores técnicos populares como RSI, MACD, Sthocastic, Bandas de Bollinger, etc. Espero que también le resulten útiles.

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

Archivos adjuntos |
SMA_System.mq5 (2.07 KB)
iAMA_System.mq5 (2.15 KB)
iDEMA_System.mq5 (2.06 KB)
iTEMA_System.mq5 (2.06 KB)
iFrAMA_System.mq5 (2.08 KB)
Redes neuronales: así de sencillo (Parte 54): Usamos un codificador aleatorio para una exploración eficiente (RE3) Redes neuronales: así de sencillo (Parte 54): Usamos un codificador aleatorio para una exploración eficiente (RE3)
Siempre que analizamos métodos de aprendizaje por refuerzo, nos enfrentamos al problema de explorar eficientemente el entorno. Con frecuencia, la resolución de este problema hace que el algoritmo se complique, llevándonos al entrenamiento de modelos adicionales. En este artículo veremos un enfoque alternativo para resolver el presente problema.
Teoría de categorías en MQL5 (Parte 16): Funtores con perceptrones multicapa Teoría de categorías en MQL5 (Parte 16): Funtores con perceptrones multicapa
Seguimos analizando los funtores y cómo se pueden implementar utilizando redes neuronales artificiales. Dejaremos temporalmente el enfoque que implica el pronóstico de la volatilidad e intentaremos implementar nuestra propia clase de señales para establecer señales de entrada y salida para una posición.
Teoría de Categorías en MQL5 (Parte 17): Funtores y monoides Teoría de Categorías en MQL5 (Parte 17): Funtores y monoides
Este es el último artículo de la serie sobre funtores. En él, revisaremos los monoides como categoría. Los monoides, que ya hemos introducido en esta serie, se utilizan aquí para ayudar a dimensionar la posición junto con los perceptrones multicapa.
Biblioteca de análisis numérico ALGLIB en MQL5 Biblioteca de análisis numérico ALGLIB en MQL5
En este artículo, echaremos un vistazo rápido a la biblioteca de análisis numérico ALGLIB 3.19, sus aplicaciones y sus nuevos algoritmos, que pueden mejorar la eficiencia del análisis de datos financieros.