English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Como acessar o banco de dados MySQL a partir do MQL5 (MQL4)

Como acessar o banco de dados MySQL a partir do MQL5 (MQL4)

MetaTrader 5Integração | 4 novembro 2014, 16:51
8 787 3
Eugeniy Lugovoy
Eugeniy Lugovoy

Introdução

O problema de interação entre o MQL e com os bancos de dados não são novos, no entanto, é algo ainda relevante. O uso de bancos de dados podem aumentar consideravelmente as possibilidades do MetaTrader: armazenamento e análise do histórico de preços, copiar negociações de uma plataforma de negociação para outra, fornecer cotações/negociações em tempo real, realizar cálculos computacionais analíticos ​​no lado do servidor e/ou usar uma agenda, monitoramento remoto e controle de contas utilizando a tecnologia web.

De qualquer forma, houve muitas tentativas para se beneficiar da combinação do MQL e MySQL, algumas soluções estão disponíveis na Base de código.

Por exemplo, o projeto "MySQL wrapper -biblioteca para MetaTrader 4", do qual muitos programadores iniciaram seus próprios desenvolvimentos adicionando mais recursos. Na minha opinião, um dos inconvenientes desta solução é atribuição de arrays especiais para a leitura de dados a partir do banco de dados.

Outro projeto "MySQL logger 1 - EA para MetaTrader 4" é altamente especializado, ele não utiliza o wrapper para acessar a biblioteca padrão libmysql.dll. Portanto ele não funciona no MetaTrader4 build 600+, uma vez que os caracteres do tipo char foram substituídos por wchar_t, e a utilização do tipo int, em vez da estrutura do ponteiro TMYSQL fez com que houvessem vazamentos de memória no projeto (a memória alocada não podia ser controlada/liberada).

Outro projeto interessante é o projeto "EAX_Mysql - MySQL library - biblioteca para MetaTrader 5". É uma implementação muito boa. A lista de desvantagens indicadas pelo autor impõe algumas restrições ao seu uso.

Qualquer um que nunca precisou usa bancos de dados em seus projetos MQL tem duas opções: ou desenvolver sua própria solução e saber cada parte dela, ou usar / adaptar qualquer solução de terceiros, aprender a usá-la e detectar todos os seus defeitos que podem dificultar de alguma maneira o seu projeto.

Eu enfrentei tal necessidade enquanto eu desenvolvia um robô de negociação bem complexo. Tendo procurado por projetos existentes e estudado um número muito grande de soluções, eu percebi que nenhuma das implementações encontradas poderiam me ajudar a levar o meu robô de negociação para o "nível profissional".

Além disso, houve também soluções absurdas, por exemplo: as operações DML/DDL (inserir/atualizar/remover dados, criar objetos/excluir do banco de dados) foram realizadas utilizando a libmysql.dll padrão, e a seleção de dados (SELECT) foi realmente implementada como um solicitação HTTP (utilizando inet.dll) para um script PHP localizado no servidor web no lado do servidor MySQL. As consultas em SQL foram escritas no script em PHP.

Em outras palavras, para executar o projeto, era preciso manter os seguintes componentes disponíveis, configurado e em execução: servidor MySQL, o servidor web Apache/IIS, os scripts PHP/ASP no lado do servidor... Uma combinação de um número bem grande de tecnologias. É claro que, em algumas circunstâncias, isto pode ser aceitável, mas apenas quando a tarefa é a de selecionar os dados a partir do banco de dados - isto é um absurdo. Além disso, o suporte de uma solução tão complicada é demorada.

A maioria das soluções não tinha problemas na inserção de dados, criação de objetos e similares. O problema foi a seleção de dados, como os dados devem ser devolvidos para o ambiente de chamada.

Eu pensei em usar arrays para este fim, mas era pouco prático e inconveniente, simplesmente porque durante o desenvolvimento/depuração/suporte do projeto principal, as consultas selecionadas para o banco de dados podem ser alteradas, enquanto que você também deve controlar a alocação de memória correta para os arrays... Bom, isto pode e deve ser evitado.

A seguir eu discuto a interface MQL <-> MySql que é baseada em uma abordagem típica utilizada em Oracle PL/SQL, MS SQL T-SQL, AdoDB - trabalhando com cursores. Esta interface foi desenvolvida com objetivo de facilitar a programação e manutenção, além de minimizar seus componentes. Ela é implementada como um DLL wrapper para a biblioteca padrão libmysql.dll e um conjunto de funções de interface como um arquivo em ".mqh".


1. A Interface MQL <-> MySQL

A interação entre o terminal MetaTrader (através dos programas MQL) pode ser implementada com a ajuda dos componentes abaixo:

O esquema de interação MQL e MySQL

1. A biblioteca da interface MQLMySQL.mqh. Ela é adicionada ao projeto usando a diretriz #include e ela pode ser modificada conforme seu gosto.

Ela contém as diretrizes para importar as funções da biblioteca dinâmica MQLMySQL.dll, bem como as funções de importação para chamá-las e e tratar seus erros.

2. A biblioteca dinâmica MQLMySQL.dll. Ela é um wrapper para acessar a funcionalidade da biblioteca padrão libmysql.dll.

Além disso, a biblioteca MQLMySQL.dll processa os resultados das operações e o acesso compartilhado entre as conexões do banco de dados e do cursores. Isso significa que você pode criar e usar múltiplas conexões ao mesmo tempo (a partir de um ou mais programas MQL), mantenha alguns cursores em aberto, com consultas para um ou mais bancos de dados. Os Mutex são usados ​​para separar o acesso de recursos compartilhados.

3. A biblioteca dinâmica padrão libmysql.dll é um condutor nativo de acesso. Você pode copiá-la a partir de qualquer distribuição de banco de dados MySql em C:\Windows\Sytem32 ou <Terminal>\MQL5\Libraries (para o MetaTrader 4 em <Terminal>\MQL4\ Libraries).

Na verdade, ela é responsável por enviar consultas à base de dados e recuperar seus resultados.

Vamos debruçar sobre os pontos principais, tais como: abrir/fechar uma conexão, realizar consultas DML/DDL e a seleção de dados.

1.1. Abrindo e Fechando uma Conexão

A função MySqlConnect foi implementada para a abrir uma conexão com o banco de dados MySQL:

Tipo

Nome

Parâmetros

Descrição

int

MySqlConnect

Esta função implementa a conexão com o banco de dados e retorna um identificador de conexão. Essa identificação (ID) será necessária para consultar o banco de dados.

Em caso de falha na conexão, o valor de retorno é igual a "-1". Para maiores detalhes sobre o erro, verifique as variáveis MySQLErrorNumber e MySqlErrorDescription.

Normalmente, essa função é chamada quando se processa o evento OnInit() no programa MQL.

string pHost

O nome DNS ou o endereço IP do servidor MySQL

string pUser

Usuário do banco de dados (por exemplo, root)

string pPassword

A senha do usuário do banco de dados

string pDatabase

O nome do banco de dados

int pPort

A porta TCP/IP do banco de dados (geralmente 3306)

string pSocket

O socket Unix (para os sistemas baseados em Unix)

int pClientFlag

A combinação de flags especiais (geralmente 0)

A interface da função MySqlDisconnect foi implementada para fechar a conexão:

Tipo

Nome Parâmetros Descrição

void

MySqlDisconnect

Esta função fecha a conexão com o banco de dados MySQL.

Normalmente, essa função é chamada quando se processa o evento OnDeinit() no programa MQL.

int pConnection

Identificador da conexão

Deve-se notar que a base de dados MySQL pode fechar a conexão por si próprio em caso de uma falha de hardware, congestionamento da rede ou atingir o tempo limite (quando não há consultas a serem enviadas para o banco de dados por um longo período de tempo).

Muitas vezes, os desenvolvedores usam o evento OnTick() para gravar os dados no banco de dados. No entanto, quando o fim de semana chega e o mercado está fechado, a conexão ainda fica "pendurada". Neste caso, o MySQL irá fechar sua conexão por ter atingido o tempo limite (o padrão é de 8 horas).

E na segunda-feira, quando o mercado abrir, será encontrado erros no projeto. Por isso é altamente recomendável verificar a conexão e/ou reconectar-se ao banco de dados após um intervalo de tempo menor do que o limite especificado nas configurações do servidor MySQL.

1.2. Execução das Consultas DML/DDL

As operações DML são usadas para a manipulação de dados (Data Manipulation Language). As manipulações de dados incluem o seguinte conjunto de instruções: inserir (INSERT), atualizar (UPDATE) e remover (DELETE).

Operações DDL são usadas ​​para definição dos dados (Data Definition Language). Isso inclui a criação (CREATE) de objetos do banco de dados (tabelas, exibições, procedimentos armazenados, acionamentos, etc.) e sua modificação (ALTER) e exclusão (DROP).

Não são todas as declarações DML/DDL, além disso, DCL (Data Control Language) é usada para o acesso de dados em separado, mas nós não iremos aprofundar as características do SQL. Qualquer um destes comandos podem ser executados usando a função de interface MySqlExecute:


Tipo

Nome

Parâmetros

Descrição

bool

MySqlExecute

Esta função pode ser usada para executar instruções non-SELECT do SQL, após a conexão com o banco de dados ser criada com sucesso (usando a função MySqlConnect).

Em caso dos comandos terem sido executados com sucesso, a função retorna true, caso contrário - false. Para maiores detalhes sobre o erro, utilize o MySQLErrorNumber e MySqlErrorDescription.

int pConnection

Identificador da conexão

string pQuery

Consulta SQL

Como uma consulta SQL, é possível usar também o comando USE para selecionar o banco de dados. Eu gostaria de mencionar o uso das consultas multi-instrução. É um conjunto de comandos SQL separados por caractere ";".

Para habilitar o modo multi-instrução, a conexão com o banco de dados deve ser aberta com a flag CLIENT_MULTI_STATEMENTS:

...
int ClientFlag = CLIENT_MULTI_STATEMENTS; // Definir o flag multi-statements
int DB; 

DB = MySqlConnect(Host, User, Password, Database, Port, Socket, ClientFlag); // Conexão com o banco de dados

if (DB == -1)
   {
    // Tratamento de erro da conexão
   }
...

// Preparando uma consulta SQL para inserir dados (3 linhas em uma consulta)
string SQL;
SQL = "INSERT INTO EURUSD(Ask,Bid) VALUES (1.3601,1.3632);";
SQL = SQL + "INSERT INTO EURUSD(Ask,Bid) VALUES (1.3621,1.3643);";
SQL = SQL + "INSERT INTO EURUSD(Ask,Bid) VALUES (1.3605,1.3629);";
...

if (!MySqlExecute(DB,SQL)) 
   {
    // Exibir uma mensagem de erro
   }
...

Neste fragmento, 3 entradas serão inseridos na tabela EURUSD com uma única chamada para o banco de dados. Cada uma das consultas armazenadas na variável SQL é separada por ";".

Esta abordagem pode ser usada para uma frequente inserção/atualização/remoção; um conjunto de comandos necessários é combinado em um único "pacote", aliviando, assim, o tráfego da rede e melhorar o desempenho do banco de dados.

A sintaxe INSERT no MySQL é muito bem desenvolvida em termos de tratamento de exceção.

Por exemplo, se a tarefa é mover o histórico de preços, a tabela deve ser criada para os pares de moedas com a chave primária do tipo data e hora, uma vez que a data e a hora da barra for única. Além disso, deve-se verificar se os dados sobre qualquer barra em particular existe na base de dados (para melhorar a estabilidade da migração de dados). Com o MySQL não é necessário essa verificação, uma vez que a instrução INSERT suporta ON DUPLICATE KEY.

Em palavras mais simples, se for feito uma tentativa de inserir os dados, e a tabela já tiver uma entrada com a mesma data e hora, a instrução INSERT pode ser ignorada ou substituída devido a uma atualização nesta linha (veja em http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html).

1.3. Seleção dos Dados

A instrução SQL SELECT é usada para recuperar os dados do banco de dados. A seqüência de ações abaixo é usada para selecionar os dados e recuperar o resultado da seleção:

  1. Preparar a instrução SELECT.
  2. Abrir o cursor.
  3. Obter o número de linhas retornadas pela consulta.
  4. Looping e recuperar cada linha da consulta.
  5. Buscar dados para as variáveis ​​MQL dentro do loop.
  6. Fechar o cursor.

É claro que este é um esquema geral, de modo que nem todas as operações são necessárias para cada caso. Por exemplo, se você quiser ter certeza de que existe uma linha na tabela (por qualquer critério), será suficiente apenas preparar uma consulta, abrir um cursor, obter o número de linhas e fechar o cursor. Na verdade, as partes obrigatórias são - preparar a instrução SELECT, abrir e fechar o cursor.

O que é um cursor? Ele é uma referência para a área de memória do contexto, na verdade - o conjunto resultante de valores. Quando você envia a consulta SELECT, o banco de dados aloca memória para o resultado e cria um ponteiro para uma linha que é possível passar de uma linha para outra. Assim, é possível ter acesso a todas as linhas no fim de uma fila definida pela consulta (ORDER BY (ordem por) cláusula da instrução SELECT).

As seguintes funções de interface são usados ​​para a seleção dos dados:

Abrir o cursor:

Tipo

Nome

Parâmetros

Descrição

int

MySqlCursorOpen

Esta função abre um cursor para a consulta SELECT e retorna o identificador do cursor em caso de sucesso. Caso contrário, a função retorna "-1". Para descobrir a causa do erro, use as variáveis MySQLErrorNumber e MySqlErrorDescription.

int pConnection

Identificador da conexão com o banco de dados

string pQuery

Consulta SQL (a instrução SELECT)

Obter o número de linhas retornadas pela consulta:

Tipo

Nome

Parâmetros

Descrição

int

MySqlCursorRows

Esta função retorna o número de linhas selecionadas pela consulta.

int pCursorID

O identificador do cursor é retornado por MySqlCursorOpen

Buscar a linha de consulta:

Tipo

Nome

Parâmetros

Descrição

bool

MySqlCursorFetchRow

Obtém uma linha do conjunto de dados retornado pela consulta. Após a execução bem-sucedida, você pode recuperar os dados para as variáveis ​​MQL. A função retorna true se for bem sucedida, caso contrário, retorna false.

int pCursorID

O identificador do cursor é retornado por MySqlCursorOpen

Buscar os dados nas variáveis ​​MQL após a busca da linha de consulta:

Tipo

Nome

Parâmetros

Descrição

int

MySqlGetFieldAsInt

Esta função retorna a representação do valor no campo da tabela utilizando o tipo de dados int.

int pCursorID

O identificador do cursor é retornado por MySqlCursorOpen

int pField

O número do campo na lista SELECT (numeração começa com 0)

double

MySqlGetFieldAsDouble

Esta função retorna a representação do valor no campo da tabela utilizando o tipo de dados double.

int pCursorID

O identificador do cursor é retornado por MySqlCursorOpen

int pField

O número do campo na lista SELECT (numeração começa com 0)

datetime

MySqlGetFieldAsDatetime

Esta função retorna a representação do valor no campo da tabela utilizando o tipo de dados datetime.

int pCursorID

O identificador do cursor é retornado por MySqlCursorOpen

int pField

O número do campo na lista SELECT (numeração começa com 0)

string

MySqlGetFieldAsString

Esta função retorna a representação do valor no campo da tabela utilizando o tipo de dados string.

int pCursorID

O identificador do cursor é retornado por MySqlCursorOpen

int pField

O número do campo na lista SELECT (numeração começa com 0)


Todos os dados retornados pelo MySQL possuem uma representação nativa (apresentada sem tipos como strings).

Portanto, usando essas funções, você pode lançar os dados selecionados para o tipo desejado. A única desvantagem é a especificação do número de colunas (a numeração começa em 0) na lista SELECT em vez de seu nome. No entanto, ao desenvolver uma aplicação, a preparação da instrução SELECT e a obtenção dos resultados estão quase sempre em uma página, assim você pode ver a consulta SELECT, quando prescrever a lógica dos dados de busca.

Assim, você sempre saberá os números dos campos da lista SELECT (esta abordagem também é utilizada ao acessar os dados usando AdoDB). Bem, esta parte pode ainda ser revista no futuro. Mas isso terá pouco impacto sobre a funcionalidade da solução desenvolvida.

Fechar o cursor:

Tipo

Nome

Parâmetros

Descrição

void

MySqlCursorClose

Esta função fecha o cursor especificado e libera a memória.

int pCursorID

O identificador do cursor é retornado por MySqlCursorOpen

Fechar o cursor é uma operação crítica. Não se esqueça de fechar os cursores.

Imagine que você abria o cursor e se esquece de fechá-lo. Suponha que, os dados são recuperados para o cursor com todos os ticks durante o processamento do evento OnTick(), e cada vez que um novo cursor é aberto, a memória é alocada para ele (tanto do lado do cliente quanto do lado do servidor). Em algum momento, o servidor irá recusar o serviço, pois o limite de cursores abertos é alcançado, e isso pode causar estouro de buffer.

É claro, que é exagerado, mas tal resultado é possível quando se trabalha com a libmysql.dll diretamente. No entanto, a biblioteca dinâmica MQLMySQL.DLL distribui a memória para os cursores e se recusará a abrir um cursor que vai além do limite permitido.

Ao implementar tarefas reais, 2-3 cursores já é o suficiente para se manter em aberto. Cada cursor pode lidar com uma medição cartesiano de dados; utilizando dois ou três cursores simultaneamente (aninhados, por exemplo, quando um depende parametricamente de outro cursor), podemos abranger de duas a três dimensões. Isso é perfeitamente normal para a maioria das tarefas. Além disso, para a implementação de seleção de dados complexos, é possível sempre usar esses objetos para representar o banco de dados (VIEW), criá-los no lado do servidor e enviar consultas a elas a partir do código MQL como para as tabelas.

1.4. Informações Adicionais

A seguir vamos mencionar algumas características adicionais:

1.4.1. Lendo os dados de um arquivo .INI

Tipo

Nome

Parâmetros

Descrição

String

ReadIni

Retorna o valor de uma chave da seção dada do arquivo INI.

string pFileName

O nome do arquivo INI

string pSection

O nome da seção

string pKey

O nome da chave


Muitas vezes, armazenar informações sobre as conexões do banco de dados (endereço IP do servidor, porta, nome de usuário, senha, etc.) diretamente no código MQL (ou nos parâmetros do Expert Advisor, indicador do script) não é racional, porque o servidor pode ser movido, seu endereço pode mudar dinamicamente, etc. Você terá que modificar o código MQL neste caso. Assim, todos esses dados devem ser melhor armazenado no arquivo .INI padrão, enquanto que apenas o seu nome deve ser escrito no programa MQL. Em seguida, use a função ReadINI para ler os parâmetros de conexão e comeãr a usá-los.

Por exemplo, o arquivo INI contém as seguintes informações:

[MYSQL]
Server = 127.0.0.1
User = root
Password = Adm1n1str@t0r
Database = mysql
Port = 3306

Para obter o endereço IP do servidor, execute o seguinte:

string vServer = ReadIni("C:\\MetaTrader5\\MQL5\\Experts\\MyConnection.ini", "MYSQL", "Server");

O arquivo INI está localizado em C:\MetaTrader5\MQL5\Experts e é chamado de "MyConnection.ini", você acessa a chave do Server da seção MYSQL. Em um arquivo INI, você pode armazenar as configurações de diversos servidores utilizados em seu projeto.

1.4.2. Rastreando as Áreas Problemáticas

A biblioteca de interface fornece o modo de rastreamento, que pode ser ativado para depurar as consultas SQL em qualquer lugar do programa em MQL.

Especifique o seguinte na área do problema:

SQLTrace = true;

e, em seguida

SQLTrace = false;

Se você ativar o rastreamento no início do programa MQL e não desativá-lo, todas as chamadas para o banco de dados serão registadas. O log é mantido no console de terminal (usando o comando de impressão).


2. Exemplos

Esta seção fornece alguns exemplos relacionados a conexão e utilização das bibliotecas desenvolvidas. Observe e estime a capacidade de utilização da solução de software.

O exemplo MySQL-003.mq5 mostra o seguinte: a conexão com um banco de dados (os parâmetros de conexão são armazenados no arquivo .ini), a criação de uma tabela, a inserção de dados (também usando multi-instâncias) e se desconectar do banco de dados.

//+------------------------------------------------------------------+
//|                                                    MySQL-003.mq5 |
//|                                   Copyright 2014, Eugene Lugovoy |
//|                                              https://www.mql5.com |
//| Inserting data with multi-statement (DEMO)                       |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, Eugene Lugovoy."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

#include <MQLMySQL.mqh>

string INI;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
 string Host, User, Password, Database, Socket; // database credentials
 int Port,ClientFlag;
 int DB; // database identifier
 
 Print (MySqlVersion());

 INI = TerminalInfoString(TERMINAL_PATH)+"\\MQL5\\Scripts\\MyConnection.ini";
 
 // reading database credentials from INI file
 Host = ReadIni(INI, "MYSQL", "Host");
 User = ReadIni(INI, "MYSQL", "User");
 Password = ReadIni(INI, "MYSQL", "Password");
 Database = ReadIni(INI, "MYSQL", "Database");
 Port     = (int)StringToInteger(ReadIni(INI, "MYSQL", "Port"));
 Socket   = ReadIni(INI, "MYSQL", "Socket");
 ClientFlag = CLIENT_MULTI_STATEMENTS; //(int)StringToInteger(ReadIni(INI, "MYSQL", "ClientFlag"));  

 Print ("Host: ",Host, ", User: ", User, ", Database: ",Database);
 
 // open database connection
 Print ("Connecting...");
 
 DB = MySqlConnect(Host, User, Password, Database, Port, Socket, ClientFlag);
 
 if (DB == -1) { Print ("Connection failed! Error: "+MySqlErrorDescription); } else { Print ("Connected! DBID#",DB);}
 
 string Query;
 Query = "DROP TABLE IF EXISTS `test_table`";
 MySqlExecute(DB, Query);
 
 Query = "CREATE TABLE `test_table` (id int, code varchar(50), start_date datetime)";
 if (MySqlExecute(DB, Query))
    {
     Print ("Table `test_table` created.");
     
     // Inserting data 1 row
     Query = "INSERT INTO `test_table` (id, code, start_date) VALUES ("+(string)AccountInfoInteger(ACCOUNT_LOGIN)+",\'ACCOUNT\',\'"+TimeToString(TimeLocal(), TIME_DATE|TIME_SECONDS)+"\')";
     if (MySqlExecute(DB, Query))
        {
         Print ("Succeeded: ", Query);
        }
     else
        {
         Print ("Error: ", MySqlErrorDescription);
         Print ("Query: ", Query);
        }
     
     // multi-insert
     Query =         "INSERT INTO `test_table` (id, code, start_date) VALUES (1,\'EURUSD\',\'2014.01.01 00:00:01\');";
     Query = Query + "INSERT INTO `test_table` (id, code, start_date) VALUES (2,\'EURJPY\',\'2014.01.02 00:02:00\');";
     Query = Query + "INSERT INTO `test_table` (id, code, start_date) VALUES (3,\'USDJPY\',\'2014.01.03 03:00:00\');";
     if (MySqlExecute(DB, Query))
        {
         Print ("Succeeded! 3 rows has been inserted by one query.");
        }
     else
        {
         Print ("Error of multiple statements: ", MySqlErrorDescription);
        }
    }
 else
    {
     Print ("Table `test_table` cannot be created. Error: ", MySqlErrorDescription);
    }
 
 MySqlDisconnect(DB);
 Print ("Disconnected. Script done!");
}

O exemplo MySQL-004.mq5 mostra a seleção de dados de uma tabela criada pelo script "MySQL-003.mq5". 

//+------------------------------------------------------------------+
//|                                                    MySQL-004.mq5 |
//|                                   Copyright 2014, Eugene Lugovoy |
//|                                              https://www.mql5.com |
//| Select data from table (DEMO)                                    |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, Eugene Lugovoy."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

#include <MQLMySQL.mqh>

string INI;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
 string Host, User, Password, Database, Socket; // database credentials
 int Port,ClientFlag;
 int DB; // database identifier
 
 Print (MySqlVersion());

 INI = TerminalInfoString(TERMINAL_PATH)+"\\MQL5\\Scripts\\MyConnection.ini";
 
 // reading database credentials from INI file
 Host = ReadIni(INI, "MYSQL", "Host");
 User = ReadIni(INI, "MYSQL", "User");
 Password = ReadIni(INI, "MYSQL", "Password");
 Database = ReadIni(INI, "MYSQL", "Database");
 Port     = (int)StringToInteger(ReadIni(INI, "MYSQL", "Port"));
 Socket   = ReadIni(INI, "MYSQL", "Socket");
 ClientFlag = (int)StringToInteger(ReadIni(INI, "MYSQL", "ClientFlag"));  

 Print ("Host: ",Host, ", User: ", User, ", Database: ",Database);
 
 // open database connection
 Print ("Connecting...");
 
 DB = MySqlConnect(Host, User, Password, Database, Port, Socket, ClientFlag);
 
 if (DB == -1) { Print ("Connection failed! Error: "+MySqlErrorDescription); return; } else { Print ("Connected! DBID#",DB);}
 
 // executing SELECT statement
 string Query;
 int    i,Cursor,Rows;
 
 int      vId;
 string   vCode;
 datetime vStartTime;
 
 Query = "SELECT id, code, start_date FROM `test_table`";
 Print ("SQL> ", Query);
 Cursor = MySqlCursorOpen(DB, Query);
 
 if (Cursor >= 0)
    {
     Rows = MySqlCursorRows(Cursor);
     Print (Rows, " row(s) selected.");
     for (i=0; i<Rows; i++)
         if (MySqlCursorFetchRow(Cursor))
            {
             vId = MySqlGetFieldAsInt(Cursor, 0); // id
             vCode = MySqlGetFieldAsString(Cursor, 1); // code
             vStartTime = MySqlGetFieldAsDatetime(Cursor, 2); // start_time
             Print ("ROW[",i,"]: id = ", vId, ", code = ", vCode, ", start_time = ", TimeToString(vStartTime, TIME_DATE|TIME_SECONDS));
            }
     MySqlCursorClose(Cursor); // NEVER FORGET TO CLOSE CURSOR !!!
    }
 else
    {
     Print ("Cursor opening failed. Error: ", MySqlErrorDescription);
    }
    
 MySqlDisconnect(DB);
 Print ("Disconnected. Script done!");
}

Os exemplos acima contem o tratamento de erro típico utilizado em projetos reais.

Na verdade, cada consulta utilizada em um programa MQL deve ser depurada em qualquer cliente MySQL (PHPMyAdmin, DB Ninja, console MySQL). Eu, pessoalmente, uso e recomendo o software profissional Quest TOAD para o desenvolvimento de banco de dados em MySQL.


Conclusão

Este artigo não descreve os detalhes da implementação do MQLMySQL.DLL que foi desenvolvido no ambiente Microsoft Visual Studio 2010 (C/C ++). Esta solução de software foi projetado para o uso prático e tem mais de 100 implementações de sucesso em várias áreas de desenvolvimento de software MQL (a partir da criação de sistemas de negociação complexos para publicação na web).

  • As versões das bibliotecas para MQL4 e MQL5 se encontram em anexo abaixo. Os anexos também incluem um arquivo zip com o código fonte do MQLMySQL.DLL;
  • A documentação está inclusa nos arquivos;
  • Para usar os exemplos, não se esqueça de especificar os parâmetros de conexão com o banco de dados no arquivo \Scripts\ MyConnection.ini.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/932

Arquivos anexados |
MQLMySQL_for_MQL4.zip (1124.85 KB)
MQLMySQL_for_MQL5.zip (1125.19 KB)
Últimos Comentários | Ir para discussão (3)
Eugeniy Lugovoy
Eugeniy Lugovoy | 4 nov 2014 em 17:27
Para MetaTrader5 x64 utilize a seguinte biblioteca (anexado na discussão):
Hallyton Ribeiro
Hallyton Ribeiro | 19 jun 2020 em 05:28
em qual pasta eu salvo os a DLL?
Eugeniy Lugovoy
Eugeniy Lugovoy | 20 jun 2020 em 11:57
Ana Fonseca:
em qual pasta eu salvo os a DLL?
Aqui está o pacote completo de atualização da DLL: https://github.com/elugovoy/MQLMySQL-Project
inclui dlls compiladas localizadas na estrutura de pastas do metatrader
Guia Prático MQL5: Processamento de Eventos Personalizados do Gráfico Guia Prático MQL5: Processamento de Eventos Personalizados do Gráfico
Este artigo considera os aspectos de design e desenvolvimento de eventos personalizados do gráfico no ambiente em MQL5. Um exemplo de uma abordagem para a classificação dos eventos também podem ser encontrados aqui, bem como um código de programação para uma classe de eventos e uma classe de tratamento de eventos personalizados.
Guia Prático MQL5 - Expert Advisor Multi-Moeda e Trabalhando com ordens pendentes em MQL5 Guia Prático MQL5 - Expert Advisor Multi-Moeda e Trabalhando com ordens pendentes em MQL5
Desta vez, vamos criar um Expert Advisor multi-moeda com um algoritmo de negociação baseado no envio de ordens pendentes do tipo Buy Stop e Sell Stop. Neste artigo veremos os seguintes tópicos: a negociação em um intervalo de tempo especificado, colocar/modificar/remover as ordens pendentes, verificar se a última posição foi fechada no Take Profit ou no Stop Loss e controlar o histórico de transações para cada símbolo.
Porque a Hospedagem Virtual no MetaTrader 4 e no MetaTrader 5 são Melhores que os VPS Usuais Porque a Hospedagem Virtual no MetaTrader 4 e no MetaTrader 5 são Melhores que os VPS Usuais
A rede de hospedagem virtual em nuvem foi desenvolvida especialmente para o MetaTrader 4 e o MetaTrader 5, possuindo todas as vantagens de uma solução nativa. Obtenha os benefícios de nossa oferta gratuita por 24 horas - teste um servidor virtual agora mesmo.
Guia Prático MQL5: Processamento de Eventos Típicos do Gráfico Guia Prático MQL5: Processamento de Eventos Típicos do Gráfico
Este artigo considera os eventos típicos do gráfico e inclui exemplos de seu processamento. Iremos nos concentrar em eventos realizados pelo mouse, teclas, criação/alteração/remoção de um objeto gráfico, clique do mouse no gráfico e em um objeto gráfico, arrastamento de um objeto gráfico com o mouse, término da edição do texto em um campo de texto, bem como os eventos de modificação do gráfico. Será fornecido um exemplo de programa em MQL5 para cada tipo de evento aqui considerado.