TensorFlow利用LSTM训练MQL5的数据

Title TensorFlow利用LSTM训练MQL5的数据
Framework TensorFlow
User wy8817399@vip.qq.com
Id 63
Created 3/6/26, 7:44 PM
Modified 3/6/26, 7:44 PM
Published Yes
Content

1、Tensorflow在windows上2.10版本过后就不支持GPU训练了

2、Python关于MT5的库也只支持windows。

3、综上所述,本篇笔记推荐的环境是win10的系统、4090以下的显卡。但很明显这样终将被淘汰。目前已经转PyTorch。但MT5对PyTorch转的onnx模型的GPU运行支持度还不够完美,期待MT5更新。

# python libraries
import MetaTrader5 as mt5
import tensorflow as tf
import numpy as np
import pandas as pd
import tf2onnx

# input parameters
inp_model_name = "model.eurusd.H1.120_old.onnx"
inp_history_size = 120

if not mt5.initialize():
	print("initialize() failed, error code =", mt5.last_error())
	quit()

# we will save generated onnx-file near our script to use as resource
from sys import argv

data_path = argv[0]
last_index = data_path.rfind("\\") + 1
data_path = data_path[0:last_index]
print("data path to save onnx model", data_path)

# set start and end dates for history data
from datetime import timedelta, datetime

# end_date = datetime.now()
end_date = datetime(2023, 1, 1, 0)
start_date = end_date - timedelta(days=inp_history_size)

# print start and end dates
print("data start date =", start_date)
print("data end date =", end_date)

# get rates
eurusd_rates = mt5.copy_rates_range("EURUSD", mt5.TIMEFRAME_H1, start_date, end_date)

# create dataframe
df = pd.DataFrame(eurusd_rates)

# get close prices only
data = df.filter(['close']).values

# scale data
from sklearn.preprocessing import MinMaxScaler

# MinMaxScaler:一个用于数据归一化的工具,将数据的值缩放到指定的范围,这里是[0, 1]。
# fit_transform():将scaler适配到数据并对其进行变换。
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(data)

# training_size:定义训练集的大小,占总数据的80%。
# 将数据分为训练集(train_data_initial)和测试集(test_data_initial)。
# training size is 80% of the data
training_size = int(len(scaled_data) * 0.80)
print("Training_size:", training_size)
train_data_initial = scaled_data[0:training_size, :]
test_data_initial = scaled_data[training_size:, :1]


# split_sequence():将时间序列数据分割成输入(X)和输出(y)序列。n_steps是输入序列的长度,输出是下一个时间点的预测值。
# 例如,输入的时间步长为n_steps,输出为时间步长后的下一个值。
def split_sequence(sequence, n_steps):
	X, y = list(), list()
	for i in range(len(sequence)):
		# find the end of this pattern
		end_ix = i + n_steps
		# check if we are beyond the sequence
		if end_ix > len(sequence) - 1:
			break
		# gather input and output parts of the pattern
		seq_x, seq_y = sequence[i:end_ix], sequence[end_ix]
		X.append(seq_x)
		y.append(seq_y)
	return np.array(X), np.array(y)


# 拆分训练集和测试集数据
# 将训练集和测试集数据传入 split_sequence 函数,将数据转换为时间序列输入输出对。
time_step = inp_history_size
x_train, y_train = split_sequence(train_data_initial, time_step)
x_test, y_test = split_sequence(test_data_initial, time_step)

# 调整数据形状以适应LSTM
# LSTM模型要求输入的数据形状为 [样本数, 时间步长, 特征数],这里每个数据点只有一个特征(即收盘价),因此将输入数据的形状调整为 (样本数, 时间步长, 1)。
x_train = x_train.reshape(x_train.shape[0], x_train.shape[1], 1)
x_test = x_test.reshape(x_test.shape[0], x_test.shape[1], 1)

# define model
from keras.models import Sequential
from keras.layers import Dense, Activation, Conv1D, MaxPooling1D, Dropout, Flatten, LSTM
from keras.metrics import RootMeanSquaredError as rmse

# Sequential:初始化一个线性堆叠的模型。
# Conv1D:一维卷积层,用于提取时间序列中的局部特征。
# MaxPooling1D:最大池化层,用于减少数据的维度。
# LSTM:长短期记忆层,擅长处理时间序列数据。
# Dropout:丢弃层,防止过拟合。
# Dense:全连接层,用于输出预测值。
# compile:编译模型,指定优化器、损失函数和评估指标(均方误差和RMSE)。
model = Sequential()
model.add(Conv1D(filters=256, kernel_size=2, activation='relu', padding='same', input_shape=(inp_history_size, 1)))
model.add(MaxPooling1D(pool_size=2))
model.add(LSTM(100, return_sequences=True))
model.add(Dropout(0.3))
model.add(LSTM(100, return_sequences=False))
model.add(Dropout(0.3))
model.add(Dense(units=1, activation='sigmoid'))
model.compile(optimizer='adam', loss='mse', metrics=[rmse()])


# model.fit():训练模型,使用训练数据训练300个周期,并在每个周期后使用验证数据进行验证。
# epochs=300:训练300个周期。
# batch_size=32:每次梯度更新时使用32个样本。
# verbose=2:显示每个周期的训练进度。
history = model.fit(x_train, y_train, epochs=300, validation_data=(x_test, y_test), batch_size=32, verbose=2)

# 评估模型在训练集和测试集上的表现
# 使用训练集和测试集对模型进行评估,输出损失值和根均方误差(RMSE)
train_loss, train_rmse = model.evaluate(x_train, y_train, batch_size=32)
print(f"train_loss={train_loss:.3f}")
print(f"train_rmse={train_rmse:.3f}")

test_loss, test_rmse = model.evaluate(x_test, y_test, batch_size=32)
print(f"test_loss={test_loss:.3f}")
print(f"test_rmse={test_rmse:.3f}")

# save model to ONNX
output_path = data_path + inp_model_name
onnx_model = tf2onnx.convert.from_keras(model, output_path=output_path)
print(f"saved model to {output_path}")

# finish
mt5.shutdown()