English Русский 中文 Español Deutsch 日本語
preview
Machine Learning e Data Science (Parte 41): YOLOv8v para detectar padrões nos mercados Forex e de ações

Machine Learning e Data Science (Parte 41): YOLOv8v para detectar padrões nos mercados Forex e de ações

MetaTrader 5Sistemas de negociação |
13 0
Omega J Msigwa
Omega J Msigwa

Conteúdo


Introdução

A identificação de padrões nos mercados financeiros é uma tarefa complexa para modelos de machine learning e inteligência artificial. Por mais simples que isso possa parecer para nós, humanos, para uma máquina, detectar e interpretar esses padrões exige um processamento mais elaborado. Isso ocorre porque, ao contrário dos dados tabulares normalmente utilizados em trading, a detecção de padrões também envolve imagens bidimensionais, geralmente armazenadas em formatos como .png, .jpg etc.

Há um grande número de traders cujas estratégias se baseiam na análise da ação do preço (price action) e em padrões gráficos específicos do mercado, como:

  • Escada ascendente e descendente
  • Triângulo ascendente
  • Triângulo descendente
  • Triângulo simétrico
  • Bandeira
  • Cunha
  • Topo duplo
  • Fundo duplo
  • Ombro-cabeça-ombro
  • Topo ou fundo arredondado
  • Xícara com alça
  • e muitos outros.

Quando se trata de programação, os padrões associados a formações de candlestick (candlestick patterns) e às reações dos indicadores, que podem ser identificados sem código muito complexo, diferem bastante dos padrões gráficos mencionados acima, que são consideravelmente mais complexos.

Até mesmo para identificar um padrão simples, como um fundo em W, seria necessário um código complexo, bem elaborado e otimizado. Então, por que não tentar resolver essa tarefa com a ajuda da IA?

Para abordar esse problema com inteligência artificial (AI), neste artigo veremos um modelo bastante interessante chamado YOLOv8, que conheci no site huggingface.co.

Esse modelo ajuda a detectar padrões gráficos em imagens e gráficos com precisão bastante alta.

Para acompanhar o conteúdo deste artigo, é necessário ter conhecimentos básicos de machine learning e da linguagem de programação Python.


O que é o YOLOv8?

De acordo com a documentação,

YOLOv8s é um modelo de detecção de objetos baseado no framework YOLO (You Only Look Once). O modelo foi desenvolvido para identificar diferentes padrões gráficos em tempo real a partir de dados de negociação capturados da tela do computador.

O modelo auxilia traders e investidores ao automatizar a análise de padrões gráficos e fornecer informações em tempo hábil para a tomada de decisões fundamentadas.

O modelo passou por um ajuste incremental contínuo com um conjunto de dados diversificado e apresenta alta precisão na detecção e classificação de padrões do mercado de ações em condições reais de negociação.

No momento, o modelo é capaz de reconhecer com precisão vários padrões, entre eles:

Ombro-cabeça-ombro

Ombro-cabeça-ombro

Breve descrição do padrão

Esse padrão indica uma possível reversão do mercado.

Considera-se que três sequências de topos e fundos, com o pico central acima dos demais, sinalizam que o preço da ação pode começar a cair.

A linha de pescoço (neckline) representa o nível a partir do qual os traders baixistas começam a vender. Mais detalhes.

Ombro-cabeça-ombro invertido

É a versão oposta do padrão "ombro-cabeça-ombro".

Padrão de topo duplo M:

Padrão de topo duplo M

Breve descrição do padrão

Também conhecido como "topo duplo" (double top), esse padrão é formado por dois topos arredondados consecutivos.

Esses topos arredondados costumam indicar uma reversão baixista, pois frequentemente surgem após uma alta prolongada.

Quando se forma um topo duplo, o segundo topo arredondado geralmente se forma um pouco abaixo do primeiro, indicando resistência e perda de força do mercado.

Os topos duplos são relativamente raros, e sua formação muitas vezes indica que os investidores estão buscando realizar os lucros finais de uma tendência de alta. Mais detalhes.

Padrão de fundo duplo W:

Padrão de fundo duplo W

Funciona de forma semelhante ao padrão de topo duplo M, porém na direção oposta. Mais detalhes.

Padrão Stock Line

Não consegui encontrar nenhuma referência a ele nem na documentação nem na internet, então, por enquanto, vamos ignorá-lo.

Padrões de triângulo:

Esses padrões podem atuar tanto como padrões de continuação da tendência, quando confirmados, quanto como fortes padrões de reversão, caso ocorra um rompimento na direção oposta.

Os triângulos são usados para identificar o momento em que a faixa de negociação de uma ação ou de outro instrumento financeiro começa a se estreitar após uma tendência de baixa ou de alta. Mais detalhes.


Obtenção de padrões gráficos do MetaTrader 5

Como o YOLOv8 trabalha com imagens, precisamos obter uma grande quantidade de imagens de boa qualidade que possam ser usadas para testar o modelo e realizar experimentos.

Felizmente, o MetaTrader 5 e a linguagem de programação MQL5 oferecem recursos para criar screenshots de qualquer gráfico e símbolo de negociação selecionados. Vamos coletar algumas imagens usando um script.

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

Essa função cria vários screenshots do gráfico atual ao longo de 1000 barras, por padrão, recuando 50 barras, também por padrão, em relação ao screenshot anterior.

Antes de chamar a função responsável pela criação dos screenshots, é preciso garantir que o gráfico esteja o mais limpo possível. Até mesmo pequenos elementos de ruído, como as linhas da grade ou os volumes de ticks, podem introduzir ruído e prejudicar a detecção dos principais padrões que estão se formando no 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  

Todos os screenshots serão salvos na pasta MQL5\Files\Screenshots.


Uso do YOLOv8 para detectar padrões

    Abaixo está o código mínimo necessário para executar esse modelo e obter o resultado da previsão.

    Instalação

    $pip install ultralytics

    Início

    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)

    No entanto, no seu ambiente de execução, esse código gerará erros, pois atualmente a biblioteca ultralytics não inclui o YOLOvv8 (a documentação está um pouco desatualizada). Abaixo está a forma correta de fazer isso.

    Primeiro, precisamos importar o objeto YOLO e inicializá-lo com o modelo treinado para essa tarefa.

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

    O arquivo model.pt pode ser encontrado aqui. Depois de baixá-lo, salve-o em uma subpasta chamada Models no diretório de trabalho atual.

    Em seguida, basta chamar o método predict do objeto do modelo e passar o nome da imagem. Pronto, você obterá o resultado da previsão :).

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

    Quando o parâmetro save=True, o modelo salva a imagem resultante com os padrões detectados destacados.

    No entanto, essa abordagem é simples demais e pouco flexível. Vamos criar uma classe wrapper para esse preditor, para garantir um código confiável e robusto para analisar e realizar previsões em várias imagens armazenadas na pasta que contém nossos screenshots.

    Além disso, precisamos implementar uma forma otimizada de processar as previsões e visualizar os resultados.

    Detecção de padrões em uma única imagem

    O construtor da nossa classe recebe um objeto do modelo YOLO e a pasta de imagens que contém todos os screenshots obtidos do 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

    Também precisaremos de uma função dentro da classe para obter todas as imagens presentes na pasta especificada.

    Essa função será útil ao realizar várias previsões, pois permitirá determinar quantas imagens estão disponíveis na pasta, retornando uma tupla com o número total de imagens e seus nomes em uma lista 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

    Vamos ampliar a função predict para que ela seja capaz de realizar a previsão de uma única imagem. Essa função também deverá fornecer informações sobre os padrões encontrados e o nível de confiança (confidence) de cada um deles.

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

    A função predict do modelo YOLOv8 retorna um dicionário com informações sobre a caixa delimitadora (bounding box), que depois é exibida sobre a imagem. Essa caixa delimita o padrão detectado, enquanto a anotação exibe o nível de confiança (confidence) correspondente ao padrão gráfico reconhecido.

    Depois de extrair essas informações, nós as exibimos no console do Python ou na linha de comando (Command Prompt, CMD).

    No final da função, quando o parâmetro hist está definido como False, o módulo cv2 é usado para exibir o resultado da previsão em uma janela separada.

    Isso é útil quando precisamos visualizar a imagem final com os padrões detectados pelo modelo.

    Exemplo.

    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)
    

    Temos uma imagem obtida do gráfico EURUSD.PERIOD_H1, identificada pelo número 11 na pasta Screenshots, e queremos visualizá-la.

    Imagem original.

    Abaixo está o resultado: a imagem gerada pelo modelo após a chamada da função predict, exibida em uma janela separada.

    Detecção de padrões em várias imagens

    Depois de obter as imagens da pasta Screenshots, percorremos cada uma delas em um laço e passamos cada imagem para a função predict_image que acabamos de criar.

    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)

    Agora vamos chamar essa função para realizar previsões em várias das imagens coletadas. Isso é semelhante a um backtest: fornecemos várias imagens históricas para avaliar a qualidade desse modelo.

    pattern_detector.predict_images()
    Resultados.

    *Todas as previsões e imagens geradas pelo modelo podem ser encontrados no diretório de trabalho atual, na pasta runs\predict

    Como podemos ver, o modelo apresentou previsões bastante boas. No entanto, assim como qualquer modelo de machine learning já desenvolvido, ele possui pontos fracos e limitações. A seguir, veremos alguns deles.


    Vieses, riscos e limitações do YOLOv8

    1. O desempenho pode variar em função das diferenças no estilo dos gráficos, na resolução da tela e nas condições de mercado.

    É extremamente importante que as cores dos candles no gráfico não gerem confusão visual. O fundo e os candles devem apresentar um contraste nítido entre si para que os resultados sejam melhores.

    A escala do gráfico também é importante: um nível de zoom muito alto no MetaTrader 5 pode fazer com que os padrões apareçam incompletos, enquanto um zoom muito baixo pode introduzir ruído.

    É necessário encontrar um equilíbrio adequado entre a escala do gráfico e o tamanho da imagem.

    2. Movimentos bruscos do mercado e ruído nos dados de negociação podem reduzir a precisão.

    Essas flutuações podem gerar falsos rompimentos e padrões anômalos. Nesses gráficos e mercados, o modelo inevitavelmente cometerá erros.

    3. O modelo também terá dificuldade para reconhecer padrões de mercado pouco representados no conjunto de dados de treinamento.

    É recomendável evitar mercados e timeframes em que os padrões não estejam claramente definidos. A melhor forma de aproveitar ao máximo o modelo é utilizá-lo em mercados adequados.


    Detecção de padrões gráficos no MetaTrader 5 com o YOLOv8

    Como já mencionado, o modelo YOLOv8 trabalha com imagens e gera o resultado da previsão também em formato de imagem, o que não pode ser lido e interpretado diretamente pelo MQL5. No entanto, a linguagem oferece suporte a imagens no formato bitmap (.BMP), o que nos dá um bom ponto de partida.

    Como em MQL5 é possível criar um objeto gráfico a partir de uma imagem ou inserir uma imagem no fundo do gráfico do MetaTrader 5, algo que já demonstramos diversas vezes, vamos abrir as imagens geradas pelo YOLOv8 com os padrões gráficos detectados e exibi-las no MetaTrader 5 como fundo do gráfico, da mesma forma que fizemos em um dos artigos anteriores.

    Depois de adicionar a imagem ao fundo do gráfico (background), podemos ocultar as barras atuais exibidas em primeiro plano e atualizar a exibição do gráfico com a imagem dos candles.

    Para isso, precisamos fazer algumas alterações em nossa classe Python. Vamos começar modificando a função predict para que ela salve todas as imagens com as previsões em um único diretório definido.

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

    Como a função predict permite salvar as imagens em uma pasta específica, podemos armazenar todos os arquivos em uma subpasta chamada YOLOv8 Images, criada no diretório MQL5\Files.

    O YOLOv8 gera imagens nos formatos JPEG ou JPG. Para poder utilizá-las no MetaTrader 5, precisamos convertê-las para o formato Bitmap (BMP). Abaixo está a função responsável por essa tarefa.

    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

    Agora veremos como identificar e prever os padrões presentes em uma única imagem.

    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)

    Esse processo pode ser automatizado. Após alguns minutos de execução, nosso script deverá ler uma imagem do diretório MQL5\Files\Screenshots, realizar a previsão e salvar o resultado na pasta MQL5\Files\YOLOv8 Images. Agora vamos preparar o ambiente adequado para exibir no gráfico do MetaTrader 5 a imagem resultante no formato Bitmap (.BMP).

    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)

    Agora vamos preparar o ambiente para exibir no gráfico do MetaTrader 5 a imagem resultante no formato Bitmap (.BMP).

    Começaremos inicializando a função de tratamento do timer, que permitirá automatizar a criação do screenshot e a atualização do gráfico com a imagem contendo os padrões detectados.

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

    A função showBars é responsável por limpar o gráfico e preparar uma área adequada para a criação do screenshot.

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

    Quando essa função é chamada com o valor false, todas as propriedades de cor do gráfico, incluindo as cores dos candles japoneses, são definidas com a mesma cor do fundo do gráfico. Dessa forma, todos esses elementos ficam invisíveis.

    Isso é necessário porque colocaremos a imagem no fundo do gráfico atual, e as barras exibidas em primeiro plano não devem aparecer sobre ela nem gerar poluição visual.

    Abaixo está a função que converte a imagem Bitmap (.BMP) em um objeto e, em seguida, a define como fundo do gráfico atual.

    //+------------------------------------------------------------------+
    //|       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 fim, vamos automatizar a criação dos screenshots e seu envio para o diretório Screenshots, de onde serão posteriormente lidos pelo nosso script Python. Também automatizaremos a leitura das imagens com as previsões na pasta YOLOv8 Images e sua exibição no gráfico do 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);
      }

    Para concluir, executamos o EA no gráfico EURUSD, PERIOD_H1, usando o mesmo timeframe do script Python. O script Python também foi iniciado, e o timer foi configurado para 60 segundos.

    Após 60 segundos, a imagem gerada pelo modelo foi exibida no gráfico EURUSD do MetaTrader 5.


    Funciona!

    O método de usar uma imagem como fundo do gráfico é bastante rudimentar e pressupõe que o tamanho do gráfico permaneça constante ou, pelo menos, não seja alterado durante o intervalo definido na função do timer.

    Assim, redimensionar o gráfico pode comprometer temporariamente a renderização da imagem. Recomendo usar o método apresentado aqui para implementar uma forma mais robusta de exibir a imagem como fundo do gráfico.


    Considerações finais

    Na minha opinião, o YOLOv8 é um modelo impressionante. Assim como qualquer outro modelo de machine learning, ele apresenta limitações e desvantagens, mas, para tarefas de detecção de padrões gráficos, realmente funciona corretamente. Por isso, seus desenvolvedores merecem reconhecimento, pois, no passado, eu mesmo tentei criar um modelo semelhante para essa tarefa, mas não consegui obter nenhum resultado realmente satisfatório.

    Embora usemos com frequência modelos de IA para automatizar estratégias de trading, este modelo ainda não é prático para negociação algorítmica, pois gera imagens que, no momento, só podem ser interpretadas por uma pessoa. Trata-se, portanto, de uma ferramenta interessante para detectar padrões no trading manual. Para utilizá-lo em estratégias algorítmicas, é possível implementar uma conexão entre Python e MetaTrader 5 para transferir, em formato de texto ou JSON, dados brutos com o estado do modelo e as previsões retornadas pelo método predict.

    Boa sorte a todos!

    Continue acompanhando e contribua para o desenvolvimento de algoritmos de machine learning para a linguagem MQL5 neste repositório do GitHub.


    Tabela de anexos


    Nome e caminho do arquivo
    Descrição e finalidade
    Experts\YOLOv8 EA.mq5 EA para coletar screenshots do gráfico e adicionar ao gráfico atual a imagem com as previsões do YOLOv8.
    Include\errordescription.mqh Biblioteca para converter códigos de erro gerados no MetaTrader 5 e no MQL5 de integer para strings legíveis.
    Scripts\ChartScreenshots.mq5 Script para criar screenshots históricos de um gráfico especificado no MetaTrader 5.
    YOLOv8 Proj\test.py Script Python para testar o modelo YOLOv8 em várias imagens.
    YOLOv8 Proj\deploy.py Script Python para implantar e executar continuamente o modelo YOLOv8.
    YOLOv8 Proj\requirements.txt Contém todas as dependências Python utilizadas no projeto e suas respectivas versões.


    Traduzido do Inglês pela MetaQuotes Ltd.
    Artigo original: https://www.mql5.com/en/articles/18143

    Arquivos anexados |
    Attachements.zip (1023.22 KB)
    Caminhe em novos trilhos: Personalize indicadores no MQL5 Caminhe em novos trilhos: Personalize indicadores no MQL5
    Vou agora listar todas as possibilidades novas e recursos do novo terminal e linguagem. Elas são várias, e algumas novidades valem a discussão em um artigo separado. Além disso, não há códigos aqui escritos com programação orientada ao objeto, é um tópico muito importante para ser simplesmente mencionado em um contexto como vantagens adicionais para os desenvolvedores. Neste artigo vamos considerar os indicadores, sua estrutura, desenho, tipos e seus detalhes de programação em comparação com o MQL4. Espero que este artigo seja útil tanto para desenvolvedores iniciantes quanto para experientes, talvez alguns deles encontrem algo novo.
    Recursos do Assistente MQL5 que você precisa conhecer (Parte 65): uso de padrões com FrAMA e Índice de Força Recursos do Assistente MQL5 que você precisa conhecer (Parte 65): uso de padrões com FrAMA e Índice de Força
    A média móvel adaptativa fractal (FrAMA) e o oscilador Índice de Força (Force Index Oscillator) são mais um par de indicadores que podem ser usados em conjunto em um EA desenvolvido em MQL5. Esses dois indicadores se complementam até certo ponto, pois a FrAMA é um indicador de acompanhamento de tendência, enquanto o Índice de Força é um oscilador baseado em volume. Como sempre, usaremos o Assistente MQL5 para avaliar rapidamente o potencial da combinação dessas duas ferramentas.
    Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
    Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
    Trading com o Calendário Econômico MQL5 (Parte 9): Aprimorando a interação com as notícias com uma barra de rolagem dinâmica e uma exibição aprimorada Trading com o Calendário Econômico MQL5 (Parte 9): Aprimorando a interação com as notícias com uma barra de rolagem dinâmica e uma exibição aprimorada
    Neste artigo, aprimoramos o Calendário Econômico MQL5 adicionando uma barra de rolagem dinâmica para tornar a navegação pelas notícias mais intuitiva. Os eventos serão exibidos de forma fluida, e as informações serão atualizadas quando necessário. Naturalmente, durante os testes também verificaremos a capacidade de adaptação da barra de rolagem e a qualidade do painel de controle.