English 中文 Español Deutsch 日本語 Português
preview
Интеграция MQL5 с пакетами обработки данных (Часть 1): Расширенный анализ данных и статистическая обработка

Интеграция MQL5 с пакетами обработки данных (Часть 1): Расширенный анализ данных и статистическая обработка

MetaTrader 5Торговые системы |
458 1
Hlomohang John Borotho
Hlomohang John Borotho

Введение

Финансовые рынки генерируют огромные объемы данных, которые может быть сложно анализировать исключительно в целях технического анализа. Кроме того, технический анализ, выполняемый вручную, сам по себе не позволяет трейдерам анализировать и интерпретировать закономерности, тренды и аномалии в данных. Продвинутый пакет анализа данных, такой как 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.
код python:
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())

вывод:

вывод2

Мы видим, что в столбце 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 обработаны правильно. Если вы видите значение 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' возвращает имена этих столбцов. Приступим к построению гистограммы на основе данных. Ниже приведены гистограммы, построенные на основе приведенного выше кода.

OPEN

   

HIGH

LOW

CLOSE

TICKVOL

RSI

После проведения операций статистической обработки можно приступить к обучению модели на собранных данных. Цель состоит в том, чтобы иметь возможность делать прогнозы на основе собранных нами исторических данных. Мы будем делать прогнозы, используя только индикатор 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

Прикрепленные файлы |
jupyterpackage.ipynb (323.31 KB)
features.txt (0 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (1)
3866233
3866233 | 3 дек. 2024 в 23:03
XAUUSD дневной максимум закрытия
От начального до среднего уровня: Операторы BREAK и CONTINUE От начального до среднего уровня: Операторы BREAK и CONTINUE
В данной статье мы рассмотрим, как использовать операторы RETURN, BREAK и CONTINUE в цикле. Понимание того, что делает каждый из этих операторов в потоке выполнения цикла, очень важно для работы с более сложными приложениями. Представленные здесь материалы предназначены только для обучения. Ни в коем случае не рассматривайте его как окончательное приложение, целью которого не является изучение представленных концепций.
Добавляем пользовательскую LLM в торгового робота (Часть 5): Разработка и тестирование торговой стратегии с помощью LLM (I) - Тонкая настройка Добавляем пользовательскую LLM в торгового робота (Часть 5): Разработка и тестирование торговой стратегии с помощью LLM (I) - Тонкая настройка
Языковые модели (LLM) являются важной частью быстро развивающегося искусственного интеллекта, поэтому нам следует подумать о том, как интегрировать мощные LLM в нашу алгоритмическую торговлю. Большинству людей сложно настроить эти модели в соответствии со своими потребностями, развернуть их локально, а затем применить к алгоритмической торговле. В этой серии статей будет рассмотрен пошаговый подход к достижению этой цели.
Диалектический поиск — Dialectic Search (DA) Диалектический поиск — Dialectic Search (DA)
Представляем Диалектический Алгоритм (DA) — новый метод глобальной оптимизации, вдохновленный философской концепцией диалектики. Алгоритм использует уникальное разделение популяции на спекулятивных и практических мыслителей. Тестирование показывает впечатляющую производительность до 98% в задачах малой размерности и общую эффективность 57.95%. Статья объясняет эти показатели и представляет детальное описание алгоритма и результаты экспериментов на различных типах функций.
От начального до среднего уровня: Операторы WHILE и DO WHILE От начального до среднего уровня: Операторы WHILE и DO WHILE
В этой статье мы практически и весьма наглядно рассмотрим первый оператор цикла. Несмотря на то, что многие новички испытывают страх, сталкиваясь с необходимостью создания циклов, знание того, как это делать правильно и безопасно, может прийти только с опытом и практикой. Но кто знает, возможно, я смогу уменьшить ваши трудности и страдания, показав основные проблемы и меры предосторожности, которые следует соблюдать при использовании циклов в коде.