English Русский Español Deutsch 日本語
preview
Teoria das Categorias em MQL5 (Parte 23): uma nova perspectiva sobre a média móvel exponencial dupla

Teoria das Categorias em MQL5 (Parte 23): uma nova perspectiva sobre a média móvel exponencial dupla

MetaTrader 5Sistemas de negociação | 11 março 2024, 17:19
235 0
Stephen Njuki
Stephen Njuki

Introdução

A implementação prática da teoria das categorias no MQL5 parece ser uma tarefa difícil. Há poucos materiais disponíveis para estudo. Existem muitos livros, mas eles geralmente são destinados a pós-graduandos ou doutorandos. Simplificar esse tema é um desafio, especialmente considerando que o objetivo não é apresentar argumentos acadêmicos e teorias, mas sim interpretar e aplicar seus princípios para traders. Para isso, vamos ampliar nosso tópico e olhar para os simples indicadores do dia a dia de uma maneira nova.

O objetivo deste artigo é esclarecer o conceito de composição horizontal em transformações naturais. Analisamos seu antônimo no artigo anterior, onde vimos como derivar três funtores entre duas categorias, implicando duas transformações naturais em composição vertical, quando as categorias representam conjuntos de dados simples como séries temporais de preços e séries temporais de médias móveis dos mesmos preços. Neste artigo, expandiremos a série temporal de médias móveis horizontalmente, adicionando uma terceira categoria de médias móveis, mais conhecida como média móvel exponencial dupla. Nossa versão desse conhecido indicador não usa essa fórmula de facto, mas sim suaviza a média móvel, sendo uma média móvel de uma média móvel. As relações entre funtores são semelhantes às que tínhamos no artigo anterior, no entanto, temos apenas dois funtores entre categorias, em vez de três, como tínhamos no artigo anterior. No entanto, assim como no último artigo, cada funtor entre duas categorias terá seu próprio período de média móvel, de modo que a transformação natural entre cada par de funtores pode nos ajudar a formar um buffer de séries temporais para análise.

A importância de prever a volatilidade na negociação pode não ser tão crítica quanto determinar o tipo de posição (longa ou curta). Porém, oferece a oportunidade de explorar potenciais usos e melhorias de outras estratégias de sinais de entrada existentes ou até mesmo de criar novas, utilizando suas ideias. Já usamos essa abordagem muitas vezes em artigos anteriores. Tentaremos combinar nossas previsões de volatilidade, que serão processadas em uma instância de classe de trailing do EA, com uma classe de sinais do oscilador Awesome embutida. Os leitores, como sempre, podem testar esta classe com outros sinais ou suas próprias estratégias para descobrir o que melhor se adapta a eles. Neste artigo, vamos examinar o oscilador Awesome.


Visão geral

Em artigos anteriores, além de outros tópicos, exploramos brevemente conceitos-chave da teoria das categorias: ordens como categorias, funtores, morfismos como funtores em situações especiais e, finalmente, o quadrado de naturalidade, que prova a existência de transformações naturais.

Entender o que se entende por "composição horizontal" de transformações naturais neste artigo é fundamental, pois não estamos nos referindo simplesmente a uma representação esquemática de transformações naturais em duas dimensões. Examinemos o esquema abaixo:

A horizontalidade aqui é usada para denotar funtores arranjados em uma sequência de tal forma que diferentes pares (ou conjuntos) são associados a diferentes categorias de domínios e codomínios, como mostrado acima, onde os primeiros dois funtores A e C ligam a categoria-1 à categoria-2, e os funtores B e D conectam a categoria-2 à categoria-3. Isso contrasta com o que foi discutido no artigo anterior, onde todos os funtores ligavam o mesmo par de categorias. Mesmo se, no último artigo, duas categorias fossem desenhadas verticalmente, o que significa que as transformações naturais ocorreriam horizontalmente, isso ainda seria considerado uma composição vertical. Da mesma forma, aqui, mesmo que as categorias sejam desenhadas em uma sequência vertical, o que significa que as transformações naturais pareçam ocorrer em uma ordem "vertical", isso ainda seria considerado como composição horizontal.

Bem, nossas categorias são a série temporal de preços, a série temporal de média móvel e a série temporal de média móvel exponencial dupla. O uso de séries temporais exponenciais duplas pode criar alguma confusão ao comparar essa categoria com a categoria das séries temporais de preços. Na verdade, a 3-a categoria representa a média móvel exponencial dupla da categoria-1. Se simplesmente pegássemos os funtores B e D como a média móvel exponencial dupla para objetos da categoria 2, o resultado não seria muito útil para nós. Afinal, o que é a média móvel DEMA? Assim, esses funtores parecem mapear a categoria 1, a série temporal de preços inicial. A estrutura deve ser entendida como um mapa de média móvel da categoria 2. O leitor pode realizar seus próprios testes conforme apropriado, uma vez que o código fonte completo é fornecido no final deste artigo, mas é importante manter essa distinção em mente.


Categorias e funtores

Pois bem, nossa primeira categoria, a categoria-1, possui a série temporal de preços. Em um dos artigos anteriores, já exploramos como a ordem total pode ser interpretada como uma categoria. Nossa série temporal é muito semelhante a uma ordem linear, como indicado aqui. Os objetos nesta categoria serão os valores de preço e tempo em cada intervalo, o que significa que cada objeto terá pelo menos dois elementos, nomeadamente preço e data/hora. Os morfismos para a categoria serão definidos pelo intervalo temporal da série. Eles simplesmente associam os valores de preço em ordem crescente com o tempo. O instrumento cuja série temporal analisaremos neste artigo será o EURUSD.

As médias móveis de preços serão nossa categoria-2. Assim como a primeira categoria, esta é uma série temporal que também pode ser considerada como uma ordem linear e, portanto, como uma categoria. Principalmente, ela incluirá dois objetos, cada um representando uma série temporal. O primeiro será mapeado pelo funtor A e representará a média móvel da série de preços para o período definido pelo funtor A. Esse modelo essencialmente terá dois períodos de média móvel, e aquele que será usado pelo funtor A será o mais curto dos dois. O segundo funtor, denotado por C, também mapeará a série temporal de preços para a categoria-2 e terá um período de média móvel mais longo do que o funtor A. Cada um de nossos objetos na categoria 2 representa uma série temporal.

A terceira e última categoria, a categoria-3, incluirá quatro objetos que representam séries temporais, embora consideremos apenas 2. A cada par de objetos (4 objetos são 2 pares), será associado um funtor que calcula a média móvel da média móvel, para obter a média móvel exponencial dupla (DEMA). Como explicado anteriormente, o DEMA do código mapeia a série de preços da categoria-1, mas isso é feito apenas para facilitar os cálculos e não requer a criação de um indicador especial. Como é uma média móvel da média móvel, pode ser considerada como um mapeamento da categoria-2. Agora, a categoria-2 tem duas séries temporais de médias móveis, que podem ser consideradas como a média móvel rápida e a média móvel lenta. No entanto, isso significa que nossa categoria-3 terá 4 objetos, já que cada um dos dois funtores da categoria-2 é associado a dois objetos, assim vinculando-se a um objeto específico ou série temporal.


Funtores e transformações naturais

O total de transformações naturais desses dois pares de funtores pode ser 6, mas como planejamos usar apenas 2 dos 4 objetos da categoria-3, esse número será 2. Lembremos que uma transformação natural é a diferença entre dois objetos do codomínio dos funtores. Seguimos facilmente esta definição, subtraindo dois objetos da média móvel. Como fizemos no artigo anterior, cada transformação natural será fixada como um buffer de série temporal, e a correlação desses buffers nos ajudará a tomar decisões sobre o ajuste do(s) trailing stop(s) em posições abertas. No artigo anterior, essa correlação entre os buffers de transformação natural serviu como um filtro de ruído branco. Neste artigo, como estamos interessados apenas no ajuste do trailing stop, ela servirá novamente como um filtro, se a correção do stop-loss for aplicada em relação às tendências das médias móveis. Assim, uma tendência negativa com correlação positiva entre esses buffers será um sinal para reduzir o stop-loss em uma posição curta. Da mesma forma, uma tendência positiva com correlação suficiente (nosso limiar acima de zero) indicará o movimento do stop-loss para posições longas, se existirem. Portanto, em muitos casos, não teremos um sinal devido a correlações negativas ou porque o tipo de posição aberta é incompatível com o sinal gerado, uma vez que nossas decisões sobre stop-loss dependem da posição específica. Como vimos no último artigo, esse modelo pode ser recriado como uma instância da classe de sinais do EA e compilado em um EA usando o Assistente, assim seus sinais podem ser mais cuidadosamente testados para avaliar o desempenho e os resultados.


Previsão de volatilidade

Assim, a previsão de volatilidade é o que faz nossa instância da classe de trailing stop do EA, como visto em vários artigos desta série. Aqui, alcançamos isso usando um filtro. As tendências da média móvel devem ser confirmadas por uma correlação substancial entre os buffers de transformação natural. Outra abordagem para a volatilidade que podemos aplicar é ter a categoria-1 na forma de faixas de preço (máximos menos mínimos). Então, as médias dessa série pertenceriam à categoria-2, e a categoria-3 seria seu DEMA, como fazemos com os preços de fechamento no código anexado. O processo é muito o mesmo, mas esta abordagem pode fornecer resultados mais adaptados e sensíveis à volatilidade.


Implementação prática no MQL5

A configuração do ambiente MQL5 para este modelo será muito semelhante ao que discutimos nesta série. Como mencionado anteriormente, a instância da classe de trailing stop do EA é compilada como parte do EA por meio do Assistente MQL5. Para que ele funcione ou seja testado, precisamos primeiro selecionar a instância da classe de sinal do EA no Assistente. Este artigo utiliza a classe de sinais embutida do Awesome Oscillator. "Embutido" aqui significa que a classe já existe na biblioteca de sinais do IDE.

Escrever código para funtores aqui não é necessário, pois podemos usar instâncias embutidas de classes de média móvel. As classes CiMA e CiDEMA podem facilmente satisfazer as necessidades de média móvel e média móvel exponencial dupla. No entanto, declaramos e usamos instâncias da classe CObjects para lidar com essas médias, e sua declaração é a seguinte:

...

   CObjects<double>        m_o_average_a;
   CObjects<double>        m_o_average_b;
   CObjects<double>        m_o_average_c;
   CObjects<double>        m_o_average_d;
...

Como no artigo anterior, precisaremos inicializar os buffers de transformação natural, já que a capacidade de ler sinais é importante desde o início. Seu tamanho, como antes, é um parâmetro de entrada m_transformations, como foi no artigo anterior, então este passo importante será tratado quase identicamente ao que implementamos no último artigo, com a principal diferença sendo que temos quatro instâncias de média móvel para usar nos buffers. A atualização desses valores, que também é um pouco semelhante à inicialização, é feita assim:

//+------------------------------------------------------------------+
//| Refresh function from Natural Transformations.                   |
//+------------------------------------------------------------------+
void CTrailingCT::Refresh(void)
   {
      if(!m_init)
      {
         Init();
      }
      else
      {
         m_close.Refresh(-1);
         
         int _x=StartIndex();
         
         for(int i=m_functor_ab+m_functor_ab-1;i>0;i--)
         {
            m_e_price.Let();m_e_price.Cardinality(1);m_o_prices.Get(i,m_e_price);m_o_prices.Set(i-1,m_e_price);
         }
         
         double _p=m_close.GetData(_x);
         m_e_price.Let();m_e_price.Cardinality(1);m_e_price.Set(0,_p);m_o_prices.Set(0,m_e_price);
         
         for(int i=0;i<m_transformations+1;i++)
         {
            double _a=0.0;
            for(int ii=i;ii<m_functor_ab+i;ii++)
            {
               _a+=m_close.GetData(_x+ii);
            }
            _a/=m_functor_ab;
            m_e_price.Let();m_e_price.Cardinality(1);m_e_price.Set(0,_a);m_o_average_a.Set(i,m_e_price);
            //
            double _b=0.0;
            for(int ii=i;ii<m_functor_cd+i;ii++)
            {
               m_e_price.Let();m_e_price.Cardinality(1);m_o_average_a.Get(i,m_e_price);
               double _b_i=0.0;m_e_price.Set(0,_b_i);
               _b+=_b_i;
            }
            _b/=m_functor_cd;
            m_e_price.Let();m_e_price.Cardinality(1);m_e_price.Set(0,_b);m_o_average_b.Set(i,m_e_price);
            //
            double _c=0.0;
            for(int ii=i;ii<m_functor_ab+i;ii++)
            {
               _c+=m_close.GetData(_x+ii);
            }
            _c/=m_functor_ab;
            m_e_price.Let();m_e_price.Cardinality(1);m_e_price.Set(0,_c);m_o_average_c.Set(i,m_e_price);
            //
            double _d=0.0;
            for(int ii=i;ii<m_functor_cd+i;ii++)
            {
               m_e_price.Let();m_e_price.Cardinality(1);m_o_average_c.Get(i,m_e_price);
               double _d_i=0.0;m_e_price.Set(0,_d_i);
               _d+=_d_i;
            }
            _d/=m_functor_cd;
            m_e_price.Let();m_e_price.Cardinality(1);m_e_price.Set(0,_d);m_o_average_d.Set(i,m_e_price);
         }
         
         
         for(int i=m_transformations-1;i>0;i--)
         {
            m_natural_transformations_ac[i]=m_natural_transformations_ac[i-1];
            m_natural_transformations_bd[i]=m_natural_transformations_bd[i-1];
         }
         //
         double _a=0.0;
         m_e_price.Let();m_e_price.Cardinality(1);m_o_average_a.Get(0,m_e_price);m_e_price.Get(0,_a);
         double _b=0.0;
         m_e_price.Let();m_e_price.Cardinality(1);m_o_average_b.Get(0,m_e_price);m_e_price.Get(0,_b);
         double _c=0.0;
         m_e_price.Let();m_e_price.Cardinality(1);m_o_average_c.Get(0,m_e_price);m_e_price.Get(0,_c);
         double _d=0.0;
         m_e_price.Let();m_e_price.Cardinality(1);m_o_average_d.Get(0,m_e_price);m_e_price.Get(0,_d);
         
         m_natural_transformations_ac[0]=_a-_c;
         m_natural_transformations_bd[0]=_b-_d;
      }
   }


A função de atualização pode parecer um pouco complicada. Começamos atualizando o ponteiro do preço de fechamento, pois ele é a base para a categoria-1. Antes de atribuirmos o último valor ao único objeto desta categoria, precisamos deslocar todos os elementos existentes dentro deste objeto. Em seguida, fazemos quase a mesma coisa com os dois objetos da categoria-2. A diferença aqui é que precisamos primeiro calcular a média móvel para cada período correspondente, e uma vez feito isso, atribuímos os valores após deslocar os valores em ambos os objetos, como fizemos na categoria-1. Depois disso, teremos que lidar com os objetos da categoria-3. São quatro, mas, como já mencionado, para nossas previsões usaremos apenas dois deles. Os valores desses objetos obtemos dos dois objetos que acabamos de preencher e, modificando ligeiramente a fórmula da DEMA, que subtrai a média móvel da média móvel do dobro da média móvel, calculamos o valor necessário - a média móvel da média móvel.

A integração do nosso modelo com os dados diários de preços do EURUSD para testes é feita depois que nossa instância da classe de trailing stop do EA é compilada com o Assistente MQL5. Como de costume, há um guia para isso. Como mencionado anteriormente, compilamos este EA com o oscilador Awesome como a instância da classe de sinal do EA.

O teste histórico e a análise de dados históricos do EURUSD foram realizados de 01.01.2020 a 01.01.2023. Nosso relatório de teste com os melhores resultados de otimização é apresentado abaixo:

r1

Os aspectos mais importantes do relatório que merecem atenção são geralmente a correlação do MAE de lucro, bem como o período de posse e a correlação de lucro. Estes dois indicadores geralmente são apresentados em gráficos na parte inferior do relatório completo. Um resumo dos indicadores gerais aos quais se deve prestar atenção é fornecido acima.


Teste forward

Se realizarmos um teste forward de 01.01.2023 a 01.08.2023 com as melhores configurações do nosso back-test, obteremos os seguintes resultados:

r2

Não conseguimos os resultados desejados, o que geralmente significa uma de duas coisas. A tese do nosso modelo (uso da classe de trailing stop) é aleatória e não pode ser confiável em sistemas de negociação, porque implementamos a ideia com erros que afetam a estrutura de controle no código da nossa classe final. Mesmo se tivéssemos obtido um resultado positivo, ainda seria necessário realizar um teste mais abrangente por um período muito mais longo. Para o Forex, isso pode significar até duas décadas, e esses testes devem incluir rodadas em ticks reais. Os sinais únicos de ajuste do trailing stop, gerados pelo nosso Expert Advisor, ocorrem raramente, já que a tendência da média móvel deve estar na direção da posição aberta. Por conta disso, a eficácia da classe de trailing stop não é suficientemente verificada em janelas de teste curtas, uma das quais é o período de três anos. Além disso, esses resultados são baseados na combinação da nossa classe de trailing stop com o oscilador Awesome, mas qual seria o desempenho quando combinado com outros sinais de entrada? Todas essas e outras questões precisam ser consideradas ao fazer a avaliação.

Testar com dados reais é outro passo necessário que deve ser tomado antes que seja possível implementar este Expert Advisor ou sua variante, que inclui o que discutimos aqui. A primeira etapa desse processo é configurar uma conta demo com sua possível corretora, de preferência com o mesmo tipo de conta que você usará em tempo real. Em seguida, anexe o EA ao gráfico do(s) símbolo(s) que está(ão) sendo negociado(s). Também seria bom usar o serviço MetaQuote VPS, pois requer menos dor de cabeça para configurar e tem um preço competitivo, mas qualquer que seja a escolha, a necessidade de monitorar o log do Expert Advisor permanece, pois isso permite alcançar o desempenho esperado e os resultados de negociação necessários. Tanto o MetaQuote VPS quanto um servidor VPS comum facilitam isso. Adicionalmente, a conta de teste em tempo real deve começar com a quantidade de capital que se pretende usar, caso o teste seja positivo. Por fim, outra boa ideia é manter um diário de negociação pessoal, especialmente se as ideias apresentadas aqui se tornarem parte de outro sistema de negociação que, de alguma forma, depende de notícias. Lembre-se de que, por enquanto, o testador de estratégias do MQL5 não permite testar a leitura de eventos do calendário econômico, então pode ser útil registrá-los manualmente para que, ao revisar, você possa facilmente avaliar a importância relativa de cada notícia a longo prazo.

A interpretação dos resultados e a decisão sobre o que fazer a seguir são muito subjetivas, mas como um ponto de referência, pode-se afirmar que, em um sistema suficientemente lucrativo para atender aos requisitos de objetivo, a correlação entre lucro e MAE deve ser positiva, e o período de posse, bem como o lucro de cada transação, devem ter uma correlação positiva. Esta última métrica é frequentemente chamada de expectativa, mas, infelizmente, nos relatórios do testador de estratégias, esse valor não é calculado.


Considerações finais

Vimos como a composição horizontal de transformações naturais pode ser útil na previsão. As previsões que consideramos neste artigo dizem respeito aos intervalos de barras de preços, que podem ser vistos como uma medida de volatilidade. Estas previsões foram utilizadas, como já foi feito várias vezes nesta série de artigos, ajustando o trailing stop de posições abertas. Enquanto os resultados do treinamento na amostra foram positivos, os resultados fora da amostra foram os piores. No entanto, esse fracasso não elimina a necessidade de testes mais abrangentes por um período mais longo antes de se poder emitir um veredito sobre a eficácia do sistema.

As implicações desses resultados para o desenvolvimento do sistema de negociação são que eles podem ser combinados com diferentes classes de sinais de entrada para obter melhores resultados, ou mesmo podem ser feitas alterações em nossos conjuntos de dados de entrada para representar diferentes cenários de teste.

Como sempre, convido o leitor a explorar estas e outras maneiras de fazer mudanças e testar o código anexado.


Referências

As referências, como sempre, são principalmente de artigos da Wikipédia. Mas desta vez também há da Investopedia.

Informações adicionais sobre a montagem e uso do código fornecido no Expert Advisor podem ser encontradas aqui e aqui.


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

Arquivos anexados |
ct_22.mqh (29.34 KB)
TrailingCT_23.mqh (16.88 KB)
Anotação de dados na análise de série temporal (Parte 3): Exemplo de uso de anotação de dados Anotação de dados na análise de série temporal (Parte 3): Exemplo de uso de anotação de dados
Esta série de artigos apresenta várias técnicas destinadas a rotular séries temporais, técnicas essas que podem criar dados adequados à maioria dos modelos de inteligência artificial (IA). A rotulação de dados (ou anotação de dados) direcionada pode tornar o modelo de IA treinado mais alinhado aos objetivos e tarefas do usuário, melhorar a precisão do modelo e até mesmo ajudar o modelo a dar um salto qualitativo!
Indicadores alternativos de risco e rentabilidade em MQL5 Indicadores alternativos de risco e rentabilidade em MQL5
Neste artigo, apresentaremos a implementação de vários indicadores de rentabilidade e risco, considerados alternativas ao índice de Sharpe, e exploraremos curvas de patrimônio líquido hipotéticas para analisar suas características.
Algoritmos de otimização populacional: busca por difusão estocástica (Stochastic Diffusion Search, SDS) Algoritmos de otimização populacional: busca por difusão estocástica (Stochastic Diffusion Search, SDS)
O artigo aborda a busca por difusão estocástica, SDS, um algoritmo de otimização muito poderoso e prático, baseado nos princípios de passeio aleatório. O algoritmo permite encontrar soluções ótimas em espaços multidimensionais complexos, possuindo uma alta velocidade de convergência e a capacidade de evitar extremos locais.
Redes neurais de maneira fácil (Parte 58): transformador de decisões (Decision Transformer — DT) Redes neurais de maneira fácil (Parte 58): transformador de decisões (Decision Transformer — DT)
Continuamos a explorar os métodos de aprendizado por reforço. Neste artigo, proponho apresentar um algoritmo ligeiramente diferente que considera a política do agente sob a perspectiva de construir uma sequência de ações.