English Русский Deutsch 日本語
preview
Aprendizaje automático y Data Science (Parte 41): Detección de patrones en los mercados de divisas y de valores mediante YOLOv8

Aprendizaje automático y Data Science (Parte 41): Detección de patrones en los mercados de divisas y de valores mediante YOLOv8

MetaTrader 5Sistemas comerciales |
21 0
Omega J Msigwa
Omega J Msigwa

Contenido


Introducción

La detección de patrones en los mercados financieros es una tarea compleja en el aprendizaje automático y la inteligencia artificial. Aunque para nosotros, los seres humanos, parezca algo sencillo, una máquina necesita cierto esfuerzo para detectar e interpretar estos patrones, simplemente porque, a diferencia de los datos tabulares bidimensionales que solemos usar en el trading, la detección de patrones se extiende a datos de imágenes bidimensionales que normalmente se almacenan en formatos como .png, .jpg, etc.

Existe una gran cantidad de operadores con estrategias que dependen de la acción del precio y de patrones gráficos específicos en los mercados, tales como:

  • Escaleras ascendentes y descendentes
  • Triángulo ascendente
  • Triángulo descendente
  • Triángulo simétrico
  • Bandera 
  • Cuña
  • Techo doble
  • Doble fondo
  • Cabeza y hombros
  • Techo o suelo redondeado
  • Taza y asa
  • y muchos más.

En lo que respecta a la programación, patrones como los de velas japonesas y las reacciones de los indicadores, que pueden identificarse incluso sin líneas de código sofisticadas, los patrones gráficos mencionados anteriormente son bastante complejos.

Se necesitaría un código sofisticado, bien escrito y optimizado para poder detectar incluso un patrón simple como la base en forma de W, así que ¿por qué no usar la IA para que nos ayude con esta tarea tediosa?

Para abordar este problema mediante la inteligencia artificial (IA), en este artículo vamos a analizar un modelo muy interesante llamado YOLOv8 que descubrí en huggingface.co.

Este modelo ayuda a detectar patrones gráficos en imágenes y gráficos con una precisión aceptable.

Para comprender plenamente el contenido de este artículo, es necesario tener conocimientos básicos sobre aprendizaje automático y el lenguaje de programación Python.


¿Qué es YOLOv8?

Según su documentación.

YOLOv8s es un modelo de detección de objetos basado en el marco YOLO (You Only Look Once). Este modelo está diseñado para detectar diversos patrones gráficos en tiempo real a partir de datos de negociación bursátil capturados en pantalla.

Este modelo ayuda a los operadores e inversores automatizando el análisis de los patrones gráficos y proporcionando información oportuna para la toma de decisiones informadas.

El modelo se ha perfeccionado con un conjunto de datos diverso y logra una alta precisión en la detección y clasificación de patrones del mercado de valores en escenarios de negociación en tiempo real.

Tal como está actualmente, este modelo puede predecir con precisión un par de patrones, entre ellos:

Patrón de cabeza y hombros superior

parte superior de cabeza y hombros

Una breve descripción del patrón

Este patrón indica que es posible un cambio de tendencia en el mercado.

Los operadores creen que tres conjuntos de picos y valles, con un pico más grande en el medio, indican que el precio de una acción comenzará a caer.

La línea del cuello representa el punto en el que los operadores bajistas comienzan a vender. Más información.

Patrón de cabeza y hombros inferior

Este es el patrón opuesto al de cabeza y hombros superior.

Patrón M Head:

Patrón M Head

Una breve descripción del patrón

También conocido como doble techo, este patrón se forma a partir de dos partes superiores redondeadas consecutivas.

Estos techos redondeados suelen indicar un cambio de tendencia bajista, ya que a menudo se producen después de un repunte alcista prolongado.

Si se forma un doble techo, el segundo techo redondeado suele quedar ligeramente por debajo del máximo del primero, lo que indica resistencia y agotamiento.

Los dobles techos son fenómenos poco frecuentes, y su formación suele indicar que los inversores buscan obtener los beneficios finales de una tendencia alcista. Más información.

Patrón W Bottom:

Patrón W Bottom

Esto funciona igual que el patrón M Head, pero a la inversa; más información.

Stock Line

No pude encontrar referencias al respecto en la documentación ni en internet, así que dejémoslo de lado por ahora.

Patrón de triángulo(s):

Estos patrones pueden ser un patrón de continuación, si se validan, o un potente patrón de reversión, en caso de fallo.

Los operadores utilizan triángulos para determinar cuándo se produce una reducción del rango de negociación de una acción o valor tras una tendencia bajista o alcista. Más información.


Obtención de patrones gráficos desde MetaTrader 5

Dado que YOLOv8 trabaja con imágenes (datos de imagen), necesitamos extraer una gran cantidad de imágenes de alta calidad que podamos usar para probar y experimentar con el modelo.

Por suerte, MetaTrader 5 y el lenguaje de programación MQL5 ofrecen una funcionalidad para tomar una captura de pantalla de cualquier gráfico y símbolo que deseemos. Vamos a recopilar un par de imágenes usando un script.

Archivo: 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);
}

Esta función captura varias capturas de pantalla del gráfico actual durante 1000 barras (valor predeterminado), desplazando 50 barras (valor predeterminado) hacia atrás desde la captura de pantalla anterior.

Antes de llamar a la función de captura de pantalla, debemos asegurarnos de que el gráfico esté lo más limpio posible. Incluso pequeñas fuentes de ruido, como las líneas de la cuadrícula y el volumen de los ticks, podrían distraer a los modelos e impedirles detectar patrones importantes que aparecen en el gráfico.

    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  

Todas las imágenes se guardarán en la ruta MQL5\Files\Screenshots.


Uso de YOLOv8 para la detección de patrones

    Según su documentación, a continuación se muestra el código mínimo necesario para ejecutar este modelo y obtener el resultado previsto.

    Instalación

    $pip install ultralytics

    Primeros pasos.

    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)

    Sin embargo, este código generará errores en su entorno, ya que actualmente no existe YOLOvv8 de Ultralytics (la documentación está algo desactualizada). A continuación se indica la forma correcta de hacerlo.

    En primer lugar, necesitamos importar el objeto YOLO y completarlo con un modelo entrenado para la tarea.

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

    El archivo model.pt se encuentra aquí. Una vez descargado el archivo, guárdelo en una subcarpeta denominada Models dentro de su directorio de trabajo actual.

    A continuación, debemos llamar al método «predict» desde un objeto de modelo y pasarle el nombre de la imagen, y eso es todo: obtendrá el resultado previsto :).

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

    Cuando save=True, el modelo guarda la imagen resultante, que contiene los patrones resaltados.

    Pero esto es demasiado simple e insuficiente; vamos a crear una clase para este predictor para asegurarnos de tener un código fiable y robusto para analizar y predecir múltiples imágenes de una carpeta que contiene nuestras capturas de pantalla.

    Además, necesitamos la mejor manera de gestionar las predicciones y visualizar el resultado.

    Detección de patrones en una sola imagen

    El constructor de nuestra clase recibe como entrada el objeto del modelo YOLO y la carpeta de imágenes, que contiene todas las capturas de pantalla tomadas de 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

    También necesitamos una función en la clase para obtener todas las imágenes presentes en la carpeta especificada.

    Esta función será útil al realizar múltiples predicciones, ya que nos permite saber la cantidad de imágenes disponibles en una carpeta al devolver una tupla que contiene la cantidad total de imágenes y sus nombres en una lista de 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

    Ampliemos la función de predicción para que pueda predecir una sola imagen; esta función también debería informarnos sobre los patrones detectados y el nivel de confianza para dichos patrones.

    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.")
    

    La función de predicción que ofrece YOLOv8 devuelve un diccionario que contiene información sobre el cuadro, el cual se muestra dentro de una imagen. Este cuadro envuelve un patrón detectado, seguido del nivel de confianza para un patrón gráfico específico detectado.

    Tras extraer esta información, la imprimimos en una consola de Python o en el Símbolo del sistema (CMD).

    Al final de la función, cuando hist se establece en False, se utiliza el módulo cv2 para mostrar el resultado previsto en un cuadro de diálogo.

    Esto resulta práctico cuando se desea visualizar la imagen resultante que contiene los patrones producidos por el modelo.

    Ejemplo.

    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)
    

    Tenemos una imagen tomada de EURUSD.PERIOD_H1 con el número 11 marcado dentro de la carpeta Capturas de pantalla que pretendemos visualizar. 

    Imagen original.

    A continuación se muestra la imagen resultante generada por el modelo tras la función de predicción, en una ventana independiente.

    Detección de patrones en varias imágenes

    Una vez recibidas las imágenes de la carpeta «Screenshots», las recorremos todas y pasamos cada imagen a la función predict_image que acabamos de crear anteriormente.

    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)

    Ahora, vamos a llamar a esta función para predecir varias imágenes que hemos recopilado. Esto es similar a las pruebas retrospectivas: al pasar varias imágenes recopiladas históricamente, podemos comprobar si este modelo es adecuado o no.

    pattern_detector.predict_images()
    Resultados.

    Todos los resultados previstos y las imágenes generadas por este modelo se encuentran en el directorio de trabajo actual, en la carpeta runs\predict*

    Como se puede observar, el modelo obtuvo algunas predicciones decentes, pero al igual que cualquier modelo de aprendizaje automático jamás creado, tiene algunas debilidades y limitaciones. A continuación se muestran algunos ejemplos.


    Sesgos, riesgos y limitaciones de YOLOv8

    01: El rendimiento puede verse afectado por variaciones en los estilos de los gráficos, la resolución de la pantalla y las condiciones del mercado.

    Es fundamental asegurarse de que los colores de las velas japonesas en el gráfico sean menos confusos; el fondo y los colores de las velas deben ser muy distintos entre sí para obtener mejores resultados.

    La escala del gráfico también es importante: una escala más amplia en MetaTrader 5 podría dar lugar a patrones incompletos, mientras que una más reducida podría introducir ruido.

    Hay que encontrar el equilibrio adecuado entre la escala del gráfico y el tamaño de la imagen.

    02: Las rápidas fluctuaciones del mercado y el ruido en los datos de negociación pueden afectar la precisión.

    Las fluctuaciones pueden dar lugar a falsas rupturas y patrones extraños. Es inevitable que este modelo cometa errores en este tipo de gráficos y mercados.

    03: Los patrones específicos del mercado que no están bien representados en los datos de entrenamiento pueden plantear dificultades para su detección.

    Hay que evitar los mercados y marcos temporales con patrones poco definidos; la mejor manera de garantizar que se obtenga el máximo rendimiento del modelo es aplicarlo en el mercado o mercados adecuados.


    Detección de patrones gráficos en MetaTrader 5 usando YOLOv8

    Una vez más, el modelo YOLOv8 trabaja con imágenes y produce el resultado previsto en formato de imagen, lo cual es imposible de leer e interpretar en el lenguaje nativo MQL5. Sin embargo, el lenguaje tiene la capacidad de trabajar con imágenes en formato de mapa de bits .BMP, lo cual es un buen punto de partida.

    Dado que es posible crear un objeto basado en imágenes o incrustar una imagen en el fondo del gráfico de MetaTrader 5 utilizando MQL5, como se ha hecho varias veces, abramos estas imágenes generadas por YOLOv8, que muestran los patrones gráficos detectados en MetaTrader 5 en la parte inferior del gráfico, tal y como se hizo en este artículo.

    Tras añadir una imagen en la parte posterior del gráfico (fondo), podemos ocultar las barras actuales que se muestran en primer plano y actualizar el gráfico como una imagen con velas.

    Para lograr esto, tenemos que modificar un par de cosas en nuestra clase de Python, comenzando por mejorar la función predict, para que sea capaz de guardar todas las imágenes que contienen predicciones en un directorio específico.

    Nombre del archivo: 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.")
    
    

    Dada esta capacidad de guardar las imágenes en una carpeta específica usando la función predict, podemos guardar todos los archivos en una subcarpeta llamada YOLOv8 Images creada bajo la ruta principal de los archivos MQL5.

    YOLOv8 genera una imagen en formato JPEG o JPG; si queremos usar esta imagen en MetaTrader 5, debemos convertirla a formato Bitmap (BMP). A continuación se muestra la función para la tarea.

    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

    Ahora bien, así es como podemos detectar y predecir los patrones presentes en una sola imagen.

    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)

    Podemos automatizar este proceso. Una vez transcurridos varios minutos, queremos que nuestro script lea una imagen de MQL5\Files\Screenshots, realice predicciones y guarde una imagen en MQL5\Files\YOLOv8 Images.

    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)

    Ahora, preparemos el entorno adecuado para mostrar la imagen generada, presente en formato Bitmap (.BMP), en un gráfico de MetaTrader 5.

    Comenzamos inicializando la función de gestión del temporizador para ayudarnos a automatizar el proceso de tomar una captura de pantalla y actualizar el gráfico con la imagen que contiene los patrones predichos (detectados).

    Nombre del archivo: 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);
      }

    La función denominada showBars se encarga de limpiar y preparar el entorno adecuado en el gráfico para realizar una captura de pantalla.

    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();
     }

    Cuando se invoca esta función con un valor false, todas las propiedades del gráfico (incluidos los colores de las velas) se establecen en el mismo color que el fondo del gráfico; esto se hace para que todo quede oculto.

    Esto es necesario porque vamos a colocar una imagen de fondo en el gráfico actual, por lo que no queremos que las barras del primer plano aparezcan sobre la imagen, ya que podrían crear una imagen confusa.

    A continuación se muestra la función para convertir una imagen Bitmap (.BMP) en un objeto y, a continuación, asignarla al fondo del gráfico actual.

    //+------------------------------------------------------------------+
    //|       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;
    }

    Por último, automatizaremos el proceso de realizar capturas de pantalla y enviarlas a la ruta de capturas de pantalla para que nuestro script de Python las lea; también automatizaremos el proceso de leer las imágenes predichas de la carpeta YOLOv8 Images, así como el proceso de trazar la imagen en el gráfico de 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);
      }

    Por último, se adjuntó un asesor experto (EA) al gráfico EURUSD, en el timeframe PERIOD_H1 (igual que en el script de Python). El script de Python estaba en funcionamiento y el temporizador estaba configurado en 60 segundos.

    Transcurridos 60 segundos en el gráfico EURUSD, MetaTrader 5 recibió una imagen del modelo.


    ¡Muy interesante!

    El método utilizado para insertar una imagen como fondo del gráfico anterior es rudimentario y parte del supuesto de que el tamaño del gráfico es constante, o que permanece igual durante un tiempo (al menos durante el tiempo establecido en la función de temporizador).

    Por lo tanto, al ajustar el tamaño del gráfico se interrumpirá durante un tiempo el proceso de dibujo de una imagen en el gráfico; le recomiendo que utilice el método que se describe aquí para disponer de una forma fiable de visualizar la imagen como fondo del gráfico.


    Reflexiones finales

    En mi opinión, YOLOv8 es un modelo impresionante. Como cualquier otro modelo de aprendizaje automático, tiene sus limitaciones y desventajas, pero a la hora de detectar los patrones gráficos mencionados anteriormente, acierta en algunos. Por eso, felicito a sus creadores, ya que en el pasado intenté crear un modelo similar para esta tarea y obtuve malos resultados.

    Si bien siempre utilizamos modelos de IA para automatizar nuestras estrategias de trading, este modelo no es práctico para el trading algorítmico, ya que produce imágenes que, por ahora, solo un ser humano puede interpretar. Se trata más bien de una forma interesante de detectar patrones para los operadores manuales; si desea utilizarlo para estrategias algorítmicas, puede buscar la manera de establecer una conexión entre Python y MetaTrader para enviar información sin procesar, en formato de texto o JSON, sobre el estado del modelo y las predicciones que ofrece el método predict de este modelo.

    Atentamente.

    Manténgase al tanto y colabore en el desarrollo de algoritmos de aprendizaje automático para el lenguaje MQL5 en este repositorio de GitHub.


    Tabla de archivos adjuntos


    Nombre y ruta del archivo
    Descripción y uso
    Experts\YOLOv8 EA.mq5 Un asesor experto para recopilar capturas de pantalla del gráfico y agregar la imagen predicha por YOLOv8 al gráfico actual.
    Include\errordescription.mqh Una biblioteca para convertir códigos de error generados en MetaTrader 5 y MQL5, de números enteros a cadenas de texto legibles para humanos.
    Scripts\ChartScreenshots.mq5 Un script para tomar varias capturas de pantalla históricas de un gráfico específico en MetaTrader 5.
    YOLOv8 Proj\test.py Un script de Python para probar el modelo YOLOv8 en múltiples imágenes.
    YOLOv8 Proj\deploy.py Un script de Python para desplegar y ejecutar el modelo YOLOv8 de forma continua.
    YOLOv8 Proj\requirements.txt Contiene todas las dependencias de Python utilizadas en el proyecto y su número de versión.


    Traducción del inglés realizada por MetaQuotes Ltd.
    Artículo original: https://www.mql5.com/en/articles/18143

    Archivos adjuntos |
    Attachements.zip (1023.22 KB)
    Utilizando redes neuronales en MetaTrader Utilizando redes neuronales en MetaTrader
    En el artículo se muestra la aplicación de las redes neuronales en los programas de MQL, usando la biblioteca de libre difusión FANN. Usando como ejemplo una estrategia que utiliza el indicador MACD se ha construido un experto que usa el filtrado con red neuronal de las operaciones. Dicho filtrado ha mejorado las características del sistema comercial.
    Estrategia de Evolución de Adaptación de la Matriz de Covarianza — Covariance Matrix Adaptation Evolution Strategy (CMA-ES) Estrategia de Evolución de Adaptación de la Matriz de Covarianza — Covariance Matrix Adaptation Evolution Strategy (CMA-ES)
    Hoy analizaremos uno de los algoritmos de optimización sin gradiente más interesantes, que aprende a comprender la geometría de la función objetivo. Consideremos la implementación clásica de CMA-ES con una ligera modificación: la sustitución de la distribución normal por una distribución potencial. Asimismo, veremos un análisis detallado de las bases matemáticas del algoritmo, su implementación práctica y un análisis honesto: dónde el CMA-ES es imbatible y dónde es mejor evitarlo.
    Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
    En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
    Características del Wizard MQL5 que debe conocer (Parte 65): Uso de los patrones FrAMA y Force Index Características del Wizard MQL5 que debe conocer (Parte 65): Uso de los patrones FrAMA y Force Index
    La media móvil adaptativa fractal (FrAMA) y el oscilador Force Index son otro par de indicadores que podrían utilizarse conjuntamente en un asesor experto de MQL5. Estos dos indicadores se complementan en cierta medida, ya que FrAMA es un indicador de seguimiento de tendencias, mientras que el Force Index es un oscilador basado en el volumen. Como siempre, utilizamos el asistente MQL5 para explorar rápidamente el potencial que puede tener esta combinación.