Redes neurais em trading: Dos transformers aos neurônios spiking (Conclusão)
Introdução
Os mercados financeiros podem ser comparados a um imenso oceano, cujas ondas sobem e descem a cada segundo. Às vezes, o mar está calmo e previsível; em outros momentos, torna-se turbulento e ameaça virar a embarcação; e há ainda ocasiões em que exibe uma superfície aparentemente tranquila, ocultando fortes correntes logo abaixo. Nesse oceano, o trader se assemelha a um capitão que precisa distinguir não cada ondulação da água, mas justamente a rajada de vento capaz de indicar a direção correta. Um erro de percepção ou uma interpretação equivocada dos sinais, e a embarcação pode naufragar. Essa metáfora resume a essência da busca por ferramentas analíticas eficientes. O que importa não é a quantidade de informações, mas sua qualidade e a capacidade de extrair significado do caos.
É justamente nesse ponto que o framework SpikingBrain abre novos horizontes. Ele se baseia em princípios de processamento orientado a eventos. O sistema não reage a um fluxo contínuo de dados, mas apenas aos impulsos que carregam informações realmente relevantes. Para o trader, isso significa que o modelo não se perde em meio ao ruído do mercado, mas aprende a identificar sinais genuínos capazes de alterar o rumo das operações.
Na aplicação aos mercados financeiros, isso oferece uma série de vantagens. Em primeiro lugar, reduz os custos computacionais, algo especialmente importante ao processar dados de alta frequência. O modelo torna-se mais leve e rápido e pode ser integrado com facilidade às plataformas de trading sem provocar uma carga excessiva sobre o sistema. Em segundo lugar, aumenta a estabilidade do modelo diante do ruído, permitindo obter sinais de trading mais limpos e reduzir a probabilidade de entradas falsas. Por fim, em terceiro lugar, o SpikingBrain possibilita uma resposta adaptativa, ou seja, a capacidade do modelo de se reajustar rapidamente quando o mercado muda de direção de forma inesperada.
O framework SpikingBrain chama atenção não apenas por sua filosofia de percepção orientada a eventos, mas também por uma arquitetura que transforma essa filosofia em uma ferramenta prática. Em sua base está a ideia de representar o fluxo de dados como uma sequência de impulsos discretos, ou spikes. Cada um desses impulsos não surge continuamente, mas apenas quando ocorre um evento que rompe o equilíbrio anterior. Isso permite substituir a análise contínua pelo processamento de pontos compactos, porém altamente informativos.
A arquitetura do SpikingBrain é composta por vários módulos fundamentais, cada um responsável por um aspecto específico da percepção do mercado. O primeiro elemento que chama atenção são os neurônios spiking com limiar adaptativo. Eles reagem apenas a eventos que fogem do padrão habitual. O limiar de ativação varia dinamicamente de acordo com o comportamento dos dados, fazendo com que o modelo se torne mais sensível quando necessário ou, ao contrário, filtre pequenas oscilações.
O segundo elemento fundamental é o módulo de atenção. Os Transformers clássicos são conhecidos por sua capacidade de lidar com o contexto. Mas essa capacidade tem um custo elevado. Quanto mais longa a sequência, maior o custo computacional. O SpikingBrain aborda esse problema de outra forma. Ele utiliza atenção linear e uma estratégia de janela deslocada. Nas versões mais complexas, adota uma abordagem híbrida, na qual diferentes tipos de atenção atuam em conjunto. Isso permite ao modelo processar longas sequências de preços e volumes sem custos computacionais excessivos, preservando a capacidade de enxergar o contexto geral.
O mecanismo Mixture of Experts ocupa um papel de destaque. Na versão com arquitetura expandida, nem todos os blocos do modelo operam simultaneamente. Apenas os componentes necessários em determinada situação são ativados. Em essência, isso reflete a própria estratégia do trader, que em condições normais opera de forma mais moderada, mas, durante movimentos intensos, atua com concentração redobrada.
Talvez a solução mais elegante do SpikingBrain, porém, seja o sistema de codificação de eventos em spikes. Os dados de entrada são convertidos em uma sequência de impulsos, na qual cada disparo representa não apenas uma mudança no preço, mas também sua relevância. A frequência e a intensidade dos spikes tornam-se uma espécie de linguagem por meio da qual o modelo descreve o mercado. Se o movimento é fraco, o sinal é raro e discreto. Se o mercado entra em forte movimento, os spikes se transformam em um verdadeiro toque de sinos, e o sistema reage imediatamente.
Portanto, o SpikingBrain não é apenas um conjunto de artifícios matemáticos, mas uma tentativa de construir um modelo que pensa em termos de eventos. Ele aprende a escutar o mercado. E é justamente por isso que sua arquitetura merece uma análise cuidadosa, especialmente no contexto de aplicações nos mercados financeiros.
A visualização do framework SpikingBrain proposta pelos autores é apresentada a seguir.

Toda arquitetura em ciência e tecnologia permanece apenas como um esquema no papel até que suas linhas e blocos ganhem vida em uma implementação concreta. É por isso que nossa análise do SpikingBrain segue uma sequência lógica. Avançamos passo a passo para que as ideias não permaneçam abstratas, mas se transformem em ferramentas reais de análise. A arquitetura discutida acima define a direção e estabelece a estrutura geral. Porém, qualquer construção só adquire sentido quando seus componentes passam a fazer parte da implementação prática e os módulos teóricos se transformam em código capaz de responder ao fluxo do mercado.
Nosso percurso começou com o primeiro contato com o SpikingBrain. Inicialmente, analisamos as ideias propostas pelos autores do framework e procuramos interpretá-las sob a perspectiva dos mercados financeiros. Sempre que o texto original dos pesquisadores assumia um caráter mais acadêmico, buscamos extrair seu significado prático. Em essência, essa etapa serviu para preparar a base. Delineamos as perspectivas e mostramos que o SpikingBrain tem potencial para ir além da teoria.
Em seguida, mostramos como as ideias da lógica orientada a eventos podem ser traduzidas em código e demos um passo importante: ensinamos o modelo a converter um fluxo contínuo de números em spikes discretos. O elemento central aqui foi a transformação do sinal pela aplicação de um limiar. O neurônio permanece inativo enquanto o valor não atinge um nível crítico e somente então gera um impulso curto. Essa abordagem permitiu separar imediatamente o ruído das mudanças realmente relevantes e observar as cotações sob uma nova perspectiva. No entanto, para que esse mecanismo não se tornasse uma limitação, adicionamos a possibilidade de treinamento: tornamos os limiares adaptativos e permitimos a propagação dos gradientes mesmo através dos neurônios inativos. Como resultado, a rede passou a ter a capacidade de se adaptar ao mercado ao longo do tempo, em vez de permanecer presa a uma configuração estática.
No entanto, fomos além e desenvolvemos essas ideias em uma arquitetura completa. Os principais componentes necessários para manter o sistema em funcionamento passaram a ocupar o centro da implementação. Integramos as transformações em spikes à estrutura convencional de camadas e mostramos como elas podem coexistir com blocos convolucionais e outros elementos clássicos de redes neurais. A implementação prática em MQL5 exigiu atenção especial à memória e aos recursos computacionais. Os neurônios não devem operar todos simultaneamente, pois isso eliminaria a própria essência da abordagem orientada a eventos. Por isso, implementamos um mecanismo no qual uma parcela significativa dos neurônios permanece inativa, enquanto os recursos computacionais se concentram justamente onde há atividade relevante. Em essência, estabelecemos a base para que o SpikingBrain possa se integrar naturalmente ao ecossistema de trading, preservando a arquitetura já conhecida e, ao mesmo tempo, enriquecendo-a com uma nova dimensão orientada a eventos.
Módulo de atenção esparsa
Continuamos nosso percurso da filosofia geral orientada a eventos para a implementação concreta da arquitetura proposta. Saímos do nível dos esquemas e descemos diretamente ao convés do navio: o código e a lógica de execução. Anteriormente, explicamos por que o SpikingBrain interpreta o mercado como uma sequência de episódios relevantes e mostramos os primeiros passos práticos para converter ativações contínuas em spikes. Agora surge uma questão natural: como essa lógica orientada a eventos deve se comportar onde tradicionalmente são utilizadas janelas locais de atenção? Que alterações são necessárias para que a atenção local funcione de acordo com os princípios dos spikes e consiga lidar com o forte ruído do mercado?
Os autores do framework propõem uma janela deslocada, mas o mercado é imprevisível. A distância entre disparos relevantes varia dinamicamente, enquanto o ruído costuma preencher as janelas com uma densidade maior do que seria desejável. Por isso, escolhemos outro caminho: preservamos a lógica de atenção esparsa baseada em graphons, mas a construímos de modo a respeitar a própria essência dos spikes, ou seja, a assincronicidade, os limiares adaptativos e o valor informacional do silêncio de um neurônio. Trata-se de uma nova versão do módulo CNeuronSparseGraphAttention, que não se limita a reproduzir a implementação anterior, mas representa sua evolução. CNeuronSpikeSparseAttention é nosso atento guardião da atenção, adaptado ao ritmo do mercado e à linguagem dos spikes.
class CNeuronSpikeSparseAttention : public CNeuronSpikeConv { protected: CNeuronConvOCL cValue; CNeuronGraphons cGraphs; CNeuronSparseSoftMax cScores; CNeuronBaseOCL cAttention; //--- virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override; virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override; virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL) override; public: CNeuronSpikeSparseAttention(void) {}; ~CNeuronSpikeSparseAttention(void) {}; //--- virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint units, uint window, uint experts, float dropout, uint emb_dimension, uint sparse_dimension, ENUM_OPTIMIZATION optimization_type, uint batch); //--- virtual int Type(void) override const { return defNeuronSpikeSparseAttention; } //--- methods for working with files virtual bool Save(int const file_handle) override; virtual bool Load(int const file_handle) override; //--- virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau) override; virtual void SetOpenCL(COpenCLMy *obj) override; virtual void TrainMode(bool flag) override; };
Antes de tudo, vale destacar que o novo objeto é derivado de CNeuronSpikeConv, nosso mecanismo de conversão de sinais contínuos em spikes. Isso, por si só, já revela muito sobre a finalidade da classe. Ela não reinventa a geração de spikes, mas continua processando-os de forma adequada. A herança garante que a lógica básica de convolução e de codificação inicial de eventos seja herdada, enquanto na classe derivada podemos nos concentrar exclusivamente na lógica de atenção orientada a spikes.
À primeira vista, o corpo da classe apresenta um conjunto familiar de objetos internos: cValue, cGraphs, cScores e cAttention. Os nomes já são conhecidos, mas é importante observar que há menos componentes do que na implementação original. Optamos deliberadamente por eliminar o caminho residual e o módulo FeedForward separado. O motivo é simples e o mesmo que já mencionamos ao implementar a atenção linear com gates: no paradigma orientado a eventos, caminhos adicionais diluem o impulso e geram cálculos desnecessários. Em vez disso, a conexão residual e o FFN compartilhado ficam no nível do bloco, onde são reunidos os resultados das diferentes ramificações de atenção e onde faz sentido combinar e reforçar o sinal uma única vez.
Vale destacar um aspecto importante da estrutura. Todos os objetos internos são declarados estaticamente como membros da classe. Isso permite manter o construtor e o destrutor vazios, transferindo toda a inicialização para o método Init.
bool CNeuronSpikeSparseAttention::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint units, uint window, uint experts, float dropout, uint emb_dimension, uint sparse_dimension, ENUM_OPTIMIZATION optimization_type, uint batch) { if(!CNeuronSpikeConv::Init(numOutputs, myIndex, open_cl, window, window, window, units, 1, optimization_type, batch)) return false; activation = None;
O método Init prepara o módulo para operar efetivamente no mercado. Sua assinatura contém tudo o que é necessário para controlar as dimensionalidades e o comportamento da atenção esparsa. Dentro do método, primeiro delegamos parte da inicialização à classe pai, preservando a compatibilidade com o codificador spiking.
Em seguida, inicializamos sequencialmente os módulos internos. cValue é o primeiro a assumir a função de obter a representação local: trata-se de uma convolução que prepara os valores V para a posterior ponderação.
int index = 0; if(!cValue.Init(0, index, OpenCL, window, window, window, units, 1, optimization, iBatch)) return false; cValue.SetActivationFunction(None);
Observe que desativamos imediatamente a função de ativação de cValue. A razão é prática: as representações spiking já incorporam não linearidade e esparsidade, e uma ativação adicional nesse ponto apenas distorceria o impulso. Precisamos dos vetores V brutos para que a atenção possa ponderar corretamente a contribuição de cada spike.
Depois, inicializamos a mistura de graphons cGraphs, que constitui o núcleo da nossa esparsidade. Ela aprende a estrutura dos dados levando em conta as distâncias temporais, os volumes e a densidade dos spikes.
index++; if(!cGraphs.Init(0, index, OpenCL, units, window, emb_dimension, experts, dropout, optimization, iBatch)) return false;
cScores corresponde ao nosso Sparse SoftMax. Ele recebe a estrutura dos dados proposta pelos graphons e concentra a atenção apenas nos vizinhos mais relevantes, criando assim a esparsidade da atenção local. Essa abordagem reduz a complexidade computacional a um nível próximo ao da atenção por janelas, mas preserva a flexibilidade: aqui, a própria janela é dinâmica e depende da atividade atual e das estatísticas dos spikes.
index++; if(!cScores.Init(0, index, OpenCL, units, units, sparse_dimension, optimization, iBatch)) return false;
cAttention acumula o resultado final α·V.
index++; if(!cAttention.Init(0, index, OpenCL, Neurons(), optimization, iBatch)) return false; cAttention.SetActivationFunction(None); //--- return true; }
O significado prático dessas decisões é claro: eliminamos antecipadamente tudo o que é desnecessário, pois, na lógica spiking, esses elementos tendem mais a atrapalhar do que a ajudar. Mantemos apenas os componentes que realmente influenciam a seleção dos impulsos. Fazemos a gestão da memória de modo que o kernel OpenCL opere sobre estruturas compactas e comprimidas. Isso reduz a latência e o consumo de energia, dois fatores críticos para o trading em tempo real.
Concluída a inicialização, passamos diretamente à execução. O método feedForward é o ponto em que a teoria encontra os dados. O algoritmo é simples em sua estrutura e claro em seu propósito. Não há nada supérfluo. Tudo converge para um único objetivo: o resultado deve refletir os impulsos spiking relevantes, e não o ruído.
bool CNeuronSpikeSparseAttention::feedForward(CNeuronBaseOCL *NeuronOCL) { if(!cValue.FeedForward(NeuronOCL)) return false;
Primeiro, é chamado o método de propagação para frente do objeto cValue. Essa etapa convolucional extrai os atributos locais e gera a matriz de valores V. Aqui preparamos aquilo que será posteriormente ponderado pela atenção.
Em seguida, são geradas as máscaras de graphons, a lista de vizinhos e seus pesos relativos. A máscara não representa uma janela estática, mas uma vizinhança dinâmica que depende do tempo, do volume e da densidade dos spikes. É nessa etapa que determinamos com quais elementos a posição analisada será comparada.
if(!cGraphs.FeedForward(NeuronOCL)) return false; if(!cScores.FeedForward(cGraphs.AsObject())) return false;
cScores é utilizado para obter uma matriz esparsa de pesos de atenção a partir dos graphons gerados. Na prática, cScores produz dois elementos fundamentais: compact-indexes (listas de vizinhos) e um array de pesos para cada par posição-vizinho.
A principal etapa computacional é SparseMatMul. Essa função multiplica a matriz esparsa de pesos (scores) pela matriz densa de valores V. O resultado é uma matriz densa de atenção com valores contínuos.
if(!SparseMatMul(cScores.GetIndexes(), cScores.getOutput(), cValue.getOutput(), cAttention.getOutput(), cScores.Heads(), cScores.DimensionOut(), cValue.GetUnits(), cValue.GetFilters())) return false; //--- return CNeuronSpikeConv::feedForward(cAttention.AsObject()); }
O algoritmo da propagação para frente é concluído com a chamada do método de mesmo nome da classe pai. Nesse ponto, retornamos ao espaço dos spikes. Passamos o vetor agregado de atenção para o sistema de codificação em spikes, onde serão aplicados os mecanismos de limiar, geração de spikes e preparação da saída do módulo para sua posterior combinação no nível superior do bloco de atenção.
De modo geral, feedForward atua como um ponto de sincronização entre a lógica esparsa baseada em graphons e a codificação em spikes. Ele converte o contexto local e dinâmico em representações densas de atenção e, em seguida, as devolve ao domínio dos spikes.
Quanto aos algoritmos de propagação reversa, proponho que você os analise por conta própria. Todos os detalhes, incluindo o código completo da classe e a implementação de cada método, estão disponíveis no anexo.
Variante do Mixture of Experts
Depois de implementar os módulos de atenção, passamos à construção do módulo Mixture of Experts. Já implementamos estruturas semelhantes em estudos anteriores, mas nenhuma delas esteve livre de compromissos. Encontrar um equilíbrio entre eficiência computacional e capacidade expressiva do modelo sempre foi uma tarefa complexa. A filosofia da arquitetura spiking acrescenta suas próprias particularidades: o silêncio dos neurônios, a esparsidade dos sinais e a atividade dinâmica dos especialistas tornam o problema ainda mais delicado. Por isso, neste estudo criamos um novo objeto que leva essas características em consideração.
Mais uma vez, a economia de recursos computacionais e a execução paralela eficiente dos especialistas tornam-se questões centrais. A complexidade aumenta porque cada elemento da sequência pode utilizar seu próprio conjunto de especialistas. A abordagem convencional, na qual cada especialista recebe sua própria entrada, rapidamente leva à duplicação dos cálculos.
Para entender como podemos evitar isso, vamos observar a visualização do bloco MoE proposta pelos autores.

Os resultados dos especialistas são simplesmente somados, o que abre uma importante oportunidade de otimização. Todos os especialistas ativos recebem o mesmo conjunto de dados de entrada. Do ponto de vista matemático, isso permite colocar a entrada em evidência e, em vez de executar várias projeções independentes, realizar uma única projeção linear utilizando a soma dos parâmetros dos especialistas. Esse recurso preserva a correção dos cálculos, mas reduz significativamente o uso de memória e a carga sobre o processador, algo especialmente importante ao processar longas séries temporais de instrumentos financeiros e alta frequência de atualização dos dados.
Como resultado, obtemos um módulo MoE econômico em termos computacionais e, ao mesmo tempo, expressivo, que se integra à filosofia da arquitetura spiking e está preparado para operar com fluxos paralelos de atenção e sinais de mercado.
Implementamos a abordagem proposta na forma de uma nova classe CNeuronMoEConv. Trata-se de um módulo completo, integrado de maneira consistente à arquitetura spiking e capaz de distribuir eficientemente a carga entre os especialistas. A classe é derivada da classe base CNeuronBaseOCL, o que permite operar no mesmo contexto OpenCL das demais camadas e interagir facilmente com outros módulos.
class CNeuronMoEConv : public CNeuronBaseOCL { protected: CLayer acProbability; CParams cExperts; CNeuronBaseOCL cWeightsConv; //--- virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override; virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override; virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL) override; public: CNeuronMoEConv(void) {}; ~CNeuronMoEConv(void) {}; virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint units, uint window, uint window_out, uint experts, float dropout, uint topK, ENUM_OPTIMIZATION optimization_type, uint batch); //--- virtual int Type(void) override const { return defNeuronMoEConv; } //--- methods for working with files virtual bool Save(int const file_handle) override; virtual bool Load(int const file_handle) override; //--- virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau) override; virtual void SetOpenCL(COpenCLMy *obj) override; virtual void TrainMode(bool flag) override; };
Dentro da classe, são definidos vários componentes fundamentais. acProbability é responsável pela distribuição probabilística da atividade dos especialistas, determinando quais deles participarão do processamento de cada elemento da sequência. cExperts armazena os parâmetros de todos os especialistas, que, em conjunto, formam um amplo conjunto funcional do modelo. cWeightsConv é utilizado para gerar o conjunto agregado de parâmetros dos especialistas ativos. É aqui que implementamos a ideia, mencionada anteriormente, de colocar a entrada em evidência. Essa abordagem reduz significativamente o número de cálculos e o consumo de memória sem comprometer a capacidade expressiva do modelo.
A inicialização do novo objeto ocorre no método Init, que inicializa e configura todos os componentes internos e garante o funcionamento correto da camada.
bool CNeuronMoEConv::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint units, uint window, uint window_out, uint experts, float dropout, uint topK, ENUM_OPTIMIZATION optimization_type, uint batch) { if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, units * window_out, optimization_type, batch)) return false;
Primeiro, é executada a inicialização básica da classe pai.
Em seguida, os principais elementos do módulo são criados e configurados sequencialmente. Primeiro, é montada a cadeia responsável pelo cálculo das probabilidades de ativação dos especialistas, acProbability.
//--- int index = 0; //--- CNeuronConvOCL *conv = NULL; CNeuronDropoutOCL *dout = NULL; CNeuronSparseSoftMax *softmax = NULL; //--- Probability acProbability.Clear(); acProbability.SetOpenCL(OpenCL); index++; conv = new CNeuronConvOCL(); if(!conv || !conv.Init(experts, index, OpenCL, window, window, 2 * experts, units, 1, optimization, iBatch) || !acProbability.Add(conv)) { DeleteObj(conv); return false; } conv.SetActivationFunction(SoftPlus); index++; conv = new CNeuronConvOCL(); if(!conv || !conv.Init(experts, index, OpenCL, 2 * experts, 2 * experts, experts, units, 1, optimization, iBatch) || !acProbability.Add(conv)) { DeleteObj(conv); return false; } conv.SetActivationFunction(SoftPlus); index++; dout = new CNeuronDropoutOCL(); if(!dout || !dout.Init(0, index, OpenCL, conv.Neurons(), dropout, optimization, iBatch) || !acProbability.Add(dout)) { DeleteObj(dout); return false; } index++; softmax = new CNeuronSparseSoftMax; if(!softmax || !softmax.Init(0, index, OpenCL, units, experts, topK, optimization, iBatch) || !acProbability.Add(softmax)) { DeleteObj(softmax); return false; } softmax.SetHeads(units);
Aqui, criamos uma sequência de duas camadas convolucionais com uma ativação SoftPlus entre elas. Essa estrutura proporciona uma distribuição suave e estável dos valores, algo especialmente importante ao processar sinais financeiros dinâmicos, nos quais picos abruptos e ruído podem facilmente prejudicar o funcionamento do modelo. As camadas convolucionais geram distribuições de relevância dos especialistas para cada elemento da sequência, avaliando quais deles são mais adequados em determinado momento. A cadeia é concluída por um objeto com função SoftMax esparsa, que seleciona um número predefinido de especialistas entre os mais relevantes e atribui a cada um deles um peso de importância. Isso permite ao modelo concentrar-se nos sinais de mercado realmente importantes, ignorando ruído e padrões pouco relevantes.
A adição de Dropout antes do SoftMax controla a desativação aleatória de elementos, prevenindo o sobreajuste e aumentando a estabilidade do modelo diante do ruído de mercado.
Em paralelo, é inicializado o objeto cExperts, que armazena os parâmetros de todos os especialistas, reunindo-os em um único espaço.
index++; if(!cExperts.Init(0, index, OpenCL, window * window_out * experts, optimization, iBatch)) return false; index++; if(!cWeightsConv.Init(0, index, OpenCL, window * window_out * units, optimization, iBatch)) return false; //--- return true; }
Já cWeightsConv desempenha a função de conjunto agregado de parâmetros dos especialistas ativos.
Cada etapa de inicialização dos componentes internos é acompanhada pela verificação do sucesso das operações. Em caso de falha, o objeto é removido e o método retorna false. Isso garante a confiabilidade e a previsibilidade da camada mesmo com combinações complexas de parâmetros.
O método feedForward é o principal ciclo de execução, no qual a teoria da mistura de especialistas se transforma em cálculos concretos.
bool CNeuronMoEConv::feedForward(CNeuronBaseOCL *NeuronOCL) { CNeuronBaseOCL* prev = NeuronOCL; CNeuronBaseOCL* current = NULL; CNeuronConvOCL *conv = NULL; CNeuronSparseSoftMax *softmax = NULL; //--- Probability for(int i = 0; i < acProbability.Total(); i++) { current = acProbability[i]; if(!current || !current.FeedForward(prev)) return false; prev = current; } conv = acProbability[0]; softmax = prev;
Primeiro, percorremos todas as camadas da cadeia de probabilidades acProbability. Cada camada convolucional e a camada de SoftMax esparsa processam sequencialmente o sinal de entrada, gerando a distribuição de relevância dos especialistas para cada elemento da sequência. Em cada etapa, verificamos se a execução foi concluída corretamente. Se alguma camada não conseguir processar a entrada, o método retorna false de forma controlada, garantindo a estabilidade do funcionamento.
Em seguida, passamos à etapa de operação dos especialistas. No modo de treinamento (bTrain==true), é chamado o método de propagação para frente do objeto cExperts, gerando os parâmetros de todos os especialistas. Durante a operação, os parâmetros dos especialistas permanecem estáticos e essa etapa é ignorada, reduzindo a complexidade computacional do modelo.
//--- Experts if(bTrain) if(!cExperts.FeedForward()) return false;
A próxima etapa fundamental é a geração da mistura de parâmetros por meio de SparseMatMul. Essa operação matricial esparsa combina os especialistas ativos selecionados (top-K) com seus respectivos parâmetros, gerando a matriz final de pesos cWeightsConv. Essa abordagem permite economizar recursos computacionais e, ao mesmo tempo, considerar a atividade dinâmica dos especialistas e a esparsidade dos dados, algo especialmente importante na análise de séries temporais financeiras com sinais ruidosos e pouco frequentes.
uint units = conv.GetUnits(); uint window_in = conv.GetWindow(); uint window_out = Neurons() / units; uint topK = softmax.DimensionOut(); uint experts = cExperts.Neurons() / (window_in * window_out); //--- Generate Weights if(!SparseMatMul(softmax.GetIndexes(), softmax.getOutput(), cExperts.getOutput(), cWeightsConv.getOutput(), units, topK, window_in * window_out, experts)) return false;
Por fim, a matriz de pesos resultante é aplicada aos dados de entrada pelo método MatMul, gerando a saída da camada.
//--- Result if(!MatMul(NeuronOCL.getOutput(), cWeightsConv.getOutput(), Output, 1, window_in, window_out, units, true)) return false; if(activation != None) if(!Activation(Output, Output, activation)) return false; //--- return true; }
Se houver uma função de ativação definida, ela é aplicada à saída, adicionando não linearidade e estabilizando a distribuição dos sinais.
Dessa forma, o método feedForward integra três níveis de lógica: geração das probabilidades dos especialistas, seleção dos participantes ativos e agregação de sua influência sobre o sinal de saída. Tudo isso proporciona um processamento flexível, econômico e adaptativo das séries temporais, algo especialmente importante para a análise dos mercados financeiros, caracterizados por elevado dinamismo e alto nível de ruído.
Como resultado, obtemos um módulo MoE que não apenas economiza recursos, mas também preserva a flexibilidade na distribuição da atenção entre os especialistas, permitindo que cada elemento da série temporal ative seu próprio conjunto de especialistas.
Quanto aos algoritmos dos métodos de propagação reversa, proponho que você os analise por conta própria para compreender integralmente o funcionamento da camada e sua interação com os demais componentes do modelo. O código completo da classe e a implementação de cada método estão disponíveis no anexo, permitindo estudá-los detalhadamente e passo a passo.
Objeto de nível superior
Depois de analisarmos em detalhes o funcionamento dos componentes individuais do framework, chegou o momento de avançar para o próximo nível e reunir tudo em um único objeto de nível superior, CNeuronSpikingBrain. Essa classe implementa a sincronização e a interação entre vários módulos fundamentais: a execução paralela de dois algoritmos de atenção, o processamento posterior dos resultados pela mistura de especialistas e a integração das conexões residuais. Essa abordagem permite combinar contextos locais e globais, levando em conta a atividade dinâmica dos spikes e a esparsidade dos sinais, algo especialmente importante na análise de séries temporais financeiras de alta volatilidade.
O objeto de nível superior que implementamos não se limita estritamente ao framework proposto pelos autores, mas adota uma solução contextual mais ampla. Utilizamos a atenção esparsa não apenas como mecanismo de análise local, mas também como ferramenta para identificar os passos temporais mais relevantes no contexto de toda a sequência analisada. Isso permite concentrar o processamento nos momentos em que realmente ocorrem mudanças capazes de influenciar o comportamento do mercado.
Ao mesmo tempo, aplicamos os módulos de atenção linear, originalmente voltados à agregação global de atributos, à análise independente da dinâmica de sequências individuais. Essa abordagem permite estabelecer um equilíbrio entre a profundidade da amostragem local e a amplitude da cobertura global. Os mecanismos locais identificam impulsos relevantes, enquanto os mecanismos lineares constroem uma visão integrada da dinâmica. Em conjunto, eles formam uma representação mais estável dos dados e aumentam a capacidade do modelo de lidar com o ruído característico das séries temporais financeiras.
class CNeuronSpikingBrain : public CNeuronBaseOCL { protected: CNeuronSpikeSparseAttention cTimeAttention; CLayer caSpatialAttention; CNeuronBaseOCL cResidual; CLayer caFFN; //--- virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override; virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override; virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL) override; public: CNeuronSpikingBrain(void) {}; ~CNeuronSpikingBrain(void) {}; //--- virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint units, uint window, uint experts, float dropout, uint emb_dimension, uint sparse_dimension, ENUM_OPTIMIZATION optimization_type, uint batch); //--- virtual int Type(void) override const { return defNeuronSpikingBrain; } //--- methods for working with files virtual bool Save(int const file_handle) override; virtual bool Load(int const file_handle) override; //--- virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau) override; virtual void SetOpenCL(COpenCLMy *obj) override; virtual void TrainMode(bool flag) override; virtual bool Clear(void) override; virtual void SetActivationFunction(ENUM_ACTIVATION value) override { }; };
Dentro da classe, são definidos vários objetos centrais:
- cTimeAttention implementa a atenção esparsa local no domínio temporal, concentrando o sinal apenas nos momentos relevantes da sequência;
- caSpatialAttention realiza a análise independente das sequências unitárias, gerando uma representação paralela do contexto;
- cResidual soma as saídas dos dois módulos de atenção, garantindo estabilidade e evitando a degradação dos sinais durante a integração dos resultados;
- caFFN realiza o pós-processamento por meio da mistura de especialistas, reforçando a representação dos atributos mais relevantes e preparando a entrada para o módulo seguinte.
A inicialização do objeto ocorre no método Init, que constitui, na prática, o seu núcleo de configuração. É aqui que reunimos sequencialmente todos os componentes principais e definimos a arquitetura de nível superior.
bool CNeuronSpikingBrain::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint units, uint window, uint experts, float dropout, uint emb_dimension, uint sparse_dimension, ENUM_OPTIMIZATION optimization_type, uint batch) { if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, window * units, optimization_type, batch)) return false; activation = None;
Primeiro, chamamos a inicialização da classe pai, na qual são definidas as dimensões do espaço de resultados e o tipo de otimização. Nessa etapa, é utilizada uma ativação neutra, pois a transformação final resultará de uma combinação mais complexa de módulos.
Em seguida, configuramos o módulo de atenção temporal cTimeAttention, construído com base na arquitetura spiking esparsa. Sua função é identificar os passos temporais mais relevantes da sequência, o que corresponde diretamente às particularidades da análise de sinais de mercado, em que nem todo tick é importante, mas sim os momentos fundamentais da dinâmica.
int index = 0; if(!cTimeAttention.Init(0, index, OpenCL, units, window, experts, dropout, emb_dimension, sparse_dimension, optimization, iBatch)) return false;
O bloco seguinte é a atenção espacial caSpatialAttention, que utiliza um par de objetos de transposição de dados e o módulo de atenção linear CNeuronGateLineAttention.
CNeuronTransposeOCL* transp = NULL; CNeuronGateLineAttention* line_att = NULL; caSpatialAttention.Clear(); caSpatialAttention.SetOpenCL(OpenCL); index++; transp = new CNeuronTransposeOCL(); if(!transp || !transp.Init(0, index, OpenCL, units, window, optimization, iBatch) || !caSpatialAttention.Add(transp)) { DeleteObj(transp) return false; } index++; line_att = new CNeuronGateLineAttention(); if(!line_att || !line_att.Init(0, index, OpenCL, window, units, emb_dimension, experts, optimization, iBatch) || !caSpatialAttention.Add(line_att)) { DeleteObj(line_att) return false; } index++; transp = new CNeuronTransposeOCL(); if(!transp || !transp.Init(0, index, OpenCL, window, units, optimization, iBatch) || !caSpatialAttention.Add(transp)) { DeleteObj(transp) return false; }
Essa combinação permite analisar as dependências entre os atributos em diferentes projeções, preservando o equilíbrio entre a velocidade dos cálculos e a abrangência do contexto global. As camadas são adicionadas sequencialmente ao contêiner, o que proporciona flexibilidade e permite expandir a arquitetura.
Em seguida, incorporamos à estrutura o objeto cResidual, que desempenha o papel de estabilizador. Ele acumula os resultados dos blocos paralelos de atenção e garante a propagação correta dos sinais para as etapas seguintes, sem perda de informações nem degradação dos gradientes.
index++; if(!cResidual.Init(0, index, OpenCL, window * units, optimization, iBatch)) return false; cResidual.SetActivationFunction(None);
Dedicamos atenção especial à construção do bloco caFFN, no qual combinamos uma camada Mixture of Experts (CNeuronMoEConv) com a transformação spiking por meio de CNeuronSpikeConv. Primeiro, criamos o módulo MoE, que distribui dinamicamente a carga entre vários especialistas, preservando a eficiência computacional graças ao SoftMax esparso.
CNeuronSpikeConv* conv = NULL; CNeuronMoEConv* moe = NULL; caFFN.Clear(); caFFN.SetOpenCL(OpenCL); index++; moe = new CNeuronMoEConv(); if(!moe || !moe.Init(0, index, OpenCL, units, window, 2 * window, experts, dropout, sparse_dimension, optimization, iBatch) || !caFFN.Add(moe)) { DeleteObj(moe) return false; } moe.SetActivationFunction(SoftPlus);
Em seguida, adicionamos uma camada convolucional de transformação, responsável pelo processamento final da sequência. É importante observar que, entre as camadas, utilizamos SoftPlus como função de ativação, pois ela suaviza a dinâmica e se adapta bem à análise de sinais financeiros instáveis.
index++; conv = new CNeuronSpikeConv(); if(!conv || !conv.Init(0, index, OpenCL, 2 * window, 2 * window, window, units, 1, optimization, iBatch) || !caFFN.Add(conv)) { DeleteObj(conv) return false; } if(!Clear()) return false; //--- return true; }
A inicialização é concluída com a chamada do método Clear, garantindo que o estado de todos os objetos internos seja corretamente preparado antes do início da execução.
Como resultado, o método Init reúne todos os componentes em uma única estrutura. Aqui fica clara a ideia de executar em paralelo os mecanismos de atenção local e global, integrando e filtrando posteriormente seus resultados por meio do bloco MoE.
O método feedForward, implementado na classe CNeuronSpikingBrain, desempenha um papel fundamental na estruturação de todo o laço computacional do framework. Imagine um analista cuja tarefa seja reunir informações sobre o mercado e transformá-las em uma previsão coerente. Primeiro, ele recorre à atenção temporal, como se observasse a dinâmica dos preços ao longo das últimas horas. Ele identifica os principais passos temporais: movimentos bruscos, períodos de consolidação e relatórios importantes. Tudo isso é registrado como um conjunto de pontos de referência que servirão de base para a análise subsequente.
bool CNeuronSpikingBrain::feedForward(CNeuronBaseOCL *NeuronOCL) { CNeuronBaseOCL* prev = NeuronOCL; CNeuronBaseOCL* current = NULL; //--- if(!cTimeAttention.FeedForward(prev)) return false;
Em seguida, o analista passa à atenção espacial. É como distribuir os eventos entre diferentes setores ou ativos. Essas relações nem sempre são evidentes à primeira vista, mas são justamente elas que compõem o contexto global que o analista precisa levar em conta.
for(int i = 0; i < caSpatialAttention.Total(); i++) { current = caSpatialAttention[i]; if(!current || !current.FeedForward(prev)) return false; prev = current; }
Para não se perder em meio à grande quantidade de sinais, o analista utiliza o mecanismo de conexão residual. É a capacidade de retornar aos fatos básicos e compará-los com as novas conclusões. Como um especialista experiente, ele confronta constantemente as observações recentes com aquilo que já conhece, preservando um equilíbrio adequado entre o conhecimento anterior e as novas informações.
if(!SumAndNormilize(prev.getOutput(), cTimeAttention.getOutput(), cResidual.getOutput(), cTimeAttention.GetFilters(), false, 0, 0, 0, 1) || !SumAndNormilize(cResidual.getOutput(), NeuronOCL.getOutput(), cResidual.getOutput(), cTimeAttention.GetFilters(), true, 0, 0, 0, 1)) return false;
A etapa final é a atuação dos especialistas. Aqui entra em ação o bloco Mixture of Experts, que pode ser comparado a uma equipe de analistas com diferentes especializações: um se concentra em análise técnica, outro em macroeconomia e um terceiro nos fluxos de capital. Dependendo das condições do mercado, o sistema determina qual opinião tem maior peso naquele momento e agrega as decisões dos especialistas. A convolução spiking atua como um mecanismo de identificação de padrões locais, semelhante a um analista técnico que examina os gráficos nos mínimos detalhes.
prev = cResidual.AsObject(); for(int i = 0; i < caFFN.Total(); i++) { current = caFFN[i]; if(!current || !current.FeedForward(prev)) return false; prev = current; } if(!SumAndNormilize(cResidual.getOutput(), prev.getOutput(), Output, cTimeAttention.GetFilters(), true, 0, 0, 0, 1)) return false; //--- return true; }
O método feedForward não é apenas um algoritmo de propagação para frente, mas uma lógica estruturada em etapas para coordenar uma verdadeira equipe de análise. Ele começa registrando os principais eventos, depois aprofunda a análise das relações entre os ativos, compara os novos dados com os resultados anteriores e conclui o processamento sintetizando as opiniões dos especialistas. Na saída, obtemos uma previsão coerente que reflete tanto o contexto global quanto os sinais locais do mercado.
Como resultado, CNeuronSpikingBrain torna-se um poderoso módulo integrador, capaz de considerar simultaneamente os contextos temporal e espacial, adaptar-se aos sinais dinâmicos do mercado e distribuir de forma eficiente a atividade entre os especialistas. Isso o transforma em um componente central da nossa arquitetura spiking para análise de dados financeiros, proporcionando flexibilidade, eficiência computacional e estabilidade diante do ruído. O código completo desta classe e de todos os seus métodos pode ser consultado no anexo.
Arquitetura dos modelos
Agora que os módulos individuais estão prontos, é hora de reuni-los em modelos completos: o Codificador do estado do ambiente, o Ator e o Crítico.
Começamos pelo Codificador, componente responsável por ler o histórico do instrumento e convertê-lo em uma representação compacta e multinível. Primeiro, temos uma camada básica contendo um total de HistoryBars * BarDescr valores. Cada barra corresponde a um conjunto de atributos do candle. São dados brutos, ainda sem qualquer destaque específico.
bool CreateDescriptions(CArrayObj *&encoder, CArrayObj *&actor, CArrayObj *&critic ) { //--- CLayerDescription *descr; //--- if(!encoder) { encoder = new CArrayObj(); if(!encoder) return false; } if(!actor) { actor = new CArrayObj(); if(!actor) return false; } if(!critic) { critic = new CArrayObj(); if(!critic) return false; } //--- Encoder encoder.Clear(); //--- Input layer if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronBaseOCL; uint prev_count = descr.count = (HistoryBars * BarDescr); descr.activation = None; descr.optimization = ADAM; if(!encoder.Add(descr)) { delete descr; return false; }
Em seguida, aplicamos a normalização com regularização por ruído, BatchNormWithNoise. Essa camada evita que os dados fiquem estagnados. Ela equaliza as escalas e adiciona um leve ruído estocástico durante o treinamento, algo útil diante da volatilidade variável dos mercados.
//--- layer 1 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronBatchNormWithNoise; descr.count = prev_count; descr.batch = BatchSize; descr.activation = None; descr.optimization = ADAM; if(!encoder.Add(descr)) { delete descr; return false; }
Depois vem a etapa de agregação ConcatDiff. Pegamos os dados e acrescentamos a eles uma sequência de diferenças. Trata-se de uma técnica clássica que enfatiza o movimento, em vez dos níveis absolutos.
//--- layer 2 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronConcatDiff; prev_count = descr.count = HistoryBars; descr.layers = BarDescr; descr.step = 1; descr.batch = BatchSize; descr.optimization = ADAM; descr.activation = None; if(!encoder.Add(descr)) { delete descr; return false; } uint prev_out = descr.layers * 2 ;
Na sequência, utilizamos Mamba4CastEmbedding, uma camada específica que constrói embeddings multiperíodo. Aqui, consideramos explicitamente diferentes timeframes para fornecer ao modelo um amplo contexto histórico sem perder a sensibilidade às variações locais.
//--- layer 3 if(!(descr = new CLayerDescription())) return false; descr.type = defMamba4CastEmbeding; prev_count = descr.count = HistoryBars; descr.window = prev_out; prev_out = descr.window_out = NSkills; { uint temp[] = {PeriodSeconds(PERIOD_D1), PeriodSeconds(PERIOD_MN1)}; if(ArrayCopy(descr.windows, temp) < (int)temp.Size()) return false; } descr.batch = BatchSize; descr.optimization = ADAM; descr.activation = None; if(!encoder.Add(descr)) { delete descr; return false; }
A etapa principal é nosso bloco spiking NeuronSpikingBrain. Nós o inserimos AttentionLayers vezes, montando uma pilha na qual a atenção temporal local e esparsa opera em conjunto com a atenção espacial linear com gates, e seus resultados são posteriormente agregados por meio de uma conexão residual compartilhada e de um MoE-FFN.
//--- layer 4 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronSpikingBrain; descr.count = prev_count; descr.window = prev_out; descr.variables = NExperts; // Experts descr.window_out = EmbeddingSize; // Inside Dimension descr.step = TopK; // Top-K descr.probability = 0.3f; descr.optimization = ADAM; descr.batch = BatchSize; descr.activation = None; for(int i = 0; i < AttentionLayers; i++) if(!encoder.Add(descr)) { delete descr; return false; } uint window = descr.window; uint count = prev_count;
Após a camada de atenção, comprimimos a representação para o espaço original de atributos e para o horizonte de planejamento especificado.
//--- layer 5 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronConvOCL; descr.count = prev_count; descr.window = prev_out; descr.step = prev_out; prev_out = descr.window_out = BarDescr; descr.activation = TANH; descr.optimization = ADAM; if(!encoder.Add(descr)) { delete descr; return false; } //--- layer 6 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronTransposeOCL; descr.count = prev_count; prev_count = descr.window = prev_out; descr.batch = BatchSize; descr.optimization = ADAM; descr.activation = None; if(!encoder.Add(descr)) { delete descr; return false; } prev_out = descr.count; //--- layer 7 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronConvOCL; descr.count = prev_count; descr.window = prev_out; descr.step = prev_out; prev_out = descr.window_out = NForecast; descr.activation = TANH; descr.optimization = ADAM; if(!encoder.Add(descr)) { delete descr; return false; } //--- layer 8 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronTransposeOCL; descr.count = prev_count; prev_count = descr.window = prev_out; descr.batch = BatchSize; descr.optimization = ADAM; descr.activation = None; if(!encoder.Add(descr)) { delete descr; return false; } prev_out = descr.count;
O Codificador é concluído com RevInDenorm, que reconverte as previsões para as escalas originais e devolve os valores a uma forma conveniente para uso em trading.
//--- layer 9 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronRevInDenormOCL; descr.count = prev_count * prev_out; descr.layers = 1; if(!encoder.Add(descr)) { delete descr; return false; }
Os resultados gerados pelo Codificador do estado do ambiente servem como dados de entrada para os modelos do Ator e do Crítico, responsáveis, respectivamente, pela geração das decisões de trading e por sua posterior avaliação. A arquitetura desses modelos baseia-se, de modo geral, nos desenvolvimentos realizados em estudos anteriores, mas recebeu modificações importantes, incluindo elementos das soluções spiking, que aumentam a capacidade de adaptação e a sensibilidade do sistema à dinâmica do mercado. Essas alterações criam um mecanismo de tomada de decisão mais flexível, no qual a estrutura clássica é enriquecida com camadas adicionais de processamento neural. Para quem deseja se aprofundar nos detalhes técnicos, recomendamos consultar o código completo da arquitetura dos modelos disponível no anexo.
Testes
Antes de confiar recursos reais ao modelo, submetemos a estratégia a testes com dados históricos, como se estivéssemos treinando sua capacidade de avaliar riscos e tomar decisões nas mais diversas condições de mercado. Cada etapa simulou o comportamento de um mercado real, permitindo que o modelo acumulasse experiência gradualmente e desenvolvesse algoritmos de comportamento mais estáveis.
A primeira etapa, o treinamento offline, foi realizada com dados históricos do par de moedas EURUSD no timeframe H1, no período de janeiro de 2024 a junho de 2025. Esse intervalo serviu como um verdadeiro campo de treinamento. O modelo aprendeu a reproduzir padrões históricos, compreender a dinâmica do mercado, identificar regularidades nos movimentos dos preços e no volume das operações e se adaptar à variabilidade do mercado. Pode-se dizer que ele desenvolveu uma espécie de intuição de trader combinada com uma avaliação estratégica precisa.
A etapa seguinte, o ajuste online no Testador de Estratégias do MetaTrader 5, permitiu que o modelo processasse fluxos de dados em tempo real, candle a candle. Nessa fase, ele assimilou a dinâmica do mercado real, aprendeu a manter a estabilidade em meio ao ruído, ajustar suas ações em condições de baixa liquidez e reagir imediatamente a picos bruscos de preço. Essa etapa serviu para refinar a estratégia: a estrutura básica formada com os dados históricos permaneceu inalterada, enquanto o modelo aprendeu a se adaptar de maneira flexível às condições atuais do mercado, minimizando o risco de sobreajuste e aumentando a precisão das previsões em um ambiente imprevisível.
A avaliação final utilizou dados de julho e agosto de 2025, completamente novos e nunca utilizados anteriormente. Todos os parâmetros obtidos nas etapas anteriores foram carregados sem qualquer alteração, garantindo uma avaliação imparcial da capacidade de generalização do modelo e de sua estabilidade diante de novas situações de mercado. Os resultados dos testes são apresentados a seguir e demonstram a eficiência da abordagem passo a passo de treinamento e adaptação do modelo às condições reais do mercado financeiro.

Os resultados dos testes demonstram a eficiência do modelo com dados nunca utilizados anteriormente. O gráfico de saldo e equity mostra um crescimento gradual e controlado do capital. O saldo apresenta uma trajetória relativamente estável, enquanto a equity reflete as oscilações de curto prazo características de um ambiente real de mercado. Também são observados alguns picos e correções, indicando a capacidade do modelo de se adaptar a eventos inesperados do mercado sem perder a tendência positiva geral.
Os indicadores estatísticos reforçam essa impressão visual. O lucro total foi de 15,53 USD, com um depósito inicial de 100 USD, o que corresponde a uma rentabilidade moderada com risco controlado. O drawdown máximo da equity atingiu 22,76%, um valor relativamente significativo, mas ainda dentro de um nível de risco aceitável para uma estratégia em fase de testes. O Profit Factor foi de 1,88, confirmando a predominância dos ganhos sobre as perdas.
O modelo realizou apenas 11 operações de trading (22 transações), das quais 54,55% foram lucrativas. O lucro médio por operação foi de 5,53 USD, enquanto a perda média ficou em 3,54 USD, demonstrando uma relação lucro/risco equilibrada. A maior sequência lucrativa foi de 2 transações, totalizando 12,70 USD, enquanto a maior sequência de transações com perda também foi de 2, totalizando -10,06 USD. Esses indicadores confirmam que o modelo consegue manter um equilíbrio entre agressividade e estabilidade sem expor o capital a riscos excessivos.
De modo geral, os resultados dos testes mostram que o modelo integra com sucesso as abordagens do SpikingBrain, é capaz de processar sinais financeiros dinâmicos e tomar decisões de forma controlada em condições reais de mercado, mantendo estabilidade e rentabilidade sob controle.
Conclusão
A evolução das arquiteturas de redes neurais até os modelos spiking abre novos horizontes para o trading. Se os Transformers já demonstraram sua eficiência na análise de grandes volumes de dados de mercado e na geração de sinais estáveis, os neurônios spiking nos aproximam de sistemas mais biologicamente plausíveis e energeticamente eficientes. Sua capacidade de lidar com padrões temporais e fluxos de informação ruidosos torna essas arquiteturas promissoras para trading de alta frequência e estratégias adaptativas.
No entanto, o principal desafio permanece o mesmo: a integração desses modelos em sistemas reais de trading exige testes rigorosos, consideração dos riscos e compreensão das limitações de cada arquitetura.
Referências
Programas usados no artigo
| # | Nome | Tipo | Descrição |
|---|---|---|---|
| 1 | Study.mq5 | Expert Advisor | EA de treinamento offline de modelos |
| 2 | StudyOnline.mq5 | Expert Advisor | EA de treinamento online de modelos |
| 3 | Test.mq5 | Expert Advisor | EA para teste do modelo |
| 4 | Trajectory.mqh | Biblioteca de classes | Estrutura de descrição do estado do sistema e da arquitetura dos modelos |
| 5 | NeuroNet.mqh | Biblioteca de classes | Biblioteca de classes para criação de rede neural |
| 6 | NeuroNet.cl | Biblioteca | Biblioteca de código do programa OpenCL |
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/19802
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.
Caminhe em novos trilhos: Personalize indicadores no MQL5
Criando sistemas de trading com IA em MQL5 (Parte 3): Evoluindo para uma interface rolável voltada para um único chat
Está chegando o novo MetaTrader 5 e MQL5
Negociando opções sem opções (Parte 3): Estratégias complexas com opções
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso