
Интеграция MQL5 с пакетами обработки данных (Часть 1): Расширенный анализ данных и статистическая обработка
Введение
Финансовые рынки генерируют огромные объемы данных, которые может быть сложно анализировать исключительно в целях технического анализа. Кроме того, технический анализ, выполняемый вручную, сам по себе не позволяет трейдерам анализировать и интерпретировать закономерности, тренды и аномалии в данных. Продвинутый пакет анализа данных, такой как Jupyter Lab, позволяет трейдерам выполнять сложный статистический анализ, машинное обучение и визуализацию данных. Это позволяет выявить прибыльные торговые возможности, понять поведение рынка, сезонные тенденции и прогнозировать будущие движения цен.
Сбор исторических данных
Для начала нам нужны исторические данные из MetaTrader 5 в .csv-формате. Запустите платформу MetaTrader, "Сервис" > "Настройки" > вкладка "Графики". Затем нужно выбрать количество баров на графике, которое необходимо загрузить. Лучше всего выбрать вариант с неограниченным количеством баров, поскольку мы будем работать с датой и не будем знать, сколько баров в определенном периоде времени.
После этого загрузим реальные данные. Для этого пройдите "Вид" > "Символы". Вы окажетесь на вкладке "Спецификация". Переключитесь на вкладку "Бары" или "Тики" в зависимости от того, какие данные вы хотите загрузить. Введите начальную и конечную дату периода исторических данных, которые вы хотите загрузить, после чего нажмите "Запрос", чтобы загрузить данные и сохранить их в формате .csv.
Исторические данные загружены. Теперь необходимо загрузить и настроить среду Jupyter Lab для анализа. Перейдите на официальный сайт Jupyter Lab и следуйте простым шагам, чтобы загрузить его. В зависимости от вашей операционной системы у вас будет несколько вариантов установки с помощью pip, conda или brew.
Загрузка исторических данных MetaTrader 5 в Jupyter Lab
Для успешной загрузки исторических данных MetaTrader 5 в Jupyter Lab нужно знать папку, которую вы выбрали для загрузки данных, а затем в Jupyter Lab просто перейти в эту папку. Для начала вам нужно будет загрузить данные и проверить имена столбцов. Нам необходимо проверить имена столбцов, чтобы правильно обрабатывать их и избегать ошибок, которые могут возникнуть при использовании неправильного имени столбца.
Предварительная обработка
Прежде чем приступить к анализу данных, нам необходимо провести их предварительную обработку.
1. Анализ даты и времени: преобразование столбца даты в формат даты и времени.
2. Обработка всех отсутствующих значений.
3. Создание новых параметров при необходимости.
код python:
import pandas as pd # Load historical data file_path = '/home/int_junkie/Documents/ML/XAUUSD.m_H1_historical.csv' data = pd.read_csv(file_path) # Display the first few rows and column names print(data.head()) print(data.columns)
вывод:
Мы видим специальные символы '<>' внутри столбцов, а также '\t', что указывает на то, что файл разделен табуляцией. Теперь мы можем приступить к загрузке исторических данных с правильным именем столбца.
В коде ниже сделаем следующее:
1. Импорт библиотек:
- Pandas — мощная библиотека для обработки данных на Python.
- Для технического анализа данных финансовых рынков используется Technical Analysis Library (TA lib).
2. Загрузка исторических данных:
- Путь к файлу используется для указания местоположения CSV-файла, содержащего исторические данные.
- Pd.read считывает CSV-файл в pandas Data-Frame. Разделитель '\t' указывает на то, что файл разделен табуляцией.
3. Отображение данных:
- Data.head распечатывает первые несколько строк Data-frame для проверки содержимого.
- Data.columns выводит имена столбцов для проверки структуры фрейма данных.
4. Сортировка данных по дате:
- Date.sort сортирует фрейм данных на месте по колонке '<DATE>' (дата). Это гарантирует, что данные будут располагаться в хронологическом порядке.
5. Расчет RSI:
- TA.RSI рассчитывает индекс относительной силы (RSI) с использованием столбца цены '<CLOSE>' (закрытие).
- Временной период, указывается 14-периодный RSI.
- Рассчитанные значения сохраняются в новом столбце с именем RSI в фрейме данных.
6. Отображение обновленных данных:
- Data.head распечатывает первые несколько строк Data-frame для проверки расчета RSI.
import pandas as pd import talib as ta # Load historical data file_path = '/home/int_junkie/Documents/ML/XAUUSD.m_H1_historical.csv' data = pd.read_csv(file_path, delimiter='\t') # Display the first few rows and column names to verify print(data.head()) print(data.columns) # Ensure data is sorted by the correct date column data.sort_values('<DATE>', inplace=True) # Calculate RSI using the '<CLOSE>' price column data['RSI'] = ta.RSI(data['<CLOSE>'], timeperiod=14) # Display the first few rows to verify print(data.head())
вывод:
Мы видим, что в столбце RSI имеются значения NAN, и нам необходимо их правильно обработать. Для расчета индикатора функции RSI требуется минимальное количество точек данных. Она может возвращать значения NAN для начальных периодов. Для правильной обработки значений NAN нам необходимо знать тип данных для столбца '<CLOSE>'. Убедитесь в правильном доступе к Data-Frame и столбцу. Следующий код Python показывает, как обрабатывать значения NAN.
import pandas as pd import talib as ta # Load the historical data file_path = '/home/int_junkie/Documents/ML/XAUUSD.m_H1_historical.csv' data = pd.read_csv(file_path, delimiter='\t')data['<CLOSE>'] = data['<CLOSE>'].astype(float) # Verify the column names print(data.columns) # Convert the column to the correct data type if necessary data['<CLOSE>'] = data['<CLOSE>'].astype(float) # Calculate the RSI data['RSI'] = ta.RSI(data['<CLOSE>'], timeperiod=14) # Display the RSI values print(data[['<CLOSE>', 'RSI']].tail(20))
Результат:
Мы видим, что значения NAN обработаны правильно. Если вы видите значение NAN для начальных периодов (что ожидаемо из-за периода блокировки (lock-back period)), вы можете продолжить обработку следующим образом:
data['RSI'] = ta.RSI(data['<CLOSE>'], timeperiod=14) data['RSI'] = data['RSI'].fillna(0) # or use any other method to handle NaN values
Разведочный анализ данных
Основная цель разведочного анализа данных (exploratory data analysis, EDA) — исследовать базовую структуру путем обобщения основных характеристик данных. При выполнении EDA мы обнаруживаем закономерности и определяем тенденции и взаимосвязи в данных. В EDA мы также обнаруживаем аномалии и выбросы или любые необычные наблюдения, которые могут потребовать дальнейшего изучения. Мы также проверяем предположения о данных, которые могут повлиять на последующий анализ. Затем мы выполняем очистку данных, выявляя любые пропущенные значения, ошибки и несоответствия, которые необходимо устранить.
Используем следующие скрипты python для выполнения EDA:
import seaborn as sns import matplotlib.pyplot as plt import warnings warnings.filterwarnings("ignore") for i in data.select_dtypes(include="number").columns: sns.histplot(data=data, x=i) plt.show()
В приведенном выше коде после импорта всех необходимых библиотек мы начинаем с игнорирования предупреждений, чтобы получить чистый вывод. Затем перебираем числовые столбцы. 'data.select_dtypes(include="number")' возвращает фрейм данных, содержащий только числовые столбцы. 'columns' возвращает имена этих столбцов. Приступим к построению гистограммы на основе данных. Ниже приведены гистограммы, построенные на основе приведенного выше кода.
После проведения операций статистической обработки можно приступить к обучению модели на собранных данных. Цель состоит в том, чтобы иметь возможность делать прогнозы на основе собранных нами исторических данных. Мы будем делать прогнозы, используя только индикатор RSI. Прежде чем приступить к работе, нам необходимо узнать тип взаимосвязи, существующей между самими данными. Для этого используем матрицу корреляции. Мы должны иметь возможность определять, имеет ли существующая связь положительную корреляцию, отрицательную корреляцию либо корреляция вовсе отсутствует.
- Положительная корреляция: Значения, близкие к 1, указывают на сильную положительную корреляцию между двумя переменными. Например, если корреляция между Open и Close близка к 1, это означает, что они движутся в одном направлении.
- Отрицательная корреляция: Значения, близкие к -1, указывают на сильную отрицательную корреляцию. Например, если корреляция между Volume и Price близка к -1, это означает, что по мере увеличения объема цена имеет тенденцию к снижению.
- Отсутствие корреляции: значения, близкие к 0, указывают на отсутствие корреляции между переменными.
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import r2_score, mean_squared_error import talib as ta # Technical Analysis library # Load the data file_path = '/home/int_junkie/Documents/ML/XAUUSD.m_H1_historical.csv' data = pd.read_csv(file_path, delimiter='\t') # Exploratory Data Analysis (EDA) print(data.info()) print(data.describe()) # Visualize the closing price plt.figure(figsize=(12, 6)) plt.plot(data['<CLOSE>']) plt.title('XAUUSD Closing Price') plt.xlabel('<DATE>') plt.ylabel('Price') plt.show() # Feature Engineering data['RSI'] = ta.RSI(data['<CLOSE>'], timeperiod=14) # Drop rows with missing values data.dropna(inplace=True) # Define target variable data['Target'] = data['<CLOSE>'].shift(-1) data.dropna(inplace=True) # Split the data X = data[['RSI']] # Only use RSI as the feature y = data['Target'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False) # Model Development model = RandomForestRegressor(n_estimators=100, random_state=42) model.fit(X_train, y_train) # Predictions y_pred = model.predict(X_test) # Evaluate the model mse = mean_squared_error(y_test, y_pred) print(f'Mean Squared Error: {mse}') # Visualize the predictions plt.figure(figsize=(12, 6)) plt.plot(y_test.index, y_test, label='Actual Values') plt.plot(y_test.index, y_pred, label='Predicted Values') plt.xlabel('Samples') plt.ylabel('TARGET_CLOSE') plt.title('Actual vs Predicted Values') plt.legend() plt.show()
Вот результат, который мы получаем при обучении модели:
Из анализа данных видно, что прогнозные значения не соответствуют фактическим. Это указывает на то, что модель не отражает эффективно базовую закономерность. Причин может быть несколько.
1. Недостаточно данных для обучения: Если набор данных слишком мал, у модели может быть недостаточно информации для обучения в полном объеме.
2. Переобучение: Модель могла запомнить обучающие данные, а не научиться обобщать их. Это часто происходит, когда модель слишком сложна или не обобщена должным образом.
3. Недообучение: Модель может быть слишком простой, чтобы отразить основную закономерность в данных. Это может произойти, если в модели отсутствуют важные функции.
4. Параметры: Неправильный или недостаточный выбор параметров могут привести к тому, что модель не будет иметь достаточно необходимой информации для прогнозов.
Шаги по поиску и устранению проблемы:
1. Проверьте данные: убедитесь, что данные чисты, непротиворечивы и прошли надлежащую предварительную обработку.
2. Оцените эффективность модели: используйте матрицы, такие как среднеквадратическая ошибка (Mean Squared Error, MSE) и средняя абсолютная ошибка (Mean Absolute Error, MAB).
3. Улучшите работу с параметрами: Поэкспериментируйте с разными параметрами, включая технические индикаторы, запаздывающие значения и другие необходимые финансовые метрики.
4. Настройте гиперпараметры: Используйте такие методы, как поиск по сетке (Grid Search) или случайный поиск (Random Search), чтобы найти оптимальные гиперпараметры для вашей модели.
Собираем всё вместе в MQL5
После сохранения модели создадим скрипт Python для прогнозирования. Этот скрипт загрузит модель и сделает прогнозы.
import joblib import sys import os
- Joblib - используется для загрузки сериализованной модели машинного обучения.
- Sys - обеспечивает доступ к аргументам командной строки.
- OS - используется для проверки наличия файлов и выполнения файловых операций.
model_path = sys.argv[/home/int_junkie/Documents/ML/random_forest_model.pkl] features_path = sys.argv[/home/int_junkie/Documents/ML/features.txt]
- Sys.argv[1] - первый аргумент командной строки. Это путь к файлу модели.
- Sys.argv[2] - второй аргумент командной строки. Это путь к файлу параметров.
print(f"Model path: {model_path}") print(f"Features path: {features_path}")
Выводим отладочную информацию. Распечатывает пути к файлам модели и параметров для отладки.
if not os.path.exists(model_path): print(f"Error: Model file not found at {model_path}") sys.exit(1) if not os.path.exists(features_path): print(f"Error: Features file not found at {features_path}") sys.exit(1)
- Проверим, существуют ли файлы модели и параметров.
- Если ни один из них не существует, выводится сообщение об ошибке и скрипт завершается с кодом состояния 1.
model = joblib.load(model_path)
- Загружает обученную модель машинного обучения из указанного 'model-path'.
with open(features_path, 'r') as f: features = [float(line.strip()) for line in f]
- Открывает файл параметров для чтения.
- Считывает каждую строку, удаляет все начальные и конечные пробелы, преобразует файл в число с плавающей точкой и сохраняет его в списке features.
prediction = model.predict([features])[0]
- Использует загруженную модель для создания прогноза на основе загруженных параметров.
- Model.predict возвращает список прогнозов (в данном случае один), '[0]' извлекает первый прогноз.
print(prediction)
- Выводит прогноз. Эти выходные данные могут быть приняты другим скриптом или программой, например MQL5, для принятия торговых решений.
MQL5
Загрузите модель в OnInit().
int OnInit(){ // Load the model and feature names string modelPath = "/home/int_junkie/Documents/ML/random_forest_model.pkl"; string featurePath = "/home/int_junkie/Documents/ML/features.txt"; // Your code to load the model (use appropriate library for pkl files) // Initialize the features double features[]; int fileHandle = FileOpen(featurePath, FILE_READ | FILE_TXT); if (fileHandle != INVALID_HANDLE) { string line; while(!FileIsEnding(fileHandle)) { line = FileReadString(fileHandle); ArrayResize(features, ArraySize(features) + 1); features[ArraySize(features) - 1] = StringToDouble(line); } FileClose(fileHandle); } return(INIT_SUCCEEDED); }
Считываем прогнозы из файла python в OnTick().
void OnTick(){ // Declare static variables to retain values across function calls static bool isNewBar = false; static int prevBars = 0; // Get the current number of bars int newbar = iBars(_Symbol, _Period); // Check if the number of bars has changed if (prevBars == newbar) { // No new bar isNewBar = false; } else { // New bar detected isNewBar = true; // Update previous bars count to current prevBars = newbar; } // Update the features based on current data double features[]; ArrayResize(features, 1); features[0] = iClose(Symbol(), 0, 0); // Write the features to a file int fileHandle = FileOpen("/home/int_junkie/Documents/ML/features.txt", FILE_WRITE | FILE_TXT); if (fileHandle != INVALID_HANDLE) { for (int i = 0; i < ArraySize(features); i++) { FileWrite(fileHandle, DoubleToString(features[i])); } FileClose(fileHandle); } else { Print("Error: Cannot open features file for writing"); return; } // Call the Python script to get the prediction string command = "python /home/int_junkie/Documents/ML/predict.py /home/int_junkie/Documents/ML/random_forest_model.pkl /home/int_junkie/Documents/ML/features.txt"; int result = ShellExecuteA(command); if(result != 0) { Print("Error: ShellExecuteA failed with code ", result); return; } // Read the prediction from a file Sleep(1000); // Wait for the Python script to complete fileHandle = FileOpen("/home/int_junkie/Documents/ML/prediction.txt", FILE_READ | FILE_TXT); if (fileHandle != INVALID_HANDLE) { string prediction = FileReadString(fileHandle); FileClose(fileHandle); double pred_value = StringToDouble(prediction); // Generate trading signals based on predictions double some_threshold = 0.0; // Define your threshold if (pred_value > some_threshold) { // Buy signal double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),Digits()); double sl = Ask - stopLoss * _Point; double tp = Ask + takeProfit * _Point; trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, lotsize, Ask, sl, tp, "ML"); } else if (pred_value < some_threshold) { // Sell signal double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),Digits()); double sl = Bid + stopLoss * _Point; double tp = Bid - takeProfit * _Point; trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, lotsize, Bid, sl, tp, "ML"); } } else { Print("Error: Cannot open prediction file for reading"); } }
В OnTick переменная command подготавливает строковую команду для запуска скрипта python с файлами параметров и модели в качестве аргументов. ShellExecuteA (command) выполняет скрипт python с помощью ShellExecuteA. 'Sleep (1000)', Ожидает 1 секунду, пока скрипт python завершит выполнение. После этого открываем файл прогноза для чтения. Затем проверяем, успешно ли открылся файл прогноза. Если да, считываем прогноз. Если нет, выводится ошибка. Переменная threshold используется для принятия торговых решений. Если ее значение больше прогнозируемого, генерируется сигнал на покупку. Если меньше - на продажу.
Заключение
Мы извлекли данные из торговой платформы MetaTrader 5. Затем использовали их в Jupyter Lab для анализа данных и статистической обработки. После проведения анализа в Jupyter Lab мы интегрировали модель в MQL5 для принятия торговых решений на основе выявленных закономерностей. Интеграция MQL5 с Jupyter Lab решает проблему ограниченных аналитических, статистических и визуальных возможностей MQL5. Процесс улучшает разработку стратегии, повышает эффективность обработки данных и обеспечивает совместную, гибкую и мощную среду для расширенного анализа данных и статистической обработки в трейдинге.
В заключение следует отметить, что благодаря интеграции MQL5 с Jupyter Lab мы можем выполнять расширенный анализ данных и статистическую обработку. Благодаря таким возможностям мы можем разрабатывать и оптимизировать любые торговые стратегии с помощью передовых методов. В результате мы получаем значительное конкурентное преимущество в динамичной и интенсивной по объему данных сфере финансовой торговли.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/15155
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.






- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования