English Русский 中文 Español Deutsch 日本語
preview
Como conectar o MetaTrader 5 ao PostgreSQL

Como conectar o MetaTrader 5 ao PostgreSQL

MetaTrader 5Integração | 25 julho 2023, 08:57
312 0
Jocimar Lopes
Jocimar Lopes

Introdução

A paisagem do desenvolvimento de software mudou muito nos últimos dez anos. Vimos a popularização da computação em nuvem e acrônimos como IASS, PASS e SAAS são agora ferramentas-chave que devem ser consideradas em qualquer projeto de software. As coisas ficaram mais fáceis tanto para o usuário final quanto para o desenvolvedor de software.

A equipe da MetaQuotes estava ciente dessas mudanças e, desde 2014, temos uma WebRequest nativa para o MetaTrader 5.

Uma das áreas que mais mudou foi a gestão de bancos de dados (BD). Soluções que costumavam ser complexas ou até mesmo "estranhas" de um ponto de vista prático se tornaram não só viáveis, mas a solução preferida para muitos casos de uso. Este foi o caso do acesso a bancos de dados via REST API.

Uma proposta de acesso a bancos de dados via REST API pareceria superdimensionada alguns anos atrás. Hoje, uma rápida busca por "banco de dados gerenciado com acesso via rest API" retornará dezenas de provedores, variando desde alguns dólares/mês em planos básicos até soluções empresariais personalizadas. Muitos desses provedores oferecem generosos níveis gratuitos para prototipagem, testes ou até mesmo implantação de pequenas cargas de trabalho de produção.

Este artigo analisa cinco alternativas padrão para conectar um banco de dados Postgres ao MetaTrader 5, seus requisitos, prós e contras. Além disso, configuraremos um ambiente de desenvolvimento, instalaremos um banco de dados Postgres como remoto, nos conectaremos a ele e inseriremos e recuperaremos dados a serem consumidos por um script ou EA MQL5.

Esta configuração de ambiente de desenvolvimento e respectivos procedimentos podem ser facilmente replicados com qualquer RDBMS, uma vez que a API REST serve como uma camada de abstração entre o sistema de BD e o código do cliente.


MetaTrader 5 e bancos de dados

O MetaTrader 5 já tem as funções de que você pode precisar para trabalhar com um banco de dados e as funções de que você pode precisar para se conectar a um banco de dados via rede.

Desde 2020, a plataforma oferece integração nativa com o SQLite. Você pode usar as funções de banco de dados mencionadas acima para interagir com ele a partir do código. Além disso, você pode interagir com seus bancos de dados através de uma GUI dedicada no MetaEditor, facilitando a criação de tabelas, alteração de tabelas e realização de operações CRUD sem a necessidade de software adicional.

Isso foi uma grande melhoria na experiência do usuário final e uma adição chave ao arsenal do desenvolvedor MQL5.

Entre dezenas de RDBMS disponíveis, muitos deles com licenças de código aberto, SQLite parece ter sido uma escolha inteligente pelos desenvolvedores do MetaTrader 5. Apesar de ser um banco de dados SQL completo, com índices multicolunas, triggers, views, transações acid, busca de texto completo, funções agregadas e mais, é leve, baseado em arquivos, escalável e requer zero manutenção. De acordo com seu site, "parece provável que existam mais de um trilhão (1e12) de bancos de dados SQLite em uso ativo".

Apesar de suas impressionantes características, SQLite é limitado por design a um único usuário e não é destinado a acesso concorrente em implantações web. O grande número de postagens no fórum e artigos no site MQL5 sobre como conectar o MetaTrader 5 ao MySQL revela que há uma demanda por uma solução mais robusta para outros casos de uso.

Este artigo está focado em configurar um ambiente de desenvolvimento para esses casos de uso usando Postgres.

Por que Postgres

Primeiro de tudo, escolhi o Postgres porque a outra alternativa popular de código aberto, o MySQL, já foi extensivamente abordada aqui.

Em segundo lugar, o Postgres é um projeto de código aberto maduro, multiplataforma, é muito bem mantido, com documentação consistente. É popular e você pode encontrar uma infinidade de códigos de exemplo, guias e tutoriais pela web. Da mesma forma, existem muitos provedores de nuvem disponíveis para todas as necessidades e orçamentos.

O Postgres é de nível empresarial e, ao mesmo tempo, pode ser facilmente gerenciado por um único usuário trabalhando sozinho em uma máquina doméstica.

E claro, escolhi o Postgres porque confio nele. Por mais de uma década, sou um usuário satisfeito do Postgres em diferentes projetos.

E, por último, mas não menos importante, atualmente estou implementando a solução que estou compartilhando aqui para o meu ambiente de negociação pessoal. Então, é uma espécie de "dar a cara a tapa".


Quatro maneiras de interagir com Postgres a partir do MQL5

Até onde eu posso ver, existem quatro abordagens principais para chamar o Postgres a partir do MQL5:

  1. Uma biblioteca/driver MQL5 dedicada
  2. Um .dll a partir da interface do cliente C++
  3. Via driver .NET Npgsql
  4. Uma API REST

Vamos dar uma olhada nos requisitos, prós e contras de cada um. Tenho certeza de que a grande comunidade de desenvolvedores experientes da comunidade MQL5 estará oferecendo soluções fáceis para os contras, bem como apontando as desvantagens que não consegui ver nos prós. Este feedback da comunidade MQL5 é esperado, pois tanto o desenvolvedor menos experiente quanto o trader não desenvolvedor que chega aqui se beneficiarão desta discussão relacionada.


1. Uma biblioteca/driver MQL5 dedicada

Esta biblioteca ainda não existe. Precisa ser desenvolvida e exigiria muitas horas de trabalho duro de um desenvolvedor MQL5 sênior. Isso não seria barato. Precisamos levar em conta os custos de manutenção também. O Postgres é maduro, mas não é de forma alguma estático. É um projeto ativo com lançamentos regulares e alguns desses lançamentos, senão muitos, exigirão atualizações no código do cliente.

Por exemplo: agora, no momento da escrita, a última versão do Postgres (15) exige que usuários regulares de um banco de dados devam ser concedidos alguns privilégios no esquema público (public schema). Este requisito não existia em versões anteriores. Provavelmente, a manutenção é necessária em várias bases de código por aí.

A vantagem de encomendar o desenvolvimento de um driver MQL5 dedicado para o Postgres é que, se compartilhado, poderia ser útil para muitos usuários do MQL5. A desvantagem é bastante óbvia: o custo em tempo/dinheiro.

Por onde começar se você escolher este caminho:

Uma busca genérica por artigos MySQL neste site retornará algumas referências úteis.

Biblioteca de cliente C++ de código abert libpqxx

Biblioteca oficial do cliente em C para Postgres libpq


2. Um .dll a partir da interface do cliente C++

Esta é uma biblioteca oficial externamente mantida em C++, a libpqxx, que é construída sobre a biblioteca oficial em C internamente mantida, a libpq, que é fornecida com a distribuição Postgres.

Pessoalmente, nunca a usei, e tudo o que posso dizer é que ela está lá há muito tempo e parece ser bem mantida. A desvantagem deste método é que o Mercado MQL5 não permite DLL's. Se isso não for um problema para o seu projeto e você estiver à vontade trabalhando com .dll's do MetaTrader, essa pode ser a sua solução.

Por onde começar se você escolher este caminho:

A biblioteca de cliente C++ de código aberto libpqxx


3. Via driver .NET Npgsql

Desde 2018, o MetaTrader 5 adicionou suporte nativo para bibliotecas .NET com importação de funções 'inteligentes'. Com o lançamento da plataforma build 1930, as bibliotecas .NET podem ser usadas sem escrever wrappers especiais - o MetaEditor faz isso por conta própria". 

Tudo o que você precisa para usar o driver .NET Npgsql é importar o .dll em si. Existem algumas limitações que você pode verificar nas notas de lançamento oficiais (https://www.mql5.com/ru/forum/285631).

Por onde começar se você escolher este caminho:

O driver Postgres de código aberto para .NET


4. Uma API REST

Se você escolher o caminho "sem .dll", este deve ser o método mais rápido e barato. A API pode ser escrita em qualquer linguagem e você pode ter um protótipo funcionando em um dia ou até mesmo algumas horas.

Além disso, alguns provedores de nuvem oferecem API REST integrada para o Postgres de graça. Tudo o que você precisa para começar é um bom ambiente de desenvolvimento para o seu código MQL5.

Usando este método, o seu código MQL5 pode consumir as respostas do seu Postgres como JSON.

Por onde começar se você escolher este caminho:

Aqui, com este artigo! Basta continuar lendo, seguir os passos abaixo, baixar o código de exemplo e começar a armazenar e consultar seus negócios e negociações em um banco de dados Postgres.


Configurando o ambiente de desenvolvimento

Escolha o método que escolher, você precisará de um ambiente de desenvolvimento em uma máquina Windows com um servidor Postgres em execução. Como diz o ditado, há mais de uma maneira de fazer isso. Lembro-me desses três caminhos, do mais complexo e demorado ao mais simples:

  1. Compilação a partir do código fonte
  2. Contêiner docker
  3. Instalador msi de terceiros

Todos eles são boas maneiras de ter o Postgres no Windows, mas acredite em mim, a compilação a partir do código fonte no Windows deve ser sua última opção, exceto se você estiver disposto a aprender a teoria e a prática da resiliência intermitente no desenvolvimento de software.

O contêiner docker é uma opção muito boa, uma instalação robusta e flexível em que seu servidor de banco de dados estará funcionando em uma "máquina remota", não "localhost" (veja abaixo). Afinal, é fácil. Você só precisa do Docker instalado, e duas a três linhas de comando e você está pronto para ir.

Deixando de lado o inconveniente relativo de software de "terceiros", o instalador msi de terceiros é uma boa alternativa para evitar a aventura de compilar a partir do código-fonte ou a instalação do Docker e gestão de contêineres.

No entanto, eu não recomendaria um ambiente de desenvolvimento para um servidor de banco de dados, ou qualquer tipo de servidor para este assunto, como um "localhost", se for possível desenvolver contra um servidor localizado em uma máquina remota. Isso porque é sempre uma boa prática desenvolver, testar e depurar um servidor em um ambiente remoto, e não em "localhost", a fim de solucionar problemas de configurações de conexão e problemas de autenticação o mais rápido possível.

O que é o WSL

WSL é a sigla para Windows Subsystem For Linux.

Caso você não tenha percebido, desde 2016 você pode executar uma distribuição Linux em uma máquina Windows como um subsistema. Não se preocupe! Não há hacks aqui. O WSL é desenvolvido pela Microsoft e está integrado ao Windows. Você só precisa ativá-lo, como veremos a seguir.

Por que WSL

Por que não simplesmente instalar o Postgres em outra máquina Windows, eventualmente uma máquina virtual?

Porque o Postgres é um sistema nativo Unix, criado e desenvolvido em sistemas \*nix. Ao instalá-lo no Linux, você terá fácil instalação, atualizações fáceis e fácil manutenção. Toda a documentação oficial é direcionada a um sistema Unix. E a maioria do código de exemplo, trechos e ajuda geral que você pode encontrar na web reflete esse fato.

Assim, você terá facilidade para desenvolver em um sistema Linux. E o WSL foi desenvolvido pela Microsoft exatamente para este propósito.

Instale o WSL

Pré-requisitos da documentação da Microsoft:

"Você deve estar executando a versão 2004 do Windows 10 ou superior (Build 19041 e superior) ou Windows 11 para usar os comandos abaixo. Se você estiver em versões anteriores, por favor, veja a página de instalação manual".

Se o seu sistema atender a este pré-requisito, basta abrir um Power Shell como administrador e digitar o comando abaixo para instalar/ativar o WSL:

wsl -install

Comando de instalação do wsl no PowerShell

Este comando instalará o Ubuntu no WSL, pois é a distro padrão. 

Reinicie o Windows.

Este deve ser um processo simples. Se não for, você encontrará uma seção com os problemas de instalação mais comuns na documentação oficial da MS, linkada acima.

Depois de reiniciar, você deverá ver algo assim. Vá em frente, crie um novo nome de usuário e senha UNIX.

Instalação do wsl após a primeira reinicialização


Agora que você tem o WSL/Ubuntu instalado e funcionando, vamos instalar o Postgres nele.

No WSL, instale o Postgres

Digite o comando abaixo.

sudo apt install postgresql postgresql-contrib

Este comando instalará a última versão estável do pacote PostgreSQL disponível nos repositórios do Ubuntu. Ele inclui o servidor, o cliente pgsql, binários convenientes e algumas utilidades. Tudo o que você precisa para começar.

Se você quiser instalar a última versão estável do Postgres - geralmente diferente da última versão estável nos repositórios do Ubuntu - você pode incluir o repositório oficial do Postgres na lista de fontes do seu gerenciador de pacotes. Você pode encontrar instruções detalhadas na documentação oficial do Postgres.

Se tudo estiver ok, ao digitar o comando

psql --version

deverá retornar a versão instalada do seu banco de dados Postgres.


Inicie o servidor

Digite este comando para iniciar o servidor.

sudo service postgresql start

Por padrão, uma nova instalação do Postgres só aceita conexões do "localhost". Vamos mudar isso.

Encontre o arquivo de configuração do Postgres.

sudo -u postgres psql -c "SHOW config_file"

Arquivo de configuração do Postgres


Edite o arquivo de configuração para aceitar conexões fora do localhost. Mude a linha listen_addresses.

Linha listen_addresses no Postgres


Encontre o arquivo de configuração pg_hba.

sudo -u postgres psql -c "SHOW hba_file"

Arquivo de configuração pg_hba no Postgres


Edite o arquivo pg_hba.conf para permitir autenticação por senha tanto em IPv4 quanto em IPv6.

Autorização de senha


Agora acesse a utilidade psql como o usuário Postgres padrão criado pela instalação. Ele é chamado de 'postgres'.

sudo -u postgres psql


Crie um usuário regular de banco de dados com privilégio CREATEDB. Até agora só existe o usuário 'postgres' criado pela instalação.

Conceda todos os privilégios no esquema público para mt5_user. Isso não é necessário se a sua versão do Postgres for inferior a 15.

CREATE USER mt5_user PASSWORD '123' CREATEDB;

GRANT ALL ON SCHEMA public TO mt5_user;

Concessão de todos os privilégios a um usuário no Postgres


Crie um banco de dados my_remote_db e conceda todos os privilégios a mt5_user.

GRANT ALL PRIVILEGES ON DATABASE my_remote_db TO mt5_user;

Criação de um banco de dados e concessão de todos os privilégios


Conecte ao Postgres

A esta altura, você deve ter um servidor de banco de dados rodando em uma máquina remota, com um IP diferente do seu localhost do Windows e pronto para aceitar conexões via rede. Podemos conectar via socket ou HTTP. Como vamos interagir com uma API REST, neste exemplo usaremos o último.

Vamos ver se conseguimos nos conectar ao my_remote_db como mt5_user com a senha 123 no host WSL.

Digite este comando para obter o nome do host (IP) do seu WSL.

hostname -I

Nome do host do comando do terminal do ubuntu


Verifique o status do servidor Postgres. Inicie-o se estiver desligado. Você pode usar este comando para iniciar, reiniciar ou parar o servidor.

sudo service postgresql {status, start, stop}


No terminal MetaTrader 5, vá para Ferramentas > Opções > guia Expert Advisors e inclua o IP do host WSL na lista dos permitidos.

Menu de configurações do terminal MetaTrader 5

O terminal MetaTrader 5 aceita conexões HTTP e HTTPS apenas nas portas 80 e 443, respectivamente. Apenas as portas 80 e 443. Você deve levar em conta este recurso de segurança se estiver desenvolvendo sua API. Normalmente, antes de passar para um servidor real em produção, o servidor de desenvolvimento estará ouvindo em uma porta não privilegiada, como 3000 ou 5000. Assim, para poder enviar solicitações para o IP que você declarou nas configurações do seu terminal acima, você precisa redirecionar o tráfego que chega na porta do servidor de desenvolvimento para a porta 80 para solicitações HTTP e/ou 443 para solicitações HTTPS.

Para manter as coisas simples, você encontrará instruções no README do aplicativo Python anexo sobre como realizar este redirecionamento no WSL.


Iniciando o aplicativo de demonstração

Como este artigo é sobre MQL5, não discutirei os detalhes da implementação da API. Em vez disso, fiz um aplicativo de demonstração que você pode baixar e instalar como um pacote Python para testar as interações do seu código MQL5 com a API.

Para iniciar o aplicativo de demonstração, você só precisa do Python instalado no WSL. Ele já deve estar lá.

É altamente recomendável que você crie um ambiente virtual Python ('venv') para instalar o aplicativo. Isso garantirá que a instalação do Python no seu sistema não seja afetada. Após brincar com o aplicativo, você pode simplesmente excluir o ambiente virtual.

Você pode criar o ambiente virtual com este comando.

python3 -m venv 'venv'


Portanto, depois de ter instalado o aplicativo de demonstração, para começar a desenvolver seu código MQL5, você irá:

  1. iniciar o WSL
  2. iniciar o servidor Postgres
  3. iniciar o aplicativo de demonstração
  4. obter o IP do nome do host a partir da saída do aplicativo de demonstração
  5. adicionar IP do host aos endereços permitidos no terminal

Tanto o WSL quanto o servidor Postgres podem ser configurados para iniciar na inicialização do Windows.


Inserindo dados de MQL5

Vamos tentar inserir alguns dados. Primeiro, as informações da nossa conta. No seu terminal MT5, crie um novo script e adicione o seguinte código.

//+------------------------------------------------------------------+
//|                                                post_acc_info.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <JAson.mqh> //--- include the JSON library
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- gathering the data - Account Info
   CJAVal data;
   CJAVal acc_info;
//--- doubles
   data["balance"] =          AccountInfoDouble(ACCOUNT_BALANCE);
   data["credit"] =           AccountInfoDouble(ACCOUNT_CREDIT);
   data["profit"] =           AccountInfoDouble(ACCOUNT_PROFIT);
   data["equity"] =           AccountInfoDouble(ACCOUNT_EQUITY);
   data["margin"] =           AccountInfoDouble(ACCOUNT_MARGIN);
   data["margin_free"] =      AccountInfoDouble(ACCOUNT_MARGIN_FREE);
   data["margin_level"] =     AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
   data["margin_so_call"] =   AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL);
   data["margin_so_so"] =     AccountInfoDouble(ACCOUNT_MARGIN_SO_SO);
//--- integers
   data["login"] =            AccountInfoInteger(ACCOUNT_LOGIN);
   data["leverage"] =         AccountInfoInteger(ACCOUNT_LEVERAGE);
   data["trade_allowed"] =    AccountInfoInteger(ACCOUNT_TRADE_ALLOWED);
   data["ea_allowed"] =       AccountInfoInteger(ACCOUNT_TRADE_EXPERT);
   data["trade_mode"] =       AccountInfoInteger(ACCOUNT_TRADE_MODE);
   data["margin_so_mode"] =   AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE);
//-- strings
   data["company"] =          AccountInfoString(ACCOUNT_COMPANY);
   data["currency"] =         AccountInfoString(ACCOUNT_CURRENCY);
   data["name"] =             AccountInfoString(ACCOUNT_NAME);
   data["server"] =           AccountInfoString(ACCOUNT_SERVER);
   
//--- fill in the acc_info array with Account Info data
   acc_info["acc_info"].Add(data);
   
//--- WebRequest arguments
   string method = "POST";
   string url = "http://172.22.18.235/accs";
   string headers = "Content-Type: application/json";
   int timeout = 500;
   char post[], result[];
   string result_headers;
   
//--- prepare JSON data to send
   string json = acc_info.Serialize();
   ArrayResize(post, json.Length(), 0);
   StringToCharArray(json, post, 0, StringLen(json), CP_UTF8);
   ResetLastError();
   
//--- send the request
   int res = WebRequest(method, url, headers, timeout, post, result, result_headers);
   if(res == -1)
     {
      Print("Error in WebRequest  =", GetLastError());
      MessageBox("Add " + url + " to allowed URLs on MT5 terminal", "Unknown URL", MB_ICONINFORMATION);     }
   else
     {
      Print("Starting post...");
      
      if(res == 201)// HTTP result code 201 (created)
        {
         Print("posted accs");
        }
     }
  }

Como você pode ver a partir do início do arquivo, estamos usando uma biblioteca auxiliar para serializar/desserializar nossos dados JSON. Ela foi desenvolvida por um membro da comunidade MQL5 e você pode encontrar a biblioteca no seu repositório no GitHub.

Agora, vamos inserir nossos negócios a partir do histórico do MetaTrader 5. Crie um novo script e adicione o seguinte código.

//+------------------------------------------------------------------+
//|                                                   post_deals.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <JAson.mqh> //--- include the JSON library
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- gathering the data - Deals
   CJAVal data;
   CJAVal deals;
//--- request trade history
   HistorySelect(0, TimeCurrent());
   int deals_total = HistoryDealsTotal();
//--- iterate over all deals to get data
//--- of each deal from its ticket number
   for(int i = 0; i < deals_total; i++)
     {
      //-- integers
      ulong deal_ticket =   HistoryDealGetTicket(i);
      data["ticket"] =     (int) deal_ticket;
      data["order"] =      (int) HistoryDealGetInteger(deal_ticket, DEAL_ORDER);
      data["position"] =   (int) HistoryDealGetInteger(deal_ticket, DEAL_POSITION_ID);
      data["time"] =       (int) HistoryDealGetInteger(deal_ticket, DEAL_TIME);
      data["type"] =       (int) HistoryDealGetInteger(deal_ticket, DEAL_TYPE);
      data["entry"] =      (int) HistoryDealGetInteger(deal_ticket, DEAL_ENTRY);
      data["magic"] =      (int) HistoryDealGetInteger(deal_ticket, DEAL_MAGIC);
      data["reason"] =     (int) HistoryDealGetInteger(deal_ticket, DEAL_REASON);
      //--- strings
      data["symbol"] =     (string) HistoryDealGetString(deal_ticket, DEAL_SYMBOL);
      //--- doubles
      data["volume"] =     (double) HistoryDealGetDouble(deal_ticket, DEAL_VOLUME);
      data["price"] =      (double) HistoryDealGetDouble(deal_ticket, DEAL_PRICE);
      data["profit"] =     (double) HistoryDealGetDouble(deal_ticket, DEAL_PROFIT);
      data["swap"] =       (double) HistoryDealGetDouble(deal_ticket, DEAL_SWAP);
      data["comission"] =  (double) HistoryDealGetDouble(deal_ticket, DEAL_COMMISSION);
 //--- fill in the deals array with each deal data
      deals["deals"].Add(data);
     }
 //--- WebRequest arguments
   string method = "POST";
   string url = "http://172.22.18.235/deals";
   string headers = "Content-Type: application/json";
   int timeout = 500;
   char post[], result[];
   string result_headers;
   
 //--- prepare JSON data to send
   string json = deals.Serialize();
   ArrayResize(post, json.Length(), 0);
   StringToCharArray(json, post, 0, StringLen(json), CP_UTF8);
   ResetLastError();
//--- send the request
   int res = WebRequest(method, url, headers, timeout, post, result, result_headers);
   
   if(res == -1)
     {
      Print("Error in WebRequest  =", GetLastError());
      MessageBox("Add " + url + " to allowed URLs on MT5 terminal", "Unknown URL", MB_ICONINFORMATION);     }
   else
     {
      Print("Starting post...");
      
      if(res == 201)// HTTP result code 201 (created)
        {
         Print("posted deals");
        }
     }
  }


Consultando dados a partir do MQL5

Agora vamos consultar os dados que acabamos de inserir. No seu terminal MetaTrader 5, crie um novo script e adicione o seguinte código.

//+------------------------------------------------------------------+
//|                                                 get_endpoint.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <JAson.mqh> //--- include the JSON library
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- choose the testing endpoint
   string endpoint = "accs"; // or "deals"
//--- WebRequest arguments
   string method = "GET";
   string url = "http://172.22.18.235/" + endpoint;
   string cookie = NULL, headers;
   int timeout = 500;
   char post[], result[];
   ResetLastError();
//--- send the request
   int res = WebRequest(method, url, cookie, NULL, timeout, post, 0, result, headers);
   if(res == -1)
     {
      Print("Error in WebRequest  =", GetLastError());
      MessageBox("Add " + url + " to allowed URLs on MT5 terminal", "Unknown URL", MB_ICONINFORMATION);
     }
   else
     {
      Print("Starting get...");
      if(res == 200)// HTTP result code 200 (OK)
        {
         PrintFormat("Server headers: %s", headers);
         ResetLastError();
         // save the returned JSON in a file
         string terminal_data_path = TerminalInfoString(TERMINAL_DATA_PATH);
         string subfolder = "TutoPostgres";
         string filename = endpoint + "_fromserver.json";
         int filehandle = FileOpen(subfolder + "\\" + filename, FILE_WRITE | FILE_BIN);
         if(filehandle != INVALID_HANDLE)
           {
            FileWriteArray(filehandle, result, 0, ArraySize(result));
            FileClose(filehandle);
            Print(filename + " created at " + terminal_data_path + "\\" + subfolder);
           }
         else
            Print("File open failed with error ", GetLastError());
        }
      else
         PrintFormat("Request to '%s' failed with error code %d", url, res);
     }
  }

Ao mudar o endpoint de "accs" para "deals", você pode consultar suas negociações recém-inseridas. Verifique o seu <caminho do terminal MT5>\Files\TutoPostgres. Se tudo correu bem, deve haver pelo menos dois arquivos lá: accs_fromserver.json e deals_fromserver.json. 


Consumindo dados JSON em Expert Advisors

Para consumir os dados JSON retornados pelo servidor, você precisa desserializá-los. A biblioteca auxiliar mencionada acima pode fazer isso.

Se você olhou para os arquivos JSON salvos após consultar o banco de dados com o código de exemplo acima, você pode ter visto uma string JSON como esta:

[
  {
    "a_balance": "10005.93",
    "a_company": "MetaQuotes Software Corp.",
    "a_credit": "0.0",
    "a_currency": "USD",
    "a_ea_allowed": true,
    "a_equity": "10005.93",
    "a_id": 3,
    "a_leverage": 100,
    "a_login": 66744794,
    "a_margin": "0.0",
    "a_margin_free": "10005.93",
    "a_margin_level": "0.0",
    "a_margin_so_call": "50.0",
    "a_margin_so_mode": "0",
    "a_margin_so_so": "30.0",
    "a_name": "MetaTrader 5 Desktop Demo",
    "a_profit": "0.0",
    "a_server": "MetaQuotes-Demo",
    "a_trade_allowed": true,
    "a_trade_mode": "0"
  },
  {
(...)

Estaremos usando estas chaves para acessar os dados desserializados. O '0' retornará todas as contas e você pode acessar cada uma delas iterando sobre a matriz por este índice.

//+------------------------------------------------------------------+
//|                                                 consume_json.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <JAson.mqh> //--- include the JSON library
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- choose the testing endpoint
   string endpoint = "accs"; // or "deals"
//--- WebRequest arguments
   string method = "GET";
   string url = "http://172.22.18.235/" + endpoint;
   string cookie = NULL, headers;
   int timeout = 500;
   char post[], result[];
   ResetLastError();
//--- send the request
   int res = WebRequest(method, url, cookie, NULL, timeout, post, 0, result, headers);
   if(res == -1)
     {
      Print("Error in WebRequest  =", GetLastError());
      MessageBox("Add " + url + " to allowed URLs on MT5 terminal", "Unknown URL", MB_ICONINFORMATION);
     }
   else
     {
      Print("Starting get...");
      if(res == 200)// HTTP result code 200 (OK)
        {
         CJAVal data;
         data.Deserialize(result);
         //--- doubles
         double a_balance =         data[0]["a_balance"].ToDbl();
         double a_credit =          data[0]["a_credit"].ToDbl();
         double a_profit =          data[0]["a_profit"].ToDbl();
         double a_equity =          data[0]["a_equity"].ToDbl();
         double a_margin =          data[0]["a_margin"].ToDbl();
         double a_margin_free =     data[0]["a_margin_free"].ToDbl();
         double a_margin_level =    data[0]["a_margin_level"].ToDbl();
         double a_margin_so_call =  data[0]["a_margin_so_call"].ToDbl();
         double a_margin_so_so =    data[0]["a_margin_so_so"].ToDbl();
         //--- longs
         long a_login =             data[0]["a_login"].ToInt();
         long a_leverage =          data[0]["a_leverage"].ToInt();
         long a_trade_mode =        data[0]["a_trade_mode"].ToInt();
         long a_margin_so_mode =    data[0]["a_margin_so_mode"].ToInt();
         long a_id =                data[0]["a_id"].ToInt(); //--- database generated ID
         //--- strings
         string a_company =         data[0]["a_company"].ToStr();
         string a_currency =        data[0]["a_currency"].ToStr();
         string a_name =            data[0]["a_name"].ToStr();
         string a_server =          data[0]["a_server"].ToStr();
         //--- booleans
         bool a_ea_allowed =        data[0]["a_ea_allowed"].ToBool();
         bool a_trade_allowed =     data[0]["a_trade_allowed"].ToBool();
         //printf("Server headers: %s", headers);
         //--- doubles
         printf("Balance: %d", a_balance);
         printf("Credit: %d", a_credit);
         printf("Profit: %d", a_profit);
         printf("Equity: %d", a_equity);
         printf("Margin: %d", a_margin);
         printf("Margin Free: %d", a_margin_free);
         printf("Margin Level: %d", a_margin_level);
         printf("Margin Call Level: %d", a_margin_so_call);
         printf("Margin Stop Out Level: %d", a_margin_so_so);
         //--- longs
         printf("Login: %d", a_login);
         printf("Leverage: %d", a_leverage);
         printf("Trade Mode: %d", a_trade_mode);
         printf("Margin Stop Out Mode: %d", a_margin_so_mode);
         printf("Database ID: %d", a_id);
         //--- strings
         printf("Company: %s", a_company);
         printf("Currency: %s", a_currency);
         printf("Platform Name: %s", a_name);
         printf("Server: %s", a_server);
         //--- booleans
         printf("Expert Advisor Allowed: %d", a_ea_allowed);
         printf("Trade Allowed: %d", a_trade_allowed);
         Print("Done!");
        }
      else
         PrintFormat("Request to '%s' failed with error code %d", url, res);
     }
  }


SQLite como um espelho do Postgres

Também é possível aproveitar a infraestrutura existente do MQL5 usando os dados remotos como um banco de dados SQLite local. Para implementar essa funcionalidade, precisamos sincronizar os bancos de dados. Esta sincronização seria quase em tempo real, com apenas alguns segundos de atraso. Mas melhoraria o desempenho, evitaria a latência da rede, e permitiria o acesso aos dados via GUI padrão do MetaEditor e o uso das Funções de Banco de Dados MQL5 no seu código MQL5.

Se você achar essa funcionalidade útil, por favor me avise. Ficarei feliz em escrever um tutorial detalhado com código de exemplo para essa sincronização entre os bancos de dados Postgres remoto e SQLite local.


Considerações finais

Nestas notas revisamos alguns métodos atualmente disponíveis para conectar uma instância de código MQL5 a um banco de dados Postgres. Escolhemos uma API REST como uma alternativa viável e rápida ao desenvolvimento de driver dedicado mais caro ou ao uso de .dll's. Além disso, desenvolvemos um aplicativo de demonstração básico como exemplo de como configurar um ambiente de desenvolvimento para MQL5/Postgres no Subsistema Windows Para Linux.

Agora você pode começar a desenvolver! Escolha um bom provedor de nuvem e aproveite todo o poder das análises do Postgres, automação, escalabilidade web e extensões de aprendizado de máquina para potencializar suas negociações.

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

Multibot no MetaTrader: lançando vários robôs a partir de um único gráfico Multibot no MetaTrader: lançando vários robôs a partir de um único gráfico
Neste artigo, veremos um modelo simples para a criação de um robô universal no MetaTrader que pode ser usado em vários gráficos, mas que é fixado em apenas um gráfico, sem a necessidade de configurar cada instância do robô em cada gráfico individual.
Um exemplo de como montar modelos ONNX em MQL5 Um exemplo de como montar modelos ONNX em MQL5
O ONNX (Open Neural Network Exchange) é um padrão aberto para a representação de modelos de redes neurais. Neste artigo, mostraremos a possibilidade de usar dois modelos ONNX simultaneamente em um Expert Advisor.
Teoria das Categorias em MQL5 (Parte 6): produtos fibrados monomórficos e coprodutos fibrados epimórficos Teoria das Categorias em MQL5 (Parte 6): produtos fibrados monomórficos e coprodutos fibrados epimórficos
A teoria das categorias é um ramo diversificado e em expansão da matemática que só recentemente começou a ser abordado na comunidade MQL5. Esta série de artigos tem como objetivo analisar alguns de seus conceitos para criar uma biblioteca aberta e utilizar ainda mais essa maravilhosa seção na criação de estratégias de negociação.
Desenvolvendo um sistema de Replay - Simulação de mercado ( Parte 21):  FOREX (II) Desenvolvendo um sistema de Replay - Simulação de mercado ( Parte 21): FOREX (II)
Vamos continuar a montagem do sistema para cobrir o mercado de FOREX. Então para resolver este problema, precisaríamos primeiramente, declarar o carregamento dos tickets, antes de fazer o carregamento das barras previas. Isto resolve o problema, mas ao mesmo tempo força o usuário, a um tipo de modelagem do arquivo de configuração, que ao meu ver não faz muito sentido. O motivo é que, ao desenvolver a programação, responsável por analisar e executar o que esta no arquivo de configuração, podemos permitir ao usuário, declarar as coisas em qualquer ordem.