Accueil Trading Systématique Publication

Moyenne Mobile : Un Expert pour MetaTrader 5

Pièce jointe
1921.zip (1.81 KB, Télécharger 0 fois)

Le système de trading basé sur la Moyenne Mobile est intégré dans le pack standard de MetaTrader 5. Cet EA (Expert Advisor) est une excellente illustration de l'utilisation de l'indicateur Moyenne Mobile pour le trading.

Le fichier de l'EA, Moving Average.mq5, se trouve dans le dossier "terminal_data_folder\MQL5\Experts\Examples\Moving Average". Cet EA sert d'exemple pour l'utilisation des indicateurs techniques, des fonctions d'historique de trading et des classes de trading de la Bibliothèque Standard. En outre, cet EA intègre un système de gestion des fonds basé sur les résultats des trades.

Voyons maintenant la structure de cet Expert Advisor et son fonctionnement.

1. Propriétés de l'EA

//+------------------------------------------------------------------+
//|                                              Moyennes Mobiles.mq5 |
//|                                              Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2009-2013, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

Les cinq premières lignes contiennent un commentaire, les trois lignes suivantes définissent les propriétés du programme MQL5 (droits d'auteur, lien, version) utilisant les directives préprocesseur #property.

Lorsque vous exécutez l'Expert Advisor, ces informations s'affichent dans l'onglet "Commun" :


Figure 1. Paramètres Communs de l'EA Moyenne Mobile


1.2. Fichiers Inclus

Ensuite, la directive #include indique au compilateur d'inclure le fichier "Trade.mqh".

Ce fichier fait partie de la Bibliothèque Standard, il contient la classe CTrade pour un accès facile aux fonctions de trading.

#include <Trade\Trade.mqh>

Le nom du fichier d'inclusion est affiché entre crochets "<>;", donc le chemin est défini par rapport au répertoire : "terminal_data_folder\Include".

1.3 Entrées

Ensuite, on trouve le type, le nom, les valeurs par défaut et un commentaire. Leur rôle est illustré à la figure 2.

input double MaximumRisk        = 0.02;    // Risque Maximum en pourcentage
input double DecreaseFactor     = 3;       // Facteur de diminution
input int    MovingPeriod       = 12;      // Période de la Moyenne Mobile
input int    MovingShift        = 6;      // Décalage de la Moyenne Mobile

Les paramètres MaximumRisk et DecreaseFactor seront utilisés pour la gestion des fonds, MovingPeriod et MovingShift définissent la période et le décalage de l'indicateur Moyenne Mobile qui sera utilisé pour vérifier les conditions de trading.

Le texte dans le commentaire de la ligne de paramètre d'entrée, ainsi que les valeurs par défaut, sont affichés dans l'onglet "Options" au lieu du nom du paramètre d'entrée :


Fig. 2. Paramètres d'Entrée de l'EA Moyenne Mobile

1.4. Variables Globales


Puis, la variable globale ExtHandle est déclarée. Elle sera utilisée pour stocker le handle de l'indicateur Moyenne Mobile.

//---
int   ExtHandle=0;

Elle est suivie de six fonctions. Le but de chacune d'elles est décrit dans le commentaire avant le corps de la fonction :

  1. TradeSizeOptimized() - Calcule la taille de lot optimale ;
  2. CheckForOpen() - Vérifie les conditions d'ouverture de position ;
  3. CheckForClose() - Vérifie les conditions de fermeture de position ;
  4. OnInit() - Fonction d'initialisation de l'Expert ;
  5. OnTick() - Fonction tick de l'Expert ;
  6. OnDeinit() - Fonction de désinitialisation de l'Expert ;

Les trois dernières fonctions sont des fonctions de gestion d'événements ; les trois premières fonctions de service sont appelées dans leur code.


2. Fonctions de Gestion des Événements

2.1. La fonction d'initialisation OnInit()

La fonction OnInit() est appelée une fois lors du premier démarrage de l'Expert Advisor. En général, dans le gestionnaire d'événements OnInit(), l'EA est préparé pour fonctionner : les paramètres d'entrée sont vérifiés, les indicateurs et les paramètres sont initialisés, etc. En cas d'erreurs critiques, lorsque le travail ultérieur n'a pas de sens, la fonction se termine avec le code de retour INIT_FAILED.

//+------------------------------------------------------------------+
//| Fonction d'initialisation de l'Expert                                   |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//---
   ExtHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE);
   if(ExtHandle==INVALID_HANDLE)
     {
      printf("Erreur lors de la création de l'indicateur MA");
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }

Étant donné que le trading de l'EA est basé sur l'indicateur Moyenne Mobile, en appelant iMA(), l'indicateur Moyenne Mobile est créé et son handle est sauvegardé dans la variable globale ExtHandle.

En cas d'erreur, OnInit() se termine avec un code de retour INIT_FAILED - c'est la manière correcte de terminer le fonctionnement de l'EA/l'indicateur en cas d'initialisation infructueuse.


2.2. La fonction OnTick()

La fonction OnTick() est appelée chaque fois qu'une nouvelle cotation est reçue pour le symbole du graphique sur lequel l'EA est exécuté.

//+------------------------------------------------------------------+
//| Fonction tick de l'Expert                                             |
//+------------------------------------------------------------------+
void OnTick(void)
  {
//---
   if(PositionSelect(_Symbol))
      CheckForClose();
   else
      CheckForOpen();
//---
  }

La fonction PositionSelect() est utilisée pour définir s'il existe une position ouverte pour le symbole actuel.

Si des positions sont ouvertes, la fonction CheckForClose() est appelée, qui analyse l'état actuel du marché et ferme la position ouverte, sinon CheckForOpen() est appelée, qui vérifie les conditions d'entrée sur le marché et ouvre une nouvelle position si de telles conditions se présentent.


2.3. La fonction de désinitialisation OnDeInit()

OnDeInit() est appelée lorsqu'un EA est retiré du graphique. Si un programme place des objets graphiques pendant son fonctionnement, ils peuvent être retirés du graphique.

//+------------------------------------------------------------------+
//| Fonction de désinitialisation de l'Expert                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+

Dans ce cas, aucune action n'est effectuée lors de la désinitialisation de l'Expert Advisor.


3. Fonctions de Service

3.1. Fonction TradeSizeOptimized()

Cette fonction calcule et retourne la valeur de la taille de lot optimale pour l'ouverture de position avec le niveau de risque spécifié et les résultats du trading.

//+------------------------------------------------------------------+
//| Calculer la taille de lot optimale                                       |
//+------------------------------------------------------------------+
double TradeSizeOptimized(void)
  {
   double price=0.0;
   double margin=0.0;
//--- Calculer la taille de lot
   if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price))
      return(0.0);
   if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin))
      return(0.0);
   if(margin<=0.0)
      return(0.0);

   double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_FREEMARGIN)*MaximumRisk/margin,2);
//--- calculer la longueur de la série de pertes consécutives
   if(DecreaseFactor>0)
     {
      //--- demander l'historique de trading complet
      HistorySelect(0,TimeCurrent());
      //--
      int    orders=HistoryDealsTotal();  // le nombre total de transactions
      int    losses=0                    // le nombre de transactions perdantes dans la série

      for(int i=orders-1;i>=0;i--)
        {
         ulong ticket=HistoryDealGetTicket(i);
         if(ticket==0)
           {
            Print("Échec de HistoryDealGetTicket, pas d'historique de trades");
            break;
         }
         //--- vérification du symbole de la transaction
         if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol)
            continue;
         //--- vérification du profit
         double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);
         if(profit>0.0)
            break;
         if(profit<0.0)
            losses++;
    }
      //---
      if(losses>1)
         lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
     }
//--- normaliser et vérifier les valeurs autorisées du volume de trading
   double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   lot=stepvol*NormalizeDouble(lot/stepvol,0);

   double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   if(lot<minvol)
      lot=minvol;

   double maxvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
   if(lot>maxvol)
      lot=maxvol;
//--- retourner la valeur du volume de trading
   return(lot);
  }

La fonction SymbolInfoDouble() est utilisée pour vérifier la disponibilité des prix pour le symbole actuel, ensuite la fonction OrderCalcMargin() est utilisée pour demander la marge requise pour placer un ordre (dans ce cas, un ordre d'achat). La taille de lot initiale est déterminée à partir de la valeur de la marge requise pour placer un ordre, la marge libre du compte (AccountInfoDouble(ACCOUNT_FREEMARGIN)) et la valeur maximale de risque autorisée spécifiée dans le paramètre d'entrée MaximumRisk.

Si la valeur du paramètre d'entrée DecreaseFactor est positive, les transactions dans l'historique sont analysées et la taille du lot est ajustée en tenant compte de l'information sur la série maximale de pertes : la taille de lot initiale est multipliée par la taille (1-pertes/DecreaseFactor).

Ensuite, le volume de trading est "arrondi" à une valeur qui est un multiple du minimum autorisé de volume (stepvol) pour le symbole actuel. Les valeurs minimale (minvol) et maximale (maxvol) du volume de trading sont également demandées, et si la valeur de lot dépasse les limites autorisées, elle est ajustée. En conséquence, la fonction retourne la valeur calculée du volume de trading.


3.2. Fonction CheckForOpen()

CheckForOpen() est utilisée pour vérifier les conditions d'ouverture de position et l'ouvre lorsque des conditions de trading se présentent (dans ce cas, lorsque le prix traverse la moyenne mobile).

//+------------------------------------------------------------------+
//| Vérifier les conditions d'ouverture de position                               |
//+------------------------------------------------------------------+
void CheckForOpen(void)
  {
   MqlRates rt[2];
//--- copier les valeurs de prix
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("Échec de CopyRates de ",_Symbol," échoué, pas d'historique");
      return;
     }
//--- Trader uniquement sur le premier tick de la nouvelle bougie
   if(rt[1].tick_volume>1)
      return;
//--- Obtenir la valeur actuelle de l'indicateur Moyenne Mobile 
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer de iMA échoué, pas de données");
      return;
     }
//--- vérifier les signaux
   ENUM_ORDER_TYPE signal=WRONG_VALUE;

   if(rt[0].open>ma[0] && rt[0].close<ma[0])
      signal=ORDER_TYPE_SELL    // condition de vente
   else
       {
      if(rt[0].open<ma[0] && rt[0].close>ma[0])
         signal=ORDER_TYPE_BUY  // condition d'achat
     }
//--- vérifications supplémentaires
   if(signal!=WRONG_VALUE)
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         if(Bars(_Symbol,_Period)>100)
           {
            CTrade trade;
            trade.PositionOpen(_Symbol,signal,TradeSizeOptimized(),
                               SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ? SYMBOL_BID:SYMBOL_ASK),
                               0,0);
           }
//---
  }

Lors du trading en utilisant la moyenne mobile, il est nécessaire de vérifier si le prix traverse la moyenne mobile. En utilisant la fonction CopyRates(), deux valeurs des prix actuels sont copiées dans le tableau de structures rt[], rt[1] correspond à la bougie actuelle, rt[0] - bougie complétée.

Une nouvelle bougie commence par le contrôle du volume des ticks de la bougie actuelle s'il est égal à 1, alors une nouvelle bougie a commencé. Il convient de noter que cette méthode de détection d'une nouvelle bougie peut échouer dans certains cas (lorsque des cotations arrivent par paquets), donc le fait de commencer une nouvelle formation de bougie doit être effectué en sauvegardant et en comparant le temps de la cotation actuelle (voir IsNewBar).

La valeur actuelle de l'indicateur Moyenne Mobile est demandée en utilisant la fonction CopyBuffer() et est sauvegardée dans le tableau ma[] qui ne contient qu'une seule valeur. Le programme vérifie ensuite si le prix a traversé la moyenne mobile et effectue des vérifications supplémentaires (si le trading à l'aide de l'EA est possible et la présence de bougies dans l'historique). Si cela réussit, une position appropriée pour le symbole est ouverte en appelant la méthode PositionOpen() de l'objet de trading (une instance de CTrade).

Le prix d'ouverture de la position est défini en utilisant la fonction SymbolInfoDouble() qui retourne le prix Bid ou Ask selon la valeur de la variable signal. Le volume de la position est déterminé en appelant TradeSizeOptimized() décrit ci-dessus.


3.3. Fonction CheckForClose()

CheckForClose() vérifie les conditions de fermeture de position et la ferme si des conditions de fermeture se présentent.

//+------------------------------------------------------------------+
//| Vérifier les conditions de fermeture de position                              |
//+------------------------------------------------------------------+
void CheckForClose(void)
  {
   MqlRates rt[2];
//--- Copier les valeurs de prix
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("Échec de CopyRates de ",_Symbol," échoué, pas d'historique");
      return;
     }
//--- Trader uniquement sur le premier tick de la nouvelle bougie
   if(rt[1].tick_volume>1)
      return;
//--- obtenir la valeur actuelle de l'indicateur Moyenne Mobile
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer de iMA échoué, pas de données");
      return;
     }
//--- obtenir le type de la position sélectionnée précédemment en utilisant PositionSelect()
   bool signal=false;
   long type=PositionGetInteger(POSITION_TYPE);

   if(type==(long)POSITION_TYPE_BUY   && rt[0].open>ma[0] && rt[0].close<ma[0])
      signal=true;
   if(type==(long)POSITION_TYPE_SELL  && rt[0].open<ma[0] && rt[0].close>ma[0])
      signal=true;
//--- vérifications supplémentaires
   if(signal)
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         if(Bars(_Symbol,_Period)>100)
           {
            CTrade trade;
            trade.PositionClose(_Symbol,3);
           }
//---
  }

L'algorithme de la fonction CheckForClose() est similaire à celui de CheckForOpen(). En fonction de la direction des positions ouvertes actuelles, les conditions de fermeture sont vérifiées (croisement de prix vers le bas pour acheter ou vers le haut pour vendre). Une position ouverte est fermée en appelant la méthode PositionClose() de l'objet de trading (instance de CTrade).


4. Backtesting

Les meilleures valeurs des paramètres peuvent être trouvées en utilisant le Testeur de Stratégies du terminal MetaTrader 5.

Par exemple, lors de l'optimisation du paramètre MovingPeriod dans l'intervalle 2012.01.01-2013.08.01, les meilleurs résultats sont obtenus avec MovingPeriod=45 :

Résultats de Backtesting de l'Expert Advisor Moyenne Mobile

Résultats de Backtesting de l'Expert Advisor Moyenne Mobile

Conclusions :

L'Expert Advisor Moyenne Mobile inclus dans le pack standard de MetaTrader 5 est un exemple d'utilisation des indicateurs techniques, des fonctions d'historique de trading et des classes de trading de la Bibliothèque Standard. De plus, l'EA comprend un système de gestion des fonds basé sur les résultats des trades.


Articles connexes

Commentaire (0)