English Русский 中文 Español Deutsch 日本語
preview
Teoria das Categorias em MQL5 (Parte 15): Funtores com grafos

Teoria das Categorias em MQL5 (Parte 15): Funtores com grafos

MetaTrader 5Testador | 18 janeiro 2024, 10:11
216 0
Stephen Njuki
Stephen Njuki

Introdução

No artigo anterior, vimos como os conceitos já considerados, como ordens lineares, podem ser vistos como categorias e por que seus "morfismos" são de fato funtores em relação a outras categorias. Veremos exemplos do artigo anterior, especialmente como os grafos podem ter a mesma aplicação que as ordens lineares discutidas no artigo anterior. Para usar grafos, converteremos os dados do calendário MQL5 em um grafo e, dessa forma, em uma categoria. Esse é o foco do artigo atual. Sendo assim, o propósito deste artigo, como o anterior, é demonstrar o potencial dos funtores na previsão da volatilidade entre duas categorias. Entretanto, nesse caso, nossa categoria de domínio é um grafo, enquanto o codomínio exibirá os valores de volatilidade do S&P 500 (não do VIX) em uma pré-condição de série temporal.


Conversão de dados de entrada do Calendário MQL5 em um grafo

Já falei sobre o Calendário Econômico MQL5 quando abordei a teoria das categorias no contexto dos esquemas de bancos de dados, por isso não vou me repetir. Para representá-lo como um grafo, uma sequência de arestas e nós, primeiro precisamos pré-selecionar um subconjunto de notícias que incluiremos em nossa categoria. Como pode ser visto no site do calendário econômico, temos muito a escolher, no entanto, se decidirmos selecionar, digamos, apenas quatro tipos de dados com base em sua relação aparente, como mostrado abaixo:


Assim, nossa hipótese seria a de que as vendas no varejo são uma função do PMI, que, por sua vez, é um derivado do IPC, que é uma função do leilão de rendimento de 10 anos, cujos resultados também se baseiam nas vendas no varejo. Então, esse é um ciclo simples, cuja validade não é o assunto deste artigo, mas pretende ilustrar a possível composição de um grafo com base nos dados do calendário econômico.

Os grafos simplificam sistemas interconectados complexos por meio da criação de duas tabelas simples, uma representando pares de vértices e a outra como índice de vértices. Um grafo pode ser visto como uma categoria porque os vértices podem ser entendidos como objetos (domínios), o que significa que as arestas agem como morfismos. A diferença em relação à ordem linear discutida no artigo anterior é (como o nome sugere) a linearidade. Os grafos tendem a formar relações mais complexas quando um objeto/domínio pode ser relacionado a mais de um objeto.

Por isso, em vez de combinar objetos individuais dessa categoria com objetos da categoria de volatilidade do S&P, como fizemos no artigo anterior sobre ordens lineares, conectaremos linhas de pares de vértices à categorio S&P. Isso significa que a categoria não pode ser isomórfica porque várias linhas estão vinculadas a um único objeto (ponto de dados) no S&P, uma vez que o S&P é baseado no tempo. Isso também significa que nossos objetos de domínio consistirão em quatro elementos (os últimos valores de cada um dos quatro elementos do laço).


Teoria de categorias e funtores: uma breve visão geral

Como mencionado anteriormente, a teoria das categorias tem muitas aplicações, mas a maioria dos conteúdos disponíveis ao público se concentra na topologia algébrica e não na negociação de ações. A maioria dos traders familiarizados com o MQL5 tende a usar redes neurais para melhorar a eficiência de seus sistemas, talvez porque elas sejam mais bem compreendidas em comparação com as categorizações. No entanto, isso não deve desencorajar o estudo de categorizações. A maioria dos traders está procurando algum tipo de vantagem de negociação, mas se um sistema ou método for muito difundido, as chances de encontrar essa vantagem diminuem.

Assim como mencionado em nosso último artigo, os funtores são essencialmente morfismos entre categorias. Esses "morfismos" não apenas conectam objetos em duas categorias, mas também conectam homomorfismos entre categorias.

No artigo anterior, avaliamos dois cenários: em um deles, usamos a ligação de objetos entre duas categorias e, no outro, consideramos a ligação de morfismos entre as mesmas categorias. O funtor é o logaritmo de ambos, mas, para nossos propósitos, exploramos as diferenças entre os dois considerando um de cada vez e geramos relatórios de teste de estratégia para cada um que destacaram a importância relativa na previsão da volatilidade do NASDAQ. Dada a curta margem de testes, de 1º de janeiro a 15 de março de 2020, não foi possível tirar conclusões sobre qual cenário era melhor, mas a diferença nos resultados indicou uma alta sensibilidade às diferenças.


Criando a categoria de volatilidade do S&P 500

A coleta e o processamento dos dados de volatilidade do SP500 serão simples e semelhantes à forma como medimos a volatilidade do NASDAQ no último artigo. O VIX é um indicador separado. Por isso, o valor atual da volatilidade será recalculado em cada nova barra, de acordo com a listagem abaixo:

      double _float_value=0.0;
      //where R is an instance of MqlRates...
      _float_value=(R.high-R.low)/Point();


Conforme mencionado antes, o S&P formará nosso codomínio com objetos que capturam os valores de volatilidade como um conjunto de objetos e morfismos entre eles que capturam a mudança relativa entre as leituras de volatilidade. Essa categoria pode ser inicializada da seguinte forma:

//+------------------------------------------------------------------+
//|   Get SP500-100 data from symbol (NDX100 for this broker).       | 
//|   Load it into SP500 category.                                   |
//+------------------------------------------------------------------+
void SetSP500(MqlRates &R)
   {
      _hmorph_sp500.Let();
      
      double _float_value=0.0;
      
      _float_value=(R.high-R.low)/Point();
      
      _element_value.Let();_element_value.Cardinality(1);_element_value.Set(0,DoubleToString(_float_value));
      _domain_sp500.Cardinality(1);_domain_sp500.Set(0,_element_value);
      
      //_category_sp500.Domains(_category_sp500.Domains()+1);
      _category_sp500.SetDomain(_category_sp500.Domains(),_domain_sp500);  
   }


Como vimos no artigo anterior, se pudermos associar o domínio de atraso a esse codomínio, poderemos ter alguma capacidade de prever a volatilidade do índice S&P 500. Como no artigo anterior, testaremos os funtores dos objetos e do morfismo separadamente usando configurações idênticas de controle de sinal e de capital para avaliar a sensibilidade.


Funtores entre o calendário econômico e o S&P 500

Construiremos uma categoria de dados sobre o calendário econômico usando a listagem abaixo:

//+------------------------------------------------------------------+
//|   Get Ocean data from file defined in input.                     | 
//|   Load it into Ocean category.                                   |
//+------------------------------------------------------------------+
void SetEconomic(MqlRates &R)
   {
      datetime _time=R.time;
      
      int _elements=1;
      
      _e_retail.Let();
      SampleEvents(_time,_e_retail,IntToCountry(__country),__currency,TYPE_RETAIL_SALES);//printf(__FUNCSIG__+"...retail. ");
      
      _e_cpi.Let();
      string _cpi_time="";_e_retail.Get(0,_cpi_time);
      SampleEvents(StringToTime(_cpi_time),_e_cpi,IntToCountry(__country),__currency,TYPE_CPI);//printf(__FUNCSIG__+"...cpi. ");
      
      _e_auction.Let();
      string _auction_time="";_e_cpi.Get(0,_auction_time);
      SampleEvents(StringToTime(_auction_time),_e_auction,IntToCountry(__country),__currency,TYPE_AUCTION_10YR);//printf(__FUNCSIG__+"...auction. ");
      
      _e_pmi.Let();
      string _pmi_time="";_e_auction.Get(0,_pmi_time);
      SampleEvents(StringToTime(_pmi_time),_e_pmi,IntToCountry(__country),__currency,TYPE_PMI);//printf(__FUNCSIG__+"...pmi. ");
      
       _domain_economic.Cardinality(__ECON);
       _domain_economic.Set(0,_e_retail);
       _domain_economic.Set(1,_e_cpi);
       _domain_economic.Set(2,_e_auction);
       _domain_economic.Set(3,_e_pmi);
      
       _category_economic.SetDomain(_category_economic.Domains(),_domain_economic);
   }


Cada objeto nesse domínio tem dois vértices que representam valores de calendário emparelhados, dos quais pelo menos um está no intervalo de tempo do valor de volatilidade no codomínio. Como esses dados econômicos são publicados em intervalos de aproximadamente um mês, vamos testá-los em um gráfico mensal. Como no artigo anterior, nosso mapeamento de funtor terá coeficientes para cada ponto de dados no objeto. A diferença aqui é que nos deparamos com a possibilidade de combinar vários objetos com a mesma volatilidade em um codomínio. Idealmente, gostaríamos de obter o coeficiente (para mapeamento linear) de cada objeto separadamente e usá-lo na previsão. Isso significa que eles devem fornecer projeções inconsistentes além das projeções fornecidas pelo mapeamento de morfismo. É por isso que, para os fins deste artigo, poderíamos ponderar cada funtor que mapeia os dados do calendário para a categoria S&P e obter a soma dos produtos escalares de todos para mapear o valor de volatilidade.

A aplicação prática dos funtores, como no artigo anterior, seguirá dois caminhos: mapearemos os objetos na primeira iteração e, em seguida, mapearemos os morfismos na próxima iteração. O mapeamento de objetos de Output() terá a seguinte aparência:

//+------------------------------------------------------------------+
//| Get Forecast value, forecast for next change in price bar range. |
//+------------------------------------------------------------------+
double GetObjectsForecast(MqlRates &R)
   {
      double _output=0.0;
      
      //econ init
      SetEconomic(R);
      
      //sp500 init
      SetSP500(R);
      
      matrix _domain;
      vector _codomain,_inputs;
      
      _domain.Init(__ECON+1,__ECON);
      
      for(int r=0;r<__ECON+1;r++)
      {
         CDomain<string> _d;_d.Let();
         _category_economic.GetDomain(_category_economic.Domains()-r-1,_d);
         
         for(int c=0;c<__ECON;c++)
         {
            CElement<string> _e; _d.Get(c,_e);
            
            string _s; _e.Get(1,_s);
            
            _domain[r][c]=StringToDouble(_s);
         }
      }
      
      _codomain.Init(__ECON);
      
      for(int r=0;r<__ECON;r++)
      {
         CDomain<string> _d;_d.Let();
         _category_sp500.GetDomain(_category_sp500.Domains()-r-1,_d);
         
         CElement<string> _e; _d.Get(0,_e);
         
         string _s; _e.Get(0,_s);
            
         _codomain[r]=StringToDouble(_s);
      }
      
      _inputs.Init(__ECON);_inputs.Fill(__constant_morph);
      
      M(_domain,_codomain,_inputs,_output,1);
      
      return(_output);
   }


Nosso mapeamento de morfismos também será tratado de forma diferente, relacionando os morfismos entre os vértices, definidos pelo delta de alteração, com o morfismo entre os pontos de dados de volatilidade do S&P, que também é definido pelo valor de alteração. O processamento é implementado da seguinte forma:

//+--------------------------------------------------------------------+
//|   Get Forecast value, forecast for next change in price bar range. |
//+--------------------------------------------------------------------+
double GetMorphsForecast(MqlRates &R)
   {
      ...
      
      for(int r=0;r<__ECON+1;r++)
      {
         ...
         
         for(int c=0;c<__ECON;c++)
         {
            CElement<string> _e_new; _d_new.Get(c,_e_new);
            
            string _s_new; _e_new.Get(1,_s_new);
            
            CElement<string> _e_old; _d_old.Get(c,_e_old);
            
            string _s_old; _e_old.Get(1,_s_old);
            
            _domain[r][c]=StringToDouble(_s_new)-StringToDouble(_s_old);
         }
      }
      
      _codomain.Init(__ECON);
      
      for(int r=0;r<__ECON;r++)
      {
         ...
         
         CElement<string> _e_new; _d_new.Get(0,_e_new);
         
         string _s_new; _e_new.Get(0,_s_new);
         
         CElement<string> _e_old; _d_old.Get(0,_e_old);
         
         string _s_old; _e_old.Get(0,_s_old);
         
         _codomain[r]=StringToDouble(_s_new)-StringToDouble(_s_old);
      }
      
      _inputs.Init(__ECON);_inputs.Fill(__constant_morph);
      
      M(_domain,_codomain,_inputs,_output,1);
      
      return(_output);
   }


A representação esquemática dessas duas partes do funtor também será um pouco diferente da que consideramos no último artigo, pois nossa relação não será mais isomórfica. Podemos ilustrar a correspondência de objetos da seguinte forma:


O mapeamento de morfismos terá a seguinte aparência:


Infelizmente, o testador de estratégia MQL5 não permite testes com acesso a eventos do calendário econômico. A tarefa de aumentar significativamente o desempenho com o desenvolvimento de sistemas de negociação mais confiáveis continua sem solução. O melhor que podemos fazer é exibir a mudança de volatilidade prevista com base em nossa previsão e, se você percorrer algum histórico, poderá ter uma ideia de quão precisas são nossas previsões.

Entretanto, se executarmos nosso script com base nos dados de preço fornecidos pela corretora, poderemos plotar nossas duas categorias tendo como base um gráfico de dados de calendário e a volatilidade do SP500 mais seu funtor de vinculação. Poderemos obter as seguintes previsões de volatilidade. O mapeamento do functor objeto a objeto gera as seguintes entradas:

2023.07.30 13:45:47.035 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 0.00000000, on: 2020.01.01 00:00, with actual being: 54260.00000000
2023.07.30 13:45:47.134 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 0.00000000, on: 2020.02.01 00:00, with actual being: 95438.00000000
2023.07.30 13:45:47.265 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 0.00000000, on: 2020.03.01 00:00, with actual being: 53588.00000000
2023.07.30 13:45:47.392 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 0.00000000, on: 2020.04.01 00:00, with actual being: 30352.00000000
2023.07.30 13:45:47.512 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 0.00000000, on: 2020.05.01 00:00, with actual being: 29694.00000000
2023.07.30 13:45:47.644 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -716790.11376869, on: 2020.06.01 00:00, with actual being: 21905.00000000
2023.07.30 13:45:47.740 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -12424.22112077, on: 2020.07.01 00:00, with actual being: 26509.00000000
2023.07.30 13:45:47.852 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 53612.17123096, on: 2020.08.01 00:00, with actual being: 37890.00000000




...

2023.07.30 13:45:50.294 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -27774.72154618, on: 2022.09.01 00:00, with actual being: 42426.00000000
2023.07.30 13:45:50.377 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 46751.59791572, on: 2022.10.01 00:00, with actual being: 39338.00000000
2023.07.30 13:45:50.487 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -19820.29385469, on: 2022.11.01 00:00, with actual being: 37305.00000000
2023.07.30 13:45:50.593 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -5370.60103622, on: 2022.12.01 00:00, with actual being: 30192.00000000
2023.07.30 13:45:50.700 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -4662833.98425755, on: 2023.01.01 00:00, with actual being: 25359.00000000
2023.07.30 13:45:50.795 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 33455.47933459, on: 2023.02.01 00:00, with actual being: 30681.00000000
2023.07.30 13:45:50.905 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -40357.22273603, on: 2023.03.01 00:00, with actual being: 12502.00000000
2023.07.30 13:45:51.001 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -37676.03496283, on: 2023.04.01 00:00, with actual being: 18835.00000000
2023.07.30 13:45:51.094 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -54634.02723538, on: 2023.05.01 00:00, with actual being: 28877.00000000
2023.07.30 13:45:51.178 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -35897.40757724, on: 2023.06.01 00:00, with actual being: 23306.00000000
2023.07.30 13:45:51.178 ct_15_w (SPX500,MN1)    void OnStart() corr is: 0.36053106 with morph constant as: 50000.00000000


A correspondência de morfismo traz os seguintes resultados:

2023.07.30 13:47:38.737 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 0.00000000, on: 2020.01.01 00:00, with actual being: 54260.00000000
2023.07.30 13:47:38.797 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 0.00000000, on: 2020.02.01 00:00, with actual being: 95438.00000000
2023.07.30 13:47:38.852 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 0.00000000, on: 2020.03.01 00:00, with actual being: 53588.00000000
2023.07.30 13:47:38.906 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 0.00000000, on: 2020.04.01 00:00, with actual being: 30352.00000000
2023.07.30 13:47:39.010 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 0.00000000, on: 2020.05.01 00:00, with actual being: 29694.00000000
2023.07.30 13:47:39.087 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: -2482719.31391738, on: 2020.06.01 00:00, with actual being: 21905.00000000




...

2023.07.30 13:47:41.541 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: -86724.54189079, on: 2022.11.01 00:00, with actual being: 37305.00000000
2023.07.30 13:47:41.661 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: -126817.99564744, on: 2022.12.01 00:00, with actual being: 30192.00000000
2023.07.30 13:47:41.793 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: -198737.93199622, on: 2023.01.01 00:00, with actual being: 25359.00000000
2023.07.30 13:47:41.917 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: -280104.88246660, on: 2023.02.01 00:00, with actual being: 30681.00000000
2023.07.30 13:47:42.037 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 24129.34336223, on: 2023.03.01 00:00, with actual being: 12502.00000000
2023.07.30 13:47:42.157 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 4293.73674465, on: 2023.04.01 00:00, with actual being: 18835.00000000
2023.07.30 13:47:42.280 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 763492.31964126, on: 2023.05.01 00:00, with actual being: 28877.00000000
2023.07.30 13:47:42.401 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: -30298.30836734, on: 2023.06.01 00:00, with actual being: 23306.00000000
2023.07.30 13:47:42.401 ct_15_w (SPX500,MN1)    void OnStart() corr is: 0.03400012 with morph constant as: 50000.00000000


Observamos alguns pontos em relação às entradas. Em primeiro lugar, todos os cinco primeiros meses preveem um valor zero. Acredito que isso se deva à falta de dados de preço para fazer cálculos completos, como às vezes acontece com muitos indicadores. Em segundo lugar, os valores negativos fazem parte das previsões, mas estamos apenas procurando um valor estritamente positivo para indicar qual será a nossa volatilidade na próxima barra. Isso pode se dever ao fato de não termos conseguido determinar valores baixos de volatilidade, pois usamos as ferramentas de regressão da biblioteca MQL5, que utilizam matrizes únicas ao trabalhar com múltiplos coeficientes (no nosso caso, quatro). Esse problema pode ser contornado com a normalização dos valores negativos por meio de uma função como a proposta a seguir.

//+------------------------------------------------------------------+
//| Normalizes negative projections to positive number.              |
//+------------------------------------------------------------------+
double NormalizeForecast(double NegativeValue,double CurrentActual,double PreviousActual,double PreviousForecast)
   {
      return(CurrentActual+(((CurrentActual-NegativeValue)/CurrentActual)*fabs(PreviousActual-PreviousForecast)));
   }


Se agora executarmos nosso script e verificarmos a correlação entre nossas previsões e os valores reais, certamente obteremos resultados diferentes, especialmente porque a constante da equação é uma variável muito sensível que determina em grande parte o tipo de resultado e as previsões que teremos. Nós a definimos como igual a zero para as entradas abaixo. Primeiro, executamos o funtor objeto-objeto:

2023.07.30 14:43:42.224 ct_15_w_n (SPX500,MN1)  void OnStart() Objects forecast is: 15650.00000000, on: 2020.01.01 00:00, with actual being: 54260.00000000

...

2023.07.30 14:43:45.895 ct_15_w_n (SPX500,MN1)  void OnStart() Objects forecast is: 15718.63125861, on: 2023.03.01 00:00, with actual being: 12502.00000000
2023.07.30 14:43:45.957 ct_15_w_n (SPX500,MN1)  void OnStart() Objects forecast is: 12187.53007421, on: 2023.04.01 00:00, with actual being: 18835.00000000
2023.07.30 14:43:46.026 ct_15_w_n (SPX500,MN1)  void OnStart() Objects forecast is: 19185.80075759, on: 2023.05.01 00:00, with actual being: 28877.00000000
2023.07.30 14:43:46.129 ct_15_w_n (SPX500,MN1)  void OnStart() Objects forecast is: 11544.54076238, on: 2023.06.01 00:00, with actual being: 23306.00000000
2023.07.30 14:43:46.129 ct_15_w_n (SPX500,MN1)  void OnStart() correlation is: 0.46195608 with morph constant as: 0.00000000


Em seguida, executamos nosso script criando projeções com base no funtor morfismo-morfismo, novamente com a mesma constante de equação definida como zero.

2023.07.30 14:45:54.257 ct_15_w_n (SPX500,MN1)  void OnStart() Morphs forecast is: 54260.00000000, on: 2020.02.01 00:00, with actual being: 95438.00000000

...

2023.07.30 14:45:57.449 ct_15_w_n (SPX500,MN1)  void OnStart() Morphs forecast is: 257937.92970615, on: 2023.05.01 00:00, with actual being: 28877.00000000
2023.07.30 14:45:57.527 ct_15_w_n (SPX500,MN1)  void OnStart() Morphs forecast is: 679078.55629755, on: 2023.06.01 00:00, with actual being: 23306.00000000
2023.07.30 14:45:57.527 ct_15_w_n (SPX500,MN1)  void OnStart() correlation is: -0.03589660 with morph constant as: 0.00000000


Obtemos uma correlação ligeiramente maior de 0,46 em comparação com o valor de 0,3 que obtivemos sem a normalização. Isso pode indicar algum benefício decorrente da normalização, mas, em nosso caso, a constante de entrada foi alterada de 50.000 e, conforme mencionado, as previsões e, por conseguinte, a correlação são muito sensíveis a isso. Como temos apenas uma entrada, vamos executar o testador de estratégia para otimizar seu valor e obter resultados mais relevantes.


Implicações para os traders

Em minha opinião, o valor subestimado da teoria das categorias para a análise financeira está no aprendizado por transferência. Quais são suas vantagens? Como resultado de nossos testes acima, obtivemos os coeficientes entre o mapeamento de funtores de objeto e o mapeamento de morfismos. O processo de obtenção desses coeficientes necessariamente exigirá grandes recursos computacionais, especialmente se a otimização for realizada, como seria de se esperar, considerando longos períodos históricos no testador de estratégias MQL5.

No entanto, como os coeficientes do funtor fazem parte da hipótese apresentada acima na forma de um laço, é possível argumentar que esses coeficientes, que funcionam de uma maneira específica para os valores em dólares do calendário econômico, podem ser igualmente eficazes, por exemplo, para os valores do calendário econômico em euros sobre a volatilidade do EURO-STOXX ou para os valores em libras esterlinas sobre a volatilidade do FTSE. Obtemos um conjunto de combinações possíveis. E é nesse ponto que nossos funtores se tornam ferramentas inestimáveis, pois pegam os coeficientes resultantes de uma otimização longa e intensiva por meio de computação intensiva e os aplicam a qualquer uma dessas combinações que (com base em nossa hipótese) podem produzir um resultado melhor do que a média.

Para ilustrar o que dissemos, usamos os dados de entrada mostrados abaixo:


Vamos fazer alguns testes com moedas alternativas e seus índices de ações correspondentes. Se começarmos com os valores do calendário econômico do euro da Alemanha, na categoria conjugada pelo functor com a categoria de volatilidade do DAX30, com as configurações acima, obteremos o seguinte relatório do testador:

2023.07.30 15:12:25.655	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 75550.00000000, on: 2020.01.01 00:00, with actual being: 210640.00000000
2023.07.30 15:12:25.727	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 210640.00000000, on: 2020.02.01 00:00, with actual being: 431320.00000000

...

2023.07.30 15:12:28.445	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 144734.23693128, on: 2022.09.01 00:00, with actual being: 154697.00000000
2023.07.30 15:12:28.539	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 171908.69769099, on: 2022.10.01 00:00, with actual being: 156643.00000000
2023.07.30 15:12:28.648	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 298789.42486333, on: 2022.11.01 00:00, with actual being: 99044.00000000
2023.07.30 15:12:28.753	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 178962.89317906, on: 2022.12.01 00:00, with actual being: 137604.00000000
2023.07.30 15:12:28.901	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 440957.33259197, on: 2023.01.01 00:00, with actual being: 55544.00000000
2023.07.30 15:12:29.032	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 143198.91357580, on: 2023.02.01 00:00, with actual being: 124659.00000000
2023.07.30 15:12:29.151	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 24327.24201304, on: 2023.03.01 00:00, with actual being: 48737.00000000
2023.07.30 15:12:29.267	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 167059.32862279, on: 2023.04.01 00:00, with actual being: 69888.00000000
2023.07.30 15:12:29.357	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 67301.73632062, on: 2023.05.01 00:00, with actual being: 74073.00000000
2023.07.30 15:12:29.470	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 87406.10063493, on: 2023.06.01 00:00, with actual being: 104992.00000000
2023.07.30 15:12:29.470	ct_15_w_n (GER30,MN1)	void OnStart() correlation is: 0.02260757 with morph constant as: 0.00000000


Para GBP e FTSE-100, obtemos o seguinte:

2023.07.30 15:12:45.341	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 45860.00000000, on: 2020.01.01 00:00, with actual being: 109780.00000000
2023.07.30 15:12:45.381	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 109780.00000000, on: 2020.02.01 00:00, with actual being: 210420.00000000
2023.07.30 15:12:45.420	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 210420.00000000, on: 2020.03.01 00:00, with actual being: 87250.00000000
2023.07.30 15:12:45.466	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 87250.00000000, on: 2020.04.01 00:00, with actual being: 58380.00000000
2023.07.30 15:12:45.508	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 1581489.63705309, on: 2020.05.01 00:00, with actual being: 58370.00000000

...

2023.07.30 15:12:46.685	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 153576.16806574, on: 2023.01.01 00:00, with actual being: 30453.00000000
2023.07.30 15:12:46.710	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 222058.94934174, on: 2023.02.01 00:00, with actual being: 77051.00000000
2023.07.30 15:12:46.739	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 50993.02046828, on: 2023.03.01 00:00, with actual being: 30780.00000000
2023.07.30 15:12:46.784	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 66795.26430874, on: 2023.04.01 00:00, with actual being: 45453.00000000
2023.07.30 15:12:46.832	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 75492.86146563, on: 2023.05.01 00:00, with actual being: 28845.00000000
2023.07.30 15:12:46.876	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 92298.50964858, on: 2023.06.01 00:00, with actual being: 49472.00000000
2023.07.30 15:12:46.876	ct_15_w_n (UK100,MN1)	void OnStart() correlation is: 0.14415363 with morph constant as: 0.00000000


Pelas nossas observações iniciais, fica claro que, embora possamos fazer previsões, não podemos testá-las de forma confiável por causa do uso limitado de dados de calendário no testador de estratégia. Claramente, nossa hipótese não foi confirmada e a correlação de 0,46 obtida para o USD e o SP500 não foi conclusiva. 

Na verdade, o valor da correlação é uma "solução" temporária, pois serve apenas como um indicador muito inicial de quão confiáveis as previsões podem ser dependendo da escolha dos dados, que, no nosso caso, são principalmente o coeficiente da relação linear entre a categoria de domínio e seu codomínio. Outras opções mais confiáveis e de longo prazo envolvem a exportação manual dos dados do calendário econômico como um arquivo CSV para ser lido pelo EA ou até mesmo a exportação para um banco de dados para melhor armazenamento. Com qualquer uma dessas alternativas, é possível realizar testes apropriados para períodos longos e ideais.

Além da previsão de volatilidade como forma de determinar o stop loss ideal, também podemos precisar de uma abordagem sistemática para o dimensionamento da posição. Para conseguir isso por meio de nossa metodologia, suponha que tenhamos uma categoria não relacionada de dados de série temporal que represente o histórico de negociação de um determinado título, em que cada objeto da categoria represente um determinado resultado de negociação e as setas (morfismos) entre os objetos denotem mudanças nesses resultados registrados ao longo do tempo.

Ao utilizar essa categoria para determinar ou prever o tamanho ideal da posição em um sistema de negociação, nós a mapearíamos usando um funtor para outra categoria de série temporal de tamanhos ideais de posição com base no desempenho real da negociação e, possivelmente, na volatilidade associada. Assim, por exemplo, se uma operação não fosse lucrativa, um objeto dessa categoria registraria um tamanho de posição pequeno naquele momento, enquanto, caso contrário, registraria um tamanho maior. A volatilidade pode ser um fator adicional para diminuir ou aumentar uma posição, dependendo da volatilidade registrada no momento da negociação. Assim, o ajuste de escala pode ser tal que, quando as negociações forem perdedoras, o tamanho da posição ideal diminua ainda mais na proporção da leitura da volatilidade. Da mesma forma, quando as operações resultam em um ganho, o tamanho da posição ideal também aumenta proporcionalmente à volatilidade. O funtor de mapeamento, como esperado, terá um atraso de tal forma que, digamos, o resultado de uma operação agora esteja relacionado ao tamanho da posição para o próximo período.

O funtor associará não apenas os resultados da negociação ao tamanho da posição ideal esperada, mas também os morfismos entre os resultados da negociação e os morfismos entre os tamanhos da posição ideal. Como vimos no artigo anterior e também acima, uma coisa pode ser verificada com outra, mas a questão mais profunda pode ser como a função de correspondência relaciona o domínio com o codomínio.

Até agora, usamos coeficientes muito simples com base na regressão de resultados anteriores. Como você pode ver na fonte anexada no final deste artigo e dos anteriores, assumimos que uma constante simples mais um coeficiente para o valor do domínio foram adicionados para obter o valor do codomínio no que pode ser interpretado como uma relação linear simples. Mas, além de uma relação linear, os valores de domínio podem ser combinados a um codomínio usando uma relação quadrática, na qual, se o nosso expoente mais alto for dois, teremos um coeficiente adicional que é multiplicado pelo quadrado do valor do domínio para obter o análogo vinculado do codomínio. E, é claro, quanto mais expoentes forem usados, mais coeficientes serão necessários para definir o mapa do funtor.

Uma alternativa a essa abordagem simples e possivelmente propensa a erros seria usar uma rede neural para determinar a correspondência do homomorfismo entre dois domínios. Isso precisaria ser feito tanto para objetos quanto para morfismos e, necessariamente, apresentaria resultados mais precisos quando treinado com grandes quantidades de dados. Mas, deixando de lado a questão da precisão, essa é uma abordagem intuitivamente correta, já que as redes neurais são hábeis em receber várias entradas e gerar uma única saída, o que é aplicável neste caso.


Considerações finais

Os principais aspectos abordados neste artigo foram a compilação de dados do calendário econômico em um gráfico, a visualização do respectivo gráfico como uma categoria e, como em nosso artigo anterior, o uso da relação do funtor que apresenta defasagem em relação à volatilidade do Índice S&P 500 para fazer previsões sobre a volatilidade do Índice S&P 500. Como nos artigos anteriores desta série, usamos essas previsões para mover os trailing stops das posições abertas. Além do ajuste de stop loss para posições abertas, poderíamos usar a relação do funtor para definir o tamanho da posição de novas ordens ou até mesmo determinar um sinal de entrada para qualquer ativo negociado. Nesta série de artigos, nos absteremos desses dois últimos exemplos, pois estamos falando sobre a criação do EA usando o assistente IDE. Cabe ao usuário fazer as alterações necessárias de acordo com sua própria estratégia. Vimos também a definição de morphing e agora as relações do funtor. Usamos valores incrementais aproximados que poderiam ter uma relação linear ou quadrática do domínio para o codomínio, porém as redes neurais artificiais também podem ser usadas para definir esse mapeamento. Talvez esse tópico seja explorado em artigos futuros.


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

Arquivos anexados |
ct_14_1s.mqh (73.52 KB)
ct_15_w.mq5 (17.23 KB)
ct_15_w_n.mq5 (18.41 KB)
Redes neurais de maneira fácil (Parte 52): exploração com otimização e correção de distribuição Redes neurais de maneira fácil (Parte 52): exploração com otimização e correção de distribuição
À medida que a política do Ator se afasta cada vez mais dos exemplos armazenados no buffer de reprodução de experiências, a eficácia do treinamento do modelo, baseado nesse buffer, diminui. Neste artigo, examinamos um algoritmo que aumenta a eficácia do uso de amostras em algoritmos de aprendizado por reforço.
Desenvolvendo um agente de Aprendizado por Reforço em MQL5 com Integração RestAPI (Parte 4): Organizando Funções em Classes no MQL5 Desenvolvendo um agente de Aprendizado por Reforço em MQL5 com Integração RestAPI (Parte 4): Organizando Funções em Classes no MQL5
Este artigo examina a transição da codificação procedural para a Programação Orientada a Objetos (POO) no MQL5, com foco na integração com REST APIs. Discutimos como organizar funções de requisições HTTP (GET e POST) em classes, ressaltando vantagens como encapsulamento, modularidade e facilidade de manutenção. A refatoração de código é detalhada, mostrando a substituição de funções isoladas por métodos de classes. O artigo inclui exemplos práticos e testes.
Melhore os gráficos de negociação com uma interface gráfica interativa baseada em MQL5 (Parte III): Interface de negociação simples e móvel Melhore os gráficos de negociação com uma interface gráfica interativa baseada em MQL5 (Parte III): Interface de negociação simples e móvel
Nesta série de artigos, exploramos a integração de interfaces gráficas interativas em painéis de negociação móveis no MQL5. Na terceira parte, usamos os desenvolvimentos das partes anteriores para transformar painéis de negociação estáticos em dinâmicos.
Estratégia de negociação RSI Deep Three Move Estratégia de negociação RSI Deep Three Move
Este artigo apresenta a estratégia de negociação RSI Deep Three Move no MetaTrader 5. O artigo é baseado em uma nova série de pesquisas que demonstram vários métodos de negociação com base no RSI, que é um indicador técnico para medir a força e o impulso de ativos financeiros, incluindo ações, moedas e commodities.