CopySpreadTest de Stratégies de Trading

L'idée du trading automatisé est séduisante par le fait que le robot de trading peut fonctionner non-stop 24 heures sur 24, 7 jours sur 7. Le robot ne connait pas la fatigue, le doute, la peur ; il est totalement exempt de tout problème psychologique. Il est nécessaire de formaliser clairement les règles de trading et de les mettre en œuvre dans les algorithmes ; le robot est alors prêt à travailler sans relâche. Mais d'abord, vous devez vous assurer que les deux conditions suivantes sont remplies :

  • L'Expert Advisor effectue des opérations de trading en conformité avec les règles du système de trading ;
  • La stratégie de trading mise en œuvre dans l'EA montre un profit dans l'historique.

Pour obtenir des réponses à ces questions, nous nous tournons vers le Strategy Tester, inclus dans le terminal client MetaTrader 5.

Cette section traite des caractéristiques de tests et d'optimisation du programme dans le Strategy Tester :

 

Limites de mémoire et d'espace disque dans le MQL5 Cloud Network

La limitation suivante s'applique aux optimisations exécutées dans le MQL5 Cloud Network : l'Expert Advisor ne doit pas écrire sur le disque plus de 4 Go d'informations ou utiliser plus de 4 Go de RAM . Si la limite est dépassée, l'agent du réseau ne pourra pas effectuer le calcul correctement et vous ne recevrez pas le résultat. Vous serez cependant facturé pour tout le temps passé sur les calculs.

Si vous avez besoin d'obtenir des informations à chaque passe d'optimisation, envoyez des images sans écrire sur le disque. Pour éviter d'utiliser les opérations sur les fichiers dans les Expert Advisors lors des calculs dans le MQL5 Cloud Network, vous pouvez utiliser la vérification suivante :

   int handle=INVALID_HANDLE;
   bool file_operations_allowed=true;
   if(MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_FORWARD))
      file_operations_allowed=false;
 
   if(file_operations_allowed)
     {
      ...
      handle=FileOpen(...);
      ...
     }

 

Limitations des Fonctions dans le Strategy Tester #

Il y a des limites de fonctionnement pour certaines fonctions dans le Strategy Tester du terminal client.

Les Fonctions Comment(), Print() et PrintFormat() #

Pour augmenter les performances, les fonctions Comment(), Print() et PrintFormat() ne sont pas exécutées lors de l'optimisation des paramètres du robot de trading. Une exception est l'utilisation de ces fonctions à l'intérieur du gestionnaire OnInit(). Cela vous permet de trouver facilement la cause des erreurs quand elles se produisent.

Les fonctions Alert(), MessageBox(), PlaySound(), SendFTP, SendMail(), SendNotification(), WebRequest() #

Les fonctions Alert(), MessageBox(), PlaySound(), SendFTP(), SendMail(), SendNotification() et WebRequest() conçus pour interagir avec "le monde extérieur" ne sont pas exécutées dans le Strategy Tester.

 

Les modes de génération des ticks #

Un Expert Advisor est un programme écrit en MQL5 qui est exécuté à chaque fois en réponse à un évènement extérieur. L'EA a une fonction correspondant à chaque événement prédéfini - ce sont les gestionnaires d'évènements.  

L'événement NewTick (changement de prix) est l'événement principal de l'EA et, par conséquent, nous avons besoin de générer une séquence de ticks pour tester l'EA. 3 modes de génération de ticks existent dans le Strategy Tester du terminal client MetaTrader 5 :

  • Tous les ticks
  • 1 Minute OHLC (les prix OKLC en barre 1 minute)
  • Prix d'ouverture uniquement

Le mode de base de génération et le plus détaillé est le mode "Tous les ticks", les deux autres modes sont une simplification du mode de base et seront comparés avec le mode "Tous les ticks". Considérons les trois modes afin de comprendre leurs différences.

Tous les ticks

L'historique des cotations des instruments financiers est transmis du serveur de trading au terminal client MetaTrader 5 sous forme de barres 1 minute. Des informations détaillées sur l'apparition de demandes et sur la construction des cadres de temps requis sont disponibles dans le chapitre Organisation de l'Accès aux Données de la référence MQL5.

L'élément minimal de l'historique des prix est la barre en minute, à partir de laquelle vous pouvez obtenir des informations sur les quatre valeurs du prix :

  • Open - le prix d'ouverture de la barre 1 minute ;
  • High - le prix maximum atteint au cours de cette barre 1 minute ;
  • Low - le prix minimum atteint au cours de cette barre 1 minute ;
  • Close - le prix de fermeture de la barre.

La nouvelle barre 1 minute n'est pas ouverte au moment où une nouvelle minute commence (le nombre de secondes devient égal à 0), mais lorsqu'un tick se produit - un changement de prix d'au moins un point La figure montre la première barre 1 minute de la nouvelle semaine de trading, avec une heure d'ouverture le 10/01/2011 à 00:00. L'écart de prix entre le vendredi et le lundi, que nous voyons sur le graphique, est commun, puisque les taux de change fluctuent, même le week-end, en réponse aux nouvelles informations.

new_bar_of_week

Pour cette barre, nous savons seulement que la barre 1 minute a été ouverte le 10 janvier 2011 à 00 heures 00 minutes, mais on ne sait rien sur les secondes. Elle aurait pu être ouverte à 00:00:12 ou 00:00:36 (12 ou 36 secondes après le début d'un nouveau jour) ou à tout autre moment pendant cette minute. Mais nous savons que le prix d'ouverture de l'EURUSD était à 1,28940 au moment de l'ouverture de la nouvelle barre 1 minute.

De la même manière, nous ne savons pas (à la seconde près) quand le tick correspondant au prix de la clôture de la barre 1 minute examinée a été reçu. Nous ne savons qu'une chose - le dernier prix de Clôture de la barre 1 minute. Pour cette minute, le prix était de 1,28958. Les moments d'apparition des prix High et Low sont également inconnus, mais on sait que les prix maximum et minimum étaient respectivement sur les niveaux 1,28958 et 1,28940.

Pour tester la stratégie de trading, nous avons besoin d'une séquence de ticks sur laquelle le travail de l'Expert Advisor sera simulé. Ainsi, pour chaque barre 1 minute, nous connaissons les 4 points de contrôle où le prix a été de façon sûre. Si une barre ne dispose que de 4 ticks, nous avons alos suffisamment d'informations pour effectuer un test, mais en général le volume des ticks est supérieur à 4. Par conséquent, il est nécessaire de générer des points de contrôle supplémentaires pour les ticks qui ont eu lieu entre les prix Open, High, Low et Close. Le principe de la génération des ticks en mode "Tous les ticks" est décrit dans l'article Algorithme de génération des ticks dans le Strategy Tester du Terminal MetaTrader 5, dont la figure est présentés plus bas.

ideal_white_MQL5_2

Lors du test en mode "Tous les ticks", la fonction OnTick() de l'expert sera appelée à chaque point de contrôle. Chaque point de contrôle correspond à un tick de la séquence générée. L'expert recevra l'heure et le prix du tick modélisé de la meme façon qu'il le recevrait en temps réel.

Important : le mode de test "Tous les ticks" est le plus précis, mais il prend beaucoup plus de temps. Pour un test initial de la plupart des stratégies de trading, il suffit d'utiliser l'un de deux autres modes de test.

1 minute OHLC

Le mode "Tous les ticks" est le plus précis des trois modes, mais c'est aussi le plus lent. Le lancement du gestionnaire OnTick() se produit à chaque tick, tandis que le volume des ticks peut être assez important. Pour les stratégies pour lesquelles la séquence des mouvements des prix dans la barre n'est pas importante, il existe un mode de simulation plus rapide et moins fin - "1 minute OHLC".

En mode "1 minute OHLC", la succession des ticks est construite seulement selon les prix OHLC des barres 1 minute, le nombre de points de contrôle générés diminue beaucoup - donc, diminue le temps du test. L'appel à la fonction OnTick() est effectué sur tous les points de contrôle, qui sont construits aux prix OHLC des barres 1 minute.

Le refus de génération des ticks supplémentaires intermédiaires entre les prix Open, High, Low et Close amène à l'apparition d'une détermination rigide du développement des prix à partir du moment où le prix Open est déterminé. Cela permet de créer un "Test du Graal", montrant un beau graphique haussier de la balance du test. L'exemple d'un tel Graal est présenté dans le Code Base - Grr-al.

graal_OHLC

La figure montre un graphique très attractif pour le test de cet EA. Comment a t'il été obtenu ? Nous connaissons 4 prix pour une barre 1 minute et nous savons aussi que le premier est le prix d'Ouverture, et le dernier est le prix de Clôture. Entre eux, il y a les prix High et Low, et la séquence de leur apparition est inconnue, mais on sait que le prix High est supérieur ou égal au prix Open (le prix Low est inférieur ou égal au prix Open).

Il suffit de définir le moment d'entrée du prix Open et d'analyser le tick suivant pour déterminer quel prix nous avons en ce moment - soit High ou Low. Si le prix est inférieur au prix Open, alors nous avons un prix Low - achetons sur ce tick, le tick suivant correspondra au prix High, sur lequel nous fermons à l'achat et nous ouvrons à la vente. Le tick suivant est le dernier, c'est le prix Close, nous y fermons la vente.

Si, après le prix, nous recevons un tick avec un prix supérieur au prix d'ouverture, la séquence des transactions est inversée . Traitons une barre 1 minute dans ce mode et attendons la suivante. Lors du test de cet EA sur l'historique, tout se passe bien, mais une fois que nous l'éxécutons en ligne, la situation change de façon spectaculaire - la ligne d'équilibre reste stable, mais tend à descendre. Pour révéler cette astuce, il suffit de lancer cet EA en mode "Tous les ticks".

Remarque : si les résultats du test de l'EA dans les modes de tests bruts ("1 minute OHLC" et "Prix d'Ouverture uniquement") semblent trop bon, assurez-vous de le tester en mode "Tous les ticks".

Prix d'ouverture uniquement

Dans ce mode, les ticks sont générés sur la base des prix OHLC de la période sélectionnée pour les tests. La fonction OnTick() de l'Expert Advisor fonctionne uniquement au début de la barre au prix d'Ouverture. Grâce à cette caractéristique, les niveaux stops et les ordres en attente peuvent se déclencher à un prix différent de celui spécifié (en particulier lors du test sur des périodes plus élevées). Au lieu de cela, nous avons la possibilité d'exécuter rapidement un test d'évaluation de l'Expert Advisor.

Les périodes W1 et MN1 sont des exceptions dans le mode de génération "Prix d'Ouverture Uniquement" : pour ces périodes, les ticks sont générés pour les prix OHLC de chaque jour, et non pas les prix OHLC de la semaine ou du mois.

Supposons que nous testons un Expert Advisor sur EURUSD H1 en mode "Prix d'Ouverture Uniquement". Dans ce cas, le nombre total de ticks (points de contrôle) ne sera pas supérieur à 4*le nombre de barres d'une heure dans l'intervalle testé. Mais le gestionnaire OnTick() est appelé uniquement à l'ouverture de la barred'une heure . Les contrôles requis pour un test correct se produisent sur le reste des ticks (qui sont "cachés" pour l'EA) :

  • le calcul des exigences de marge ;
  • le déclenchement des Stop Loss et Take Profit ;
  • le déclenchement des ordres en cours ;
  • la suppression des ordres en attente et expirés.

S'il n'y a pas de position ouverte ou d'ordre en cours, on n'a pas besoin d'effectuer ces contrôles sur les ticks, ce qui augmente considérablement la vitesse. Ce mode "Prix d'Ouverture uniquement" est bien adapté pour le test de stratégies qui n'effectuent des transactions qu'à l'ouverture d'une barre et qui n'utilisent pas d'ordres en attente, d'ordres StopLoss et TakeProfit. Pour de telles stratégies, la précision nécessaire des tests est préservée.

Utilisons l'EA Moving Average du package standard comme exemple d'un EA pouvant être testé dans tous les modes. La logique de cet EA est que toutes les décisions sont prises à l'ouverture de la barre, et les transactions sont effectuées immédiatement, sans utilisation des ordres en attente. Exécutez un test de l'EA sur EURUSD H1 sur un intervalle du 01/09/2010 au 31/12/2010, et comparez les graphiques. La figure montre le graphique du solde du rapport de test pour l'ensemble des trois modes.

Le graphique du test de l'EA Moving Average.mq5 du package standard ne dépend pas du mode de test.

Comme vous le voyez, les graphiques sur les différents modes de test sont absolument identiques pour l'EA Moving Average du package standard.

Il y a quelques limitations sur le mode "Prix d'Ouverture uniquement" :

  • On ne peut pas utiliser le mode d'exécution "Délai Aléatoire" ;
  • Dans l'expert testé, vous ne pouvez pas accéder aux données de la période inférieure à celle utilisée pour les tests/l'optimisation. Par exemple, si vous exécutez les tests/optimisation sur la période H1, vous pouvez accéder aux données de H2, H3, H4, etc., mais pas à celles de M30, M20, M10, etc. En outre, les périodes les plus élevées utilisées doivent être des multiplies de la période de test. Par exemple, si vous exécutez les tests en M20, vous ne pouvez pas accéder aux données de M30, mais il est possible d'accéder à H1. Ces limitations sont liées à l'impossibilité d'obtenir des données des périodes inférieures ou non-multiples des barres générées pendant le test/optimisation.
  • Les limitations sur l'accès aux données d'autres périodes sont également applicables aux autres symboles dont les données sont utilisées par l'Expert Advisor. Dans ce cas, la limitation pour chaque symbole dépend de la première période consultée lors du test/optimisation. Supposons, au cours des essais sur EURUSD H1, qu'un Expert Advisor accède aux données de GBPUSD en M20. Dans ce cas, l'Expert Advisor sera en mesure d'utiliser d'autres données de EURUSD en H1, H2, etc., ainsi que la paire GBPUSD en M20, H1, H2, etc.

Remarque : le mode "Prix d'Ouverture uniquement" est le plus rapide pour les tests, mais ne convient pas à toutes les stratégies de trading. Sélectionnez le mode de test désiré sur la base des caractéristiques du système de trading.

Pour conclure la section sur les modes de génération des ticks, comparons les différents modes de génération des ticks pour l'EURUSD, pour deux barres M15 sur l'intervalle du 11/01/2011 à 21:00:00 au 11/01/2011 à 21:30:00. Les ticks sont enregistrés dans différents fichiers en utilisant l'EA WriteTicksFromTester.mq5 et la fin de ces noms de fichiers sont spécifiés dans les paramètres d'entrée filenamEveryTick, filenameOHLC et filenameOpenPrice.

EA_inputs_in_tester

Pour obtenir trois fichiers avec trois séquences de tick (pour chacun des modes suivants : "Tous les ticks", "1 minute OHLC" et "Prix d'Ouverture Uniquement"), l'EA a été lancé trois fois dans les modes correspondants, en exécution simple. Ensuite, les données de ces trois fichiers sont affichées sur le graphique en utilisant l'indicateur TicksFromTester.mq5. Le code de l'indicateur est joint au présent article.

three_tick_series

Par défaut, toutes les opérations sur les fichiers dans le langage MQL5 sont effectuées dans la "sandbox" et pendant le test, l'EA n'a accès qu'à sa propre "sandbox de fichiers". Pour que l'indicateur et l'EA puissent travailler avec les fichiers d'un dossier lors de tests, nous avons utilisé le flag FILE_COMMON. Exemple de code de l'EA :

//--- ouverture du fichier
   file=FileOpen(filename,FILE_WRITE|FILE_CSV|FILE_COMMON,";");
//--- vérification du succès de l'opération
   if(file==INVALID_HANDLE)
     {
      PrintFormat("Erreur dans l'ouverture du fichier pour l'enregistrement %s. Le code de l'erreur=%d",filename,GetLastError());
      return;
     }
   else
     {
      //--- affiche le nom du dossier
      PrintFormat("Le fichier sera enregistré dans le dossier %s",TerminalInfoString(TERMINAL_COMMONDATA_PATH));
     }

Pour lire les données de l'indicateur, nous avons également utilisé le flag FILE_COMMON, cela a permis d'éviter le transfert des fichiers nécessaires manuellement d'un dossier à l'autre.

//--- ouverture du fichier
   int file=FileOpen(fname,FILE_READ|FILE_CSV|FILE_COMMON,";");
//--- vérification du succès de l'opération
   if(file==INVALID_HANDLE)
     {
      PrintFormat("Erreur dans l'ouverture du fichier pour la lecture %s. Le code de l'erreur=%d",fname,GetLastError());
      return;
     }
   else
     {
      //--- affichage du nom du dossier 
      PrintFormat("Le fichier sera lu du dossier %s",TerminalInfoString(TERMINAL_COMMONDATA_PATH));
     }

Simulation du spread #

La différence entre les prix Bid et Ask s'appelle le spread. Pendant le test, le spread n'est pas modelisé, mais est pris à partir des données historiques. Si le spread est inférieur ou égal à zéro dans les données historiques, le dernier spread connu (au moment de la génération) est utilisé par l'agent de test.

Dans le Strategy Tester, le spread est toujours considéré comme flottant. C'est à dire que SymbolInfoInteger(symbol, SYMBOL_SPREAD_FLOAT) retourne toujours vrai.

En outre, les données historiques contiennent les valeurs des ticks et les volumes des transactions. Pour le stockage et la récupération des données, nous utilisons une structure spéciale MqlRates:

struct MqlRates
  {
   datetime time;         // l'heure de l'ouverture de la barre
   double   open;         // le prix de l'ouverture Open
   double   high;         // le prix le plus haut High
   double   low;          // le prix le plus bas Low
   double   close;        // le prix de la clôture Close
   long     tick_volume;  // le volume du tick
   int      spread;       // le spread
   long     real_volume;  // le volume réel
  };

Utiliser des ticks réels pendant un test #

Les tests et les optimisations sur des ticks réels sont aussi proches des conditions réelles que possible. Au lieu de générer des ticks basées sur les données des barres 1 minutes, il est possible d'utiliser les ticks réels accumulés par un courtier. Ce sont les ticks issus des places boursières et des fournisseurs de liquidité.

Pour assurer la meilleure précision des tests, les barres 1 minute sont également utilisées dans le mode des ticks réels. Les barres sont appliquées pour vérifier et corriger les données des ticks. Ceci vous permet également d'éviter une divergence des graphiques dans le tester et dans le terminal client.

Le tester compare les données du tick avec les paramètres de la barre 1 minute : un tick ne doit pas être supérieur ou inférieur aux niveaux High et Low, le tick initial et le tick final doivent également coincider avec les prix Open/Close de la barre. Le volume est aussi comparé. Si un décalage est détecté, tous les ticks correspondant à cette barre 1 minute sont rejetés. Les ticks générés sont utilisés à leur place (comme dans le mode "Chaque tick").

Si l'historique d'un symbole possède une barre 1 minute sans données de tick, le tester génère des ticks dans le mode "Chaque tick". Cela permet de tracer un graphique correct dans le tester au cas où les données d'un courtier sont insuffisantes.

Si l'historique d'un symbole n'a pas de barre 1 minute, mais que les données du tick correspondant à cette minute sont présentes, les données peuvent être utilisées dans le tester. Par exemple, les paires de devises sont formées en utilisant les prix Last. Si seulement des ticks avec les prix Bid/Ask mais sans le prix Last arrivent du serveur, la barre n'est pas générée. Le tester utilise ces données puisqu'elles ne contredisent pas les données en minute.

Les données du tick peuvent ne pas coïncider avec les barres 1 minute pour diverses raisons, par exemple en raison de pertes de connexion ou d'autres défaillances lors de la transmission des données d'une source jusqu'au terminal client. Les données 1 minute sont considérées comme plus fiables au cours des tests.

Gardez en mémoire les éléments suivants lors de tests sur des ticks réels :

  • Lors du lancement d'un test, les données 1 minute d'un symbole sont synchronisées avec le premier tick.
  • Les ticks sont stockés dans le cache du symbole du strategy tester. La taille du cache ne doit pas excéder 128 000 ticks. Lorsque de nouveaux ticks arrivent, les données les plus anciennes sont supprimées du cache. Cependant, la fonction CopyTicks permet de récupérer les ticks en dehors du cache (seulement pour des tests sur des ticks réels).Dans ce cas, les données sont récupérées depuis la base de données des ticks du tester qui est totalement similaire à la base de données correspondante du terminal client. Aucune correction de barre 1 minute n'est faite dans cette base. De plus, les ticks peuvent différer de ceux stocker dans le cache.

Les Variables globales du terminal client #

Pendant le test, les variables globales du terminal client sont également émulées, mais elles ne sont aucunement liées aux variables globales actuelles du terminal, qui peuvent être vues dans le terminal en utilisant la touche F3. Cela signifie que toutes les opérations avec les variables globales du terminal, au cours des tests, ont lieu à l'extérieur du terminal client (dans l'agent de test).

Calcul des indicateurs au cours des tests #

En mode temps réel, les valeurs des indicateurs sont calculées à chaque tick.

Dans le Strategy Tester, les indicateurs sont calculés uniquement lorsqu'ils sont consultés pour les données, c'est-à-dire lorsque des valeurs du buffer de l'indicateur sont demandées. Les seules exceptions sont les indicateurs personnalisés avec la propriété #property tester_everytick_calculatespécifiée. Dans ce cas, le recalcul est effectué à chaque tick.

En mode de test visuel, tous les indicateurs sont inconditionnellement recalculés à l'arrivée d'un nouveau tick afin d'être correctement affichés sur le graphique de test visuel.

L'indicateur est calculé une fois par tick. Toutes les demandes ultérieures de données de l'indicateur n'entraînent pas de recalcul jusqu'à ce qu'un nouveau tick arrive. Par conséquent, si la minuterie est activée dans un EA via la fonction EventSetTimer(), les données de l'indicateur sont demandées à partir du dernier tick avant chaque appel du gestionnaire OnTimer(). Si l'indicateur n'a pas encore été calculé sur le dernier tick, les calculs des valeurs de l'indicateur sont lancés. Si les données ont déjà été préparées, elles sont fournies sans nouveau recalcul.

Ainsi, tous les calculs d'indicateurs sont effectués de la manière la plus économe en ressources – si l'indicateur a déjà été calculé à un tick donné, ses données sont fournies "telles quelles". Aucun recalcul n'est lancé.

Chargement de l'historique au cours des tests #

L'historique d'un symbole à tester est synchronisé et chargé par le terminal à partir du serveur de trading avant de commencer le processus de test. La première fois, le terminal charge l'historique disponible du symbole afin de ne pas le demander plus tard. Par la suite, sules les nouvelles données sont chargées.

Un agent de test reçoit l'historique d'un symbole à tester à partir du terminal client juste après le lancement du test. Si les données d'autres instruments sont utilisées dans le processus de test (par exemple, Expert Advisor multidevises), l'agent de test demande l'historique nécessaire à partir du terminal client lors du premier appel à ces données. Si les données historiques sont disponibles dans le terminal, elles sont immédiatement transmises à l'agent de test. Si les données ne sont pas disponibles, le terminal les demande et les télécharge à partir du serveur, puis les passe à l'agent de test.

Les données des instruments supplémentaires sont également nécessaires pour le calcul des taux croisés pour les opérations de trading. Par exemple, lors du test d'une stratégie sur l'EURCHF avec la monnaie de dépôt en USD, avant le traitement de la première opération de trading, l'agent de test demande l'historique des données de la paire EURUSD et USDCHF au terminal client, bien que la stratégie ne contienne pas l'utilisation directe de ces symboles.

Avant de tester une stratégie multi-devises, il est recommandé de télécharger toutes les données historiques nécessaires pour le terminal client. Cela permettra d'éviter des retards dans les tests/optimisation dûs au téléchargement des données requises. Vous pouvez télécharger l'historique, par exemple, en ouvrant les graphiques appropriés et les faire défiler vers le début de l'historique. Un exemple du chargement forcé de l'historique dans le terminal est disponible dans la section MQL5 Organisation de l'Accès aux Données.

Les agents de test reçoivent à leur tour l'historique du terminal. Lors du test suivant, le testeur ne charge pas l'historique du terminal, puisque les données nécessaires sont disponibles depuis l'exécution précédente du testeur.

  • Le terminal ne charge l'historique du serveur qu'une seule fois au premier appel de l'agent par le terminal pour recevoir l'historique du symbole testé. L'historique est chargé sous forme d'un paquet pour réduire le trafic.
  • Les ticks ne sont pas envoyés sur le réseau, ils sont générés sur les agents de test.

Tests Multi-Devises #

Le Strategy Tester nous permet de tester des stratégies tradant sur plusieurs symboles. Ces EA sont habituellement appelés Expert Advisors multi-devises, puisqu'à l'origine, dans les plateformes précédentes, les tests n'étaient effectués que pour un seul symbole. Dans le Strategy Tester du terminal MetaTrader 5, nous pouvons modéliser le trading pour tous les symboles disponibles.

Le testeur charge l'historique des symboles utilisés à partir du terminal client (pas à partir du serveur de trading !) automatiquement lors du premier appel des données du symbole.

L'agent de test télécharge seulement l'historique manquant, avec une petite marge pour fournir les données nécessaires, pour le calcul des indicateurs à l'heure du début des tests. Pour les périodes D1 et inférieures, le volume minimum de l'historique téléchargé est de un an. Ainsi, si nous lançons un test sur l'intervalle 01/11/2010 - 01/12/2010 (test pour un intervalle d'un mois) avec une période de M15 (chaque barre est égale à 15 minutes), le terminal demandera l'historique de l'instrument pour l'ensemble de l'année 2010. Pour les périodes Hebdomadaires, nous allons demander un historique de 100 barres, environ deux ans (52 semaines par an). Pour un test sur une période Mensuelle, l'agent demandera l'historique sur 8 ans (12 mois x 8 ans = 96 mois).

S'il n'y a pas la quantité nécessaires de barres, la date de début sera automatiquement déplacée vers le passé pour fournir la quantité de barres nécessaire avant le test.

Pendant le test, le "Market Watch" est également émulé, à partir duquel on peut obtenir des informations sur les symboles. Par défaut, au début du test, il n'y a qu'un symbole dans le "Market Watch" du Strategy Tester - le symbole sur lequel le test est exécuté. Tous les symboles nécessaires sont connectés au "Market Watch" du Strategy Tester (pas à celui du terminal !) automatiquement lorsqu'ils sont appelés.

Avant de commencer le test d'un Expert Advisor multi-devises, il est nécessaire de sélectionner les symboles requis dans le "Market Watch" du terminal et de charger les données requises Lors du premier appel d'un symbole "étranger", son historique sera automatiquement synchronisé entre l'agent de test et le terminal client. Un symbole "étranger" est un symbole autre que celui sur lequel le test est en cours d'exécution.

Le renvoi aux données d'un "autre" symbole se produit dans les cas suivants :

  • lorsque vous utilisez la fonction et IndicatorCreate() des indicateurs techniques sur le symbole/la période ;
  • La demande de données au "Market Watch" pour l'autre symbole :
  • la demande de la série chronologique pour un symbole/une période en utilisant les fonctions suivantes :

Au moment du premier appel à un symbole "autre", le processus de test s'arrête et l'historique est téléchargé pour le symbole/la période à partir du terminal vers l'agent de test. En même temps, la séquence de ticks pour ce symbole est générée.

Une séquence individuelle de ticks est générée pour chaque symbole, selon le mode sélectionné de génération des ticks. Vous pouvez également demander explicitement l'historique des symboles souhaités en appelant la fonction SymbolSelect() dans le gestionnaire OnInit() - le téléchargement de l'historique sera fait immédiatement avant le test de l'Expert Advisor.

Ainsi, pour effectuer des tests multi-devises dans le terminal client MetaTrader 5, aucun effort supplémentaire n'est nécessaire. Il suffit d'ouvrir les graphiques des symboles appropriés dans le terminal client. L'historique sera automatiquement téléchargé à partir du serveur pour tous les symboles nécessaires, à condition qu'il contienne ces données.

Simulation du Temps dans le Strategy Tester #

Au cours des tests, l'heure locale TimeLocal() est toujours égale à l'heure du serveur TimeTradeServer(). À son tour, l'heure du serveur est toujours égale à l'heure GMT - TimeGMT(). Ainsi, toutes ces fonctions affichent la même heure lors des tests.

L'absence de différence entre l'heure GMT, l'heure locale, et l'heure du serveur dans le Strategy Tester se fait délibérément dans le cas où il n'y a pas de connexion au serveur. Les résultats des tests doivent toujours être identiques, indépendamment de la présence ou non d'une connexion. L'information sur l'heure du serveur n'est pas stockée localement, et est prise à partir du serveur.

Objets Graphiques pendant le Test #

Lors des tests/optimisations, les objets graphiques ne sont pas tracés. Ainsi, en se référant aux propriétés d'un objet créé lors des tests/optimisations, un Expert Advisor recevra des valeurs nulles.

Cette limitation ne concerne pas les tests en mode visuel.

La Fonction OnTimer() dans le Strategy Tester #

MQL5 prévoit la possibilité de gérer des événements de timer. L'appel du gestionnaire OnTimer() est fait quel que soit le mode de test. Cela signifie que si un test est en cours d'exécution en mode "Prix d'Ouverture Uniquement" pour la période H4, et que l'EA a un timer réglé à un appel par seconde, alors à l'ouverture de chaque barre en H4, le gestionnaire OnTick() sera appelé une seule fois, et le gestionnaire OnTimer() sera appelé 14.400 fois (3.600 secondes * 4 heures). . L'augmentation de temps qui en découlera dépend de la logique de l'EA.

Pour vérifier la dépendance du temps du test de la fréquence donnée du timer, nous avons créé un EA simple, sans aucune opération de trading.

//--- paramètres d'entrée
input int      timer=1;              // valeur du time, sec
input bool     timer_switch_on=true; // le timer est activé
//+------------------------------------------------------------------+
//| Fonction d'initialisation de l'expert                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- démarrage du timer si timer_switch_on==true
   if(timer_switch_on)
     {
      EventSetTimer(timer);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Fonction de désinitialisation de l'expert                        |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- arrêt du timer
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
// ne fait rien, le corps du gestionnaire est vide
  }
//+------------------------------------------------------------------+

Les mesures de temps du test ont été faites avec différentes valeurs du paramètre du timer (périodicité de l'événement Timer). Le graphique de la dépendance du temps du test T à la valeur de la périodicité Period est construit sur les données reçues.

Time_Dependence

Il est clair que, plus le paramètre timer est petit lors de l'initialisation de la fonction EventSetTimer (timer), plus courte sera la période (Period) entre les appels du gestionnaire OnTimer(), et plus grand est le test du temps T, dans les mêmes autres conditions.

Fonction Sleep() dans le Strategy Tester #

La fonction Sleep() permet à l'EA ou à un script de suspendre l'exécution du programme MQL5 pendant un certain temps, lorsque l'on travaille sur le graphique. Cela peut être utile lors de la demande de données, qui ne sont pas prêtes au moment de la demande et qu'il est nécessaire d'attendre jusqu'à ce qu'elles le soient. Un exemple détaillé de l'utilisation de la fonction Sleep() peut être trouvé dans la section Organisation de l'Accès aux Données.

Dans le testeur, les appels Sleep() ne bloquent pas le déroulement du test. A l'appel de Sleep(), les ticks générés sont "joués" dans le délai spécifié, ce qui peut entraîner le déclenchement des ordres en attente, stops, etc. Après l'appel de Sleep(), le temps modelisé dans le testeur augmente de l'intervalle indiqué dans le paramètre de la fonction Sleep.

Si, à la suite de l'exécution de la fonction Sleep(), l'heure actuelle dans le testeur dépasse l'intervalle du test, l'erreur "Boucle infinie détectée dans Sleep". Si vous recevez cette erreur, les résultats des tests ne sont pas rejetés, tous les calculs sont effectués en totalité (le nombre de transactions, l'affaissement, etc.), et les résultats de ce test sont transmis au terminal.

La fonction Sleep() ne fonctionne pas dans OnDeinit(), puisque après son appel l'heure du test se trouve en dehors de l'intervalle du test de façon certaine.

Le schéma de l'utilisation de la fonction Sleep() dans le Strategy Tester du terminal MetaTrader 5.

Utilisation du Strategy Tester pour l'Optimisation des Problèmes dans les Calculs Mathématiques #

On peut utiliser le testeur dans le terminal MetaTrader 5 non seulement pour vérifier des stratégies de trading, mais également pour des calculs mathématiques. Pour l'utiliser, il est nécessaire de sélectionner le mode "Calculs Mathématiques" :

math_calculations

Dans ce cas, seules trois fonctions seront appelées : OnInit(), OnTester(), OnDeinit(). En mode "Calculs Mathématiques", le Strategy Tester ne génère pas de ticks et télécharge l'historique. Dans ce cas, seules trois fonctions seront appelées : OnInit(), OnTester(), OnDeinit().

Si la date de fin du test est inférieure ou égale à la date de début du test, cela signifiera que le test sera exécuté en mode "Calculs Mathématiques".

Lorsque vous utilisez le testeur pour résoudre des problèmes mathématiques, l'ajout de l'historique et la génération de ticks ne sont pas effectués.

Un problème mathématique typique à résoudre dans le Strategy Tester de MetaTrader 5 : la recherche de l'extremum d'une fonction à plusieurs variables. Pour le résoudre, nous devons :

  • Placer le bloc de calcul de la valeur de la fonction à plusieurs variables dans la fonction OnTester() et retourner la valeur calculée avec return(la valeur_de la fonction);
  • Les paramètres de la fonction doivent être définis comme des variables d'entrée de l'Expert Advisor ;

Pour compiler l'EA, ouvrez la fenêtre du "Strategy Tester". Dans l'onglet "Paramètres d'entrée", sélectionnez les variables d'entrées demandées, et définissez l'ensemble des valeurs des paramètres en spécifiant les valeurs de démarrage, d'arrêt et de pas pour chacune des variables de la fonction.

Sélectionnez le type d'optimisation - "Algorithme Complet Lent" (recherche complète de l'espace des paramètres) ou "Algorithme Génétique Rapide". Pour une simple recherche de l'extremum de la fonction, il est préférable de choisir une optimisation rapide, mais si vous voulez calculer les valeurs pour l'ensemble des variables, alors il est préférable d'utiliser l'optimisation lente.

Sélectionnez le mode "Calculs Mathématiques", utilisez le bouton "Démarrer", et exécutez la procédure d'optimisation. A noter que lors de l'optimisation, le Strategy Tester recherche les valeurs maximum de la fonction OnTester. Pour trouver un minimum local, retournez l'inverse de la valeur de la fonction calculée à partir de la fonction OnTester :

return(1/valeur_de la fonction);

Il est nécessaire de vérifier que valeur_de_la_fonction n'est pas égale à zéro, autrement une erreur critique de division par zéro peut être générée. Il existe une autre variante, plus facile et qui ne fausse pas les résultats de l'optimisation ; elle a été suggérée par les lecteurs de cet article :

return(-valeur_de la fonction);

Dans cette variante, il n'est pas utile vérifier si valeur_de_la_fonction est égal à zéro et la surface des résultats de l'optimisation dans la représentation 3D a la même forme. La seule différence est qu'elle est inversée symétriquement par rapport à l'initiale.

A titre d'exemple, nous fournissons la fonction sink() :

sink_formula

Plaçons le code de l'EA pour trouver l'extremum de cette fonction dans la fonction OnTester() :

//+------------------------------------------------------------------+
//|                                                         Sink.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//--- paramètres d'entrée
input double   x=-3.0; // start=-3, step=0.05, stop=3
input double   y=-3.0; // start=-3, step=0.05, stop=3
//+------------------------------------------------------------------+
//| Fonction du tester                                              |
//+------------------------------------------------------------------+
double OnTester()
  {
//---
   double sink=MathSin(x*x+y*y);
//---
   return(sink);
  }
//+------------------------------------------------------------------+

Effectuons une optimisation et voyons les résultats de l'optimisation sous la forme d'un graphique 2D.

Les résultats de l'optimisation complète de la fonction sink(x*x+y*y) en format 2D.

Meilleure est la valeur pour une paire de données des paramètres (x, y), plus la couleur est saturée. Comme il était attendu de la vue de la formule de la fonction sink(), ses valeurs forment des cercles concentriques avec un centre au point (0,0). On peut voir dans le graphique 3D que la fonction sink() n'a pas d'extremum absolu. Graphique 3D de la fonction Sink()

3d

Synchronisation des Barres en mode "Prix d'Ouverture Uniquement" #

Le testeur dans le terminal client MetaTrader 5 permet de vérifier les fameux EA "multi-devises". Un EA multi-devises est un EA qui trade sur 2 symboles ou plus.

Le test des stratégies tradant sur plusieurs symboles impose quelques exigences techniques supplémentaires sur le testeur :

  • la génération des ticks pour ces symboles ;
  • le calcul des valeurs des indicateurs pour ces symboles ;
  • le calcul des exigences de marge pour ces symboles ;
  • la synchronisation des séquences de tick générées pour tous les symboles.

Le Strategy Tester produit et joue une séquence de ticks pour chaque instrument selon le mode de trading sélectionné. En même temps, une nouvelle barre est ouverte pour chaque symbole, indépendamment de la façon dont la barre a été ouverte sur un autre symbole. Cela signifie que lors du test d'un expert multi-devises, une situation peut se produit (et se produit souvent) lorsque une nouvelle barre est ouverte sur un instrument, mais pas encore sur l'autre instrument. Ainsi, pendant le test tout se passe comme dans la réalité.

Cette simulation authentique de l'historique dans le testeur ne pose pas de problème tant que les modes "Chaque tick" et "1 minute OHLC" sont utilisés. Pour ces modes, suffisamment de ticks sont générés pour une bougie pour pouvoir attendre que la synchronisation des barres des différents symboles soit effectuée. Mais comment tester les stratégies multi-devises en mode "Prix d'Ouverture Uniquement" si la synchronisation des barres sur les instruments de trading est obligatoire ? Dans ce mode, l'EA est n'est appelé que sur un tick, correspondant à l'heure d'ouverture des barres.

Nous allons l'expliquer avec un exemple : nous testons un expert sur le symbole EURUSD, et une nouvelle bougie en H1 a été ouverte sur l'EURUSD. Il est aisé de reconnaître ce fait - pendant le test en mode "Prix d'Ouverture Uniquement", l'événement NewTick correspond au moment de l'ouverture de la barre sur la période testée. Mais il n'y a aucune garantie qu'une nouvelle bougie a été ouverte sur le symbole USDJPY, qui est utilisé dans l'expert.

Dans des conditions ordinaires, il suffit de terminer le travail de la fonction OnTick() et de vérifier l'apparition d'une nouvelle barre USDJPY sur le tick suivant. Mais pendant le test en mode "Prix d'ouverture uniquement", il n'y aura pas d'autres ticks, et il peut donc sembler que ce mode ne convient pas pour tester des EA multi-devises. Mais ce n'est pas vrai - n'oubliez pas que le testeur sur MetaTrader 5 se comporte comme dans la vraie vie. On peut attendre jusqu'à ce qu'une nouvelle barre s'ouvre sur un autre symbole en utilisant la fonction Sleep() !

Le code de l'EA Synchronize_Bars_Use_Sleep.mq5 montre un exemple de synchronisation des barres dans le mode "Prix d'Ouverture Uniquement" :

//+------------------------------------------------------------------+
//|                                   Synchronize_Bars_Use_Sleep.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//--- paramètres d'entrée
input string   other_symbol="USDJPY";
//+------------------------------------------------------------------+
//| Fonction d'initialisation de l'expert                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- vérification du symbole courant
   if(_Symbol==other_symbol)
     {
      PrintFormat("Il est nécessaire d'indiquer un autre symbole ou lancer le test sur un autre symbole !");
      //--- fin du test de l'expert
      return(INIT_PARAMETERS_INCORRECT);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Fonction tick de l'expert                                        |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- variable statique pour stocker l'heure d'ouverture de la dernière barre
   static datetime last_bar_time=0;
//--- signe indiquant que l'heure d'ouverture de la dernière barre sur les symboles différents est synchronisée
   static bool synchonized=false;
//--- si la variable statique n'est pas encore initialisée
   if(last_bar_time==0)
     {
      //--- c'est le premier appel, stocke l'heure de l'ouverture et sort
      last_bar_time=(datetime)SeriesInfoInteger(_Symbol,Period(),SERIES_LASTBAR_DATE);
      PrintFormat("La variable last_bar_time est initialisée avec la valeur %s",TimeToString(last_bar_time));
     }
//--- récupère l'heure d'ouverture de la dernière barre selon le symbole
   datetime curr_time=(datetime)SeriesInfoInteger(Symbol(),Period(),SERIES_LASTBAR_DATE);
//--- si l'heure d''ouverture de la barre actuelle ne correspond pas à celle qui est stockée dans last_bar_time
   if(curr_time!=last_bar_time)
     {
      //--- stocke l'heure d'ouverture de la nouvelle barre dans la variable statique
      last_bar_time=curr_time;
      //--- la synchronisation est rompue, le flag est mis à false
      synchonized=false;
      //--- construction du message sur cet événement
      PrintFormat("Une nouvelle barre s'est ouverte sur le symbole %s dans %s",_Symbol,TimeToString(TimeCurrent()));
     }
//--- stockera l'heure d''ouverture de la barre sur le symbole étranger
   datetime other_time;
//--- boucle jusqu'à ce que l'heure d'ouverture de la dernière barre sur un autre symbole soit égale à curr_time
   while(!(curr_time==(other_time=(datetime)SeriesInfoInteger(other_symbol,Period(),SERIES_LASTBAR_DATE)) && !synchonized))
     {
      PrintFormat("Attendons 5 secondes..");
      //--- attente de 5 secondes et demande encore SeriesInfoInteger(other_symbol,Period(),SERIES_LASTBAR_DATE)
      Sleep(5000);
     }
//--- l'heure d'ouverture de la barre est identique maintenant pour les deux symboles
   synchonized=true;
   PrintFormat("L'heure d'ouverture de la dernière barre sur le symbole %s: %s",_Symbol,TimeToString(last_bar_time));
   PrintFormat("L'heure d'ouverture de la dernière barre sur le symbole %s: %s",other_symbol,TimeToString(other_time));
//--- TimeCurrent() ne convient pas, utilise TimeTradeServer() pour
   Print("Les barres étaient synchronisées dans ",TimeToString(TimeTradeServer(),TIME_DATE|TIME_SECONDS));
  }
//+------------------------------------------------------------------+

Prêtez attention à la dernière ligne de l'EA, qui affiche l'heure actuelle quand la synchronisation a été établie :

   Print("Les barres étaient synchronisées dans ",TimeToString(TimeTradeServer(),TIME_SECONDS));

Pour afficher l'heure actuelle, nous avons utilisé la fonction TimeTradeServer(), plutôt queTimeCurrent(). La fonction TimeCurrent () retourne l'heure du dernier tick, qui n'a pas changé après l'utilisation de la fonction Sleep(). Exécutez l'EA en mode "Prix d'Ouverture Uniquement" et vous verrez un message sur la synchronisation des barres.

Synchronize_Bars_Use_Sleep_EA

Utilisez la fonction TimeTradeServer() au lieu de TimeCurrent(), si vous avez besoin d'obtenir l'heure actuelle du serveur, et non l'heure d'entrée du dernier tick.

Il y a une autre façon de synchroniser les barres - à l'aide du timer. L'exemple d'un tel EA Synchronize_Bars_Use_OnTimer.mq5 est attaché à cet article.

La fonction IndicatorRelease() dans le Strategy Tester #

A la fin du test, le graphique de l'instrument s'ouvre automatiquement, et affiche les transactions réalisées et les indicateurs utilisés dans l'EA. Cela permet de vérifier visuellement les points d'entrée et de sortie, et de les comparer aux valeurs des indicateurs.

Remarque : les indicateurs affichés sur le graphique s'ouvrent automatiquement après l'achèvement du test, et sont calculés de nouveau après la fin du test. Même si ces indicateurs ont été utilisés dans l'EA testé.

Mais dans certains cas, le programmeur peut vouloir cacher les informations sur les indicateurs impliqués dans l'algorithme de trading. Par exemple, le code de l'EA est loué ou est vendu comme un fichier exécutable sans mise à disposition du code source. Pour cela, la fonction IndicatorRelease() est utile.

Si le terminal établit un modèle avec le nom tester.tpl dans le directory/profiles/templates du terminal client, alors il sera appliqué au graphique ouvert. En son absence, le modèle par défaut est appliqué (default.tpl).

La fonction IndicatorRelease() est initialement prévue pour supprimer la partie du calcul de l'indicateur, si elle n'est plus nécessaire. Cela permet d'économiser la mémoire, ainsi que les ressources CPU, parce que chaque tick appelle un calcul de l'indicateur. Son deuxième objectif est d'interdire l'affichage d'un indicateur sur le graphique de test, après un seul essai.

Pour interdire l'affichage de l'indicateur sur le graphique à la fin du test, appelez IndicatorRelease() avec le handle de l'indicateur dans le gestionnaire OnDeinit(). La fonction OnDeinit() est toujours appelée après la fin et avant l'affichage du graphique du test.

//+------------------------------------------------------------------+
//| Fonction de désinitialisation de l'expert                        |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   bool hidden=IndicatorRelease(handle_ind);
   if(hidden) Print("IndicatorRelease() est exécuté avec succès ");
   else Print("IndicatorRelease() a retourné false. Code de l'erreur ",GetLastError());
  }

Pour interdire l'affichage de l'indicateur sur le graphique à la fin du test, utilisez la fonction IndicatorRelease() dans le gestionnaire OnDeinit().

Gestion des Evénements dans le Strategy Tester #

La présence du gestionnaire OnTick() dans l'EA n'est pas obligatoire pour effectuer des tests sur les données historiques dans le MetaTrader 5 Tester. Il suffit que l'EA contienne au moins l'une des fonctions-gestionnaire suivantes :

  • OnTick() - le gestionnaire de l'événement de l'arrivée d'un nouveau tick ;
  • OnTrade() - le gestionnaire de l'événement de trading ;
  • OnTimer() - le gestionnaire de l'événement de l'arrivée du signal du timer ;
  • OnChartEvent() - le gestionnaire d'événements clients.

Lors du test dans un EA, nous pouvons gérer les événements personnalisés en utilisant la fonction OnChartEvent(), mais dans les indicateurs, cette fonction n'est pas appelée dans le testeur. Même si l'indicateur a le gestionnaire OnChartEvent() et que cet indicateur est utilisé dans l'EA testé, l'indicateur lui-même ne recevra pas les événements personnalisés.

Pendant le test, un indicateur peut générer des événements personnalisés en utilisant la fonction EventChartCustom(), et l'EA peut traiter cet événement dans la fonction OnChartEvent().

En plus de ces événements, des événements spéciaux associés aux processus de test et d'optimisation sont générés dans le Strategy Tester :

  • Tester - cet événement est généré à la fin du test de l'EA sur les données historiques. L'événement Tester est géré en utilisant la fonction OnTester(). Cette fonction peut être utilisée seulement dans les EA de test et est destinée principalement au calcul d'une valeur qui est utilisée comme critère personnalisé maximum pour l'optimisation génétique des paramètres d'entrée.
  • TesterInit - cet événement est généré au lancement de l'optimisation dans le Strategy Tester avant le premier passage. L'événement TesterInit est géré en utilisant la fonction OnTesterInit(). Au lancement de l'optimisation, un Expert Advisor ayant cette fonction est chargée automatiquement sur un graphique séparé du terminal avec le symbole et la période indiqués dans le testeur et reçoit l'évènement TesterInit. La fonction est utilisée pour initialiser un Expert Advisor avant le début de l'optimisation pour un traitement ultérieur des résultats de l'optimisation.
  • TesterPass - cet événement est généré lorsqu'un nouveau bloc de données est reçu. L'événement TesterPass est géré en utilisant la fonction OnTesterPass(). Au lancement de l'optimisation, un Expert Advisor ayant cette fonction est chargée automatiquement sur un graphique séparé du terminal avec le symbole et la période indiqués dans le testeur et reçoit l'évènement TesterPass lorsqu'un bloc de données est reçu pendant l'optimisation. La fonction est utilisée pour le traitement dynamique des résultats d'optimisation "aussitôt", sans attendre son achèvement. Les frames sont ajoutés à l'aide de la fonction FrameAdd(), qui peut être appelé à la fin d'une passe unique dans le gestionnaire OnTester().
  • TesterDeinit - cet événement est généré à l'issue de l'optimisation de l'Expert Advisor A dans le Strategy Tester. L'événement TesterDeinit est géré en utilisant la fonction OnTesterDeinit(). L'Expert Advisor qui a ce gestionnaire est chargé automatiquement sur un graphique au début de l'optimisation et reçoit l'événement TesterDeinit après son achèvement. La fonction est utilisée pour le traitement final de tous les résultats de l'optimisation.

Agents de Test #

Les tests dans le terminal client MetaTrader 5 sont effectués en utilisant des agents de test. Les agents locaux sont créés et activés automatiquement. Le nombre d'agents locaux correspond par défaut au nombre de coeurs de l'ordinateur.

Chaque agent de test a sa propre copie des variables globales, qui ne sont pas liés au terminal client. Le terminal lui-même est le répartiteur qui distribue les tâches aux agents locaux et aux agents distants. Après l'exécution d'une tâche sur l'Expert Advisor avec les paramètres spécifiés, l'agent retourne les résultats au terminal. Pour un seul test, un seul agent est utilisé.

L'agent sauvegarde l'historique reçu du terminal dans des dossiers séparés, nommés avec le nom de l'instrument, de sorte que l'historique de la paire EURUSD est stocké dans un dossier nommé EURUSD. En outre, l'historique des instruments est séparé de leurs sources. La structure de stockage de l'historique est construit de la façon suivante :

répertoire_du testeur\Agent-AdresseIP-Port\bases\nom_de la source\history\nom_de l'instrument

Par exemple, l'historique de la paire EURUSD du serveur MetaQuotes-Demo peut être stocké dans le dossier tester_catalog\Agent-127.0.0.1-3000\bases\MetaQuotes-Demo\EURUSD.

L'agent local passe en veille pendant 5 minutes après la fin du test, en attente de la prochaine tâche, afin de ne pas perdre de temps au lancement de l'appel suivant. L'agent local cesse son travail et est supprimé de la mémoire de l'ordinateur à l'expiration de l'attente.

Dans le cas d'une fin prématurée du test du côté de l'utilisateur (bouton "Annuler") ou en cas de fermeture du terminal client, tous les agents locaux arrêtent immédiatement leur travail et sont supprimés de la mémoire.

L'Echange des Données entre le Terminal et l'Agent #

Lorsque vous exécutez un test, le terminal client se prépare à envoyer à un agent un certain nombre de blocs paramètres :

  • Les paramètres d'entrée du test (le mode de simulation, l'intervalle du test, les instruments, le critère de l'optimisation, etc.)
  • La liste des symboles sélectionnés dans le "Market Watch"
  • La spécification du symbole du test (la taille du contrat, les marges admissibles du marché pour définir un StopLoss et un TakeProfit, etc.)
  • L'Expert Advisor testé et les valeurs de ses paramètres d'entrée
  • Les informations sur les fichiers supplémentaires (les bibliothèques, les indicateurs, les fichiers de données - #property tester_...)

tester_indicator

string

Le nom de l'indicateur personnalisé au format "indicator_name.ex5". Les indicateurs qui nécessitent des tests sont définis automatiquement à partir de l'appel à la fonction iCustom() si le paramètre correspondant est défini par une chaîne de caractères constante. Cette propriété est requise pour tous les autres cas (utilisation de la fonctionIndicatorCreate() ou utilisation d'une chaîne de caractères non constante dans le paramètre qui définit le nom de l'indicateur)

tester_file

string

Le nom de fichier d'un testeur avec l'extension, entre guillemets (comme une chaîne de caractères constante). Le fichier spécifié sera transmis au testeur. Les fichiers d'entrée du test doivent être toujours spécifiés s'ils sont nécessaires.

tester_library

string

Le nom de la bibliothèque avec l'extension, entre guillemets. La bibliothèque peut avoir l'extension dll ou ex5. Les bibliothèques qui nécessitent des tests sont définies automatiquement. Toutefois, si l'une des bibliothèques est utilisé par un indicateur personnalisé, il est nécessaire d'utiliser la propriété donnée

Pour chaque bloc de paramètres, une empreinte numérique sous la forme de MD5-hash est créée, et envoyée à l'agent. Le MD5-hash est unique pour chaque ensemble, son volume est plus petit que le volume de l'information, cette propriété est requise.

Pour chaque bloc de paramètres, une empreinte digitale, sous la forme d'un hash MD5, est créée et envoyée à l'agent. L'agent reçoit un ensemble de blocs et les compare avec ceux qu'il a déjà. Si l'empreinte du bloc de paramètres donné n'est pas présent sur l'agent, ou si le hash reçu est différent de celui existant, l'agent demande ce bloc de paramètres. Cela permet de réduire le trafic entre le terminal et l'agent.

Après le test, l'agent retourne tous les résultats de la passe au terminal, qui sont ensuite affichés dans les onglets "Résultats du test" et "Résultats de l'optimisation" : le bénéfice réalisé, le nombre de transactions, le ratio de Sharpe, le résultat de la fonction OnTester(), etc.

Pendant l'optimisation, le terminal distribue les tâches aux agents par petits paquets, chaque paquet contenant plusieurs tâches (chaque tâche est un test simple avec un ensemble de paramètres d'entrée). Cela diminue le temps d'échange entre le terminal et l'agent.

Les agents n'enregistrent jamais les fichiers EX5 reçus du terminal sur le disque dur (l'Expert Advisor, les indicateurs, les bibliothèques, etc.) pour des raisons de sécurité, de sorte qu'un ordinateur avec un agent en cours d'exécution ne peut pas utiliser les données envoyées. Tous les autres fichiers, y compris les DLL, sont enregistrés dans la "sandbox". Vous ne pouvez pas tester les EA utilisant les DLL sur les agents distants.

Les résultats des tests sont ajoutés au terminal dans un cache spécial des résultats (le cache des résultats) pour un accès rapide. Pour chaque ensemble de paramètres, le terminal recherche les résultats déjà disponibles à partir des tests précédents dans le cache des résultats afin d'éviter les redémarrages. Si le résultat d'un tel ensemble de paramètres n'a pas été trouvé, la tâche est donnée à l'agent pour effectuer le test.

Tout le trafic entre le terminal et l'agent est crypté.

Les ticks ne sont pas envoyés sur le réseau, ils sont générés sur les agents de test.

Utilisation du Dossier Partagés de Tous les Terminaux Client #

Tout les agents de test sont isolés les uns des autres et du terminal client : chaque agent a un dossier personnel, dans lequel les journaux sont enregistrés. En outre toutes les opérations sur les fichiers pendant les tests de l'agent se produisent dans le dossier nom_de l'agent/MQL5/Files. Cependant, nous pouvons implémenter l'interaction entre les agents locaux et le terminal client à travers un dossier partagé pour tous les terminaux clients, si lors de l'ouverture du fichier vous spécifiez le drapeau FILE_COMMON :

//+------------------------------------------------------------------+
//| Fonction d'initialisation de l'Expert                           |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- le dossier partagé de tous les terminaux clients
   common_folder=TerminalInfoString(TERMINAL_COMMONDATA_PATH);
//--- construction du nom de ce dossier
   PrintFormat("Ouvre le fichier dans le dossier partagé des terminaux client %s", common_folder);
//--- ouvre le fichier dans le dossier partagé (indiqué par le drapeau FILE_COMMON)
   handle=FileOpen(filename,FILE_WRITE|FILE_READ|FILE_COMMON);
  ... d'autres actions
//---
   return(INIT_SUCCEEDED);
  }

Utilisation de DLL #

Pour accélérer l'optimisation, nous pouvons utiliser non seulement les agents locaux, mais aussi les agents distants. Dans ce cas, il existe certaines limites pour les agents distants. Tout d'abord, les agents distants n'affichent pas dans leurs journaux les résultats de l'exécution de la fonction Print(), les messages sur l'ouverture et la fermeture des positions. Un minimum d'information est affichée dans le journal pour empêcher les EA mal écrits de remplir l'ordinateur sur lequel l'agent distant travaille avec des messages.

La deuxième limite est l'interdiction d'utiliser les DLL lors du test des EA. Les appels aux DLL sont absolument interdits sur les agents distants pour des raisons de sécurité. Sur les agents locaux, les appels aux DLL dans les EA testés sont autorisés uniquement avec l'autorisation correspondante "Autoriser l'importation de DLL".

L'option "Autoriser l'importation de DLL" dans les programmes MQL5

Remarque : lorsque vous utilisez des EA tiers (scripts, indicateurs) qui nécessitent des appels autorisés aux DLL, vous devez être conscient des risques que vous prenez lorsque vous autorisez cette option dans les paramètres du terminal. Indépendamment de comment l'EA sera utilisé - pour le test ou pour l'éxécution sur le graphique.