English Русский 中文 Español Deutsch 日本語
preview
Integração do MQL5 com pacotes de processamento de dados (Parte 1): Análise avançada de dados e processamento estatístico

Integração do MQL5 com pacotes de processamento de dados (Parte 1): Análise avançada de dados e processamento estatístico

MetaTrader 5Sistemas de negociação |
131 1
Hlomohang John Borotho
Hlomohang John Borotho

Introdução

Os mercados financeiros geram enormes volumes de dados que, por sua vez, podem dificultar a análise técnica. Além disso, a análise técnica realizada manualmente, por si só, não permite que os traders analisem e interpretem padrões, tendências e anomalias nos dados. Um pacote avançado de análise de dados, como o Jupyter Lab, permite que os traders executem análises estatísticas complexas, aprendizado de máquina e visualização de dados. Isso possibilita identificar oportunidades de negociação lucrativas, entender o comportamento do mercado, tendências sazonais e prever movimentos futuros dos preços.


Coleta de Dados Históricos

Para começar, precisamos de dados históricos do MetaTrader 5 no formato .csv. Abra a plataforma MetaTrader, "Serviço" > "Configurações" > aba "Gráficos". Em seguida, selecione a quantidade de barras no gráfico que deseja carregar. É recomendável escolher a opção sem limite de barras, pois trabalharemos com datas e não saberemos quantas barras há em um determinado período de tempo.

Aba "Gráficos"

Após isso, carregaremos os dados reais. Para isso, vá até "Exibir" > "Símbolos". Você estará na aba "Especificação". Alterne para a aba "Barras" ou "Ticks", dependendo do tipo de dado que deseja carregar. Insira a data inicial e final do período histórico que deseja carregar e, em seguida, clique em "Solicitar" para carregar os dados e salvá-los no formato .csv.

dados históricos

Os dados históricos foram carregados. Agora, precisamos baixar e configurar o ambiente Jupyter Lab para análise. Acesse o site oficial do Jupyter Lab e siga os passos simples para baixá-lo. Dependendo do seu sistema operacional, você terá várias opções de instalação usando pip, conda ou brew.


Carregando dados históricos do MetaTrader 5 no Jupyter Lab

Para carregar corretamente os dados históricos do MetaTrader 5 no Jupyter Lab, você precisa saber a pasta onde os dados foram salvos e, no Jupyter Lab, simplesmente navegar até essa pasta. Primeiro, é necessário carregar os dados e verificar os nomes das colunas. Precisamos conferir os nomes das colunas para processá-los corretamente e evitar erros que possam ocorrer devido a nomes incorretos.

Pré-processamento

Antes de iniciar a análise dos dados, precisamos realizar seu pré-processamento.

1. Análise de data e hora: converter a coluna de data para o formato de data e hora.

2. Processamento de todos os valores ausentes.

3. Criação de novos parâmetros, se necessário.

código Python:

import pandas as pd

# Load historical data
file_path = '/home/int_junkie/Documents/ML/XAUUSD.m_H1_historical.csv'
data = pd.read_csv(file_path)

# Display the first few rows and column names
print(data.head())
print(data.columns)

saída:

saída

Observamos caracteres especiais '<>' dentro das colunas, bem como '\t', indicando que o arquivo está delimitado por tabulação. Agora podemos prosseguir com o carregamento dos dados históricos com o nome correto da coluna.

No código abaixo, faremos o seguinte:

1. Importação de bibliotecas:

  • Pandas — poderosa biblioteca para manipulação de dados em Python.
  • Para análise técnica dos dados dos mercados financeiros, utilizamos a Technical Analysis Library (TA lib).

2. Carregamento dos dados históricos:

  • O caminho do arquivo é usado para especificar a localização do arquivo CSV contendo os dados históricos.
  • Pd.read_csv lê o arquivo CSV em um DataFrame do pandas. O delimitador '\t' indica que o arquivo está separado por tabulação.

3. Exibição dos dados:

  • Data.head() imprime as primeiras linhas do DataFrame para verificar o conteúdo.
  • Data.columns exibe os nomes das colunas para conferir a estrutura do DataFrame.

4. Ordenação dos dados por data:

  • Date.sort_values(by='<DATE>', inplace=True) ordena os dados na coluna '<DATE>'. Isso garante que os dados estejam em ordem cronológica.

5. Cálculo do RSI:

  • TA.RSI calcula o Índice de Força Relativa (RSI) com base na coluna de preços '<CLOSE>'.
  • O período utilizado é 14 períodos.
  • Os valores calculados são armazenados em uma nova coluna chamada RSI no DataFrame.

6. Exibição dos dados atualizados:

  • Data.head() exibe as primeiras linhas do DataFrame para verificar o cálculo do RSI.
código Python:
import pandas as pd
import talib as ta

# Load historical data
file_path = '/home/int_junkie/Documents/ML/XAUUSD.m_H1_historical.csv'
data = pd.read_csv(file_path, delimiter='\t')

# Display the first few rows and column names to verify
print(data.head())
print(data.columns)

# Ensure data is sorted by the correct date column
data.sort_values('<DATE>', inplace=True)

# Calculate RSI using the '<CLOSE>' price column
data['RSI'] = ta.RSI(data['<CLOSE>'], timeperiod=14)

# Display the first few rows to verify
print(data.head())

saída:

saída2

Observamos que a coluna RSI contém valores NaN, e precisamos processá-los corretamente. O cálculo do indicador RSI exige um número mínimo de pontos de dados. Isso pode resultar em valores NaN para os períodos iniciais. Para tratar os valores NaN, precisamos verificar o tipo de dado da coluna '<CLOSE>'. Certifique-se de acessar corretamente o DataFrame e a coluna correspondente. O código Python a seguir mostra como lidar com os valores NaN.

import pandas as pd
import talib as ta

# Load the historical data
file_path = '/home/int_junkie/Documents/ML/XAUUSD.m_H1_historical.csv'
data = pd.read_csv(file_path, delimiter='\t')data['<CLOSE>'] = data['<CLOSE>'].astype(float)


# Verify the column names
print(data.columns)

# Convert the column to the correct data type if necessary
data['<CLOSE>'] = data['<CLOSE>'].astype(float)

# Calculate the RSI
data['RSI'] = ta.RSI(data['<CLOSE>'], timeperiod=14)

# Display the RSI values
print(data[['<CLOSE>', 'RSI']].tail(20))

Resultado:

valores NaN tratados

Podemos ver que os valores NaN foram tratados corretamente. Se os valores NaN ainda aparecerem nos períodos iniciais (o que é esperado devido ao período de bloqueio (lock-back period)), podemos prosseguir com o processamento da seguinte forma:

data['RSI'] = ta.RSI(data['<CLOSE>'], timeperiod=14)
data['RSI'] = data['RSI'].fillna(0)  # or use any other method to handle NaN values


Análise Exploratória de Dados

O principal objetivo da Análise Exploratória de Dados (EDA - Exploratory Data Analysis) é investigar a estrutura subjacente dos dados, resumindo suas principais características. Durante a EDA, identificamos padrões e determinamos tendências e relações nos dados. Também identificamos anomalias e valores atípicos que podem exigir investigação adicional. Além disso, verificamos suposições sobre os dados que podem afetar análises futuras. Na sequência, realizamos a limpeza dos dados, identificando valores ausentes, erros e inconsistências que precisam ser corrigidos. 

Utilizamos os seguintes scripts python para realizar a EDA:

import seaborn as sns
import matplotlib.pyplot as plt
import warnings

warnings.filterwarnings("ignore")

for i in data.select_dtypes(include="number").columns:
    sns.histplot(data=data, x=i)
    plt.show()

В código acima, após importar todas as bibliotecas necessárias, começamos ignorando os avisos para obter uma saída limpa. Em seguida, percorremos as colunas numéricas. 'data.select_dtypes(include="number")' retorna um DataFrame contendo apenas colunas numéricas. 'columns' retorna os nomes dessas colunas. Agora vamos construir histogramas com base nos dados. Abaixo estão os histogramas gerados a partir do código acima.

OPEN

   

HIGH

LOW

CLOSE

TICKVOL

RSI

Após realizar operações estatísticas, podemos prosseguir para o treinamento do modelo com os dados coletados. O objetivo é possibilitar previsões baseadas nos dados históricos coletados. Faremos previsões usando apenas o indicador RSI. Antes de prosseguir, precisamos entender o tipo de relação existente entre os dados. Para isso, utilizamos uma matriz de correlação. Devemos ser capazes de identificar se há uma correlação positiva, negativa ou se não há correlação.

  • Correlação positiva: Valores próximos de 1indicam uma correlação positiva forte entre duas variáveis. Por exemplo, se a correlação entre Opene Closefor próxima de 1, isso significa que ambos se movem na mesma direção.
  • Correlação negativa: Valores próximos de -1indicam uma forte correlação negativa. Por exemplo, se a correlação entre Volumee Pricefor próxima de -1, significa que, à medida que o volume aumenta, o preço tende a cair.
  • Ausência de correlação: valores próximos de 0indicam que não há correlação entre as variáveis.

mapa de calor

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import r2_score, mean_squared_error
import talib as ta  # Technical Analysis library

# Load the data
file_path = '/home/int_junkie/Documents/ML/XAUUSD.m_H1_historical.csv'
data = pd.read_csv(file_path, delimiter='\t')

# Exploratory Data Analysis (EDA)
print(data.info())
print(data.describe())

# Visualize the closing price
plt.figure(figsize=(12, 6))
plt.plot(data['<CLOSE>'])
plt.title('XAUUSD Closing Price')
plt.xlabel('<DATE>')
plt.ylabel('Price')
plt.show()

# Feature Engineering
data['RSI'] = ta.RSI(data['<CLOSE>'], timeperiod=14)

# Drop rows with missing values
data.dropna(inplace=True)

# Define target variable
data['Target'] = data['<CLOSE>'].shift(-1)
data.dropna(inplace=True)

# Split the data
X = data[['RSI']]  # Only use RSI as the feature
y = data['Target']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)

# Model Development
model = RandomForestRegressor(n_estimators=100, random_state=42)
model.fit(X_train, y_train)

# Predictions
y_pred = model.predict(X_test)

# Evaluate the model
mse = mean_squared_error(y_test, y_pred)
print(f'Mean Squared Error: {mse}')

# Visualize the predictions
plt.figure(figsize=(12, 6))
plt.plot(y_test.index, y_test, label='Actual Values')
plt.plot(y_test.index, y_pred, label='Predicted Values')
plt.xlabel('Samples')
plt.ylabel('TARGET_CLOSE')
plt.title('Actual vs Predicted Values')
plt.legend()
plt.show()


Aqui está o resultado obtido no treinamento do modelo:

  preço real

previsão vs. real

A análise dos dados mostra que os valores previstos não correspondem aos valores reais. Isso indica que o modelo não está capturando efetivamente o padrão subjacente. As razões podem ser várias:

1. Poucos dados para treinamento: Se o conjunto de dados for muito pequeno, o modelo pode não ter informações suficientes para aprender adequadamente.

2. Overfitting (Superajuste): O modelo pode ter memorizado os dados de treinamento, em vez de aprender a generalizá-los. Isso ocorre frequentemente quando o modelo é muito complexo ou não está devidamente regularizado.

3. Underfitting (Subajuste): O modelo pode ser muito simples para capturar o padrão nos dados. Isso pode ocorrer se o modelo não possuir características relevantes.

4. Parâmetros inadequados: Escolher parâmetros incorretos ou insuficientes pode fazer com que o modelo não tenha informações adequadas para realizar previsões.

Passos para diagnosticar e corrigir o problema:

1. Verifique os dados: certifique-se de que os dados estão limpos, consistentes e passaram por um bom pré-processamento.

2. Avalie o desempenho do modelo: utilize métricas como o Erro Quadrático Médio (Mean Squared Error, MSE)e o Erro Absoluto Médio (Mean Absolute Error, MAE).

3. Melhore o trabalho com os parâmetros: Experimente diferentes parâmetros, incluindo indicadores técnicos, valores defasados e outras métricas financeiras necessárias.

4. Ajuste os hiperparâmetros: Utilize métodos como Grid Searchou Random Searchpara encontrar os melhores hiperparâmetros para sua modelo.


Juntando tudo no MQL5

Após salvar o modelo, criaremos um script Python para previsão. Esse script carregará o modelo e fará previsões.

import joblib
import sys
import os
  • Joblib - usado para carregar o modelo de aprendizado de máquina serializado.
  • Sys - fornece acesso aos argumentos da linha de comando.
  • OS - usado para verificar a existência de arquivos e realizar operações com arquivos.
model_path = sys.argv[/home/int_junkie/Documents/ML/random_forest_model.pkl]
features_path = sys.argv[/home/int_junkie/Documents/ML/features.txt]
  • Sys.argv[1] - primeiro argumento da linha de comando. Esse é o caminho do arquivo do modelo.
  • Sys.argv[2] - segundo argumento da linha de comando. Esse é o caminho do arquivo de parâmetros.
print(f"Model path: {model_path}")
print(f"Features path: {features_path}")

Exibe informações de depuração. Imprime os caminhos dos arquivos do modelo e dos parâmetros para facilitar o rastreamento de erros.

if not os.path.exists(model_path):
    print(f"Error: Model file not found at {model_path}")
    sys.exit(1)

if not os.path.exists(features_path):
    print(f"Error: Features file not found at {features_path}")
    sys.exit(1)
  • Verifica se os arquivos do modelo e dos parâmetros existem.
  • Se um deles não for encontrado, o script exibe uma mensagem de erro e termina com código de status 1.
model = joblib.load(model_path)
  • Carrega o modelo treinado de aprendizado de máquina a partir do 'model-path'.
with open(features_path, 'r') as f:
    features = [float(line.strip()) for line in f]
  • Abre o arquivo de parâmetros para leitura.
  • Lê cada linha, remove espaços extras, converte os valores em número de ponto flutuante e os armazena em uma lista features.
prediction = model.predict([features])[0]
  • Usa o modelo carregado para gerar uma previsão com base nos parâmetros carregados.
  • Model.predict retorna uma lista de previsões (neste caso, uma única previsão), '[0]' extrai a primeira previsão.
print(prediction)
  • Exibe a previsão. Esses dados podem ser usados por outro script ou programa, como o MQL5, para tomar decisões de negociação.


MQL5

Carrega o modelo no OnInit().

int OnInit(){
   // Load the model and feature names
   string modelPath = "/home/int_junkie/Documents/ML/random_forest_model.pkl";
   string featurePath = "/home/int_junkie/Documents/ML/features.txt";
   
   // Your code to load the model (use appropriate library for pkl files)

   // Initialize the features
   double features[];
   int fileHandle = FileOpen(featurePath, FILE_READ | FILE_TXT);
   if (fileHandle != INVALID_HANDLE)
     {
      string line;
      while(!FileIsEnding(fileHandle))
        {
         line = FileReadString(fileHandle);
         ArrayResize(features, ArraySize(features) + 1);
         features[ArraySize(features) - 1] = StringToDouble(line);
        }
      FileClose(fileHandle);
     }

   return(INIT_SUCCEEDED);
  }

Lê previsões do script Python no OnTick().

void OnTick(){
   // Declare static variables to retain values across function calls
   static bool isNewBar = false;
   static int prevBars = 0;
   
   // Get the current number of bars
   int newbar = iBars(_Symbol, _Period);
   
   // Check if the number of bars has changed
   if (prevBars == newbar) {
       // No new bar
       isNewBar = false;
   } else {
       // New bar detected
       isNewBar = true;
       // Update previous bars count to current
       prevBars = newbar;
   }
   
   // Update the features based on current data
   double features[];
   ArrayResize(features, 1);
   features[0] = iClose(Symbol(), 0, 0);
   
   // Write the features to a file
   int fileHandle = FileOpen("/home/int_junkie/Documents/ML/features.txt", FILE_WRITE | FILE_TXT);
   if (fileHandle != INVALID_HANDLE)
     {
      for (int i = 0; i < ArraySize(features); i++)
        {
         FileWrite(fileHandle, DoubleToString(features[i]));
        }
      FileClose(fileHandle);
     }
   else
     {
      Print("Error: Cannot open features file for writing");
      return;
     }
     
      // Call the Python script to get the prediction
   string command = "python /home/int_junkie/Documents/ML/predict.py /home/int_junkie/Documents/ML/random_forest_model.pkl /home/int_junkie/Documents/ML/features.txt";
   int result = ShellExecuteA(command);
   if(result != 0)
     {
      Print("Error: ShellExecuteA failed with code ", result);
      return;
     }

   // Read the prediction from a file
   Sleep(1000); // Wait for the Python script to complete
   fileHandle = FileOpen("/home/int_junkie/Documents/ML/prediction.txt", FILE_READ | FILE_TXT);
   if (fileHandle != INVALID_HANDLE)
     {
      string prediction = FileReadString(fileHandle);
      FileClose(fileHandle);

      double pred_value = StringToDouble(prediction);

      // Generate trading signals based on predictions
      double some_threshold = 0.0; // Define your threshold
      if (pred_value > some_threshold)
        {
         // Buy signal
         double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),Digits());
         double sl =  Ask - stopLoss * _Point;
         double tp =  Ask + takeProfit * _Point;
         trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, lotsize, Ask, sl, tp, "ML");
        }
      else if (pred_value < some_threshold)
        {
         // Sell signal
         double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),Digits());
         double sl = Bid + stopLoss * _Point;
         double tp = Bid - takeProfit * _Point;
         trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, lotsize, Bid, sl, tp, "ML");
        }
     }
   else
     {
      Print("Error: Cannot open prediction file for reading");
     }
  }

No OnTick, a variável command prepara a string de comando para executar o script Python com os arquivos de parâmetros e modelo como argumentos. ShellExecuteA (command) executa o script Python usando ShellExecuteA. 'Sleep (1000)' espera 1 segundo para o script Python terminar sua execução. Em seguida, abre o arquivo de previsão para leitura. Depois, verifica se o arquivo de previsão foi aberto com sucesso. Se sim, lê a previsão. Se não, exibe um erro. A variável threshold é usada para tomar decisões de negociação. Se seu valor for maior que a previsão, um sinal de compra é gerado. Se for menor, um sinal de venda é gerado.


Considerações finais

Extraímos dados da plataforma de negociação MetaTrader 5. Depois, usamos esses dados no Jupyter Lab para análise e processamento estatístico. Após a análise no Jupyter Lab, integramos o modelo ao MQL5 para tomar decisões de negociação com base nos padrões identificados. A integração do MQL5 com Jupyter Lab resolve a limitação das capacidades analíticas, estatísticas e visuais do MQL5. Esse processo melhora a criação de estratégias, aumenta a eficiência no processamento de dados e proporciona um ambiente colaborativo, flexível e poderoso para análises avançadas e processamento estatístico no trading.

Por fim, graças à integração do MQL5 com o Jupyter Lab, conseguimos realizar análises avançadas de dados e processamento estatístico. Com essas capacidades, podemos desenvolver e otimizar qualquer estratégia de negociação usando métodos avançados. Como resultado, obtemos uma vantagem competitiva significativa no mercado financeiro, que é dinâmico e intensivo em dados.

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

Arquivos anexados |
jupyterpackage.ipynb (323.31 KB)
features.txt (0 KB)
Últimos Comentários | Ir para discussão (1)
3866233
3866233 | 3 dez. 2024 em 23:03
Fechamento máximo diário do XAUUSD
Do básico ao intermediário: Indicador (I) Do básico ao intermediário: Indicador (I)
Neste artigo criaremos o nosso primeiro indicador totalmente prático e funcional. O objetivo aqui, não é e não será mostrar como se cria de fato uma aplicação. Mas ajudar a você, meu caro leitor, a entender como você pode por conta própria, desenvolver suas próprias ideias. As colocando em prática, de forma segura, simples e prática.
Adicionando um LLM personalizado a um robô investidor (Parte 5): Desenvolvimento e teste de estratégia de trading com LLM (I) - Ajuste fino Adicionando um LLM personalizado a um robô investidor (Parte 5): Desenvolvimento e teste de estratégia de trading com LLM (I) - Ajuste fino
Os modelos de linguagem (LLMs) são uma parte importante da inteligência artificial que evolui rapidamente. E para aproveitar isso devemos pensar em como integrar LLMs avançados em nossa negociação algorítmica Muitos acham desafiador ajustar esses modelos de acordo com suas necessidades, implantá-los localmente e, logo, aplicá-los à negociação algorítmica. Esta série de artigos explorará uma abordagem passo a passo para alcançar esse objetivo.
Simulação de mercado (Parte 11): Sockets (V) Simulação de mercado (Parte 11): Sockets (V)
Vamos começar a implementar a comunicação entre o Excel e o MetaTrader 5. Mas antes é preciso entender algumas coisas importantes. Isto para que não venha a ficar coçando a cabeça tentando entender por que as coisas funcionam ou não. Mas antes que você venha a torcer o nariz para a integração entre o Python e o Excel. Vamos ver como podemos usar o xlwings, a fim de poder controlar de alguma forma o MetaTrader 5. Isto através do Excel. O que irei mostrar aqui será como foco principal a didática. Não ache que podemos fazer apenas o que mostrarei.
Reimaginando estratégias clássicas (Parte III): Prevendo máximas mais altas e mínimas mais baixas Reimaginando estratégias clássicas (Parte III): Prevendo máximas mais altas e mínimas mais baixas
Neste artigo, analisamos empiricamente estratégias de trading clássicas para verificar se é possível aprimorá-las com inteligência artificial (IA). Utilizaremos o modelo de Análise Discriminante Linear (Linear Discriminant Analysis) para tentar prever máximas mais altas e mínimas mais baixas.