Funcionalidades do assistente MQL5 que você precisa conhecer (Parte 6): transformada de Fourier

Stephen Njuki | 23 agosto, 2023

Introdução

A transformada de Fourier é um método de decompor uma onda de pontos de dados em possíveis partes constituintes que foi introduzida por Joseph Fourier.  Integrar sobre todas as possíveis frequências na transformada de Fourier nos fornece um espectro de componentes porque desmembra a função original em seus constituintes, cada um correspondendo a um diferente componente de frequência.

A transformada de Fourier, por definição, varia de menos infinito até mais infinito:


onde F(w) é a transformada de Fourier da função f(t), i é a unidade imaginária, w é a frequência angular e e é a função exponencial.

Na prática, ao usar a transformada, o número de epiciclos é predeterminado para um número pequeno e gerenciável. Quanto mais epiciclos (frequências componentes) alguém usa, mais precisamente ele pode descrever a curva original, no entanto, em certo ponto, torna-se ineficiente, pois mais epiciclos não produzem qualquer diferença significativa na curva que está sendo descrita em partes.

Portanto, isso leva os usuários da transformada a optar por um número discreto finito n de epiciclos. E isso modifica ligeiramente a nossa fórmula acima.

Quando somamos todas as possíveis frequências, estamos somando a contribuição de cada uma à função original. Cada componente de frequência é representado por um número complexo que inclui informações de magnitude e fase. A magnitude representa a amplitude da onda, enquanto a fase representa a mudança no tempo da onda. Portanto, nossa equação modificada acima soma sobre n componentes e cada uma dessas n partes tem uma onda com vários valores em tempos t.

Ao resolver as partes constituintes, a chave é encontrar o f(t) de cada componente, que constitui tanto uma parte real quanto imaginária. O sistema Fourier reescreve qualquer função f(t) para o intervalo de 0 a 2 pi com números complexos como essa 'soma infinita'.  É 'infinito' entre aspas porque soma zero.


Com nossa equação acima, ao resolver, digamos, o coeficiente:  C 2 ,

Multiplicaríamos ambos os lados da equação com: e^-2it

Na integração, isso simplifica nossa equação para:



Assim, o 2 (e não o 2 em 2 pi!) pode ser substituído por n para obter qualquer outro coeficiente na equação f(t) acima. Todos esses cálculos são geridos pela classe 'CFastFourierTransform' que está listada no arquivo: 'Math\Alglib\fasttransforms.mqh', então tudo o que temos que fazer é usar esta biblioteca.


Aplicação

Antes de fazermos isso com exemplos muito específicos, pode ser útil primeiro ter uma visão mais ampla de como os traders podem se beneficiar desta habilidade de ter uma onda de pontos de dados dividida em partes constituintes. Há muitas aplicações. Aqui está uma possível lista curta:

  1. Analise de movimentos de preços de ações: Se coletarmos dados de preços de ações e os organizarmos em um formato de série temporal, poderíamos aplicar a Transformada de Fourier aos dados da série para obter seus componentes de frequência. A análise desses componentes de frequência separados para identificar padrões e tendências nos dados pode ajudar a tomar decisões de negociação mais informadas. Por exemplo, um trader pode perceber que uma determinada ação tem um pico recorrente em seu espectro de frequência em uma certa frequência, indicando um padrão repetitivo nos movimentos de preço da ação. Essa observação pode ser usada para comprar a ação quando estiver com um preço baixo e vendê-la quando estiver com um preço alto, baseado na expectativa de que o preço seguirá esse padrão observado. No entanto, com o tempo, isso precisa ser monitorado frequentemente para garantir que os padrões permaneçam aplicáveis.
  1. Analise de ciclos de longo prazo: Precisaríamos escolher entre um ciclo de negócios ou um ciclo de mercado. Se escolhermos um ciclo de negócios, nossas possíveis fontes de dados poderiam incluir:

Por outro lado, algumas fontes de dados de ciclos de mercado poderiam incluir:

Uma vez que coletamos nossos dados financeiros relevantes das fontes possíveis acima, os sequenciaríamos em uma série temporal e, em seguida, aplicaríamos a Transformada de Fourier para dividi-la em seus componentes de frequência. Analisar essas partes constituintes, digamos, procurando por ciclos repetitivos nos dados, poderia melhorar nossas decisões de negociação. Por exemplo, um trader pode usar isso para identificar um ciclo recorrente nos dados da taxa de juros que tende a durar vários anos e tem uma correlação positiva atrasada com sua ação ou ETF negociado. Armado com esse conhecimento, ele pode investir em posições de longo prazo quando o mercado está em um ponto baixo e manter posições de retração por períodos prolongados e só sair delas quando a correlação dos dados de juros se torna negativa ou prenuncia uma desaceleração.

  1. Processamento de Sinais: Ao analisar sinais, podemos considerar padrões de ondas de preço que ocorrem antes de grandes rompimentos, seja para cima ou para baixo. Por exemplo, uma fonte de dados mais específica aqui poderia observar apenas o padrão gartley no histórico de preços de uma ação específica, omitindo os demais dados. Esses dados de onda de preço seriam registrados como uma série temporal (mesmo que houvesse consideráveis lacunas, já que o padrão é raro). Uma Transformada de Fourier seria aplicada a cada onda dessa série. Depois, poderíamos estabelecer um limite de frequência para as ondas Fourier componentes (com base em nossas observações em relação aos rompimentos eventuais) e omitir aquelas que não atendem ao limite. Usaríamos então essas poucas ondas filtradas para fazer nossas projeções futuras. Este buffer de preço poderia ser para uma ação, paridade de moeda ou até mesmo uma commodity. O princípio seria o mesmo.
  1. Gestão de Risco: Se nos concentrarmos no risco de crédito, já que outros tipos de risco, como o risco de mercado, poderiam se sobrepor ao que já abordamos acima, estas poderiam ser nossas fontes de dados: 

e usados para analisar o risco de crédito associado a mudanças nas percepções de mercado sobre solvência. A análise de qual componente melhor se correlaciona com choques financeiros eventuais ou oscilações mais específicas de preços de ações, poderia ajudar no desenvolvimento de estratégias eficazes de gerenciamento de riscos.

  1. Precificação de Opções: Dados históricos sobre preço base, preço de exercício, tempo até o vencimento, volatilidade, taxas de juros e dividendos para opções podem ser obtidos de várias fontes, como por exemplo, o terminal Bloomberg. Observe como cada um desses conjuntos de dados é um 'componente de frequência' para o preço da opção. Com esses múltiplos conjuntos de dados, existem muitas maneiras de se abordar essa análise. Tenha em mente que não há um consenso per se sobre qual é o preço de uma opção em um determinado momento; o que temos são modelos de precificação de 'melhores práticas', como o Black-Scholes. No entanto, eles nem sempre são confiáveis. Uma abordagem possível seria simplesmente decompor o preço base em um período fixo antes do vencimento e observar qual componente de frequência melhor se correlaciona com a diferença entre o preço base e o preço de exercício no vencimento. Esta análise poderia ser útil para opções europeias, mas as opções americanas, visto que podem ser exercidas antes do vencimento, apresentam desafios mais complexos.
  1. Análise de Sentimento: Avançamos muito no que diz respeito à coleta de dados na web, e hoje o Software de Gerenciamento de Mídias Sociais é algo fundamental. Nomes como Zoho Social, Hootsuite e Khoros Marketing, para citar apenas alguns, estão rapidamente ganhando destaque como referências no mercado. Ficaram para trás os dias de apenas contar curtidas e descurtidas e encerrar o dia; atualmente, a análise de texto (e combinada com IA) permite que as empresas quantifiquem melhor o engajamento e satisfação dos clientes com seus produtos/serviços. Assim, muitos dados podem ser coletados. Como um negociador interessado em duas empresas rivais, você pode querer saber se existe alguma correlação entre o tempo de engajamento ao avaliar um produto e as vendas eventuais desse produto 3 ou 6 meses depois. Convertendo os dados de engajamento em uma série temporal e decompondo-os em partes constituintes, é possível identificar qual componente melhor se correlaciona ao nosso objetivo (neste caso, vendas futuras), e esse sistema orienta nossa decisão de comprar a ação e em que quantidade.
  1. Aprendizado de Máquina: A Transformada de Fourier para esta aplicação (e há várias outras) pode ajudar a vetorizar dados de entrada, decompondo-os em frequências constituintes. Se tivéssemos apenas diferentes ondas de preço de fechamento como dados de entrada, cada uma dessas ondas poderia ser decomposta em n ondas, onde cada nova onda agora faz parte de um vetor de ondas da antiga onda não dividida. Isso nos fornece mais informações identificadoras para qualquer novo ponto de dados que precisamos avaliar e permite uma comparação mais precisa com os dados já treinados ao avaliar uma onda desconhecida do que apenas a onda única original. Portanto, treinar esses dados vetorizados e compará-los aos dados de teste usando, por exemplo, a distância euclidiana, poderia ajudar a aprimorar as previsões do modelo.


Implementação

Para ilustrar a implementação da Transformada de Fourier em MQL5, vamos analisar a decomposição de uma série temporal de precificação de intervalo (altas menos baixas). Em seguida, examinaremos essas frequências constituintes e veremos se alguma delas, quando identificada por índice, tem uma correlação útil com as próximas mudanças nos intervalos de preço. Usaremos essas informações para orientar nosso ajuste de stop-losses de posição aberta em uma implementação personalizada da classe ‘CExpertTrailing’. Utilizaremos um sinal simples embutido listado em ‘SignalRSI.mqh’ e a gestão de dinheiro usará margem fixa.

 

Se listarmos nossa classe de trailing personalizada como abaixo. Ao recuperar os coeficientes reais e imaginários para a ‘função f(t)’, usamos uma instância da estrutura ‘a1_complex’ para armazenar essa informação após o processamento pela função ‘FFTR1D’. Para usar esses coeficientes, precisamos ‘integrá-los’ e, para isso, improvisei uma matriz ‘_output’. Esta matriz tem coeficientes para cada epiciclo em cada ponto de dados. Estamos usando 6 pontos de dados e 5 epiciclos. Além disso, nosso índice de ponto de dados de previsão ‘m_points-1’ é usado porque os ciclos de Fourier são repetitivos, então a próxima etapa seria a mais antiga do 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);
   }
//+------------------------------------------------------------------+


Na compilação com a classe de sinal RSI embutida e a gestão de dinheiro de margem fixa embutida, obtemos esses resultados para: EURJPY no período: 2022.01.01 a 2023.01.01 no período de tempo: 4 horas. Ao realizar este teste, não definimos metas de lucro nem usamos a configuração de stop loss padrão, portanto, ambas as entradas para esses são zero. Queremos que as saídas sejam determinadas inteiramente pela reversão do sinal ou pelo acionamento do stop loss definido pelo nosso stop de acompanhamento.


r_1


Para uma segunda implementação/comparativa, consideraremos a correlação da frequência constituinte com a amplitude mais alta com mudanças nos intervalos de preço, conforme descrito acima.

 

Esta implementação está listada abaixo:

//+------------------------------------------------------------------+
//|                                                   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);
   }
//+------------------------------------------------------------------+


Na compilação com os mesmos arquivos de sinal e gestão de dinheiro mencionados acima, o teste produz o seguinte relatório:


r_2


Uma implementação final, na qual usamos o componente de amplitude mínima e não o máximo, cujo código também está anexado a este artigo, nos fornece o relatório abaixo:


r_3


De nossos três relatórios de amostra, fica claro que alterar ligeiramente nosso sistema de stop de acompanhamento com sinais de entrada idênticos é significativo para os resultados nos relatórios.


Considerações finais

Em conclusão, analisamos o que é a Transformada de Fourier do ponto de vista de um trader leigo. Destacamos algumas das vastas possíveis aplicações desta transformada para os traders. Em seguida, passamos a demonstrar algumas implementações simples desta transformada em MQL5, focando no uso de previsões de volatilidade para gerenciar saídas de stop loss de posições abertas. Esta transformada tem muitas outras aplicações que não listei aqui, então o leitor é convidado a fazer algumas pesquisas para explorar estas. Além disso, o código compartilhado aqui não é um grail ou qualquer código 'pronto para conta ao vivo' para um EA, mas mais uma vez o leitor é encorajado a realizar sua própria diligência e descobrir o que funciona para ele/ela.