Русский
preview
Redes neurais em trading: Modelo de consultas temporais (TQNet)

Redes neurais em trading: Modelo de consultas temporais (TQNet)

MetaTrader 5Sistemas de negociação |
15 0
Dmitriy Gizlyk
Dmitriy Gizlyk

Introdução

A previsão de séries temporais multivariadas em finanças é um jogo de antecipação, em que a aposta recai sobre precisão e velocidade. Cotações de moedas, índices, volumes de negociação, taxas de juros, indicadores de liquidez: todos esses parâmetros interagem continuamente, formando um sistema complexo e em constante mudança. Traders, gestores de ativos e analistas sabem que, para estar um passo à frente, é preciso entender como todas as variáveis influenciam umas às outras em tempo real. É justamente nessa capacidade de enxergar o quadro completo que está a essência da previsão moderna nos mercados financeiros.

O problema é que os dados financeiros não são como medições de laboratório, feitas em condições estéreis. O mercado tem vida própria, com saltos bruscos nas cotações após notícias, períodos de alta e baixa volatilidade e correlações inesperadas que surgem e desaparecem em poucas horas. Some-se a isso o ruído, como erros de medição, atrasos nas cotações e lacunas nos dados, e surge o problema clássico: como extrair um sinal confiável em um mundo repleto de aleatoriedade. A situação se torna especialmente difícil quando as relações locais entre os parâmetros em uma janela temporal contradizem o panorama geral observado ao longo de todo o histórico. É como tentar prever a cotação de uma moeda olhando apenas para um único dia, enquanto a tendência mensal aponta na direção oposta.

Para superar esse descompasso, no trabalho "Temporal Query Network for Efficient Multivariate Time Series Forecasting" propõe-se uma nova abordagem: a Temporal Query. Trata-se de uma ferramenta que permite combinar a visão local e a visão global do mercado. Essa abordagem se baseia em vetores treináveis, deslocados ciclicamente no tempo, que capturam dependências intermercado persistentes, confirmadas por todo o histórico de dados. Simultaneamente, as próprias cotações, os indicadores e os demais parâmetros de mercado atuam como chaves e valores no mecanismo de atenção multicabeça, preservando as características específicas de cada momento. Isso gera um efeito duplo: o modelo reage a mudanças imediatas e se apoia em relações de mercado mais estruturais e estáveis.

Com base nesse princípio, foi desenvolvido o framework Temporal Query Network (TQNet), uma solução arquitetural minimalista, porém poderosa, capaz de prever a dinâmica de vários instrumentos financeiros inter-relacionados. Sua estrutura é extremamente simples: apenas uma camada de atenção multicabeça e uma rede totalmente conectada rasa. Por trás dessa simplicidade, no entanto, está a capacidade de identificar dependências sutis entre ativos e reagir a elas mais rapidamente do que a maioria dos métodos tradicionais. Nos experimentos realizados pelos autores do framework, TQNet demonstrou precisão comparável à das arquiteturas mais complexas, operando com velocidade computacional semelhante à dos modelos lineares leves.

O diferencial do TQNet está na capacidade de se adaptar a diferentes horizontes de previsão, usando o mesmo princípio de equilíbrio entre dependências locais e globais. Isso é especialmente valioso nos mercados financeiros, em que o cenário pode mudar em questão de minutos, mas ainda assim obedecer a padrões de longo prazo que não podem ser ignorados.

Nos mercados financeiros modernos, vence não quem enxerga apenas os detalhes, nem quem se apoia somente no quadro geral, mas quem sabe combinar esses dois níveis de percepção. A abordagem Temporal Query e o TQNet oferecem exatamente essa possibilidade, e fazem isso com uma simplicidade elegante, digna de integrar o arsenal de qualquer analista técnico sério.


Algoritmo TQNet

No centro da previsão de séries temporais multivariadas (Multivariate Time Series Forecasting, MTSF) está o objetivo de prever o comportamento futuro de diversas variáveis interligadas. Formalmente, no instante t, temos uma sequência histórica observada XtRC*L. Aqui, C é o número de variáveis ou canais, como pares de moedas, índices de mercado, volumes de negociação e outros indicadores, enquanto L é o comprimento da janela de observação, isto é, quantos pontos passados são considerados. A tarefa consiste em construir uma previsão para o horizonte H, obtendo YtRC*H, uma sequência de valores futuros dessas mesmas variáveis.

Em termos de mercados financeiros, isso pode significar prever as cotações dos principais pares de moedas nas próximas horas, a dinâmica dos principais índices nos próximos pregões, ou a dinâmica das taxas de juros em um horizonte de várias semanas, com base nos dados de uma janela histórica selecionada. Ao mesmo tempo, é importante considerar não apenas os padrões temporais individuais de cada variável, mas também as correlações mútuas entre elas, pois o mercado se move como um único organismo, e mudanças em um segmento podem se refletir instantaneamente em outro.

Para resolver esse problema, foi proposto o framework Temporal Query Network (TQNet). Apesar da simplicidade da solução arquitetural, o framework combina dois mecanismos essenciais: a identificação de dependências entre variáveis e a modelagem da estrutura temporal.

O TQNet começa alimentando a camada de atenção multicabeça com a sequência analisada Xt, reforçada pelo componente Temporal Query (TQ-MHA). Essa camada é responsável por identificar e integrar correlações entre variáveis, tanto globais e estáveis ao longo do tempo quanto locais, características do contexto de mercado atual. Em seguida, o resultado é processado por um perceptron multicamadas (MLP) pouco profundo, que refina as dependências temporais e ajuda o modelo a capturar tendências e a cadência das mudanças.

Ambos os blocos, TQ-MHA e MLP, são complementados por conexões residuais, o que aumenta a estabilidade do treinamento e reduz o risco de degradação da qualidade em amostras grandes. A etapa final é uma camada linear com Dropout, que projeta as representações latentes obtidas para o espaço dos dados de saída, formando a previsão tRC*H.

O elemento-chave da arquitetura TQNet é o método Temporal Query (TQ), uma forma especial de gerar consultas (Query) no mecanismo de atenção. A ideia é simples e elegante: em vez de obter as consultas diretamente dos dados de entrada, como ocorre no Self-Attention clássico, os autores do framework propõem usar um conjunto de vetores treináveis, deslocados periodicamente no tempo. Essa técnica permite capturar correlações globais entre variáveis, estáveis diante das oscilações de curto prazo do mercado e do ruído.

Formalmente, dado o tamanho do período W dos dados analisados, inicializamos a matriz de parâmetros θTQRC*W. Aqui, C é o número de variáveis ou canais, enquanto W é o comprimento do vetor que define o intervalo do deslocamento periódico. Esses parâmetros são inicialmente preenchidos com zeros e, durante o treinamento, ajustam-se de forma adaptativa às dependências internas dos dados. A escolha de W é especialmente importante: nos mercados financeiros, ele pode corresponder, por exemplo, ao número de sessões de negociação em uma semana, a ciclos recorrentes de liquidez ou a outros padrões sazonais persistentes. Esse valor pode ser definido com base no conhecimento especializado sobre o mercado ou por meio de métodos estatísticos.

O princípio de funcionamento do TQ é o seguinte: para cada exemplo analisado no instante t, extraímos da matriz θTQ uma janela de comprimento L, a partir da posição calculada como t mod W e, se necessário, fechando a seleção de forma circular. Assim, dois instantes distantes exatamente W passos terão vetores de consulta idênticos. Isso cria um efeito de memória periódica, permitindo que o modelo reutilize dependências globais aprendidas e reduza a influência de perturbações aleatórias do mercado.

No contexto financeiro, isso pode ser comparado a um trader experiente que se lembra de cenários típicos de mercado nos mesmos dias da semana ou em determinados horários de negociação, e usa esse conhecimento ao analisar a situação atual.

No TQNet, essa abordagem é incorporada ao mecanismo de atenção multicabeça (TQ-MHA). Aqui, as Consultas (Query) não são geradas a partir dos dados de entrada, mas dos vetores temporais TQ, que refletem dependências globais. Ao mesmo tempo, as Chaves (Key) e os Valores (Value) continuam sendo extraídos da sequência analisada atual Xt, preservando toda a informação local e específica sobre o mercado naquele momento.

O índice h corresponde ao identificador da cabeça de atenção, enquanto W h Q, W h K, W h V são matrizes de projeção treináveis.

Em seguida, a atenção é calculada para cada cabeça.

Depois, assim como no Multi-Head Self-Attention clássico, os resultados são combinados e passam pela projeção final.

Essa combinação de Consultas globais com Chaves e Valores locais cria um equilíbrio entre robustez ao ruído e adaptação ao contexto atual. Em dados reais de mercado, em que períodos de calmaria podem dar lugar abruptamente a fases de alta turbulência, esse equilíbrio é crítico. O modelo não perde a capacidade de reagir a eventos específicos, como estatísticas macroeconômicas inesperadas ou movimentos bruscos provocados por notícias, mas, ao mesmo tempo, apoia-se em uma estrutura de dependências globais que persistem ao longo do tempo.

O objetivo da técnica Temporal Query (TQ) proposta é integrar de maneira natural, dentro do mecanismo de atenção, tanto as relações globais quanto as locais da série temporal. A ideia é simples, mas eficaz: as consultas (Query) não são geradas diretamente a partir dos dados de entrada, e sim a partir de vetores treináveis θTQ deslocados periodicamente, enquanto as chaves (Key) continuam sendo extraídas da sequência original. Essa abordagem permite equilibrar a visão geral do mercado com as características individuais de cada fragmento específico dos dados.

Para avaliar na prática o impacto das dependências globais e locais, os autores do framework compararam três cenários:

  1. A variante clássica, em que Query e Key são gerados a partir dos dados brutos. Nesse caso, a atenção captura apenas relações locais, específicas da amostra, entre as observações.
  2. A abordagem mista, que é justamente a implementada no TQNet. Aqui, Query é gerado a partir dos vetores TQ treináveis, enquanto Key é extraído dos dados de entrada. Como resultado, no cálculo dos pesos de atenção, são consideradas tanto as dependências globais quanto as específicas da amostra, algo especialmente importante nos mercados financeiros, onde tendências gerais se entrelaçam com oscilações de curto prazo.
  3. O esquema puramente global, em que Query e Key são gerados a partir dos vetores TQ treináveis. Esse método ignora completamente as variações locais e se concentra na estrutura geral da série temporal.

Os resultados consolidados, obtidos em grandes datasets multivariados com mais de 100 variáveis e com média calculada sobre quatro horizontes de previsão, mostram que o melhor desempenho foi alcançado justamente pela abordagem TQNet. Nela, os dois tipos de correlação são combinados. Em segundo lugar ficou o esquema tradicional, baseado apenas em dependências locais da amostra, enquanto a variante puramente global ficou em último entre os três cenários. A conclusão é clara: a combinação harmoniosa de dependências globais e locais aumenta a precisão da previsão e a robustez do modelo, algo especialmente valioso ao trabalhar com séries financeiras dinâmicas.

Depois de a camada TQ-MHA extrair as relações persistentes entre variáveis e integrá-las à informação local, entra em cena o perceptron multicamadas (MLP). Sua função é refinar as representações já extraídas na dimensão temporal, capturando tendências, cadência e defasagens nas relações.

Apesar da simplicidade, o MLP continua sendo uma ferramenta surpreendentemente eficaz para extrair padrões temporais. Na arquitetura TQNet, ele é implementado em uma versão leve: apenas duas camadas totalmente conectadas com ativação GeLU, que proporciona um processamento mais suave dos sinais em comparação com a ReLU, especialmente em condições de oscilações complexas do mercado.

Na prática financeira, essa etapa pode ser comparada a uma situação em que o analista, depois de receber um panorama das principais relações do mercado, faz uma análise adicional: identifica padrões intradiários, avalia as amplitudes das oscilações e detecta pontos de inércia e reversão.

Em seguida, as representações obtidas seguem para a camada de projeção de saída. Aqui, aplica-se uma transformação linear que adapta as representações internas ao horizonte de previsão H. Além disso, pode-se usar Dropout para reduzir o risco de sobreajuste e aumentar a robustez do modelo.

A TQNet também dá atenção especial à robustez diante de deslocamentos de distribuição dos dados, um fenômeno extremamente comum no ambiente financeiro. Cotações de moedas, preços de commodities e índices acionários podem ter suas características estatísticas alteradas bruscamente sob influência de notícias, fatores macroeconômicos ou decisões regulatórias. Se o modelo ficar preso a uma distribuição antiga, suas previsões perdem relevância rapidamente.

Para evitar isso, o framework TQNet usa normalização de instância reversível (RevIN), um método já testado em várias arquiteturas modernas. A ideia é simples: antes do processamento, o modelo subtrai a média e divide os dados pelo desvio-padrão; depois de gerar a previsão, reverte os valores para a escala original. Em termos de trading, isso pode ser comparado ao modo como um analista experiente sempre recalibra seus referenciais quando as condições de mercado mudam. A normalização remove deslocamentos de curto prazo na escala e na volatilidade, permitindo que o modelo se concentre nos padrões, e não em variações aleatórias na escala das cotações.

Assim, no TQNet, o MLP e a projeção de saída funcionam como a etapa final de refinamento da previsão. O TQ-MHA fornece a estrutura-base das dependências intervariáveis, o MLP as processa na dimensão temporal e a normalização protege o modelo contra distorções estatísticas. Como resultado, o modelo gera uma previsão que considera as características locais do momento atual e, ao mesmo tempo, preserva a coerência global do mercado.

A visualização do framework TQNet elaborada pelos autores é apresentada abaixo.


Implementação com MQL5

Depois de analisarmos os fundamentos teóricos do framework TQNet e mostrarmos por que a combinação de correlações globais e locais pode aumentar a precisão da previsão, chegou o momento de passar dos conceitos à prática. Agora vamos nos concentrar em uma das formas de implementar essas ideias no ambiente MQL5, adaptando a arquitetura às tarefas de análise e previsão de séries temporais nos mercados financeiros.

Aqui, cada elemento, desde a geração de consultas e chaves até a normalização dos dados e a projeção dos resultados, será implementado em código. Isso nos permitirá demonstrar como a teoria se transforma em uma ferramenta pronta para o trading real. Com isso, será possível testar a eficácia do TQNet em condições de cotações em tempo real e avaliar sua robustez em diferentes fases do mercado: desde lateralizações tranquilas até tendências aceleradas.

Com a experiência acumulada na construção de diferentes módulos de atenção, é possível fazer uma comparação técnica consistente entre o TQNet e o bloco clássico de Cross-Attention. No esquema tradicional, a atenção cruzada opera com tensores de consultas (Queries), chaves (Keys) e valores (Values), gerados com base em diferentes fontes de dados. Essa abordagem permite que uma sequência processe por meio da atenção as informações contidas em outra, identificando as relações entre elas.

No caso do TQNet, esse princípio é adaptado de forma mais refinada e direcionada à previsão de séries temporais. Aqui, as fontes de dados são distribuídas de modo que Query carregue a informação global generalizada incorporada nos vetores treináveis θTQ, enquanto Key preserva a ligação com a estrutura local dos dados de entrada. Essa combinação desempenha um papel essencial nos mercados financeiros, em que padrões gerais, como sazonalidade ou ciclos macroeconômicos recorrentes, precisam ser integrados a mudanças locais, como saltos bruscos de preços, ruídos de mercado e desequilíbrios de curto prazo entre oferta e demanda.

Assim, o TQNet pode ser visto como uma espécie de híbrido de atenção cruzada, no qual a memória global do modelo e os sinais imediatos do mercado são combinados em um único mecanismo. Isso não apenas amplia o conjunto de relações consideradas, como também torna o modelo mais robusto a transições abruptas de regime, algo especialmente valioso em condições de alta volatilidade nos mercados cambial, acionário ou de commodities.

Nesse contexto, surge uma tarefa central: construir e treinar o tensor de parâmetros de correlação global, que será usado como fonte de dados para a geração das consultas. É justamente esse tensor, formado pelos vetores treináveis θTQ, que carrega a informação sobre as relações globais entre as variáveis e serve de base para a construção correta do mecanismo de atenção.

Seu treinamento exige cuidado: o tensor precisa se adaptar à estrutura dos dados, capturando correlações persistentes, mas sem perder robustez ao ruído e aos valores atípicos locais. Em séries financeiras, isso é especialmente importante, pois as séries temporais dos ativos estão sujeitas a oscilações bruscas, que vão de picos de liquidez de curto prazo a eventos inesperados de mercado.

Ao construir e treinar esse tensor, damos ao modelo a capacidade de usar padrões globais de mercado ao processar cada nova sequência. As consultas geradas com base nele atuam como um filtro, direcionando a atenção do modelo para as relações mais relevantes entre as variáveis e, ao mesmo tempo, integrando-as às características locais da janela temporal atual. Isso permite que o TQNet alcance alta precisão de previsão, combinando estabilidade da memória global com a adaptabilidade a condições específicas de mercado.

Já contamos com o objeto CParams, no qual está implementado o algoritmo de criação e gerenciamento de parâmetros treináveis. Teoricamente, poderíamos usá-lo para gerar o tensor de correlações globais. No entanto, surge a questão da eficiência dessa abordagem.

O ponto é que, para problemas de previsão de séries temporais multivariadas nos mercados financeiros, é necessário um tensor suficientemente grande, capaz de representar correlações ao longo de todo o ciclo dos dados analisados. Por outro lado, um tensor excessivamente grande levará a custos computacionais significativos, o que afetará negativamente a velocidade de treinamento e a operação do modelo em tempo real.

Além disso, a maior parte desses recursos computacionais seria usada em vão. A cada etapa de treinamento ou previsão, utilizamos apenas uma pequena parte do tensor, correspondente à janela temporal atual. O restante permanece passivo, e os cálculos sobre essa parte acabam sendo praticamente inúteis.

Ao mesmo tempo, o volume do tensor e o número de operações sem efeito útil crescem proporcionalmente ao aumento do comprimento do ciclo e do número de variáveis analisadas. Para dados financeiros, em que o número de canais pode chegar a centenas e os períodos históricos podem incluir milhares de passos temporais, essa ineficiência rapidamente se transforma em um gargalo, desacelerando o treinamento e reduzindo o desempenho geral do modelo.

Por isso, é extremamente importante buscar soluções que permitam reduzir cálculos desnecessários, sem comprometer a capacidade do modelo de capturar correlações globais sem perda de precisão.

Em busca de uma solução mais eficiente, decidimos reformular em parte a forma de armazenar e atualizar os parâmetros de correlação. Em vez de usar um único objeto CParams estático para gerar todo o tensor, criamos uma cópia desse objeto, na qual implementamos um array de objetos internos de parâmetros treináveis.

Agora, cada elemento do array corresponde a um passo temporal específico, o que permite usar apenas os dados e parâmetros relevantes para a janela de previsão atual. Essa abordagem reduz significativamente os cálculos desnecessários e, ao mesmo tempo, preserva a capacidade do modelo de capturar relações globais entre variáveis ao longo de todo o período de análise.

Em outras palavras, obtivemos um tensor dinâmico de parâmetros, no qual cada elemento corresponde a um instante específico, enquanto as operações desnecessárias sobre os demais passos são completamente eliminadas. Isso torna nossa implementação do TQNet muito mais econômica e escalável para grandes datasets financeiros.

Após analisarmos o conceito de tensor dinâmico de parâmetros e justificar o uso de um array de objetos para cada passo temporal, o próximo passo natural é examinar a implementação dessa abordagem no código. Em nossa arquitetura, o papel central é desempenhado pela classe CCircleParams, que herda a funcionalidade básica da camada neural totalmente conectada CNeuronBaseOCL.

class CCircleParams  :  public CNeuronBaseOCL
  {
protected:
   CLayer            cOnes;
   CNeuronBaseOCL    *cCurrent;
   //---
   virtual bool      feedForward(CNeuronBaseOCL *NeuronOCL) override          { return FeedForward(); }

   ///\ingroup neuron_base_opt
   virtual bool      updateInputWeights(CNeuronBaseOCL *NeuronOCL) override   { return UpdateInputWeights(); }
   virtual bool      calcInputGradients(CNeuronBaseOCL *NeuronOCL) override   { return true; }

public:
                     CCircleParams(void) : cCurrent(NULL) {};
                    ~CCircleParams(void)  {};
   //---
   virtual bool      Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                          uint numNeurons, uint period, 
                          ENUM_OPTIMIZATION optimization_type, uint batch);
   virtual bool      Identity(const int rows, const int cols);
   virtual bool      Zeros(void);
   //---
   virtual bool      FeedForward(void);
   virtual bool      UpdateInputWeights(void);
   virtual bool      SetPosition(int position);
   //---
   virtual bool      Save(const int file_handle) override;
   virtual bool      Load(const int file_handle) override;
   //---
   virtual int       Type(void) override const  {  return defCircleParams; }
   virtual void      SetOpenCL(COpenCLMy *obj) override;
   virtual CBufferFloat   *getWeightsParams(void);
   virtual int       GetPeriod(void) const { return cOnes.Total(); }
   //---
   virtual bool      WeightsUpdate(CNeuronBaseOCL *source, float tau) override;
  };

Essa classe representa um contêiner especializado para armazenar e controlar parâmetros treináveis de correlação, garantindo a atualização correta desses parâmetros e a interação eficiente com os mecanismos do contexto OpenCL, algo especialmente importante ao trabalhar com grandes conjuntos de dados financeiros na GPU.

Dentro da classe CCircleParams, destaca-se o objeto cOnes, um array dinâmico de tensores treináveis que sustenta o comportamento periódico do contêiner. O parâmetro cCurrent aponta para o objeto ativo no array e reflete o estado de um passo temporal específico. Isso permite que o modelo alterne dinamicamente o contexto operacional, processando cada janela temporal com máxima precisão e, ao mesmo tempo, preservando as dependências globais acumuladas ao longo de todo o período de análise.

A estrutura do objeto CCircleParams é definida e configurada no método de inicialização Init, responsável por preparar todos os componentes necessários para a operação correta do tensor de parâmetros de correlação.

bool CCircleParams::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                         uint numNeurons, uint period,
                         ENUM_OPTIMIZATION optimization_type, uint batch)
  {
   if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, numNeurons, optimization_type, batch))
      return false;

Ao chamar o método, primeiro são inicializadas as interfaces herdadas por meio da classe-base CNeuronBaseOCL, o que define os parâmetros fundamentais do objeto. Se ocorrer algum erro nessa etapa, o método retorna false imediatamente, impedindo uma operação incorreta nas etapas seguintes.

Em seguida, preparamos o array dinâmico cOnes: limpamos o array e o vinculamos ao contexto OpenCL, para que todas as operações posteriores sobre os tensores possam ser executadas com eficiência na GPU.

   cOnes.Clear();
   cOnes.SetOpenCL(OpenCL);
   for(uint i = 0; i < period; i++)
     {
      cCurrent = new CNeuronBaseOCL();
      if(!cCurrent)
         return false;
      if(!cCurrent.Init(Neurons(), i, OpenCL, 1, optimization, iBatch) ||
         !cOnes.Add(cCurrent))
        {
         delete cCurrent;
         return false;
        }
      cCurrent.SetActivationFunction(None);
     }

O laço principal do método é responsável por construir o array de objetos, sendo que cada um corresponde a um passo temporal específico. Para cada um desses passos, é criada uma nova instância de CNeuronBaseOCL, que é inicializada com os mesmos parâmetros ajustados para o respectivo passo. Após a inicialização bem-sucedida, o objeto é adicionado ao contêiner cOnes, que gerencia todos os passos temporais. Em caso de qualquer erro, o objeto em criação é imediatamente liberado, evitando vazamentos de memória e preservando a integridade da estrutura.

Para cada neurônio recém-criado, a função de ativação também é desativada, o que é importante para a operação correta do tensor de correlações, no qual, na etapa de propagação para frente, é necessário apenas o repasse dos valores, sem transformação não linear.

Depois de criados todos os objetos dos passos temporais, o método SetPosition define o primeiro elemento do nosso array como ativo, garantindo o estado inicial para os cálculos seguintes.

//---
   if(!SetPosition(0))
      return false;
//---
   return true;
  }

Assim, o método Init não apenas cria um array de objetos, mas constrói um repositório estruturado e gerenciado de parâmetros, em que cada elemento representa um instante específico. Isso permite que o modelo use correlações globais com eficiência, evitando cálculos desnecessários e deixando o modelo pronto para o treinamento e a previsão de séries temporais financeiras multivariadas.

O método SetPosition desempenha um papel central no gerenciamento do tensor dinâmico de parâmetros de correlação em CCircleParams. Sua função é definir o objeto correspondente a um passo temporal específico como ativo, permitindo que o modelo opere com os dados relevantes daquele instante.

Ao chamar o método, o ponteiro cCurrent é redirecionado para o elemento do array cOnes correspondente à posição definida. Se o objeto selecionado estiver ausente ou não tiver sido inicializado, o método retorna false, sinalizando o problema e impedindo cálculos incorretos. Caso contrário, quando o objeto é selecionado com sucesso, o método retorna true, confirmando que o modelo está pronto para continuar o processamento dos dados.

bool CCircleParams::SetPosition(int position)
  {
   cCurrent = cOnes[position];
   if(!cCurrent)
      return false;
//---
   return true;
  }

A simplicidade da implementação esconde uma funcionalidade importante: é justamente por meio de SetPosition que o modelo TQNet pode alternar dinamicamente entre diferentes passos temporais, ativando os parâmetros de correlação correspondentes sem a necessidade de recriar ou recarregar todo o tensor. Para séries temporais financeiras, isso é especialmente importante, pois cada nova janela temporal exige considerar dependências locais e globais, e o gerenciamento eficiente da posição ativa permite que o modelo permaneça rápido e adaptável mesmo com grandes volumes de dados.

Convém destacar que, na inicialização padrão, ao executar o método Init, todos os tensores de correlações globais são preenchidos com valores aleatórios. Para a maioria dos cenários, essa abordagem é perfeitamente aceitável: a inicialização aleatória garante diversidade nas condições iniciais e permite que os parâmetros treináveis se adaptem gradualmente à estrutura dos dados.

No entanto, os autores do framework TQNet recomendam outra abordagem: inicializar o tensor com valores zero. Esse método é especialmente justificável ao trabalhar com séries temporais financeiras, em que é importante iniciar o treinamento sem pressupostos prévios sobre as correlações entre as variáveis, para que o modelo possa identificar gradualmente as dependências persistentes exclusivamente com base nos dados históricos.

Para implementar essa abordagem em CCircleParams, é criado o método Zeros, que define sequencialmente como zero os parâmetros de todos os passos temporais. Ao chamar esse método, cada elemento do array cOnes é processado, e todos os valores do tensor de correlações globais são definidos como zero. Isso permite estabelecer uma base limpa para o treinamento, garantindo que as previsões iniciais do modelo não sejam enviesadas por valores iniciais aleatórios e que toda a adaptação seja determinada estritamente pelos dados analisados e pela estrutura do TQNet.

bool CCircleParams::Zeros(void)
  {
   matrix<float> zeros = matrix<float>::Zeros(Neurons(), 2);
//---
   CBufferFloat *w = NULL;
   for(int i = 0; i < cOnes.Total(); i++)
     {
      if(!cOnes[i])
         return false;
      w = cOnes[i].getWeights();
      if(!w || !w.AssignArray(zeros))
         return false;
      w.BufferFree();
      if(!w.BufferCreate(OpenCL))
         return false;
     }
//---
   return FeedForward();
  }

Assim, o método Zeros oferece uma forma conveniente e eficiente de controlar o estado inicial das correlações globais, aumentando a transparência e a previsibilidade do treinamento do modelo em dados financeiros.

Como alternativa à inicialização com zeros, implementamos um método que permite inicializar o tensor de correlações globais com uma matriz identidade. Essa abordagem pode ser útil quando é necessário definir as variáveis como independentes no início, permitindo que o modelo identifique gradualmente as dependências reais entre elas durante o treinamento.

O método Identity começa verificando se as dimensões da matriz a ser criada são compatíveis com o número de neurônios no objeto.

bool CCircleParams::Identity(const int rows, const int cols)
  {
   if(rows * cols != Neurons())
      return false;
   matrix<float> ident = matrix<float>::Identity(rows, cols);
   if(!ident.Reshape(rows * cols, 1))
      return false;
   if(!ident.Resize(rows * cols, 2))
      return false;
   if(!ident.Col(vector<float>::Zeros(rows * cols), 1))
      return false;

Em seguida, é formada uma matriz identidade com as dimensões especificadas, que depois é transformada e escalonada para se ajustar às estruturas internas de dados da classe. O método dá atenção especial à preparação e à realocação da memória por meio dos métodos Reshape e Resize, bem como ao zeramento da coluna adicional de vieses para garantir a operação correta durante a atribuição de valores.

Após a preparação da matriz, o método percorre todos os passos temporais no contêiner cOnes.

   CBufferFloat *w = NULL;
   for(int i = 0; i < cOnes.Total(); i++)
     {
      if(!cOnes[i])
         return false;
      w = cOnes[i].getWeights();
      if(!w || !w.AssignArray(ident))
         return false;
      w.BufferFree();
      if(!w.BufferCreate(OpenCL))
         return false;
     }
//---
   return FeedForward();
  }

Para cada passo, os pesos são obtidos pelo método getWeights e recebem o conteúdo da matriz identidade preparada. Depois disso, o buffer do contexto OpenCL é liberado e recriado com os novos valores, garantindo a interação correta com a GPU durante o treinamento subsequente do modelo.

O processo termina com a chamada do método FeedForward, que permite verificar imediatamente se os valores estão sendo propagados corretamente pela camada. Essa forma de inicialização garante que as correlações globais entre as variáveis não estejam enviesadas no início do treinamento e partam de um estado neutro. Ao mesmo tempo, ela preserva a estrutura que permite que o modelo acumule e considere as dependências reais de maneira eficiente durante a previsão.

No contexto financeiro, isso é especialmente importante: a matriz identidade define um ponto de partida limpo para cada variável, eliminando qualquer viés inicial e, ao mesmo tempo, permitindo que o modelo identifique gradualmente inter-relações de mercado persistentes, como correlações entre ativos.

Depois de analisarmos em detalhes os algoritmos de inicialização e as formas de preparar os parâmetros iniciais de correlação, é natural passar a descrever o algoritmo de propagação para frente, uma das etapas centrais da operação da classe CCircleParams.

O método FeedForward prepara os parâmetros globais de correlação correspondentes ao passo temporal atual, permitindo que o modelo atualize seus estados internos.

bool CCircleParams::FeedForward(void)
  {
   if(!cCurrent)
      if(!SetPosition(0))
         return false;
//---
   return CNeuronBaseOCL::feedForward(cCurrent);
  }

Primeiro, o método verifica se o passo ativo foi definido no ponteiro cCurrent. Se o objeto atual não estiver definido, o método SetPosition é chamado para selecionar automaticamente o primeiro passo temporal no array cOnes, garantindo que os cálculos comecem em um estado válido.

Depois de definido o passo ativo, o controle é passado para o método homônimo da classe-base, o que permite formar os parâmetros necessários de correlação global.

Assim, FeedForward atua como um elo entre a estrutura preparada do tensor de parâmetros de correlação global e o mecanismo de atenção do TQNet. A abordagem proposta favorece a flexibilidade e a precisão das previsões, tornando o modelo capaz de reagir tanto às oscilações locais do mercado quanto às tendências de longo prazo.

Após analisar o mecanismo de propagação para frente e verificar como FeedForward propaga corretamente os dados pelo passo temporal ativo, o próximo passo natural é examinar o método UpdateInputWeights, responsável pela atualização dos parâmetros do modelo.

Esse método desempenha um papel central no treinamento: é aqui que os pesos e parâmetros de correlação são alterados com base nos gradientes calculados, permitindo que o modelo se adapte gradualmente à estrutura dos dados. Em CCircleParams, o método é implementado transferindo o controle ao método homônimo da classe-base, com a indicação do elemento ativo do passo temporal.

bool CCircleParams::UpdateInputWeights(void)
  {
   return CNeuronBaseOCL::updateInputWeights(cCurrent);
  }

O ponteiro passado para o objeto atual do passo temporal garante que a atualização ocorra apenas no segmento relevante do tensor. Isso aumenta a eficiência e evita cálculos desnecessários sobre os demais passos temporais.

Convém destacar especialmente que, nesta etapa, optamos conscientemente por não verificar a validade do ponteiro armazenado em cCurrent. Essa escolha é intencional. É extremamente importante que, durante a propagação para frente e a propagação reversa, o modelo use o mesmo objeto de passo temporal. Qualquer redefinição desse objeto durante a atualização dos pesos poderia comprometer a consistência dos cálculos e causar erros na adaptação dos parâmetros.

Ao mesmo tempo, o método da classe-base fica responsável pela validade do ponteiro. Se ocorrer algum erro, ele simplesmente retornará false, impedindo uma atualização incorreta dos pesos. Essa abordagem permite focar no essencial: a atualização dos parâmetros do passo temporal atual, sem sobrecarga adicional e sem o risco de comprometer a estrutura do tensor de parâmetros de correlação global.

Para séries temporais financeiras, isso é especialmente importante. O modelo opera de forma confiável com os dados atuais de cada passo e, ao mesmo tempo, preserva os padrões globais, o que favorece a precisão das previsões e a estabilidade do treinamento, mesmo diante de mudanças dinâmicas e ruidosas do mercado.

Acredito que você tenha notado que omitimos a etapa de propagação dos gradientes de erro para as camadas inferiores do modelo. Em vez disso, o método calcInputGradients é sobrescrito por um stub que sempre retorna true. Essa abordagem pode parecer incomum, mas basta para atualizar os parâmetros de correlação global. O modelo precisa apenas conhecer os gradientes do erro no nível da saída da camada para corrigir os pesos do passo temporal atual.

Nesse caso, os dados subjacentes não participam dos cálculos, pois o objeto CCircleParams, na prática, não usa entradas externas de origem. Propagar os gradientes para esse nível não faz sentido.

Ainda assim, o uso do stub cumpre uma função importante: ele permite integrar o novo objeto à estrutura geral do modelo, mantendo a compatibilidade com os demais componentes da rede e permitindo atualizar corretamente os pesos sem sobrecarga desnecessária.

Juntos, esses recursos transformam o CCircleParams de uma ideia abstrata de tensor dinâmico de parâmetros de correlação global em um objeto totalmente gerenciado, capaz de se integrar eficientemente ao TQNet. O modelo passa a capturar padrões globais persistentes e, ao mesmo tempo, incorporar as características locais dos dados em cada passo temporal. Para os mercados financeiros, isso é especialmente importante: o modelo aprende a reconhecer ciclos sazonais recorrentes, correlações persistentes entre ativos, além de reagir a oscilações de curto prazo, ruído de mercado e eventos repentinos.

Avançamos bastante, e o artigo já ficou bastante extenso. Tudo o que foi apresentado exige tempo para que as informações sejam assimiladas e amadureçam na mente do leitor. Chegou a hora de fazer uma breve pausa para refletir sobre o material acumulado.

No próximo artigo, continuaremos a implementação, avançaremos para a construção dos algoritmos de atenção e para a integração completa dos componentes do TQNet, demonstrando como as estruturas e os métodos descritos se transformam em uma ferramenta eficiente para a previsão de séries temporais financeiras.


Conclusão

Neste artigo, conhecemos o framework TQNet, que combina modularidade, flexibilidade e alto desempenho. Isso o torna uma ferramenta especialmente valiosa para tarefas de previsão e análise de séries temporais financeiras. A arquitetura do framework foi projetada para que cada componente desempenhe uma função claramente definida, enquanto a substituição ou atualização de módulos individuais não exige a reformulação de todo o sistema.

A parte prática foi dedicada à implementação do novo objeto CCircleParams, destinado ao gerenciamento dos parâmetros de correlação global. Analisamos em detalhes sua inicialização, a implementação dos passos temporais e também desenvolvemos algoritmos alternativos para definir os valores iniciais dos tensores. Demos atenção especial à construção da propagação para frente, ao mecanismo de atualização dos pesos e à sincronização dos cálculos entre os passos temporais.

Assim, obtivemos um elemento flexível e confiável do framework, pronto para operar plenamente como parte de modelos mais complexos. No próximo artigo, vamos nos concentrar na construção de uma cadeia computacional integrada e realizar testes em dados históricos para avaliar a eficiência e a robustez do sistema em condições reais do mercado financeiro.


Links


Programas utilizados no artigo

# Nome Tipo Descrição
1 Study.mq5 EA EA para treinamento offline de modelos
2 StudyOnline.mq5 EA EA para treinamento online de modelos
3 Test.mq5 EA EA para teste do modelo
4 Trajectory.mqh Biblioteca de classe Estrutura para descrever o estado do sistema e a arquitetura dos modelos
5 NeuroNet.mqh Biblioteca de classe Biblioteca de classes para criação de rede neural
6 NeuroNet.cl Biblioteca Biblioteca de código OpenCL

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/19157

Arquivos anexados |
MQL5.zip (2987.62 KB)
Redes neurais em trading: Modelo de consultas temporais (Final) Redes neurais em trading: Modelo de consultas temporais (Final)
Apresentamos a etapa final de implementação e teste do framework TQNet, na qual a teoria se encontra com a prática real de trading. Percorreremos o caminho do treinamento histórico até o teste de estresse em dados recentes de mercado, avaliando a robustez e a precisão do modelo. Os resultados finais não são apenas números frios, mas também uma demonstração clara do valor prático da abordagem proposta.
Rede neural na prática: Lendo PNG do MNIST Rede neural na prática: Lendo PNG do MNIST
Aqui veremos como implementar um algorítimo simples de leitura de imagens no formato PNG. Conseguir efetuar a leitura do conteúdo destas imagens será importante para podermos avançar no desenvolvimento de uma topologia de rede perceptron. Isto por conta de que começaremos a fazer uso do banco de dados MNIST no treinamento da rede que será implementada.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Do básico ao intermediário: Arquivo template (III) Do básico ao intermediário: Arquivo template (III)
No passado, publiquei um artigo que gerou muita confusão e proporcionou pouco entendimento por parte de muitos que o leram. Pois bem, neste artigo, vamos rever de forma muito mais bem explicada, exatamente aquele conceito que outrora não fazia nenhum sentido. Ou seja, vamos ver como colocar mais de um indicador em uma única sub janela de forma que eles sejam facilmente lidos e compreendidos.