
Exemplo de novo Indicador e LSTM Condicional
Introdução
No dinâmico mundo dos mercados financeiros, traders e analistas estão sempre buscando maneiras novas e criativas de obter vantagem sobre seus concorrentes. Este artigo examina um método inovador de trading automatizado que une as habilidades preditivas do deep learning com a força da análise técnica convencional. Buscamos desenvolver uma técnica de trading estável e flexível, capaz de lidar com as complexidades dos mercados contemporâneos, fundindo um modelo neural complexo do tipo Conditional Long Short-Term Memory (LSTM) com um indicador técnico proprietário, o Volatility Adjusted Momentum (VAM).
Indicadores técnicos são utilizados há muito tempo pela indústria financeira para identificar tendências e possíveis oportunidades de negociação. Apesar de sua importância, esses indicadores frequentemente não conseguem captar totalmente as complexidades das dinâmicas de mercado, especialmente durante períodos de volatilidade extrema ou mudanças abruptas. No entanto, arquiteturas de deep learning, como as LSTMs, em particular, demonstraram um potencial impressionante em modelos de machine learning para reconhecimento de padrões e previsão em dados complexos e dependentes do tempo. Esses modelos, entretanto, nem sempre oferecem a interpretabilidade e o conhecimento específico de domínio que a análise técnica convencional proporciona.
Nossa estratégia busca preencher essa lacuna ao unir as vantagens de ambas as abordagens. Este artigo apresenta uma ferramenta inovadora chamada indicador Volatility Adjusted Momentum (VAM), que busca medir o momentum do mercado levando em consideração a volatilidade subjacente. Em comparação aos indicadores de momentum convencionais, isso oferece uma visão mais detalhada das dinâmicas de mercado. O VAM busca fornecer sinais mais confiáveis em diferentes cenários de mercado, desde períodos de calmaria até momentos de turbulência, ao incorporar a volatilidade na análise.
Para aprimorar o indicador VAM, utilizamos um modelo LSTM Condicional, um tipo de rede neural recorrente adaptada para processar dados sequenciais com informações contextuais extras. Como é treinado usando dados históricos de preços e indicadores técnicos, este modelo pode identificar relações de mercado complexas e não lineares que métodos convencionais poderiam deixar passar. Por conta do recurso ‘condicional’ do LSTM, o modelo consegue considerar mais variáveis do mercado, o que pode resultar em previsões mais precisas e contextuais.
O Expert Advisor (EA), um sistema automatizado de trading especialmente desenvolvido que combina o indicador VAM com as previsões do modelo LSTM Condicional, é o cérebro por trás de nossa estratégia. Usando sinais de ambos os componentes, esse expert advisor (EA) é integrado à famosa plataforma MetaTrader 5 para ajudar traders a tomarem decisões bem-informadas. Além disso, ele possui capacidades dinâmicas de gerenciamento de risco que ajustam níveis de take-profit e stop-loss conforme as variações do mercado.
Neste artigo, vamos examinar as bases teóricas dos modelos LSTM Condicional e do indicador VAM, oferecendo insights sobre suas vantagens e como funcionam em conjunto. Abordaremos cada etapa de criação e implementação do EA, incluindo preparação dos dados, treinamento do modelo e integração ao ambiente MetaTrader 5. Além disso, apresentaremos os resultados de uma otimização e backtesting abrangentes, comparando a eficácia da técnica apenas com VAM versus o método combinado VAM e LSTM Condicional.
Ao explorar esta nova estratégia de trading, discutiremos os desafios e fatores envolvidos ao unir métodos avançados de machine learning com análise técnica tradicional. Buscamos oferecer uma visão abrangente dos elementos práticos para implementar tal sistema, desde qualidade dos dados e interpretabilidade do modelo até as demandas computacionais de operar modelos complexos em operações de trading em tempo real.
Ao final deste artigo, os leitores terão uma compreensão completa de como técnicas modernas de machine learning podem ser usadas para aumentar a análise técnica tradicional e potencialmente melhorar os resultados das operações. Esta investigação sobre VAM e LSTM Condicional em trading automatizado traz insights valiosos sobre o futuro do trading algorítmico, independentemente de você ser trader, cientista de dados ou pesquisador interessado nos limites das finanças quantitativas.
Momentum Ajustado pela Volatilidade (VAM)
O conceito central do VAM é considerar a volatilidade do mercado ao avaliar o momentum. Ele calcula a diferença entre o preço atual e um preço passado (momentum) e depois divide pelo produto da volatilidade e a raiz quadrada do período de momentum. Esse valor, ajustado por um fator de escala, indica a força do momentum considerando a volatilidade recente do mercado.
Modelo de Deep Learning
O artigo utiliza um modelo LSTM Condicional, um tipo de rede neural recorrente (RNN) adequada para séries temporais financeiras. Esse modelo recebe como entrada dados históricos de preço e indicadores técnicos (como o MACD utilizado aqui) e prevê movimentos futuros de preços. A vantagem dos LSTMs Condicionais está em sua capacidade de capturar relações complexas entre diversos fatores de mercado.
O Expert Advisor (EA)
O artigo descreve a criação de um EA que combina as previsões do modelo de deep learning com o VAM. Abaixo, um resumo dos principais recursos:
- Inicialização: O EA carrega e configura os parâmetros de entrada e saída para o modelo de deep learning pré-treinado em ONNX.
- Aquisição e Normalização de Dados: O EA coleta leituras do MACD e dados de preços anteriores. Antes de inserir essas variáveis no modelo de deep learning, ele as normaliza.
- Cálculo do VAM: Usando dados históricos e atuais de preço, o EA calcula o indicador VAM.
- Lógica de Trading e Previsão: O EA obtém uma previsão de preço do modelo de deep learning.
- O EA inicia uma operação de compra se o VAM estiver alto e a previsão indicar alta de preço.
- Por outro lado, o EA inicia uma venda se o VAM estiver baixo e a previsão indicar queda de preço.
Ao determinar dinamicamente níveis de stop-loss e take-profit com base no Average True Range (ATR), o EA gerencia o risco.
Resultados:
O artigo menciona resultados de backtest do EA usando a estratégia VAM, com e sem LSTM Condicional.
Vamos criar um novo indicador (VAM)
E se criarmos um novo indicador, por exemplo este:
// Calcular Momentum double momentum = close_price - iClose(NULL, 0, momentum_period); // Calcular Volatilidad double volatility = iMA(NULL, 0, volatility_period, 0, MODE_SMA, PRICE_CLOSE); // Calcular VAM double vam =( momentum / (volatility * MathSqrt(momentum_period)))*10000;
Usaremos o Momentum e a Volatilidade para criar um novo indicador, chamado VAM.
O momentum é dividido pelo produto da raiz quadrada do período de momentum e da volatilidade.
Para fins de escala, o resultado é então multiplicado por 10.000.
Ao considerar a volatilidade, o indicador VAM busca quantificar o momentum. Ele tenta padronizar o momentum em diferentes condições de mercado ao dividir o momentum pela volatilidade. A raiz quadrada do período de momentum no denominador ajuda a padronizar o indicador para diversos períodos.
Um valor positivo de VAM indica momentum de alta, enquanto um valor negativo indica momentum de baixa. A magnitude do VAM representa a força do momentum, ajustada para a volatilidade recente do mercado.
Este indicador pode ser utilizado para identificar possíveis reversões de tendência ou medir a força das tendências atuais, levando em conta a volatilidade do mercado.
Com apenas este indicador, podemos criar um EA e verificar se é lucrativo ou não.
A estratégia seria assim:
void OnTick() { int bars = iBars(NULL, 0); if(bars < MathMax(momentum_period, MathMax(volatility_period, (vam_period))))//, MathMax(ma_long_period, rsi_period))))) return; double close_price = iClose(NULL, 0, 0); // Calcular Momentum double momentum = close_price - iClose(NULL, 0, momentum_period); // Calcular Volatilidad double volatility = iMA(NULL, 0, volatility_period, 0, MODE_SMA, PRICE_CLOSE); // Calcular VAM double vam =( momentum / (volatility * MathSqrt(momentum_period)))*10000; double atr = iATR(_Symbol,PERIOD_CURRENT,14)*_Point; double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double slPriceBuy = NormalizeDouble(Bid - slmul*atr,_Digits); double tpPriceBuy = NormalizeDouble(Ask + tpmul*atr,_Digits); double slPriceSell = NormalizeDouble(Ask + slmul*atr,_Digits); double tpPriceSell = NormalizeDouble(Bid - tpmul*atr,_Digits); // Señales if(vam > VAMTHRESH)// && ma_short > ma_long)// && rsi < 70 && ma_short > ma_long ) { // Comprar trade.Buy(lot_size,_Symbol, Ask, slPriceBuy, tpPriceBuy, " BUY EA "); } else if(vam < -VAMTHRESH)// && ma_short < ma_long)// rsi > 30 && ma_short < ma_long ) { // Vender trade.Sell(lot_size,_Symbol, Bid, slPriceSell, tpPriceSell, " SELL EA "); } }
A função iBars(NULL, 0) retorna o total de barras disponíveis para o símbolo e timeframe escolhidos.
bars int: O número total de barras, ou o valor retornado, é armazenado na variável bars.
MathMax: Esta função retorna o valor máximo dos números fornecidos. Neste caso, é usada de forma aninhada para determinar o valor máximo em múltiplos períodos.
As variáveis momentum_period, volatility_period, vam_period, ma_long_period e rsi_period, previamente estabelecidas, indicam os intervalos de diferentes indicadores ou cálculos.
If: A condição determina se o número total de barras é menor que a soma dos tempos alocados.
Se a condição "if" for verdadeira (ou seja, não há barras suficientes), a função é interrompida imediatamente e o restante do código não é executado.
Resultados VAM
Os resultados são assim (após uma rápida otimização, sem finalizá-la):
Isso parece bom, para uma estratégia e um indicador simples.
Vamos ver o que poderíamos alcançar se usássemos um modelo de Deep Learning para isso (mas hoje vamos usar algo diferente), vamos criar um modelo de deep learning com alguns indicadores para ver qual se encaixa melhor.
Modelo de Deep Learning
Vamos exportar este modelo em ONNX, mas primeiro vamos comparar qual é o melhor.
Para fazer tudo isso, usaremos o Google Colab (para não consumir recursos dos nossos PCs) com o script Python anexado.
Como este é um site mql5, não vou explicar o código python.
São dois scripts py: o primeiro é um script com todos os indicadores usados e o segundo é o mesmo script, mas apenas com o indicador MACD (porque no primeiro script supomos que o MACD tem boa taxa de acerto e R2, com poucos erros).
Os resultados gráficos do primeiro script são estes:
Depois de decidir usar o MACD, preparamos o script e ajustamos as datas para primeiro de janeiro de 2024 (para podermos realizar o backtest dos resultados no mql5 a partir de 01/01/2024).
Os resultados do segundo script foram estes (muito similares).
etc ... (você pode fazer por conta própria e conferir os resultados com o colab).
O script python é para o Colab, você deve primeiro rodar a primeira célula e, quando todas as bibliotecas forem instaladas, rodar a segunda célula, aceitar salvar os modelos e gráficos no seu Drive e apenas aguardar até terminar.
Os dados são obtidos fora do mlq5, pois o MetaTrader não está instalado no Colab (os valores devem ser similares).
Como pode ser visto no segundo grupo de imagens, o modelo MACD tem uma taxa de acerto realmente boa, por isso foi escolhido.
LSTM Condicional
Uma versão aprimorada da rede neural convencional Long Short-Term Memory é chamada de LSTM Condicional. Ao adicionar mais dados contextuais ou situações ao processo preditivo da arquitetura LSTM, ela o aprimora. Como muitos fatores podem afetar as mudanças de preço nos mercados financeiros, ela é especialmente interessante para previsão de mercado financeiro.Um instrumento eficaz no campo de previsão de ações ou forex é uma máquina de regressão logística condicional. Isso permite que o modelo leve em conta diversos indicadores de mercado e variáveis externas além dos dados de preços passados. Isso pode incluir dados de sentimento, indicadores econômicos gerais e indicadores técnicos como RSI ou médias móveis. O modelo busca fornecer uma visão mais completa da dinâmica do mercado ao integrar essas diversas entradas.
A consciência contextual é um dos principais benefícios de utilizar o LSTM Condicional para previsão financeira. Mercados financeiros são sistemas complexos impactados por uma grande variedade de fatores. Como o LSTM Condicional pode combinar vários indicadores, ele pode revelar correlações complexas entre diferentes dinâmicas de mercado. Sua capacidade de lidar com características estáticas e dados de séries temporais o torna adequado para mercados financeiros, onde tendências passadas e condições presentes são igualmente importantes.
Além disso, LSTMs Condicionais são excelentes em capturar dependências de longo prazo em séries temporais, assim como LSTMs convencionais. Isso é especialmente útil nos mercados financeiros, onde padrões de longo prazo podem surgir. O modelo pode detectar padrões que modelos mais simples podem não perceber graças à sua capacidade de reter informações relevantes ao longo de sequências extensas.
No entanto, há certos desafios em usar LSTM Condicional para previsão financeira. Embora a maior complexidade do modelo possa trazer vantagens, ela também apresenta desafios. O overfitting se torna mais provável à medida que o treinamento se complica, principalmente com conjuntos de dados menores. Custos computacionais mais elevados são consequência dessa complexidade, o que pode ser um fator importante em aplicações de trading em tempo real.
A qualidade e relevância dos dados se tornam ainda mais críticas com LSTMs Condicionais. O modelo requer não apenas dados de preço, mas também dados de indicadores de alta qualidade e relevância. Garantir dados consistentes e precisos em todas essas dimensões pode ser desafiador no mundo acelerado e, às vezes, opaco dos mercados financeiros.
Também é importante considerar a natureza fundamental dos mercados financeiros ao avaliar o potencial dos LSTMs Condicionais. Mercados são influenciados por eventos imprevisíveis e pelo comportamento humano, o que pode limitar a eficácia de qualquer modelo preditivo, por mais sofisticado que seja. O modelo pode se destacar ao identificar padrões em dados históricos, mas pode ter dificuldades diante de condições de mercado inéditas ou choques econômicos relevantes.
Outro desafio dos LSTMs Condicionais, assim como de muitos modelos de deep learning, é a interpretabilidade. Mesmo que possam gerar previsões precisas, pode ser difícil compreender a lógica por trás delas. O aspecto "caixa-preta" disso pode causar problemas em aplicações financeiras, onde explicabilidade e transparência são frequentemente essenciais.
Por fim, mesmo que os LSTMs Condicionais apresentem oportunidades interessantes para previsão de ações e FX baseada em indicadores, é importante usá-los de forma criteriosa. Sua capacidade de incorporar dados complexos e multifacetados pode resultar em previsões mais precisas e sofisticadas. No entanto, devem ser utilizados como parte de uma abordagem analítica mais abrangente e cuidadosamente planejada, devido aos desafios impostos pela complexidade crescente, requisitos de dados e a imprevisibilidade inerente dos mercados financeiros uma compreensão profunda dos limites do modelo em situações práticas e extensivo backtesting. Aplicar técnicas tão avançadas no cenário de trading financeiro de alto risco requer extensivo backtesting e conhecimento dos limites do modelo em ambientes práticos.
O modelo (como feito no script py) se parece com isto:
E seus inputs e outputs devem ser assim:
Código do EA
O principal objetivo deste Expert Advisor (EA) é automatizar decisões de negociação com base em uma combinação de indicadores técnicos e previsões de um modelo de deep learning (ONNX). O EA utiliza o indicador Volatility Adjusted Momentum (VAM) e o MACD (Moving Average Convergence Divergence), juntamente com previsões de preço feitas por um modelo de machine learning. Ele executa operações dependendo da combinação desses elementos.
O EA começa definindo diversas propriedades e bibliotecas. A classe CTrade é incluída para execução das operações, e outros cabeçalhos para funções estatísticas e manipulação de arrays. Parâmetros de entrada são definidos para o cálculo do VAM e execução das operações, como momentum_period, volatility_period e vam_period, que são usados para controlar a lógica de cálculo do momentum e da volatilidade. Parâmetros de negociação como lot_size, e multiplicadores para stop loss (slmul) e take profit (tpmul) também são definidos aqui, proporcionando flexibilidade ao comportamento do EA. Além disso, constantes que definem os parâmetros do modelo ONNX, como BATCH_SIZE, SEQUENCE_LENGTH e outros, são incluídas para gerenciar como os dados são passados para o modelo de deep learning.
//+------------------------------------------------------------------+ //| VAM + DL(MACD) EA | //| Copyright 2024, Javier Santiago Gaston de Iriarte Cabrera | //| https://www.mql5.com/en/users/jsgaston/news | //+------------------------------------------------------------------+ #property copyright "Javier Santiago Gaston de Iriarte Cabrera" #property link "https://www.mql5.com/en/users/jsgaston/news" #property version "1.01" #include <Trade\Trade.mqh> #include <Math\Stat\Math.mqh> #include <Arrays\ArrayFloat.mqh> CTrade trade; // Inputs input int momentum_period = 13; input int volatility_period = 7; input int vam_period = 9; input double lot_size = 0.01; input int slippage = 3; input double VAMTHRESH = 9.0; input int slmul = 2; input int tpmul = 4; // ONNX model parameters #define BATCH_SIZE 1 #define SEQUENCE_LENGTH 30 #define INPUT_FEATURES 3 #define CONDITION_FEATURES 2 #define HIDDEN_DIM 128 #define NUM_LAYERS 2 float input_x[][SEQUENCE_LENGTH][INPUT_FEATURES]; float input_condition[][CONDITION_FEATURES]; float h0[][BATCH_SIZE][HIDDEN_DIM]; float c0[][BATCH_SIZE][HIDDEN_DIM]; #define PRICE_UP 0 #define PRICE_SAME 1 #define PRICE_DOWN 2 long ExtHandle = INVALID_HANDLE; int ExtPredictedClass = -1; datetime ExtNextBar = 0; datetime ExtNextDay = 0; float ExtMin = 0.0; float ExtMax = 1.0; // Initialize to 1.0 to prevent division by zero float predicted_last; #resource "/Files/stock_prediction_model_MACD.onnx" as uchar ExtModel[]
A função de inicialização OnInit() é crucial, pois carrega o modelo ONNX a partir de um recurso binário (stock_prediction_model_MACD.onnx), configurando os formatos de entrada e saída do modelo. A entrada para o modelo ONNX consiste em dados históricos de preço, valores do MACD e estados inicializados (h0, c0) para as camadas recorrentes do modelo. Se o modelo é carregado com sucesso, a função também inicializa os valores mínimo e máximo de preço (ExtMin e ExtMax), que serão usados para normalizar os dados de entrada para o modelo ONNX. Se ocorrer qualquer erro ao carregar o modelo, retorna INIT_FAILED, interrompendo a operação do EA.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { Print("BATCH_SIZE: ", BATCH_SIZE, ", CONDITION_FEATURES: ", CONDITION_FEATURES); ExtHandle = OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT); if(ExtHandle == INVALID_HANDLE) { Print("OnnxCreateFromBuffer error ", GetLastError()); return(INIT_FAILED); } // Set input shapes long input_shape[] = {BATCH_SIZE, SEQUENCE_LENGTH, INPUT_FEATURES}; if(!OnnxSetInputShape(ExtHandle, ONNX_DEFAULT, input_shape)) { Print("OnnxSetInputShape for input_x error ", GetLastError()); return(INIT_FAILED); } long condition_shape[] = {BATCH_SIZE,CONDITION_FEATURES}; if(!OnnxSetInputShape(ExtHandle, 1, condition_shape)) { Print("OnnxSetInputShape for input_condition error ", GetLastError()); return(INIT_FAILED); } long h0_shape[] = {NUM_LAYERS, BATCH_SIZE, HIDDEN_DIM}; if(!OnnxSetInputShape(ExtHandle, 2, h0_shape)) { Print("OnnxSetInputShape for h0 error ", GetLastError()); return(INIT_FAILED); } long c0_shape[] = {NUM_LAYERS, BATCH_SIZE, HIDDEN_DIM}; if(!OnnxSetInputShape(ExtHandle, 3, c0_shape)) { Print("OnnxSetInputShape for c0 error ", GetLastError()); return(INIT_FAILED); } const long output_shape[] = {1,1}; if(!OnnxSetOutputShape(ExtHandle,0,output_shape)) { Print("OnnxSetOutputShape error ",GetLastError()); return(INIT_FAILED); } // Initialize ExtMin and ExtMax GetMinMax(); Print("Initializing EA with VAM and ONNX integration"); return(INIT_SUCCEEDED); }
A função OnTick() é a lógica central que roda a cada novo tick de preço. Ela começa verificando se é um novo dia e atualiza os preços mínimos e máximos usando GetMinMax(). O próximo bloco garante que a função só continue quando um novo candle está disponível. O EA então atualiza as variáveis ExtMin e ExtMax para os valores de preço mais recentes. O coração desta função é a combinação do cálculo do VAM e da previsão do ONNX. O VAM é calculado pela diferença de preço (momentum) dividida pelo produto da volatilidade e da raiz quadrada de momentum_period, escalado por 10.000. Se o VAM excede um limiar (VAMTHRESH), isso indica uma forte tendência de mercado, sinalizando uma possível operação.
O EA então combina o resultado da previsão e do VAM. Se o VAM está alto (acima de VAMTHRESH) e o modelo ONNX prevê aumento de preço, o EA abre uma operação de compra com stop loss e take profit calculados com base no Average True Range (ATR). Da mesma forma, se o VAM está baixo (abaixo de menos VAMTHRESH) e o modelo ONNX prevê queda de preço, o EA abre uma venda. Essas operações são executadas usando a classe CTrade, que interage com as funções de negociação da plataforma MetaTrader 5.
Em termos de gerenciamento de risco, os níveis de stop loss e take profit são calculados dinamicamente com base no ATR do ativo. Isso garante que a estratégia se adapte à volatilidade do mercado, proporcionando saídas de operações mais flexíveis conforme as condições atuais.void OnTick() { // Check for new day and update ExtMin and ExtMax if(TimeCurrent() >= ExtNextDay) { GetMinMax(); ExtNextDay = TimeCurrent() - TimeCurrent() % PeriodSeconds(PERIOD_D1) + PeriodSeconds(PERIOD_D1); } // Check for new bar if(TimeCurrent() < ExtNextBar) return; ExtNextBar = TimeCurrent() - TimeCurrent() % PeriodSeconds() + PeriodSeconds(); // Update ExtMin and ExtMax double close = iClose(_Symbol, _Period, 0); if(ExtMin > close) ExtMin = (float)close; if(ExtMax < close) ExtMax = (float)close; int bars = iBars(_Symbol, PERIOD_CURRENT); if(bars < MathMax(momentum_period, MathMax(volatility_period, MathMax(vam_period, SEQUENCE_LENGTH)))) return; // Calculate VAM double momentum = close - iClose(_Symbol, PERIOD_CURRENT, momentum_period); double volatility = iStdDev(_Symbol, PERIOD_CURRENT, volatility_period, 0, MODE_SMA, PRICE_CLOSE); double vam = (momentum / (volatility * MathSqrt(momentum_period))) * 10000; Print("VAM ", vam); // Get ONNX prediction int result=GetPrediction(); // Trading logic combining VAM and ONNX prediction double atr = iATR(_Symbol, PERIOD_CURRENT, 14)*_Point; double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double slPriceBuy = NormalizeDouble(Bid - slmul * atr, _Digits); double tpPriceBuy = NormalizeDouble(Ask + tpmul * atr, _Digits); double slPriceSell = NormalizeDouble(Ask + slmul * atr, _Digits); double tpPriceSell = NormalizeDouble(Bid - tpmul * atr, _Digits); //Print(result); if(vam > VAMTHRESH && result == 0) { trade.Buy(lot_size, _Symbol, Ask, slPriceBuy, tpPriceBuy, "BUY VAM+ONNX"); } else if(vam < -VAMTHRESH && result == 2) { trade.Sell(lot_size, _Symbol, Bid, slPriceSell, tpPriceSell, "SELL VAM+ONNX"); } }
A previsão do modelo ONNX é obtida chamando GetPrediction(). A entrada do modelo é preparada pela função PrepareInputs(), que reúne os preços de fechamento históricos e os dados do MACD, normaliza usando o intervalo de preços (ExtMin e ExtMax), e preenche os arrays de entrada esperados pelo modelo. Ela define os dados para a sequência de preços de entrada (input_x) e condições baseadas no MACD (input_condition), além de reiniciar os estados ocultos (h0, c0). Uma vez que a entrada está pronta, o modelo é executado pela função OnnxRun(), que calcula o preço previsto. A diferença entre o preço previsto e o último preço previsto é usada para determinar se o modelo espera que o preço suba, caia ou permaneça o mesmo. Se a variação na previsão for muito pequena, o modelo sugere que não há movimento (preço permanece igual).
void PrepareInputs() { ArrayResize(input_x, BATCH_SIZE); ArrayResize(input_condition, BATCH_SIZE); ArrayResize(h0, NUM_LAYERS); ArrayResize(c0, NUM_LAYERS); for(int i = 0; i < SEQUENCE_LENGTH; i++) { input_x[0][i][0] = (float)((iClose(_Symbol, PERIOD_CURRENT, i) - ExtMin) / (ExtMax - ExtMin)); double macd_main[], macd_signal[]; int macd_handle = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE); CopyBuffer(macd_handle, 0, i, 1, macd_main); CopyBuffer(macd_handle, 1, i, 1, macd_signal); input_x[0][i][1] = (float)((macd_main[0] - ExtMin) / (ExtMax - ExtMin)); input_x[0][i][2] = (float)((macd_signal[0] - ExtMin) / (ExtMax - ExtMin)); } double macd_main2[], macd_signal2[]; int macd_handle2 = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE); CopyBuffer(macd_handle2, 0, 0, 1, macd_main2); CopyBuffer(macd_handle2, 1, 0, 1, macd_signal2); input_condition[0][0] = (float)macd_main2[0]; input_condition[0][1] = (float)macd_signal2[0]; ArrayInitialize(h0, 0.0f); ArrayInitialize(c0, 0.0f); } //+------------------------------------------------------------------+ //| Get prediction from ONNX model | //+------------------------------------------------------------------+ int GetPrediction() { PrepareInputs(); float output_data[]; ArrayResize(output_data, 1); // Run the ONNX model if(!OnnxRun(ExtHandle, ONNX_NO_CONVERSION, input_x, input_condition, h0, c0, output_data)) { Print("OnnxRun error: ", GetLastError()); return ExtPredictedClass = -1; } float predicted=output_data[0]*(ExtMax-ExtMin)+ExtMin; Print("Predicted last ", predicted_last); Print("Predicted ",predicted); float last_close = (float)iClose(_Symbol, PERIOD_CURRENT, 0); Print("last close ",last_close); float delta = predicted_last - predicted; predicted_last=predicted; Print("Delta ",delta); if(MathAbs(delta) <= 0.00001) ExtPredictedClass = PRICE_SAME; else if(delta < 0) ExtPredictedClass = PRICE_UP; else ExtPredictedClass = PRICE_DOWN; Print(ExtPredictedClass); return ExtPredictedClass; }
A função GetMinMax() é responsável por definir os valores mínimo (ExtMin) e máximo (ExtMax) de preço do último dia de dados. Esses valores são usados para normalizar as entradas antes de passar para o modelo ONNX, garantindo que o modelo receba entradas em um intervalo consistente. Se o EA não conseguir obter os dados de preço necessários, ele utiliza um intervalo padrão seguro para evitar divisão por zero.
void GetMinMax() { double close[]; int copied = CopyClose(_Symbol, PERIOD_D1, 0, SEQUENCE_LENGTH, close); if(copied > 0) { ExtMin = (float)MathMin(close); ExtMax = (float)MathMax(close); } else { Print("Failed to copy price data. Error: ", GetLastError()); ExtMin = 0; ExtMax = 1; // Prevent division by zero } }
Por fim, o EA inclui a função de desinicialização OnDeinit(), que libera o handle do modelo ONNX quando o EA é removido, garantindo o gerenciamento correto da memória e evitando vazamentos de recursos.
void OnDeinit(const int reason) { if(ExtHandle != INVALID_HANDLE) { OnnxRelease(ExtHandle); ExtHandle = INVALID_HANDLE; } }
Em resumo, este EA combina análise técnica (via VAM e MACD) com previsões de machine learning de um modelo ONNX para tomar decisões automatizadas de negociação mais informadas. A análise técnica identifica tendências, enquanto o modelo de machine learning prevê o movimento dos preços, resultando em uma estratégia híbrida.
Resultados
Após otimização
Conclusão
Este artigo analisa a integração de deep learning, especificamente modelos LSTM Condicionais, com o indicador Volatility Adjusted Momentum (VAM) para aprimorar sistemas automatizados de negociação. Ao combinar a capacidade preditiva do LSTM e a análise de momentum sensível à volatilidade do VAM, a estratégia visa capturar dinâmicas de mercado complexas. Implementado no MetaTrader 5, esse sistema gera sinais de negociação e adapta o gerenciamento de risco de forma dinâmica.
Os backtests mostram resultados aprimorados quando o LSTM é combinado ao VAM. Apesar de desafios como overfitting e exigência computacional, o estudo sugere que a integração de deep learning com análise técnica pode melhorar significativamente estratégias de trading algorítmico.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15956





- 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
Oi Javier
Obrigado pela resposta.
Encontrei o problema. Você nomeou "stock_prediction_model_MACD.onnx" no EA, mas os arquivos zip o nomearam como stock_prediction_model_MACD_Signal.onnx
Também notei o uso inadequado do identificador do indicador (bug!!!) no código. Você usou
Na MQL5, os valores do indicador são derivados usando CopyBuffer e o identificador do indicador, que você usou em
Você pode explicar por que o handle foi usado de forma diferente com uma variável dupla para obter os valores no primeiro caso?Abraços e bom fim de semana.
Olá, Anil
atr * _Point() para usar o valor diretamente. Imprima atr sem o ponto e ele fornecerá valores estranhos.
Oi Javier
Obrigado pela resposta.
Encontrei o problema. Você nomeou "stock_prediction_model_MACD.onnx" no EA, mas os arquivos zip o nomearam como stock_prediction_model_MACD_Signal.onnx
Também notei o uso inadequado do identificador do indicador (bug!!!) no código. Você usou
Na MQL5, os valores do indicador são derivados usando CopyBuffer e o identificador do indicador, que você usou em
Você pode explicar por que o handle foi usado de forma diferente com uma variável dupla para obter os valores no primeiro caso?Abraços e bom fim de semana.
Você está completamente certo!
Cometi um erro nesse ponto, obrigado por esclarecer isso.
Você precisa usar copybuffer e handle.
Olá , Javier
Obrigado por esse excelente artigo, mas seu bot usa uma relação risco/recompensa de 135:20, o que o torna arriscado. Quando tento uma relação adequada, como 1:2 ou 1:3, o bot perde.
Olá , Javier
Obrigado por esse excelente artigo, mas seu bot usa uma relação risco/recompensa de 135:20, o que o torna arriscado. Quando tento uma relação adequada, como 1:2 ou 1:3, o bot perde.
Olá, acho que não fui muito explícito e expressei que esse exemplo serve apenas como uma forma de mostrar que você pode usar o LSTM com mais do que apenas o OHLC. Simplesmente não use esse exemplo para negociar.
Olá, Javier
como ter certeza de que esse valor do parâmetro VAMTHRESH está correto?