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

Características del Wizard MQL5 que debe conocer (Parte 6): Transformada de Fourier

MetaTrader 5Probador | 11 septiembre 2023, 16:06
339 0
Stephen Njuki
Stephen Njuki

Introducción

La transformada de Fourier es un método para descomponer una onda de puntos de datos en sus posibles partes componentes. Fue introducida por Joseph Fourier.  La integración de todas las frecuencias posibles en la transformada de Fourier nos ofrece un espectro de componentes, ya que divide la función original en constituyentes, cada uno de los cuales se corresponde con un componente de frecuencia distinto.

Por definición, la transformada de Fourier va desde menos infinito hasta más infinito:


donde F(w) es la transformada de Fourier de la función f(t), i es la unidad imaginaria, w es la frecuencia angular y e es la función exponencial.

Sin embargo, en la práctica, al utilizar la transformada, el número de epiciclos está predeterminado por un número pequeño con el que es conveniente trabajar. Cuantos más epiciclos (frecuencias de componentes) se utilicen, con mayor precisión podremos describir la curva original; sin embargo, en cierto punto este proceso se vuelve ineficiente, ya que más epiciclos no provocan ninguna diferencia significativa en la curva, cuyas partes describimos.

Por tanto, al realizar la transformación, tenemos que contentarnos con un número finito discreto n de epiciclos. Esto cambiará ligeramente nuestra fórmula anterior.

Cuando sumamos todas las frecuencias posibles, estamos sumando la contribución de cada una a la función original. Cada componente de frecuencia está representado por un número complejo que incluye información sobre amplitud y fase. La magnitud representa la amplitud de la onda, mientras que la fase representa el desplazamiento temporal de la onda. Entonces, nuestra ecuación anteriormente modificada suma n componentes, y cada una de estas n partes tiene una onda con diferentes valores en los momentos de tiempo t.

Al resolver las partes constituyentes, la clave consiste en encontrar f(t) de cada componente que forma tanto la parte real como la imaginaria. El sistema de Fourier reescribe cualquier función f(t) para el intervalo de 0 a 2 pi con números complejos como "suma infinita".  La expresión está entre comillas porque su suma es cero.


Utilizando la ecuación anterior al resolver, digamos, un coeficiente:  C2,

Multiplicamos ambos lados de la ecuación por: e-2it

En la integración, esto simplifica nuestra ecuación a:



Entonces 2 (¡no 2 en 2 pi!) puede reemplazarse por n para obtener cualquier otro factor en la ecuación f(t) anterior. Todos estos cálculos los realiza la clase CFastFourierTransform especificada en el archivo Math\Alglib\fasttransforms.mqh, por lo que lo único que necesitaremos hacer es usar esta biblioteca.


Aplicación

Antes de pasar a ejemplos específicos, puede resultar útil observar primero cómo los tráders pueden beneficiarse de la capacidad de descomponer una onda de puntos de datos en sus componentes. Existen muchas áreas posibles de aplicación. Aquí tenemos una posible lista breve:

  1. Análisis del movimiento de precio de las acciones: si recopilamos los datos del precio de las acciones y los organizamos en un formato de serie temporal, podremos aplicar una transformada de Fourier a los datos de la serie para obtener sus componentes de frecuencia. El análisis de estos componentes de frecuencia individuales para identificar patrones y tendencias en los datos puede ayudarnos a tomar decisiones comerciales más fundamentadas. Por ejemplo, un tráder puede notar que una determinada acción tiene un pico que se repite en su espectro de frecuencia a una determinada frecuencia, lo cual indica un patrón repetido en el movimiento del precio de la acción. Esta observación se puede usar para comprar una acción a un precio bajo y venderla a un precio alto basándose en la esperanza de que el precio seguirá el patrón observado. No obstante, con este enfoque, deberemos asegurarnos constantemente de que los patrones sigan siendo aplicables.
  1. Análisis de ciclos de largo plazo: deberemos elegir entre el ciclo económico y el ciclo de mercado. Si elegimos el ciclo económico, nuestras posibles fuentes de datos podrían incluir:

  • El Producto Interior Bruto (PIB): uno de los indicadores más importantes del crecimiento económico, mide el valor total de los bienes y servicios producidos en un país durante un periodo determinado, generalmente un año.
  • Dlos datos sobre el empleo: los datos sobre la tasa de desempleo y/o el número de puestos de trabajo creados pueden ofrecer información sobre el estado del mercado laboral. El aumento del desempleo o el estancamiento del crecimiento del mismo podrían indicar un debilitamiento de la economía.
  • Los datos de producción industrial: pueden incluir el índice de producción industrial, que mide la producción en los sectores manufacturero, minero y de servicios públicos y puede indicar la salud general de la economía, el índice de actividad empresarial, la utilización de la capacidad, los pedidos de bienes duraderos, el empleo manufacturero y muchos más.
  • Los datos de confianza del consumidor: el índice de confianza del consumidor, el índice de confianza del consumidor de la Universidad de Michigan, el índice de confianza del consumidor del Conference Board, el volumen de negocios minoristas, el crédito al consumo y muchos más.
  • Los datos sobre las tasas de interés: las tasas de interés pueden influir en la inversión empresarial y el gasto de los consumidores, lo cual puede afectar al rendimiento de la economía. Las tasas de interés más altas tienden a frenar la inversión y el gasto, mientras que la bajada de las tasas de interés puede alentar la inversión y el gasto, lo que en última instancia afecta el precio de las acciones de las empresas que cotizan en bolsa.
  • Los datos de inflación: miden la tasa de aumento de los precios de los bienes y servicios y, por tanto, pueden proporcionar cierta claridad sobre el estado de la economía. Una inflación alta puede indicar una economía sobrecalentada, mientras que una inflación baja puede indicar una economía débil. Este es otro conjunto de datos que puede influir en las decisiones de compra de un tráder para diversas acciones y, por lo tanto, supone una fuente clave de datos.
  • Los datos de la vivienda: incluye las ventas de viviendas y el inicio de nuevas construcciones, y también puede arrojar luz sobre el estado del mercado inmobiliario, que es un componente importante de la economía y puede resultar relevante para acciones específicas que un tráder tiene en su portafolio.

Algunas fuentes de datos del ciclo de mercado pueden incluir:

  • Precio/Ganancias (Price/Earnings, P/E): esta medida general compara el precio de las acciones de una empresa con sus ganancias por acción (earnings per share, EPS) y se puede utilizar para determinar si el mercado está sobrevalorando una acción (cuando es alta) o la está subestimando cuando el valor suele estar por debajo de 15 o incluso 10 dependiendo de la geografía del mercado.
  • Rendimiento de dividendos: mide la cantidad de los dividendos pagados por acción. Un rendimiento de dividendos bajo puede indicar que una acción está sobrevalorada, mientras que un rendimiento de dividendos alto puede indicar que está infravalorada.
  • Indicadores técnicos: se incluyen medias móviles, indicadores de impulso e indicadores de fuerza relativa. Puede ayudarnos a resumir el comportamiento actual del precio de las acciones. Por ejemplo, cuando el precio de una acción cotiza por encima de su media móvil de 200 días, esto puede indicar una tendencia alcista, mientras que una cotización por debajo de su media móvil de 200 días puede indicar una tendencia bajista, por lo que en este caso, nuestros datos pueden suponer el spread entre el precio y su media móvil de 200 días.
  • Amplitud del mercado: mide la cantidad de acciones que suben frente a las que bajan en un mercado determinado. Cuando una gran cantidad de acciones suben, esto puede indicar que el mercado está sano, mientras que una disminución en la amplitud puede indicar debilidad. Estos datos pueden obtenerse de defensores de fuentes que generalmente las ofrecen junto con otra información por una tarifa única o, en algunos casos, mediante suscripción.
  • Volatilidad: medida por indicadores como VIX, ayuda a evaluar el riesgo de mercado y el sentimiento de los inversores. Esto suele tener una correlación positiva con el riesgo de mercado y el sentimiento negativo.

Una vez hayamos recopilado los datos financieros relevantes de las posibles fuentes anteriores, los organizaremos en una serie temporal y luego aplicaremos una transformada de Fourier para descomponerlos en componentes de frecuencia. El análisis de estos componentes, por ejemplo, al buscar ciclos recurrentes en los datos, puede mejorar nuestras decisiones comerciales. Por ejemplo, un tráder puede usarlo para identificar un ciclo recurrente en los datos de las tasas de interés que generalmente dura varios años y tiene una correlación positiva rezagada con sus acciones o ETF negociados. Usando este conocimiento, un tráder puede invertir en posiciones a largo plazo cuando el mercado se encuentra en un punto bajo y mantener posiciones con reducción durante largos periodos de tiempo y solo salir cuando la correlación de los datos porcentuales se vuelva negativa o presagie una desaceleración.

  1. Procesamiento de señales: al observar las señales, podríamos analizar los patrones de ondas de precios que preceden a las grandes rupturas alcistas o bajistas. Por ejemplo, una fuente de datos concreta puede considerar solamente el patrón de Gartley en la historia de precios de una acción determinada, omitiendo otros datos. Los datos de estos precios de onda se registrarán como una serie temporal (aunque existirán brechas significativas, ya que el patrón es poco común). La transformada de Fourier se aplicará a cada onda de esta serie. Luego podríamos establecer un umbral de frecuencia para los componentes de la onda de Fourier (basándonos en nuestras propias observaciones con correlación con posibles rupturas) y omitir aquellos que no alcancen el umbral, utilizando estas pocas ondas filtradas para hacer nuestras predicciones. Este colchón de precios podría ser para una acción, una pareja de divisas o incluso una materia prima: el principio sería el mismo.
  1. Gestión de riesgos: los datos sobre el riesgo crediticio pueden resultar particularmente importantes para nosotros, ya que otros tipos de riesgo, como el riesgo de mercado, pueden superponerse con lo que ya hemos discutido anteriormente: 

  • Tarifas de incumplimiento Las tasas de incumplimiento trimestrales o anuales de un mercado bancario particular, digamos Estados Unidos, pueden usarse para analizar el riesgo crediticio estadounidense y, por lo tanto, el desempeño del S&P 500.
  • Spreads de crédito: los datos diarios o semanales sobre los spreads de crédito entre los bonos corporativos y del tesoro pueden ayudar a evaluar el riesgo crediticio asociado con los cambios en las percepciones del mercado sobre la solvencia.
  • La morosidad de préstamos (no debe confundirse con la tasa de incumplimiento): se puede obtener mensual o trimestralmente para un banco o prestamista específico y se utiliza para examinar el riesgo crediticio asociado con la cartera de préstamos de ese banco si un tráder está considerando comprar acciones de ese banco en particular.
  • Calificaciones crediticias: si bien estos datos no están tan serializados como la mayoría de los datos, aún pueden recopilarse durante un periodo histórico razonable trimestral o anual para una empresa en particular y usarse para evaluar el valor del papel comercial de una empresa o incluso sus bonos a largo plazo.
  • Credit default swaps (CDS): suelen constituir un seguro para el prestamista por su(s) préstamo(s). Los datos pueden obtenerse diaria o semanalmente a precios de contrato y usarse para analizar el riesgo crediticio vinculado con los cambios en las percepciones del mercado sobre la solvencia.

Los datos de cualquiera de estas fuentes se combinarán en una serie temporal, aplicándose luego una transformada de Fourier a los datos de la serie temporal para obtener los componentes de frecuencia. Analizar qué componente se correlaciona mejor con posibles shocks financieros o fluctuaciones más específicas del precio de las acciones puede ayudarnos a desarrollar estrategias efectivas de gestión de riesgos.

  1. Precios de opciones: los datos históricos sobre el precio básico, el precio de ejercicio, el tiempo hasta el vencimiento, la volatilidad, las tasas de interés y los dividendos de las opciones se pueden obtener de varias fuentes, como Bloomberg Terminal. Tenga en cuenta que cada uno de estos conjuntos de datos es el "componente de frecuencia" del precio de la opción. Estos conjuntos múltiples de datos permiten el análisis de muchas maneras. Deberá tener en consideración que no existe consenso sobre cuál es el precio de una opción en un momento dado. Contamos con los modelos de fijación de precios de las "mejores prácticas", como el modelo Black-Scholes, pero no siempre son fiables. Un enfoque podría simplemente consistir en descomponer el precio del básico durante un periodo fijo antes del vencimiento y ver qué componente de frecuencia se correlaciona mejor con la diferencia entre el precio básico y el precio de ejercicio al vencimiento. Este análisis puede resultar útil para las opciones europeas, pero las opciones estadounidenses presentan mayor dificultad porque pueden ejercerse antes de su vencimiento.
  1. Análisis de sentimiento: hemos recorrido un largo camino en lo que respecta al hallazgo de datos en la web y el software de gestión de redes sociales es esencial hoy en día. Marcas como Zoho Social, Hootsuite, Khoros Marketing y muchas más están ganando popularidad rápidamente. Atrás quedaron los días en los que bastaba con contar lo que nos gusta y lo que no nos gusta. Hoy en día, el análisis de texto (combinado con inteligencia artificial) permite a las empresas cuantificar mejor las interacciones de los clientes y la satisfacción con los productos/servicios. Es posible recopilar muchos datos. Como tráder interesado en dos empresas competidoras, es posible que desee saber si existe alguna correlación entre la duración de su participación en una revisión de producto y las posibles ventas del producto en 3 o 6 meses. Transformando los datos de interacción en una serie temporal y descomponiéndolos en sus componentes, podemos determinar cual de estos se adapta mejor a nuestro objetivo (en este caso, las ventas futuras), y este sistema luego guiará nuestra decisión respecto a la compra de acciones y el número de estas.
  1. Aprendizaje automático: la transformada de Fourier para esta aplicación (y muchas otras) puede ayudarnos a vectorizar nuestra entrada dividiéndola en frecuencias de componentes. Si tuviéramos diferentes ondas de cierre como entrada, cada una de esas ondas podría descomponerse en n ondas, donde cada nueva onda ahora sería parte del vector de onda de la antigua onda indivisa. Esto nos ofrecerá más información de identificación para cualquier punto de datos nuevo que necesitemos valorar y permitirá realizar una comparación (con los datos ya entrenados al estimar la onda desconocida) más precisa que si solo estuviéramos tratando con la onda única original. Por lo tanto, entrenar estos datos vectorizados y compararlos con los datos de prueba usando, por ejemplo, la distancia euclidiana puede ayudar a mejorar las predicciones del modelo.


Implementación

Para ilustrar la implementación de la transformada de Fourier en MQL5, analizaremos la descomposición de la serie temporal del rango de precios (máximos menos mínimos). Luego examinaremos estos componentes de frecuencia y veremos si alguno en particular identificado por el índice tiene una correlación útil con los siguientes cambios en el rango de precios. Usaremos esta información para ajustar los stop loss de las posiciones abiertas en la implementación personalizada de la clase CExpertTrailing. Asimismo, utilizaremos la señal incorporada simple especificada en SignalRSI.mqh, mientras que en la gestión de capital usaremos un margen fijo.

 

Si enumeramos nuestra clase final personalizada como se muestra a continuación, al obtener los coeficientes reales e imaginarios para la función 'f(t)', usaremos un ejemplar de la estructura 'a1_complex' para almacenar esta información después de ser procesada por la función 'FFTR1D'. Para usar estos coeficientes, necesitaremos "integrarlos". Para lograr esto, hemos pensado la matriz '_output'. Esta matriz tiene coeficientes para cada epiciclo en cada punto de datos: usaremos 6 puntos de datos y 5 epiciclos. También utilizaremos nuestro índice de puntos de datos de predicción 'm_points-1', ya que los ciclos de Fourier se repiten, por lo que la siguiente etapa será la más antigua del ciclo. 

//+------------------------------------------------------------------+
//|                                                   TrailingCT.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Math\Alglib\fasttransforms.mqh>
#include <Expert\ExpertTrailing.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Trailing Stop based on 'Fourier Transform' v3              |
//| Type=Trailing                                                    |
//| Name=CategoryTheory                                              |
//| ShortName=CT                                                     |
//| Class=CTrailingFT                                                |
//| Page=trailing_ct                                                 |
//| Parameter=Step,double,0.5,Trailing Step                          |
//| Parameter=Index,int,0,FT-Index                                   |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CTrailingFT.                                               |
//| Appointment: Class traling stops with 'Fourier Transform' v3     |
//|               relative-sets concepts.                            |
//| Derives from class CExpertTrailing.                              |
//+------------------------------------------------------------------+
#define     __PI 245850922/78256779

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CTrailingFT : public CExpertTrailing
  {
protected:
   CFastFourierTransform   FFT;
   
   //--- adjusted parameters
   
   double            m_step;                    // trailing step

   int               m_index;                    // the epicycle index

public:
   //--- methods of setting adjustable parameters
   
   
   
   //--- 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 bool      CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp);
   virtual bool      CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp);
   //---
                     CTrailingFT(void);
                    ~CTrailingFT(void);
   //--- methods of setting adjustable parameters
   void              Step(double value)                  { m_step=value;      }
   void              Index(int value)                    { m_index=value;     }

protected:
   
   double            ProcessFT(int Index);

  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CTrailingFT::CTrailingFT(void)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_TIME+USE_SERIES_SPREAD+USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CTrailingFT::~CTrailingFT(void)
  {
  }
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CTrailingFT::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertTrailing::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_index<0 || m_index>=5)
     {
      printf(__FUNCTION__+": index must be greater than 0 and less than epicycles");
      return(false);
     }

//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CTrailingFT::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertTrailing::InitIndicators(indicators))
      return(false);
//--- 
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for long position.          |
//+------------------------------------------------------------------+
bool CTrailingFT::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
      
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      double _ft=ProcessFT(_x);
      double _type=_ft/100.0;
      
      double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
      
      double _sl=m_low.GetData(_x)-(m_step*_atr);
      
      double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
      double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
      double pos_sl=position.StopLoss();
      double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
      
      sl=EMPTY_VALUE;
      tp=EMPTY_VALUE;
      if(new_sl>base && new_sl<level)
         sl=new_sl;
//---
   return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for short position.         |
//+------------------------------------------------------------------+
bool CTrailingFT::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
   
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      double _ft=ProcessFT(_x);
      double _type=_ft/100.0;
   
      double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
      
      double _sl=m_high.GetData(_x)+(m_step*_atr);
      
      double level =NormalizeDouble(m_symbol.Ask()+m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
      double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
      double pos_sl=position.StopLoss();
      double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
      
      sl=EMPTY_VALUE;
      tp=EMPTY_VALUE;
      if(new_sl<base && new_sl>level)
         sl=new_sl;
//---
      return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Fourier Transform                                                |
//| INPUT PARAMETERS                                                 |
//|     Index   -   int, read index within price buffer.             |
//| OUTPUT                                                           |
//|     double  -   forecast change in price                         |
//+------------------------------------------------------------------+
double CTrailingFT::ProcessFT(int Index)
   {
      double _ft=0.0;
      
      int _index=Index;//+StartIndex();
      
      m_close.Refresh(-1);
      
      double _a[];
      matrix _output;
      al_complex _f[];
      
      //6 data points, 5 epicycles
   
      ArrayResize(_a,6);ArrayInitialize(_a,0.0);
      _output.Init(6,5);_output.Fill(0.0);
      
      for(int p=0;p<6;p++)
      {
         _a[p]=m_close.GetData(_index+p)-m_close.GetData(_index+p+1);
      }
      
      FFT.FFTR1D(_a,5,_f);
       
      for(int p=0;p<6;p++)
      {
         for(int s=0;s<5;s++)
         {
            double _divisor=(1.0/5),_angle=(p);_angle/=6;
            _output[p][s]=(_divisor*_a[p]*MathExp(-2.0*__PI*(_f[s].im/_f[s].re)*_angle));
         }
      }
      
      double _close=m_close.GetData(_index)>m_close.GetData(_index+1);
      
      _ft=(_output[5][m_index]/fmax(m_symbol.Point(),fabs(_output[5][m_index])+fabs(_close)))*100.0;
      
      return(_ft);
   }
//+------------------------------------------------------------------+


Realizando la compilación con la clase de señal RSI incorporada y la gestión de capital de margen fijo incorporada, obtendremos los siguientes resultados para EURJPY con el periodo de 2022.01.01 a 2023.01.01 y H4. Al ejecutar esta prueba, no estableceremos un objetivo de beneficio y no utilizaremos un stop loss por defecto, por lo que ambos parámetros serán iguales a cero. Nuestra intención es que las salidas estén completamente determinadas por la reversión de la señal o la activación del stop loss fijado por nuestro trailing stop.


r_1


Para la segunda implementación/comparativa, analizaremos la correlación del componente de frecuencia con mayor amplitud con los cambios en los rangos de precios, como hemos indicado anteriormente.

 

Esta implementación se muestra a continuación:

//+------------------------------------------------------------------+
//|                                                   TrailingCT.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Math\Alglib\fasttransforms.mqh>
#include <Expert\ExpertTrailing.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Trailing Stop based on 'Fourier Transform' v3              |
//| Type=Trailing                                                    |
//| Name=CategoryTheory                                              |
//| ShortName=CT                                                     |
//| Class=CTrailingFT                                                |
//| Page=trailing_ct                                                 |
//| Parameter=Points,int,6,FT-Points                                 |
//| Parameter=Epicycles,int,5,FT-Epicycles                           | 
//| Parameter=Step,double,0.5,Trailing Step                          |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CTrailingFT.                                               |
//| Appointment: Class traling stops with 'Fourier Transform' v3     |
//|               relative-sets concepts.                            |
//| Derives from class CExpertTrailing.                              |
//+------------------------------------------------------------------+
#define     __PI 245850922/78256779

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CTrailingFT : public CExpertTrailing
  {
protected:
   CFastFourierTransform   FFT;
   
   //--- adjusted parameters
   
   double            m_step;                    // trailing step

public:
   //--- methods of setting adjustable parameters
   
   
   
   //--- 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 bool      CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp);
   virtual bool      CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp);
   //---
                     CTrailingFT(void);
                    ~CTrailingFT(void);
   //--- methods of setting adjustable parameters
   void              Step(double value)                  { m_step=value;      }

protected:
   
   double            ProcessFT(int Index);

  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CTrailingFT::CTrailingFT(void)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_TIME+USE_SERIES_SPREAD+USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CTrailingFT::~CTrailingFT(void)
  {
  }
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CTrailingFT::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertTrailing::ValidationSettings())
      return(false);
//--- initial data checks

//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CTrailingFT::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertTrailing::InitIndicators(indicators))
      return(false);
//--- 
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for long position.          |
//+------------------------------------------------------------------+
bool CTrailingFT::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
      
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      double _ft=ProcessFT(_x);
      double _type=_ft/100.0;
      
      double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
      
      double _sl=m_low.GetData(_x)-(m_step*_atr);
      
      double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
      double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
      double pos_sl=position.StopLoss();
      double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
      
      sl=EMPTY_VALUE;
      tp=EMPTY_VALUE;
      if(new_sl>base && new_sl<level)
         sl=new_sl;
//---
   return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for short position.         |
//+------------------------------------------------------------------+
bool CTrailingFT::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
   
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      double _ft=ProcessFT(_x);
      double _type=_ft/100.0;
   
      double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
      
      double _sl=m_high.GetData(_x)+(m_step*_atr);
      
      double level =NormalizeDouble(m_symbol.Ask()+m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
      double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
      double pos_sl=position.StopLoss();
      double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
      
      sl=EMPTY_VALUE;
      tp=EMPTY_VALUE;
      if(new_sl<base && new_sl>level)
         sl=new_sl;
//---
      return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Fourier Transform                                                |
//| INPUT PARAMETERS                                                 |
//|     Index   -   int, read index within price buffer.             |
//| OUTPUT                                                           |
//|     double  -   forecast change in price                         |
//+------------------------------------------------------------------+
double CTrailingFT::ProcessFT(int Index)
   {
      double _ft=0.0;
      
      int _index=Index;//+StartIndex();
      
      m_close.Refresh(-1);
      
      double _a[];
      matrix _output;
      al_complex _f[];
      
      //6 data points, 5 epicycles
   
      ArrayResize(_a,6);ArrayInitialize(_a,0.0);
      _output.Init(6,5);_output.Fill(0.0);
      
      for(int p=0;p<6;p++)
      {
         _a[p]=m_close.GetData(_index+p)-m_close.GetData(_index+p+1);
      }
      
      FFT.FFTR1D(_a,5,_f);
       
      for(int p=0;p<6;p++)
      {
         for(int s=0;s<5;s++)
         {
            double _divisor=(1.0/5),_angle=(p);_angle/=6;
            _output[p][s]=(_divisor*_a[p]*MathExp(-2.0*__PI*(_f[s].im/_f[s].re)*_angle));
         }
      }
      
      double _close=m_close.GetData(_index)>m_close.GetData(_index+1);
      
      int _max_index=0;
      double _max=fabs(_output[5][_max_index]);
      for(int s=0;s<5;s++)
      {
         if(_max<fabs(_output[5][s]))
         {
            _max_index=s;
            _max=fabs(_output[5][s]);
         }
      }
      
      _ft=(_output[5][_max_index]/fmax(m_symbol.Point(),fabs(_output[5][_max_index])+fabs(_close)))*100.0;
      
      return(_ft);
   }
//+------------------------------------------------------------------+


Al realizar la compilación con los mismos archivos de señal y gestión de capital de antes, la ejecución de la prueba produce los siguientes resultados:


r_2


La implementación final, en la que usaremos el componente de amplitud mínima en lugar del máximo, cuyo código también se adjunta a este artículo, arrojará el siguiente informe:


r_3


De nuestros tres informes se desprende que un ligero cambio en nuestro sistema de trailing stop con entradas idénticas muestra una influencia significativa en los resultados.


Conclusión

Hoy hemos analizado qué supone la transformada de Fourier desde el punto de vista de un tráder no especialista. También hemos descrito algunas de las amplias aplicaciones posibles de esta transformación para los tráders. Luego hemos mostrado varias implementaciones simples de esta transformación en MQL5, centrándonos en el uso de pronósticos de volatilidad para controlar el cierre de posiciones abiertas con stop loss. Esta transformación tiene muchas otras aplicaciones que no hemos enumerado aquí. El lector podrá estudiarlas por su cuenta. Huelga decir que el código aquí mostrado no es la panacea y no puede considerarse una herramienta lista para trabajar en una cuenta real en forma de asesor. Le rogamos que muestre la debida prudencia y, antes que nada, determine qué es lo más adecuado para usted.

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

Archivos adjuntos |
TrailingFT_3_.mqh (8.72 KB)
TrailingFT_2_.mqh (8.72 KB)
TrailingFT_1_.mqh (8.84 KB)
Redes neuronales: así de sencillo (Parte 41): Modelos jerárquicos Redes neuronales: así de sencillo (Parte 41): Modelos jerárquicos
El presente artículo describe modelos de aprendizaje jerárquico que ofrecen un enfoque eficiente para resolver problemas complejos de aprendizaje automático. Los modelos jerárquicos constan de varios niveles; cada uno de ellos es responsable de diferentes aspectos del problema.
Redes neuronales: así de sencillo (Parte 40): Enfoques para utilizar Go-Explore con una gran cantidad de datos Redes neuronales: así de sencillo (Parte 40): Enfoques para utilizar Go-Explore con una gran cantidad de datos
Este artículo analizará el uso del algoritmo Go-Explore durante un largo periodo de aprendizaje, ya que la estrategia de elección aleatoria puede no conducir a una pasada rentable a medida que aumenta el tiempo de entrenamiento.
Redes neuronales: así de sencillo (Parte 42): Procrastinación del modelo, causas y métodos de solución Redes neuronales: así de sencillo (Parte 42): Procrastinación del modelo, causas y métodos de solución
La procrastinación del modelo en el contexto del aprendizaje por refuerzo puede deberse a varias razones, y para solucionar este problema deberemos tomar las medidas pertinentes. El artículo analiza algunas de las posibles causas de la procrastinación del modelo y los métodos para superarlas.
Implementando el algoritmo de aprendizaje ARIMA en MQL5 Implementando el algoritmo de aprendizaje ARIMA en MQL5
En este artículo, implementaremos un algoritmo que aplica un modelo autorregresivo de media móvil integrada (modelo Box-Jenkins) utilizando el método de minimización de la función de Powell. Box y Jenkins argumentaron que la mayoría de las series temporales se pueden modelar con una o ambas estructuras.