Examinemos na prática o método adaptativo de acompanhamento do mercado

4 outubro 2017, 07:53
Dmitriy Gizlyk
0
1 056

Introdução

Este artigo apresenta uma estratégia de negociação que foi descrita pela primeira vez por Vladimir Kravchuk na revista rusa Especulador de moedas [Валютный спекулянт] em 2001 e 2002. O sistema é baseado no uso de filtros digitais e na avaliação espectral de séries temporais (cronológicas) discretas.

O gráfico real contendo as mudanças nas cotações pode ter uma forma arbitrária. Em matemática, tais funções são chamadas de não-analíticas. No entanto, o famoso teorema de Fourier diz que qualquer função num intervalo de tempo finito pode ser representada pela soma infinita de funções senoidais. Portanto, quaisquer sinais temporais podem ser representados exclusivamente por funções de frequência, que são chamadas seus espectros de frequência.

Para os sinais de não-aleatórios, a transição a partir da descrição temporal para a de frequência (isto é, o cálculo do espectro de frequências) é realizada por meio de uma transformada de Fourier. Os processos aleatórios são apresentados pela densidade espectral do processo, que é a transformada de Fourier da sua função de autocorrelação.

1. Aspectos teóricos da estratégia

A filtragem é a mudança no espectro de frequencia do sinal para a direção certa. Tal transformação pode aumentar ou diminuir as componentes frequenciais num intervalo específico, suprimir ou isolar qualquer uma delas. O filtro digital é um sistema digital para transformar sinais, definidos apenas em momentos discretos.

Há certos aspectos importantes ao trabalhar com filtros digitais e séries temporais discretas. 

Em primeiro lugar, a maioria das ferramentas técnicas mais populares (MA, RSI, Momentum, Stochastic, etc.) são baseadas nas alterações no espectro de frequência do sinal e, portanto, são filtros digitais. O ganho de sua função de transferência depende da frequência. Porém poucas pessoas refletem sobre essa função de transferência. É por isso que a maioria dos usuários não sabem em qual direção muda o espectro de frequência do sinal e, portanto, não entendem a natureza do impacto do indicador sobre o sinal. isso complica a configuração do indicador e o modo de tratar os sinais.

Em segundo lugar, o movimento das cotações sempre aparece como um sinal discreto, cujas propriedades gerais devem ser levadas em conta no desenvolvimento de indicadores técnicos. Assim, por exemplo, o espectro do sinal discreto é sempre uma função periódica. Se essa propriedade é ignorada, você pode obter uma distorção da série temporal de entrada .

Em terceiro lugar, a densidade espectral dos movimentos de preços é bem desigual entre os mercados. Neste caso, o melhor para o usuário é configurar os parâmetros dos indicadores, ou seja, ele deve selecionar parâmetros arbitrários e testar sua viabilidade na prática.

Às vezes acontece que um indicador já otimizado (ou EA) que vem tendo boa reputação mostra resultados pobres hoje. Isto tem a ver com a série temporal não-estacionária. Na prática, quando se comparam as duas estimativas, calculadas em diferentes timeframes para um só mercado, muda a forma da amplitude dos picos espectrais. Isto pode ser interpretado como uma manifestação do efeito Doppler, quando a fonte de uma onda harmônica se move em relação a um receptor, ela muda seu comprimento. Isso mais uma vez prova a existência do movimento de tendência no mercado.

O objetivo do método adaptativo de acompanhamento do mercado consiste em encontrar as ferramentas técnicas mínimas ​​que criem um algoritmo de negociação com um rendimento máximo, mas com o mínimo risco. Para isso, são realizadas várias etapas.

  • Estuda-se a composição espectral das flutuações de preços para um mercado particular.
  • De maneira adaptativa são configurados os filtros digitais não-recursivos. O resultado deste procedimento é um conjunto de respostas ao impulso otimizadas.
  • Filtra-se a série temporal de entrada, e é definido o conjunto de indicadores discutidos mais adiante neste artigo.
  • Desenvolve-se o algoritmo de negociação.
O método adaptativo pode ser aplicado a qualquer mercado. Mas é necessário ter em mente que a capitalização e liquidez do mercado escolhido afetará o tamanho máximo de uma posição aberta sem perda de rendimento. 

1.1. Selecionando o método de análise espectral

O desenvolvimento de um sistema de negociação de acordo com o método adaptativo de acompanhamento do mercado começa com o estudo do espectro do movimento do preço de um certo instrumento. É óbvio que a eficiência final de todo o sistema depende dos resultados desta fase.

Pareceria que a solução se consegue por si só, isto é, é necessário realizar uma análise espectral ou harmônica. Mas qual o método a escolher? Hoje, existem duas classes de métodos de análise espectral principais, isto é, paramétricos e não paramétricos.

Métodos de análise espectral paramétricos são práticas, em que é definido um certo modelo de densidade espectral e são avaliados seus parâmetros com base nos resultados da observação do processo correspondente num período limitado. Além disso, o modelo original pode ter o mais diverso aspecto.

Em particular, o modelo inicial pode ser a densidade espectral da série temporal como uma função racional. Em tal caso, é possível distinguir o modelo autorregressivo, o modelo de média móvel e o modelo autorregressivo de média móvel. Consequentemente, na avaliação dos parâmetros do modelo, serão utilizados diferentes abordagens metodológicas.

Além disso, para resolver este problema, podemos usar o princípio variacional e o correspondente recurso de avaliação da qualidade. Aqui, os multiplicadores de Lagrange realizarão o papel de parâmetros avaliados. Tal método é utilizado na avaliação da densidade espectral de acordo com o método da máxima entropia, onde é necessário maximizar a entropia do processo segundo os valores individuais conhecidos da função de correlação.

Métodos não paramétricos de análise espectral, ao contrário dos paramétricos, não conta com modelos pré-definidos. Entre eles, o método mais popular é aquele em que na fase inicial do processo é determinada a periodicidade do processo, isto é, o módulo quadrado da transformada de Fourier. Depois disso, o problema se resume à escolha da janela adequada que satisfará certos requisitos.

O método de Blackman-Tukey também é amplamente utilizado, nele, para a série temporal examinada, encontra-se a transformada de Fourier da estimativa ponderada da sequência de correlação.

Outra abordagem consiste em reduzir a avaliação da densidade espectral da série temporal à solução de uma equação integral fundamental, que descreve a transformada de Fourier da série temporal estudada por meio de um processo aleatório com incrementos ortogonais.

O autor do sistema de negociação proposto acredita que é impossível avaliar qualitativamente a densidade espectral das flutuações nas cotações usando métodos clássicos não paramétricos de estimação espectral baseados no cálculo da transformada discreta de Fourier das séries temporais. A única solução é utilizar métodos paramétricos de análise espectral, que são capazes de obter uma avaliação consistente da densidade espectral em relação à amostra de tempo discreta, em que o processo já é estacionário (ele também se pode tornar estacionário excluindo a tendência linear). Entre a variedade de métodos paramétricos de estimação espectral, talvez, aquele que merece mais atenção é o método de máxima entropia.

1.2. Ferramentas de análise técnica usadas

A principal diferença da estratégia apresenta está na linha de tendência adaptativa. Sua direção é o indicador de direção da tendência atual.

Linha de tendência adaptativa é uma componente de baixa frequência da série temporal de entrada. Ela é obtida graças ao filtro passa-baixo. Quanto menor a frequência de corte fc do filtro passa-baixo, mais ajustada é a linha de tendência.

Entre os pontos da linha de tendência adaptativa existe uma ligação interna, cuja força é inversamente proporcional à distância entre eles. Não há ligação apenas entre os valores dos pontos, cuja distância entre eles é igual ou superior ao assim chamado intervalo de Nyquist TN=1/(2 fc). Por conseguinte, com a diminuição da frequência de corte do filtro esta ligação aumenta e o ponto de inversão de tendência se afasta.

Para determinar a tendência do sistema de negociação, usam-se duas linhas de tendência adaptativas com diferentes períodos.

FATL (Fast Adaptive Trend Line) é a linha de tendência adaptativa rápida. Para sua plotagem, é necessário o filtro passa-baixo. Ele suprime o ruído de alta frequência e os ciclos de mercado com um período muito curto de oscilação.

SATL (Slow Adaptive Trend Line) é a linha de tendência adaptativa lenta. Para sua plotagem, é necessário o filtro passa-baixo 2. Ao contrário do filtro passa-baixo 1, ele transmite ciclos de mercado com um longo período de oscilação.

Os parâmetros do filtro descrito acima (frequência de corte fc e atenuação σ na banda de rejeição) são calculados a partir das estimativas de espectro do nosso instrumento de interesse. Filtro passa-baixo 1 e filtro passa-baixo 2 fornecem atenuação na banda de rejeição não inferior a 40 dB. Seu uso é não tem nenhum efeito sobre a amplitude e a fase do sinal de entrada na banda de passagem. Esta propriedade dos filtros digitais fornece supressão de ruído eficaz e, em comparação com o MA simples, produz menos alarmes falsos.

Do ponto de vista matemático, o valor FATL(k) é o valor esperado do preço Close(k), onde k é o número do dia de negociação.

RFTL (Reference Fast Trend Line)RSTL (Reference Slow Trend Line) são as linhas de referência rápida e lenta. Eles envolvem os valores emitidos pelos filtros digitais passa-baixo 1 e 2 em resposta ao sinal de entrada, e tomados com um atraso igual ao intervalo de Nyquist correspondente.

FTLM (Fast Trend Line Momentum) e STLM (Slow Trend Line Momentum) mostram os deslocamentos do FATL e do SATL. São calculados da mesma forma como o indicador Momentum, mas, em vez de preços de fechamento, são utilizadas linhas de tendência ajustadas por filtragem. Como resultado, as linhas são mais suaves e mais regulares do que estamos acostumados a ver no Momentum.

As linhas FTLM e STLM são calculadas de acordo com as regras da matemática discreta. Esta é a diferença entre dois pontos adjacentes e independentes, limitados pela banda do processo. No cálculo convencional do Momentum, estas exigência são, muitas vezes, menosprezadas, levando a distorções fatais no espectro do sinal de entrada.

RBCI (Range Bound Channel Index) é o índice de canal, limitado em largura de banda. É calculado pelo filtro de banda, que inclui as seguintes tarefas:

  • exclusão da tendência de baixa frequência, formada a partir das componentes espectrais de baixa frequência com períodos maiores do que T2 = 1/fc2;
  • remoção de ruído de alta frequência gerado a partir dos componentes espectrais de alta frequência com períodos mais pequenas do que o T1 = 1/fc1.

Períodos Т1 e Т2 são selecionados de modo a satisfazer a condição Т2 > T1. Ao mesmo tempo, as frequências de corte fc1 e fc2 devem ser tais que todos os ciclos de mercado dominantes caiam em consideração.

Simplesmente, RBCI(k) = FATL(k) - SATL(k). De fato, quando o RBCI se aproxima de seus extremos locais, os preços se aproximam da borda superior ou inferior do canal de negociação (dependendo se é um valor máximo ou mínimo, respectivamente).

PCCI (Perfect Commodity Channel Index) é o índice de canal de mercadorias perfeito. A fórmula para seu cálculo é PCCI(k) = close(k) – FATL(k).

Seu método de cálculo é semelhante ao cálculo do índice de canal de mercadorias CCI. De fato, o CCI é a diferença normalizada entre o preço atual e a sua média móvel, enquanto o PCCI é a diferença entre o preço de fechamento do dia e sua expectativa matemática (que, como vimos acima, é feita a partir dos valores do FATL).

Assim, o índice PCCI é uma componente de alta frequência de flutuações de cotações, normalizada pelo seu desvio padrão.

Exemplo de indicadoresExemplo de indicadores


1.3. Regras de Interpretação para os sinais dos indicadores.

Especificamos os princípios básicos do sistema de negociação.

  • O sistema pertence aos de tendência, com negociação de acordo com a tendência. A tendência identificada usando o SATL.
  • Pontos de entrada são determinados de acordo com as características dinâmicas das tendências rápida e lenta FTLM e STLM.
  • O cálculo envolve as atuais condições de mercado (neutralidade, sobrecompra, sobrevenda, extremos locais), que são determinadas pelo índice RBCI.
  • A direção da entrada no mercado é determinada pelos indicadores de tendência. Você pode fazer isso usando osciladores só se houver fase de correção.
  • A colocação de ordens stop é obrigatória (nos índices RBCI, PCCI e volatilidade do mercado).

Os instrumentos acima referidos devem ser interpretados segundo as regras a seguir.

  • Se a linha do SATL aponta para cima, o mercado se encontra numa tendência ascendente, se aponta para baixo, descendente. O surgimento de extremos locais indica que a tendência começa a se manifestar. O cruzamento com o RSTL é um indício de que a tendência se desenrolou completamente. Ao acontecer isso, o STML muda de caractere.
  • O fato da linha do SATL ser horizontal ou quase horizontal indica que existe uma fase de correção no mercado.
  • STLM é positivo para a tendência de alta é negativo, para a de baixa. Ele é considerado como um dos principais indicadores. Seus extremos locais sempre anunciam o surgimento dos respectivos extremos do SATL. O valor absoluto do STLM é diretamente proporcional à força da tendência. O fato de o STLM e SATL se moverem na mesma direção indica que a tendência se torna mais forte. A existência de várias tendências prova o enfraquecimento da tendência. A linha horizontal do STLM indica que a tendência se formou definitivamente.
  • Se as linhas de tendência rápida e lenta (FATL e SATL) estão na mesma direção, a força da tendência é alta. Caso contrário, mercado está consolidado ou na etapa de correção. 
  • O fato de as linhas do FATL e SATL começarem ir na mesma direção significa que a tendência se desenrolou. Se a direção se junta reiteradamente após ir em várias direções, a correção do mercado acaba, e as cotações começam a se moverem na direção do SATL.

A partir dessas regras, formulamos os sinais de negociação principais.

  1. В начале долгосрочного тренда появляется надежный разворотный сигнал: o fato de o STLM cair indica a convergência entre a linha de tendência lenta adaptativa e a de suporte (SATL e RSTL). Durante a formação do sinal, aumenta a volatilidade dos preços agudamente. Isso é um sinal de que é a hora da mudança de tendência. Por isso, ao escolher o ponto de abertura da transação, é necessário ter em conta o PCCI. Quando o sinal é de baixa, venderemos, se, para o fechamento, o último candle do oscilador PCCI se encontrar acima do nível de -100. Se o o PCCI estiver abaixo do nível de -100, não abriremos a transação, mas sim esperaremos o oscilador ultrapassar este patamar.

  2. O próximo sinal indica a continuação da tendência fortalecida e formada depois de uma breve correção. Volatilidade neste caso, como regra, é mais fraca do que durante a inversão de tendência. Portanto, as condições para a formação do sinal são mais rigorosas e, ao mesmo tempo, o próprio sinal é mais robusto.
    Negociamos, se os indicadores FATL, FTLM e RBCI se deslocarem de foma síncrona. Sinais falsos são filtrados pelo indicador STLM (seu valor absoluto aumenta ou mantem-se inalterado). O fato de o STLM diminuir anuncia a aproximação entre o SATL e o RSTL. Ao acontecer isso, imediatamente após surgir o sinal de baixa do RBCI, verifica-se se o mercado está sobrevendido. Escolhe-se o preço de entrada no mercado que seja igual ou melhor em relação ao preço Open da seguinte barra após a chegada do sinal.

  3. Este sinal é baseado na quantidade de ciclos ativos numa banda de frequências, especificada pelo índice RBCI. Não são levados em conta nem a direção da linha do STLM nem como o SATL converge/diverge com o RSTL. A única coisa importante é se o valor do STLM é positivo ou negativo, o que indicaria a direção da tendência principal, formada no mercado. Filtro adicional: direção e comportamento da linha do FATL.
    A geração do sinal acorre quado, durante uma tendência de longo prazo neutra ou descendente, o ciclo de onda composto alcança o máximo local na zona de sobrecompra forte. Durante a fase de correção, o potencial do movimento proveniente dos ciclos de mercado será superior ao potencial do movimento devido à volatilidade. Se a tendência é formada, o potencial do movimento - com base nos ciclos de mercado - surge com o potencial da tendência de longo prazo.
    Escolhe-se uma abertura da transação que seja igual ou melhor em relação ao preço Open da seguinte barra após a chegada do sinal.

  4. A base do sinal consiste em duas divergências, isto é, entre as direções do RBCI e a linha do FATL, bem como entre os índices RBCI e FTLM. Se, durante certo período, o FATL e os índices RBCI e FTLM se deslocarem em diferentes direções, nós voltaremos para a fase de espera. O sinal de baixa consta do mínimo do FTLM, quando o FATL e o RBCI não mudam de direção. No gráfico, isto parece um "aceno" do FTLM na direção do FATL.
    Na maioria das vezes, vemos o sinal perto do ponto final da tendência de queda rápida (valor do FTLM próximo de 0). O sistema gera um sinal bastante preciso para um movimento de tendência curto.
    Isso é um o sinal importante que antecede à inversão da tendência.
    Escolhe-se o preço de entrada no mercado que seja igual ou melhor em relação ao preço Open da seguinte barra após a chegada do sinal.

  5. O siinal é gerado durante uma tendência longa. Os índices RBCI e PCCI atingem os valores de sobrevenda do mercado simultaneamente (para uma tendência de baixa). Geralmente, tais sinais são formados na última fase da tendência, quando as cotações de repente pulam na direção oposta e, depois, novamente "arrebentam" no sentido da tendência principal, que ainda está forte.
    Escolhe-se o preço de entrada no mercado que seja igual ou melhor em relação ao preço Open da seguinte barra após a chegada do sinal.

  6. Na formação da tendência de baixa de longo prazo (SATL cai, mas STLM ainda se mantem positivo), o índice PCCI alcança um valor superior a 100 (zona sobrevenda do mercado). O sinal de reversão é baseado no uso de alta volatilidade do mercado no momento da formação da tendência.
    Escolhe-se o preço de entrada no mercado que seja igual ou melhor em relação ao preço Open da seguinte barra após a chegada do sinal.

  7. Um forte sinal de uma inversão de tendência é observado após a primeira correção técnica para cima, depois de que a linha do FATL é quebrada pela linha do SATL de cima para baixo. Após isso, vendemos. O máximo local do FATL é um indicio de que esta correção técnica é concluída.
    O preço de venda é superior ou igual ao preço de abertura do seguinte candle após a chegada do sinal.

  8. E, finalmente, mais um sinal de reversão é formado quando dois cruzamentos ocorrem simultaneamente, isto é, entre as linhas adaptativas rápida e lenta do FATL, bem como entre o FATL e o RFTL (se houver o rompimento para baixo, vendemos, se a quebra for para cima, compramos). Este sinal marca o a fratura violenta da tendência anterior que já está enfraquecida. O preço de venda é superior ou igual ao preço de abertura do seguinte candle após a chegada do sinal.

2. Construímos os filtros passa-baixos

Agora que já foram estabelecidos os principais aspectos da estratégia, é hora de abordar a parte prática do trabalho. E, claro, vamos começar o trabalho com a construção do filtro de baixa frequência, porque é desses filtros são a base da estratégia.

Para construirmos o filtro passa-baixos, precisamos definir seus principais parâmetros: частотой среза и затуханием. O autor da estratégia indica claramente que o filtro deve fornecer atenuação na banda de latência de pelo menos 40 dB, é por isso que, para definir a frequência de corte, necessitamos realizar uma análise espectral dos dados de preços do instrumento.

Como mencionado acima, a estimativa da densidade espectral foi levada a cabo pelo autor utilizando o método da máxima entropia. Este método se aplica aos paramétricos e é realizado por um modelo matemático. O modelo matemático será construído pelo método de auto-regressão.

2.1. Análise da densidade espectral.

Para estimar a densidade espectral, criaremos a classe CSpertrum (o código completo pode ser encontrado em anexo). Ao inicializar a classe, nós transferiremos o nome do instrumento, o timeframe de trabalho e o número de barras para análise.

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

Realizamos o cálculo das funções de auto-regressão e densidade espectral pelo procedimento proposto por Victor. Aqueles que desejam se familiarizar com o algoritmo podem ler este artigo. O resultado da análise espectral da área é uma matriz de dados, que, para maior clareza, pode se representada como um gráfico.

Densidade espectral do par EURUSD

Aumentos esporádicos no gráfico mostram o aumento na potência do sinal a uma certa frequência. Precisamos encontrar esses aumentos para determinar as respostas em frequência de nossos filtros. Para fazer isso, à nossa classe CSpecrum adicionamos a função public GetPeriods, que, quando soliditado, retorna os períodos FATL e SATL.

Dentro da função, determinaremos os aumentos como fractais. Para o período do filtro SATL, determinamos o primeiro aumento, que exibe os impulsos com frequência mais baixa. Para o FATL encontramos o impulso com maior frequência e uma potência superior a -40 dB, após eliminar os impulsos de ruído com uma pequena amplitude e alta frequência. Se a função não encontrar períodos para ambos os filtros, ela retornará false.

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

2.2. Cálculo dos coeficientes filtro passa-baixo.

Como já definimos as frequências dos filtros, é hora de construir nossos filtros passa-baixos. Está é a fórmula geral do filtro digital


Onde y é a saída do filtro; x é a matriz de dados de origem; hk são as respostas ao impulso; N é o número de respostas ao impulso.

Dados de preços são usados como valores iniciais, enquanto nós definimos o número de respostas ao impulso igual ao intervalo de Nyquist. Além disso, temos de calcular as respostas ao impulso. Respostas ao impulso ideais para o filtro passa-baixo podem ser calculadas de acordo com a fórmula


Onde fc e wc são a frequência de corte.

Infelizmente, nosso mundo está longe de ser ideal. Por isso, precisamos de uma resposta ao impulso real. Para seu cálculo precisamos da função de peso w(n). Existem várias funções-peso. Eu costumo usar a função Blackman que tem a forma


Onde N é o número de elementos do filtro.

Para obter uma resposta ao impulso real, é necessário multiplicar a resposta ao impulso ideal com a função-peso correspondente


Agora que já temos definidas as fórmulas de cálculo, criamos a classe CFLF, nela calcularemos as respostas ao impulso e filtraremos os dados recebidos. Para calcular o coeficiente das respostas ao impulso, criamos a função public CalcImpulses, para a qual transferimos o período de filtragem. Em diante, o algoritmo da função repete as fórmulas mencionadas acima. Em seguida, normalizamos as respostas ao impulso, levando-as à quantidade de "1".

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

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

Assim que recebermos as respostas ao impulso, podemos avançar para o cálculo dos valores dos indicadores utilizados. Será conveniente obter o valor dos indicadores FATL, SATL, RFTL e RSTL diretamente da classe do filtro.

Como vamos usar diferentes instâncias da classe para os filtros rápido e lento, só temos que criar na classe as funções AdaptiveTrendLine e ReferenceTrendLine. Vamos transferir para as funções o instrumento, timeframe e deslocamento usados em relação ao candle atual. As funções retornarão o valor filtrado.

Deve-se reparar que a função ReferenceTrendLine é substancialmente semelhante à AdaptiveTrendLine. A diferença é que a ReferenceTrendLine é calculada com deslocamento para o período da amostragem de Nyquist. Portanto, na ReferenceTrendLine, calculamos o período de Nyquist e chamamos a função AdaptiveTrendLine, indicando o deslocamento necessário em relação à barra atual.

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

Os restantes indicadores utilizados são derivados a partir dos valores obtidos e serão calculados e abaixo.

3. Criamos o módulo de sinais de negociação para o gerador de experts MQL5

Hoje resolvi me afastar um pouco da escrita do EA de costume para refrescar a memória sobre a existência do assistente de geração de Experts MT5. Esse recurso útil é uma espécie de construtor, no qual é montado o EA a partir dos módulos anteriormente preparados. Isso permite criar facilmente um novo Expert Advisor, acrescentando novas funções ou removendo as não utilizadas. Por isso, sugiro colocar o algoritmo para tomada de decisões de nosso EA num módulo desse tipo. Já mais de uma vez foi discutido em detalhes este método nos artigos neste site [4], [5]. Por isso neste artigo vou me concentrar apenas no pontos relacionados com nossa estratégia.

Comecemos pela criação da classe de sinal CSignalATCF com base na classe CExpertSignal e conectemos a ela nossas classes criadas mais cedo.

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

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

Durante a inicialização, devemos transferir para o módulo o nome do instrumento, o timeframe usado, o número de barras no histórico para análise da densidade espectral, bem como o número de barras de média (usa-se no cálculo os indicadores RBCI e PCCI). Além disso, é preciso especificar qual padrão deve ser utilizado para abertura das posições. O aparência geral da descrição do módulo será:

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

Agora declaramos as variáveis ​​e funções necessárias:

class CSignalATCF : public CExpertSignal
  {
private:
   ENUM_TIMEFRAMES   ce_Timeframe;     //Timeframe
   uint              ci_HistoryBars;   //Bars in history to analysis
   uint              ci_AveragePeriod; //Period for RBCI and PCCI
   CSpectrum         *Spectrum;        //Class for spectr calculation
   CFLF              *FFLF;            //Class of fast low frequency filter
   CFLF              *SFLF;            //Class of slow low frequency filter
   //--- Indicators data
   double             FATL, FATL1, FATL2;
   double             SATL, SATL1;
   double             RFTL, RFTL1, RFTL2;
   double             RSTL, RSTL1;
   double             FTLM, FTLM1, FTLM2;
   double             STLM, STLM1;
   double             RBCI, RBCI1, RBCI2;
   double             PCCI, PCCI1, PCCI2;
   //--- Patterns flags
   bool               cb_UsePattern1;
   bool               cb_UsePattern2;
   bool               cb_UsePattern3;
   bool               cb_UsePattern4;
   bool               cb_UsePattern5;
   bool               cb_UsePattern6;
   bool               cb_UsePattern7;
   bool               cb_UsePattern8;
   //---
   datetime           cdt_LastSpectrCalc;
   datetime           cdt_LastCalcIndicators;
   bool               cb_fast_calced;
   bool               cb_slow_calced;
   
   bool              CalculateIndicators(void);
       
public:
                     CSignalATCF();
                    ~CSignalATCF();
   //---
   void              TimeFrame(ENUM_TIMEFRAMES value);
   void              HistoryBars(uint value);
   void              AveragePeriod(uint value);
   void              Pattern1(bool value)                {  cb_UsePattern1=value;   }
   void              Pattern2(bool value)                {  cb_UsePattern2=value;   }
   void              Pattern3(bool value)                {  cb_UsePattern3=value;   }
   void              Pattern4(bool value)                {  cb_UsePattern4=value;   }
   void              Pattern5(bool value)                {  cb_UsePattern5=value;   }
   void              Pattern6(bool value)                {  cb_UsePattern6=value;   }
   void              Pattern7(bool value)                {  cb_UsePattern7=value;   }
   void              Pattern8(bool value)                {  cb_UsePattern8=value;   }
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);
  };

Criamos a função para calcular os valores dos indicadores:

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

Em seguida, codificamos as padrões de abertura e fechamento de posições, indicando os pesos correspondentes (40 para abertura e 80 para fechamento). Abaixo estão as funções para a abertura de posições longas. Para posições curtas, a função é construída de forma semelhante.

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


4. Criamos o Expert Advisor de acompanhamento adaptativo do mercado

Depois de criar o módulo de sinal, pode-se proceder a gerar o EA. O processo de criação do EA com ajuda do assistente é descrito neste artigo em detalhes. Durante a criação do EA, eu usei apenas o módulo de sinais de negociação, criado acima. Além disso, foi adicionado um Trailing-Stop com um número fixo de pontos. Quando a estratégia for testada, usaremos um lote fixo, o que permitirá avaliar a qualidade dos sinais gerados.





5. Testando o Expert Advisor.

Após criado o Expert Advisor, podemos testar o método adaptativo de acompanhamento do mercado na Testador de estratégias. Durante o teste, é necessário indicar o peso para abertura da posição no nível de 60 e o peso para fechamento da posição no nível de 10.

5.1. O teste sem o uso de Stop-Loss, Take-Profit e Trailing-Stop.

Para verificar a qualidade dos sinais gerados pelo EA, o primeiro teste foi realizado sem o uso de Stop-Loss, Take-Profit e Trailing-Stop. O teste foi realizado no timeframe H4 durante para 7 meses de 2017.

Teste 1

Teste 1

Infelizmente, o primeiro teste mostrou perdas na implementação de estratégia sem o uso de Stop-Loss.

Teste 1. Resultado

Teste 1. Resultado

Teste 1. Resultado

Teste 1. Resultado

Teste 1. Resultado 

A análise detalhada das transações realizadas na gráfico de preços mostra duas áreas de estratégia problemáticas:

  1. Expert Advisor não consegue fechar a tempo as transações durante recuos acentuados, o que leva à perda do lucro e fechamento desfavorável de transações potencialmente rentáveis.
  2. O EA trabalha bem com grandes movimentos, mas abre uma série de transações não rentáveis em movimentos de correção.

Teste 1 Transações no gráfico

5.2. Teste usando Stop-Loss e Trailing-Stop.

Para minimizar as perdas do primeiro ponto foi colocado Stop-Loss e aplicado o Trailing-Stop.

Teste 2

Teste 2

Mantendo-se constantes outros fatores, o segundo teste mostrou uma diminuição na retenção da posição, um ligeiro aumento na proporção da transações rentáveis, e, ao todo, um tendência geral na direção do lucro. 

Teste 2. Resultado

Teste 2. Resultado

Teste 2. Resultado

Teste 2. Resultado

Teste 2. Resultado

Contudo, a porcentagem de transações rentáveis ​​foi de 39,26%. E manteve-se a segunda área problemática (transações desfavoráveis).

5.3. Testando usando ordens de stop.

Para reduzir as perdas associadas com as contínuas transações não favoráveis em movimentos de correção, foi realizado o teste usando ordens de stop.

Teste 3

Teste 3

Como resultado, o terceiro teste mostrou que a quantidade de transações diminuiu quase duas vezes, enquanto que o rendimento total aumentou, e o percentual de transações rentáveis apresentou um aumento de 44,57%.

Teste 3. Resultado

Teste 3. Resultado

Teste 3. Resultado

Teste 3. Resultado

Teste 3. Resultado


Fim do artigo

No artigo, foi examinado o método de acompanhamento adaptativo do mercado. Testes revelaram a presença de potencial nesta estratégia, mas, para uso no mercado real, é necessária a eliminação de alguns gargalos. Contudo, o método é viável. Os arquivos de origem e os resultados dos testes são apresentados no anexo ao artigo.

Referências

  1. Especulador de moedas, Dezembro de 2000 - Junho de 2001.
  2. Análise das principais características da série temporal.
  3. Extrapolação AR de preço - indicadores para MetaTrader 5
  4. Assistente MQL5: Como criar um módulo de sinais de negociação
  5. Crie o seu próprio robô de negociação em 6 passos!
  6. Assistente MQL5: nova versão

Programas utilizados no artigo:

#
 Nome
Tipo 
Descrição 
 1 Spectrum.mqh Biblioteca de classes Classe para estimar a densidade espectral do instrumento de teste
 2 FLF.mqh Biblioteca de classes Classe para construir o filtro passa-baixos e filtrar os dados de origem
 3 SignalATCF.mqh Biblioteca de classes Módulo de sinais de negociação para o método de acompanhamento adaptativo do mercado
 4 ATCF.mq5 Expert Advisor Expert Advisor para o método de acompanhamento adaptativo do mercado.
 5 ACTF_Test.zip Arquivo O arquivo contém os resultados dos testes do EA no testador de estratégias.

Traduzido do russo pela MetaQuotes Software Corp.
Artigo original: https://www.mql5.com/ru/articles/3456

Arquivos anexados |
ACTF_Test.zip (226.43 KB)
MQL5.zip (289.94 KB)
Redes Neurais Profundas (Parte II). Desenvolvimento e seleção de preditores Redes Neurais Profundas (Parte II). Desenvolvimento e seleção de preditores

O segundo artigo da série sobre redes neurais profundas considerará a transformação e seleção dos preditores durante o processo de preparação de dados para treinar um modelo.

Redes Neurais Profundas (Parte I). Preparando os Dados Redes Neurais Profundas (Parte I). Preparando os Dados

Esta série de artigos continua a explorar as redes neurais profundas (RNP), que são usadas em muitas áreas de aplicação, incluindo a negociação. Serão exploradas aqui novas dimensões deste tema juntamente com o teste de novos métodos e ideias usando experiências práticas. O primeiro artigo da série é dedicado a preparar os dados para a RNP (DNN).

Criação e teste de símbolos personalizados na MetaTrader 5 Criação e teste de símbolos personalizados na MetaTrader 5

A criação de símbolos personalizados empurra os limites no desenvolvimento de sistemas de negociação e análise do mercado financeiro. Agora, os traders são capazes de desenhar gráficos e testar estratégias de negociação em um número ilimitado de instrumentos financeiros.

Interfaces gráficas XI: Caixas de Edição de Texto e Caixas de Combinação nas células da tabela (build 15) Interfaces gráficas XI: Caixas de Edição de Texto e Caixas de Combinação nas células da tabela (build 15)

Nesta atualização da biblioteca, o controle da tabela (a classe CTable) será complementado com novas opções. A gama de controles nas células da tabela foi expandida, desta vez adicionando as caixas de edição de texto e as caixas de combinação. Além disso, esta atualização também apresenta a capacidade de redimensionar a janela de uma aplicação MQL em tempo de execução.