138 lines
4.5 KiB
Python
138 lines
4.5 KiB
Python
# Copyright 2023, MetaQuotes Ltd.
| |||
# https://www.mql5.com
| |||
| |||
from datetime import datetime
| |||
| |||
import tensorflow as tf
| |||
import MetaTrader5 as mt5
| |||
import numpy as np
| |||
import pandas as pd
| |||
import tf2onnx
| |||
from sklearn.model_selection import train_test_split
| |||
from tqdm import tqdm
| |||
from sys import argv
| |||
# --- for Sequential ---{
| |||
from tensorflow.keras.models import Sequential
| |||
from tensorflow.keras.layers import LSTM, Dense, BatchNormalization, Dropout
| |||
from tensorflow.keras.regularizers import l2
| |||
# --- for Sequential ---}
| |||
| |||
if not mt5.initialize():
| |||
print("initialize() failed, error code =",mt5.last_error())
| |||
quit()
| |||
| |||
#terminal_info=mt5.terminal_info()
| |||
#file_path=terminal_info.data_path+"\\MQL5\\Files\\"
| |||
| |||
# you code here
| |||
#
| |||
| |||
# we will save generated onnx-file near the our script
| |||
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)
| |||
| |||
start_date = datetime(2013, 1, 1, 0)
| |||
end_date = datetime(2023, 8, 8, 0)
| |||
| |||
eurusd_rates = mt5.copy_rates_range("EURUSD", mt5.TIMEFRAME_H1, start_date, end_date)
| |||
df = pd.DataFrame(eurusd_rates)
| |||
| |||
| |||
def collect_dataset(df: pd.DataFrame, history_size: int):
| |||
"""
| |||
Collect dataset for the following regression problem:
| |||
- input: history_size consecutive H1 bars;
| |||
- output: close price for the next bar.
| |||
| |||
:param df: H1 bars for a range of dates
| |||
:param history_size: how many bars should be considered for making a prediction
| |||
:return: features and labels
| |||
"""
| |||
n = len(df)
| |||
xs = []
| |||
ys = []
| |||
for i in tqdm(range(n - history_size)):
| |||
w = df.iloc[i: i + history_size + 1]
| |||
| |||
start_ts = w.iloc[-1].time
| |||
end_ts = w.iloc[0].time
| |||
hours_elapsed = (start_ts - end_ts) // 3600
| |||
if hours_elapsed > history_size:
| |||
# skip non-consecutive H1 bars
| |||
continue
| |||
| |||
x = w[['open', 'high', 'low', 'close']].iloc[:-1].values
| |||
# --- y ---{
| |||
# y = w.iloc[-1]['close']
| |||
# ---
| |||
y = (w.iloc[-1]['high'] - w.iloc[-1]['open']) - (w.iloc[-1]['open'] - w.iloc[-1]['low']) # Updated line
| |||
# ---
| |||
# y = (w.iloc[-1]['high'] - w.iloc[-2]['high']) + (w.iloc[-1]['low'] - w.iloc[-2]['low']) # Updated line
| |||
# --- y ---}
| |||
xs.append(x)
| |||
ys.append(y)
| |||
| |||
X = np.array(xs)
| |||
y = np.array(ys)
| |||
return X, y
| |||
| |||
| |||
X, y = collect_dataset(df, history_size=10)
| |||
| |||
m = X.mean(axis=1, keepdims=True)
| |||
s = X.std(axis=1, keepdims=True)
| |||
X_norm = (X - m) / s
| |||
# --- y_norm ---{
| |||
y_norm = (y - ((m[:, 0, 1] - m[:, 0, 0]) - (m[:, 0, 0] - m[:, 0, 2]))) / ((s[:, 0, 1] - s[:, 0, 0]) - (s[:, 0, 0] - s[:, 0, 2]))
| |||
# ---
| |||
# y_mean = y.mean()
| |||
# y_std = y.std()
| |||
# y_norm = (y - y_mean) / y_std
| |||
# ---
| |||
# y_norm = y
| |||
# --- y_norm ---}
| |||
| |||
X_train, X_test, y_train, y_test = train_test_split(X_norm, y_norm, test_size=0.2, random_state=0)
| |||
| |||
# --- Sequential ---{
| |||
model = tf.keras.Sequential([
| |||
tf.keras.layers.LSTM(64, input_shape=(10, 4)),
| |||
tf.keras.layers.BatchNormalization(),
| |||
tf.keras.layers.Dropout(0.1),
| |||
tf.keras.layers.Dense(32, activation='relu'),
| |||
tf.keras.layers.BatchNormalization(),
| |||
tf.keras.layers.Dropout(0.1),
| |||
tf.keras.layers.Dense(32, activation='relu'),
| |||
tf.keras.layers.Dense(1)
| |||
])
| |||
# ---
| |||
# model = tf.keras.Sequential([
| |||
# tf.keras.layers.LSTM(128, input_shape=(10, 4), return_sequences=True), # Increased LSTM units for more complexity
| |||
# tf.keras.layers.BatchNormalization(),
| |||
# tf.keras.layers.Dropout(0.2), # Slightly increased dropout for regularization
| |||
# tf.keras.layers.LSTM(64), # Add another LSTM layer
| |||
# tf.keras.layers.BatchNormalization(),
| |||
# tf.keras.layers.Dropout(0.2),
| |||
# tf.keras.layers.Dense(64, activation='relu', kernel_regularizer=l2(0.001)), # Added L2 regularization
| |||
# tf.keras.layers.BatchNormalization(),
| |||
# tf.keras.layers.Dropout(0.2),
| |||
# tf.keras.layers.Dense(1)
| |||
# ])
| |||
# --- Sequential ---}
| |||
| |||
model.compile(optimizer='adam', loss='mse', metrics=['mae'])
| |||
| |||
lr_reduction = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, min_delta=1e-6)
| |||
history = model.fit(X_train, y_train, epochs=32, verbose=2, validation_split=0.15, callbacks=[lr_reduction])
| |||
| |||
test_loss, test_mae = model.evaluate(X_test, y_test)
| |||
print(f"test_loss={test_loss:.3f}")
| |||
print(f"test_mae={test_mae:.3f}")
| |||
| |||
output_path = data_path+"model2.onnx"
| |||
onnx_model = tf2onnx.convert.from_keras(model, output_path=output_path)
| |||
print(f"saved model to {output_path}")
| |||
| |||
mt5.shutdown()
|