Машинное обучение и Data Science (Часть 27): Сверточные нейросети (CNN) в торговых роботах для MetaTrader 5
Использование операции пулинга в сверточных нейронных сетях является большой ошибкой, а тот факт, что она так хорошо работает, — настоящее бедствие.
Джеффри Хинтон
Содержание
- Что такое сверточные нейронные сети (CNNS)?
- Сверточные слои
- Функции активации
- Слои пулинга
- Полносвязные слои
- Слои Dropout - Можно ли использовать сверточные нейросети (CNN) для программ финансового анализа и торговли?
- Создание сверточной нейросети (CNN) на Python
- Создание торгового робота на основе сверточной нейросети (CNN)
- Заключение
Для понимания статьи необходимо базовое представление о языке Python, искусственных нейросетях, машинном обучении и ONNX в MQL5.
Что такое сверточные нейронные сети (CNNS)?
Сверточные нейронные сети (CNN) — это класс алгоритмов глубокого обучения, специально разработанных для обработки структурированных данных в виде сетки, таких как изображения, аудиоспектрограммы и данные временных рядов. Они особенно хорошо подходят для задач с визуальными данными, поскольку могут автоматически и адаптивно изучать пространственные иерархии признаков на основе входных данных.
Сверточные нейронные сети представляют собой расширенную версия искусственных нейронных сетей. Они в основном используются для извлечения признаков из набора данных с сеточной структурой. Например, это могут визуальные наборы данных, такие как изображения или видео, где используются паттерны.
Ключевые компоненты сверточных нейросетей: сверточные слои, функции активации, слои пулинга, полносвязанные слои и Dropout-слои. Чтобы лучше разобраться в сверточных нейронных сетях, давайте разберем каждый компонент и выясним, в чем суть.
Сверточные слои
Это основные строительные блоки сверточных нейросетей, именно в них происходит большая часть вычислений. Задача сверточных слоев — обнаруживать локальные закономерности во входных данных, таких как края на изображениях. Для этого используются фильтры (или ядра), которые скользят по входным данным для создания карт признаков.
Сверточный слой — это скрытый слой, содержащий несколько сверточных единиц, используется для извлечения признаков.
from tensorflow.keras.layers import Conv1D
model = Sequential()
model.add(Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(window_size, X_train.shape[2])))
Фильтры/Ядра
Фильтры (или ядра) представляют собой небольшие обучаемые квадратные матрицы (обычно размером 3x3, 5x5 и т. д.), которые скользят по входным данным для поиска локальных закономерностей.
Как они работают
Они проходят по входным данным, а затем выполняют поэлементное умножение между значениями фильтра и входными значениями в текущем рецептивном поле фильтра, после чего суммируют результаты. Эта операция называется сверткой.
В процессе обучения сеть изучает оптимальные значения фильтров. На ранних уровнях фильтры обычно обучаются обнаруживать простые особенности, такие как края и текстуры. На более глубоких уровнях фильтры могут обнаруживать более сложные паттерны, например, формы и объекты.
Рассмотрим простой фильтр размером 3x3 и входное изображение размером 5x5 пикселей. Фильтр скользит по изображению, вычисляя операцию свертки для создания карты признаков.
Шаг
Также в сверточном слое используется шаг. Это размер шага, на который фильтр перемещается по входным данным. Параметр определяет, насколько сильно смещается фильтр на каждом этапе процесса свертки.
Как они работают
При шаге 1 фильтр перемещается на одну единицу за раз. Так мы получаем сильно перекрывающуюся и подробную карту объектов. Это позволяет получить более крупную выходную карту признаков.
При шаге 2 или более, получается менее подробной, но и меньшая по размеру выходная карта объектов. Это эффективно уменьшает пространственные размеры выхода и выполняет даунсэмплинг входных данных.
Например, если у вас есть фильтр размером 3x3 и входное изображение 5x5 с шагом 1, фильтр будет перемещаться на один пиксель за раз, создавая выходную карту признаков размером 3x3. При шаге 2 фильтр будет перемещаться на два пикселя за раз, создавая выходную карту признаков размером 2x2.
Дополнение (Padding)
Дополнение заключается в добавлении дополнительных пикселей (обычно нулей) вокруг границы входных данных. Это позволяет фильтру корректно размещаться и контролировать пространственные размеры выходной карты признаков.
Типы дополнения
Согласно библиотеки Keras, существуют три типа дополнения (учитывается регистр): (с учетом регистра)
- valid — дополнение не применяется.
- same — входные данные дополняются таким образом, чтобы размер выхода совпадал с размером входа при шаге 1.
- causal — используется для временных данных, чтобы выход на временном шаге 𝑡 не зависел от будущих входов.
Дополнение помогает сохранить пространственные размеры входных данных. Без дополнения выходная карта признаков уменьшается с каждым сверточным слоем, что может привести к потере важной информации на краях изображения.
Благодаря дополнению сеть может эффективно изучать особенности на границах и сохранять пространственное разрешение входных данных.
Например, рассмотрим фильтр 3x3 и входное изображение 5x5. При valid-дополнении (без дополнения) выходная карта признаков будет размером 3x3. При same к границе входных данных можно добавить рамку из нулей, увеличив размеры до 7x7. В этом случае выходная карта признаков будет 5x5, сохраняя размеры входного изображения.
Ниже представлен Python-код для сверточного слоя.
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv1D model = Sequential() model.add(Conv1D(filters=64, kernel_size=3, activation='relu', strides=2, padding='causal', input_shape=(window_size, X_train.shape[2]) ) )
Функции активации
Функции активации мы уже разбирали ранее в статье Разбираем нейронные сети. Это математическая функция, которая принимает на вход значение и преобразует его в выходное.
Функции активации применяются к каждому элементу данных, чтобы ввести в модель нелинейность. Наиболее часто используемые функции активации в сверточных нейронных сетях (CNN) включают ReLU (Rectified Linear Unit), Sigmoid и TanH.
Слои подвыборки (Pooling Layers)
Также известные как слои понижения разрешения, эти слои играют ключевую роль в сетях CNN, так как они уменьшают пространственные размеры входных данных (ширину и высоту), сохраняя при этом наиболее важную информацию.
Как они работают
Сначала входные данные делятся на пересекающиеся области или окна, после чего на каждую область применяется функция агрегации, такая как Max Pooling или Average Pooling, чтобы получить одно значение.
Max pooling берет максимальное значение из набора значений внутри области фильтра. Это позволяет уменьшить пространственные размеры данных, снижая вычислительную нагрузку и количество параметров.
Python
from tensorflow.keras.layers import Conv1D, MaxPooling1D model = Sequential() model.add(Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(window_size, X_train.shape[2]))) model.add(MaxPooling1D(pool_size=2))
MaxPooling1D(pool_size=2)
Этот слой берет максимальное значение из каждого двухэлементного окна.
Average pooling берет среднее значение из набора значений внутри области фильтра. Используется реже, чем Max pooling.
Python
from tensorflow.keras.layers import Conv1D, AveragePooling1D model = Sequential() model.add(Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(window_size, X_train.shape[2]))) model.add(AveragePooling1D(pool_size=2))
AveragePooling1D(pool_size=2)
Этот слой берет среднее значение из каждого двухэлементного окна.
Для чего используется 1D-сверточный слой?
Для сверточных нейронных сетей (CNN) существуют слои Conv1D, Conv2D и Conv3D. 1D-сверточный слой (Conv1D) предназначен для обработки одномерных данных, таких как последовательности или временные ряды. Это делает его подходящим для задач, связанных с временными рядами или последовательными данными. Другие типы сверточных слоев (Conv2D и Conv3D) слишком сложны для такого рода задач.
Полносвязные слои
Нейроны в полносвязном слое соединены со всеми активациями предыдущего слоя. Такие слои обычно используются на завершающих этапах нейронной сети для выполнения задач классификации или регрессии, основываясь на признаках, извлеченных сверточными и пулинг-слоями.
from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense, Dropout
model = Sequential()
model.add(Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(window_size, X_train.shape[2])))
model.add(MaxPooling1D(pool_size=2))
model.add(Flatten())
model.add(Dense(100, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(units=len(np.unique(y)), activation='sigmoid')) # For binary classification (e.g., buy/sell signal)
model.summary()
Слой Flatten преобразует карту признаков (например, из слоя подвыборки) в одномерный вектор, чтобы его можно было передать в полносвязные (dense) слои.
Полносвязные слои Dense представляют собой слои, где каждый нейрон соединен со всеми активациями предыдущего слоя. Они используются для принятия окончательных решений на основе признаков, извлеченных сверточными и пулинг-слоями. Полносвязные слои являются основным компонентом традиционных искусственных нейронных сетей (ANN).
Слои Dropout
Слой Dropout выполняет роль маски, отключая часть нейронов и предотвращая их вклад в следующий слой, при этом все остальные нейроны продолжают работать. Если Dropout применяется ко входному вектору, часть его признаков исключается. Если он применяется к скрытому слою, то исключаются некоторые скрытые нейроны.
Dropout-слои играют ключевую роль в предотвращении переобучения модели на тренировочных данных. Без них первые обучающие выборки могут оказывать чрезмерно сильное влияние на процесс обучения, что мешает модели изучать признаки, характерные для данных из последующих выборок или батчей.
from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense, Dropout
model = Sequential()
model.add(Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(window_size, X_train.shape[2])))
model.add(MaxPooling1D(pool_size=2))
model.add(Flatten())
model.add(Dense(100, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(units=len(np.unique(y)), activation='sigmoid')) # For binary classification (e.g., buy/sell signal)
model.summary()
Можно ли использовать сверточные нейросети (CNN) для программ финансового анализа и торговли?
Сверточные нейросети чаще всего применяются для обработки изображений и видео, поскольку они изначально были разработаны для таких задач. Если посмотреть на все описания выше, все они касаются использования сверточных нейронных сетей при работе с классификациями изображений и т.п.
Однако использование таких сетей для анализа табличных данных, таких как финансовая информация, может показаться необычным по сравнению с другими типами нейронных сетей, такими как полносвязные сети (Feed Forward Neural Networks, FFNN), рекуррентные сети (RNN), долгосрочная кратковременная память (LSTM) или модули с управляемым рекуррентным доступом (GRU). Тем не менее, существуют веские основания и преимущества применения сетей CNN и в данном контексте.
1. CNN хорошо извлекают локальные паттерны из данных
3. Устойчивость к шуму и избыточным данным
4. Эффективная работа с многомерными временными рядами
Итак, мы убедились, что сверточные сети вполне подходят для использования в торговых приложениях. Теперь давайте создадим такую модель, обучим ее, а затем посмотрим, как интегрировать сеть в советника для MetaTrader 5.
Создание сверточной нейросети (CNN) на Python
Этот процесс включает несколько шагов:
- Сбор данных
- Подготовка данных для модели CNN
- Обучение модели CNN
- Сохранение модели CNN в формате ONNX
1. Сбор данных
Для создания модели мы будем использовать данные временных рядов, которые были рассмотрены в предыдущих статьях.
Теперь мы знаем, что сверточные нейросети отлично справляются с обнаружением паттернов в данных высокой размерности. Далее мы можем упростить модель, выбрав только те признаки, которые, как я полагаю, содержат множество таких паттернов, которые CNN сможет эффективно выявить.
Python code
open_price = df['TARGET_OPEN'] close_price = df['TARGET_CLOSE'] # making the target variable target_var = [] for i in range(len(open_price)): if close_price[i] > open_price[i]: # if the price closed above where it opened target_var.append(1) # bullish signal else: target_var.append(0) # bearish signal new_df = pd.DataFrame({ 'OPEN': df['OPEN'], 'HIGH': df['HIGH'], 'LOW': df['LOW'], 'CLOSE': df['CLOSE'], 'TARGET_VAR': target_var }) print(new_df.shape)
После подготовки целевой переменной на основе TARGET_OPEN и TARGET_CLOSE (соответственно значения открытия и закрытия, смещенные на один бар вперед), мы создали упрощенный набор данных под названием new_df. Этот набор включает в себя только 4 независимые переменные (OPEN, HIGH, LOW) и одну зависимую переменную под названием TARGET_VAR.
2. Подготовка данных для модели CNN
Прежде всего, необходимо предварительно обработать входные данные, изменив их форму и разбив на окна. Это особенно важно при работе с табличными данными в сверточной сети, и вот почему.
Торговые данные носят последовательный характер, и паттерны в них чаще всего проявляются в течение нескольких временных шагов, а не в конкретный момент времени. Создавая перекрывающиеся окна данных, мы можем охватывать временные зависимости и обеспечивать модель CNN контекстной информацией.
Кроме того, сверточная сеть ожидает входные данные определенной формы. Для одномерных сверточных слоев входные данные, как правило, должны быть представлены в формате (количество окон, размер окна, количество признаков). Эта форма напоминает ту, которую мы использовали при анализе временных рядов с использованием рекуррентных нейронных сетей в предыдущей статье. Предстоящий этап предварительной обработки данных обеспечит приведение данных к этому формату, делая их подходящими для подачи в модель CNN.
# Example data preprocessing function def preprocess_data(df, window_size): X, y = [], [] for i in range(len(df) - window_size): X.append(df.iloc[i:i+window_size, :-1].values) y.append(df.iloc[i+window_size, -1]) return np.array(X), np.array(y) window_size = 10 X, y = preprocess_data(new_df, window_size) print(f"x_shape = {X.shape}\ny_shape = {y.shape}")
Результаты
x_shape = (990, 10, 4) y_shape = (990,)
Поскольку наши данные собирались ежедневно, размер окна 10 указывает на то, что мы будем обучать модель CNN для понимания закономерностей в течение 10 дней.
Затем нам необходимо разделить данные на обучающую и тестовую выборки.
# Split data into training and testing sets X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False) # Standardize the data scaler = StandardScaler() X_train = scaler.fit_transform(X_train.reshape(-1, X_train.shape[-1])).reshape(X_train.shape) X_test = scaler.transform(X_test.reshape(-1, X_test.shape[-1])).reshape(X_test.shape) print(f"x_train\n{X_train.shape}\nx_test\n{X_test.shape}\n\ny_train {y_train.shape} y_test {y_test.shape}")
Результаты
x_train (792, 10, 4) x_test (198, 10, 4) y_train (792,) y_test (198,)
Наконец, для задачи классификации необходимо применить one-hot-кодирование к целевой переменной
from tensorflow.keras.utils import to_categorical
y_train_encoded = to_categorical(y_train)
y_test_encoded = to_categorical(y_test)
print(f"One hot encoded\n\ny_train {y_train_encoded.shape}\ny_test {y_test_encoded.shape}")
Результаты
One hot encoded y_train (792, 2) y_test (198, 2)
3. Обучение модели CNN
Именно здесь выполняется большая часть работы.
# Defining the CNN model model = Sequential() model.add(Conv1D(filters=64, kernel_size=3, activation='relu', strides=2, padding='causal', input_shape=(window_size, X_train.shape[2]) ) ) model.add(MaxPooling1D(pool_size=2)) model.add(Flatten()) model.add(Dense(100, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(units=len(np.unique(y)), activation='softmax')) # For binary classification (buy/sell signal) model.summary() # Compiling the model optimizer = Adam(learning_rate=0.001) model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy']) # Training the model early_stopping = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True) history = model.fit(X_train, y_train_encoded, epochs=100, batch_size=16, validation_split=0.2, callbacks=[early_stopping]) plt.figure(figsize=(7.5, 6)) plt.plot(history.history['loss'], label='Training Loss') plt.plot(history.history['val_loss'], label='Validation Loss') plt.xlabel('Epochs') plt.ylabel('Loss') plt.title('Training Loss Curve') plt.legend() plt.savefig("training loss cuver-cnn-clf.png") plt.show()
Результаты
Model: "sequential_2" ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ conv1d_2 (Conv1D) │ (None, 5, 64) │ 832 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling1d_2 (MaxPooling1D) │ (None, 2, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ flatten_2 (Flatten) │ (None, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_4 (Dense) │ (None, 100) │ 12,900 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_2 (Dropout) │ (None, 100) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_5 (Dense) │ (None, 2) │ 202 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Обучение остановилось на 34-й эпохе.
40/40 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.5105 - loss: 0.6875 - val_accuracy: 0.4843 - val_loss: 0.6955 Epoch 32/100 40/40 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.5099 - loss: 0.6888 - val_accuracy: 0.5283 - val_loss: 0.6933 Epoch 33/100 40/40 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.4636 - loss: 0.6933 - val_accuracy: 0.5283 - val_loss: 0.6926 Epoch 34/100 40/40 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.5070 - loss: 0.6876 - val_accuracy: 0.5346 - val_loss: 0.6963
Модель оказалась точной примерно в 57% случаев при прогнозировании вне выборки.
y_pred = model.predict(X_test) classes_in_y = np.unique(y) y_pred_binary = classes_in_y[np.argmax(y_pred, axis=1)] # Confusion Matrix cm = confusion_matrix(y_test, y_pred_binary) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues') plt.xlabel("Predicted Label") plt.ylabel("True Label") plt.title("Confusion Matrix") plt.savefig("confusion-matrix CNN") # Display the heatmap print("Classification Report\n", classification_report(y_test, y_pred_binary))
Результаты
7/7 ━━━━━━━━━━━━━━━━━━━━ 0s 11ms/step Classification Report precision recall f1-score support 0 0.53 0.24 0.33 88 1 0.58 0.83 0.68 110 accuracy 0.57 198 macro avg 0.55 0.53 0.50 198 weighted avg 0.55 0.57 0.52 198
Наша модель CNN достаточно хороша для создания советника. Но прежде чем мы начнем писать код советника, нам нужно сохранить обученную нами модель в формате ONNX.
4. Сохранение модели CNN в формате ONNX.
Процесс довольно прост. Нам нужно сохранить модель сверточной нейросети в формате .onnx, а параметры метода масштабирования — в бинарных файлах.
import tf2onnx onnx_file_name = "cnn.EURUSD.D1.onnx" spec = (tf.TensorSpec((None, window_size, X_train.shape[2]), tf.float16, name="input"),) model.output_names = ['outputs'] onnx_model, _ = tf2onnx.convert.from_keras(model, input_signature=spec, opset=13) # Save the ONNX model to a file with open(onnx_file_name, "wb") as f: f.write(onnx_model.SerializeToString()) # Save the mean and scale parameters to binary files scaler.mean_.tofile(f"{onnx_file_name.replace('.onnx','')}.standard_scaler_mean.bin") scaler.scale_.tofile(f"{onnx_file_name.replace('.onnx','')}.standard_scaler_scale.bin")
Создание торгового робота на основе сверточной нейросети (CNN)
Первое, что нужно сделать при написании нашего советника, это подключить в виде ресурсов модель в формате ONNX и стандартный машатбатор в формате бинарных файлов.
MQL5 | ConvNet EA.mq5
#resource "\\Files\\cnn.EURUSD.D1.onnx" as uchar onnx_model[] #resource "\\Files\\cnn.EURUSD.D1.standard_scaler_scale.bin" as double scaler_stddev[] #resource "\\Files\\cnn.EURUSD.D1.standard_scaler_mean.bin" as double scaler_mean[]
Далее нужно их инициализировать: масштабатор и модель ONNX.
#include <MALE5\Convolutioal Neural Networks(CNNs)\Convnet.mqh> #include <MALE5\preprocessing.mqh> CConvNet cnn; StandardizationScaler scaler; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ input group "cnn"; input uint cnn_data_window = 10; //this value must be the same as the one used during training in a python script vector classes_in_y = {0,1}; //we have to assign the classes manually | it is essential that their order is preserved as they can be seen in python code, HINT: They are usually in ascending order //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- if (!cnn.Init(onnx_model)) //Initialize the ONNX model return INIT_FAILED; //--- Initializing the scaler with values loaded from binary files scaler = new StandardizationScaler(scaler_mean, scaler_stddev); //load the scaler return(INIT_SUCCEEDED); }
Отлично, этого достаточно, чтобы модель заработала. Теперь давайте создадим функцию для извлечения данных, аналогично тому, как мы использовали независимые переменные во время обучения. Мы использовали четыре переменные: значения OHLC (Open, High, Low, Close) с предыдущего закрытого бара и до 10 баров назад, что и было размером окна. Также используем все тот же дневной таймфрейм.
input group "cnn"; input uint cnn_data_window = 10; //this value must be the same as the one used during training in a python script input ENUM_TIMEFRAMES timeframe = PERIOD_D1; input int magic_number = 1945; input int slippage = 50;
matrix GetXVars(int bars, int start_bar=1) { vector open(bars), high(bars), low(bars), close(bars); //--- Getting OHLC values open.CopyRates(Symbol(), timeframe, COPY_RATES_OPEN, start_bar, bars); high.CopyRates(Symbol(), timeframe, COPY_RATES_HIGH, start_bar, bars); low.CopyRates(Symbol(), timeframe, COPY_RATES_LOW, start_bar, bars); close.CopyRates(Symbol(), timeframe, COPY_RATES_CLOSE, start_bar, bars); //--- matrix data(bars, 4); //we have 10 inputs from cnn | this value is fixed //--- adding the features into a data matrix data.Col(open, 0); data.Col(high, 1); data.Col(low, 2); data.Col(close, 3); return data; }
У нас есть функция для сбора независимых переменных, и теперь мы можем сформулировать торговую стратегию.
void OnTick() { //--- if (NewBar()) //Trade at the opening of a new candle { matrix input_data_matrix = GetXVars(cnn_data_window); //get data for the past 10 days(default) input_data_matrix = scaler.transform(input_data_matrix); //applying StandardSCaler to the input data int signal = cnn.predict_bin(input_data_matrix, classes_in_y); //getting trade signal from the RNN model Comment("Signal==",signal); //--- MqlTick ticks; SymbolInfoTick(Symbol(), ticks); if (signal==1) //if the signal is bullish { if (!PosExists(POSITION_TYPE_BUY)) //There are no buy positions { if (!m_trade.Buy(lotsize, Symbol(), ticks.ask, 0, 0)) //Open a buy trade printf("Failed to open a buy position err=%d",GetLastError()); ClosePosition(POSITION_TYPE_SELL); //close opposite trade } } else if (signal==0) //Bearish signal { if (!PosExists(POSITION_TYPE_SELL)) //There are no Sell positions if (!m_trade.Sell(lotsize, Symbol(), ticks.bid, 0, 0)) //open a sell trade printf("Failed to open a sell position err=%d",GetLastError()); ClosePosition(POSITION_TYPE_BUY); } else //There was an error return; } }
Стратегия проста. Получив определенный сигнал, скажем, сигнал на покупку, мы открываем сделку на покупку без значений стоп-лосса и тейк-профита, затем закрываем по противоположному сигналу и наоборот для сигнала на продажу.
Я протестировал эту стратегию на том же символе, на котором она была обучена:EURUSD, в течение десяти лет. С 01.01.2014 по 27.05.2024 на 4-часовом графике в режиме по ценам открытия на каждом баре.
Результаты тестирования стратегии оказались впечатляющими.
Советник на базе сверточной нейросети делал точные прогнозы в 58% случаев, в результате чего он получил чистую прибыль в размере 503 долларов.
Заключение
Несмотря на то, что сверточные нейронные сети (CNN) были изначально разработаны для обработки изображений и видео, при адаптации для работы с табличными данными, такими как данные о форекс-рынке, они могут неплохо справляться с выявлением паттернов и использовать их для прогнозирования в рынке форекс.
Как видно из отчета тестера стратегий, основанный на нейросети CNN советник показал хорошие результаты, сделав точные предсказания. Я уверен, что многие традиционные модели, предназначенные для табличных данных, такие как линейная регрессия, машины опорных векторов, наивный байесовский классификатор и другие, не смогли бы достичь такой предсказательной точности, особенно учитывая, что CNN-модели использовали всего 4 независимых переменные (OHLC). На моем опыте, немногие модели могут достичь таких результатов, имея всего несколько переменных.
С наилучшими пожеланиями.
За развитием этой модели машинного обучения и других из этой серии статей можно следить в моем репозиторий на GitHub.
Таблица вложений
Название файла | Тип файла | Описание и использование |
---|---|---|
ConvNet EA.mq5 | Expert | Торговый робот для загрузки модели сверточной нейросети в ONNX и тестирования полученной торговой стратегии в MetaTrader 5. |
cnn.EURUSD.D1.onnx | ONNX | Модель сверточной сети CNN в формате ONNX. |
cnn.EURUSD.D1.standard_scaler_mean.bin cnn.EURUSD.D1.standard_scaler_scale.bin | Бинарные файлы | Бинарные файлы для стандартного масштабатора |
preprocessing.mqh | Включаемый файл | Библиотека стандартного масштабатора |
ConvNet.mqh | Включаемый файл | Библиотека для загрузки и развертывания модели CNN в формате ONNX |
cnn-for-trading-applications-tutorial.ipynb | Скрипт Python/Блокнот Jupyter | Содержит весь код Python, обсуждаемый в этой статье. |
Источники и ссылки
- Convolutional Neural Network-based a novel Deep Trend Following Strategy for Stock Market Trading (https://ceur-ws.org/Vol-3052/paper2.pdf)
- What are Convolutional Neural Networks (CNNs)? (https://youtu.be/QzY57FaENXg)
- Converting tabular data into images for deep learning with convolutional neural networks (https://www.nature.com/articles/s41598-021-90923-y)
- Image kernels (https://setosa.io/ev/image-kernels/)
- Pooling Methods in Deep Neural Networks, a Review(https://arxiv.org/pdf/2009.07485)
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/15259
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Опубликована статья Машинное обучение и Data Science (Часть 27): Сверточные нейросети (CNN) в торговых роботах для MetaTrader 5:
Автор: Omega J Msigwa
5.5 сделок в год по H4 это мало. Очень мало.
Это самое краткое объяснение применения CNN в трейдинге, которое я когда-либо видел, причем по большей части на простом языке и с диаграммами. Затем оно сведено к коду на MQL5. Обратите внимание, что код не ограничивается таймфреймом H4.
Отличная работа, сэр! 👍