Examinamos en la práctica el método adaptativo del seguimiento del mercado

Dmitriy Gizlyk | 13 octubre, 2017


Introducción

En este artículo se representa una estrategia comercial que fue descrita por primera vez por Vladimir Kravchuk en la revista «Especulador de divisas» (Валютный спекулянт) en los años 2001 y 2002. El sistema se basa en el uso de los filtros digitales y la estimación espectral de las series temporales discretas.

El gráfico real del cambio de las cotizaciones puede tener una forma aleatoria. En las matemáticas, estas funciones se llaman no analíticas. No obstante, de la famosa teorema de Fourier se desprende que cualquier función en un intervalo de tiempo finito puede ser representada por una suma infinita de las funciones sinusoidales. Por tanto, cualquier señal temporal puede ser representada unívocamente por las funciones de frecuencia, que son llamadas sus espectros de frecuencia.

Para las señales no aleatorios, la transición de la descripción temporal de la señal a la de frecuencia (o sea, el cálculo del espectro de frecuencia) se realiza por medio de la transformada de Fourier. Los procesos aleatorios son representados por la Densidad Espectral de Potencia (DEP) del proceso, que es la trasformada de Fourier de su función de autocorrelación, y no del propio proceso aleatorio.

1. Aspectos teóricos de la estrategia

Recordaré que la filtración es el cambio del espectro de frecuencia de la señal en la dirección necesaria. Esta trasformación puede intensificar o atenuar los componentes frecuenciales en un determinado intervalo, neutralizar o escoger alguno de ellos. Al filtro digital se le llaman a un sistema digital para transformar las señales definidas sólo en los momentos discretos.

En el proceso de trabajo con los filtros temporales y las series temporales discretas hay unos aspectos importantes.

En primer lugar, la mayoría de las herramientas técnicas más populares (MA, RSI, Momentum, Stochastic, etc.) se basan en el cambio del espectro de frecuencia de la señal, por tanto, son filtros digitales. El coeficiente de la intensificación de su función de transferencia depende de la frecuencia.Pero poca gente se pone a pensar en esta función de transferencia. Por eso la mayoría de los usuarios no saben en qué dirección se cambia el espectro de frecuencia de la señal, y entonces, no entienden la naturaleza del impacto del indicador sobre la señal. Eso complica la configuración del indicador y la interpretación de sus señales.

En segundo lugar, el proceso del movimiento de las cotizaciones siempre se ve como una señal discreta, cuyas propiedades generales deben tomarse en cuenta a la hora de desarrollar los indicadores técnicos. Así, por ejemplo, el espectro de la señal discreta es siempre una función periódica. Si esta propiedad se ignora, se puede obtener una distorsión no reparable de la serie temporal de entrada.

En tercer lugar, las densidades espectrales de los movimientos de precios son muy desiguales en diferentes mercados. En este caso, el usuario no tiene un algoritmo claro para configurar los parámetros de los indicadores: en vez de eso él debe seleccionar los parámetros aleatorios y testear su viabilidad en la práctica.

Muchas veces sucede que un indicador (o EA) ya optimizado y que se comportaba bien ayer, hoy muestra unos resultados pésimos. Eso tiene que ver con que las series temporales no son estacionarias. En la práctica, cuando se comparan dos evaluaciones de la DEP calculadas en diferentes timeframes para el mismo mercado, la amplitud de los picos espectrales se desplaza y cambia su forma. Eso se puede interpretar como una manifestación del efecto de Doppler, cuando la fuente de una onda armónica se mueve respecto al receptor, se cambia su longitud. Eso confirma otra vez más la presencia del movimiento tendencial en el mercado.

El objetivo del método adaptativo de seguimiento del mercado es encontrar aquel mínimo razonable de las herramientas técnicas que permita crear un algoritmo para tradear con rentabilidad máxima y riesgo mínimo. Para eso, se realizan varios pasos consecutivos.

  • Se estudia la composición espectral de las fluctuaciones de precios de un mercado en particular.
  • Se configuran de manera adaptativa los filtros digitales no recursivos. El resultado de este procedimiento es un conjunto de respuestas impulsivas (RI) ya optimizadas.
  • Se filtra la serie temporal de entrada, y al final se define el conjunto de los indicadores que se consideran más abajo.
  • Se desarrolla el algoritmo comercial.
El método adaptativo puede aplicarse a cualquier tipo de mercados. No obstante, hay que tomar en cuenta que la capitalización y la liquidez de un mercado seleccionado influirá en el tamaño máximo de una posición abierta sin la perdida del rendimiento. 

1.1. Seleccionando el método del análisis espectral

El desarrollo del sistema comercial de acuerdo con el método adaptativo del seguimiento del mercado comienza con el estudio del espectro de los movimientos de los precios de un instrumento en particular. Es obvio que la eficacia final del sistema entero depende de los resultados de esta fase.

Podría parecer que la solución se consigue por sí sola: hay que realizar el análisis espectral o armónico. ¿Pero cuál de los métodos hay que escoger exactamente? Actualmente, se conocen dos clases principales de los métodos del análisis espectral: paramétricos y no paramétricos.

Los métodos del análisis espectral paramétricos son metodologías en las que se establece un cierto modelo de la densidad espectral y se estiman sus parámetros según los resultados de la observación del proceso correspondiente en un período limitado. En este caso, el modelo original puede tener el más diverso aspecto.

En particular, El modelo inicial puede ser la densidad espectral de la serie temporal en forma de una función racional. En este caso, se puede distinguir el modelo autoregresivo, modelo de la media móvil y el modelo autoregresivo de la media móvil. Por tanto, durante la evaluación de los parámetros del modelo, van a usarse diferentes enfoques metodológicos.

Además, para resolver este problema, podemos usar el principio de variaciones y el recurso correspondiente de la evaluación de la calidad. Aquí, los multiplicadores de Lagrange van a jugar el papel de los parámetros evaluados. Este método se aplica durante la evaluación de la densidad espectral de cuerdo con el método de máxima entropía, donde es necesario maximizar la entropía del proceso según los valores individuales conocidos de la función correlativa.

Los métodos del análisis espectral no paramétricos, a diferencia de los paramétricos, no cuentan con ningunos modelos predefinidos. Entre ellos, el método más popular es aquel donde la periodicidad del proceso se determina en la fase inicial (es decir, el cuadrado del módulo de la transformada de Fourier de una implementación existente). Después de eso, el problema se resume a la selección de la ventana apropiada que va a satisfacer ciertos requerimientos.

También se utiliza ampliamente el método de Blackmen y Tukey, en el que, para la serie temporal utilizada, se encuentra la transformada de Fourier de la estimación ponderada de la secuencia de correlación.

Otro enfoque consiste en reducir el problema de la evaluación de la densidad espectral de la serie temporal a la solución de una ecuación integral fundamental que describe la transformada de Fourier de la serie temporal estudiada por medio de un proceso aleatorio con incrementos ortogonales.

El autor del sistema comercial propuesto afirma que es imposible evaluar cualitativamente la densidad espectral de la potencia de las fluctuaciones de las cotizaciones usando los métodos clásicos no paramétricos de la estimación espectral que se basan en el cálculo de la transformada discreta de Fourier de las series temporales. La única solución consiste en usar los métodos paramétricos del análisis espectral, que son capaces de obtener la evaluación consistente de la DEP para una muestra temporal discreta relativamente corta, en la que el proceso ya es estacionario, o se puede hacerlo así excluyendo la tendencia lineal. Entre la variedad de los métodos paramétricos de la estimación espectral, tal vez, aquél que merece la más atención es el método de máxima entropía.

1.2. Herramientas del análisis técnico usadas

La principal diferencia de la estrategia propuesta es la línea de tendencia adaptativa. Su dirección es el indicador de la dirección de la tendencia actual.

La línea de tendencia adaptativa representa una componente de baja frecuencia de la serie temporal de entrada. Se obtiene gracias al filtro paso bajo (FPB). Cuanto más baja sea la frecuencia del corte fc del FPB, la línea de tendencia se suaviza con mayor intensidad.

Entre los puntos de la línea de tendencia adaptativa hay una vinculación interna, cuya fuerza es inversamente proporcional a la distancia entre ellos. No hay vinculación sólo entre los valores de los puntos, la distancia entre los cuales es igual o mayor que así llamado el intervalo de Nyquist TN=1/(2 fc). Por consiguiente, esta vinculación se aumenta con la disminución de la frecuencia del corte del filtro, y por tanto el momento de la reversa de la tendencia se aplaza.

Para determinar la tendencia, en el sistema comercial se usan dos líneas de tendencia adaptativas con períodos diferentes.

FATL (Fast Adaptive Trend Line) es la línea de tendencia adaptativa «corta». Para la construcción hace falta el FPB-1. El filtro elimina los ruidos de alta frecuencia y los ciclos de mercado con un período de oscilación muy corto.

SATL (Slow Adaptive Trend Line) es la línea de tendencia adaptativa «lenta». Para su construcción hace falta el FPB-2. A diferencia del FPB-1, él transmite los ciclos de mercado con un período de oscilaciones más largo.

Los parámetros de los filtros arriba descritos (frecuencia del corte fc y la atenuación σ en la banda de rechazo) se calculan a partir de las estimaciones del espectro del instrumento que nos interese. FPB-1 Y FPB-2 aseguran la atenuación en la banda de rechazo no menos de 40 dB. Su uso no afecta en absoluto la amplitud y la fase de la señal de entrada en la banda pasante. Esta propiedad de los filtros digitales asegura la supresión eficaz de los ruidos y, en comparación de la MA simple, producen menos señales falsas.

Desde el punto de vista matemático, el valor FATL(k) es el valor esperado del precio Close(k), donde k es el número del día de trading.

RFTL (Reference Fast Trend Line)RSTL (Reference Slow Trend Line) — líneas de tendencia de apoyo «rápida» y «lenta». Ellas representan los valores emitidos por los filtros FPB-1 y FPB-2 en respuesta a la señal de entrada, y tomados con atrasos iguales al intervalo de Nyquist correspondiente.

FTLM (Fast Trend Line Momentum) y STLM (Slow Trend Line Momentum) demuestran los desplazamientos FATL y SATL. Se calculan de la misma forma como el indicador Momentum, sólo en vez de los precios de cierre se usan las líneas de tendencia suavizados por la filtración. Como resultado, las líneas son más suaves y más regulares de que estamos acostumbrados a ver en Momentum.

Las líneas FTLM y STLM se calculan según las reglas de las matemáticas discretas. Es la diferencia entre dos puntos adyacentes e independientes, limitados por la banda del proceso. En el cálculo convencional de Momentum, muchas veces estas exigencias se menosprecian, provocando distorsiones fatales en el espectro de la señal de entrada.

RBCI (Range Bound Channel Index) es el índice del canal limitado por la zona de ultraje. Se calcula por el filtro de banda que incluye las siguientes tareas:

  • exclusión de la tendencia de baja frecuencia formada por las componentes espectrales de baja frecuencia con períodos mayores que T2 = 1/fc2;
  • exclusión del ruido de alta frecuencia formada por las componentes espectrales de alta frecuencia con períodos menores que T1 = 1/fc1
    ;

Los períodos Т1 y Т2 están seleccionados de tal manera que se cumpla la condición Т2 > T1. Al mismo tiempo, las frecuencias del corte fc1 y fc2 tienen que ser así que los ciclos de mercado dominantes entren en consideración.

Simplificando, RBCI(k) = FATL(k) - SATL(k). De hecho, cuando RBCI se aproxima a sus extremos locales, los precios se acercan al borde superior e inferior del canal del trading (dependiendo de que si es el máximo o el mínimo, respectivamente).

PCCI (Perfect Commodity Channel Index) es el índice perfecto del canal del precio. La fórmula para su cálculo es PCCI(k) = close(k) – FATL(k).

El método de su cálculo parece al calculo del índice del canal del precio CCI. Efectivamente, CCI es la diferencia normalizada entre el precio actual y su media móvil, y PCCI es la diferencia entre el precio de cierre del día y su beneficio esperado (el cual, como hemos aclarado antes, se coge del valor de FATL).

Por tanto, el índice PCCI es una componente de alta frecuencia de las oscilaciones de cotizaciones, normalizada por su desviación estándar.

Ejemplo de indicadoresEjemplo de indicadores


1.3. Reglas de interpretación de las señales de los indicadores.

Especificamos los principios básicos del sistema de trading.

  • El sistema pertenece a los tendenciales, tradeando de acuerdo con la tendencia. La tendencia se identifica usando SATL.
  • Los puntos de entrada se determinan de acuerdo con las características dinámicas de las tendencias «rápida» y «lenta» FTLM y STLM.
  • El cálculo envuelve el estado actual del mercado (neutralidad, sobrecompra, sobreventa, extremos locales) que se determina usando el índice RBCI.
  • La dirección de la entrada en el mercado se determina usando los indicadores tendenciales. Puede usar los osciladores solamente en caso del flat.
  • La colocación de las órdenes Stop es obligatoria (por los índices RBCI, PCCI y por la volatilidad del mercado).

Las herramientas arriba descritas deben interpretarse según las siguientes reglas.

  • Si la línea SATL apunta hacia arriba, el mercado se encuentra en la tendencia ascendiente, si apunta hacia abajo, es descendiente. La aparición de los extremos locales indica en que la tendencia empieza a dar la vuelta. La intersección con RSTL es un indicio de que la tendencia ha dado el giro completo. Cuando sucede eso, STML cambia de signo.
  • Si la línea SATL es horizontal, o casi horizontal, es el indicio de la presencia del flat en el mercado.
  • STLM es positivo en caso de la tendencia alcista, es negativo en caso de la tendencia bajista. Se considera como un indicador adelantado. Sus extremos locales siempre anuncian la aparición de los extremos correspondientes SATL. El valor absoluto de STLM es directamente proporcional a la fuerza de la tendencia. Si STLM y SATL se mueven en la misma dirección, por tanto, la tendencia se hace más fuerte. Las tendencias bidireccionales indican en la disminución de la tendencia. La línea horizontal de STLM indica en que la tendencia se ha formado definitivamente.
  • Si las líneas tendenciales «rápida» y «lenta» (FATL и SATL) indican en la misma dirección, la fuerza de la tendencia es alta. De lo contrario, el mercado está consolidado o se encuentra en la fase de la corrección. 
  • Si las líneas FATL y SATL han empezado a ir en la misma dirección, entonces la tendencia ha hecho el giro. Si la dirección ha vuelto a ser la misma después del período bidireccional, entonces, la corrección en el mercado ha terminado y las cotizaciones han empezado a moverse en la dirección SATL.

A base de estas reglas, vamos a formular las principales señales de trading.

  1. Al principio de una tendencia de larga duración aparece una segura señal de reversa: STLM cae indicando en la convergencia de la línea de tendencia «lenta» adaptativa y de apoyo (SATL y RSTL). Durante la formación de la señal, la volatilidad de precios se aumenta bruscamente. Es el indicio característico del momento del cambio de la tendencia. Por eso, al escoger los puntos de apertura de la transacción, es necesario tomar en cuenta PCCI. Cuando la señal es bajista, vendemos si para el cierre de la última vela el oscilador PCCI se encuentra por encima del nivel -100.Si el valor de PCCI está por debajo de -100, no abrimos la transacción, sino esperamos a que el oscilador supere este nivel.

  2. La siguiente señal indica en la continuación de una tendencia ya formada y fortalecida después de una corrección no prolongada. La volatilidad en este caso normalmente es más débil que durante la reversa de la tendencia. Por eso las condiciones de formación de la señal son más estrictas y ella es más segura.
    Negociamos si los indicadores FATL, FTLM y RBCI se mueven sincrónicamente. Las señales se filtran por el indicador STLM (su valor absoluto crece o se mantiene inalterado). Si STLM se disminuye, eso indica en la aproximación entre SATL y RSTL. Cuando ocurre eso, inmediatamente después de que surja una señal bajista por RBCI, se comprueba si el mercado no está sobrevendido. Se escoge el precio de entrada en el mercado que sea igual o mejor que el precio Open de la siguiente barra tras la llegada de la señal.

  3. Esta señal se basa en la suma de los ciclos activos en la banda de frecuencia que se determina por el índice RBCI. No se toma en cuenta en qué dirección está apuntada la línea STLM, y cómo SATL se converge/se diverge con RSTL. Importa sólo si el valor de STLM es positivo o negativo, que indica en la dirección de la tendencia principal formada en el mercado. El filtro adicional es la dirección y el comportamiento de la línea de FATL.
    La formación de la señal ocurre cuando, durante una tendencia prolongada neutral o descendiente, el ciclo de onda compuesto alcanza el máximo local en la zona de una sobrecompra fuerte. Durante la fase del flat, el potencial del movimiento proveniente de los ciclos de mercado será más alto que el potencial del movimiento debido a la volatilidad. Si la tendencia está formada, el potencial del movimiento a base de los ciclos de mercado va a sumarse con el potencial de una tendencia de duración larga.
    Se escoge el precio de la transacción que sea igual o mejor que el precio Open de la siguiente barra tras la llegada de la señal.

  4. La base de la señal consiste en dos divergencias: entre la dirección del movimiento de RBCI y la línea de FATL, así como entre los índices RBCI y FTLM. Si durante un determinado período, FATL y los índices RBCI y FTLM se mueven en direcciones diferentes, pasamos a la fase de la espera. La señal bajista es el mínimo local de FTLM, cuando FATL y RBCI no cambian la dirección del movimiento. En el gráfico, eso parece a «inclinación» FTLM en dirección del movimiento de FATL.
    En la mayoría de las veces, vemos esta señal cerca del punto de terminación de la tendencia descendiente «rápida» (el valor de FTLM es próximo a "0"). El sistema genera una señal bastante precisa para un movimiento tendencial corto.
    Es una señal adelantada que precede la reversa de la tendencia.
    Se escoge el precio de entrada en el mercado que sea igual o mejor que el precio de apertura de la siguiente vela tras la llegada de la señal.

  5. La señal se forma durante una tendencia larga. Los índices RBCI y PCCI llegan simultáneamente a los valores de sobrecompra del mercado (para una tendencia descendiente). Generalmente, estas señales se forman en la última fase de la tendencia cuando las cotizaciones de repente saltan en la dirección opuesta, y luego «se rompen» de nuevo en la dirección de la tendencia principal que todavía es fuerte.
    Se escoge el precio de entrada en el mercado que sea igual o mejor que el precio de apertura de la siguiente vela tras la llegada de la vela de la señal.

  6. Durante la formación de una tendencia bajista de larga duración (SATL ya va cayendo, pero STLM todavía se mantiene positivo), el índice PCCI alcanza los valores por encima de 100 (zona de sobrecompra del mercado). La señal de reversa se basa en el uso de la volatilidad alta del mercado en el momento de la formación de la tendencia.
    Se escoge el precio de entrada en el mercado que sea igual o mejor que el precio de apertura de la siguiente vela tras la llegada de la señal.

  7. La señal de reversa de la tendencia se observa tras la finalización de la primera corrección técnica hacia arriba, después de que la línea FATL se rompe por la línea SATL de arriba abajo. Después de eso, vendemos. El máximo local de FATL es el indicio de que esta corrección técnica haya concluido.
    El precio de venta es mayor o igual al precio de apertura de la siguiente vela tras la llegada de la señal.

  8. Y finalmente, otra señal de reversa se forma cuando ocurren simultáneamente dos intersecciones: entre la línea adaptativa «rápida» y «lenta» FATL y SATL, así como entre FATL y RFTL (en caso de la ruptura hacia abajo, vendemos, en caso de la ruptura hacia arriba, compramos). Esta señal indica en el momento de la fractura brusca de la tendencia anterior que ya está débil. El precio de venta supera o es igual al precio de apertura de la siguiente vela tras la llegada de la señal.

2. Construyendo los filtros paso bajo

Ahora, cuando ya han sido establecidos los principales aspectos de la estrategia, es el momento de abordar la parte práctica del trabajo. Claro que vamos a comenzar este trabajo con la construcción del filtro paso bajo (FPB), porque la estrategia se basa precisamente en este tipo de filtros.

Para construir el FPB necesitamos definir sus principales parámetros: frecuencia de corte y atenuación. Si el autor de la estrategia indica claramente que el filtro debe asegurar la atenuación en la banda de latencia no menos de 40 dB, entonces para definir la frecuencia de corte, necesitamos realizar el análisis espectral de los datos del instrumento.

Como mencionábamos antes, la estimación de la Densidad Espectral de Potencia (DEP) fue realizada por el autor usando el método de máxima entropía. Este método pertenece a los paramétricos, y ha sido realizado por un modelo matemático. El modelo matemático será construido por el método de autoregresión.

2.1. Análisis de la Densidad Espectral de Potencia

Para estimar la densidad espectral, vamos a crear la clase CSpertrum (el código completo se puede encontrar en el anexo). Al inicializar la clase, vamos a transmitir el nombre del instrumento, el timeframe de trabajo y el número de barras para el análisis.

class CSpectrum
  {
private:
   int               ci_HistoryBars;               //Bars for analysis
   string            cs_Symbol;                    //Symbol
   ENUM_TIMEFRAMES   ce_Timeframe;                 //Timeframe
   double            cda_AR[];                     //Autoregression coefficients
   int               ci_NumberCoeffs;              //Number of coefficients
  
public:
                     CSpectrum(int bars=2880, string symbol=NULL, ENUM_TIMEFRAMES period=PERIOD_CURRENT);
                    ~CSpectrum();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSpectrum::CSpectrum(int bars=2880, string symbol=NULL, ENUM_TIMEFRAMES period=PERIOD_CURRENT)
  {
   ci_HistoryBars =  bars;
   cs_Symbol      =  (symbol==NULL ? _Symbol : symbol);
   ce_Timeframe   =  period;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSpectrum::~CSpectrum()
  {
  }

Para calcular la función de autoregresión y la DEP usaremos la metodología propuesta por Victor. A los que desean estudiar en detalle el algoritmo les recomiendo leer este artículo. El resultado de la función del análisis espectral del área es el array de datos que -para mayor claridad- puede ser representado como un gráfico.

Densidad Espectral de Potencia de EURUSD

Los saltos esporádicos en el gráfico reflejan el aumento de la potencia de la señal en una determinada frecuencia. Necesitamos encontrar precisamente estos saltos para determinar las características de frecuencia de nuestros filtros. Para eso, a la clase CSpecrum añadiremos la función public GetPeriods que devolverá los períodos para FATL y SATL cuando eso será solicitado.

Dentro de la función, vamos a determinar los saltos como fractales. Para el período del filtro SATL, determinaremos el primer salto que muestra los impulsos con la menor frecuencia. Para FATL encontraremos el impulso con la mayor frecuencia y la potencia más de -40 dB, eliminando los impulsos de ruido con una amplitud pequeña y frecuencia grande. Si la función no encuentra los períodos para ambos filtros, devolverá el valor false.

bool CSpectrum::GetPeriods(int &FAT,int &SAT)
  {
   if(!Spectrum())
      return false;
   FAT=SAT=0;
   int total=ArraySize(cad_Spectr)-1;
   for(int i=1;(i<total);i++)
     {
      int temp=2*(total+1)/i;
      if(cad_Spectr[i]==0 || temp>(int)ci_HistoryBars/4)
         continue;
      if((cad_Spectr[i]-cad_Spectr[i+1])>=0 && (cad_Spectr[i]-cad_Spectr[i-1])>0)
        {
         if(SAT==0)
            SAT=temp;
         else
           {
            if(cad_Spectr[i]<-40)
              {
               if(FAT==0)
                  FAT=temp;
               break;
              }
            if(temp>=20)
               FAT=temp;
           }
        }
     }
   if(SAT==0 || FAT==0)
      return false;
   return true;
  }

2.2. Cálculo de los coeficientes del filtro paso bajo

Después de definir las frecuencias de los filtros, es la hora de construir nuestros filtros paso bajo. Ésta es la fórmula general del filtro paso bajo


Donde y es la salida del filtro; x es el array de datos de origen; hk son las respuestas a impulso; N es el número de las características de impulso.

Los datos de precios del instrumento se usan como valores iniciales, el número de las respuestas a impulso lo estableceremos igual al intervalo de Nyquist. Además, tenemos que calcular las respuestas a impulso. Las respuestas a impulso ideales para el filtro de la densidad de potencia se calculan usando la fórmula


Donde fc y wc es la frecuencia de corte.

Lamentablemente, nuestro mundo está lejos de ser ideal. Por eso, necesitamos una respuesta a impulso «real». Para su cálculo, necesitamos la función de peso w(n). Existen varias funciones de peso. Yo utilizo la función de Blackman que es la siguiente


Donde N es el número de los elementos del filtro.

Para obtener una respuesta a impulso «real», hay que multiplicar una respuesta a impulso real por la función de peso correspondiente


Ahora, cuando ya hemos aclarado las fórmulas del cálculo, crearemos la clase CFLF en la que vamos a calcular las respuestas a impulso y filtrar los datos de entrada. Para calcular los coeficientes de la respuesta a impulso, calcularemos la función public CalcImpulses, a la que pasaremos el período de la filtración. Luego, el algoritmo de la función repetirá las fórmulas de arriba. A continuación, normalizamos las respuestas a impulso llevando su cantidad a "1".

bool CFLF::CalcImpulses(int period)
  {
   if(period<20)
      return false;
   int N=(int)(period/2);
   if(ArraySize(cda_H)!=N)
      if(ArrayResize(cda_H,N)<N)
         return false;
   double H_id[],W[];
   if(ArrayResize(H_id,N)<N || ArrayResize(W,N)<N)
      return false;
  
   cd_Fs=1/(double)period;
   for (int i=0;i<N;i++)
     {
      if (i==0)
         H_id[i] = 2*M_PI*cd_Fs;
      else
         H_id[i] = MathSin(2*M_PI*cd_Fs*i )/(M_PI*i);
      
      W[i] = 0.42 - 0.5 * MathCos((2*M_PI*i) /( N-1)) + 0.08 * MathCos((4*M_PI*i) /( N-1));
      cda_H[i] = H_id[i] * W[i];
     }
      
   //Normalization
   double SUM=MathSum(cda_H);
   if(SUM==QNaN || SUM==0)
      return false;
   for (int i=0; i<N; i++)
      cda_H[i]/=SUM; //summ of coefficients equal 1 
   //---
   return true;
  }

2.3. Cálculo de indicadores FATL, SATL, RTFL, RSTL.

Después de obtener las respuestas a impulso, se puede proceder al cálculo de los valores de indicadores usados. Será conveniente obtener el valor de indicadores FATL, SATL, RFTL y RSTL directamente de la clase del filtro.

Como vamos a usar diferentes instancias de la clase para el filtro rápido y lento, basta con crear las funciones AdaptiveTrendLineReferenceTrendLine dentro de la clase. Dentro de la función, vamos a transferir el instrumento usado, timeframe y el desplazamiento respecto a la vela actual. Las funciones van a devolver el valor filtrado.

Se debe prestar atención en que la función ReferenceTrendLine es prácticamente semejante que la función AdaptiveTrendLine. La diferencia consiste en que ReferenceTrendLine se calcula con el desplazamiento en el período de Nyquist. Por tanto, calcularemos el período de Nyquist en ReferenceTrendLine y llamaremos a la función AdaptiveTrendLine, indicando el desplazamiento necesario respecto a la barra actual.

double CFLF::AdaptiveTrendLine(string symbol=NULL,ENUM_TIMEFRAMES timeframe=0,int shift=1)
  {
   string symb=(symbol==NULL ? _Symbol : symbol);
   int bars=ArraySize(cda_H);
   double values[];
   if(CopyClose(symb,timeframe,shift,bars,values)<=0)
      return QNaN;
   double mean=MathMean(values);
   double result=0;
   for(int i=0;i<bars;i++)
      result+=cda_H[i]*(values[bars-i-1]-mean);
   result+=mean;
   return result;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CFLF::ReferenceTrendLine(string symbol=NULL,ENUM_TIMEFRAMES timeframe=0,int shift=1)
  {
   shift+=(int)(1/(2*cd_Fs));
   return AdaptiveTrendLine(symbol,timeframe,shift);
  }

El resto de los indicadores utilizados son derivados de los valores obtenidos y serán calculados a continuación.

3. Creamos el módulo de las señales comerciales para el generador de los Asesores Expertos en MQL5

Hoy he decidido apartarse un poco de la escritura habitual del EA y recordar sobre la existencia del Asistente para generar los EAs en MT5. Este recurso útil es una especie del constructor en el cual el EA se construye usando los módulos preparados anteriormente. Eso permite crear fácilmente un nuevo EA añadiendo las funciones nuevas y quitando las que no se utilizan. Por eso propongo colocar el algoritmo de la toma de decisiones de nuestro EA en el módulo de este tipo. Mas información sobre este método se puede encontrar en los artículos [4], [5] en este sitio web. Por eso, en el presente artículo, me centraré solamente en los momentos referentes a nuestra estrategia.

Empezaremos con la creación de la clase de señal CSignalATCF a base de la clase CExpertSignal y conectaremos a ella nuestras clases creadas antes.

class CSignalATCF : public CExpertSignal
  {
private:
   CSpectrum         *Spectrum;     //Class for spectr calculation
   CFLF              *FFLF;         //Class of fast low frequency filter
   CFLF              *SFLF;         //Class of slow low frequency filter

public:                      CSignalATCF();                     ~CSignalATCF();   };

Durante la inicialización, tenemos que pasar en el módulo el nombre del instrumento, el timeframe usado, el número de las barras del historial para el análisis de la DEP, así como el número de las barras de la media (se usa para el cálculo de los indicadores RBCI y PCCI). Aparte de eso, hay que indicar cuáles de los patrones se usan para abrir la posición. La apariencia general de la descripción del módulo será la siguiente:

// wizard description start
//+---------------------------------------------------------------------------+
//| Description of the class                                                  |
//| Title=Signals degign by DNG for Adaptive Trend & Cycles Following Method  |
//| Type=SignalAdvanced                                                       |
//| Name=Signals Adaptive Trend & Cycles Following Method                     |
//| ShortName=ATCF                                                            |
//| Class=CSignalATCF                                                         |
//| Page=https://www.mql5.com/ru/articles/3456                                |
//| Parameter=TimeFrame,ENUM_TIMEFRAMES,PERIOD_H4,Timeframe                   |
//| Parameter=HistoryBars,uint,1560,Bars in history to analysis               |
//| Parameter=AveragePeriod,uint,500,Period for RBCI and PCCI                 |
//| Parameter=Pattern1,bool,true,Use pattern 1                                |
//| Parameter=Pattern2,bool,true,Use pattern 2                                |
//| Parameter=Pattern3,bool,true,Use pattern 3                                |
//| Parameter=Pattern4,bool,true,Use pattern 4                                |
//| Parameter=Pattern5,bool,true,Use pattern 5                                |
//| Parameter=Pattern6,bool,true,Use pattern 6                                |
//| Parameter=Pattern7,bool,true,Use pattern 7                                |
//| Parameter=Pattern8,bool,true,Use pattern 8                                |
//+---------------------------------------------------------------------------+
// wizard description end

Ahora declaramos las variables y funciones necesarias:

class CSignalATCF : public CExpertSignal
  {
private:
   ENUM_TIMEFRAMES   ce_Timeframe;     //Timeframe
   uint              ci_HistoryBars;   //Bars in history to analysis
   uint              ci_AveragePeriod; //Period for RBCI and PCCI
   CSpectrum         *Spectrum;        //Class for spectr calculation
   CFLF              *FFLF;            //Class of fast low frequency filter
   CFLF              *SFLF;            //Class of slow low frequency filter
   //--- Indicators data
   double             FATL, FATL1, FATL2;
   double             SATL, SATL1;
   double             RFTL, RFTL1, RFTL2;
   double             RSTL, RSTL1;
   double             FTLM, FTLM1, FTLM2;
   double             STLM, STLM1;
   double             RBCI, RBCI1, RBCI2;
   double             PCCI, PCCI1, PCCI2;
   //--- Patterns flags
   bool               cb_UsePattern1;
   bool               cb_UsePattern2;
   bool               cb_UsePattern3;
   bool               cb_UsePattern4;
   bool               cb_UsePattern5;
   bool               cb_UsePattern6;
   bool               cb_UsePattern7;
   bool               cb_UsePattern8;
   //---
   datetime           cdt_LastSpectrCalc;
   datetime           cdt_LastCalcIndicators;
   bool               cb_fast_calced;
   bool               cb_slow_calced;
   
   bool              CalculateIndicators(void);
       
public:
                     CSignalATCF();
                    ~CSignalATCF();
   //---
   void              TimeFrame(ENUM_TIMEFRAMES value);
   void              HistoryBars(uint value);
   void              AveragePeriod(uint value);
   void              Pattern1(bool value)                {  cb_UsePattern1=value;   }
   void              Pattern2(bool value)                {  cb_UsePattern2=value;   }
   void              Pattern3(bool value)                {  cb_UsePattern3=value;   }
   void              Pattern4(bool value)                {  cb_UsePattern4=value;   }
   void              Pattern5(bool value)                {  cb_UsePattern5=value;   }
   void              Pattern6(bool value)                {  cb_UsePattern6=value;   }
   void              Pattern7(bool value)                {  cb_UsePattern7=value;   }
   void              Pattern8(bool value)                {  cb_UsePattern8=value;   }
   //--- 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);
  };

Creamos la función para calcular los valores del indicador:

bool CSignalATCF::CalculateIndicators(void)
  {
   //--- Check time of last calculation
   datetime current=(datetime)SeriesInfoInteger(m_symbol.Name(),ce_Timeframe,SERIES_LASTBAR_DATE);
   if(current==cdt_LastCalcIndicators)
      return true;                  // Exit if data alredy calculated on this bar
   //--- Check fo recalc spectrum
   MqlDateTime Current;
   TimeToStruct(current,Current);
   Current.hour=0;
   Current.min=0;
   Current.sec=0;
   datetime start_day=StructToTime(Current);
   
   if(!cb_fast_calced || !cb_slow_calced || (!PositionSelect(m_symbol.Name()) && start_day>cdt_LastSpectrCalc))
     {
      if(CheckPointer(Spectrum)==POINTER_INVALID)
        {
         Spectrum=new CSpectrum(ci_HistoryBars,m_symbol.Name(),ce_Timeframe);
         if(CheckPointer(Spectrum)==POINTER_INVALID)
           {
            cb_fast_calced=false;
            cb_slow_calced=false;
            return false;
           }
        }
      
      int fast,slow;
      if(Spectrum.GetPeriods(fast,slow))
        {
         cdt_LastSpectrCalc=(datetime)SeriesInfoInteger(m_symbol.Name(),ce_Timeframe,SERIES_LASTBAR_DATE);
         if(CheckPointer(FFLF)==POINTER_INVALID)
           {
            FFLF=new CFLF();
            if(CheckPointer(FFLF)==POINTER_INVALID)
               return false;
           }
         cb_fast_calced=FFLF.CalcImpulses(fast);
         if(CheckPointer(SFLF)==POINTER_INVALID)
           {
            SFLF=new CFLF();
            if(CheckPointer(SFLF)==POINTER_INVALID)
               return false;
           }
         cb_slow_calced=SFLF.CalcImpulses(slow);
        }
     }
   if(!cb_fast_calced || !cb_slow_calced)
      return false;                       // Exit on some error
   
   //--- Calculate indicators data
   int shift=StartIndex();
   double rbci[],pcci[],close[];
   if(ArrayResize(rbci,ci_AveragePeriod)<(int)ci_AveragePeriod || ArrayResize(pcci,ci_AveragePeriod)<(int)ci_AveragePeriod ||
      m_close.GetData(shift,ci_AveragePeriod,close)<(int)ci_AveragePeriod)
     {
      return false;
     }
   for(uint i=0;i<ci_AveragePeriod;i++)
     {
      double fatl=FFLF.AdaptiveTrendLine(m_symbol.Name(),ce_Timeframe,shift+i);
      double satl=SFLF.AdaptiveTrendLine(m_symbol.Name(),ce_Timeframe,shift+i);
      switch(i)
        {
         case 0:
            FATL=fatl;
            SATL=satl;
            break;
         case 1:
            FATL1=fatl;
            SATL1=satl;
            break;
         case 2:
            FATL2=fatl;
            break;
        }
      rbci[i]=fatl-satl;
      pcci[i]=close[i]-fatl;
     }
   RFTL=FFLF.ReferenceTrendLine(m_symbol.Name(),ce_Timeframe,shift);
   RSTL=SFLF.ReferenceTrendLine(m_symbol.Name(),ce_Timeframe,shift);
   RFTL1=FFLF.ReferenceTrendLine(m_symbol.Name(),ce_Timeframe,shift+1);
   RSTL1=SFLF.ReferenceTrendLine(m_symbol.Name(),ce_Timeframe,shift+1);
   RFTL2=FFLF.ReferenceTrendLine(m_symbol.Name(),ce_Timeframe,shift+2);
   FTLM=FATL-RFTL;
   STLM=SATL-RSTL;
   FTLM1=FATL1-RFTL1;
   STLM1=SATL1-RSTL1;
   FTLM2=FATL2-RFTL2;
   double dev=MathStandardDeviation(rbci);
   if(dev==0 || dev==QNaN)
      return false;
   RBCI=rbci[0]/dev;
   RBCI1=rbci[1]/dev;
   RBCI2=rbci[2]/dev;
   dev=MathAverageDeviation(pcci);
   if(dev==0 || dev==QNaN)
      return false;
   PCCI=pcci[0]/(dev*0.015);
   PCCI1=pcci[1]/(dev*0.015);
   PCCI2=pcci[2]/(dev*0.015);
   cdt_LastCalcIndicators=current;
  //---
   return true;
  }

Luego, codificamos los patrones de la apertura y el cierre de la posición, indicando los pesos correspondientes (40 para el cierre y 80 para la apertura). Abajo se muestra la función para abrir las posiciones largas. La función para las posiciones cortas se construye de la misma manera.

int CSignalATCF::LongCondition(void)
  {
   if(!CalculateIndicators() || m_open.GetData(1)>m_close.GetData(1))
      return 0;
   int result=0;
   //--- Close
   if(m_high.GetData(2)<m_close.GetData(1) || (STLM1<=0 && STLM>0) || (PCCI1<PCCI && PCCI1<=PCCI2) || (RBCI>RBCI1 && RBCI1>=RBCI2 && RBCI1<-1) || (RBCI1<=0 && RBCI>0))
      result=40;
   //--- Pattern 1
   if(cb_UsePattern1 && FTLM>0 && STLM>STLM1 && PCCI<100)
      result=80;
   else
   //--- Pattern 2
   if(cb_UsePattern2 && STLM>0 && FATL>FATL1 && FTLM>FTLM1 && RBCI>RBCI1 && (STLM>=STLM1 || (STLM<STLM1 && RBCI<1)))
      result=80;
   else
   //--- Pattern 3
   if(cb_UsePattern3 && STLM>0 && FATL>FATL1 && RBCI>RBCI1 && RBCI1<-1 && RBCI1<=RBCI2 && FTLM>FTLM1)
      result=80;
   else
   //--- Pattern 4
   if(cb_UsePattern4 && SATL>SATL1 && FATL>FATL1 && RBCI>RBCI1 && FTLM<FTLM1 && FTLM2<=FTLM1)
      result=80;
   else
   //--- Pattern 5
   if(cb_UsePattern5 && SATL>SATL1 && STLM>=0 && PCCI1<=-100 && PCCI1<PCCI && PCCI>-100 && RBCI>RBCI1 && RBCI1<=RBCI2 && RBCI1<-1)
      result=80;
   else
   //--- Pattern 6
   if(cb_UsePattern6 && SATL>SATL1 && STLM<0 && PCCI1<=-100 && PCCI>-100)
      result=80;
   else
   //--- Pattern 7
   if(cb_UsePattern7 && FATL>FATL1 && FATL1<=SATL1 && FATL>SATL && FATL1<=FATL2)
      result=80;
   //--- Pattern 8
   if(cb_UsePattern8 && FATL>FATL1 && FATL1<=SATL1 && FATL>SATL && FATL1<=RFTL1 && FATL>RFTL)
      result=80;
   
   return result;
  }


4. Creamos el EA del seguimiento ataptativo del mercado

Después de crear el módulo de señal, podemos comenzar con la generación del EA. El proceso de la creación del EA a través del Asistente se describe detalladamente en este artículo. Durante la creación del EA, usé solamente un módulo de las señales comerciales creado más arriba. Además de eso, fue añadido un Trailing Stop con un número de puntos fijo. Durante la prueba de la estrategia, vamos a usar un lote fijo, lo que permitirá evaluar el número de señales generadas.





5. Prueba del EA

Después de crear el EA, podemos testear el método ataptativo del seguimiento del mercado en el Probador de estrategias. Durante la prueba, es obligatorio indicar el peso para la apertura de la posición en el nivel de 60 y el peso para el cierre de la posición en el nivel de 10.

5.1. Prueba sin el uso de Stop Loss, Take Profit, Trailing Stop

Para comprobar la calidad de las señales generadas por el EA, la primera prueba fue realizada sin usar Stop Loss, Take Profit, Trailing Stop. La prueba fue realizada en el timeframe H4 para 7 meses del año 2017.

Prueba 1

Prueba 1

Por desgracia, la primera simulación mostró las pérdidas en la aplicación de la estrategia sin el uso de los Stop Loss.

Prueba 1. Resultado

Prueba 1. Resultado

Prueba 1. Resultado

Prueba 1. Resultado

Prueba 1. Resultado 

El análisis detallado de las transacciones realizadas en el gráfico de precios muestra dos zonas problemáticas de la estrategia:

  1. El EA no consigue cerrar a tiempo las transacciones durante los retrocesos fuertes, lo que lleva a la pérdida del beneficio y el cierre desfavorable de las transacciones potencialmente rentables.
  2. El EA trabaja bien con los movimientos grandes, pero abre una serie de las transacciones no rentables en los movimientos de corrección (flat).

Prueba 1 Transacciones en el gráfico

5.2. Prueba con el uso de Stop Loss y Trailing Stop.

Para minimizar las pérdidas del primer punto, fue colocado el Stop Loss y aplicado el Trailing Stop.

Prueba 2

Prueba 2

Manteniendo las mismas condiciones, la segunda prueba mostró una reducción del tiempo de la retención de posición, un pequeño aumento de la parte de las transacciones rentables, y al final, obtuvimos una tendencia general en la dirección del beneficio. 

Prueba 2. Resultado

Prueba 2. Resultado

Prueba 2. Resultado

Prueba 2. Resultado

Prueba 2. Resultado

Sin embargo, la parte de las transacciones rentables fue de 39.26%. Y se mantuvo la segunda zona problemática (transacciones con pérdidas en el flat).

5.3. Prueba con el uso de las órdenes Stop.

Para reducir las pérdidas relacionadas con las series de las transacciones no rentables en los movimientos de flat, fue realizada las simulación con el uso de las órdenes Stop.

Prueba 3

Prueba 3

Como resultado, la tercera prueba mostró que la cantidad de las transacción se disminuyó casi dos veces, mientras que el beneficio general subió, y la parte de las transacciones rentables llegó a 44,57%.

Prueba 3. Resultado

Prueba 3. Resultado

Prueba 3. Resultado

Prueba 3. Resultado

Prueba 3. Resultado


Conclusión

En este artículo, ha sido examinado el método del seguimiento adaptativo del mercado. La simulación ha revelado la presencia del potencial en esta estrategia, pero, para usarla en el mercado real, es necesario eliminar algunos “cuellos de botella”. No obstante, el método es viable. Los archivos originales y los resultados de las pruebas se adjuntan al artículo.

Referencias

  1. «Especulador de divisas» (Валютный спекулянт), Diciembre de 2000 - Junio de 2001.
  2. Análisis de las características principales de las series cronológicas.
  3. Extrapolación del precio AR - indicador para MetaTrader 5
  4. Asistente MQL5: Cómo crear un modelo de señales de trading
  5. ¡Cree su propio robot de trading en 6 pasos!
  6. Asistente MQL5: Nueva versión

Programas usados en el artículo:

#
 Nombre
Tipo 
Descripción 
 1 Spectrum.mqh Librería de la clase Clase para estimar la densidad espectral de potencia del instrumento de prueba
 2 FLF.mqh Librería de la clase Clase para construir el filtro de paso bajo y filtración de los datos de origen
 3 SignalATCF.mqh Librería de la clase Módulo de señales comerciales para el método del seguimiento adaptativo del mercado
 4 ATCF.mq5 Asesor Experto Asesor Experto según el método del seguimiento ataptativo del mercado
 5 ACTF_Test.zip Archivo El archivo contiene los resultados del testeo del Asesor Experto en el Probador de Estrategias.