English Русский Español Deutsch 日本語
preview
Teoria das Categorias em MQL5 (Parte 22): Outra Perspectiva sobre Médias Móveis

Teoria das Categorias em MQL5 (Parte 22): Outra Perspectiva sobre Médias Móveis

MetaTrader 5Sistemas de negociação | 8 março 2024, 14:20
187 0
Stephen Njuki
Stephen Njuki

Introdução

O foco desta série de artigos sempre foi a teoria das categorias. Falamos muito sobre a previsão de séries temporais, pois ela é relevante para a maioria dos traders, que constituem a maioria dos participantes desta plataforma. No entanto, outras aplicações relevantes incluem avaliação, risco, alocação de portfólio e muitas outras. Para dar um breve exemplo sobre avaliação, veremos muitas maneiras de aplicar a teoria das categorias na avaliação de ações. Por exemplo, se tomarmos os principais indicadores de uma ação de modo que cada um seja um objeto na categoria, os morfismos (ou caminhos do grafo), que conectam esses diferentes indicadores (como receitas, dívidas, etc.), podem ser classificados em diferentes classes de avaliação (por exemplo, A+, A, B, etc.). Assim, ao obter os indicadores de uma ação específica, podemos determinar a qual classe ela pertence. Esse é uma abordagem simplificada, que serve apenas como uma dica do que pode ser feito nesta área.

Mas, voltando às séries temporais. Muitos consideram as médias móveis uma representação excessivamente simplificada. No entanto, elas são muito importantes para a análise técnica, principalmente porque seu conceito está na base de muitos outros indicadores, como as Bandas de Bollinger, MACD, etc. Elas podem ser vistas como uma perspectiva menos volátil sobre a ação dos preços. Isso é importante, considerando a quantidade de ruído branco nos mercados.

Neste artigo, continuaremos a examinar as transformações naturais. No artigo anterior, exploramos a capacidade das transformações naturais de superar a lacuna entre conjuntos de dados relacionados de diferentes dimensões. Aqui, o conceito de "dimensões" é usado para representar o número de colunas em um conjunto de dados. Bem, como antes, nos deparamos com duas categorias: uma com uma série "simples" de preços não processados e outra com uma série "complexa" de médias móveis de preços. Nosso objetivo será demonstrar o uso da teoria das categorias para a previsão de séries temporais com o escopo de apenas três funtores.


Visão geral

Então, para começar, vamos considerar algumas definições básicas do que estamos examinando aqui. O funtor é uma função que mapeia duas categorias. Aqui, lidaremos com três. As categorias são esquematicamente representadas abaixo:


Em nossa categoria de domínio, há objetos com valores de preço em intervalos de tempo especificados, bem como objetos no codomínio com valores de preço médio móvel também em intervalos de tempo similares. Destacamos três funtores, a saber, A, B e C. Em artigos recentes, apresentamos funtores que conectam categorias. A novidade aqui é a adição de um terceiro funtor. Isso serve aos nossos propósitos, pois mostra as transformações naturais em um arranjo "vertical". A configuração "vertical" é indicada no esquema, mas para evitar qualquer ambiguidade no futuro, "vertical" refere-se às transformações naturais entre funtores que têm a mesma categoria de domínio e codomínio. Isso significa que, se as categorias fossem dispostas esquematicamente na vertical, e nossas transformações naturais parecessem apontar na direção horizontal, as transformações naturais ainda estariam em uma configuração "vertical".

As médias móveis são frequentemente utilizadas como indicadores de negociação, acompanhando os pontos de cruzamento entre elas. Esses pontos podem ser onde elas cruzam o preço base, de modo que um cruzamento acima é considerado bearish (tendência de queda), pois representa uma barreira de resistência, enquanto um cruzamento abaixo é considerado bullish (tendência de alta), pois indica suporte. No entanto, mais frequentemente, esses pontos de cruzamento são encontrados entre duas médias móveis de diferentes períodos. Assim, geralmente, quando a média de período mais curto cruza acima da mais longa, isso é interpretado como uma configuração bullish, porque a média mais longa e, consequentemente, menos volátil, indica suporte. Inversamente, se a média de período mais curto cai abaixo da mais longa, é considerado bearish. Com esse propósito, nesta modelagem, cada funtor representa um determinado período de média. Assim, o funtor A será o de período mais curto dentre todos os três, enquanto o período do funtor B será intermediário, e o funtor C terá o período de média mais longo.

Se olharmos para as categorias que estamos considerando, pode ser útil delinear por que essas duas séries temporais correspondem às axiomas das categorias. Lembre-se, já discutimos como as relações de ordem (às quais as séries temporais são mais próximas) podem ser interpretadas como categorias, ainda que as axiomas de uma categoria sejam objetos, morfismos, morfismos de identidade e associações. As categorias de domínio e codomínio representam séries temporais de preços, portanto, ilustrações de uma facilmente derivam da outra. Assim, se focarmos na categoria de preços brutos (domínio), cada ponto de preço representa um objeto, consistindo de dois elementos - tempo e preço. O morfismos representam mapeamentos consecutivos entre pontos de preço, já que cada ponto de preço segue outro ponto de preço. O morfismo de identidade em cada ponto de preço pode ser considerado como a média móvel para um período igual a um. Isso é o mesmo que a série de preços, mas a média para um período fornece uma relação de identidade. Finalmente, a composição com associação é facilmente implicada, dado três pontos de preço consecutivos L, M e N.

L o (M o N) = (L o M) o N

O preço após o morfismo de M para N, quando associado ao morfismo de L, é o mesmo que o preço em N, quando associado ao resultado do morfismo de L para M.


Categorias e funtores

Nossa categoria 1, que será a categoria de domínio para todos os funtores, como já mencionado, conterá a série temporal bruta de preços, da qual os funtores mapeiam seus valores médios.

Assim, nesta categoria haverá um total de 4 funtores, dos quais apenas 3 são de interesse para nós. A primeira coisa a mencionar é o funtor de identidade. Isso se deve ao fato de que categorias e funtores se comportam de maneira muito semelhante a objetos e morfismos, portanto, a identidade é necessária. Os outros três funtores, que, como mencionado, representam diferentes implementações da média móvel, terão cada um seus períodos definidos por parâmetros de entrada inteiros, a saber, m_functor_a, m_functor_b e m_functor_c para os funtores A, B e C, respectivamente.

A segunda categoria, que serve como codomínio para nossos três funtores, terá três objetos, cada um com suas médias móveis de preços na série temporal. Assim, cada funtor da série bruta de preços na categoria 1 será mapeado para seu próprio objeto na categoria 2.

A categoria 2 terá um único funtor inicial, que, como mencionado anteriormente, será o de identidade. Os morfismos entre esses objetos serão equivalentes a transformações naturais, conforme as definições que discutimos em nossos artigos recentes. Tudo isso pode ser resumido com um esquema um pouco mais detalhado abaixo:



Nosso mapeamento de funtores para este artigo não usa algoritmos de terceiros, como o perceptron multicamada, floresta aleatória ou análise discriminante linear, como fizemos nos artigos mais recentes. Em vez disso, é o algoritmo de média móvel, e as transformações naturais serão ainda mais simples, pois representarão a diferença aritmética entre os valores finais dos dois funtores em consideração.


Transformações naturais

A definição de transformações naturais no contexto financeiro assemelha-se à exploração de novos territórios. Há poucos materiais e referências sobre o tema. Frequentemente, outros métodos são usados ou considerados, como a correlação, que possui duas principais implementações - Pearson e Spearman. Existem outros métodos que podem ser usados para comparação, mas neste artigo usaremos a correlação de Spearman como parte do nosso algoritmo de geração de sinais.

Bem, uma transformação natural entre dois funtores é a diferença pura dos objetos-alvo dos funtores. No nosso caso, temos 3 funtores, o que implica 3 possíveis transformações naturais. No entanto, nos concentraremos apenas em duas transformações, a saber, a transformação entre o funtor A e o funtor B, que chamaremos de AB, e entre o funtor B e o funtor C, que chamaremos de BC. Usando esses dois funtores, queremos criar dois buffers de dados para cada um. Assim, estaremos acompanhando a diferença correspondente nas médias móveis e registrando-as nos arrays apropriados, criando assim dois buffers de dados. Acompanhamos o coeficiente de correlação dos buffers. Monitorar esse valor é a essência do nosso sinal de negociação. Um valor positivo deve indicar que os mercados estão em tendência, enquanto um valor negativo indica uma lateralização.

Logo, nosso sinal corresponderá à soma de todas as mudanças adicionais nas médias móveis com o sinal indicado. Dessa forma, se o valor for positivo, indica uma predisposição para alta, e se for negativo, indica uma predisposição para baixa. Este sinal, que sempre fornecerá um valor em cada a barra, será filtrado, conforme mencionado anteriormente, usando a correlação entre os dois buffers naturais de transformação. Em outras palavras, nosso sistema questiona se há algum benefício adicional em monitorar as transformações naturais, considerando que já estabelecemos tendências para cada média móvel.


Composição vertical de transformações naturais

No âmbito da teoria das categorias, o conceito de "composição vertical" e seu oposto, "composição horizontal" de transformações naturais, às vezes pode variar de significado dependendo do contexto e das convenções dos autores. Em algumas fontes, as transformações naturais de funtores com categorias de domínio e codomínio comuns são chamadas de "composições horizontais". Mas não usaremos essa definição. Neste e, possivelmente, em artigos subsequentes, composições verticais serão referidas como transformações naturais de funtores com categorias de domínio e codomínio comuns.

Então, qual é o significado da composição vertical? Ela é mais simples que a horizontal e também oferece a oportunidade de olhar para dois conjuntos de dados relativamente simples (que podem ser considerados como categorias) e estabelecer entre eles relações especiais que podem ser facilmente perdidas ao trabalhar com múltiplas categorias em condições mais complexas.

Uma boa ilustração é a escolha de um conjunto de dados de séries de preços e um conjunto de dados de médias móveis para este artigo. Além do comércio, um exemplo mais ilustrativo poderia ser a culinária. Considere uma lista de ingredientes culinários (categoria de domínio) e vários menus (categoria de codomínio). Nossos funtores simplesmente conectariam os ingredientes aos menus correspondentes. As transformações naturais, como funtores e morfismos, preservam definições e estruturas de sua origem. Pode parecer trivial, mas é a pedra angular da teoria das categorias. Assim, tendo elementos e a estrutura do objeto (ou seja, menus e suas posições), transformações naturais entre diferentes menus podem ajudar a medir e avaliar o tempo relativo necessário para preparar cada prato, ou o custo de cada prato, além de muitos outros parâmetros, dependendo do que interessa ao chef/restaurante. Armados com essa informação, é possível utilizar o isomorfismo e explorar a aquisição de ingredientes considerando um conjunto de diferentes menus. Embora isso possa ser feito por outros métodos e sistemas, a teoria das categorias garante a preservação da estrutura e uma abordagem que pode ser quantificada.


Previsão de variação de preços

Ao usar a estrutura vertical, a previsão de variação de preços é feita pelo registro e análise dos coeficientes de correlação de nossos dois buffers naturais de transformação. Esses arrays precisam ser inicializados, pois na primeira execução do expert, dados insuficientes são carregados para realizar a correlação. O tratamento desse comportamento é mostrado abaixo:

//+------------------------------------------------------------------+
//| Get Direction function from Natural Transformations.             |
//+------------------------------------------------------------------+
void CSignalCT::Init(void)
   {
      if(!m_init)
      {
         m_close.Refresh(-1);
         
         int _x=StartIndex();
         
         m_o_prices.Cardinality(m_functor_c+m_functor_c);
         for(int i=0;i<m_functor_c+m_functor_c;i++)
         {
            m_e_price.Let();m_e_price.Cardinality(1);m_e_price.Set(0,m_close.GetData(_x+i));m_o_prices.Set(i,m_e_price);
         }
         
         m_o_average_a.Cardinality(m_transformations+1);
         m_o_average_b.Cardinality(m_transformations+1);
         m_o_average_c.Cardinality(m_transformations+1);
         
         for(int i=0;i<m_transformations+1;i++)
         {
            double _a=0.0;
            for(int ii=i;ii<m_functor_a+i;ii++)
            {
               _a+=m_close.GetData(_x+ii);
            }
            _a/=m_functor_a;
            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_b+i;ii++)
            {
               _b+=m_close.GetData(_x+ii);
            }
            _b/=m_functor_b;
            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_c+i;ii++)
            {
               _c+=m_close.GetData(_x+ii);
            }
            _c/=m_functor_c;
            m_e_price.Let();m_e_price.Cardinality(1);m_e_price.Set(0,_c);m_o_average_c.Set(i,m_e_price);
         }
         //
         ArrayResize(m_natural_transformations_ab,m_transformations);ArrayInitialize(m_natural_transformations_ab,0.0);
         ArrayResize(m_natural_transformations_bc,m_transformations);ArrayInitialize(m_natural_transformations_bc,0.0);
         
         for(int i=m_transformations-1;i>=0;i--)
         {
            double _a=0.0;
            m_e_price.Let();m_e_price.Cardinality(1);m_o_average_a.Get(i,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(i,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(i,m_e_price);m_e_price.Get(0,_c);
            
            m_natural_transformations_ab[i]=_a-_b;
            m_natural_transformations_bc[i]=_b-_c;
         }
         
         m_init=true;
      }
   }

Declaramos três marcadores de média móvel para cada funtor, e precisamos atualizá-los antes de ler quaisquer valores deles. O período de cada média móvel é um parâmetro de entrada, portanto, temos m_functor_a, m_functor_b e m_functor_c para os identificadores m_ma_a, m_ma_b e m_ma_c, respectivamente. Também temos dois buffers para cada transformação natural, nomeadamente m_natural_transformations_ab e m_natural_transformations_bc. O tamanho desses arrays é definido pelo parâmetro de entrada m_transformations, portanto, inicialmente, os tamanhos de ambos os arrays precisam ser ajustados para esse valor. Os objetos na categoria de codomínio, nomeadamente m_o_average_a, m_o_average_b, e m_o_average_c, também devem ser ajustados para esse valor mais um, para ser possível obter todos os incrementos de mudanças.

Assim, o impacto de diferentes períodos de médias móveis na capacidade de previsão por este sistema será avaliado à medida que os sinais gerados pelo casamento das mudanças nas médias móveis aparecem, quando a correlação dos buffers de transformação natural é maior que zero. O comportamento é implementado na função GetDirection:

//+------------------------------------------------------------------+
//| Get Direction function from Natural Transformations.             |
//+------------------------------------------------------------------+
double CSignalCT::GetDirection()
   {
      double _r=0.0;
      
      Refresh();
      
      MathCorrelationSpearman(m_natural_transformations_ab,m_natural_transformations_bc,_r);
      
      return(_r);
   }

Cada uma das funções CheckOpenLong e CheckOpenShort, que calculam nosso "tendência". Esta tendência define a direção do sinal, com a "direção" atuando como um filtro para mercados laterais. A implementação é mostrada abaixo:

      m_ma_a.Refresh(-1);
      m_ma_b.Refresh(-1);
      m_ma_c.Refresh(-1);
      
      int _x=StartIndex();
      
      double _trend= (m_ma_a.GetData(0,_x)-m_ma_a.GetData(0,_x+1))+
                     (m_ma_b.GetData(0,_x)-m_ma_b.GetData(0,_x+1))+
                     (m_ma_c.GetData(0,_x)-m_ma_c.GetData(0,_x+1));


Também precisamos de uma função para atualizar esses valores, muito semelhante à função Init. O código-fonte completo está anexado no final do artigo.

Durante o teste no histórico do par de moedas USDJPY de 1999.01.01 a 2020.01.01 no timeframe diário, obtivemos o relatório abaixo com algumas das nossas configurações ideais:

r1


Se tentarmos continuar o teste com essas configurações de 2020.01.01 a 2023.08.01, obteremos o seguinte relatório:

r2

Como de costume, resultados positivos não significam que temos um sistema operacional, mas sim que podemos ter algo que vale a pena testar por períodos mais longos para confirmar nossas conclusões iniciais.


Testes ao desenvolver um sistema de negociação

A classe de sinais pode ser facilmente integrada a um novo ou existente sistema de negociação graças ao Assistente MQL5. Tudo o que precisamos fazer é compilar um novo Expert Advisor com esta classe de sinais como um dos outros sinais que o trader sempre usa ou deseja testar. O típico parâmetro de entrada Signal_XXX_Weight (onde XXX é o nome da classe de sinal), cujo valor geralmente varia de 0,0 a 1,0, pode ser otimizado para todos os sinais para determinar o peso adequado para cada um.

A avaliação de tal sistema de negociação deve basear-se nas necessidades do trader. Normalmente, isso varia entre o crescimento e a preservação do capital. Simplificando, eu diria que o AHPR (Retorno Médio por Operação) é um melhor indicador de crescimento, enquanto a taxa de recuperação é um indicador de segurança. Estas são todas estimativas aproximadas, então os traders terão que se esforçar mais para encontrar o que funciona para eles.

Com um sistema de avaliação de desempenho em vigor, o próximo passo, e talvez igualmente importante, será o método de melhoria incremental da estratégia sem comprometer suas premissas e capacidade de avançar. Nesse processo, não existe um método único além da constante verificação de desempenho baseada em back-tests e avançar com cada iteração ou modificação do sistema.

Como sempre, existe a possibilidade de ter uma instância da classe final baseada neste modelo. Teremos que fazer algumas alterações, mas a essência permanecerá a mesma. Primeiramente, nossas médias móveis, em vez de usar o preço de fechamento como o preço aplicado, usarão algo que tenda à volatilidade, podendo ser o preço típico ou talvez o preço mediano. Em segundo lugar, a direção da previsão ainda indicará as correlações entre os dois buffers de transformações naturais, mas neste caso estaremos monitorando a mudança atual na faixa das barras, para que ela aja como nossa "tendência". Assim, uma diminuição na faixa deve ser suportada por uma correlação positiva (valores acima de zero). O mesmo se aplica ao aumento da volatilidade. Se a correlação for zero ou negativa, isso significará que nosso modelo indica que quaisquer mudanças atuais na volatilidade podem ser ignoradas. A implementação é anexada no final do artigo.


Considerações finais

Em resumo, pode-se dizer que o impacto das transformações naturais na composição vertical soa muito acadêmico e arcaico para despertar o interesse da maioria das pessoas. No entanto, ao examinar ilustrações com indicadores comuns, como a média móvel, neste artigo, identificamos vários padrões dos quais pudemos extrair sinais de confirmação ao prever séries temporais.

A aplicação do conhecimento adquirido para desenvolver um sistema de negociação confiável ocorre onde a teoria encontra a prática, e sua implementação exige um pouco mais de esforço por parte do trader. Ainda assim, há recursos suficientes disponíveis online para que um trader interessado possa levar o projeto até o fim.

Encorajo a exploração adicional desses conceitos além da previsão de séries temporais e em outras áreas de negociação e finanças, como avaliação ou risco.


Referências

Artigos da Wikipédia foram amplamente utilizados.

Recursos para a implementação dos conceitos de teoria das categorias discutidos neste artigo estão anexados abaixo. Isso inclui o arquivo de classe da teoria das categorias ct_22.mq5 e o arquivo de trailing TraillingCT_22_r1.mqh. O arquivo de classe deve ser colocado na pasta include, e o arquivo de trailing na pasta Include\Expert\Trailling. Os leitores não familiarizados com o Assistente MQL5 podem consultar este artigo, já que o arquivo de sinal é destinado para compilação no Assistente.


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

Arquivos anexados |
ct_22.mqh (29.34 KB)
TrailingCT_22.mqh (13.97 KB)
Interface Gráfico: Dicas e recomendações para criar uma biblioteca gráfica no MQL Interface Gráfico: Dicas e recomendações para criar uma biblioteca gráfica no MQL
Vamos explorar os fundamentos das bibliotecas de interface gráfica para que você possa entender como elas funcionam ou até mesmo começar a criar as suas próprias.
Rede neural na prática: Reta Secante Rede neural na prática: Reta Secante
Como foi explicado na parte teórica. Precisamos usar regressões lineares e derivadas, quando o assunto é rede neural. Mas por que ?!?! O motivo disto, é que a regressão linear é uma das fórmulas mais simples que existe. Basicamente uma regressão linear, é apenas uma função afim. Porém quando falamos em rede neural, não estamos interessados na reta, que a regressão linear cria. Estamos interessados é na equação que gera tal reta. A reta gerada pouco importa. Mas você sabe qual é a equação principal a ser compreendida ?!?! Se não veja este artigo para começar a entender.
Criando um Expert Advisor simples multimoeda usando MQL5 (Parte 2): Sinais do indicador - Parabolic SAR multiframe Criando um Expert Advisor simples multimoeda usando MQL5 (Parte 2): Sinais do indicador - Parabolic SAR multiframe
Neste artigo, por EA multimoeda, entendemos um robô investidor ou um robô de negociação que pode negociar (abrir/fechar ordens, gerenciar ordens como trailing-stop-loss e trailing profit) mais de um par de moedas em um gráfico. Desta vez, usaremos apenas um indicador, o Parabolic SAR ou iSAR, em vários timeframes, começando com PERIOD_M15 e terminando com PERIOD_D1.
Algoritmos de otimização populacionais: Algoritmo de evolução da mente (Mind Evolutionary Computation, MEC) Algoritmos de otimização populacionais: Algoritmo de evolução da mente (Mind Evolutionary Computation, MEC)
Este artigo discute um algoritmo da família MEC, denominado algoritmo simples de evolução da mente (Simple MEC, SMEC). O algoritmo se destaca pela beleza da ideia subjacente e pela simplicidade de implementação.