English Русский Deutsch 日本語
preview
Negociação algorítmica com MetaTrader 5 e R para iniciantes

Negociação algorítmica com MetaTrader 5 e R para iniciantes

MetaTrader 5Negociação | 25 junho 2024, 09:53
30 0
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana



Introdução

MetaTrader é um produto mundialmente reconhecido no campo das plataformas de negociação. Este software, conhecido por sua alta qualidade, é gratuito, o que o torna acessível a uma ampla gama de usuários. Por esse motivo, a comunidade MetaTrader tem registrado um crescimento sustentável ano após ano. A comunidade, que agora é mais diversificada do que nunca em sua história, inclui pessoas de diferentes origens culturais e com excelentes habilidades em linguagens de programação. É notável que, além do MetaQuotes Language 5 (a linguagem oficial da plataforma), o Python é a única linguagem de programação com suporte completo na plataforma MetaTrader.

A comunidade MetaQuotes sempre dá as boas-vindas aos novos membros que fazem a transição R, independentemente de sua experiência em meio acadêmico ou em computação científica. Apesar dos avanços em Python e a integração exclusiva do Python como a única linguagem (além do MQL5) totalmente suportada no terminal MetaTrader, pessoas que dominam R não devem considerar suas habilidades de programação como obsoletas. Este artigo desafia qualquer noção de obsolescência, mostrando que, com um pouco de criatividade e engenhosidade, é perfeitamente possível criar um Expert Advisor de negociação algorítmica complexo usando R e MetaTrader 5.

Com base na experiência do autor, é importante notar que os pacotes discutidos neste artigo demonstram interação imperfeita quando usados separadamente no terminal MetaTrader 5. Cada pacote tem suas limitações. No entanto, quando usados em conjunto, esses pacotes compensam efetivamente as limitações uns dos outros, formando uma base confiável que facilita o desenvolvimento de algoritmos de negociação usando R e MetaTrader.

Pontos de atenção:

1. Considerações sobre o sistema operacional:

A demonstração foi realizada em um computador rodando o Windows 11, build 22621.1848. Esses passos não foram testados em sistemas operacionais alternativos.

2. Compatibilidade da versão do R:

A demonstração utiliza a versão 4.3.2 do R. É fundamental que os participantes usem a mesma versão do R, pois alguns pacotes apresentados nesta apresentação não suportam versões anteriores da linguagem R.

3. Integração com RStudio:

Esta demonstração se integra ao RStudio, que é um ambiente de desenvolvimento integrado avançado projetado para codificação em R. Recomenda-se aos participantes que utilizem o RStudio para uma experiência de programação otimizada durante toda a demonstração.


Configuração do ambiente

Vamos começar configurando nosso ambiente.

Primeiro, certifique-se de que a versão 4.3.2 do R está instalada no seu computador. Se você não tem certeza ou não tem o R instalado, vamos passar por todas as etapas juntos.

Para verificar se o R está instalado, procure o ícone do R na área de trabalho. Se ele não estiver lá, você pode buscar por "R" — isso deve abrir o terminal do R, se ele já estiver instalado. Você pode instalar o R a partir do repositório oficial no The Comprehensive R Archive Network. Este link sempre levará você à última versão do R, que atualmente é a versão 4.3.2. Após baixar o arquivo de instalação, siga as instruções na tela, começando pela seleção do idioma. 

Agora que você tem o R instalado, vamos verificar a versão em uso. Abra o terminal do R e você verá a versão exibida no topo da mensagem de boas-vindas, toda vez que iniciar uma nova sessão. Se precisar de mais informações, você sempre pode usar o comando `version` no terminal.

Verificação da versão do R

Fig. 1. Verificação da versão do R

Agora vamos configurar o RStudio. Você pode baixar o RStudio aqui: RStudio Desktop - Posit. Basta seguir as instruções na tela conforme elas aparecem, similar ao processo de instalação do R que discutimos anteriormente.

Após a conclusão da instalação, vamos verificar a versão do R que o RStudio está usando.

Abra o RStudio.

Selecione Tools (ferramentas) e Global Options... (opções globais).

Opções globais

Fig. 2. Verificação da versão do R usada no RStudio

Você verá a versão do R em uso.

Se o seu computador tiver duas ou mais versões do R instaladas, clique em Change... (alterar).

Menu de configurações

Fig. 3. Verificação da versão do R usada no RStudio

Escolha "Choose a specific version of R" (escolher uma versão específica do R), selecione a versão 4.3.2, clique em OK e reinicie o RStudio para que as alterações tenham efeito. 

Escolha da versão do R

Fig. 4. Escolha da versão do R

Após reiniciar o RStudio, é necessário instalar algumas dependências. 

#Algorithmic Trading With RStudio And MetaTrader 5
#Gamuchirai Zororo Ndawana
#This script will help you get your environment setup and test that everything is working fine
#Sunday 17 December 2023

#Installing Dependencies
install.packages("stringi")             #This package is a dependency for devtools
install.packages("devtools")            #We will use this package to install R packages hosted on github
install.packages("xts")                 #We will use this package to plot data fetched from the MetaTrader 5 Terminal
install.packages("quantmod")            #We will use this package to plot data fetched from the MetaTrader 5 Terminal
install.packages("ttr")                 #We will use this package to calculate technical indicator values 
install.packages("reticulate")          #We will use this package to call Python libraries in R 
devtools::install_github("Kinzel/mt5R") #We will use this open source package to interact with the MetaTrader 5 Terminal

Começaremos importando a primeira biblioteca — `reticulate`. Esta biblioteca permite executar código Python no R. Utilizaremos `reticulate` para instalar a biblioteca MT5 Python em um ambiente virtual. Após instalar a biblioteca MT5, poderemos usar `reticulate` como uma ponte entre o RStudio e o ambiente virtual Python. Esta conexão intermediária nos permitirá enviar comandos ao nosso terminal MetaTrader 5, facilitando a execução de negociações.

Vamos começar baixando a biblioteca `reticulate`.

#Libraries
#Importing reticulate
library(reticulate)
Em seguida, criaremos um ambiente virtual usando a função `virtualenv_create()` da biblioteca `reticulate`. A função aceita um parâmetro de string, representando o nome do nosso ambiente virtual. Na programação, ambientes virtuais oferecem um método para criar espaços isolados e autônomos para projetos individuais. A justificativa fundamental para o uso de ambientes virtuais é o gerenciamento eficaz de dependências, mitigando conflitos e garantindo a reprodutibilidade do projeto. Isso se torna especialmente importante quando vários projetos ou pacotes têm dependências comuns, mas precisam de diferentes versões das mesmas dependências. 
#Create a virtual environment
virtualenv_create("rstudio-metatrader5")

Após a criação da virtualenv, o próximo passo é ativá-la e utilizá-la. Isso é feito utilizando a função `use_virtualenv()` da biblioteca `reticulate`. Ativar a virtualenv garante que as operações subsequentes em Python sejam executadas no contexto isolado desse ambiente, permitindo gerenciar dependências e configurações específicas do nosso projeto. 

#Use the virtual environemnt 
use_virtualenv("rstudio-metatrader5")

Vamos instalar a biblioteca Python para MetaTrader 5, utilizando a função `py_install()` da biblioteca `reticulate`. Nós fornecemos à função o nome da biblioteca que vamos instalar, neste caso "MetaTrader5".

#Install metatrader5 python library
py_install("MetaTrader5")

Depois de instalar a biblioteca, o próximo passo é importar a biblioteca MetaTrader 5 e salvá-la em uma variável chamada "MT5". Isso é feito com a função `import()` da biblioteca `reticulate`. A variável "MT5" servirá como nossa interface para interagir com a biblioteca MetaTrader 5 nos próximos passos.

#Import MetaTrader 5
MT5 <- import("MetaTrader5")

Antes de continuar, certifique-se de que o terminal MetaTrader 5 não está em execução no momento. Se ele estiver aberto, por favor, feche-o.

Agora vamos iniciar o terminal MetaTrader 5 diretamente do RStudio. Podemos conseguir isso chamando a função de inicialização da biblioteca MetaTrader 5 Python. Se a inicialização for bem-sucedida, a função retornará TRUE, indicando que o terminal MetaTrader 5 foi iniciado com sucesso.

#Initialize the MetaTrader 5 Terminal
MT5$initialize()

[1] TRUE

Embora possamos acessar informações da conta, dados do terminal e características dos símbolos, enfrentamos nossa primeira limitação: a incapacidade de fazer login programático em outra conta. A conta que está ativa durante a inicialização do terminal se torna a única conta acessível, a menos que seja alterada manualmente pelo usuário. Embora seja possível criar um script Python para fazer login em outra conta usando a biblioteca MetaTrader 5 e executá-lo a partir do R usando `reticulate`, este artigo assume que os leitores possuem apenas conhecimento de programação em R e uma compreensão básica de programação em MQL5.


Outra limitação é a incapacidade de solicitar informações históricas de preços usando `reticulate`. Esta limitação pode estar relacionada à conversão automática de tipos de dados pelo `reticulate` ao transferir objetos entre R e Python. Consequentemente, surgem dificuldades ao lidar com o objeto retornado ao solicitar dados históricos de preços do terminal. Aqui, utilizamos um segundo pacote para corrigir as limitações do `reticulate`.

#Get account information
account_info <- MT5$account_info()

#Print account information
account_info$company
account_info$balance
account_info$name

#Get terminal information
terminal_info <- MT5$terminal_info()

terminal_info$build
terminal_info$company
terminal_info$name

[1]"Deriv.com Limited"

[1]868.51

[1]"Gamuchirai Ndawana"

[1]4094

[1]"MetaQuotes Software Corp."

[1]"MetaTrader 5"

#Requesting price data
price_data <- MT5$copy_rates_from_pos("Boom 1000 Index",MT5$TIMEFRAME_M1,0,10)

Error in py_call_impl(callable, call_args$unnamed, call_args$named) :

SystemError: returned a result with an exception set

Run `reticulate::py_last_error()` for details.

Usamos o MT5R para resolver esses problemas. Mas primeiro, vamos entender como o MT5R funciona internamente.

O pacote MT5R estabelece uma conexão WebSocket entre o RStudio e o terminal MetaTrader 5, criando um canal de comunicação full-duplex. Em um sistema full-duplex, os dados podem ser enviados e recebidos simultaneamente. Para que esse canal seja eficaz, o terminal MetaTrader 5 deve ouvir em uma porta específica que utilizaremos para enviar instruções. Além disso, ele deve interagir com nossa sessão do RStudio através dessa mesma porta. Felizmente, o MT5R inclui um Expert Advisor, escrito em MetaQuotes Language 5, que escuta nossos comandos. O Expert Advisor tem código aberto, proporcionando flexibilidade para adicionar funcionalidades adicionais. O código-fonte pode ser baixado aqui. Note que anexamos à artigo uma versão configurada do Expert Advisor, que inclui uma função adicional para posicionamento automático de trailing stops e take profits.

MT5R

Fig. 5. Esquema do MT5R

Depois de baixar o Expert Advisor, você deve colocá-lo nas mesmas pastas que os outros EAs. Inicie seu terminal MetaTrader 5, abra o menu "Arquivo" e selecione "Abrir pasta de dados".

Abrir pasta de dados

Fig. 6. Localizando a pasta de dados

Em seguida, navegue até ".\MQL5\experts\" e coloque o Expert Advisor na pasta Experts. Depois, abra o símbolo que você deseja negociar e coloque o Expert Advisor MT5R no gráfico. O sistema pode perguntar se você deseja conceder permissão para que o MetaTrader 5 realize operações de rede no seu computador. Conceda essa permissão. Uma vez feito isso, estamos prontos para voltar ao RStudio e continuar a criação do nosso algoritmo de negociação. 

Abra o RStudio e importe as bibliotecas MT5R, xts e quantmod.

#Import the MT5R Library
library(mt5R)
#Import xts to help us plot
library(xts)
#Import quantmod to help us plot
library(quantmod)

Em seguida, verifique se nossa conexão com o terminal está estabelecida usando a função `Ping()` do pacote MT5R. A função retornará TRUE se conseguir se comunicar com o Expert Advisor.

#Check if our connection is established
MT5.Ping()
#Global variables
MARKET_SYMBOL <- "Volatility 75 Index"

[1] TRUE

O MT5R não resolve o problema de login que discutimos anteriormente, mas resolve a questão da solicitação de dados de preços.

Para solicitar dados de preços do nosso terminal MetaTrader 5, chamamos a função `GetSymbol` da nossa biblioteca MT5R. A função espera o nome do símbolo, seguido do timeframe em minutos (portanto, dados diários serão 1440) e, por fim, o número de linhas. Os dados mais antigos estão no topo, e o preço atual está na parte inferior. 

Observe que definimos o parâmetro `xts` como verdadeiro. Isso converte o bloco de dados em um objeto de série temporal do R e formata automaticamente as datas no gráfico. Isso também nos permite adicionar facilmente valores de indicadores técnicos ao nosso bloco de dados.

#Request historical price data
price_data <- MT5.GetSymbol(MARKET_SYMBOL, iTF = 1, iRows=5000,xts = TRUE)
Podemos facilmente plotar os dados de preços usando a função `lineChart()` do quantmod.

#Plotting a line chart
lineChart(price_data, name = MARKET_SYMBOL)


Gráfico de linhas

Fig. 7. Exibição de dados de preços no RStudio

Também podemos adicionar indicadores técnicos ao nosso gráfico usando a função `addIndicator` do quantmod, por exemplo, adicionando um Índice de Força Relativa (RSI) de 60 períodos ao nosso gráfico. 

#We can also add technical indicators to the plot
addRSI(n=60)

Adicionando indicadores técnicos

Fig. 8. Adicionando indicadores técnicos ao gráfico


Processamento de dados personalizados

Quando adicionamos RSI e o indicador Aroon, nós os adicionamos apenas ao gráfico. Para adicionar os valores dos indicadores técnicos ao nosso dataframe, devemos chamar o indicador do pacote quantmod e, em seguida, fornecer as colunas apropriadas necessárias para os cálculos. As colunas relevantes são indicadas na documentação; neste exemplo, adicionaremos ao dataframe uma média móvel simples de 20 períodos, um índice de força relativa (RSI) de 20 períodos e um indicador de amplitude média verdadeira (ATR) de 20 períodos.

#Add moving average
price_data$SMA_20 <- SMA(price_data$Close,n = 20)
#Add RSI to the dataframe
price_data$RSI_20 <- RSI(price_data$Close,n=20)
#Add ATR to the dataframe
price_data$ATR_20 <- ATR(price_data[,c("High","Low","Close")], n=20)

Depois de fazer isso, removeremos todas as linhas com valores ausentes.

#Drop missing values
price_data <- na.omit(price_data)

Adicionaremos uma função chamada "próximo fechamento" (next close), que conterá o preço do próximo fechamento. Se o valor do próximo fechamento for maior que o preço de fechamento atual, nosso alvo será igual a um, caso contrário, será zero. Isso é feito usando a função `ifelse` no R.

#Next close price
price_data$Next_Close <- lag(price_data$Close,-1)

#Setting up our target
price_data$Target <- ifelse( ( (price_data$Next_Close) > price_data$Close) , 1 , 0)

Agora estamos prontos para fazer a divisão treino-teste. Usaremos as primeiras 4000 linhas para treinamento e o restante para teste. Ao trabalhar com dados de séries temporais, evitamos a divisão aleatória para evitar vazamento de dados — situação em que o modelo inadvertidamente aprende com informações futuras para prever o passado. Em vez disso, priorizamos manter a ordem temporal natural dos dados. Na prática, escolhemos as primeiras 4000 linhas em sua sequência cronológica e seguimos com o restante das linhas. Essa abordagem garante que nosso modelo aprenda com dados passados para prever o futuro, mantendo as melhores práticas de análise de séries temporais.

#Train test split
train_set <- price_data[1:4000,]
train_y <- price_data[1:4000,c("Target")]

test_set <- price_data[4001:4980,]
test_y <- price_data[4001:4980,c("Target")]

Agora que dividimos nossos dados em conjuntos de treinamento e teste, o próximo passo é treinar o modelo escolhido. Neste caso, escolhemos a análise discriminante quadrática (QDA). O QDA é focado em maximizar a diferenciação entre duas classes, promovendo uma classificação mais eficaz dos dados. Isso é alcançado maximizando a separação das médias dos dois grupos e minimizando a variabilidade média dentro de cada grupo. Para implementar o QDA, usamos a biblioteca MASS, que contém o modelo QDA. Portanto, importamos a biblioteca MASS para acessar e usar o modelo QDA em nossa análise.

#Fitting models
library(MASS)
#Quadratic Discriminant Analysis
#Using OHLC Data
qda  <- qda(Target ~ Open+High+Low+Close,data = train_set)
qda

Call:

qda(Target ~ Open + High + Low + Close, data = train_set)

Prior probabilities of groups:

      0 1 

0.49925 0.50075 

Group means:

      Open High Low Close

0 365424.6 365677.8 365159.9 365420.5

1 365125.4 365384.0 364866.6 365131.4

A partir da matriz de confusão, vemos que nosso modelo prevê melhor os movimentos de alta do que os de baixa no mercado.

#Evaluating model performance
#Custom Quadratic Discriminant Analysis
qda_predictionts <- predict(qda,test_set)
qda_predictionts <- qda_predictionts$class

#Confusion matrix
table(qda_predictionts,test_y)

Matriz de confusão

Fig. 9. Matriz de confusão


Implementação da lógica de negociação

Chegamos ao ponto fundamental do nosso algoritmo de negociação, onde o imperativo inicial é criar uma variável denominada `last_trade`. Essa variável adquire importância ao desempenhar a função chave de monitorar a transação mais recente iniciada. Sua importância reside em auxiliar no fechamento oportuno das posições quando nosso modelo prevê um movimento desfavorável do mercado, que pode potencialmente minar nossa posição geral no mercado. Vale lembrar nosso sistema simples de codificação, onde o valor 1 significa compra (BUY) e o valor 0 significa venda (SELL).

#Keeping track of the last trade
last_trade <- -1

Ao implementar nosso algoritmo, é necessário iniciar um loop infinito, no qual nossa lógica de negociação está inserida. Esse loop infinito é alcançado incluindo uma função de timeout, regulando assim a frequência das iterações. Em conformidade com a geração de novos candles, buscamos ciclos de iteração síncronos. A integração da função `Sys.sleep` garante que nossas ações de negociação estejam em sintonia com as mudanças do mercado minuto a minuto.

Nosso primeiro passo é obter as informações de mercado atuais.

Em seguida, passamos esses dados para nosso modelo e obtemos a previsão.

Depois que nosso modelo fez a previsão, verificamos se temos posições abertas usando o pacote MT5 que instalamos via `reticulate`. Se não tivermos posições abertas, procedemos à abertura de uma posição na direção da previsão do mercado e, em seguida, atualizamos nossa variável `last_trade`.

Caso contrário, se tivermos uma posição aberta, verificamos se o nosso modelo prevê um movimento contra ela. Se sim, fechamos a posição.

Por fim, precisamos adicionar um timeout para que nosso algoritmo verifique nossa posição uma vez a cada candle.

while(TRUE){
  #Fetching current market data
  print("Fetching market information")
  data <- MT5.GetSymbol(MARKET_SYMBOL,iTF=1, iRows = 2)
  data <- data[1,]
  
  #Forecasting market move
  qda_forecast <- predict(qda,data)
  qda_forecast <- qda_forecast$class
  print("Model forecast: ")
  print(qda_forecast)
  #Checking if we have no open positions
  current_positions <- MT5$positions_total()
  
  #If we have no open positions, open a position following the model forecast
  if(current_positions == 0){
    print("We have no open positions. Opening a new position")
    
    #A Forecast of 1 means buy
    if(qda_forecast == 1){
      print("Opening Buy Position")
      MT5$Buy(MARKET_SYMBOL,symbol_info$volume_min)
      last_trade <- 1
    }
    #A Forecast of 0 means sell
    if (qda_forecast == 0){
      print("Opening Sell Position")
      MT5$Sell(MARKET_SYMBOL,symbol_info$volume_min)
      last_trade <- 0
    }
  }
  
  else{
      #Are we anticipating a move against our open position?
      if(last_trade != qda_forecast){
        #If we are, let's close our position
        print("Closing open position")
        MT5$Close(MARKET_SYMBOL)
        #Reset last trade
        last_trade <- -1
      }
    
    else{
      #Otherwise everything is expected to be fine
      print("The current position is aligned with the market")
      info <- MT5$account_info()
      print("Current Profit")
      print(info$profit)
    }
    
  }
  #Wait for a new candle to form 
  Sys.sleep(60)
}


Juntando tudo

Fig. 10. Modelo de Análise Discriminante Quadrática no R negociando em tempo real no MetaTrader 5


Considerações finais

Apesar das dificuldades ao desenvolver um algoritmo de negociação em tempo real usando R e MetaTrader 5, o artigo demonstra que a tarefa é mais alcançável do que pode parecer à primeira vista. Até mesmo iniciantes na linguagem R podem fazer progressos significativos. As limitações dos pacotes individuais são eficazmente mitigadas por pacotes adicionais, e, em particular, a abordagem adotada minimiza as dependências. No geral, apresenta uma estrutura viável e confiável, acessível a qualquer usuário de R.

Além disso, a versão configurada do Expert Advisor MT5R anexada ao artigo é destinada à inclusão autônoma de stop-losses e take-profits, ajudando no gerenciamento da negociação. Os usuários são encorajados a expandir a funcionalidade do Expert Advisor conforme necessário. Desejo a vocês paz, prosperidade e negociações lucrativas!

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

Arquivos anexados |
mt5R_v0_1_5.mq5 (151.33 KB)
Funcionalidades do assistente MQL5 que você precisa conhecer (Parte 10): RBM não convencional Funcionalidades do assistente MQL5 que você precisa conhecer (Parte 10): RBM não convencional
As máquinas de Boltzmann restritas (Restrictive Boltzmann Machines, RBM) são, em um nível básico, uma rede neural de duas camadas capaz de realizar classificação não supervisionada através da redução de dimensionalidade. Vamos usar seus princípios básicos e ver o que acontece se a desenharmos e a treinarmos de forma não convencional. Será que conseguiremos obter um filtro de sinais útil?
Ciência de dados e aprendizado de máquina (Parte 18): Comparando a eficácia do TruncatedSVD e NMF no tratamento de dados complexos de mercado Ciência de dados e aprendizado de máquina (Parte 18): Comparando a eficácia do TruncatedSVD e NMF no tratamento de dados complexos de mercado
A decomposição em valores singulares truncada (TruncatedSVD) e a fatoração de matriz não negativa (NMF) são métodos de redução de dimensionalidade. Ambos podem ser bastante úteis ao trabalhar com estratégias de negociação baseadas na análise de dados. Neste artigo, analisamos a aplicabilidade desses métodos no processamento de dados complexos de mercado, incluindo suas capacidades de redução de dimensionalidade para otimizar a análise quantitativa nos mercados financeiros.
Anotação de dados na análise de série temporal (Parte 6): Aplicação e teste de EA com ONNX Anotação de dados na análise de série temporal (Parte 6): Aplicação e teste de EA com ONNX
Nesta série de artigos, apresentamos vários métodos de anotação de séries temporais, que podem criar dados adequados à maioria dos modelos de inteligência artificial (IA). A anotação de dados direcionada pode tornar o modelo de IA treinado mais alinhado aos objetivos e tarefas do usuário, aumentar a precisão do modelo e até ajudar o modelo a alcançar um salto qualitativo!
Desenvolvimento de um Cliente MQTT para o MetaTrader 5: Metodologia TDD (Parte 5) Desenvolvimento de um Cliente MQTT para o MetaTrader 5: Metodologia TDD (Parte 5)
Este artigo é a quinta parte de uma série que descreve as etapas de desenvolvimento de um cliente MQL5 nativo para o protocolo MQTT 5.0. Nesta parte, vamos detalhar a estrutura dos pacotes PUBLISH, configuraremos seus flags de publicação, codificaremos os nomes dos tópicos e estabeleceremos identificadores de pacotes quando necessário.