ИИ-трейдинг: Показываем код, сомневаемся в результатах или много кода, мало толка? Проверяем "умную" стратегию ИИ.

 

Код и его логика полностью написаны ИИ, описание кода и комментарии к коду также генерируются ИИ. 

Приглашаю желающих включиться в обсуждение этой игрушки (кода) и, если есть возможности, улучшить ее, чтобы код не был просто игрушкой с переоптимизированными результатами. 

Код выполняется в среде Python, но не пригоден для использования в MQL MetaEditor. Для запуска кода требуется Python IDE.

Общее назначение кода:

Данный код представляет собой сложную систему для оптимизации и бэктестирования торговой стратегии на финансовых рынках, используя данные, полученные из платформы MetaTrader 5 (MT5). Он включает в себя загрузку исторических данных, вычисление технических индикаторов, построение моделей машинного обучения для прогнозирования цен, реализацию торговой стратегии на основе полос Боллинджера и использование генетического алгоритма для оптимизации параметров стратегии, а также модели stop-loss. Код также генерирует различные графики и отчёты для анализа производительности стратегии.

Основные компоненты и их функциональность:

  1. Импорт библиотек: Код начинает с импорта необходимых библиотек, включая:
    • logging: для ведения журнала событий.
    • os: для работы с файловой системой.
    • sys: для взаимодействия с интерпретатором Python.
    • MetaTrader5 (mt5): для получения данных из платформы MT5.
    • pandas (pd): для работы с табличными данными (DataFrame).
    • numpy (np): для математических операций и работы с массивами.
    • matplotlib: для построения графиков.
    • mplfinance: для построения графиков свечей.
    • datetime: для работы с датой и временем.
    • deap: для реализации генетических алгоритмов.
    • random: для генерации случайных чисел.
    • warnings: для контроля предупреждений.
    • multiprocessing: для параллельных вычислений.
    • functools: для создания функций с фиксированными аргументами.
    • gc: для сборки мусора.
    • xgboost (xgb): для градиентного бустинга.
    • sklearn: для моделей машинного обучения и метрик.
    • ta: для технических индикаторов.
    • joblib: для сохранения и загрузки моделей.
    • seaborn: для статистических графиков.
    • shap: для интерпретации результатов машинного обучения.
    • statsmodels: для статистических тестов.
    • tabulate: для форматирования таблиц.
  2. Настройка логирования: Код настраивает логирование для записи событий в файл и на консоль, включая фильтрацию определенных сообщений для консоли.
  3. Параметры и глобальные переменные: Задаются глобальные переменные и параметры, такие как даты начала и конца данных, комиссии, проскальзывание, безрисковая ставка, таймфреймы для обработки, валютные пары, параметры генетического алгоритма, и параметры XGBoost. Также создается словарь для отображения числовых значений таймфреймов в текстовые.
  4. Вспомогательные функции:
    • get_conversion_rate: Получает курс конвертации между двумя валютами из MT5.
    • apply_transformations: Применяет различные преобразования к временному ряду (первая разность, процентное изменение, логарифм).
    • replace_inf_nan: Заменяет бесконечные и NaN значения в ряде на корректные.
    • select_best_transformation: Выбирает наилучшее преобразование для временного ряда на основе теста Дики-Фуллера.
    • get_mt5_data: Загружает данные либо из CSV-файла, либо из MT5.
  5. Класс StrategyEvaluator:
    • Инициализация: Содержит конструктор для инициализации объекта оценщика стратегии, включая загрузку информации о символе из MT5, расчёт коэффициента конвертации валют, создание словаря для хранения сделок и инициализации параметров, необходимых для вычисления доходности.
    • evaluate: Оценивает торговую стратегию на основе входных параметров, генерирует сигналы, моделирует открытие и закрытие позиций, рассчитывает чистую доходность, и возвращает коэффициент Сортино, а также сохраняет данные по совершенным сделкам. При этом может быть использована SL-модель для фильтрации входов в позиции.
  6. Функции отрисовки графиков:
    • plot_error_distribution: Построение гистограммы распределения ошибок предсказания.
    • plot_residuals: Построение графика остатков во времени.
    • backtest_strategy: Построение графика кумулятивной доходности стратегии.
    • plot_trade_metrics: Построение различных графиков для анализа торговых сделок (длина позиций, количество прибыльных/убыточных сделок, распределение прибыли и убытков, кумулятивная прибыль, среднее время в прибыли и убытке).
    • plot_trade_execution: Отрисовка точек закрытия сделок на графике цен.
    • plot_predicted_vs_actual: Отрисовка графика фактической и предсказанной цены.
    • plot_sl_features_shap: Отрисовка SHAP summary plot для SL-модели.
  7. Функции для генетического алгоритма:
    • random_window_ga, random_multiplier_ga, random_tp_factor_ga, random_sl_factor_ga, random_sl_max_depth_ga, random_sl_learning_rate_ga, random_sl_n_estimators_ga: Случайный выбор параметров для генетического алгоритма.
    • custom_mutate: Функция мутации параметров индивида.
    • global_evaluate: Функция оценки индивида, которая обучает SL-модель и применяет её в стратегии.
    • run_ga: Запускает генетический алгоритм и возвращает лучшего индивида.
    • create_toolbox: Создает объект toolbox для генетического алгоритма, регистрируя необходимые функции.
  8. Основная функция (main_function):
    • Инициализирует MT5.
    • Определяет количество используемых ядер процессора.
    • Создаёт директории для сохранения графиков.
    • Для каждого таймфрейма и валютной пары загружает данные, вычисляет технические индикаторы, разбивает данные на обучающую, тестовую и бэктестовую выборки, проводит масштабирование данных.
    • Обучает модели машинного обучения для прогнозирования цен.
    • Производит отбор признаков на основе SHAP значений.
    • Оценивает стратегию с помощью параметров по умолчанию, а затем на основе параметров, найденных генетическим алгоритмом, который также обучает SL-модель.
    • Сохраняет графики и отчёты с результатами.
    • Рассчитывает и выводит метрики производительности ансамблевой модели.
    • Освобождает память.

Логика работы кода:

  1. Загрузка данных: Код загружает исторические данные цен из MT5 или CSV-файлов.
  2. Предварительная обработка данных: Вычисляются технические индикаторы, создаются лагированные признаки, применяются преобразования для стационарности, проводится отбор признаков на основе SHAP.
  3. Разделение данных: Данные разделяются на обучающую, тестовую и бэктестовую выборки.
  4. Обучение моделей: Обучаются модели машинного обучения для прогнозирования цен.
  5. Оценка стратегии: Производится оценка торговой стратегии на основе полос Боллинджера с различными параметрами.
  6. Генетический алгоритм: Генетический алгоритм используется для автоматической оптимизации параметров торговой стратегии, а также параметров SL-модели, с целью максимизации коэффициента Сортино.
  7. Отрисовка графиков: Для анализа производительности стратегии и SL-модели создаются различные графики и отчёты.
  8. Использование SL-модели: Для каждой пары создаётся своя SL-модель, которая отфильтровывает входы в сделку.

Особенности:

  • Модульность: Код хорошо структурирован с использованием функций и классов.
  • Гибкость: Код поддерживает различные таймфреймы и валютные пары.
  • Параллелизация: Используется многоядерный процессор для ускорения расчетов.
  • Визуализация: Генерирует различные графики для анализа результатов.
  • Оптимизация: Использует генетический алгоритм для автоматической настройки параметров стратегии.
  • Стоп-лосс модель: Используется модель машинного обучения для фильтрации входов на основе истории SL-срабатываний.
  • Проверка на стационарность: Используется тест Дики-Фуллера для приведения временных рядов к стационарному виду.
  • Выбросы: Для фильтрации выбросов, оставляются только значения, которые не выходят за пределы трех стандартных отклонений от среднего.
Автоматическая оптимизация советника в MetaTrader 5
Автоматическая оптимизация советника в MetaTrader 5
  • www.mql5.com
В данной статье описана реализация механизма самооптимизации работающего эксперта в MetaTrader 5.
 
Код на Python:
import logging
import os
import sys
import MetaTrader5 as mt5
import pandas as pd
import numpy as np
import matplotlib
  • import logging: Импортирует модуль logging для записи событий и отладочной информации.

  • import os: Импортирует модуль os для взаимодействия с операционной системой, например, создания каталогов.

  • import sys: Импортирует модуль sys, который предоставляет доступ к некоторым переменным и функциям, используемым интерпретатором Python.

  • import MetaTrader5 as mt5: Импортирует модуль MetaTrader5 для взаимодействия с платформой MetaTrader 5 (обычно для получения данных о торговле). Переименован в mt5 для краткости.

  • import pandas as pd: Импортирует библиотеку pandas для работы с табличными данными. Переименован в pd для краткости.

  • import numpy as np: Импортирует библиотеку numpy для работы с массивами и математическими операциями. Переименован в np для краткости.

  • import matplotlib: Импортирует модуль matplotlib, основную библиотеку для построения графиков.

# Use a non-interactive backend for matplotlib
matplotlib.use('Agg')
  • matplotlib.use('Agg'): Устанавливает неинтерактивный бэкенд Agg для matplotlib. Это позволяет сохранять графики в файлы без необходимости отображения на экране.

import matplotlib.pyplot as plt
import time
import mplfinance as mpf  # For candlestick charts
from datetime import datetime
from deap import base, creator, tools, algorithms
import random
import warnings
from multiprocessing import cpu_count
from functools import partial
import gc
  • import matplotlib.pyplot as plt: Импортирует модуль pyplot из matplotlib для создания графиков. Переименован в plt для краткости.

  • import time: Импортирует модуль time для работы со временем.

  • import mplfinance as mpf: Импортирует библиотеку mplfinance для построения графиков свечей (candlestick). Переименован в mpf для краткости.

  • from datetime import datetime: Импортирует класс datetime из модуля datetime для работы с датами и временем.

  • from deap import base, creator, tools, algorithms: Импортирует классы и функции для использования генетических алгоритмов из библиотеки deap.

  • import random: Импортирует модуль random для генерации случайных чисел.

  • import warnings: Импортирует модуль warnings для управления предупреждениями.

  • from multiprocessing import cpu_count: Импортирует функцию cpu_count из модуля multiprocessing для получения количества доступных ядер процессора.

  • from functools import partial: Импортирует функцию partial из модуля functools для создания функций с предопределенными аргументами.

  • import gc: Импортирует модуль gc для сборки мусора.

import xgboost as xgb
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import cross_val_score, train_test_split, StratifiedKFold
from sklearn.metrics import (
    mean_squared_error,
    mean_absolute_error,
    r2_score,
    mean_absolute_percentage_error,
    classification_report,
    roc_auc_score
)
  • import xgboost as xgb: Импортирует библиотеку xgboost для градиентного бустинга. Переименован в xgb для краткости.

  • from sklearn.preprocessing import MinMaxScaler: Импортирует класс MinMaxScaler из sklearn для масштабирования признаков.

  • from sklearn.model_selection import cross_val_score, train_test_split, StratifiedKFold: Импортирует функции для кросс-валидации, разделения данных на обучающую и тестовую выборки, а также стратифицированной кросс-валидации из библиотеки sklearn.

  • from sklearn.metrics import ( ... ): Импортирует метрики оценки моделей из sklearn:

    • mean_squared_error: Среднеквадратичная ошибка.

    • mean_absolute_error: Средняя абсолютная ошибка.

    • r2_score: Коэффициент детерминации (R-квадрат).

    • mean_absolute_percentage_error: Средняя абсолютная процентная ошибка.

    • classification_report: Отчёт о классификации.

    • roc_auc_score: ROC AUC score.

from ta.volatility import AverageTrueRange, BollingerBands
from ta.momentum import RSIIndicator, StochasticOscillator, WilliamsRIndicator, ROCIndicator
from ta.trend import MACD, EMAIndicator, CCIIndicator, ADXIndicator, IchimokuIndicator
  • from ta.volatility import ...: Импортирует классы для расчёта индикаторов волатильности из библиотеки ta:

    • AverageTrueRange: Средний истинный диапазон.

    • BollingerBands: Полосы Боллинджера.

  • from ta.momentum import ...: Импортирует классы для расчёта индикаторов моментума из библиотеки ta:

    • RSIIndicator: Индикатор относительной силы (RSI).

    • StochasticOscillator: Стохастический осциллятор.

    • WilliamsRIndicator: Индикатор Вильямса %R.

    • ROCIndicator: Индикатор скорости изменения цены (ROC).

  • from ta.trend import ...: Импортирует классы для расчёта индикаторов тренда из библиотеки ta:

    • MACD: Схождение-расхождение скользящих средних (MACD).

    • EMAIndicator: Экспоненциальная скользящая средняя (EMA).

    • CCIIndicator: Индекс товарного канала (CCI).

    • ADXIndicator: Индекс среднего направления движения (ADX).

    • IchimokuIndicator: Индикатор Ишимоку.

from sklearn.ensemble import StackingRegressor, RandomForestRegressor, GradientBoostingRegressor
from sklearn.linear_model import LinearRegression
import joblib
import seaborn as sns
import shap
from statsmodels.tsa.stattools import adfuller
from tabulate import tabulate
  • from sklearn.ensemble import ...: Импортирует классы для ансамблевых моделей из sklearn:

    • StackingRegressor: Регрессор стекинга.

    • RandomForestRegressor: Регрессор случайного леса.

    • GradientBoostingRegressor: Регрессор градиентного бустинга.

  • from sklearn.linear_model import LinearRegression: Импортирует класс LinearRegression для линейной регрессии.

  • import joblib: Импортирует библиотеку joblib для сохранения и загрузки моделей.

  • import seaborn as sns: Импортирует библиотеку seaborn для создания статистических графиков.

  • import shap: Импортирует библиотеку shap для интерпретации результатов машинного обучения.

  • from statsmodels.tsa.stattools import adfuller: Импортирует функцию adfuller из библиотеки statsmodels для теста Дики-Фуллера (теста на стационарность временных рядов).

  • from tabulate import tabulate: Импортирует функцию tabulate из библиотеки tabulate для создания таблиц в текстовом формате.

 
warnings.filterwarnings('ignore')
  • warnings.filterwarnings('ignore'): Отключает отображение предупреждений, что может быть полезно для предотвращения засорения вывода.

# --------------------- Logging Configuration ---------------------
class ExcludeInfoFilter(logging.Filter):
    def filter(self, record):
        exclude_keywords = ['Classification Report', 'ROC AUC Score']
        return not any(keyword in record.getMessage() for keyword in exclude_keywords)
  • class ExcludeInfoFilter(logging.Filter):: Определяется класс ExcludeInfoFilter, который наследуется от logging.Filter.

  • def filter(self, record):: Определяется метод filter внутри класса, который будет фильтровать записи журнала.

  • exclude_keywords = ['Classification Report', 'ROC AUC Score']: Список ключевых слов, по которым будет производиться фильтрация.

  • return not any(keyword in record.getMessage() for keyword in exclude_keywords): Возвращает True, если сообщение журнала не содержит ни одного из ключевых слов, и False в противном случае, эффективно исключая эти записи из журнала.

# Remove existing handlers if any
for handler in logging.root.handlers[:]:
    logging.root.removeHandler(handler)
  • for handler in logging.root.handlers[:]: Итерируется по копии списка обработчиков журнала logging.root, чтобы избежать проблем при изменении списка в процессе итерации.

  • logging.root.removeHandler(handler): Удаляет каждый обработчик журнала из корня, чтобы начать с чистой конфигурации.

# Create logger
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)  # Capture all logs
  • logger = logging.getLogger(): Создает экземпляр объекта логгера.

  • logger.setLevel(logging.DEBUG): Устанавливает уровень журнала на DEBUG, что означает, что все сообщения уровня DEBUG и выше будут записаны.

# Create FileHandler
file_handler = logging.FileHandler("strategy_optimization.log")
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(message)s'))
  • file_handler = logging.FileHandler("strategy_optimization.log"): Создает обработчик журнала FileHandler, который будет записывать сообщения в файл strategy_optimization.log.

  • file_handler.setLevel(logging.DEBUG): Устанавливает уровень обработчика файла на DEBUG, что соответствует уровню логгера.

  • file_handler.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')): Устанавливает формат сообщений журнала, который включает:

    • %(asctime)s: Время создания записи.

    • %(levelname)s: Уровень сообщения (DEBUG, INFO, WARNING, ERROR, CRITICAL).

    • %(message)s: Само сообщение.

# Create StreamHandler
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.setLevel(logging.INFO)
stream_handler.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(message)s'))
stream_handler.addFilter(ExcludeInfoFilter())
  • stream_handler = logging.StreamHandler(sys.stdout): Создает обработчик журнала StreamHandler, который будет выводить сообщения в стандартный вывод (консоль).

  • stream_handler.setLevel(logging.INFO): Устанавливает уровень обработчика консоли на INFO, что означает, что только сообщения уровня INFO и выше будут выведены в консоль.

  • stream_handler.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')): Устанавливает формат сообщений журнала для консоли.

  • stream_handler.addFilter(ExcludeInfoFilter()): Добавляет фильтр ExcludeInfoFilter к обработчику консоли, чтобы не выводить сообщения, содержащие 'Classification Report' и 'ROC AUC Score' в консоль.

logger.addHandler(file_handler)
logger.addHandler(stream_handler)
  • logger.addHandler(file_handler): Добавляет file_handler к логгеру.

  • logger.addHandler(stream_handler): Добавляет stream_handler к логгеру.

# --------------------- Parameters and Global Variables ---------------------
start_date = datetime(2015, 1, 1)
end_date = datetime.today()
split_date = datetime(2021, 1, 1)

backtest_start_date = datetime(2022, 1, 1)
backtest_end_date = datetime.today()
  • start_date = datetime(2015, 1, 1): Устанавливает начальную дату для загрузки данных.

  • end_date = datetime.today(): Устанавливает конечную дату для загрузки данных (сегодняшний день).

  • split_date = datetime(2021, 1, 1): Устанавливает дату разделения данных на обучающую и тестовую выборки.

  • backtest_start_date = datetime(2022, 1, 1): Устанавливает начальную дату для бэктестинга.

  • backtest_end_date = datetime.today(): Устанавливает конечную дату для бэктестинга.

transaction_cost = 0.0002
slippage = 0.0001
risk_free_rate = 0.02 / 252
time_steps = 30
  • transaction_cost = 0.0002: Устанавливает стоимость транзакции (комиссия) как 0.02%.

  • slippage = 0.0001: Устанавливает проскальзывание как 0.01%.

  • risk_free_rate = 0.02 / 252: Устанавливает годовую безрисковую ставку как 0.02, разделённую на 252 (количество торговых дней в году).

  • time_steps = 30: Задает количество временных шагов (вероятно, используется для какого-то расчета).

timeframes_to_process = [
    mt5.TIMEFRAME_D1,
]
  • timeframes_to_process = [mt5.TIMEFRAME_D1]: Список таймфреймов для обработки. Здесь указан только дневной таймфрейм mt5.TIMEFRAME_D1.

show_plots = True
my_directory = '1BBa'
plot_base_dir = "plots"
current_date = datetime.today().strftime('%Y-%m-%d')
num_cores_to_use = 6
currency_pairs = ["AUDUSD"]
  • show_plots = True: Флаг, указывающий на необходимость отображения графиков.

  • my_directory = '1BBa': Имя каталога, который будет использоваться для сохранения результатов.

  • plot_base_dir = "plots": Базовый каталог для сохранения графиков.

  • current_date = datetime.today().strftime('%Y-%m-%d'): Текущая дата в формате YYYY-MM-DD для создания подкаталогов.

  • num_cores_to_use = 6: Количество ядер процессора, которые будут использоваться для параллельных вычислений.

  • currency_pairs = ["AUDUSD"]: Список валютных пар, которые будут анализироваться. Здесь только пара AUDUSD.

timeframes_dict = {
    mt5.TIMEFRAME_M1: "M1",
    mt5.TIMEFRAME_M2: "M2",
    mt5.TIMEFRAME_M3: "M3",
    mt5.TIMEFRAME_M4: "M4",
    mt5.TIMEFRAME_M5: "M5",
    mt5.TIMEFRAME_M6: "M6",
    mt5.TIMEFRAME_M10: "M10",
    mt5.TIMEFRAME_M12: "M12",
    mt5.TIMEFRAME_M15: "M15",
    mt5.TIMEFRAME_M20: "M20",
    mt5.TIMEFRAME_M30: "M30",
    mt5.TIMEFRAME_H1: "H1",
    mt5.TIMEFRAME_H2: "H2",
    mt5.TIMEFRAME_H3: "H3",
    mt5.TIMEFRAME_H4: "H4",
    mt5.TIMEFRAME_H6: "H6",
    mt5.TIMEFRAME_H8: "H8",
    mt5.TIMEFRAME_H12: "H12",
    mt5.TIMEFRAME_D1: "D1",
    mt5.TIMEFRAME_W1: "W1",
    mt5.TIMEFRAME_MN1: "MN1",
}
  • timeframes_dict = { ... }: Словарь, сопоставляющий константы таймфреймов из MetaTrader5 с их строковыми представлениями.

ga_base_seed = 41
ga_pop_size = 150
ga_num_generations = 10
ga_cxpb = 0.7
ga_mutpb = 0.2
ga_mutate_indpb = 0.3
ga_mate_indpb = 0.9
  • ga_base_seed = 41: Базовое случайное зерно для генетического алгоритма.

  • ga_pop_size = 150: Размер популяции для генетического алгоритма.

  • ga_num_generations = 10: Количество поколений для генетического алгоритма.

  • ga_cxpb = 0.7: Вероятность скрещивания (кроссовера) для генетического алгоритма.

  • ga_mutpb = 0.2: Вероятность мутации для генетического алгоритма.

  • ga_mutate_indpb = 0.3: Вероятность мутации одного гена в особи для генетического алгоритма.

  • ga_mate_indpb = 0.9: Вероятность обмена генами во время скрещивания для генетического алгоритма.

xgb_n_estimators = 200
xgb_max_depth = 20
xgb_learning_rate = 0.1
xgb_random_state = ga_base_seed
  • xgb_n_estimators = 200: Количество деревьев в XGBoost.

  • xgb_max_depth = 20: Максимальная глубина дерева в XGBoost.

  • xgb_learning_rate = 0.1: Скорость обучения для XGBoost.

  • xgb_random_state = ga_base_seed: Случайное зерно для XGBoost.

 
# Initialize DEAP framework
creator.create('FitnessMax', base.Fitness, weights=(1.0,))
creator.create('Individual', list, fitness=creator.FitnessMax)
  • creator.create('FitnessMax', base.Fitness, weights=(1.0,)): Создает класс FitnessMax для представления фитнеса (максимизация) с весом 1.0, используя функционал deap.

  • creator.create('Individual', list, fitness=creator.FitnessMax): Создает класс Individual, который является списком, с ассоциированным фитнесом типа FitnessMax, используя функционал deap.

sl_features = [
    'RSI', 'MACD', 'ATR', 'BB_High', 'BB_Low', 'EMA_14', 'SMA_14',
    'DayOfWeek', 'WeekOfYear', 'Month', 'ROC_14', 'Momentum_14',
    'WilliamsR', 'Ichimoku_A', 'Ichimoku_B', 'Corr_Close_RSI_14',
    'Return_Lag_1', 'Return_Lag_2', 'Return_Lag_3', 'RSI_MACD', 'ATR_Close',
    'Close_Stationary', 'High_Stationary', 'Low_Stationary'
]
  • sl_features = [ ... ]: Список фичей, используемых в модели прогнозирования Stop Loss (SL).

window_values_ga = np.arange(20, 252, 1)
multiplier_values_ga = np.arange(0.8, 3.0, 0.1)
tp_factor_values_ga = np.arange(1.2, 5.61, 0.05)
sl_factor_values_ga = np.arange(0.1, 1.21, 0.05)

sl_max_depth_values = [3, 5, 7]
sl_learning_rate_values = [0.01, 0.05, 0.1]
sl_n_estimators_values = [100, 200, 300]
  • window_values_ga = np.arange(20, 252, 1): Диапазон значений для окна (window) генетического алгоритма, созданный с помощью numpy.arange.

  • multiplier_values_ga = np.arange(0.8, 3.0, 0.1): Диапазон значений для мультипликатора генетического алгоритма.

  • tp_factor_values_ga = np.arange(1.2, 5.61, 0.05): Диапазон значений для фактора тейк-профита (take-profit) генетического алгоритма.

  • sl_factor_values_ga = np.arange(0.1, 1.21, 0.05): Диапазон значений для фактора стоп-лосса (stop-loss) генетического алгоритма.

  • sl_max_depth_values = [3, 5, 7]: Список возможных значений для максимальной глубины дерева в модели stop-loss.

  • sl_learning_rate_values = [0.01, 0.05, 0.1]: Список возможных значений для скорости обучения в модели stop-loss.

  • sl_n_estimators_values = [100, 200, 300]: Список возможных значений для количества деревьев в модели stop-loss.

window_values_ga_list = window_values_ga.tolist()
multiplier_values_ga_list = multiplier_values_ga.tolist()
tp_factor_values_ga_list = tp_factor_values_ga.tolist()
sl_factor_values_ga_list = sl_factor_values_ga.tolist()

sl_max_depth_list = sl_max_depth_values
sl_learning_rate_list = sl_learning_rate_values
sl_n_estimators_list = sl_n_estimators_values
  • Преобразует numpy массивы в списки для удобства использования в генетическом алгоритме.

scaler_X_selected_dict = {}
pip_scale_factor = 100000
  • scaler_X_selected_dict = {}: Словарь для хранения Scaler'ов, используемых для масштабирования данных.

  • pip_scale_factor = 100000: Масштабирующий коэффициент для пипсов, значение по умолчанию 100000.

# --------------------- Helper Functions ---------------------
def get_conversion_rate(from_cur, to_cur):
    direct_symbol = to_cur + from_cur
    reverse_symbol = from_cur + to_cur

    symbol_info_direct = mt5.symbol_info(direct_symbol)
    if symbol_info_direct is not None:
        mt5.symbol_select(direct_symbol, True)
        tick = mt5.symbol_info_tick(direct_symbol)
        if tick is not None:
            if direct_symbol.startswith(to_cur):
                rate = 1.0 / tick.ask
                return rate
            else:
                return tick.ask

    symbol_info_reverse = mt5.symbol_info(reverse_symbol)
    if symbol_info_reverse is not None:
        mt5.symbol_select(reverse_symbol, True)
        tick = mt5.symbol_info_tick(reverse_symbol)
        if tick is not None:
            if reverse_symbol.startswith(to_cur):
                rate = 1.0 / tick.ask
                return rate
            else:
                return tick.ask

    return None
  • def get_conversion_rate(from_cur, to_cur):: Определяет функцию для получения обменного курса между двумя валютами.

  • direct_symbol = to_cur + from_cur: Строит прямое название символа (например, EURUSD).

  • reverse_symbol = from_cur + to_cur: Строит обратное название символа (например, USDEUR).

  • symbol_info_direct = mt5.symbol_info(direct_symbol): Получает информацию о символе из MetaTrader 5 для прямого символа.

  • Далее следует блок if для проверки, что информация получена, символ выбран и получена цена тика. Если да, то функция возвращает соответствующий курс.

  • Аналогичный блок if для обратного символа.

  • return None: Если курс не найден, функция возвращает None.

def apply_transformations(series):
    transformations = {}
    transformations['first_diff'] = series.diff().fillna(0)
    transformations['pct_change'] = series.pct_change().fillna(0)
    transformations['log'] = np.log(series.replace(0, np.nan)).fillna(0)
    return transformations
  • def apply_transformations(series):: Определяет функцию для применения различных преобразований к временному ряду.

  • transformations = {}: Инициализирует пустой словарь для хранения преобразованных рядов.

  • transformations['first_diff'] = series.diff().fillna(0): Вычисляет первую разность ряда и заполняет NaN значения нулями.

  • transformations['pct_change'] = series.pct_change().fillna(0): Вычисляет процентное изменение ряда и заполняет NaN значения нулями.

  • transformations['log'] = np.log(series.replace(0, np.nan)).fillna(0): Вычисляет логарифм ряда (с заменой 0 на NaN, чтобы избежать ошибки, и заполняет NaN значения нулями).

  • return transformations: Возвращает словарь с преобразованными рядами.

def replace_inf_nan(series):
    series = series.replace([np.inf, -np.inf], np.nan)
    series = series.fillna(method='ffill').fillna(method='bfill')
    return series
  • def replace_inf_nan(series):: Определяет функцию для замены бесконечностей и NaN значений в ряде.

  • series = series.replace([np.inf, -np.inf], np.nan): Заменяет бесконечности на NaN.

  • series = series.fillna(method='ffill').fillna(method='bfill'): Заполняет NaN значения методом ffill (заполнение последним валидным значением) и затем bfill (заполнение следующим валидным значением).

  • return series: Возвращает обработанный ряд.

def select_best_transformation(series, transformations):
    adf_results = {}
    for name, transformed_series in transformations.items():
        transformed_series_clean = transformed_series.dropna()
        if len(transformed_series_clean) < 10:
            adf_results[name] = 1.0
            continue
        result = adfuller(transformed_series_clean, autolag='AIC')
        adf_results[name] = result[1]

    stationary_transforms = {k: v for k, v in adf_results.items() if v < 0.05}
    if not stationary_transforms:
        logging.warning("No stationary transformation found. Using first_diff as default.")
        best_transform = 'first_diff'
    else:
        best_transform = min(stationary_transforms, key=stationary_transforms.get)

    best_series = transformations[best_transform]
    return best_transform, best_series
  • def select_best_transformation(series, transformations):: Определяет функцию для выбора лучшего преобразования, которое приводит временной ряд к стационарному.

  • adf_results = {}: Создаёт пустой словарь для хранения результатов теста Дики-Фуллера.

  • for name, transformed_series in transformations.items():: Итерируется по всем преобразованиям.

  • transformed_series_clean = transformed_series.dropna(): Очищает преобразованный ряд от NaN значений.

  • if len(transformed_series_clean) < 10:: Если длина ряда меньше 10, то результат adf записывается в словарь как 1.0, переходим к следующему преобразованию.

  • result = adfuller(transformed_series_clean, autolag='AIC'): Выполняет тест Дики-Фуллера на стационарность, используя параметр autolag='AIC' для автоматического выбора лага.

  • adf_results[name] = result[1]: Записывает p-value из результатов теста в словарь.

  • stationary_transforms = {k: v for k, v in adf_results.items() if v < 0.05}: Создаёт словарь только стационарных преобразований, где p-value меньше 0.05.

  • if not stationary_transforms:: Если нет стационарных преобразований, то выбирается первая разность first_diff как значение по умолчанию.

  • else: best_transform = min(stationary_transforms, key=stationary_transforms.get): В противном случае выбирается преобразование с минимальным p-value.

  • best_series = transformations[best_transform]: Получает преобразованный ряд.

  • return best_transform, best_series: Возвращает название лучшего преобразования и сам ряд.

 
Из-за ограничений по длине текста разместить здесь весь код с комментариями невозможно.
Файлы:
 
Вы написали бы ещё рекомендуемые требования к компу для работы с Вашим кодом. Например, у меня двухядерный ноут. Я установил оболочку для Питона, импортировал в программу пару десятков строк из csv-файла и дал комманду на отрисовку файермэпа. Питон отрисовал. Но увидев, насколько долго шёл процесс, я понял, что для Пайтона нужно железо посерьёзнее моего. Пришлось отложить Пайтон в долгий ящик. Думаю, что не каждый желающий имеет железо для нормальной работы с Вашим кодом.
Какие должны быть требования к компу, как считаете?
 
Vitaly Murlenko #:
Вы написали бы ещё рекомендуемые требования к компу для работы с Вашим кодом. Например, у меня двухядерный ноут. Я установил оболочку для Питона, импортировал в программу пару десятков строк из csv-файла и дал комманду на отрисовку файермэпа. Питон отрисовал. Но увидев, насколько долго шёл процесс, я понял, что для Пайтона нужно железо посерьёзнее моего. Пришлось отложить Пайтон в долгий ящик. Думаю, что не каждый желающий имеет железо для нормальной работы с Вашим кодом.
Какие должны быть требования к компу, как считаете?

CPU: 12th Gen Intel(R) Core(TM) i7-12700H
Memory: ~32GB
Это обычный старый ноутбук Dell G15 5520. Компьютер работает в теплых помещениях, со сбалансированным энергопотреблением. Один тест кода для данных D1 с 2015 по 21.12.2024. заняло время с 17:31:25 до 17:42:13. Да, это не быстро, но и не очень долго. Я думаю, что на более новых и стационарных компьютерах все происходит достаточно быстро.

C:\Users\user\PycharmProjects\pythonProject1_AI\.venv\Scripts\python.exe C:\Users\user\PycharmProjects\pythonProject1_AI\121_5_forex.py 
Starting main function...
MT5 initialized successfully.
2024-12-21 17:31:25,472 [INFO] Using 20 cores for multiprocessing.
2024-12-21 17:31:25,473 [INFO] 
Processing timeframe: D1
2024-12-21 17:31:25,473 [INFO] 
Loading and processing data for pair: AUDUSD
2024-12-21 17:31:25,473 [INFO] Loading data for AUDUSD from MT5...
2024-12-21 17:31:25,475 [INFO] 
Optimizing strategy for pair: AUDUSD
2024-12-21 17:32:12,201 [INFO] Using AUDUSD digits = 5. Point: 0.00001
2024-12-21 17:32:12,201 [INFO] Conversion rate from AUD to EUR: 0.5993658709085787
2024-12-21 17:32:12,205 [INFO] Using AUDUSD digits = 5. Point: 0.00001
2024-12-21 17:32:12,205 [INFO] Conversion rate from AUD to EUR: 0.5993658709085787
2024-12-21 17:32:12,620 [INFO] Initial Population Size: 150
2024-12-21 17:32:12,620 [INFO] Starting genetic algorithm optimization for Ensemble Predictions Close - GA Optimization...
2024-12-21 17:32:30,781 [INFO] Ensemble Predictions Close - GA Optimization - Generation 0: Max nan, Avg nan
2024-12-21 17:32:30,781 [INFO] Generation 0: No improvement. Patience remaining: 9
2024-12-21 17:32:47,229 [INFO] Ensemble Predictions Close - GA Optimization - Generation 1: Max 0.11610534798557089, Avg 0.06286744598243656
2024-12-21 17:32:47,229 [INFO] Generation 1: Improvement found. Resetting patience.
...
2024-12-21 17:42:10,740 [INFO] Ensemble Predictions Close - GA Optimization - Generation 29: Max nan, Avg nan
2024-12-21 17:42:10,740 [INFO] Generation 29: No improvement. Patience remaining: 3
2024-12-21 17:42:10,740 [INFO] Final Population Size: 150
2024-12-21 17:42:10,741 [INFO] Best GA Individual: [24.0, 1.5999999999999999, 2.8500000000000014, 0.9500000000000003, 3.0, 0.05, 300.0]
2024-12-21 17:42:10,893 [INFO] Best GA Individual Strategy Evaluation Complete.
2024-12-21 17:42:13,815 [INFO] Ensemble Model Performance for AUDUSD (D1):
2024-12-21 17:42:13,815 [INFO] MSE: 0.0000
2024-12-21 17:42:13,815 [INFO] MAE: 0.0038
2024-12-21 17:42:13,815 [INFO] R² Score: 0.9661
2024-12-21 17:42:13,815 [INFO] MAPE: 0.0057
2024-12-21 17:42:13,963 [INFO] MT5 shutdown successfully.
MT5 shutdown successfully.

Process finished with exit code 0


 
мде, в онлифанс явно 
 
Lilita Bogachkova #:

CPU: 12th Gen Intel(R) Core(TM) i7-12700H
Memory: ~32GB
Это обычный старый ноутбук Dell G15 5520. Компьютер работает в теплых помещениях, со сбалансированным энергопотреблением. Один тест кода для данных D1 с 2015 по 21.12.2024. заняло время с 17:31:25 до 17:42:13. Да, это не быстро, но и не очень долго. Я думаю, что на более новых и стационарных компьютерах все происходит достаточно быстро.


Ну вот открытая статистика пользователей.

https://cloud.mql5.com/ru/stats


Статистика - MQL5 Cloud Network
Статистика - MQL5 Cloud Network
  • cloud.mql5.com
Произведенный объем работы, распределение агентов по странам, RAM, CPU и битности OS
 

12th Gen Intel(R) Core(TM) i7-12700H - 14 ядер и 20 потоков,  базовая частота – 2300 МГц . + 32 гига оперативы. Ещё и хард SSD - я о таком могу только мечтать. И Вы говорите, что комп у Вас старенький?

У меня Intel(R) Core(TM) i3 CPU       M 330  @ 2.13GHz   2.13 GHz - Два ядра! Оператива = 4 гига. Хард имеет вращающийся диск.

 
Vitaly Murlenko #:

12th Gen Intel(R) Core(TM) i7-12700H - 14 ядер и 20 потоков,  базовая частота – 2300 МГц . + 32 гига оперативы. Ещё и хард SSD - я о таком могу только мечтать. И Вы говорите, что комп у Вас старенький?

У меня Intel(R) Core(TM) i3 CPU       M 330  @ 2.13GHz   2.13 GHz - Два ядра! Оператива = 4 гига. Хард имеет вращающийся диск.

Ноутбук старый, больше двух лет. Но, конечно, все зависит от того, какие возможности есть у каждого читателя форума.

Могу предложить исправления в коде, которые позволят сократить время работы генетического алгоритма, а значит и время использования ресурсов ПК.

В этом коде:

window_values_ga = np.arange(20, 252, 1)

multiplier_values_ga = np.arange(0.8, 3.0, 0.1)

tp_factor_values_ga = np.arange(1.2, 5.61, 0.05)

sl_factor_values_ga = np.arange(0.1, 1.21, 0.05)


внести изменения - уменьшить диапазон и шаг, например

window_values_ga = np.arange(20, 100, 1)

multiplier_values_ga = np.arange(0.8, 2.0, 0.1)

tp_factor_values_ga = np.arange(1.2, 4.00, 0.1)

sl_factor_values_ga = np.arange(0.1, 1.21, 0.1)

Если вы используете таймфрейм D1, эти параметры в большей степени будут соответствовать ожидаемому результату.


А вот для меньших таймфреймов нужно увеличить значения окна и множителя, например:

window_values_ga = np.arange(50, 300, 1)

multiplier_values_ga = np.arange(1.5, 5.0, 0.1)

tp_factor_values_ga = np.arange(1.2, 4.00, 0.1)

sl_factor_values_ga = np.arange(0.1, 1.21, 0.1)

но это будет очень ресурсоемко.

В любом случае вы всегда можете увеличить шаг (0.15; 0.2; 0.25; ...), что соответственно ускорит процесс.

+ + +

«базовая частота – 2300 МГц». Это неправда, хоть Интел и пишет, что базовый множитель равен 23, но на самом деле базовый множитель для этих процессоров равен 27. Если отредактировать «UEFI», то можно повысить как базовый множитель, так и увеличить потребляемую мощность в ваттах при сохранении тактовой частоты, без сильного троттлинга.

Как вы можете видеть на прикрепленном изображении, этот процессор работал с множителем 27 с выключенным турбо.