English Deutsch 日本語
preview
Машинное обучение и Data Science (Часть 41): YOLOv8v для поиска паттернов на рынках Forex и акций

Машинное обучение и Data Science (Часть 41): YOLOv8v для поиска паттернов на рынках Forex и акций

MetaTrader 5Торговые системы |
114 0
Omega J Msigwa
Omega J Msigwa

Содержание


Введение

Выявление паттернов на финансовых рынках — сложная задача для моделей машинного обучения и искусственного интеллекта. Как бы легко это ни казалось нам, людям, машине требуется приложить определенные усилия, чтобы обнаружить и интерпретировать эти паттерны, просто потому что, в отличие от табличных данных, которые обычно используются в торговле, поиск паттернов распространяется и на двумерные изображения, которые обычно хранятся в форматах .png, .jpg и т. д.

Существует огромное количество трейдеров со стратегиями, основанными на анализе ценового движения (price action) и конкретных графических паттернах на рынках, таких как:

  • Восходящая и нисходящая лестница
  • Восходящий треугольник
  • Нисходящий треугольник
  • Симметричный треугольник
  • Флаг 
  • Клин
  • Двойная вершина
  • Двойное дно
  • Голова и плечи
  • Скругленная вершина или дно
  • Чашка с ручкой
  • и многие другие.

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

Для определения даже простого паттерна, например W-дно, потребуется сложный, хорошо написанный и оптимизированный код. Так почему бы не попытаться справиться с этой задачей с помощью ИИ?

Чтобы решить эту проблему с использованием искусственного интеллекта (AI), в данной статье мы рассмотрим весьма интересную модель под названием YOLOv8, с которой я познакомился на сайте huggingface.co.

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

Для понимания содержания данной статьи требуется базовое понимание машинного обучения и языка программирования Python.


Что такое YOLOv8?

Согласно документации,

YOLOv8s — это модель обнаружения объектов, основанная на фреймворке YOLO (You Only Look Once). Данная модель предназначена для определения различных графических паттернов в режиме реального времени на основе данных о биржевых сделках, полученных с экрана компьютера.

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

Модель была дообучена на разнообразном наборе данных и демонстрирует высокую точность при поиске и классификации паттернов фондового рынка в условиях реальной торговли.

На текущий момент модель способна точно распознавать несколько паттернов, включая:

Голова и плечи

Голова и плечи

Краткое описание паттерна

Данный паттерн указывает на возможный разворот рынка.

Считается, что три последовательности вершин и впадин, когда при этом средний пик выше остальных, свидетельствуют о том, что цена акции начнет снижаться.

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

Перевернутая голова и плечи

Это противоположный вариант паттерна "голова и плечи"

Паттерн двойной вершины M:

Паттерн двойной вершины M

Краткое описание паттерна

Также известен как "двойная вершина" (double top). Это паттерн, формирующийся из двух последовательных скругленных вершин.

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

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

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

Паттерн двойного дна W:

Паттерн двойного дна W

Работает аналогично паттерну двойной вершины M, но в противоположном направлении, подробнее.

Паттерн Stock Line

Мне не удалось найти упоминаний о нем ни в документации, ни в интернете — пока пропустим его.

Паттерны треугольников:

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

Треугольники используют для определения момента сужения торгового диапазона акции или другого финансового инструмента после нисходящего или восходящего тренда. Подробнее.


Получение графических паттернов из MetaTrader 5

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

К счастью, MetaTrader 5 и язык программирования MQL5 предоставляют функциональность для создания скриншотов любого выбранного графика и торгового символа. Соберем несколько изображений с помощью скрипта.

Файл ChartScreenshots.mq5

#property script_show_inputs 

input uint BarsToCapture = 1000; //Total Bars
input uint BarsShift = 50; //Bars Shift
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
//--- Save current chart position

    long firstVisibleBar = ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR);
    long chartShift = ChartGetInteger(0, CHART_SHIFT);
    double priceMax = ChartGetDouble(0, CHART_PRICE_MAX);
    double priceMin = ChartGetDouble(0, CHART_PRICE_MIN);
    
//--- Set chart properties for clean screenshots

    ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, true);
    ChartSetInteger(0, CHART_SHOW_DATE_SCALE, true);
    ChartSetInteger(0, CHART_SHOW_GRID, false); // Disable grid for cleaner images
    ChartSetInteger(0, CHART_SHOW_VOLUMES, false);
    ChartSetInteger(0, CHART_SHOW_TRADE_HISTORY, false);
    ChartSetInteger(0, CHART_AUTOSCROLL, false);  // prevent scrolling  
    
    int steps = (int)MathCeil((double)BarsToCapture / BarsShift);
    
    for(int i = 0; i < steps; i++)
    {
        // Shift chart view
        int shift = i * (int)BarsShift;
        ChartNavigate(0, CHART_END, -shift);
        
        // Wait a moment for the chart to update
        Sleep(500);
        
        // Take screenshot
        string filename = StringFormat("Screenshots\\%s.%s.%d.png", Symbol(), EnumToString(Period()), i+1);
        
        FileDelete(filename); //we delete a previous screenshot with the same name
        if(!ChartScreenShot(0, filename, 640, 480, ALIGN_CENTER))
         {
            printf("Failed to take screenshot #:%d Error = %d", i+1, GetLastError());
            continue;
         }
        else
         {
            printf("Screenshot saved: %s", filename);
         }
    }

//--- Restore original chart position

    ChartNavigate(0, CHART_END, -(int)firstVisibleBar);
    ChartSetDouble(0, CHART_PRICE_MAX, priceMax);
    ChartSetDouble(0, CHART_PRICE_MIN, priceMin);
    ChartSetInteger(0, CHART_SHIFT, chartShift);
}

Эта функция делает несколько скриншотов текущего графика на протяжении 1000 баров (по умолчанию), сдвигаясь на 50 баров (по умолчанию) назад относительно предыдущего скриншота.

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

    ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, true);
    ChartSetInteger(0, CHART_SHOW_DATE_SCALE, true); // Showing the timescale on a chart
    ChartSetInteger(0, CHART_SHOW_GRID, false); // Disable grid for cleaner images
    ChartSetInteger(0, CHART_SHOW_VOLUMES, false); //Prevent displaying the tick volumes
    ChartSetInteger(0, CHART_SHOW_TRADE_HISTORY, false); //Prevent drawing arrows that displays trading history
    ChartSetInteger(0, CHART_AUTOSCROLL, false);  // prevent scrolling  

Все скриншоты будут сохраняться в папке MQL5\Files\Screenshots.


Использование YOLOv8 для поиска паттернов

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

    Установка

    $pip install ultralytics

    Начало

    from ultralytics import YOLOvv8
    
    model = YOLOvv8.from_pretrained("foduucom/stockmarket-pattern-detection-yolov8")
    source = 'http://images.cocodataset.org/val2017/000000039769.jpg'
    model.predict(source=source, save=True)

    Однако в вашей среде выполнения этот код вызовет ошибки, поскольку в настоящее время в библиотеке ultralytics отсутствует YOLOvv8 (документация несколько устарела). Ниже приведен корректный способ.

    Сначала необходимо импортировать объект YOLO и инициализировать его обученной моделью для данной задачи.

    from ultralytics import YOLO
    import os
    
    model = YOLO(os.path.join('Models','model.pt'))

    Файл model.pt можно найти здесь. После загрузки сохраните его в подпапке с именем Models в текущем рабочем каталоге.

    После этого необходимо вызвать метод predict объекта модели и передать ему имя изображения — и всё, вы получите предсказанный результат :).

    model.predict("image_name.png", save=True)

    При параметре save=True модель сохраняет итоговое изображение с выделенными на нем обнаруженными паттернами.

    Однако это слишком простой и недостаточно гибкий подход. Создадим класс-обертку для данного предиктора, чтобы обеспечить надежный и устойчивый код для анализа и предсказания по нескольким изображениям из папки, в которой хранятся наши скриншоты.

    Кроме того, нам необходимо реализовать оптимальный способ обработки предсказаний и визуализации результатов.

    Обнаружение паттернов на одном изображении

    Конструктор нашего класса принимает на вход объект модели YOLO и папку с изображениями, содержащую все скриншоты, полученные из MetaTrader 5.

    class YOLOv8deploy:
        
        def __init__(self, model: YOLO, images_folder: str):
            
            """A simple class for deploying YOLOv8 model for detecting trading patterns in chart images
    
            Args:
                model (YOLO): YOLO model object
                images_folder (str): A path where images will be imported from
            """
            
            self.model = model
            self.images_folder = images_folder

    Нам также потребуется функция внутри класса для получения всех изображений, находящихся в указанной папке.

    Эта функция будет полезна при выполнении множественных предсказаний, так как она позволит определить количество доступных изображений в папке, возвращая кортеж, содержащий общее число изображений и их имена в виде списка Python.

    def _get_images(self, folder: str, img_extensions: list=['*.png', '*.jpg', '*.jpeg']) -> tuple: 
            
       """ A function to help us detect the number of images present in a folder
    
       Args:
           folder (str): A path where images are located
           img_extensions (list, optional): Image filenames extensions. Defaults to ['*.png', '*.jpg', '*.jpeg'].
    
       Returns:
           tuple: Returns the number of images present in a folder and their names
       """
            
       image_files = []
       for ext in img_extensions:
           image_files.extend(glob.glob(os.path.join(folder, ext)))
    
       return (len(image_files), image_files) # Get the number of images and their names

    Расширим функцию predict так, чтобы она могла выполнять предсказание для одного изображения. Эта функция также должна предоставлять информацию о найденных паттернах и уровне уверенности (confidence) для каждого из них.

    def predict_image(self, img_name: str, hist: bool=True):
            
       """This function predicts a single image
    
       Args:
           img_name (str): name of the image
           hist (bool, optional): When set to false it means the function isn't predicting multiple instances and the outcome will be displayed.
                
           Defaults to True.
       """
            
       if os.path.exists(img_name) == False: # Check if an image exists
           print(f"Failed to detect patterns, {img_name} not found")
           return
            
       results = self.model.predict(source=img_name, save=True) # Predict an image 
    
       # Loop through the results
       for result in results:
           boxes = result.boxes  # Contains bounding boxes and confidence
           names = result.names  # Class index to name mapping
    
           if boxes is not None and len(boxes) > 0:
               for box in boxes:
                   cls_id = int(box.cls[0])  # class id
                   conf = box.conf[0].item()  # confidence score
                   label = names[cls_id]
                        
                   print(f"Detected: {label} (confidence: {conf:.2f})")
                        
                   # Open the saved image if this is a single (non-historical) run
                        
               if not hist:
                   base_name = os.path.splitext(os.path.basename(img_name))[0] + ".jpg"
                   saved_path = os.path.join(result.save_dir, base_name)
                        
                   print("saved path: ",saved_path)
                        
                   if os.path.exists(saved_path):
                       print(f"Opening detected image: {saved_path}")
                       img = cv2.imread(saved_path)
                       cv2.imshow("Detected Patterns", img)
                       cv2.waitKey(0)
                       cv2.destroyAllWindows()
           else:
               print("No detections.")
    

    Функция predict от модели YOLOv8 возвращает словарь, содержащий информацию о прямоугольной рамке (bounding box), которая затем отображается на изображении. Эта рамка оборачивает обнаруженный паттерн и добавляет уровень уверенности (confidence) для конкретного распознанного графического паттерна.

    После извлечения этой информации мы выводим ее в консоль Python или в командную строку (Command Prompt, CMD).

    В конце функции, когда параметр hist установлен в значение False, используется модуль cv2 для отображения предсказанного результата в отдельном диалоговом окне.

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

    Пример.

    images_path = r"C:\Users\Omega Joctan\AppData\Roaming\MetaQuotes\Terminal\F4F6C6D7A7155578A6DEA66D12B1D40D\MQL5\Files\Screenshots" # Change this for to the right path on your pc :)
    symbol = "EURUSD"
    timeframe = "PERIOD_H1"
    imgs = 100
    
    pattern_detector = YOLOv8deploy(model=model, images_folder=images_path)
    
    pattern_detector.predict_image(img_name=os.path.join(images_path, f"{symbol}.{timeframe}.{11}.png"), 
                                   hist=False)
    

    У нас есть изображение, полученное с графика EURUSD.PERIOD_H1, с пометкой номера 11 внутри папки Screenshots, которое нужно визуализировать. 

    Исходное изображение.

    Ниже показан результат — изображение, сформированное моделью после вызова функции predict, показанное в отдельном окне.

    Обнаружение паттернов на нескольких изображениях

    После получения изображений из папки Screenshots мы проходим в цикле по каждому из них и передаем каждое изображение в функцию predict_image, которую мы только что создали.

    def predict_images(self):
       
       _, image_names = self._get_images(self.images_folder) # Get all images from a folder
    
       for image_name in image_names:
           self.predict_image(img_name=image_name)

    Теперь вызовем эту функцию для предсказания по нескольким собранным изображениям. Это похоже на тестирование на истории - мы передаем несколько исторических изображений, чтобы проверить, насколько данная модель является качественной.

    pattern_detector.predict_images()
    Результаты.

    Все предсказанные результаты и изображения, созданные моделью, можно найти в текущем рабочем каталоге в папке runs\predict*

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


    Предвзятость, риски и ограничения YOLOv8

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

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

    Масштаб графика также имеет значение: слишком крупный масштаб в MetaTrader 5 может привести к отображению неполных паттернов, а слишком мелкий — к появлению шума.

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

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

    Флуктуации могут приводить к ложным пробоям и аномальным паттернам. Модель неизбежно будет допускать ошибки на таких графиках и рынках.

    3. Модели будет сложно распознавать рыночные паттерны, недостаточно представленные в обучающем наборе данных.

    Следует избегать рынков и таймфреймов с неопределенными паттернами. Лучший способ получить от модели максимальную отдачу - это использовать ее на подходящих рынках.


    Поиск графических паттернов в MetaTrader 5 с помощью YOLOv8

    Как уже отмечалось, модель YOLOv8 работает с изображениями и выдает результат предсказания в формате изображения, что невозможно напрямую прочитать и интерпретировать в MQL5. Однако данный язык поддерживает работу с изображениями в формате bitmap (.BMP), что является хорошей отправной точкой.

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

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

    Для этого необходимо внести несколько изменений в наш Python-класс. Начнем с доработки функции predict, чтобы она сохраняла все изображения с прогнозами в определенный (единый) каталог.

    Файл: deploy.py

    def predict_image(self, img_name: str, save_path: str):
            
        """This function predicts a single image
    
        Args:
           img_name (str): name of the image
           hist (bool, optional): When set to false it means the function isn't predicting multiple instances and the outcome will be displayed.
                
           Defaults to True.
       """
            
       if os.path.exists(img_name) == False: # Check if an image exists
           print(f"Failed to detect patterns, {img_name} not found")
           return
            
       results = self.model.predict(source=img_name, 
                                    save=True,
                                    project=save_path,
                                    name="YOLOv8 Images",
                                    exist_ok=True
                                    ) # Predict an image 
                        
       # Loop through the results
       for result in results:
           boxes = result.boxes  # Contains bounding boxes and confidence
           names = result.names  # Class index to name mapping
    
           # Convert a jpg image to bmp suitable for MQL5 diplay purposes
                
           base_name = os.path.splitext(os.path.basename(img_name))[0] + ".jpg"
           saved_path = os.path.join(result.save_dir, base_name)        
    
           convert_jpg_to_bmp(saved_path, os.path.join(result.save_dir, os.path.splitext(os.path.basename(img_name))[0] + '.bmp'))
    
           if boxes is not None and len(boxes) > 0:
               for box in boxes:
                   cls_id = int(box.cls[0])  # class id
                   conf = box.conf[0].item()  # confidence score
                   label = names[cls_id]
                        
                   print(f"Detected: {label} (confidence: {conf:.2f})")
           else:
               print("No detections.")
    
    

    С возможностью сохранять изображения в указанную папку с помощью функции predict, мы можем сохранять все файлы в подпапке с именем YOLOv8 Images, созданной в родительском каталоге MQL5\Files.

    YOLOv8 создает изображения в формате JPEG или JPG. Чтобы иметь возможность использовать эти изображения в MetaTrader 5, необходимо преобразовать их в формат Bitmap (BMP). Ниже приведена функция для этой задачи.

    def convert_jpg_to_bmp(jpg_path, bmp_path):
        """
        Convert a JPG image to 24-bit RGB BMP format
        
        Args:
            jpg_path (str): Path to input JPG file
            bmp_path (str): Path to save output BMP file
        """
        try:
            # Open the JPG image
            with Image.open(jpg_path) as img:
                # Convert to RGB if not already (handles CMYK, grayscale, etc.)
                if img.mode != 'RGB':
                    img = img.convert('RGB')
                
                # Save as 24-bit BMP
                img.save(bmp_path, 'BMP')
                
            print(f"Successfully converted {jpg_path} to {bmp_path}")
            return True
        
        except Exception as e:
            print(f"Conversion failed: {str(e)}")
            return False

    Теперь рассмотрим, как можно определять и предсказывать паттерны, присутствующие на одном изображении.

    files_path = r"C:\Users\Omega Joctan\AppData\Roaming\MetaQuotes\Terminal\F4F6C6D7A7155578A6DEA66D12B1D40D\MQL5\Files"
    images_path = os.path.join(files_path, "Screenshots") # Change this for to the right path on your pc :)
    
    # ....
    # ....
    
    pattern_detector = YOLOv8deploy(model=model, images_folder=images_path)
    pattern_detector.predict_image(img_name=image_filename, save_path=files_path)

    Этот процесс можно автоматизировать. Через несколько минут после запуска наш скрипт должен считывать изображение из каталога MQL5\Files\Screenshots, выполнять предсказание и сохранять результат в папке MQL5\Files\YOLOv8 Images. Теперь подготовим корректную среду для развёртывания полученного изображения в формате Bitmap (.BMP) на графике MetaTrader 5.

    files_path = r"C:\Users\Omega Joctan\AppData\Roaming\MetaQuotes\Terminal\F4F6C6D7A7155578A6DEA66D12B1D40D\MQL5\Files"
    images_path = os.path.join(files_path, "Screenshots") # Change this for to the right path on your pc :)
    symbol = "EURUSD"
    timeframe = "PERIOD_H1"
    
    def scheduledYOLOv8Run():
            
        now = datetime.now() # Get the current local date and time
    
        # Extract current day and hour
    
        date = now.day
        current_day = now.weekday()  # e.g., 'Wednesday'
        current_hour = now.strftime("%H")  # e.g., '14' for 2 PM in 24-hour format
    
        image_filename = os.path.join(images_path, f"{symbol}.{timeframe}.{date}.{current_day+1}.{current_hour}.png")
    
        pattern_detector = YOLOv8deploy(model=model, images_folder=images_path)
    
        pattern_detector.predict_image(img_name=image_filename, 
                                        save_path=files_path)
    
        print(f"Processed image at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        
    
    # Schedule the pattern detection after every minute(s)
    
    schedule.every(1).minutes.do(scheduledYOLOv8Run)
    
    print("Scheduler started. Press Ctrl+C to stop.")
    
    # Run forever
    while True:
        schedule.run_pending()
        time.sleep(1)

    Теперь подготовим среду для развертывания полученного изображения в формате Bitmap (.BMP) на графике MetaTrader 5.

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

    Файл: YOLOv8 EA.mq5

    input uint chart_scale = 3;
    input uint timer_seconds = 60;
    
    int chart_width, chart_height;
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //---
       
       if (!EventSetTimer(timer_seconds))
         {
           printf("%s failed to set the timer, Error = %d",__FUNCTION__,GetLastError());
           return INIT_FAILED;
         }
    
        showBars(true);   
             
    //---
    
       return(INIT_SUCCEEDED);
      }

    Функция showBars отвечает за очищение и подготовку подходящего места на графике для создания скриншота.

    void showBars(bool show=true)
     { 
    //--- Cleaning the chart
    
        ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, true);
        ChartSetInteger(0, CHART_SHOW_DATE_SCALE, true);
        ChartSetInteger(0, CHART_SHOW_GRID, false); // Disable grid for cleaner images
        ChartSetInteger(0, CHART_SHOW_VOLUMES, false);
        ChartSetInteger(0, CHART_SHOW_TRADE_HISTORY, false);
        ChartSetInteger(0, CHART_AUTOSCROLL, true);  // prevent scrolling  
        ChartSetInteger(0, CHART_SHIFT, true);
        
        if (ChartGetInteger(0, CHART_SCALE) != chart_scale)
             ChartSetInteger(0, CHART_SCALE, chart_scale);
       
       if (show)
         {
             ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrWhite);
             ChartSetInteger(0, CHART_COLOR_FOREGROUND, clrBlack);
             ChartSetInteger(0, CHART_COLOR_CHART_UP, clrTomato);
             ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, clrTomato);
             ChartSetInteger(0, CHART_COLOR_CHART_DOWN, clrLightSeaGreen);
             ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrLightSeaGreen);
             ChartSetInteger(0, CHART_SHOW_ASK_LINE, true);
             ChartSetInteger(0, CHART_SHOW_BID_LINE, true);
             ChartSetInteger(0, CHART_COLOR_ASK, clrTurquoise);
         }
       else
         {
             ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrWhite);
             ChartSetInteger(0, CHART_COLOR_FOREGROUND, clrBlack);
             
             ChartSetInteger(0, CHART_COLOR_CHART_UP, clrWhite);
             ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, clrWhite);
             ChartSetInteger(0, CHART_COLOR_CHART_DOWN, clrWhite);
             ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrWhite);
             ChartSetInteger(0, CHART_SHOW_ASK_LINE, true);
             ChartSetInteger(0, CHART_SHOW_BID_LINE, true);
             ChartSetInteger(0, CHART_COLOR_ASK, clrTurquoise);
         }
         
       ChartRedraw();
     }

    Когда эта функция вызывается со значением false, все свойства графика (включая цвета японских свечей) устанавливаются равными цвету фона графика — таким образом все становится невидимым.

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

    Ниже приведена функция, которая преобразует изображение Bitmap (.BMP) в объект, а затем назначает его фоном текущего графика.

    //+------------------------------------------------------------------+
    //|       Function to set a BMP image as chart background            |
    //+------------------------------------------------------------------+
    bool chartBackGroundSet(string filename, int width, int height)
    {
        string obj_name = "background-img";
            
       if(!ObjectCreate(0,obj_name,OBJ_BITMAP_LABEL,0,0,0)) 
         { 
          printf("%s failed to create a bitmap in the chart window! Error = %s",__FUNCTION__,ErrorDescription(GetLastError())); 
          return(false); 
         } 
         
    //--- set the path to the image file 
       if(!ObjectSetString(0,obj_name,OBJPROP_BMPFILE, filename)) 
         { 
          printf("%s failed to load the image! Error = %s",__FUNCTION__,ErrorDescription(GetLastError())); 
          return(false); 
         } 
    
    //--- Position the image to cover the entire chart
    
        ObjectSetInteger(0, obj_name, OBJPROP_XDISTANCE, 0);
        ObjectSetInteger(0, obj_name, OBJPROP_YDISTANCE, 0);
        ObjectSetInteger(0, obj_name, OBJPROP_XSIZE, width);
        ObjectSetInteger(0, obj_name, OBJPROP_YSIZE, height);
        
    //--- Send the image to the background
    
        ObjectSetInteger(0, obj_name, OBJPROP_BACK, true);
        ObjectSetInteger(0, obj_name, OBJPROP_ZORDER, -1);
        
    //--- Make sure the object is visible
        ObjectSetInteger(0, obj_name, OBJPROP_SELECTABLE, false);
        ObjectSetInteger(0, obj_name, OBJPROP_HIDDEN, true);
        
    //--- Redraw the chart to see changes
    
        ChartRedraw(0);    
    //---
       return true;
    }

    Наконец, автоматизируем процесс создания скриншотов и их отправки в каталог Screenshots для последующего чтения нашим Python-скриптом. Также автоматизируем процесс чтения предсказанных изображений из папки YOLOv8 Images и процесс отрисовки изображения на графике MetaTrader 5.

    void OnTimer(void)
      {   
    //---
    
        showBars(true); //explicitly show the bars
        
        // Clear the objects before taking a screenshot
        ObjectsDeleteAll(0);
        ObjectsDeleteAll(0,0);
        
        if (takeScreenShot())
         {
           Print("Screen shot taken: ",TimeCurrent());
           Sleep(100);
         }
         
        chart_width = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
        chart_height = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS);
               
    //--- Take screenshot
        
        MqlDateTime time_struct;
        TimeToStruct(TimeLocal(), time_struct);
       
        string filename = StringFormat("\\Files\\YOLOv8 Images\\%s.%s.%d.%d.%d.bmp",Symbol(),EnumToString(Period()),time_struct.day, time_struct.day_of_week, time_struct.hour);
        string fileshort_name = filename;
        
        bool checkfile = false;
        if (StringReplace(fileshort_name, "\\Files\\","")>0)
          checkfile = true; //If the parent folder was removed we can proceed to check if a file exists before drawing an object
          
        if (checkfile)
         while (!FileIsExist(fileshort_name)) 
           {
             printf("%s not found",fileshort_name);
             return;
           }
            
    //--- Set the image with patterns detected to a chart
    
        if (!chartBackGroundSet(filename, chart_width, chart_height))
            return;
            
        showBars(false);
      }

    В завершение на графике EURUSD, PERIOD_H1 (тот же таймфрейм, что и в Python-скрипте) мы запустили советника. Python-скрипт был запущен, а таймер установлен на 60 секунд.

    После 60 секунд на графике EURUSD платформа MetaTrader 5 получила изображение от модели.


    Работает!

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

    Таким образом, изменение размера графика может на некоторое время нарушить процесс отрисовки изображения. Я рекомендую использовать метод, рассмотренный здесь, чтобы реализовать более устойчивый способ визуализации изображения в качестве фона графика.


    Заключительные мысли

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

    Хотя мы часто используем модели ИИ для автоматизации торговых стратегий, данная модель пока не является практичной для алгоритмической торговли, поскольку она генерирует изображения, которые на данный момент может интерпретировать только человек. Скорее, это интересный инструмент для поиска паттернов в ручной торговле. Чтобы использовать ее в алгоритмических стратегиях, можно реализовать соединение между Python и MetaTrader 5 для передачи сырых данных в текстовом или JSON-формате о состоянии модели и предсказаниях, возвращаемых методом predict.

    Всем удачи!

    Оставайтесь с нами и вносите свой вклад в разработку алгоритмов машинного обучения для языка MQL5 в этом GitHub-репозитории.


    Таблица вложений


    Имя файла и путь
    Описание и назначение
    Experts\YOLOv8 EA.mq5 Советник для сбора скриншотов с графика и добавления прогнозного изображения от YOLOv8 к текущему графику.
    Include\errordescription.mqh Библиотека для преобразования кодов ошибок, генерируемых в MetaTrader 5 и MQL5, из integer в удобочитаемые строки.
    Scripts\ChartScreenshots.mq5 Скрипт для создания исторических скриншотов с указанного графика в MetaTrader 5.
    YOLOv8 Proj\test.py Скрипт на Python для тестирования модели YOLOv8 на нескольких изображениях.
    YOLOv8 Proj\deploy.py Скрипт на Python для развертывания и непрерывного запуска модели YOLOv8.
    YOLOv8 Proj\requirements.txt Содержит все зависимости Python, используемые в проекте, и номера их версий.


    Перевод с английского произведен MetaQuotes Ltd.
    Оригинальная статья: https://www.mql5.com/en/articles/18143

    Прикрепленные файлы |
    Attachements.zip (1023.22 KB)
    Торговые инструменты на языке MQL5 (Часть 6): Динамическая голографическая панель с импульсной анимацией и элементами управления Торговые инструменты на языке MQL5 (Часть 6): Динамическая голографическая панель с импульсной анимацией и элементами управления
    В этой статье мы создаем динамическую голографическую панель на MQL5 для мониторинга инструментов и таймфреймов с помощью RSI, оповещений о волатильности и параметров сортировки. Добавляем анимацию импульсов, интерактивные кнопки и голографические эффекты, чтобы сделать инструмент визуально привлекательным и отзывчивым.
    Нейросети в трейдинге: Адаптивная факторная токенизация (Окончание) Нейросети в трейдинге: Адаптивная факторная токенизация (Окончание)
    Статья завершает перенос и интеграцию ключевых компонентов фреймворка MTmixAtt в архитектуру торговой модели для анализа рыночных данных. Продемонстрировано, как адаптивная токенизация и блоки MTmixAttBlock позволяют эффективно выявлять локальные и глобальные паттерны, учитывать сценарии поведения цены.
    Особенности написания экспертов Особенности написания экспертов
    Написание и тестирование экспертов в торговой системе MetaTrader 4.
    Создание самооптимизирующихся советников на MQL5 (Часть 7): Одновременная торговля на нескольких периодах Создание самооптимизирующихся советников на MQL5 (Часть 7): Одновременная торговля на нескольких периодах
    В этой серии статей мы рассмотрели несколько различных способов определения наилучшего периода для использования наших технических индикаторов. Сегодня мы покажем, как применить противоположную логику, то есть, вместо выбора единственного наиболее подходящего периода, мы покажем, как эффективно использовать все доступные периоды. Такой подход сокращает объем отбрасываемых данных и предлагает альтернативные варианты использования алгоритмов машинного обучения, выходящие за рамки обычного прогнозирования цен.