English Русский Deutsch 日本語 한국어 Italiano Türkçe
preview
Trading algorithmique sans tâches routinières : analyse rapide des opérations dans MetaTrader 5 avec SQLite

Trading algorithmique sans tâches routinières : analyse rapide des opérations dans MetaTrader 5 avec SQLite

MetaTrader 5Exemples |
26 1
MetaQuotes
MetaQuotes

Le problème du feedback dans le trading algorithmique

Le trading algorithmique exige non seulement le développement de stratégies compétitives, mais aussi un suivi constant des résultats. Sans retour d'information, un système de trading peut devenir incontrôlable. Tant que vous n'aurez pas observé le comportement d'une stratégie en temps réel, vous ne gérerez pas un système, mais un ensemble de suppositions.

Sur les marchés boursiers modernes et sur le Forex, la fréquence des transactions a augmenté de façon exponentielle. Les données deviennent obsolètes plus vite qu'on ne peut en tirer des conclusions. Et à mesure que les données deviennent obsolètes, les conclusions qui en découlent le sont également. En outre, les actions manuelles répétitives et routinières entraînent inévitablement des retards et des erreurs. Elles apparaissent simplement parce qu'une personne est fatiguée, distraite ou pressée.

C’est là que MetaTrader 5 prend toute sa valeur. La prise en charge intégrée de SQLite (une base de données locale) change tout. La base de données n'est plus seulement un espace de stockage externe, mais une partie intégrante du processus de trading. Les requêtes sont exécutées quasi instantanément, les statistiques sont mises à jour automatiquement et l'analyse des transactions ne prend que quelques secondes au lieu de plusieurs heures. Et les résultats de l'analyse sont disponibles exactement là où ils sont nécessaires : au sein même du processus de trading, et non pas en dehors du terminal.

L'article examine le « socle minimal opérationnel » d'un trader algorithmique : la structure d'une base de données de journal de trading, l'enregistrement sécurisé et rapide des données, les requêtes SQL d’analyse et l'affichage des statistiques clés sur un tableau de bord interactif dans MetaTrader 5. Cela permet d'éliminer la plupart des tâches routinières et laisse au trader la possibilité de se concentrer sur l'aspect créatif : l'analyse et l'amélioration du système de trading.


Pourquoi un trader algorithmique a-t-il besoin d'une base de données locale ?

Le développement et le test de stratégies de trading génèrent des quantités colossales de données. Résultats d'optimisation, historiques de transactions, signaux d'indicateurs, événements macroéconomiques — tout cela nécessite non seulement du stockage, mais aussi une structuration et un accès rapide. Une base de données locale résout ces problèmes auxquels tout trader algorithmique sérieux est confronté.

Sauvegarde des résultats des tests et de l'optimisation

L'optimisation d'une stratégie par l'énumération des paramètres génère des centaines, voire des milliers, de variations de paramètres. Chaque passe d’optimisation correspond à un ensemble de métriques, de valeurs de paramètres et de résultats. Comment pouvons-nous les comparer entre eux ? Comment suivre l'évolution d'une stratégie au fil du temps ? La base de données permet de stocker un historique complet des optimisations et de l'analyser dans n'importe quel contexte, des tableaux simples aux corrélations complexes.

Journal de trading automatique

Au lieu de tenir manuellement un journal dans un tableur, exécutez un EA dans le terminal et obtenez un enregistrement automatique de chaque transaction avec un ensemble complet d'attributs : symbole, numéro magique, volume, prix, heure, résultat et commentaire. Les données sont saisies dans la base de données en temps réel et deviennent instantanément disponibles pour l'analyse, sans aucune action supplémentaire de la part du trader.

Analyse des signaux de trading

L'enregistrement et l'analyse des signaux de trading offrent des opportunités inaccessibles avec les journaux classiques. Quelle est l'efficacité des signaux ? Quels indicateurs sont corrélés entre eux ? Dans quelles conditions les entrées et les sorties sont-elles optimales ? Tous les traders veulent connaître les réponses à ces questions. Les requêtes SQL constituent un outil d'analyse puissant sans qu'il soit nécessaire d'écrire de code supplémentaire.

Pour commencer avec SQLite, nous n'avons besoin que de trois fonctions :

  1. DatabaseOpen — pour ouvrir la base de données
  2. DatabaseExecute — pour exécuter une requête sur la base de données
  3. DatabaseClose — pour fermer la base de données

Cela suffit à résoudre 90% des problèmes rencontrés par un trader algorithmique.

Exemple d'ouverture et de fermeture d'une base de données :

int db = DatabaseOpen("trading.sqlite", DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE);
if(db == INVALID_HANDLE)
 {
  Print("Error opening Database: ", GetLastError());
  return;
 }
// ... working with the database ...
DatabaseClose(db);     // close the database

L'essentiel : SQLite est intégré nativement à MetaTrader 5 et fonctionne directement avec le noyau du terminal. Excel et autres tableurs sont des programmes externes auxquels un EA MQL5 accède soit par des méthodes obsolètes comme l'automatisation OLE, soit par un fichier CSV externe. La différence en faveur de SQLite dans MetaTrader 5 est colossale – en termes de vitesse, de commodité et de fiabilité.


Structure des tables : architecture du journal de trading

La conception d'une base de données commence par la question suivante : que faut-il stocker exactement ? Pour un journal de trading, la réponse est évidente : historique des transactions, signaux et événements. Mais pourquoi exactement trois tables, et pas une seule « grande et universelle » ? La distinction entre les tables DEALS, SIGNALS et EVENTS n'est pas un caprice, mais une nécessité. Chaque entité est stockée séparément et liée aux autres en cas de besoin dans une requête. Vous voulez savoir « toutes les transactions effectuées après un signal avec un niveau de confiance supérieur à 80% » ? SQLite gérera cela facilement et élégamment sans qu'il soit nécessaire de quitter le terminal de trading.

Table DEALS - l’historique de trading

La table contient des informations complètes sur chaque transaction : Identifiant, tickets, symbole, numéro « magique » (identifiant de stratégie), volume, prix d'ouverture et de clôture, heure, résultat financier et commentaire optionnel. C’est le squelette du journal de trading – la base de toute analyse.

Table SIGNALS - l’historique des signaux

La table stocke les signaux provenant des indicateurs et des systèmes de trading : symbole, unité de temps (« timeframe »), type de signal (achat/vente), prix, heure d’occurrence et paramètres supplémentaires. Elle permet également d'analyser la qualité des signaux et leur corrélation avec les transactions réelles — la clé pour comprendre si votre stratégie fonctionne.

Table EVENTS - le contexte des actualités

La table contient des informations sur les événements économiques importants : nom, devise, niveau d’importance, prévision, valeur réelle et date et heure de publication. Elle permet de trouver des liens entre les résultats des transactions et le contexte de l'actualité — après tout, le marché n'existe pas en vase clos.

La figure ci-dessous présente un diagramme ER (diagramme Entité-Relation) – une représentation visuelle de la structure de la base de données et des relations entre les tables :

Diagramme Entité-Relation

Fig. 1 : diagramme ER des tables du journal de trading

Code de création des tables :

   //  Deal history table - DEALS:
   string createDeals = "CREATE TABLE IF NOT EXISTS DEALS ("
                       "id INTEGER PRIMARY KEY AUTOINCREMENT, "
                       "deal_ticket INTEGER UNIQUE, "
                       "order_ticket INTEGER, "
                       "symbol TEXT NOT NULL, "
                       "type INTEGER, "                // 0=BUY, 1=SELL
                       "direction INTEGER, "           // 0=IN, 1=OUT, 2=IN/OUT
                       "volume REAL, "
                       "price_open REAL, "
                       "price_close REAL, "
                       "profit REAL, "
                       "swap REAL, "
                       "commission REAL, "
                       "sl REAL, "
                       "tp REAL, "
                       "magic INTEGER, "
                       "comment TEXT, "
                       "time INTEGER, "                // Unix timestamp
                       "time_msc INTEGER, "
                       "reason INTEGER"
                       ");";
   
   //  Trading signals table - SIGNALS:
   string createSignals = "CREATE TABLE IF NOT EXISTS SIGNALS ("
                         "id INTEGER PRIMARY KEY AUTOINCREMENT, "
                         "symbol TEXT NOT NULL, "
                         "signal_type TEXT, "          // 'BUY', 'SELL', 'CLOSE'
                         "price REAL, "
                         "stop_loss REAL, "
                         "take_profit REAL, "
                         "strength REAL, "             // 0.0 - 1.0
                         "source TEXT, "               // Strategy name
                         "notes TEXT, "
                         "time INTEGER"
                         ");";
   
   //  Events table - EVENTS:
   string createEvents = "CREATE TABLE IF NOT EXISTS EVENTS ("
                        "id INTEGER PRIMARY KEY AUTOINCREMENT, "
                        "event_type TEXT, "            // 'NEWS', 'ERROR', 'NOTE', etc.
                        "symbol TEXT, "
                        "description TEXT, "
                        "importance INTEGER, "         // 1=Low, 2=Medium, 3=High
                        "time INTEGER,"
                        "actual REAL, "
                        "previous REAL, "
                        "forecast REAL "
                        ");";
   
   //  Indices to speed up search queries:
   string createIndexes[] = 
    {
      "CREATE INDEX IF NOT EXISTS idx_deals_symbol ON DEALS(symbol);",
      "CREATE INDEX IF NOT EXISTS idx_deals_magic ON DEALS(magic);",
      "CREATE INDEX IF NOT EXISTS idx_deals_time ON DEALS(time);",
      "CREATE INDEX IF NOT EXISTS idx_signals_symbol ON SIGNALS(symbol);",
      "CREATE INDEX IF NOT EXISTS idx_signals_time ON SIGNALS(time);"
    };
   
   //  Create tables in the database:
   if(!DatabaseExecute(database, createDeals))
    {
      Print("Error creating DEALS table: ", GetLastError());
      return(false);
    }
   
   if(!DatabaseExecute(database, createSignals))
    {
      Print("Error creating SIGNALS table: ", GetLastError());
      return(false);
    }
   
   if(!DatabaseExecute(database, createEvents))
    {
      Print("Error creating EVENTS table: ", GetLastError());
      return(false);
    }
   
   //  Create indices:
   for(int i = 0; i < ArraySize(createIndexes); i++)
    {
      DatabaseExecute(database, createIndexes[i]);
    }

Faites attention aux index : idx_deals_symbol, idx_deals_magic, idx_deals_time, idx_signals_symbol et idx_signals_time. Ils accélèrent les requêtes sur les champs clés : symbol, magic, time dans la table DEALS et symbol, time dans SIGNALS. Les index sont un levier de performance qui porte ses fruits à chaque requête d’analyse.


Insertion de données et transactions : La vitesse compte

MQL5 offre deux méthodes pour insérer des données dans les tables : l’exécution directe d’une requête SQL et l’utilisation d’instructions préparées. Laquelle choisir ? La réponse est claire : les instructions préparées sont préférables tant du point de vue de la sécurité que de celui des performances.

Insertion directe via DatabaseExecute :

string sql = StringFormat(
                         "INSERT INTO DEALS (ticket, symbol, magic, volume, price, time, profit) "
                         "VALUES (%d, '%s', %d, %.2f, %.5f, %I64d, %.2f)",
                         ticket, symbol, magic, volume, price, TimeCurrent(), profit);
DatabaseExecute(db, sql);

Requête paramétrée via DatabasePrepare :

//  Create a parameterized query:
int request = DatabasePrepare(db,
                             "INSERT INTO DEALS (ticket, symbol, magic, volume, price, time, profit) "
                             "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)");

//  Set the value of the first query parameter - in the DatabaseBind function, the indexing of fields in the entry starts from zero:
DatabaseBind(request, 0, ticket);
DatabaseTransactionBegin(db);

//  Set the values of the remaining parameters before adding the entry:
DatabaseBind(request, 1, symbol);
DatabaseBind(request, 2, magic);
DatabaseBind(request, 3, volume);
DatabaseBind(request, 4, price);
DatabaseBind(request, 5, TimeCurrent());
DatabaseBind(request, 6, profit);

//  Execute a request for inserting the entry:
DatabaseRead(request);
DatabaseFinalize(request);
DatabaseTransactionCommit(db);

L'utilisation des transactions n'est pas une option, mais une nécessité. Pour les opérations d'insertion et de mise à jour en masse, les transactions accélèrent les performances de centaines, voire de milliers de fois. Pourquoi ? Sans transaction, chaque opération est enregistrée sur le disque séparément. Dans une transaction, toutes les opérations sont regroupées et enregistrées dans un seul bloc.

Nos résultats de test sont impressionnants : Les performances de SQLite dans MQL5 sont comparables à celles du code C++ natif (LLVM 9.0). Dans la plupart des tests, la différence est inférieure à 5%, et dans certains scénarios, MQL5 surpasse même C++. Le diagramme ci-dessous compare le temps d'insertion de 1.000 enregistrements sans transactions à celui de 25.000 enregistrements avec transactions - une différence de plus de 3.500 fois par enregistrement !

Comparaison des transactions

Fig. 2 : comparaison de la vitesse d'insertion : sans/avec transactions

Exemple d'utilisation d'une transaction pour l'insertion en masse :

DatabaseTransactionBegin(db);
for(int i = 0; i < ArraySize(deals); i++)
 {
  InsertDeal(db, deals[i]);  // inserting the next trade - an element of the array of deals[] structures
 }
DatabaseTransactionCommit(db);

Tous les tests peuvent être étudiés (et vérifiés !) dans la section du forum MQL5 : SQLite dans MQL5 : nouvelles fonctionnalités et tests de performance.


Requêtes SQL : Des analyses sans programmation

L'un des principaux avantages de SQL est sa capacité à obtenir des analyses complexes avec une seule requête. Dans MetaTrader 5, cette fonctionnalité est directement accessible. Pas de boucles, pas de conditions, pas de variables temporelles. Une seule requête suffit. Examinons quelques scénarios typiques.

Statistiques sur les symboles de trading

Quels instruments génèrent des profits, et lesquels grignotent silencieusement votre dépôt ? Cette question, et la requête SQL qui l'accompagne, devraient être les premières dans l'arsenal de tout trader. Cette requête affiche, pour chaque symbole, un résumé : nombre de transactions, profit total et résultat moyen.

string sql = "SELECT symbol, COUNT(*) as deals, "
             "SUM(profit) as total_profit, "
             "AVG(profit) as avg_profit "
             "FROM DEALS GROUP BY symbol "
             "ORDER BY total_profit DESC";
DatabasePrint(db, sql);

Analyse des éléments de la requête :

Élément de la requête Description
SELECT symbol Sélectionne la colonne avec un nom de symbole
COUNT(*) Compte le nombre de transactions pour un symbole
SUM(profit) Additionne les bénéfices de toutes les transactions sur les symboles.
GROUP BY symbol Regroupe les résultats par symbole
ORDER BY total_profit DESC Trie par bénéfice total décroissant

Analyse par stratégies (nombres magiques)

Le numéro magique est un identifiant unique de l’EA ajouté à chaque transaction. Si plusieurs stratégies sont utilisées sur un même compte, cette requête permettra de déterminer laquelle est la plus efficace. Sa particularité réside dans l'utilisation d'une expression CASE conditionnelle pour calculer les transactions rentables.

string sql = "SELECT magic, COUNT(*) as trades, "
             "SUM(CASE WHEN profit > 0 THEN 1 ELSE 0 END) as wins, "
             "SUM(profit) as net_profit "
             "FROM DEALS GROUP BY magic";
DatabasePrint(db, sql);

Analyse des éléments de la requête :

Élément de la requête Description
SELECT magic Sélectionne la colonne contenant le nombre magique
COUNT(*) Nombre total de transactions pour la stratégie sélectionnée
CASE WHEN profit > 0 Condition : si le profit est positif
THEN 1 ELSE 0 END Retourne 1 pour les transactions gagnantes et 0 pour les transactions perdantes.
SUM(wins) Additionne les unités pour obtenir le nombre de transactions rentables (gains).

En divisant le nombre de transactions rentables (gains) par le nombre total (transactions), nous obtenons le pourcentage de transactions rentables — une mesure clé pour évaluer la qualité de la stratégie. Avez-vous obtenu un pourcentage élevé avec un bénéfice total négatif ? C’est le signe d’un problème de gestion des risques : les pertes sont plus importantes que les gains.

Répartition du trading par heure

Dans quelles conditions cette stratégie est-elle la plus efficace ? Pendant la session européenne ? Ou américaine ? Ou peut-être pendant les « heures de calme » ? La fonction strftime extrait l'heure d'ouverture de la transaction (format 00--23), ce qui nous permet d'identifier les intervalles de temps les plus et les moins rentables.

string sql = "SELECT strftime('%H', time, 'unixepoch') as hour, "
             "COUNT(*) as trades, SUM(profit) as profit "
             "FROM DEALS GROUP BY hour";
DatabasePrint(db, sql);

Important : dans MQL5 et SQLite, l’heure est stockée sous forme d’horodatage Unix (secondes depuis le 1er janvier 1970). Par conséquent, le modificateur « unixepoch » a été ajouté. De la même façon, nous pouvons analyser la distribution par jour de la semaine avec strftime('%w', ...), par mois avec strftime('%m', ...) ou faire des combinaisons.

Analyse des éléments de la requête :

Élément de la requête Description
strftime('%H', ...) Extrait l'heure d'ouverture de la transaction (00-23)
time Colonne indiquant l'heure d'ouverture de la transaction
GROUP BY hour Regroupe les transactions par heure d'ouverture


Tableau de bord des statistiques : visualisation au sein du terminal

Les chiffres sont utiles, mais une visualisation claire l’est encore davantage. La base de données s'intègre facilement aux tableaux de bord graphiques du terminal, transformant les données en informations visuelles compréhensibles. Le tableau de bord interactif des statistiques fonctionne en temps réel et affiche précisément ce dont le trader a besoin.

Le tableau de bord ci-dessous affiche le résultat total pour un nombre de jours donné (SUMMARY), le résultat ventilé par instrument (BY SYMBOL) et les meilleures heures de trading (BEST HOURS). Pour lire des données dans une structure, utilisez la fonction DatabaseReadBind :

Panel statistique

Fig. 3 : tableau de bord statistique interactif dans le terminal

struct DealStats
 {
  string symbol;
  int count;
  double total_profit;
  double avg_profit;
 };

int request = DatabasePrepare(db,
                             "SELECT symbol, COUNT(*) as count, SUM(profit) as total_profit, "
                             "AVG(profit) as avg_profit FROM DEALS GROUP BY symbol");
DealStats stats;
while(DatabaseReadBind(request, stats))
 {
  //  Output to the table on the dashboard:
  AddRowToTable(stats);
 }
DatabaseFinalize(request);

La fonction DatabaseReadBind fait automatiquement correspondre les champs de structure aux colonnes de la requête par leur nom. Il suffit de déclarer une structure avec des champs correspondant aux noms de colonnes de la requête SQL.

Gestion du tableau de bord

Le bouton [Refresh] met à jour les statistiques avec un recalcul complet. Le bouton [Export] enregistre les données calculées à partir des tables de la base de données vers des fichiers CSV : le résultat global, les transactions, les événements et les signaux. Exemple d'export :

(#),symbol,trades,total_profit,avg_profit,wins,losses
1,XAGUSD,196,322.25,1.64,14,181
2,AUDUSD,196,-12.0,-0.06,82,99
3,EURUSD,58,-38.5,-0.66,23,35
4,GBPUSD,57,-43.2,-0.75,17,40

Touches de raccourci pour un contrôle rapide :

  • ’A’ ou ’a’ — mise à jour des analyses,
  • ’E’ ou ’e’ — export des données vers un fichier CSV,
  • ’R’ ou ’r’ — chargement de l’historique de trading,
  • ’P’ ou ’p’ — activation/désactivation de l'affichage du tableau de bord.

Paramètres de l’EA :

  • Database file name — nom du fichier de base de données (par défaut : "TradingJournal.db"),
  • Auto-import trade history — chargement automatique de l'historique (par défaut : activé),
  • History depth in days — profondeur de l'historique (par défaut : 30 jours),
  • Export path — chemin vers les fichiers CSV (par défaut : "MQL5/Files"),
  • Export to CSV format — export au format CSV (par défaut : true),
  • Show statistics dashboard on chart — affichage du tableau de bord (par défaut : true).


MetaEditor : un outil de base de données

MetaEditor, inclus dans MetaTrader 5, possède un outil intégré pour travailler avec SQLite : ouverture et modification des tables, exécution de requêtes SQL et annulation des modifications. Étant donné que la base de données SQLite est stockée dans un seul fichier sur l'ordinateur de l'utilisateur, elle peut être consultée à tout moment via le navigateur MetaEditor — pour examiner la structure et le contenu des tables et pour exécuter des requêtes de débogage.

C’est particulièrement pratique lors du débogage d'applications MQL5 qui fonctionnent avec une base de données. Vous pouvez voir en temps réel quelles données sont affichées et ajuster la logique de l’EA.

Voyons comment cela peut être réalisé facilement en utilisant une base de données d'exemple créée par l'EA de test TradingJournalSQLite-EA de cet article. Ouvrons la base de données et les tables qu'elle contient, exécutons plusieurs requêtes SQL et fermons-la. Je pourrais l’expliquer longuement, mais mieux vaut le voir une fois…

1. Commencez par la chose la plus simple : ouvrez la base de données et sélectionnez la table souhaitée :

    Ouvrir/Sélectionner/Fermer

    Fig. 4 :  Ouvrir/Sélectionner la table/Fermer

    La table DEALS est sélectionnée en double-cliquant sur son nom avec le bouton gauche de la souris. Cela équivaut à exécuter une requête SQL dans le navigateur :

    SELECT * FROM 'DEALS';
    2. Définissez le format de l'heure :

      Format de l'heure

      Fig. 5 : format de l'heure

      3. La question principale : qui gagne combien ? Trouvez la réponse en quelques millisecondes :
        SELECT symbol, COUNT(*) as count, SUM(profit) as total_profit, AVG(profit) as avg_profit FROM DEALS GROUP BY symbol;

        Pour ceux qui n'aiment pas les longues lignes :

        SELECT symbol,
        COUNT(*) as count,
        SUM(profit) as total_profit,
        AVG(profit) as avg_profit FROM DEALS GROUP BY symbol;
        

        PnL

        Fig. 6 : qui gagne combien ?

        4. Tri par profits décroissants :
          SELECT symbol, COUNT(*) as count, SUM(profit) as total_profit, AVG(profit) as avg_profit FROM DEALS GROUP BY symbol
          ORDER BY total_profit DESC;
          

          PnL trié

          Fig. 7 : par ordre décroissant de gains


          5. Quel est le bénéfice total ? Découvrons-le :
            SELECT  SUM(CASE WHEN direction IN (1, 2, 3) THEN profit ELSE 0 END) as net_profit FROM DEALS;

            NetPnL

            Fig. 8 : total

            Souhaitez-vous déboguer une requête complexe ? Aucun problème :

            SELECT   COUNT(*) as total_deals, 
                            SUM(CASE WHEN direction IN (1, 2, 3) THEN 1 ELSE 0 END) as closed_trades, 
                            SUM(CASE WHEN (profit + swap + commission) > 0 AND direction IN (1, 2, 3) THEN 1 ELSE 0 END) as total_wins, 
                            SUM(CASE WHEN (profit + swap + commission) < 0 AND direction IN (1, 2, 3) THEN 1 ELSE 0 END) as total_losses, 
                            ROUND(100.0 * SUM(CASE WHEN (profit + swap + commission) > 0 AND direction IN (1, 2, 3) THEN 1 ELSE 0 END) / 
                            NULLIF(SUM(CASE WHEN direction IN (1, 2, 3) THEN 1 ELSE 0 END), 0), 2) as overall_win_rate, 
                            SUM(CASE WHEN direction IN (1, 2, 3) THEN profit ELSE 0 END) as net_profit, 
                            SUM(CASE WHEN direction IN (1, 2, 3) THEN swap ELSE 0 END) as total_swap,
                            SUM(CASE WHEN direction IN (1, 2, 3) THEN commission ELSE 0 END) as total_commission, 
                            SUM(CASE WHEN direction IN (1, 2, 3) THEN profit + swap + commission ELSE 0 END) as net_result, 
                            ROUND(AVG(CASE WHEN direction IN (1, 2, 3) THEN profit + swap + commission ELSE NULL END), 2) as avg_profit_per_trade, 
                            SUM(CASE WHEN (profit + swap + commission) > 0 AND direction IN (1, 2, 3) THEN (profit + swap + commission) ELSE 0 END) as gross_profit, 
                            SUM(CASE WHEN (profit + swap + commission) < 0 AND direction IN (1, 2, 3) THEN ABS(profit + swap + commission) ELSE 0 END) as gross_loss, 
                            CASE WHEN SUM(CASE WHEN (profit + swap + commission) < 0 AND direction IN (1, 2, 3) THEN ABS(profit + swap + commission) ELSE 0 END) > 0 
                            THEN ROUND(SUM(CASE WHEN (profit + swap + commission) > 0 AND direction IN (1, 2, 3) THEN (profit + swap + commission) ELSE 0 END) / 
                            SUM(CASE WHEN (profit + swap + commission) < 0 AND direction IN (1, 2, 3) THEN ABS(profit + swap + commission) ELSE 0 END), 2) 
                            ELSE 0 END as profit_factor, 
                            COUNT(DISTINCT symbol) as symbols_traded, 
                            COUNT(DISTINCT magic) as strategies_used 
                            FROM DEALS;
            

            Requête complexe

            Fig. 9 : requête SQL complexe

            La requête SQL est reprise de l'EA de test TradingJournalSQLite-EA joint à l'article, sans modification.


            Conclusion : Un système de trading et d'analyse intégré à MetaTrader 5

            Le journal de trading n'est plus un fichier statique qu'il faut exporter, ouvrir dans un programme tiers et convertir manuellement dans un format approprié. Dans MetaTrader 5, il est devenu partie intégrante du système de trading et d'analyse — précis, fiable et réactif aux changements en temps réel. Cela se fait nativement SQLite est intégré au terminal MetaTrader 5 au niveau du noyau.

            Cela nous permet d'utiliser MetaTrader 5 comme un système de trading et d'analyse autonome et d'exploiter toute la puissance des requêtes SQL avec la possibilité d'extension et de modification pour s'adapter à de nouvelles idées. Cela offre aux traders les avantages suivants :

              • Les données sont enregistrées automatiquement et sont disponibles pour analyse immédiatement après leur apparition ;
              • Les requêtes SQL d’analyse peuvent être modifiées rapidement et de manière flexible, sans complexifier le code de l’EA ;
              • Le tableau de bord d’analyse est disponible directement sur le graphique dans le terminal, où les transactions ont lieu ;
              • Le système peut être facilement étendu pour intégrer de nouvelles idées, de nouvelles mesures et de nouvelles perspectives analytiques sans avoir recours à des applications tierces.

              C’est pourquoi la prise en charge intégrée de SQLite dans MetaTrader 5 est bien plus qu’une simple solution de stockage de données pratique : c’est une base solide pour une infrastructure de trading et d’analyse complète, où le trading et l’analyse fonctionnent dans un seul environnement, utilisant un seul langage et une prise en charge native de SQL.


              Ressources recommandées pour une étude approfondie de SQLite en MQL5 :

              Liste des fichiers joints à l'article :

              Nom de fichier Description
              TradingJournalSQLite-EA.mq5 Le fichier contenant le code d'un EA de test qui crée un tableau de bord avec des statistiques de trading

              Traduit du russe par MetaQuotes Ltd.
              Article original : https://www.mql5.com/ru/articles/22009

              Derniers commentaires | Aller à la discussion (1)
              Gerard William G J B M Dinh Sy
              Gerard William G J B M Dinh Sy | 5 mai 2026 à 12:35
              Merci
              Comment Échanger des Données : Une DLL pour MQL5 en 10 minutes Comment Échanger des Données : Une DLL pour MQL5 en 10 minutes
              Maintenant, peu de développeurs se rappellent de la façon d'écrire une DLL simple et des caractéristiques spéciales des différentes liaisons système. À l'aide de plusieurs exemples, je vais tenter de montrer l'ensemble du processus de création de la DLL simple en 10 minutes, ainsi que de discuter de certains détails techniques de notre implémentation de liaison. Je vais montrer étape par étape le processus de la création de DLL dans Visual Studio avec des exemples d'échange de différents types de variables (nombres, tableaux, chaînes, etc.). En outre, je vais vous expliquer comment protéger votre terminal client des plantages dans les DLL personnalisées.
              Python + MetaTrader 5 : Сadre de recherche rapide pour les données, les variables et les prototypes Python + MetaTrader 5 : Сadre de recherche rapide pour les données, les variables et les prototypes
              Cet article démontre comment l'intégration de Python et de MetaTrader 5 combine la flexibilité de la recherche et l'exécution des transactions dans un même flux de travail. Python est utilisé pour l'analyse des données, la sélection des variables et l'entraînement des modèles, et MetaTrader 5 est utilisé pour les tests et l’automatisation du trading. Cette approche simplifie la mise en pratique des solutions, accroît la reproductibilité et rend le développement des systèmes de trading plus rapide et plus structuré.
              L'Histogramme des prix (Profile du Marché) et son implémentation  en MQL5 L'Histogramme des prix (Profile du Marché) et son implémentation en MQL5
              Le Profile du Marché a été élaboré par le brillant penseur Peter Steidlmayer. Il a suggéré l’utilisation de la représentation alternative de l'information sur les mouvements de marché « horizontaux » et « verticaux » qui conduit à un ensemble de modèles complètement différent. Il a assumé qu'il existe une impulsion sous-jacente du marché ou un modèle fondamental appelé cycle d'équilibre et de déséquilibre. Dans cet article, j’examinerai l'Histogramme des Prix - un modèle simplifié de profil de marché, et décrirai son implémentation dans MQL5.
              Comment nous avons construit la plateforme de trading la plus puissante propulsée par le machine learning : l'évolution de MQL et de MetaTrader à travers les archives, les forums et les versions Comment nous avons construit la plateforme de trading la plus puissante propulsée par le machine learning : l'évolution de MQL et de MetaTrader à travers les archives, les forums et les versions
              Historique technique de l'évolution de MQL : des langages limités MQL et MQL II, en passant par le langage procédural MQL4, jusqu'au langage orienté objet MQL5 avec compilation native, des API riches et un environnement d'ingénierie complet. Nous présentons ici les principales fonctionnalités du langage et ses intégrations avec Python, OpenCL, ONNX, OpenBLAS, les bases de données, DirectX, l'Assistant IA agentique et le Model Context Protocol (MCP), qui connecte les systèmes d'IA au terminal, à MetaEditor, aux données de marché, aux opérations de trading et aux outils de développement. Cet article examine des documents d'archives sur les origines de MetaQuotes et de MetaTrader, le lancement de MQL4.COM et MQL5.COM, les championnats, Algo Forge et leur impact sur l'écosystème.