English Русский 中文 Español Deutsch 日本語
preview
Funcionalidades do assistente MQL5 que você precisa conhecer (Parte 6): transformada de Fourier

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

MetaTrader 5Testador | 23 agosto 2023, 09:46
261 0
Stephen Njuki
Stephen Njuki

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:

  • Produto Interno Bruto (PIB): Um dos indicadores mais importantes do crescimento econômico que mede o valor total de bens e serviços produzidos em um país durante um determinado período, que normalmente é um ano.
  • Dados de Emprego: Como a taxa de desemprego e/ou números de criação de empregos, podem fornecer insights sobre a saúde do mercado de trabalho. O aumento do desemprego ou o crescimento estagnado do emprego podem sinalizar uma economia enfraquecendo.
  • Dados de Produção Industrial: Isso poderia incluir o Índice de Produção Industrial, que mede a produção dos setores de manufatura, mineração e serviços públicos, podendo indicar a saúde geral da economia, Índice de Gerentes de Compras, Utilização da Capacidade, pedidos de bens duráveis, emprego na manufatura e muitos outros.
  • Dados de Confiança do Consumidor: Isso incluiria o Índice de Confiança do Consumidor, Índice de Sentimento do Consumidor da Universidade de Michigan, Índice de Confiança do Consumidor do Conference Board, Vendas no Varejo, Crédito ao Consumidor, para citar apenas alguns.
  • Dados de Taxas de Juros: As taxas de juro podem impactar o investimento empresarial e os gastos do consumidor, ambos os quais podem afetar o desempenho da economia. As taxas de juros crescentes tendem a diminuir o investimento e os gastos, enquanto taxas de juros em queda podem incentivar investimentos e gastos, fatores que tendem a afetar eventualmente o preço das ações de empresas listadas publicamente.
  • Dados de Inflação: Isso mede a taxa de aumento nos preços de bens e serviços e, assim, pode fornecer alguma clareza sobre o estado de uma economia. Alta inflação pode indicar uma economia superaquecida, enquanto baixa inflação pode sinalizar uma economia fraca. Esse também é outro conjunto de dados que pode influenciar as decisões do trader na compra de várias ações e, portanto, é uma fonte de dados chave.
  • Dados de Habitação: Isso poderia cobrir vendas de casas e inícios de construção e pode lançar luz sobre a saúde do mercado imobiliário, que é um componente importante da economia e pode ser relevante para uma determinada ação que um trader tenha em seu portfólio.

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

  • Relação Preço/Lucro (P/L): Esta métrica comum compara o preço das ações de uma empresa com seus lucros por ação (EPS) e pode ser usada para avaliar se o mercado está superestimando uma ação (com uma leitura alta) ou se o mercado está subestimando a ação quando a leitura geralmente está abaixo de 15 ou até 10, dependendo da geografia do mercado.
  • Rendimentos de Dividendos: Eles medem a quantidade de dividendos pagos por cada ação em relação ao preço da ação. Rendimentos de dividendos baixos podem sugerir uma ação supervalorizada, enquanto rendimentos de dividendos altos podem indicar subavaliação.
  • Indicadores Técnicos: Uma lista que inclui médias móveis, indicadores de momentum e indicadores de força relativa, pode ajudar a resumir a ação atual do preço de uma ação. Por exemplo, quando o preço de uma ação está sendo negociado acima de sua média móvel de 200 dias, isso pode indicar uma tendência altista, enquanto negociar abaixo da média móvel de 200 dias pode sinalizar uma tendência baixista; neste caso, nossos dados poderiam ser a diferença entre o preço e sua média móvel de 200 dias.
  • Amplitude do Mercado: Aqui, medimos o número de ações que estão avançando versus aquelas que estão em queda em um determinado mercado. Quando um alto número de ações está avançando, isso pode sugerir que o mercado está saudável, enquanto uma amplitude em declínio pode indicar fraqueza. Esses dados poderiam ser obtidos de terceiros que geralmente os agrupam com outros fluxos de dados por uma taxa única ou, em alguns casos, uma assinatura.
  • Volatilidade: Isso é medido por indicadores como o VIX e ajuda a avaliar o risco do mercado e o sentimento do investidor. Geralmente é positivamente correlacionado com risco de mercado e sentimento negativo.

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: 

  • Taxas de inadimplência: Taxas de inadimplência trimestrais ou anuais para um mercado bancário específico, digamos os EUA, podem ser usadas para analisar o risco de crédito nos EUA e, portanto, o desempenho do S&P 500.
  • Spreads de crédito: Dados diários ou semanais sobre spreads de crédito entre títulos corporativos e títulos do tesouro podem ajudar a avaliar o risco de crédito associado a mudanças nas percepções de mercado sobre solvência.
  • Inadimplências de empréstimos: Que não são a mesma coisa que taxas de inadimplência, podem ser obtidas mensal ou trimestralmente para um banco ou credor específico e usadas para examinar o risco de crédito associado ao portfólio de empréstimos deste banco, se um trader estiver considerando comprar ações desse banco em particular.
  • Classificações de crédito: Embora esses dados não sejam tão serializados como a maioria, ainda podem ser coletados ao longo de um período histórico razoável, trimestral ou anualmente para uma empresa específica, e usados para avaliar a solidez dos títulos comerciais de uma empresa ou até mesmo de seus títulos de longo prazo.
  • Credit Default Swaps (CDS): Que geralmente equivalem a um seguro do credor para seus empréstimos, podem ser obtidos diária ou semanalmente sobre os preços de seus contratos

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.

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/12599

Arquivos anexados |
TrailingFT_3_.mqh (8.72 KB)
TrailingFT_2_.mqh (8.72 KB)
TrailingFT_1_.mqh (8.84 KB)
Teoria das Categorias em MQL5 (Parte 8): Monoides Teoria das Categorias em MQL5 (Parte 8): Monoides
Esse artigo continua a série sobre a implementação da teoria da categoria em MQL5. Aqui, apresentamos os monoides como um domínio (conjunto) que distingue a teoria da categoria de outros métodos de classificação de dados ao incorporar regras e um elemento de equivalência.
Implementando um algoritmo de treinamento ARIMA em MQL5 Implementando um algoritmo de treinamento ARIMA em MQL5
Neste artigo, implementaremos um algoritmo que aplica o modelo integrado de autorregressão com média móvel (modelo Box-Jenkins) usando o método de minimização de função de Powell. Box e Jenkins afirmaram que a maioria das séries temporais pode ser modelada usando uma ou ambas das duas estruturas.
Redes neurais de maneira fácil (Parte 39): Go-Explore - uma abordagem diferente para exploração Redes neurais de maneira fácil (Parte 39): Go-Explore - uma abordagem diferente para exploração
Continuamos com o tema da exploração do ambiente no aprendizado por reforço. Neste artigo, abordaremos mais um algoritmo, o Go-Explore, que permite explorar eficazmente o ambiente durante a fase de treinamento do modelo.
Gestão de dinheiro de negociação Gestão de dinheiro de negociação
Neste artigo, veremos várias novas maneiras de criar sistemas de gerenciamento de dinheiro e identificar seus principais recursos. Hoje, existem algumas estratégias de gerenciamento de dinheiro para todos os gostos. Tentaremos considerar várias maneiras de administrar o dinheiro com base em diferentes modelos matemáticos de crescimento.