Comment accéder à la base de données MySQL à partir de MQL5 (MQL4)
Introduction
Le problème de l'interaction de MQL avec les bases de données n'est pas nouveau, mais il est toujours d'actualité. L'utilisation de bases de données peut grandement améliorer les possibilités de MetaTrader : stockage et analyse de l'historique des prix, copie des transactions d'une plateforme de trading à une autre, fourniture de cotations/trades en temps réel, calculs analytiques lourds côté serveur et/ou utilisation d'un planning, suivi et contrôle à distance des comptes à l'aide des technologies web.
Quoi qu'il en soit, il y a eu de nombreuses tentatives pour bénéficier de la combinaison de MQL et MySQL, certaines solutions sont disponibles dans le CodeBase.
Par exemple, « MySQL wrapper - bibliothèque pour MetaTrader 4 » est le projet à partir duquel de nombreux programmeurs commencent leurs propres développements avec d'autres ajouts. À mon avis, l'un des inconvénients de cette solution est l'allocation de tableaux spéciaux pour la lecture des données de la base de données.
Un autre projet « MySQL logger 1 - EA pour MetaTrader 4 » est hautement spécialisé, il n'utilise aucun wrapper pour accéder à la bibliothèque standard libmysql.dll. Par conséquent, cela ne fonctionne pas dans MetaTrader4 Build 600+, car les types de caractères char ont été remplacés par wchar_t, et l'utilisation du type int au lieu du pointeur de structure TMYSQL provoque des fuites de mémoire dans le projet (la mémoire allouée ne peut pas être contrôlée/libéré).
Un autre projet intéressant est « EAX_Mysql - Bibliothèque MySQL - bibliothèque pour MetaTrader 5 ». C'est une très bonne mise en œuvre. La liste des inconvénients énoncés par l'auteur impose certaines restrictions à son utilisation.
Quiconque a besoin d'utiliser des bases de données dans ses projets MQL a deux options : soit développer sa propre solution et en connaître chaque partie, soit utiliser/adapter n'importe quelle solution tierce, apprendre à l'utiliser et détecter tous ses défauts qui peuvent entraver son projet.
J'ai été confronté à une telle nécessité et aux deux options tout en développant un robot de trading assez complexe. Après avoir parcouru des projets existants et étudié un très grand nombre de solutions, je me suis rendu compte qu'aucune des implémentations trouvées ne pouvait aider à amener mon robot de trading au « niveau professionnel ».
De plus, il y avait aussi des solutions absurdes, par exemple : Les opérations DML/DDL (insertion/mise à jour/suppression de données, création/suppression d'objets dans la base de données) ont été effectuées à l'aide de la norme libmysql.dll, et la sélection de données (SELECT) a en fait été implémentée en tant que requête HTTP (en utilisant inet.dll) vers un PHP script situé sur le serveur web côté serveur MySQL. Les requêtes SQL ont été écrites dans le script PHP.
En d'autres termes, pour exécuter le projet, il fallait garder les composants suivants disponibles, configurés et en cours d'exécution : Serveur MySQL, serveur web Apache/IIS, scripts PHP/ASP côté serveur... Une combinaison d'un assez grand nombre de technologies. Bien sûr, dans certaines circonstances, cela peut être acceptable, mais lorsque la seule tâche consiste à sélectionner des données dans la base de données, cela n'a aucun sens. De plus, la prise en charge d'une solution aussi lourde prend du temps.
La plupart des solutions n'avaient aucun problème pour insérer des données, créer des objets, etc. Le problème était la sélection des données, car les données devaient être renvoyées à l'environnement appelant.
Je pensais que l'utilisation de tableaux à cette fin était peu pratique et peu convenable, simplement parce qu'au cours du développement/débogage/prise en charge du projet principal, les requêtes sélectionnées dans la base de données peuvent être modifiées, tandis que vous devez également contrôler l'allocation de mémoire correcte pour les tableaux. . Eh bien, cela peut et doit être évité.
L'interface MQL <-> MySql discutée ci-après est basée sur une approche typique utilisée dans Oracle PL/SQL, MS SQL T-SQL, AdoDB - utilisation de curseurs. Cette interface a été développée en ciblant la facilité de programmation et de maintenance, ainsi qu'un minimum de composants. Il est implémenté en tant que wrapper de DLL dans la bibliothèque standard libmysql.dll et un ensemble de fonctions d'interface en tant que fichier .mqh.
1. Interface MQL <-> MySQL
L'interaction entre le terminal MetaTrader (via les programmes MQL) peut être mise en œuvre à l'aide des composants ci-dessous :
1. La bibliothèque d'interface MQLMySQL.mqh. Elle est ajoutée au projet à l'aide du répertoire #include et peut être modifiée à votre convenance.
Elle contient les directives d'import des fonctions de la bibliothèque dynamique MQLMySQL.dll, ainsi que les fonctions d'appel et de gestion des erreurs.
2. La bibliothèque dynamique MQLMySQL.dll. C'est un wrapper pour accéder aux fonctionnalités de la bibliothèque standard libmysql.dll.
De plus, la bibliothèque MQLMySQL.dll traite les résultats des opérations et l'accès partagé aux connexions et curseurs de la base de données. Cela signifie que vous pouvez créer et utiliser plusieurs connexions à la fois (à partir d'un ou plusieurs programmes MQL), garder quelques curseurs ouverts, avec des requêtes vers une ou plusieurs bases de données. Les mutex sont utilisés pour séparer l'accès aux ressources partagées.
3. La bibliothèque dynamique standard libmysql.dll est un pilote d'accès natif. Vous pouvez la copier à partir de n'importe quelle distribution de base de données MySql dans C:\Windows\Sytem32 ou <Terminal>\MQL5\Libraries (pour MetaTrader 4 dans <Terminal>\MQL4\Libraries).
En fait, elle est chargée d'envoyer des requêtes à la base de données et d'en récupérer les résultats.
Attardons-nous sur les points principaux, tels que : l'ouverture/fermeture de la connexion, l'exécution de requêtes DML/DDL et la sélection de données.
1.1. Ouverture et fermeture de la connexion
La fonction MySqlConnect a été implémentée pour ouvrir la connexion avec la base de données MySQL :
Type | Nom | Paramètres | Description |
int | MySqlConnect | Cette fonction implémente la connexion avec la base de données et renvoie un identifiant de connexion. Cet identifiant sera requis pour interroger la base de données. En cas d'échec de connexion, la valeur de renvoi est « -1 ». Pour les détails de l'erreur, vérifiez les variables MySQLErrorNumber et MySqlErrorDescription. En règle générale, cette fonction est appelée lors de la gestion de l'événement OnInit() dans le programme MQL. | |
chaîne pHost | Le nom DNS ou l'adresse IP du serveur MySQL | ||
chaîne pUser | Utilisateur de la base de données (par exemple, root) | ||
chaîne pPassword | Le mot de passe de l'utilisateur de la base de données | ||
chaîne pDatabase | Le nom de la base de données | ||
int pPort | Le port TCP/IP de la base de données (généralement 3306) | ||
chaîne pSocket | Le socket Unix (pour les systèmes basés sur Unix) | ||
int pClientFlag | La combinaison d’indicateurs spéciaux (généralement 0) |
La fonction d'interface MySqlDisconnect a été implémentée pour fermer la connexion :
Type | Nom | Paramètres | Description |
vide | MySqlDisconnect | Cette fonction ferme la connexion avec la base de données MySQL. En règle générale, cette fonction est appelée lors de la gestion de l'événement OnDeinit() dans le programme MQL. | |
int pConnection | Identifiant de connexion |
Il est à noter que la base de données MySQL peut fermer la connexion d'elle-même en cas de panne matérielle, de congestion du réseau ou de timeout (lorsqu'aucune requête n'est envoyée à la base de données pendant une longue période).
Les développeurs utilisent souvent l'événement OnTick() pour écrire des données dans la base de données. Cependant, lorsque le week-end arrive et que le marché est fermé, la connexion est toujours « suspendue ». Dans ce cas, MySQL fermera son timeout (la valeur par défaut est de 8 heures).
Et le lundi, quand le marché est ouvert, des erreurs sont trouvées dans le projet. Il est donc fortement recommandé de vérifier la connexion et/ou de se reconnecter à la base de données après un intervalle de temps inférieur au timeout spécifié dans les paramètres du serveur MySQL.
1.2. Exécution de requêtes DML/DDL
Les opérations DML sont utilisées pour les manipulations de données (Data Manipulation Language). Les manipulations de données incluent l'ensemble d'instructions suivant : INSÉRER, METTRE À JOUR et SUPPRIMER.
Les opérations DDL sont utilisées pour la définition des données (Data Definition Language). Cela inclut la création (CREATE) des objets de la base de données (tables, affichages, procédures stockées, triggers, etc.) et leur modification (ALTER) et suppression (DROP).
Ce ne sont pas toutes les instructions DML/DDL. De plus, le DCL (Data Control Language) est utilisé pour séparer l'accès aux données, mais nous n'approfondirons pas les fonctionnalités du SQL. Chacune de ces commandes peut être exécutée à l'aide de la fonction d'interface MySqlExecute :
Type | Nom | Paramètres | Description |
bool | MySqlExecute | Cette fonction peut être utilisée pour exécuter des instructions SQL non SELECT, après que la connexion à la base de données ait été établie avec succès (à l'aide de la fonction MySqlConnect ). En cas d'exécution réussie de la commande, la fonction renvoie vrai, sinon - faux. Pour les détails de l'erreur, utilisez MySQLErrorNumber et MySqlErrorDescription. | |
int pConnection | Identifiant de connexion | ||
chaîne pQuery | Requête SQL |
En tant que requête SQL, vous pouvez également utiliser la commande USE pour sélectionner la base de données. Je voudrais mentionner l'utilisation de requêtes multi-instructions. C'est un ensemble de commandes SQL séparées par le caractère « ; ».
Pour activer le mode multi-instructions, la connexion avec la base de données doit être ouverte avec l’indicateur CLIENT_MULTI_STATEMENTS :
... int ClientFlag = CLIENT_MULTI_STATEMENTS; // Setting the multi-statements flag int DB; DB = MySqlConnect(Host, User, Password, Database, Port, Socket, ClientFlag); // Connection to the database if (DB == -1) { // Handling the connection error } ... // Preparing a SQL query to insert data (3 rows in one query) 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)) { // Showing an error message } ...
Dans ce fragment, 3 entrées seront insérées dans la table EURUSD avec un seul appel à la base de données. Chacune des requêtes stockées dans la variable SQL est séparée par « ; ».
Cette approche peut être utilisée pour des insertions/mises à jour/suppressions fréquentes ; un ensemble de commandes nécessaires est combiné en un seul « package », soulageant ainsi le trafic réseau et améliorant les performances de la base de données.
La syntaxe INSERT dans MySQL est assez bien développée en termes de gestion des exceptions.
Par exemple, si la tâche consiste à déplacer l'historique des prix, une table doit être créée pour les paires de devises avec la clé primaire de type datetime, car la date et l'heure d'une barre sont uniques. De plus, il convient de vérifier si les données d'une barre particulière existent dans la base de données (pour améliorer la stabilité de la migration des données). Avec MySQL, cette vérification n'est pas requise, car l'instruction INSERT prend en charge ON DUPLICATE KEY.
En termes plus simples, si une tentative est faite pour insérer des données et que la table a déjà une entrée avec la même date et la même heure, l'instruction INSERT peut être ignorée ou remplacée par UPDATE pour cette ligne (voir. http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html).
1.3. Sélection de données
L'instruction SQL SELECT est utilisée pour récupérer les données de la base de données. La séquence d'actions ci-dessous est utilisée pour sélectionner les données et récupérer le résultat de la sélection :
- Préparation de l'instruction SELECT.
- Ouverture du curseur.
- Obtention du nombre de lignes renvoyées par la requête.
- Boucle et récupération de chaque ligne de la requête.
- Récupération des données dans les variables MQL à l'intérieur de la boucle.
- Fermeture du curseur.
Bien sûr, il s'agit d'un schéma général, donc toutes les opérations ne sont pas nécessaires pour chaque cas. Par exemple, si vous voulez vous assurer qu'une ligne existe dans la table (quel que soit le critère), il suffira de préparer une requête, d'ouvrir un curseur, d'obtenir le nombre de lignes et de fermer le curseur. En fait, les parties obligatoires sont - la préparation de l'instruction SELECT, l'ouverture et la fermeture du curseur.
Qu'est-ce qu'un curseur ? Il s'agit d'une référence à la zone de mémoire de contexte, en fait - l'ensemble de valeurs résultant. Lorsque vous envoyez la requête SELECT, la base de données alloue de la mémoire pour le résultat et crée un pointeur vers une ligne que vous pouvez déplacer d'une ligne à une autre. Ainsi il est possible d'accéder à toutes les lignes dans l'ordre d'une file d'attente définie par la requête (clause ORDER BY de l'instruction SELECT).
Les fonctions d'interface suivantes sont utilisées pour la sélection des données :
Ouverture du curseur :
Type | Nom | Paramètres | Description |
int | MySqlCursorOpen | Cette fonction ouvre un curseur pour la requête SELECT et renvoie un identifiant de curseur en cas de succès. Sinon, la fonction renvoie « -1 ». Pour connaître la cause de l'erreur, utilisez les variables MySQLErrorNumber et MySqlErrorDescription. | |
int pConnection | Identifiant de connexion à la base de données | ||
chaîne pQuery | Requête SQL (l'instruction SELECT) |
Obtention du nombre de lignes renvoyées par la requête :
Type | Nom | Paramètres | Description |
int | MySqlCursorRows | Cette fonction renvoie le nombre de lignes sélectionnées par la requête. | |
int pCursorID | L'identifiant du curseur renvoyé par MySqlCursorOpen |
Récupération de la ligne de requête :
Type | Nom | Paramètres | Description |
bool | MySqlCursorFetchRow | Récupère une ligne de l'ensemble de données renvoyé par la requête. Après une exécution réussie, vous pouvez récupérer les données dans les variables MQL. La fonction renvoie vrai en cas de succès, sinon elle renvoie faux. | |
int pCursorID | L'identifiant du curseur renvoyé par MySqlCursorOpen |
Récupérer des données dans des variables MQL après avoir récupéré la ligne de requête :
Type | Nom | Paramètres | Description |
int | MySqlGetFieldAsInt | Cette fonction renvoie la représentation de la valeur du champ de table à l'aide du type de données int. | |
int pCursorID | L'identifiant du curseur renvoyé par MySqlCursorOpen | ||
int pField | Le numéro de champ dans la liste SELECT (la numérotation commence par 0) | ||
double | MySqlGetFieldAsDouble | Cette fonction renvoie la représentation de la valeur du champ de table à l'aide du type de données double. | |
int pCursorID | L'identifiant du curseur renvoyé par MySqlCursorOpen | ||
int pField | Le numéro de champ dans la liste SELECT (la numérotation commence par 0) | ||
datetime | MySqlGetFieldAsDatetime | Cette fonction renvoie la représentation de la valeur du champ de table à l'aide du type de données datetime. | |
int pCursorID | L'identifiant du curseur renvoyé par MySqlCursorOpen | ||
int pField | Le numéro de champ dans la liste SELECT (la numérotation commence par 0) | ||
chaîne | MySqlGetFieldAsString | Cette fonction renvoie la représentation de la valeur du champ de table à l'aide du type de données chaîne. | |
int pCursorID | L'identifiant du curseur renvoyé par MySqlCursorOpen | ||
int pField | Le numéro de champ dans la liste SELECT (la numérotation commence par 0) |
Toutes les données renvoyées par MySQL ont une représentation native (présentées sans types sous forme de chaînes).
Par conséquent, en utilisant ces fonctions, vous pouvez convertir les données sélectionnées dans le type souhaité. Le seul inconvénient est la spécification du numéro de colonne (la numérotation commence à partir de 0) dans la liste SELECT au lieu de son nom. Cependant, lors du développement d'une application, la préparation de l'instruction SELECT et l'obtention des résultats se font presque toujours sur une seule page, vous pouvez donc voir la requête SELECT lorsque vous prescrivez la logique d'extraction des données.
Ainsi, vous connaissez toujours les numéros des champs de la liste SELECT (cette approche est également utilisée lors de l'accès aux données à l'aide d'AdoDB). Eh bien, cette partie peut encore être révisée à l'avenir. Mais cela aura peu d'impact sur la fonctionnalité de la solution développée.
Fermeture du curseur :
Type | Nom | Paramètres | Description |
vide | MySqlCursorClose | Cette fonction ferme le curseur spécifié et libère la mémoire. | |
int pCursorID | L'identifiant du curseur renvoyé par MySqlCursorOpen |
La fermeture d'un curseur est une opération critique. N'oubliez pas de fermer les curseurs.
Imaginez que vous ouvrez le curseur et oubliez de le fermer. Supposons que les données soient récupérées vers le curseur à chaque tick lors de la gestion de l'événement OnTick(), et chaque fois qu'un nouveau curseur est ouvert, de la mémoire lui est allouée (à la fois côté client et côté serveur). À un moment donné, le serveur refusera le service car la limite de curseurs ouverts est atteinte, ce qui pourrait provoquer un débordement de la mémoire tampon.
Bien sûr, c'est exagéré, un tel résultat est possible en travaillant directement avec libmysql.dll. Cependant, la bibliothèque dynamique MQLMySQL.DLL distribue de la mémoire pour les curseurs et refusera d'ouvrir un curseur qui dépasse la limite autorisée.
Lors de la mise en œuvre de tâches réelles, il suffit de garder 2-3 curseurs ouverts. Chaque curseur peut gérer une mesure cartésienne de données ; l'utilisation simultanée de deux-trois curseurs (imbriqués, par exemple, lorsqu'un curseur dépend paramétriquement d'un autre curseur) couvre deux ou trois dimensions. C'est parfaitement bien pour la plupart des tâches. De plus, pour la mise en œuvre de sélection de données complexes, vous pouvez toujours utiliser ces objets pour représenter la base de données (VIEW), les créer côté serveur et leur envoyer des requêtes depuis le code MQL comme vers des tables.
1.4. Information additionnelle
Les éléments suivants peuvent être mentionnés comme fonctionnalités supplémentaires :
1.4.1. Lecture de données à partir d'un fichier .INI
Type | Nom | Paramètres | Description |
Chaîne | ReadIni | Renvoie la valeur d'une clé de la section donnée du fichier INI. | |
chaîne pFileName | Le nom du fichier INI | ||
chaîne pSection | Le nom de la section | ||
chaîne pKey | Le nom de la clé |
Souvent stocker des informations sur les connexions à la base de données (adresse IP du serveur, port, nom d'utilisateur, mot de passe, etc.) directement dans le code MQL (ou paramètres de l'Expert Advisor, indicateur de script) n'est pas rationnel, car le serveur peut être déplacé, son adresse peut changer dynamiquement, etc. Vous devrez modifier le code MQL dans ce cas. Ainsi, toutes ces données devraient mieux être stockées dans le fichier .INI standard, alors que seul son nom devrait être écrit dans le programme MQL. Ensuite, utilisez la fonction ReadINI pour lire les paramètres de connexion et les utiliser.
Par exemple, le fichier INI contient les informations suivantes :
[MYSQL] Server = 127.0.0.1 User = root Password = Adm1n1str@t0r Database = mysql Port = 3306
Pour obtenir l'adresse IP du serveur, exécutez la commande suivante :
string vServer = ReadIni("C:\\MetaTrader5\\MQL5\\Experts\\MyConnection.ini", "MYSQL", "Server");
Le fichier INI se trouve dans C:\MetaTrader5\MQL5\Experts et s'appelle « MyConnection.ini », vous accédez à la clé Serveur de la section MYSQL. Dans un fichier INI, vous pouvez stocker les paramètres sur différents serveurs utilisés dans votre projet.
1.4.2. Traçage des zones à problèmes
Dans la bibliothèque, l’interface fournit le mode trace, qui peut être activé pour le débogage des requêtes SQL n'importe où dans un programme MQL.
Spécifiez les éléments suivants dans la zone à problème :
SQLTrace = true;
puis
SQLTrace = false;
Si vous activez le traçage au début du programme MQL et ne le désactivez pas, tous les appels à la base de données seront enregistrés. Le Journal est conservé dans la console du terminal (à l'aide de la commande Imprimer).
2. Exemples
Cette section fournit quelques exemples de connexion et d'utilisation des bibliothèques développées. Consultez-les et estimez l'utilisabilité de la solution logicielle.
L’exemple MySQL-003.mq5 montre ce qui suit : connexion à une base de données (les paramètres de connexion sont stockés dans le fichier .ini), création d'une table, insertion de données (également à l'aide d'instructions multiples) et déconnexion de la base de données.
//+------------------------------------------------------------------+ //| 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!"); }
L’exemple MySQL-004.mq5 montre une sélection de données à partir d'une table créée par le 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!"); }
Les exemples ci-dessus contiennent la gestion des erreurs typique utilisée dans les projets réels.
En fait, chaque requête utilisée dans un programme MQL doit être déboguée dans n'importe quel client MySQL (PHPMyAdmin, DB Ninja, console MySQL). Personnellement, j'utilise et recommande un logiciel professionnel pour le développement de bases de données Quest TOAD pour MySQL.
Conclusion
Cet article ne décrit pas les détails de l'implémentation de MQLMySQL.DLL développé dans l'environnement Microsoft Visual Studio 2010 (C/C++). Cette solution logicielle est conçue pour une utilisation pratique et compte plus de 100 implémentations réussies dans divers domaines du développement de logiciels MQL (de la création de systèmes de trading complexes à la publication Web).
- Les versions des bibliothèques pour MQL4 et MQL5 sont jointes ci-dessous. Les pièces jointes incluent également un fichier zip avec le code source de MQLMySQL.DLL ;
- La documentation est incluse dans les archives ;
- Pour utiliser les exemples, n'oubliez pas de préciser les paramètres de connexion à votre base de données dans le fichier \Scripts\MyConnection.ini.
Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/932
- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Vous acceptez la politique du site Web et les conditions d'utilisation