English Русский Deutsch 日本語
preview
Previsão baseada em aprendizado profundo e abertura de ordens com o pacote MetaTrader 5 python e arquivo de modelo ONNX

Previsão baseada em aprendizado profundo e abertura de ordens com o pacote MetaTrader 5 python e arquivo de modelo ONNX

MetaTrader 5Sistemas de negociação | 26 junho 2024, 12:41
72 0
Javier Santiago Gaston De Iriarte Cabrera
Javier Santiago Gaston De Iriarte Cabrera

Introdução

O aprendizado profundo é uma área do aprendizado de máquina que se concentra em redes neurais artificiais, baseadas na estrutura e funções do cérebro humano. Envolve o treinamento de modelos para realizar tarefas sem programação explícita, aprendendo padrões e representações baseadas em dados. O aprendizado profundo atraiu considerável atenção devido à sua capacidade de aprender automaticamente funções e representações hierárquicas, tornando-o eficaz em várias áreas, como reconhecimento de imagens e fala, processamento de linguagem natural e muito mais.

Conceitos-chave do aprendizado profundo:

  • Redes neurais - unidades básicas do aprendizado profundo, compostas por nós interconectados ou neurônios, organizados em camadas.
  • Redes neurais profundas (Deep Neural Networks, DNNs) - redes neurais com várias camadas, permitindo que aprendam padrões complexos.
  • Aprendizado - ajuste dos parâmetros do modelo usando dados rotulados para minimizar a diferença entre os resultados previstos e os reais.
  • Funções de ativação - funções aplicadas aos sinais de saída dos neurônios para introduzir não linearidade, permitindo que o modelo aprenda relações mais complexas.
  • Retropropagação - algoritmo de otimização usado para atualizar os pesos do modelo com base no erro em suas previsões.

Python - linguagem de programação de alto nível versátil, conhecida por sua legibilidade e facilidade de uso. Ela possui um ecossistema amplo de bibliotecas e frameworks que a tornam adequada para várias aplicações, incluindo desenvolvimento web, processamento de dados, inteligência artificial e muito mais.

Características principais do Python:

  • Legibilidade - a sintaxe do Python é amigável para leitura e compreensível, permitindo que os desenvolvedores expressem conceitos com menos linhas de código.
  • Bibliotecas extensivas - Python tem um conjunto rico de bibliotecas e plataformas para várias aplicações, como NumPy e pandas para manipulação de dados, TensorFlow e PyTorch para aprendizado profundo, Django e Flask para desenvolvimento web e muitos outros.
  • Suporte comunitário - Python possui uma grande e ativa comunidade de desenvolvedores, contribuindo para seu aprimoramento contínuo e disponibilização de inúmeros recursos de aprendizado.

Uso do Python para aprendizado profundo - Python é uma linguagem popular para aprendizado profundo devido às suas extensas bibliotecas e plataformas. Duas bibliotecas principais para aprendizado profundo em Python são TensorFlow e PyTorch. Essas bibliotecas fornecem abstrações de alto nível para a construção e o treinamento de redes neurais, tornando-as acessíveis tanto para iniciantes quanto para usuários experientes.

Resumindo, pode-se dizer que o aprendizado profundo é uma abordagem funcional dentro da área mais ampla do aprendizado de máquina, e Python é uma excelente linguagem de programação para a implementação de modelos e soluções de aprendizado profundo. A combinação de Python e aprendizado profundo levou a avanços em várias áreas, tornando tarefas complexas mais acessíveis e automatizáveis.


Trabalho com ordens usando Python e MQL5: Se você está lendo este artigo, provavelmente está interessado em combinar Python com o pacote MQL5 para o processamento de ordens de negociação. O MQL5 é uma linguagem especializada projetada para negociação algorítmica na plataforma MetaTrader 5 (MT5). Aqui está um esquema geral de como você pode abordar a integração do Python com MQL5 para negociação:

  • Script Python para aprendizado profundo - desenvolva um script Python usando uma biblioteca de aprendizado profundo (por exemplo, TensorFlow, PyTorch) para criar e treinar um modelo para sua estratégia de negociação específica. Esse script realizará análises e tomará decisões com base no seu modelo de aprendizado profundo.

  • Conexão entre Python e MQL5 - estabeleça a conexão entre seu script Python e a plataforma MetaTrader 5. Isso pode ser feito por meio de vários métodos, como sockets, REST API ou outros protocolos de comunicação. O objetivo é que seu script Python possa enviar sinais de negociação ou ordens para o terminal MetaTrader.

  • Execução de ordens no MQL5 - implemente a lógica de recebimento dos sinais do script Python e a execução das ordens de compra/venda correspondentes na plataforma MetaTrader 5 em seu script ou EA MQL5. Isso envolve o uso das funções de negociação fornecidas pela linguagem MQL5.


ONNX

O Open Neural Network Exchange (ONNX) é um formato de código aberto projetado para facilitar a interoperabilidade de modelos de inteligência artificial (IA) em diferentes ambientes. O ONNX, desenvolvido e mantido pela Microsoft e pelo Facebook, permite que os usuários treinem modelos usando uma plataforma e os implementem com outra.

A principal vantagem do ONNX é sua capacidade de servir como um formato intermediário entre diferentes plataformas de aprendizado profundo, como TensorFlow, PyTorch e outras. Essa intercambiabilidade simplifica o processo de integração de modelos de aprendizado de máquina em várias aplicações, ambientes e plataformas.

No contexto do MQL5 (MetaQuotes Language 5), a integração de modelos ONNX envolve a conversão de um modelo de aprendizado de máquina treinado para o formato ONNX. Depois de convertido para o formato ONNX, o modelo pode ser carregado em scripts ou EAs MQL5, permitindo o uso de capacidades avançadas de aprendizado de máquina para estratégias de negociação algorítmica na plataforma MetaTrader 5.


Introdução breve

Vamos nos aprofundar no fascinante mundo do aprendizado profundo aplicado à negociação automatizada. O foco principal será em um programa destinado ao trading automatizado que utiliza métodos avançados de aprendizado profundo. Exploraremos as nuances do teste de desempenho do modelo usando indicadores-chave como erro absoluto médio (MAE), erro quadrático médio (MSE) e R-quadrado (R2). Este estudo visa fornecer insights sobre a eficácia do modelo de aprendizado profundo no contexto do trading algorítmico, bem como avaliar a precisão de suas previsões e a confiabilidade geral. Iremos revelar a interconexão entre aprendizado profundo, trading automatizado e testes de desempenho abrangentes.


Além disso, discutiremos o processo de conversão de um script Python (.py) em um arquivo executável para obter um pacote completo e conveniente. Este guia passo a passo fornecerá informações detalhadas para uma compreensão completa de todo o processo. Ao final do artigo, você não apenas terá um entendimento profundo da implementação do aprendizado profundo no trading automatizado, mas também conhecimentos práticos sobre como transformar sua solução em um formato executável conveniente. Acompanhe o guia detalhado que ajudará a fazer a transição suave da escrita de código para um programa executável completo, tornando sua experiência tanto educativa quanto praticamente útil.


Como etapa final do artigo, criarei um script para gerar a saída no formato ONNX. O script facilitará a inclusão do modelo ONNX no MetaTrader 5 (MT5) usando um EA (Expert Advisor). Isso aumentará a adaptabilidade e integração das capacidades de aprendizado de máquina na plataforma MetaTrader 5, facilitando o desenvolvimento de estratégias de trading algorítmico mais sofisticadas e eficazes.


Antes de começar a escrever o código

Nosso objetivo é desenvolver um bot Python que segue um processo em duas etapas: primeiro, ele realiza uma análise profunda dos dados disponíveis e, em seguida, executa ordens de trading. Considerando que o MetaTrader 5 facilita o carregamento de uma grande quantidade de dados de ticks, nossa estratégia envolve obter esses dados e transformá-los em informações de preços. A metodologia de conversão incluirá a média dos valores dos ticks, permitindo-nos criar uma representação mais gerenciável dos preços de mercado para análise e tomada de decisões em nosso bot.


Mas antes de prosseguir, precisamos usar Python. Para uma configuração conveniente do Python, é recomendável baixar e instalar o Anaconda. Além disso, a instalação do Visual Studio Code fornecerá um ambiente conveniente para escrever scripts.


Anaconda

VSC

Após instalar o Anaconda e o Visual Studio Code, o próximo passo será instalar alguns pacotes usando pip no Visual Studio Code.

Você pode fazer isso abrindo o terminal integrado no Visual Studio Code e usando os seguintes comandos (se você estiver usando Conda/Anaconda, execute esses comandos no Anaconda Prompt):

pip install [package1] [package2] ...

Substitua [package1], [package2] etc. pelos nomes dos pacotes Python específicos que você precisa para seu projeto. Isso garante que seu ambiente esteja equipado com as ferramentas e bibliotecas necessárias para continuar o desenvolvimento do seu bot em Python.


Pacotes

Você precisa instalar certos pacotes para o ambiente Python, incluindo MetaTrader 5, TensorFlow e outras bibliotecas fornecidas com o Anaconda. Aqui está um guia geral para a instalação dessas bibliotecas:

  1. MetaTrader 5 (MT5) - plataforma de negociação. Infelizmente, até a minha última atualização de conhecimentos em janeiro de 2022, o MetaTrader 5 não possui um API Python direto disponível no distribuidor oficial. No entanto, podem existir algumas bibliotecas ou wrappers de terceiros. Por favor, consulte a documentação oficial do MetaTrader 5 ou os fóruns da comunidade relevante para obter as informações mais recentes.   

    pip install MetaTrader5
  2. TensorFlow - biblioteca popular de aprendizado de máquina. Você pode instalá-la usando o seguinte comando pip no terminal ou na linha de comando:

    pip install tensorflow


Começando a escrever código

Após a instalação bem-sucedida das bibliotecas necessárias, o próximo passo será escrever o código Python. Para isso, você precisa importar as bibliotecas que instalou. Em Python, para adicionar funcionalidade de uma biblioteca ao código, usa-se o operador import.
import MetaTrader5 as mt5
from MetaTrader5 import *
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.regularizers import l2
from sklearn.model_selection import KFold


from MetaTrader5 import *

Esta linha importa todas as funções e classes da biblioteca MetaTrader 5. O uso de * (curinga) significa que você está importando tudo, embora isso geralmente não seja recomendado devido aos potenciais conflitos de espaço de nomes.

import numpy as np

Esta linha importa a biblioteca NumPy e atribui a ela o pseudônimo np. O NumPy é amplamente utilizado para operações numéricas em Python.

from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

Estas linhas importam funções/classes específicas da biblioteca scikit-learn. Elas incluem utilitários para pré-processamento de dados, avaliação e seleção de modelos.

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.regularizers import l2

Estas linhas importam componentes da biblioteca TensorFlow, que é geralmente usada para aprendizado profundo. Elas incluem o modelo sequencial (Sequential model), camadas densas (Dense layers) e regularização L2.

from sklearn.model_selection import KFold

Esta linha importa a classe KFold da scikit-learn, que é frequentemente usada para validação cruzada em aprendizado de máquina.

Assim, seu script se prepara para usar a biblioteca MetaTrader 5 para dados financeiros, NumPy para operações numéricas, scikit-learn para utilitários de aprendizado de máquina e TensorFlow para aprendizado profundo. É necessário configurar o ambiente para análise de dados financeiros e, possivelmente, construir um modelo de aprendizado de máquina para previsões financeiras. Certifique-se de que essas bibliotecas estão instaladas no seu ambiente Python usando o gerenciador de pacotes adequado (por exemplo, pip ou conda).


Carregamento de dados

Para baixar ticks, primeiro precisamos nos conectar ao provedor de dados (MT5), e a partir daí podemos baixar o que precisamos. Para essa finalidade, usaremos o seguinte código:
# You will need to update the values for path, login, pass, and server according to your specific case.
creds = {
    "path": "C:/Program Files/XXX MT5/terminal64.exe",
    "login": account,
    "pass": clave_secreta,
    "server": server_account,
    "timeout": 60000,
    "portable": False
}
# We launch the MT5 platform and connect to the server with our username and password.
if mt5.initialize(path=creds['path'],
                  login=creds['login'],
                  password=creds['pass'],
                  server=creds['server'],
                  timeout=creds['timeout'],
                  portable=creds['portable']):
    
    print("Plataform MT5 launched correctly")
else:
    print(f"There has been a problem with initialization: {mt5.last_error()}")

Uma vez feito isso, procedemos ao download dos dados de nosso interesse para o símbolo de nosso interesse na forma de ticks.

rates = rates.drop(index=rates.index)
rates = mt5.copy_ticks_from(symbol, utc_from, 1000000000, mt5.COPY_TICKS_ALL)

O código primeiro limpa todos os dados existentes no 'rates' DataFrame e, em seguida, extrai os dados de ticks para um determinado símbolo e intervalo de tempo usando a função copy_ticks_from da biblioteca MetaTrader 5.

Como buscamos armazenar os dados em um DataFrame do Pandas (que geralmente é usado junto com o NumPy) para melhor manipulação dos dados no Python, transferiremos os dados para um DataFrame do Pandas.
rates_frame=pd.DataFrame()
# Empty DataFrame
rates_frame = rates_frame.drop(index=rates_frame.index)
rates_frame = pd.DataFrame(rates)

Este código inicializa um DataFrame do Pandas vazio chamado rates_frame, limpa todos os dados existentes nele e, em seguida, preenche-o com dados da variável rates.

Para simplificar a tarefa, vamos somar e dividir os valores bid e ask dos dados por dois. Assim, obtemos um valor médio que será nossa entrada para o aprendizado profundo.
rates_frame['time']=pd.to_datetime(rates_frame['time'], unit='s')
rates_frame['close']=(rates_frame['ask']+rates_frame['bid'])/2

Este código converte a coluna time para o formato de data e hora, usando segundos como unidade de medida, e calcula o valor médio de ask e bid, atribuindo o resultado a uma nova coluna close no DataFrame rates_frame.

A escolha das entradas para aprendizado profundo em aplicações financeiras, como a previsão de movimentos de preços, depende de vários fatores, e não há uma solução única para todos os casos. No entanto, algumas recomendações gerais devem ser consideradas:


Dados brutos vs. funções derivadas (osciladores e indicadores):

1. Dados brutos:

  • Vantagens:
    • Preservam todas as informações disponíveis sem suposições adicionais.
    • Permitem que a rede neural aprenda padrões diretamente dos dados de entrada brutos.
  • Desvantagens:
    • Podem conter ruído ou informações irrelevantes.
    • Pode ser necessário processamento adicional dos dados.

2. Funções derivadas (osciladores e indicadores):

  • Vantagens:
    • Podem capturar dinâmicas específicas do mercado.
    • Podem fornecer uma representação mais estruturada dos dados.
  • Desvantagens:
    • Introduzem suposições sobre quais funções são relevantes.
    • A eficácia depende dos indicadores escolhidos e de seus parâmetros.


Recomendações práticas:

1. Normalização dos dados:

  • Isso permite que a série seja ajustada a um determinado intervalo, com média 0 e dispersão 1, melhorando a convergência durante o treinamento.

2. Comprimento da sequência:

  • Para dados de séries temporais, o comprimento da sequência é importante. Experimente diferentes comprimentos para encontrar o equilíbrio ideal entre a detecção de padrões relevantes e a eficiência computacional.

3. Aspectos temporais:

  • Considere a inclusão de aspectos temporais, como valores defasados ou janelas deslizantes, para capturar dependências temporais.

4. Escolha das funções:

  • Experimente diferentes subconjuntos de funções para determinar quais são mais informativas para sua tarefa específica.

5. Arquitetura do modelo:

  • Ajuste a arquitetura da rede neural de acordo com a natureza dos dados de entrada. Redes Neurais Recorrentes (RNN) e Redes Neurais de Longa Memória de Curto Prazo (LSTM) são eficazes para dados sequenciais.

6. Regularização:

  • Use métodos de regularização (como dropout) para evitar o sobreajuste, especialmente ao lidar com dados multidimensionais.

7. Ajuste de hiperparâmetros:

  • Experimente diferentes configurações de hiperparâmetros para encontrar a configuração ideal para seu modelo.

Na prática, muitas vezes é útil comparar diferentes abordagens empiricamente. Algumas tarefas podem se beneficiar da simplicidade dos dados brutos, enquanto outras podem melhorar o desempenho com funções derivadas bem projetadas. É crucial encontrar um equilíbrio entre fornecer informações suficientes para treinar o modelo e evitar ruídos ou detalhes desnecessários. Além disso, reavalie regularmente a abordagem escolhida, pois a dinâmica do mercado pode mudar ao longo do tempo.


Deslocamento de dados

Agora que temos os dados em um DataFrame do Pandas, podemos enviá-los para o aprendizado profundo para processamento como dados de entrada. Há muitos artigos interessantes sobre aprendizado profundo em MQL5, então não vou me aprofundar nesse tópico. Vou direto para o aspecto prático do Python. Mas antes de enviar os dados para o TensorFlow, precisamos ter dados de entrada para o deslocamento temporal, que aplicaremos aos dados para previsão (o tempo deslocado será o tempo que buscamos prever). Por isso, temos o seguinte código.


Deslocar o DataFrame no contexto do aprendizado profundo, especialmente na previsão de séries temporais, geralmente é feito para criar sequências de variáveis de entrada e alvo. Aqui estão as razões pelas quais o deslocamento é usado no contexto do aprendizado profundo para previsão de séries temporais:

  1. Dependências temporais - modelos de aprendizado profundo, como redes neurais recorrentes (RNN) ou redes de memória de longo curto prazo (LSTM), podem capturar dependências temporais em dados sequenciais. Deslocar o DataFrame permite criar sequências onde cada sequência de entrada corresponde a um segmento de dados passados, e a sequência alvo correspondente representa dados futuros.

  2. Aprendizado sequencial - modelos de aprendizado profundo são eficazes na aprendizagem de padrões e dependências em dados sequenciais. Ao deslocar o DataFrame, você garante que as sequências de entrada e alvo estejam alinhadas no tempo, permitindo que o modelo aprenda com o contexto histórico e faça previsões com base nesse contexto.

  3. Aprendizado de pares entrada-saída - o deslocamento ajuda a criar exemplos de treinamento para o modelo de aprendizado profundo. Cada linha no DataFrame deslocado pode ser vista como um par entrada-saída, onde os dados de entrada são a sequência de observações passadas, e os dados de saída são a variável alvo que precisa ser prevista no futuro.


number_of_rows= seconds
empty_rows = pd.DataFrame(np.nan, index=range(number_of_rows), columns=df.columns)
df = df._append(empty_rows, ignore_index=True)
df['target'] = df['close'].shift(-seconds)
print("df modified",df)
  • number_of_rows - variável que representa o número de segundos.
  • empty_rows cria um novo DataFrame com valores NaN, tendo as mesmas colunas que o DataFrame original (df).
  • df.append(empty_rows, ignore_index=True) adiciona linhas vazias ao DataFrame original (df), ignorando o índice para garantir um índice contínuo.
  • df['target'] = df['close'].shift(-seconds) cria uma nova coluna target contendo os valores de close deslocados negativamente pelo número especificado de segundos. Isso geralmente é feito na preparação de dados de séries temporais para modelagem preditiva.

Agora só falta limpar os dados para que possamos usá-los como dados de entrada para o TensorFlow.

# Drop NaN values
df=df.dropna()

O resultado é um DataFrame (df) modificado, com linhas adicionais preenchidas com valores NaN e uma nova coluna "target" para os valores de close deslocados no tempo.


Aprendizado profundo

Uso de TensorFlow e Keras para criar e treinar uma rede neural para previsão de séries temporais.

# Split the data into features (X) and target variable (y)
X=[]
y=[]
X = df2[['close']]
y = df2['target']

# Split the data into training and testing sets
X_train=[]
X_test=[]
y_train=[]
y_test=[]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)

# Standardize the features
X_train_scaled=[]
X_test_scaled=[]
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# Build a neural network model
model=None
model = Sequential()
model.add(Dense(128, activation='relu', input_shape=(X_train.shape[1],), kernel_regularizer=l2(k_reg)))
model.add(Dense(256, activation='relu', kernel_regularizer=l2(k_reg)))
model.add(Dense(128, activation='relu', kernel_regularizer=l2(k_reg)))
model.add(Dense(64, activation='relu', kernel_regularizer=l2(k_reg)))
model.add(Dense(1, activation='linear'))

# Compile the model[]
model.compile(optimizer='adam', loss='mean_squared_error')

# Train the model
model.fit(X_train_scaled, y_train, epochs=int(epoch), batch_size=256, validation_split=0.2, verbose=1)

# Use the model to predict the next 4 instances
X_predict=[]
X_predict_scaled=[]

predictions = pd.DataFrame()
predictions=[]
# Empty DataFrame
#predictions = predictions.drop(index=predictions.index)
X_predict = df2.tail(segundos)[['close']]
X_predict_scaled = scaler.transform(X_predict)
predictions = model.predict(X_predict_scaled)

# Print actual and predicted values for the next 
    n  instances
print("Actual Value for the Last Instances:")
print(df.tail(1)['close'].values)

print("\nPredicted Value for the Next Instances:")
print(predictions[:, 0])
predictions=pd.DataFrame(predictions)

Preparação e treinamento da rede neural usando dados financeiros históricos para prever valores futuros. Ela utiliza as bibliotecas TensorFlow e Keras para construir e treinar o modelo. Em seguida, as previsões são impressas para os próximos exemplos com base no modelo treinado.

Explicações:

  • O modelo é inicializado como um modelo sequencial, ou seja, um conjunto linear de camadas.

  • As camadas densas representam camadas totalmente conectadas da rede neural. Os parâmetros incluem o número de neurônios (unidades), a função de ativação, a forma de entrada (aplicável apenas à primeira camada) e a regularização do núcleo (neste caso, regularização L2 com intensidade definida por k_reg).

  • activation='relu' implica na função de ativação de unidade linear retificada (Rectified Linear Unit, ReLU), comumente usada em camadas ocultas.

  • A última camada tem um neurônio com uma função de ativação linear, indicando uma saída de regressão. Se fosse uma tarefa de classificação, seria usada uma função de ativação diferente, como sigmoid ou softmax.

Esta arquitetura representa uma rede neural de propagação direta com várias camadas ocultas para fins de regressão. Ajuste os parâmetros e camadas de acordo com sua tarefa específica e características do conjunto de dados.


Previsão

Quão boa é a aproximação deste modelo?

# Calculate and print mean squared error
mse = mean_squared_error(y_test, model.predict(X_test_scaled))
print(f"\nMean Squared Error: {mse}")

# Calculate and print mean absolute error
mae = mean_absolute_error(y_test, model.predict(X_test_scaled))
print(f"\nMean Absolute Error: {mae}")

# Calculate and print R2 Score
r2 = r2_score(y_test, model.predict(X_test_scaled))
print(f"\nR2 Score: {r2}")

O código fornecido calcula e imprime três métricas de avaliação para o modelo de regressão treinado.

Explicações:

  • Erro Quadrático Médio (Mean Squared Error, MSE) - mede a diferença média quadrática entre os valores previstos e os valores reais. Quanto menor o MSE, melhor o modelo.

  • Erro Absoluto Médio (Mean Absolute Error, MAE) - mede a diferença média absoluta entre os valores previstos e os valores reais. Assim como no MSE, valores mais baixos indicam um melhor desempenho do modelo.

  • R-quadrado (R2 Score) - também conhecido como coeficiente de determinação. Mede a proporção da variância da variável dependente que pode ser prevista pela variável independente (ou várias variáveis independentes). Uma pontuação R2 de 1 indica um ajuste perfeito, enquanto uma pontuação de 0 sugere que o modelo não é melhor do que prever a média da variável alvo. Valores negativos indicam um desempenho ruim do modelo.

Essas métricas fornecem uma visão de quão bem o modelo treinado está funcionando no conjunto de teste.

Neste contexto, você precisa experimentar o volume de dados (defasagem de entrada) e o número de épocas. Por exemplo, uso dados de 900 dias e 1 época para EURUSD em um período de 2 horas (explicações serão dadas posteriormente). No entanto, também alcanço bons resultados usando significativamente menos dados e mais épocas.


Ordens

Agora que temos a funcionalidade necessária, precisamos apenas medir o tempo necessário para o script retornar os dados. Isso nos permite marcar no gráfico o ponto inicial da previsão (já que a previsão começa um pouco antes; no meu caso, leva cerca de 15-20 minutos). O ponto de partida para a abertura de ordens será quando esse tempo passar. Além disso, após usar ativamente esse bot, notei que as previsões mais precisas são feitas no primeiro quarto de todo o tempo de execução. Para aumentar a precisão, limitarei e marcarei as ordens no gráfico e as executarei durante esse período específico. Isso é facilmente implementado com time.now(). Podemos registrar o tempo nesse momento e convertê-lo em segundos, já que nossa previsão e escala no eixo X são indicadas em segundos. Considerando tudo isso, marcaremos onde começa nossa previsão, e as ordens serão acionadas a partir desse ponto inicial.

Este é um exemplo típico de ordem em Python, usando MetaTrader 5 (MT5). A função open_trade_sell2 representa uma estrutura geral para colocar uma ordem de venda na plataforma MetaTrader 5. Ela usa o método mt5.order_send para enviar uma solicitação de negociação para execução da ordem. Os parâmetros incluem a ação de negociação (buy ou sell), símbolo, tamanho do lote, número inteiro aleatório (possivelmente para identificação do número mágico), take profit (tp), stop loss (sl) e desvio.

def open_trade_sell2(action, symbol, lot,random_integer, tp, sl, deviation):
        '''https://www.mql5.com/en/docs/integration/python_metatrader5/mt5ordersend_py
        '''
        # prepare the buy request structure
        symbol_info = get_info(symbol)
        
        if action == 'buy':
            trade_type = mt5.ORDER_TYPE_BUY
            price = mt5.symbol_info_tick(symbol).ask
        elif action =='sell':
            trade_type = mt5.ORDER_TYPE_SELL
            price = mt5.symbol_info_tick(symbol).bid
        point = mt5.symbol_info(symbol).point
        print("el precio mt5 es:", price)

        buy_request = {
            "action": mt5.TRADE_ACTION_DEAL,
            "symbol": symbol,
            "volume": lot,
            "type": trade_type,
            "price": price,
            "sl":sl,
            "tp":tp,
            "deviation": deviation,
            "magic": random_integer,
            "comment": "python open",
            "type_time": mt5.ORDER_TIME_GTC, # good till cancelled
            "type_filling": mt5.ORDER_FILLING_IOC,
        }
        # send a trading request
        result = mt5.order_send(buy_request)        
        return result, buy_request

A função faz parte de um script que interage com a plataforma MetaTrader 5 para automatizar estratégias de negociação. Os passos principais incluem definir o tipo de transação, obter o preço bid ou ask atual, preparar a estrutura da solicitação de negociação e, finalmente, enviar a solicitação de negociação.


Fechamento de ordens

def close_position(position,symbol):
    """This function closes the position it receives as an argument."""
   
    request = {
        'action': mt5.TRADE_ACTION_DEAL,
        'position': position.ticket,
        'magic': position.magic,
        'symbol': symbol,
        'volume': position.volume,
        'deviation': 50,
        'type': mt5.ORDER_TYPE_BUY if position.type == 1 else mt5.ORDER_TYPE_SELL,
        'type_filling': mt5.ORDER_FILLING_FOK,
        'type_time': mt5.ORDER_TIME_GTC,
        'comment': "mi primera orden desde Python"
    }
    return mt5.order_send(request)

# Now, we define a new function that serves to close ALL open positions.
def close_all_positions(symbol):
    """This function closes ALL open positions and handles potential errors."""
   
    positions = mt5.positions_get()
    for position in positions:
        if close_position(position,symbol).retcode == mt5.TRADE_RETCODE_DONE:
            print(f"Position {position.ticket} closed correctly.")
        else:
            print(f"An error occurred while closing the position.{position.ticket}: {mt5.last_error()}")

Também podemos fechar ordens usando um EA modificado para este caso. Neste caso, o arquivo .py cria um documento e registra o tempo em minutos para o fechamento das ordens (se você usar isso, não se esqueça de deixar o arquivo na pasta File no mt5).

#Specify the path for the file and open it in write mode
file_path = "C:/XXX/MetaQuotes/Terminal/XXX/MQL5/Files/python_"+symbol+"_file.txt"
try:
    with open(file_path, "w") as file:
        # Write file parameters
        file.write(str(the_value))
    print(f"File '{file_path}' created.")
except Exception as e:
    print(f"Error creating file: {e}")

Este é um EA modificado que obtive deste usuário (você precisará adicionar os caminhos corretos para a pasta File):

//+------------------------------------------------------------------+
//|                                               Timer_modified.mq5 |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/ru/market/product/43516"
#property version   "1.000"

//--- display the window of input parameters when launching the script
#property script_show_inputs

//--- parameters for data reading
input string InpFileName="python_file.txt"; // file name
input string InpDirectoryName="Files"; // directory name
//---
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
//#include <File.mqh>
//---
CPositionInfo  m_position;                   // object of CPositionInfo class
CTrade         m_trade;                      // object of CTrade class
//--- input parameters
input uchar    InpAfterHour   = 0; // After: Hour ... (max 255)
input uchar    InpAfterMinutes= 42; // After: Minutes ... (max 255)
input uchar    InpAfterSeconds= 59; // After: Seconds ... (max 255)
//---
int file_handles;
uchar value_uchar;
long     m_after  = 0;
bool         started=false;     // flag of counter relevance
string str1,str2,str3,str4;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

int OnInit()
  {
  str1="C:/XXX/MetaQuotes/Terminal/XXXX/MQL5/Files/python_";
  str3="_file.txt";
  str2=Symbol();
  str4=str1+str2+str3;

   // Open file to read
   string file_path = str4;
   file_handles = FileOpen(file_path, FILE_READ|FILE_TXT);
   
   if(file_handles != INVALID_HANDLE)
     {
      PrintFormat("File %s opened correctly", file_path);
      
      // Read uchar value of the file
      if (FileReadInteger(file_handles, INT_VALUE))
        {
         PrintFormat("Uchar value read from file: %u", value_uchar);
         m_after  = 0;
         m_after=value_uchar;
        }
      else
        {
         Print("Error when reading the uchar value from file");
        }

      // Close file after read
      FileClose(file_handles);
     }
   else
     {
      m_after  = 0;
      m_after=InpAfterHour*60*60+InpAfterMinutes*60+InpAfterSeconds;
      PrintFormat("Error when opening file %s, error code = %d", file_path, GetLastError());
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   for(int i=PositionsTotal()-1; i>=0; i--) // returns the number of current positions
      if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
        {
         if(TimeCurrent()-m_position.Time()>=m_after)
            m_trade.PositionClose(m_position.Ticket()); // close a position
        }
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| called when a Trade event arrives                                |
//+------------------------------------------------------------------+
void OnTrade()
  {
   if(started) SimpleTradeProcessor();   
  }  
 void SimpleTradeProcessor()
  {
  str1="C:/Users/XXX/MetaQuotes/Terminal/XXX/MQL5/Files/python_";
  str3="_file.txt";
  str2=Symbol();
  str4=str1+str2+str3;
     // Open file to read it
   string file_path = str4;
   file_handles = FileOpen(file_path, FILE_READ|FILE_TXT);
   
   if(file_handles != INVALID_HANDLE)
     {
      PrintFormat("File %s is opened correctly", file_path);
      
      // Reads the uchar value from the file
      if (FileReadInteger(file_handles, INT_VALUE))
        {
         PrintFormat("value_uchar read form file: %u", value_uchar);
         m_after  = 0;
         m_after=value_uchar;
        }
      else
        {
         Print("Error while reading the value uchar from file");
        }

      // Closes the file after reading
      FileClose(file_handles);
     }
   else
     {
      m_after  = 0;
      m_after=InpAfterHour*60*60+InpAfterMinutes*60+InpAfterSeconds;
      PrintFormat("Error when opening the fileo %s, Code error = %d", file_path, GetLastError());
     }    
  }

Apresentei duas maneiras diferentes de fechar ordens. Em Python, a única coisa que faço é usar time.sleep(t), onde t é o número de segundos entre a colocação da ordem e o momento do fechamento. No entanto, essa abordagem não é muito prática, pois exige uma espera, ocupando tempo que poderia ser usado para outras operações do script. Deixo a você decidir qual método usar para fechar ordens.

Podemos gerar mais ordens, reduzindo o uso de time.sleep(), por exemplo, entre a colocação de uma ordem de compra ou venda e seu fechamento. Como? Podemos usar um EA modificado, incluindo o valor do número mágico, que permitirá fechar apenas a ordem com o número mágico e símbolo especificados. Assim, em vez de pausar a execução do script com sleep, ele pode permanecer ativo e continuar funcionando.


Visualização

Para uma visualização eficaz, vamos criar um gráfico para observar as tendências. Vamos marcar os intervalos das previsões mais confiáveis, indicar os valores máximos e mínimos nesses intervalos e salvar o gráfico.

plt.axvline(x=pt_division2, color='gray', linestyle='--', label='75 %')
plt.axvline(x=center, color='grey', linestyle='--', label='50 %')
plt.axvline(x=pt_division3, color='blue', linestyle='--', label='33 %')
plt.axvline(x=pt_division1, color='gray', linestyle='--', label='25 %')
plt.axvline(x=pt_division6, color='blue', linestyle='--', label='16 %')
plt.axvline(x=pt_division10, color='yellow', linestyle='--', label='10 %')
plt.axvline(x=pt_division14, color='blue', linestyle='--', label='7 %')
plt.axvline(x=pt_division20, color='yellow', linestyle='--', label='5 %')
plt.axvline(x=entry_point, color='orange', linestyle='--', label='entrada')
plt.axvline(x=value_25, color='orange', linestyle='--', label='salida 20%')
plt.axvline(x=maximal_index, color='red', linestyle='--', label='maximal') ##### ni idea de porqué no pinta correctamente la linea
plt.axvline(x=manimal_index, color='red', linestyle='--', label='minimal')# lo mismo aquí

plt.plot(dff5.iloc[:, 0], linestyle='-', label='Predicted')

plt.xlabel('Instances')
plt.ylabel('Prediction Price')
plt.legend()
plt.title(f'Predicted {symbol} y quedan en minutos: ' + str(MyParameter))
plt.savefig('Predicted_for_'+str(symbol)+'_quedan_'+str(MyParameter)+'_minutos_desde_'+str(formatted_now2)+'_.png')


Como o script funciona?

Primeiro, ele carrega as bibliotecas, depois marca o momento exato para rastrear a etapa atual da previsão. Depois disso, inicializa o MT5, carrega os dados, processa-os e fornece os resultados. Usamos esses resultados para criar o gráfico e executar ordens em momentos específicos, incluindo os prazos específicos para o fechamento das ordens. Além disso, temos a opção de escolher o método de fechamento das ordens.

Se você quiser repetir esse processo para o mesmo par de moedas, será suficiente um simples laço, que permitirá executar o programa continuamente com facilidade. Há apenas uma dificuldade: como determinar os dados de entrada ideais? A solução é bastante simples. Um modelo com R2 próximo de um, além de MSE e MAE próximos de zero, indica uma boa aproximação. No entanto, cuidado com o overfitting. Depois de determinar os valores de entrada ideais, você pode ignorar MSE, MAE e R2, pois seus cálculos levam um tempo considerável, e neste contexto, a velocidade de obtenção dos resultados é o mais importante.


Criação de arquivo executável

Quando começamos com um par de moedas, a primeira coisa que precisamos saber antes de colocar ordens é se nossas previsões são precisas. Considerando que o Python está em constante evolução e podemos precisar atualizar as bibliotecas, não faria mal empacotar tudo. Dessa forma, teremos um pacote consolidado, pronto para testes e experimentos.

Para isso, usaremos Tkinter e o converteremos em um arquivo executável com o auto-py-to-exe. Assim, não teremos problemas futuros ao determinar os dados de entrada e poderemos trabalhar com mais cautela no arquivo .py, que é responsável pela execução das ordens.

Vou demonstrar como criar um arquivo executável para fins de teste, deixando a você a opção de ajustar o arquivo para a execução das ordens.

Como um arquivo executável, usarei o Tkinter, que fornece uma interface gráfica para a entrada de valores. Lembre-se de que o caminho para o arquivo deve ser escrito usando "/" ou "\". A interface obterá os valores de precisão do modelo e exibirá o gráfico.

Abaixo está o código da interface gráfica (gui_console):

import tkinter as tk
from program_object import execute_program_with
from program_object_without import execute_program_without
import sys

class Aplication:
    def __init__(self, root):
        self.root = root
        self.root.title("DeepLearning Forecast")
        
        # labels and entries
        label1 = tk.Label(root, text="Input account mt5:")
        label1.pack(pady=5)

        self.value1_entry = tk.Entry(root)
        self.value1_entry.pack(pady=5)

        label2 = tk.Label(root, text="Input password:")
        label2.pack(pady=5)

        self.value2_entry = tk.Entry(root)
        self.value2_entry.pack(pady=5)

        label3 = tk.Label(root, text="Input server of mt5:")
        label3.pack(pady=5)

        self.value3_entry = tk.Entry(root)
        self.value3_entry.pack(pady=5)

        label4 = tk.Label(root, text="Input delay in days (for ticks):")
        label4.pack(pady=5)

        self.value4_entry = tk.Entry(root)
        self.value4_entry.pack(pady=5)

        label5 = tk.Label(root, text="Input timeframe 1 (1h),2,4,1d,1w:")
        label5.pack(pady=5)

        self.value5_entry = tk.Entry(root)
        self.value5_entry.pack(pady=5)

        label6 = tk.Label(root, text="Input epochs:")
        label6.pack(pady=5)

        self.value6_entry = tk.Entry(root)
        self.value6_entry.pack(pady=5)

        label7 = tk.Label(root, text="Input symbol:")
        label7.pack(pady=5)

        self.value7_entry = tk.Entry(root)
        self.value7_entry.pack(pady=5)


        label8 = tk.Label(root, text="Input path for mt5:")
        label8.pack(pady=5)

        self.value8_entry = tk.Entry(root)
        self.value8_entry.pack(pady=5)

        # Radio button to select program to execute
        self.opcion_var = tk.StringVar(value="program_object")
        radio_btn_object = tk.Radiobutton(root, text="With r2 Score, MAE & MSE", variable=self.opcion_var, value="program_object")
        radio_btn_object.pack(pady=5)
        radio_btn_object_without = tk.Radiobutton(root, text="Without", variable=self.opcion_var, value="program_object_without")
        radio_btn_object_without.pack(pady=5)

        # Botón start
        boton_execute = tk.Button(root, text="Run Program", command=self.execute_programa)
        boton_execute.pack(pady=10)

        # Botón close
        boton_quit = tk.Button(root, text="Exit", command=root.destroy)
        boton_quit.pack(pady=10)

    def write(self, text):
        # this method y called when sys.stdout.write is used
        self.salida_text.insert(tk.END, text)
    def flush(self):
        pass
    def execute_program(self):
        # Obteined value of the selected option
        selected_program = self.opcion_var.get()

        # Obteined value of inputs
        value1 = self.value1_entry.get()
        value2 = self.value2_entry.get()
        value3 = self.value3_entry.get()
        value4 = self.value4_entry.get()
        value5 = self.value5_entry.get()
        value6 = self.value6_entry.get()
        value7 = self.value7_entry.get()
        value8 = self.value8_entry.get()

                # Redirects stdout & stderr to the console
        sys.stdout = sys.__stdout__
        sys.stderr = sys.__stderr__

        # Calls the function to execute a selected program and pass values as arguments
        if selected_program == "program_object":
            execute_program_with(value1, value2, value3, value4, value5, value6, value7, value8)
        elif selected_program == "program_object_without":
            execute_program_without(value1, value2, value3, value4, value5, value6, value7, value8)
        # Restores stdout to a predeterminate value to no have conflicts
        sys.stdout = self
        sys.stderr = self

if __name__ == "__main__":
    root = tk.Tk()
    app = Aplication(root)
    root.mainloop()

E este é o código chamável (onde você precisa inserir seu código):

import sys
import MetaTrader5 as mt5
from MetaTrader5 import *
import matplotlib.pyplot as plt
import seaborn as sns  # Import seaborn for residual plot



def main(value1, value2, value3, value4, value5, value6, value7,value8):
    # Now you can use variables value1, value2, value3, value4, value5, value6, value7 en tu programa
    print("Numero de cuenta mt5 en mt5: ", value1)
    print("Password en mt5: ", value2)
    print("Servidor en mt5: ", value3)
    print("Delay dias ticks: ", value4)
    print("Time frame: ", value5)
    print("Epochs: ", value6)
    print("Symbol: ", value7)
    print("Path a mt5: ", value8)
    

def execute_program_with(value1, value2, value3, value4, value5, value6, value7, value8):
    main(value1, value2, value3, value4, value5, value6, value7, value8)

Ele termina da seguinte maneira:

if __name__ == "__main__":
    value1, value2, value3, value4, value5, value6, value7 = sys.argv[1:]
    main(value1, value2, value3, value4, value5, value6, value7)

Um código com as avaliações das previsões do modelo e o gráfico, e outro que apenas exibe o gráfico.

Para converter isso em um arquivo executável, usaremos o auto-py-to-exe. Primeiro, instalamos a biblioteca.

pip install auto-py-to-exe

Executamos ela, simplesmente digitando no terminal auto-py-to-exe.

Não se esqueça de adicionar gui_consola, bem como os arquivos programa_objetivo.py e programa_objetivo_sin.py na localização do script. Clique em convert py to exe.

auto-py-to-exe

Talvez você precise usar o ambiente conda, para isso basta digitar

conda activate XXX

onde XXX é o nome do ambiente.

Você pode encontrar problemas com o Conda. Nesse caso, remova o Anaconda do painel de controle (vá para 'Desinstalar um programa') e instale o Python diretamente do site oficial. Você pode baixá-lo aqui. Certifique-se de escolher o sistema operacional correto.

Ao instalar o Python, não se esqueça de adicionar o caminho às variáveis de sistema. Além disso, desative as restrições de comprimento de caminho.

Para concluir a configuração, instale matplotlib, seaborn e sklearn, executando o seguinte comando no terminal ou linha de comando:

pip install matplotlib
pip install seaborn
pip install scikit-learn


Interface gráfica

O termo "Tk GUI" refere-se à interface gráfica do usuário (GUI), criada usando o conjunto de ferramentas Tkinter no Python. Tkinter é um módulo integrado da biblioteca padrão do Python que simplifica o desenvolvimento de interfaces gráficas.

Ele se parece com isso:

Interface gráfica


Não se esqueça de adicionar o caminho para o mt5 e substituir "" por "/", como aqui:

C:/Program Files/XXX MT5/terminal64.exe


Interface gráfica

Isso é mais ou menos o que você verá na interface gráfica quando embalá-la em um arquivo executável e executá-la.

001


Os resultados para o testador se parecem com isso:

tester001


Os valores dentro do retângulo vermelho são bastante importantes e, obviamente, estão longe do ideal. É necessário obter um valor de R-quadrado próximo de 1, e MSE e MAE próximos de 0. Devo tentar usar mais dados e/ou mais épocas, além de alterar no script o valor para L2 (eventualmente conseguiremos um bom ajuste e poderemos criar ordens, isso é parecido com um jogo).

Métricas utilizadas:

R2 (R-quadrado), MSE (erro quadrático médio) e MAE (erro absoluto médio) são métricas amplamente utilizadas em estatísticas e aprendizado de máquina para avaliar o desempenho de modelos:

  1. R2 (R-quadrado):

    • R2 é uma medida estatística que representa a proporção da variância da variável dependente que pode ser prevista a partir da variável (ou variáveis) independente(s).
    • Vai de 0 a 1, onde 0 indica que o modelo não explica a variabilidade da variável dependente, e 1 indica uma explicação perfeita.
  2. MSE (erro quadrático médio):

    • MSE é uma métrica que calcula a diferença quadrática média entre os valores reais e previstos.
    • Ela penaliza erros maiores de forma mais severa do que erros menores, tornando-a sensível a outliers.
    • Matematicamente, é a soma dos quadrados das diferenças dividida pelo número de observações.
  3. MAE (erro absoluto médio):

    • MAE é uma métrica que calcula a diferença absoluta média entre os valores reais e previstos.
    • Ao contrário do MSE, não eleva ao quadrado as diferenças, tornando-o menos sensível a outliers.
    • É a soma das diferenças absolutas dividida pelo número de observações.

Essas métricas são comumente usadas em análise de regressão para avaliar quão bem o modelo pode prever a variável resultante. Em geral, valores mais altos de R2 e valores mais baixos de MSE ou MAE indicam um modelo mais eficaz.


Overfitting

O overfitting no aprendizado profundo para negociação envolve treinar um modelo que funciona bem em dados históricos, mas não consegue generalizar efetivamente para novos dados que ainda não encontrou. Aqui estão alguns perigos associados ao overfitting no contexto do aprendizado profundo em trading:

  1. Generalização limitada: um modelo overfit pode capturar ruído ou padrões específicos nos dados históricos que não refletem a verdadeira dinâmica do mercado. Como resultado, o modelo pode ter dificuldade em generalizar para novas condições de mercado ou dados.
  2. Desempenho ruim em dados reais: como o modelo overfit essencialmente memoriza os dados históricos, ele pode ter um desempenho ruim ao lidar com dados reais de mercado. O modelo pode fazer previsões imprecisas ou ser incapaz de se adaptar às tendências de mercado em mudança.
  3. Mudanças de regime de mercado: os mercados financeiros são dinâmicos, e diferentes regimes de mercado (tendência de alta, tendência de baixa, lateralização) podem ter características únicas. Um modelo overfit, treinado em um regime de mercado específico, pode falhar quando o mercado muda de regime, pois carece de adaptabilidade.
  4. Sinais falsos: o overfitting pode levar o modelo a capturar ruído ou outliers nos dados históricos, resultando em sinais falsos. Esses sinais falsos podem enganar as estratégias de negociação, levando a perdas financeiras em cenários reais de negociação.
  5. Erro de rastreamento de dados: o overfitting pode ser exacerbado por rastreamento de dados ou vazamento de dados. Se o modelo for exposto acidentalmente a informações do conjunto de teste durante o treinamento, ele pode aprender padrões que não generalizam bem para dados ainda não encontrados.
  6. Sensibilidade aos hiperparâmetros: modelos overfit podem ser excessivamente sensíveis aos hiperparâmetros, tornando difícil ajustá-los com precisão para garantir um desempenho confiável em diferentes condições de mercado.

Para minimizar esses perigos, especialistas em aprendizado profundo em trading frequentemente utilizam estratégias como validação cruzada, métodos de regularização e a inclusão de features que refletem um entendimento mais amplo da dinâmica do mercado. Além disso, é necessário ter cautela ao interpretar a eficácia do modelo em dados históricos e verificar seu desempenho em conjuntos de dados fora da amostra. O monitoramento regular e o re-treinamento dos modelos também são necessários para se adaptar às condições de mercado em mudança.

Validação cruzada no aprendizado profundo:

A validação cruzada é um método estatístico usado para avaliar o desempenho de um modelo de aprendizado de máquina. No contexto do aprendizado profundo, a validação cruzada envolve dividir o conjunto de dados em vários subconjuntos ou dobras (folds). O modelo é treinado em alguns desses folds e testado nos restantes. Esse processo é repetido várias vezes, com diferentes folds sendo usados para treinamento e teste em cada iteração. As métricas de desempenho são então calculadas e médias em todas as iterações para fornecer uma avaliação mais robusta do desempenho do modelo.

Os tipos comuns de validação cruzada incluem a validação cruzada k-fold, em que o conjunto de dados é dividido em k convoluções e cada convolução é usada como um conjunto de teste exatamente uma vez, e a validação cruzada leave-one-out, em que cada ponto de dados é tratado como uma única convolução.

A validação cruzada ajuda a avaliar quão bem o modelo generaliza para dados não vistos, reduzindo o risco de overfitting ou underfitting.

Regularizador de núcleo (kernel_regularizer=l2):

No contexto do aprendizado profundo e das redes neurais, o termo regularizador de núcleo refere-se a um método de regularização aplicado aos pesos (ou núcleos) das camadas da rede neural. O parâmetro kernel_regularizer=l2 especificamente indica o uso da regularização L2 para os pesos.

A regularização L2 adiciona um termo de penalidade à função de perda, proporcional ao quadrado dos valores dos pesos. O objetivo é evitar que qualquer peso individual se torne muito grande e domine o processo de treinamento. Isso ajuda a prevenir o overfitting, impedindo que o modelo se ajuste excessivamente aos dados de treinamento.

Assim, kernel_regularizer=l2 é um método de regularização usado para controlar a complexidade da rede neural, penalizando grandes pesos. É uma das ferramentas para resolver problemas de overfitting em modelos de aprendizado profundo.


Gráfico

O gráfico é salvo no local onde você executa o script.

O número indicado no título é o tempo em minutos desde a primeira linha laranja até o final do gráfico.

Você pode modificar o que precisa no gráfico (por exemplo, mostrar apenas o intervalo entre as linhas laranjas com este código de linha):

plt.plot(dff5.iloc[punto_entrada, valor_25], linestyle='-', label='Predicted')

Basta ler o código e tentar entendê-lo.

Gráfico

Aqui está o gráfico gerado. As linhas vermelhas indicam onde colocar ordens de compra/venda e fechamento. As linhas laranjas representam o intervalo em que o modelo é considerado mais confiável e preciso, especialmente nos primeiros 20% do intervalo. Neste caso, usei o timeframe de 4 horas, portanto, o intervalo ideal é a primeira hora, mostrando os pontos máximos e mínimos para entrada e saída. Assim que o script atingir o fim, ele se repetirá, e se adicionarmos ordens, continuará funcionando continuamente. As outras linhas marcadas ajudam a se posicionar no gráfico ao colocar ordens manualmente.

O preço indicado nas previsões é aproximado. O importante é saber onde estão os mínimos e máximos no intervalo.


Como usar tudo isso

O que eu faço:

Primeiro, experimento com o símbolo, usando a interface gráfica e testando-o com R2, MAE e MSE. Eu experimento diferentes valores de épocas e dias de atraso. Em segundo lugar, uma vez que eu determine valores promissores para a previsão, evitando cuidadosamente o overfitting, passo para o script. Automatizo o script para execução autônoma de ordens, alugando um VPS para execução contínua de ordens durante a semana. É importante notar que, em caso de erros significativos, também existe um parâmetro que pode ser ajustado. Por exemplo, no caso das criptomoedas, pode-se escolher L2 igual a 0,01 em vez de 0,001, que é usado para forex. Por meio de tentativa e erro, é possível determinar os valores ótimos para a quantidade de dados (dias de atraso) e épocas.


É importante considerar que o cálculo do MSE, R2 e MAE leva aproximadamente uma época. Portanto, é aconselhável realizar experimentos inicialmente. Após atingir uma boa aproximação do modelo, ele pode ser usado sem esses parâmetros. No Python, isso é alcançado comentando (desativando) o código correspondente ou usando o símbolo #.


Com este programa Python, uso um ciclo. Em caso de falha ao fechar ordens (implementei um mecanismo de cancelamento de ordens por símbolo), também utilizo o timer.mql5, pois tenho um intervalo definido para as ordens, que é de uma hora. Isso garante que nenhuma ordem permaneça aberta por mais de uma hora.


Laço

Para fazer um laço no DeepLearningForecast, em vez de while = True, podemos fazer o seguinte (Loop.py):

import time
import subprocess

def execute_program():
    
    subprocess.run(['python', 'DeepLearningForecast.py'])

# Stablish and interval in seconds (for example, 60 seconds)
seconds_interval = 5


while True:
    execute_program()
    print(f"Program executed. Waiting {seconds_interval} seconds")

    # waits the interval before executing the program
    time.sleep(seconds_interval)


Bot do Telegram

No MetaTrader 5 já existem várias maneiras de visualizar informações, mas com relação a este bot, às vezes me interessa saber se ele está prevendo corretamente e executando as ordens corretamente. Para monitorar essas ações e posteriormente comparar as previsões com o gráfico real, envio o gráfico e as informações correspondentes para um bot do Telegram. Abaixo explico como criar um bot do Telegram e enviar dados por meio dele.

Guia passo a passo para criar um bot do Telegram e obter o ID do chat e o token para enviar mensagens por meio de requisições:

Criação de um bot do Telegram:

  1. Abra o Telegram e encontre o BotFather:

    • Abra o Telegram e digite BotFather na barra de pesquisa.
    • Inicie um chat com o BotFather.
  2. Criação de um novo bot:

    • Use o comando /newbot para criar um novo bot.
    • Siga as instruções do BotFather para atribuir um nome ao bot e também um nome de usuário.
    • Após a conclusão, o BotFather fornecerá um token. Esse token é necessário para autenticar seu bot.

Obtenção do ID do chat:

  1. Inicie um chat com seu bot:

    • Após criar o bot, inicie um chat com ele no Telegram.
  2. Visite o URL da API do bot:

    • Abra um navegador da web e vá para o seguinte URL, substituindo BOT_TOKEN pelo token do seu bot:
    https://api.telegram.org/botBOT_TOKEN/getUpdates
  1. Envie uma mensagem para o bot:

    • Volte ao Telegram e envie uma mensagem para o bot com o qual você iniciou o chat.
  2. Atualize a página do navegador:

    • Volte para a página do navegador onde você inseriu o URL da API do bot.
    • Atualize a página.
  3. Encontre o ID do chat:

    • Na resposta JSON, encontre a seção contendo o histórico de mensagens.
    • Encontre o objeto que representa a mensagem que você enviou recentemente.
    • Dentro desse objeto, encontre o campo chat. Dentro dele, o campo id será o identificador do chat.


Como resultado, você poderá receber uma mensagem semelhante a esta (para monitorar o bot).

Mensagem no Telegram



Outras correções

Como não gostei de como as ordens são fechadas, modifiquei o script para aproveitar as tendências. Adicionei uma média móvel simples (SMA) e configurei para fechar as ordens quando o preço cruzar a SMA.

Então, para corrigir isso:

SMA


Eu adicionei o seguinte:

def obtain_sma_pandas(symbol, periodo):
    prices = mt5.copy_rates_from_pos(symbol, mt5.TIMEFRAME_M1, 0, periodo)
    df_sma = pd.DataFrame(prices)
    sma = df_sma['close'].rolling(window=periodo).mean().iloc[-1]
    return sma

Além disso:

    action="buy"
    price = mt5.symbol_info_tick(symbol).ask
    period_sma=14
    sma = obtain_sma_pandas(symbol, period_sma)
    while True:
        # Obtener el precio actual y la SMA
        actual_price = price
        sma = obtain_sma_pandas(symbol, period_sma)

        # Si el precio está por debajo de la SMA, cerrar la orden
        if actual_price > sma:
            close_all_position(symbol)
            continue

        # Esperar antes de verificar nuevamente
        time.sleep(10)

Você também pode adicionar o ADX ao script para procurar negociações durante períodos de tendência da seguinte forma:

def calculate_adx(high, low, close, period):

    tr_pos = []
    tr_neg = []

    for i in range(1, len(close)):
        trh = max(high[i] - high[i - 1], 0)
        trl = max(low[i - 1] - low[i], 0)

        if trh > trl:
            tr_pos.append(trh)
            tr_neg.append(0)
        elif trl > trh:
            tr_pos.append(0)
            tr_neg.append(trl)
        else:
            tr_pos.append(0)
            tr_neg.append(0)

    atr = pd.Series(tr_pos).ewm(span=period, adjust=False).mean() + pd.Series(tr_neg).ewm(span=period, adjust=False).mean()
    dx = (pd.Series(tr_pos).ewm(span=period, adjust=False).mean() / atr) * 100
    adx = dx.ewm(span=period, adjust=False).mean()

    return adx.iloc[-1]


ONNX

Agora, utilizando as ideias do artigo "Uso de Modelos ONNX no MQL5" da MetaQuotes, eu converto o modelo para o formato ONNX. Seguindo as recomendações apresentadas no mesmo artigo, eu integro o modelo ONNX resultante no EA básico para iniciar as operações de negociação. Essa abordagem permite integrar suavemente os modelos de aprendizado de máquina no ambiente MQL5, expandindo as capacidades do algoritmo de negociação.

Antes de formatar para ONNX, é necessário baixar os dados. Para isso, usaremos o script que carreguei (ticks_to_csv). Basta salvá-lo na pasta do EA do MQL5, abrir no IDE e compilar. Depois disso, adicione o script ao gráfico e deixe-o funcionar por algum tempo (como ele carrega todos os ticks para o símbolo, o processo pode demorar). No diário, você verá uma mensagem indicando a conclusão do processo. Eu o usei para EURUSD, e ele ocupou vários gigabytes.

#property script_show_inputs
#property strict
//--- Requesting 100 million ticks to be sure we receive the entire tick history
input long      getticks=100000000000; // The number of required ticks
string fileName = "ticks_data.csv";
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   int     attempts=0;     // Count of attempts
   bool    success=false;  // The flag of a successful copying of ticks
   MqlTick tick_array[];   // Tick receiving array
   MqlTick lasttick;       // To receive last tick data

   SymbolInfoTick(_Symbol,lasttick);
//--- Make 3 attempts to receive ticks
   while(attempts<3)
     {

      //--- Measuring start time before receiving the ticks
      uint start=GetTickCount();
      //--- Requesting the tick history since 1970.01.01 00:00.001 (parameter from=1 ms)
      long received=CopyTicks(_Symbol,tick_array,COPY_TICKS_ALL,1,getticks);

      // Check if ticks were successfully copied
      if(received > 0)
        {
         // Open the CSV file for writing
         int fileHandle = FileOpen(fileName, FILE_WRITE | FILE_CSV);

         // Check if the file was opened successfully
         if(fileHandle != INVALID_HANDLE)
           {
            // Write the CSV header
            FileWrite(fileHandle, "Time,Bid,Ask");

            // Write tick data to the CSV file
            for(long i = 0; i < received; i++)
              {
               string csvLine = StringFormat("%s,%.5f,%.5f", TimeToString(tick_array[i].time), tick_array[i].bid, tick_array[i].ask);
               FileWrite(fileHandle, csvLine);
              }


            // Close the CSV file
            FileClose(fileHandle);

            // Print success message
            Print("Downloaded ", received, " ticks for symbol ", _Symbol, " and period ", Period());
            Print("Ticks data saved to ", fileName);
           }
         else
           {
            // Print an error message if the file could not be opened
            Print("Failed to open the file for writing. Error code: ", GetLastError());
           }
        }
      else
        {
         // Print an error message if no ticks were downloaded
         Print("Failed to download ticks. Error code: ", GetLastError());
        }

      if(received!=-1)
        {
         //--- Showing information about the number of ticks and spent time
         PrintFormat("%s: received %d ticks in %d ms",_Symbol,received,GetTickCount()-start);
         //--- If the tick history is synchronized, the error code is equal to zero
         if(GetLastError()==0)
           {
            success=true;
            break;
           }
         else
            PrintFormat("%s: Ticks are not synchronized yet, %d ticks received for %d ms. Error=%d",
                        _Symbol,received,GetTickCount()-start,_LastError);
        }
      //--- Counting attempts
      attempts++;
      //--- A one-second pause to wait for the end of synchronization of the tick database
      Sleep(1000);
     }
  }

E desses dados (CSV), leremos e usaremos o segmento necessário, convertendo-o em um DataFrame (DeepLearning_ONNX.py foi definido para os últimos 1000 dias até hoje). Você pode usar todo o conjunto de dados, mas precisará de bastante memória RAM.

Após carregar os dados, podemos iniciar o treinamento do modelo ONNX usando o arquivo DeepLearningForecast_ONNX_training.py. (Salve o arquivo na pasta dentro da pasta File no MQL5).

Os dados são importados da seguinte maneira:

rates = pd.read_csv(file_path, encoding='utf-16le')

O modelo é criado da seguinte forma:

onnx_model = tf2onnx.convert.from_keras(model, output_path=output_path)


Considerações finais

Em conclusão, este artigo apresenta uma abordagem abrangente para o desenvolvimento de um script Python para negociação automática usando aprendizado profundo. Exploramos a integração com o MetaTrader 5, o pré-processamento de dados, o treinamento do modelo e a execução de ordens de compra/venda. O uso do Tkinter e do auto-py-to-exe para criar um arquivo executável com uma interface amigável adiciona praticidade ao script.

Além disso, discutimos a escolha de dados de entrada apropriados, a avaliação da eficácia do modelo e a implementação de estratégias eficazes de fechamento de ordens. A saída visual do script, demonstrando previsões, intervalos confiáveis e colocação de ordens, oferece uma visão clara e prática tanto para a negociação automática quanto manual.

No futuro, aprenderemos a importar todos os ticks para um par de moedas. Usamos Python para ler os dados, criar o modelo ONNX e (se o próximo artigo for de interesse) executar o modelo no MetaTrader 5 usando um EA.

No entanto, é importante enfatizar a natureza dinâmica dos mercados financeiros, garantindo monitoramento constante, adaptação e melhorias potenciais do modelo. A estrutura apresentada serve como uma base sólida, e os usuários são incentivados a adaptá-la e aprimorá-la continuamente para atender às condições de mercado em mudança e aos seus objetivos específicos de negociação.


Declaração de Isenção de Responsabilidade

Declaração de isenção de responsabilidade: resultados passados não garantem resultados futuros. Negociar criptomoedas e outros instrumentos financeiros envolve risco. Nenhuma estratégia pode garantir lucro. Sempre realize uma pesquisa cuidadosa e consulte especialistas financeiros antes de tomar decisões de investimento.


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

Arquivos anexados |
Timer.mq5 (4.57 KB)
Timer_modified.mq5 (9.73 KB)
Loop.py (0.4 KB)
gui_console.py (3.85 KB)
program_object.py (23.96 KB)
ticks_to_csv.mq5 (3.27 KB)
Algoritmos de otimização populacionais: algoritmo genético binário (Binary Genetic Algorithm, BGA). Parte II Algoritmos de otimização populacionais: algoritmo genético binário (Binary Genetic Algorithm, BGA). Parte II
Neste artigo, vamos considerar o algoritmo genético binário (BGA), que modela os processos naturais que ocorrem no material genético dos seres vivos na natureza.
Redes neurais de maneira fácil (Parte 72): previsão de trajetórias em condições de ruído Redes neurais de maneira fácil (Parte 72): previsão de trajetórias em condições de ruído
A qualidade da previsão de estados futuros desempenha um papel importante no método Goal-Conditioned Predictive Coding, com o qual nos familiarizamos no artigo anterior. Neste artigo, quero apresentar a vocês um algoritmo capaz de aumentar significativamente a qualidade da previsão em ambientes estocásticos, que incluem os mercados financeiros.
Desenvolvendo um EA multimoeda (Parte 1): várias estratégias de trading trabalhando juntas Desenvolvendo um EA multimoeda (Parte 1): várias estratégias de trading trabalhando juntas
Existem várias estratégias de trading. Do ponto de vista da diversificação de riscos e do aumento da estabilidade dos resultados de trading, pode ser útil usar várias estratégias em paralelo. Mas se cada estratégia for implementada como um EA separado, gerenciar o trabalho conjunto delas em uma conta de trading se torna muito mais complicado. Para resolver esse problema, é um boa idea implementar o trabalho de diferentes estratégias de trading em um único EA.
EA de grid-hedge modificado em MQL5 (Parte II): Criando um EA de grade simples EA de grid-hedge modificado em MQL5 (Parte II): Criando um EA de grade simples
O artigo aborda a estratégia clássica de grade, descrevendo detalhadamente sua automação com um EA em MQL5 e analisando os resultados iniciais dos testes históricos. Também enfatiza a necessidade de manter posições por um longo período e considera a possibilidade de otimização de parâmetros-chave (como distância, take-profit e tamanhos de lotes) em futuras partes. O objetivo desta série de artigos é aumentar a eficiência da estratégia de negociação e sua adaptabilidade a diferentes condições de mercado.