
Ciência de dados e aprendizado de máquina (Parte 28): Previsão de múltiplos valores futuros para EURUSD
Conteúdo
- Introdução
- Previsão multietapa direta
- Vantagens da previsão multietapa direta
- Desvantagens da previsão multietapa direta
- Previsão multietapa recursiva
- Vantagens da previsão multietapa recursiva
- Desvantagens da previsão multietapa recursiva
- Previsão multietapa utilizando modelos com múltiplas saídas
- Vantagens da previsão multietapa utilizando modelos com múltiplas saídas
- Desvantagens da previsão multietapa utilizando modelos com múltiplas saídas
- Quando e onde usar a previsão multietapa
- Considerações finais
Introdução
No mundo da análise financeira com aprendizado de máquina, o objetivo é prever valores futuros com base em dados históricos. Em diferentes artigos desta série, já discutimos as possibilidades de previsão do próximo valor imediato. No entanto, em aplicações reais, muitas vezes é necessário prever vários valores futuros em vez de apenas um. A tentativa de prever diferentes valores sequenciais é conhecida como previsão multietapa.
A previsão multietapa pode ser aplicada em várias áreas, como finanças, previsão do tempo, gerenciamento de cadeias de suprimentos e saúde. Nos mercados financeiros, por exemplo, os investidores precisam prever preços de ações ou taxas de câmbio para vários dias, semanas ou até meses à frente. Previsões mais precisas do tempo para os próximos dias ou semanas podem auxiliar no planejamento e na gestão de situações emergenciais.
Este artigo pressupõe que você tenha conhecimentos básicos sobre aprendizado de máquina e IA, ONNX, como utilizar modelos ONNX no MQL5, regressão linear, LightGBM e redes neurais..
O processo de previsão multietapa envolve várias metodologias, cada uma com seus pontos fortes e fracos. Isso inclui:
- Previsão multietapa direta
- Previsão multietapa recursiva
- Modelos com múltiplas saídas
- Vetores autorregressivos (VAR) (será abordado no próximo artigo ou artigos)
Neste artigo, abordaremos os fundamentos desses métodos, exploraremos como aplicá-los e como implementá-los utilizando diferentes abordagens de aprendizado de máquina e estatística. O objetivo da previsão multietapa neste artigo é auxiliar na tomada de decisões sobre o futuro movimento do par EURUSD.
# Create target variables for multiple future steps def create_target(df, future_steps=10): target = pd.concat([df['Close'].shift(-i) for i in range(1, future_steps + 1)], axis=1) # using close prices for the next i bar target.columns = [f'target_close_{i}' for i in range(1, future_steps + 1)] # naming the columns return target # Combine features and targets new_df = pd.DataFrame({ 'Open': df['Open'], 'High': df['High'], 'Low': df['Low'], 'Close': df['Close'] }) future_steps = 5 target_columns = create_target(new_df, future_steps).dropna() combined_df = pd.concat([new_df, target_columns], axis=1) #concatenating the new pandas dataframe with the target columns combined_df = combined_df.dropna() #droping rows with NaN values caused by shifting values target_cols_names = [f'target_close_{i}' for i in range(1, future_steps + 1)] X = combined_df.drop(columns=target_cols_names).values #dropping all target columns from the x array y = combined_df[target_cols_names].values # creating the target variables print(f"x={X.shape} y={y.shape}") combined_df.head(10)
Previsão multietapa direta
A previsão multietapa direta é um método no qual são treinados modelos preditivos distintos para cada etapa futura que se deseja prever. Se quisermos prever valores para os próximos cinco períodos, por exemplo, será necessário treinar cinco modelos diferentes. Um para prever o primeiro período, outro para o segundo e assim por diante.
Na previsão multietapa direta, cada modelo é projetado para prever um horizonte específico. Essa abordagem permite que cada modelo se concentre em padrões e relações específicas relevantes para o período futuro correspondente, o que pode potencialmente aumentar a precisão de cada previsão. No entanto, isso também significa que será necessário treinar e manter vários modelos, o que pode demandar recursos consideráveis.
Vamos tentar prever vários períodos à frente usando um modelo de aprendizado de máquina LightGBM.
Primeiro, criaremos uma função para processar os dados de múltiplos períodos.
Preparação dos dados
Código Python
def multi_steps_data_process(data, step, train_size=0.7, random_state=42): # Since we are using the OHLC values only data["next signal"] = data["Signal"].shift(-step) # The target variable from next n future values data = data.dropna() y = data["next signal"] X = data.drop(columns=["Signal", "next signal"]) return train_test_split(X, y, train_size=train_size, random_state=random_state)
Esta função cria uma nova variável alvo utilizando a coluna “Sinal” do conjunto de dados. A variável alvo é obtida a partir do valor do índice step+1 na coluna de sinal.
Suponha que temos os seguintes dados:
Sinais |
---|
1 |
2 |
3 |
4 |
5 |
No passo 1, o próximo sinal será 2, no passo 2, o próximo sinal será 3, e assim por diante.
Neste artigo, utilizaremos dados do time frame H1 do EURUSD com 1000 barras.
Código Python
df = pd.read_csv("/kaggle/input/eurusd-period-h1/EURUSD.PERIOD_H1.csv") print(df.shape) df.head(10)
Resultados
Para simplificar, criei um mini conjunto de dados com apenas cinco variáveis.
A coluna “Sinal” representa os sinais de candles de alta ou de baixa. Ela foi criada com a seguinte lógica: sempre que o preço de fechamento foi maior que o preço de abertura, o sinal recebeu o valor 1; caso contrário, recebeu o valor 0.
Agora que temos a função para criar dados multietapa, vamos declarar nossos modelos para processar cada etapa.
Treinamento de múltiplos modelos para previsão
Escrever manualmente o código do modelo para cada etapa temporal pode ser ineficiente, pois consumiria muito tempo. A programação dentro de um loop torna esse processo mais simples e eficaz. No loop, executamos todas as ações necessárias, como treinamento, validação e salvamento do modelo para uso externo no MetaTrader 5.
Código Python
for pred_step in range(1, 6): # We want to 5 future values lgbm_model = lgbm.LGBMClassifier(**params) X_train, X_test, y_train, y_test = multi_steps_data_process(new_df, pred_step) # preparing data for the current step lgbm_model.fit(X_train, y_train) # training the model for this step # Testing the trained mdoel test_pred = lgbm_model.predict(X_test) # Changes from bst to pipe # Ensuring the lengths are consistent if len(y_test) != len(test_pred): test_pred = test_pred[:len(y_test)] print(f"model for next_signal[{pred_step} accuracy={accuracy_score(y_test, test_pred)}") # Saving the model in ONNX format, Registering ONNX converter update_registered_converter( lgbm.LGBMClassifier, "GBMClassifier", calculate_linear_classifier_output_shapes, convert_lightgbm, options={"nocl": [False], "zipmap": [True, False, "columns"]}, ) # Final LightGBM conversion to ONNX model_onnx = convert_sklearn( lgbm_model, "lightgbm_model", [("input", FloatTensorType([None, X_train.shape[1]]))], target_opset={"": 12, "ai.onnx.ml": 2}, ) # And save. with open(f"lightgbm.EURUSD.h1.pred_close.step.{pred_step}.onnx", "wb") as f: f.write(model_onnx.SerializeToString())
Resultados
model for next_signal[1 accuracy=0.5033333333333333 model for next_signal[2 accuracy=0.5566666666666666 model for next_signal[3 accuracy=0.4866666666666667 model for next_signal[4 accuracy=0.4816053511705686 model for next_signal[5 accuracy=0.5317725752508361
Curiosamente, o modelo para previsão do segundo candle foi o mais preciso, com uma acurácia de 55%, seguido pelo modelo para previsão do quinto candle, que atingiu uma precisão de 53%.
Carregamento dos modelos para previsão no MetaTrader 5
Começamos integrando todos os modelos LightGBM, salvos no formato ONNX, ao nosso EA como arquivos de recursos.
Código MQL5
#resource "\\Files\\lightgbm.EURUSD.h1.pred_close.step.1.onnx" as uchar model_step_1[] #resource "\\Files\\lightgbm.EURUSD.h1.pred_close.step.2.onnx" as uchar model_step_2[] #resource "\\Files\\lightgbm.EURUSD.h1.pred_close.step.3.onnx" as uchar model_step_3[] #resource "\\Files\\lightgbm.EURUSD.h1.pred_close.step.4.onnx" as uchar model_step_4[] #resource "\\Files\\lightgbm.EURUSD.h1.pred_close.step.5.onnx" as uchar model_step_5[] #include <MALE5\Gradient Boosted Decision Trees(GBDTs)\LightGBM\LightGBM.mqh> CLightGBM *light_gbm[5]; //for storing 5 different models MqlRates rates[];
Depois, inicializamos nossos 5 modelos diferentes.
Código MQL5
int OnInit() { //--- for (int i=0; i<5; i++) light_gbm[i] = new CLightGBM(); //Creating LightGBM objects //--- if (!light_gbm[0].Init(model_step_1)) { Print("Failed to initialize model for step=1 predictions"); return INIT_FAILED; } if (!light_gbm[1].Init(model_step_2)) { Print("Failed to initialize model for step=2 predictions"); return INIT_FAILED; } if (!light_gbm[2].Init(model_step_3)) { Print("Failed to initialize model for step=3 predictions"); return INIT_FAILED; } if (!light_gbm[3].Init(model_step_4)) { Print("Failed to initialize model for step=4 predictions"); return INIT_FAILED; } if (!light_gbm[4].Init(model_step_5)) { Print("Failed to initialize model for step=5 predictions"); return INIT_FAILED; } return(INIT_SUCCEEDED); }
Por fim, podemos coletar os valores de preço de abertura, máxima, mínima e fechamento (Open, High, Low e Close) do candle anterior e usá-los para obter previsões a partir dos 5 modelos distintos.
Código MQL5
void OnTick() { //--- CopyRates(Symbol(), PERIOD_H1, 1, 1, rates); vector input_x = {rates[0].open, rates[0].high, rates[0].low, rates[0].close}; string comment_string = ""; int signal = -1; for (int i=0; i<5; i++) { signal = (int)light_gbm[i].predict_bin(input_x); comment_string += StringFormat("\n Next[%d] bar predicted signal=%s",i+1, signal==1?"Buy":"Sell"); } Comment(comment_string); }
Resultado
Vantagens da previsão multietapa direta
- Cada modelo é especializado em um horizonte de previsão específico, o que potencialmente melhora a precisão das previsões em cada etapa.
- Treinar modelos separados é mais simples, especialmente quando se utilizam algoritmos básicos de aprendizado de máquina.
- É possível escolher diferentes modelos ou algoritmos para cada etapa, proporcionando maior flexibilidade na solução de diferentes problemas de previsão.
Desvantagens da previsão multietapa direta
- Esse método exige o treinamento e a manutenção de múltiplos modelos, o que pode ser custoso em termos computacionais e de tempo.
- Diferente dos métodos recursivos, os erros de uma etapa não são propagados diretamente para a seguinte, o que pode ser tanto uma vantagem quanto uma desvantagem. Isso pode causar inconsistências entre os passos.
- Cada modelo opera de maneira independente e pode capturar menos eficientemente as relações entre os horizontes de previsão do que uma abordagem única e integrada.
Previsão multietapa recursiva
A previsão multietapa recursiva, também chamada de previsão iterativa, é um método em que um único modelo é usado para prever um passo à frente. Em seguida, essa previsão é retroalimentada no modelo para gerar a previsão do próximo passo. Esse processo se repete até que todas as previsões para os períodos desejados sejam feitas.
Na previsão multietapa recursiva, o modelo é treinado para prever o próximo valor imediatamente após o atual. Após essa previsão, o valor estimado é adicionado aos dados de entrada e utilizado para prever o valor seguinte. Esse método usa o mesmo modelo iterativamente.
Utilizaremos um modelo de regressão linear para prever o próximo preço de fechamento com base no preço de fechamento anterior. Assim, o preço de fechamento previsto pode ser usado como entrada para a próxima iteração e assim por diante. Esse método parece funcionar bem mesmo com apenas uma variável independente (característica).
Código Python
new_df = pd.DataFrame({ 'Close': df['Close'], 'target close': df['Close'].shift(-1) # next bar closing price })
Then.
new_df = new_df.dropna() # after shifting we want to drop all NaN values X = new_df[["Close"]].values # Assigning close values into a 2D x array y = new_df["target close"].values print(new_df.shape) new_df.head(10)
Resultados
Treinamento e teste do modelo de regressão linear
Antes de treinar o modelo, dividimos os dados sem randomização. Isso pode ajudar o modelo a captar as dependências temporais entre os valores, pois sabemos que o fechamento seguinte é influenciado pelo preço de fechamento anterior.
model = Pipeline([ ("scaler", StandardScaler()), ("linear_regression", LinearRegression()) ]) # Split the data into training and test sets train_size = int(len(new_df) * 0.7) X_train, X_test = X[:train_size], X[train_size:] y_train, y_test = y[:train_size], y[train_size:] # Train the model model.fit(X_train, y_train)
Em seguida, criei um gráfico mostrando os valores reais do conjunto de teste e seus valores previstos, para analisar a eficácia do modelo na geração de previsões.
# Testing the Model test_pred = model.predict(X_test) # Make predictions on the test set # Plot the actual vs predicted values plt.figure(figsize=(7.5, 5)) plt.plot(y_test, label='Actual Values') plt.plot(test_pred, label='Predicted Values') plt.xlabel('Samples') plt.ylabel('Close Prices') plt.title('Actual vs Predicted Values') plt.legend() plt.show()
Resultado
Na imagem acima, podemos ver que o modelo fez previsões razoáveis. No conjunto de teste, sua precisão foi de 98%. No entanto, as previsões no gráfico mostram como o modelo linear funciona no conjunto de dados histórico, gerando previsões de forma convencional, sem utilizar o formato recursivo. Para que o modelo faça previsões recursivas, é necessário criar uma função personalizada.
Código Python
# Function for recursive forecasting def recursive_forecast(model, initial_value, steps): predictions = [] current_input = np.array([[initial_value]]) for _ in range(steps): prediction = model.predict(current_input)[0] predictions.append(prediction) # Update the input for the next prediction current_input = np.array([[prediction]]) return predictions
A seguir, podemos obter previsões futuras para 10 barras.
current_close = X[-1][0] # Use the last value in the array # Number of future steps to forecast steps = 10 # Forecast future values forecasted_values = recursive_forecast(model, current_close, steps) print("Forecasted Values:") print(forecasted_values)
Resultados
Forecasted Values: [1.0854623040804965, 1.0853751608200348, 1.0852885667357617, 1.0852025183667728, 1.0851170122739744, 1.085032045039946, 1.0849476132688034, 1.0848637135860637, 1.0847803426385094, 1.0846974970940555]
Para verificar a precisão do modelo recursivo, utilizamos a função recursive_forecast, mostrada no código acima, para gerar previsões dos próximos 10 passos ao longo de toda a série histórica, a partir do índice atual dentro de um loop.
predicted = [] for i in range(0, X_test.shape[0], steps): current_close = X_test[i][0] # Use the last value in the test array forecasted_values = recursive_forecast(model, current_close, steps) predicted.extend(forecasted_values) print(len(predicted))
Resultados
A precisão do modelo recursivo foi de 91%.
Por fim, podemos salvar o modelo de regressão linear no formato ONNX, compatível com MQL5.
# Convert the trained pipeline to ONNX initial_type = [('float_input', FloatTensorType([None, 1]))] onnx_model = convert_sklearn(model, initial_types=initial_type) # Save the ONNX model to a file with open("Lr.EURUSD.h1.pred_close.onnx", "wb") as f: f.write(onnx_model.SerializeToString()) print("Model saved to Lr.EURUSD.h1.pred_close.onnx")
Previsões recursivas no MQL5.
Começamos adicionando o modelo de regressão linear ONNX ao nosso EA.
#resource "\\Files\\Lr.EURUSD.h1.pred_close.onnx" as uchar lr_model[]
Depois, importamos a classe do manipulador do modelo de regressão linear.
#include <MALE5\Linear Models\Linear Regression.mqh>
CLinearRegression lr;
Após inicializar o modelo dentro da função OnInit, podemos obter o preço de fechamento do último candle fechado e, em seguida, fazer previsões para os próximos 10 candles.
int OnInit() { //--- if (!lr.Init(lr_model)) return INIT_FAILED; //--- ArraySetAsSeries(rates, true); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- CopyRates(Symbol(), PERIOD_H1, 1, 1, rates); vector input_x = {rates[0].close}; //get the previous closed bar close price vector predicted_close(10); //predicted values for the next 10 timestepps for (int i=0; i<10; i++) { predicted_close[i] = lr.predict(input_x); input_x[0] = predicted_close[i]; //The current predicted value is the next input } Print(predicted_close); }
Resultados
OR 0 16:39:37.018 Recursive-Multi step forecasting (EURUSD,H4) [1.084011435508728,1.083933353424072,1.083855748176575,1.083778619766235,1.083701968193054,1.083625793457031,1.083550095558167,1.08347487449646,1.083400130271912,1.083325862884521]
Por curiosidade, decidi criar objetos de linhas de tendência para exibir esses valores previstos ao longo de 10 períodos diretamente no gráfico principal.
if (NewBar()) { for (int i=0; i<10; i++) { predicted_close[i] = lr.predict(input_x); input_x[0] = predicted_close[i]; //The current predicted value is the next input //--- ObjectDelete(0, "step"+string(i+1)+"-prediction"); //delete an object if it exists TrendCreate("step"+string(i+1)+"-prediction",rates[0].time, predicted_close[i], rates[0].time+(10*60*60), predicted_close[i], clrBlack); //draw a line starting from the previous candle to 10 hours forward } }
A função TrendCreate cria uma linha de tendência horizontal curta, começando no último candle fechado e estendendo-se por 10 barras à frente.
Resultado
Vantagens da previsão multietapa recursiva
- Como apenas um modelo é treinado e mantido, isso simplifica a implementação e reduz o consumo de recursos computacionais.
- O mesmo modelo é utilizado iterativamente, garantindo consistência nas previsões ao longo de todo o horizonte de previsão.
Desvantagens da previsão multietapa recursiva
- Os erros das previsões iniciais podem se propagar e se amplificar nas previsões subsequentes, reduzindo potencialmente a precisão geral.
- Essa abordagem pressupõe que as relações capturadas pelo modelo permanecem estáveis durante todo o período de previsão, o que nem sempre é verdade.
Previsão multietapa utilizando modelos com múltiplas saídas
Os modelos com múltiplas saídas são projetados para prever vários valores simultaneamente. Dessa forma, podemos fazer com que o modelo preveja múltiplos períodos futuros de uma só vez. Em vez de treinar modelos individuais para cada horizonte de previsão ou usar um único modelo de maneira recursiva, essa abordagem gera múltiplas saídas, cada uma correspondente a um período futuro.
Nos modelos com múltiplas saídas, o modelo é treinado para criar um vetor de previsões em um único processamento. Isso significa que ele aprende a compreender diretamente as relações e dependências entre diferentes períodos futuros. Essa abordagem pode ser implementada com sucesso utilizando redes neurais, pois elas têm a capacidade de gerar múltiplas saídas simultaneamente.
Preparação do conjunto de dados para o modelo de rede neural com múltiplas saídas
Precisamos preparar as variáveis-alvo para todos os períodos futuros que a rede neural treinada deverá ser capaz de prever.
Código Python
# Create target variables for multiple future steps def create_target(df, future_steps=10): target = pd.concat([df['Close'].shift(-i) for i in range(1, future_steps + 1)], axis=1) # using close prices for the next i bar target.columns = [f'target_close_{i}' for i in range(1, future_steps + 1)] # naming the columns return target # Combine features and targets new_df = pd.DataFrame({ 'Open': df['Open'], 'High': df['High'], 'Low': df['Low'], 'Close': df['Close'] }) future_steps = 5 target_columns = create_target(new_df, future_steps).dropna() combined_df = pd.concat([new_df, target_columns], axis=1) #concatenating the new pandas dataframe with the target columns combined_df = combined_df.dropna() #droping rows with NaN values caused by shifting values target_cols_names = [f'target_close_{i}' for i in range(1, future_steps + 1)] X = combined_df.drop(columns=target_cols_names).values #dropping all target columns from the x array y = combined_df[target_cols_names].values # creating the target variables print(f"x={X.shape} y={y.shape}") combined_df.head(10)
Resultados
x=(995, 4) y=(995, 5)
Treinamento e teste da rede neural com múltiplas saídas
Começamos definindo um modelo sequencial de rede neural.
Código Python
# Defining the neural network model model = Sequential([ Input(shape=(X.shape[1],)), Dense(units = 256, activation='relu'), Dense(units = 128, activation='relu'), Dense(units = future_steps) ]) # Compiling the model adam = Adam(learning_rate=0.01) model.compile(optimizer=adam, loss='mse') # Mmodel summary model.summary()
Resultados
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ dense (Dense) │ (None, 256) │ 1,280 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_1 (Dense) │ (None, 128) │ 32,896 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_2 (Dense) │ (None, 5) │ 645 │ └─────────────────────────────────┴────────────────────────┴───────────────┘ Total params: 34,821 (136.02 KB) Trainable params: 34,821 (136.02 KB) Non-trainable params: 0 (0.00 B)
Depois, dividimos os dados em conjuntos de treinamento e teste — esse passo difere da previsão multietapa recursiva. Dessa vez, dividimos os dados após a randomização usando a semente aleatória 42, para que o modelo não identifique padrões sequenciais, pois assumimos que a rede neural funcionará melhor ao compreender relações não lineares nesses dados.
Por fim, treinamos o modelo usando o conjunto de treinamento.
# Split the data into training and test sets X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7, random_state=42) scaler = MinMaxScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test) # Training the model early_stopping = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True) # stop training when 5 epochs doesn't improve history = model.fit(X_train, y_train, epochs=20, validation_split=0.2, batch_size=32, callbacks=[early_stopping])
Depois, testamos o modelo no conjunto de teste.
# Testing the Model test_pred = model.predict(X_test) # Make predictions on the test set # Plotting the actual vs predicted values for each future step plt.figure(figsize=(7.5, 10)) for i in range(future_steps): plt.subplot((future_steps + 1) // 2, 2, i + 1) # subplots grid plt.plot(y_test[:, i], label='Actual Values') plt.plot(test_pred[:, i], label='Predicted Values') plt.xlabel('Samples') plt.ylabel(f'Close Price +{i+1}') plt.title(f'Actual vs Predicted Values (Step {i+1})') plt.legend() plt.tight_layout() plt.show() # Evaluating the model for each future step for i in range(future_steps): accuracy = r2_score(y_test[:, i], test_pred[:, i]) print(f"Step {i+1} - R^2 Score: {accuracy}")
Abaixo está o resultado.
Step 1 - R^2 Score: 0.8664635514027637 Step 2 - R^2 Score: 0.9375671150885528 Step 3 - R^2 Score: 0.9040736780305894 Step 4 - R^2 Score: 0.8491904738263638 Step 5 - R^2 Score: 0.8458062142647863
A rede neural apresentou resultados impressionantes na resolução dessa tarefa de regressão. O código abaixo permite obter previsões em Python.
# Predicting multiple future values current_input = X_test[0].reshape(1, -1) # use the first row of the test set, reshape the data also predicted_values = model.predict(current_input)[0] # adding[0] ensures we get a 1D array instead of 2D print("Predicted Future Values:") print(predicted_values)
Resultados
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 21ms/step Predicted Future Values: [1.0892788 1.0895394 1.0892794 1.0883198 1.0884078]
Em seguida, podemos salvar esse modelo no formato ONNX e armazenar os arquivos de escalonamento em arquivos binários.
import tf2onnx # Convert the Keras model to ONNX spec = (tf.TensorSpec((None, X_train.shape[1]), tf.float16, name="input"),) model.output_names=['output'] onnx_model, _ = tf2onnx.convert.from_keras(model, input_signature=spec, opset=13) # Save the ONNX model to a file with open("NN.EURUSD.h1.onnx", "wb") as f: f.write(onnx_model.SerializeToString()) # Save the used scaler parameters to binary files scaler.data_min_.tofile("NN.EURUSD.h1.min_max.min.bin") scaler.data_max_.tofile("NN.EURUSD.h1.min_max.max.bin")
Por fim, podemos usar o modelo salvo e seus parâmetros de escalonamento de dados no MQL5.
Obtenção de previsões multietapa da rede neural no MQL5
Começamos adicionando o modelo e os parâmetros de escalonamento Min-Max ao EA.
#resource "\\Files\\NN.EURUSD.h1.onnx" as uchar onnx_model[]; //rnn model in onnx format #resource "\\Files\\NN.EURUSD.h1.min_max.max.bin" as double min_max_max[]; #resource "\\Files\\NN.EURUSD.h1.min_max.min.bin" as double min_max_min[];
Depois, importamos a classe da rede neural de regressão ONNX e o manipulador da biblioteca de escalonamento MinMax.
#include <MALE5\Neural Networks\Regressor Neural Nets.mqh> #include <MALE5\preprocessing.mqh> CNeuralNets nn; MinMaxScaler *scaler;
Em seguida, inicializamos o modelo e o escalonador, e obtemos as previsões finais do modelo.
MqlRates rates[]; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- if (!nn.Init(onnx_model)) return INIT_FAILED; scaler = new MinMaxScaler(min_max_min, min_max_max); //Initializing the scaler, populating it with trained values //--- ArraySetAsSeries(rates, true); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- if (CheckPointer(scaler)!=POINTER_INVALID) delete (scaler); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- CopyRates(Symbol(), PERIOD_H1, 1, 1, rates); vector input_x = {rates[0].open, rates[0].high, rates[0].low, rates[0].close}; input_x = scaler.transform(input_x); // We normalize the input data vector preds = nn.predict(input_x); Print("predictions = ",preds); }
Resultados
2024.07.31 19:13:20.785 Multi-step forecasting using Multi-outputs model (EURUSD,H4) predictions = [1.080284595489502,1.082370758056641,1.083482265472412,1.081504583358765,1.079929828643799]
Também adicionei linhas de tendência ao gráfico para marcar todas as previsões futuras da rede neural.
void OnTick() { //--- CopyRates(Symbol(), PERIOD_H1, 1, 1, rates); vector input_x = {rates[0].open, rates[0].high, rates[0].low, rates[0].close}; if (NewBar()) { input_x = scaler.transform(input_x); // We normalize the input data vector preds = nn.predict(input_x); for (int i=0; i<(int)preds.Size(); i++) { //--- ObjectDelete(0, "step"+string(i+1)+"-prediction"); //delete an object if it exists TrendCreate("step"+string(i+1)+"-prediction",rates[0].time, preds[i], rates[0].time+(5*60*60), preds[i], clrBlack); //draw a line starting from the previous candle to 5 hours forward } } }
Dessa vez, obtivemos linhas de previsão de qualidade superior às geradas pelo modelo de regressão linear recursiva.
Resumo da previsão multietapa utilizando modelos com múltiplas saídas
Vantagens- Ao prever vários períodos simultaneamente, o modelo pode capturar relações e dependências entre os períodos futuros.
- Apenas um único modelo é necessário, o que simplifica a implementação e a manutenção.
- O modelo aprende a fazer previsões sequenciais ao longo de todo o horizonte de previsão.
Desvantagens
- Treinar um modelo para gerar múltiplos valores futuros pode ser mais complexo e exigir uma arquitetura mais avançada, especialmente no caso de redes neurais.
- Dependendo da complexidade do modelo, o treinamento e a inferência podem demandar recursos computacionais adicionais.
- Existe o risco de overfitting, especialmente se o horizonte de previsão for muito amplo, tornando o modelo excessivamente especializado nos dados de treinamento.
Uso da previsão multietapa em estratégias de trading
A previsão multietapa pode melhorar significativamente diversas estratégias de trading, pois permite ajustes dinâmicos com base nos movimentos de mercado previstos. Em estratégias de grid trading, as previsões multietapa permitem que as ordens não sejam fixadas em pontos específicos, mas sim ajustadas dinamicamente conforme as mudanças esperadas nos preços, aumentando a capacidade de resposta da estratégia às condições de mercado.
Elas também podem ser úteis em estratégias de hedge, pois essas previsões ajudam a determinar o momento ideal para abrir ou fechar posições, protegendo contra perdas potenciais. Por exemplo, abrir posições vendidas ou comprar opções de venda (put) caso seja prevista uma tendência de baixa. Além disso, na identificação de tendências, a antecipação das futuras direções do mercado permite aos traders ajustarem suas estratégias, seja favorecendo posições curtas ou encerrando posições longas para evitar perdas.
Por fim, no trading de alta frequência (HFT), previsões rápidas e multietapa podem guiar algoritmos que buscam lucrar com os movimentos de preços de curto prazo. Elas podem ajudar a reagir mais rapidamente às mudanças esperadas nos preços nos próximos segundos ou minutos.
Considerações finais
Na análise financeira e no trading de Forex, é extremamente útil poder prever múltiplos valores futuros. Neste artigo, apresentamos diferentes abordagens para realizar tais previsões. No(s) próximo(s) artigo(s), abordaremos a vetorização autorregressiva, um método que também pode ser utilizado para prever múltiplos valores.
Tudo de bom para vocês.
O desenvolvimento deste modelo de aprendizado de máquina, assim como muitos outros desta série de artigos, pode ser acompanhado no meu repositório do GitHub.
Tabela de anexos
Nome do arquivo | Tipo de arquivo | Descrição e uso |
---|---|---|
Direct Muilti step Forecasting.mq5 Multi-step forecasting using multi-outputs model.mq5 Recursive-Multi step forecasting.mq5 | EAs | O EA utiliza vários modelos LightGBM para previsão multietapa. EA baseado em um modelo de rede neural que prevê múltiplos passos utilizando uma estrutura de múltiplas saídas. Neste EA, a regressão linear prevê iterativamente os futuros períodos de tempo. |
LightGBM.mqh | Arquivo de biblioteca MQL5 | Contém o código para carregar o modelo LightGBM no formato ONNX e utilizá-lo para previsão. |
Linear Regression.mqh | Arquivo de biblioteca MQL5 | Contém o código para carregar o modelo de regressão linear no formato ONNX e utilizá-lo para previsão. |
preprocessing.mqh | Arquivo de biblioteca MQL5 | Este arquivo contém o escalonador MinMax utilizado para normalizar os dados de entrada. |
Regressor Neural Nets.mqh | Arquivo de biblioteca MQL5 | Contém o código para carregar e implantar um modelo de rede neural no formato ONNX no MQL5. |
lightgbm.EURUSD.h1.pred_close.step.1.onnx lightgbm.EURUSD.h1.pred_close.step.2.onnx lightgbm.EURUSD.h1.pred_close.step.3.onnx lightgbm.EURUSD.h1.pred_close.step.4.onnx lightgbm.EURUSD.h1.pred_close.step.5.onnx Lr.EURUSD.h1.pred_close.onnx NN.EURUSD.h1.onnx | Modelos de IA no formato ONNX | Modelos LightGBM para previsão do próximo valor futuro. Modelo simples de regressão linear no formato ONNX. Rede neural com propagação direta no formato ONNX. |
NN.EURUSD.h1.min_max.max.bin NN.EURUSD.h1.min_max.min.bin | Arquivos binários | Contêm, respectivamente, os valores máximos e mínimos do escalonador MinMax. |
predicting-multiple-future-tutorials.ipynb | Jupyter Notebook | Todo o código Python apresentado neste artigo pode ser encontrado neste arquivo. |
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15465
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.





- 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