English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
MQL5 Cookbook : Utilisation d'indicateurs pour définir les conditions de trading dans les Expert Advisors

MQL5 Cookbook : Utilisation d'indicateurs pour définir les conditions de trading dans les Expert Advisors

MetaTrader 5Exemples | 13 janvier 2022, 10:41
217 0
Anatoli Kazharski
Anatoli Kazharski

Introduction

Dans cet article, l'Expert Advisor sera enrichi d'indicateurs dont les valeurs seront utilisées pour vérifier les conditions d'ouverture des positions. Pour le pimenter, nous allons créer une liste déroulante dans les paramètres externes pour pouvoir sélectionner un des trois indicateurs de trading.

Rappelez-vous, juste au cas où : nous continuons à modifier l'Expert Advisor sur lequel nous avons travaillé tout au long des articles précédents de la série MQL5 Cookbook. La dernière version de l'Expert Advisor peut être téléchargée à partir de l'article intitulé "MQL5 Cookbook : L'histoire des transactions et la bibliothèque de fonctions pour l'obtention de propriétés de position".

De plus, cet article comportera une fonction que nous allons créer pour vérifier si les opérations de trading peuvent ou non être effectuées. La fonction d'ouverture de position sera modifiée afin de permettre à l'Expert Advisor de déterminer le mode de trading (Exécution instantanée et Exécution au marché).

Étant donné que le code de l'Expert Advisor, suite à toutes les améliorations et améliorations apportées dans les articles précédents, dépasse déjà les 1 500 lignes, il deviendra de moins en moins pratique à chaque nouvelle fonctionnalité ajoutée. Ainsi, la solution logique consiste à le diviser en plusieurs catégories en tant que fichiers de bibliothèque distincts. Maintenant que les objectifs sont fixés, commençons.

 

Développement de l’Expert Advisor

Nous plaçons le code source de l'Expert Advisor (*.mq5) de l'article précédent dans un dossier séparé, TestIndicatorConditions, dans lequel nous devons créer le sous-dossier Include. C'est le dossier dans lequel nous allons créer les fichiers d'inclusion (*.mqh). Ils peuvent être générés à l'aide de l'assistant MQL5 (Ctrl+N) ou créés manuellement dans le répertoire requis en tant que fichiers texte standard (*.txt) et renommés en *.mqh.

Vous trouverez ci-dessous les noms et les commentaires de tous les fichiers d'inclusion créés :

  • Enums.mqh contiendra toutes les énumérations ;
  • InfoPanel.mqh comportera des fonctions pour configurer le panneau d'informations, créer et supprimer des objets graphiques ;
  • Errors.mqh couvrira toutes les fonctions qui renvoient des codes d'erreur et des raisons de désinitialisation ;
  • TradeSignals.mqh comportera des fonctions qui remplissent des tableaux avec des prix et des valeurs d'indicateur, ainsi qu'un bloc de signal ;
  • TradeFunctions.mqh contiendra des fonctions de trading ;
  • ToString.mqh couvrira les fonctions qui convertissent des valeurs numériques en valeurs de chaîne de caractères ;
  • Auxiliary.mqh sera utilisé pour d'autres fonctions auxiliaires.

Pour inclure ces bibliothèques dans le fichier principal, nous utilisons la directive #include. Étant donné que le fichier principal de l'Expert Advisor et le dossier du fichier d'inclusion (Include) se trouvent dans le même dossier, le code d'inclusion des fichiers sera le suivant :

//--- Include custom libraries
#include "Include\Enums.mqh"
#include "Include\InfoPanel.mqh"
#include "Include\Errors.mqh"
#include "Include\TradeSignals.mqh"
#include "Include\TradeFunctions.mqh"
#include "Include\ToString.mqh"
#include "Include\Auxiliary.mqh"

Ensuite, nous pourrons les ouvrir et les modifier et déplacer une partie du code source du fichier principal de l'Expert Advisor.

Pour naviguer correctement dans le code, des références aux fichiers d'en-tête adjacents, ainsi qu'au fichier principal de l'Expert Advisor seront ajoutées à chaque fichier d'en-tête. Par exemple, pour notre bibliothèque de fonctions de trading, TradeFunctions.mqh, cela ressemblera à ceci :

//--- Connection with the main file of the Expert Advisor
#include "..\TestIndicatorConditions.mq5"
//--- Include custom libraries
#include "Enums.mqh"
#include "InfoPanel.mqh"
#include "Errors.mqh"
#include "TradeSignals.mqh"
#include "ToString.mqh"
#include "Auxiliary.mqh"

Pour les fichiers de même niveau d'imbrication, il suffit de spécifier simplement le nom. Pour monter d'un niveau, vous devez mettre deux points avant la barre oblique inverse dans le chemin.

Ajoutons l'énumération des indicateurs dans le fichier Enums.mqh. À des fins d'illustration, dans cet Expert Advisor, nous utiliserons deux indicateurs standard (Moving Average et Commodity Channel Index) et un indicateur personnalisé (MultiRange_PCH). Le dénombrement sera le suivant :

//--- Indicators
enum ENUM_INDICATORS
  {
   MA       = 0, // Moving Average
   CCI      = 1, // CCI
   PCH      = 2  // Price Channel
  };

Les paramètres externes sont modifiés comme suit :

//--- External parameters of the Expert Advisor
sinput   long              MagicNumber=777;        // Magic number
sinput   int               Deviation=10;           // Slippage
input    ENUM_INDICATORS   Indicator=MA;           // Indicator
input    int               IndicatorPeriod=5;      // Indicator period
input    int               IndicatorSegments=2;    // Number of one direction indicator segments
input    double            Lot=0.1;                // Lot
input    double            VolumeIncrease=0.1;     // Position volume increase
input    double            VolumeIncreaseStep=10;  // Step for volume increase
input    double            StopLoss=50;            // Stop Loss
input    double            TakeProfit=100;         // Take Profit
input    double            TrailingStop=10;        // Trailing Stop
input    bool              Reverse=true;           // Position reversal
sinput   bool              ShowInfoPanel=true;     // Display of the info panel

Comme mentionné ci-dessus, vous pourrez sélectionner un des trois indicateurs dans la liste déroulante du paramètre Indicateur.

Il n'y a qu'un seul paramètre applicable à tous les indicateurs pour lesquels la période d'indicateur peut être définie - IndicatorPeriod. Le paramètre NumberOfBars de la version précédente de l'Expert Advisor a été renommé en IndicatorSegments et désigne désormais le nombre de barres pendant lesquelles un indicateur donné doit monter/descendre pour satisfaire la condition d'ouverture de position.

De plus, nous avons ajouté un autre paramètre externe, VolumeIncreaseStep, qui peut être utilisé pour définir le pas d'augmentation du volume en points.

La valeur de la variable AllowedNumberOfBars (maintenant AllowedNumberOfSegments) était auparavant ajustée dans la fonction personnalisée GetBarsData(). Il sera maintenant placé dans une fonction distincte et appelé uniquement à l'initialisation.

Etant donné que la condition d'ouverture de position sera désormais vérifiée à l'aide de valeurs indicatrices, la valeur à attribuer sera toujours supérieure de deux. En d'autres termes, si la variable externe IndicatorSegments reçoit la valeur 1, la variable AllowedNumberOfSegments se verra attribuer la valeur 3, car pour satisfaire la condition (par exemple pour un BUY), la valeur de l'indicateur sur la barre complétée doit être supérieur à celui de la barre précédente. À cette fin, nous devons obtenir les trois dernières valeurs d'indicateur.

Vous trouverez ci-dessous le code de la fonction CorrectInputParameters() :

//+------------------------------------------------------------------+
//| Adjusting input parameters                                       |
//+------------------------------------------------------------------+
void CorrectInputParameters()
  {
//--- Adjust the number of bars for the position opening condition
   if(AllowedNumberOfSegments<=0)
     {
      if(IndicatorSegments<=1)
         AllowedNumberOfSegments=3;                     // At least three bars are required
      if(IndicatorSegments>=5)
         AllowedNumberOfSegments=5;                     // but no more than 7
      else
         AllowedNumberOfSegments=IndicatorSegments+1;   // and always greater by two
     }
  }

Avant de commencer à traiter les indicateurs, créons une fonction qui vérifiera si le trading est autorisé - CheckTradingPermission(). Si le trading n'est pas autorisé pour l'une des raisons énumérées dans la fonction, la valeur zéro sera renvoyée. Cela signifie que le prochain essai devra être fait sur la barre suivante.

//+------------------------------------------------------------------+
//| Checking if trading is allowed                                   |
//+------------------------------------------------------------------+
bool CheckTradingPermission()
  {
//--- For real-time mode
   if(IsRealtime())
     {
      //--- Checking server connection
      if(!TerminalInfoInteger(TERMINAL_CONNECTED))
         return(1);
      //--- Permission to trade at the running program level
      if(!MQL5InfoInteger(MQL5_TRADE_ALLOWED))
         return(2);
      //--- Permission to trade at the terminal level
      if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         return(3);
      //--- Permission to trade for the current account
      if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED))
         return(4);
      //--- Permission to trade automatically for the current account
      if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT))
         return(5);
     }
//---
   return(0);
  }

Venons-en maintenant au point principal de l'article. Pour accéder aux valeurs de l'indicateur, nous devons d'abord obtenir son handle. Cela se fait à l'aide de fonctions spéciales dont les noms sont constitués du nom abrégé de l'indicateur et du symbole 'i' qui le précède.

Par exemple, l'indicateur de moyenne mobile Moving Average a la fonction correspondante iMA(). Tous les handles de l'indicateur standard dans le terminal MetaTrader 5 peuvent être obtenues en utilisant ces fonctions. La liste complète est disponible dans la section Référence MQL5 intitulée Indicateurs techniques. Si vous avez besoin d'obtenir le handle d'un indicateur personnalisé, utilisez la fonction iCustom().

Nous allons implémenter la fonction GetIndicatorHandle() où, selon l'indicateur sélectionné dans le paramètre Indicator, la valeur du handle de l'indicateur correspondant sera affectée à la variable globale indicator_handle. Le code de la fonction se trouve dans notre bibliothèque de fonctions de signal de trading (le fichier \Include\TradeSignals.mqh), tandis que la variable avec le handle de l'indicateur se trouve dans le fichier principal de l'Expert Advisor.

//+------------------------------------------------------------------+
//| Getting the indicator handle                                     |
//+------------------------------------------------------------------+
void GetIndicatorHandle()
  {
//--- If the Moving Average indicator is selected
   if(Indicator==MA)
      indicator_handle=iMA(_Symbol,Period(),IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE);
//--- If the CCI indicator is selected
   if(Indicator==CCI)
      indicator_handle=iCCI(_Symbol,Period(),IndicatorPeriod,PRICE_CLOSE);
//--- If the MultiRange_PCH indicator is selected
   if(Indicator==PCH)
      indicator_handle=iCustom(_Symbol,Period(),"MultiRange_PCH",IndicatorPeriod);
//--- If the indicator handle could not be obtained
   if(indicator_handle==INVALID_HANDLE)
      Print("Failed to get the indicator handle!");
  }

De plus, nous créons la fonction GetDataIndicators() où en utilisant les handles d'indicateur obtenues, nous pouvons obtenir leurs valeurs. Cela se fait à l'aide de la fonction CopyBuffer() de la même manière que pour obtenir des valeurs de barre à l'aide des fonctions CopyTime(), CopyClose(), CopyOpen(), CopyHigh() et CopyLow() considérées dans l'article intitulé "MQL5 Cookbook : Analyse des propriétés de position dans le MetaTrader 5 Strategy Tester".

Étant donné que l'indicateur peut avoir plusieurs tampons (lignes de valeurs), l'index de tampon est passé à la fonction CopyBuffer() en tant que deuxième paramètre. Les indices de tampon pour les indicateurs standard peuvent être trouvés dans la référence MQL5. Pour les indicateurs personnalisés, des indices de tampon peuvent être trouvés dans le code, à condition que le code source soit disponible. S'il n'y a pas de code, vous devrez trouver l'index à titre expérimental, en observant comment les conditions sont satisfaites dans le mode de visualisation du Strategy Tester.

Avant cela, nous devons créer des tableaux dynamiques pour les valeurs de tampon d'indicateur dans le fichier principal de l'Expert Advisor :

//--- Arrays for indicator values
double indicator_buffer1[];
double indicator_buffer2[];

Le code de GetIndicatorsData() est fourni ci-dessous :

//+------------------------------------------------------------------+
//| Getting indicator values                                         |
//+------------------------------------------------------------------+
bool GetIndicatorsData()
  {
//--- If the indicator handle has been obtained
   if(indicator_handle!=INVALID_HANDLE)
     {
      //--- For the Moving Average or CCI indicator
      if(Indicator==MA || Indicator==CCI)
        {
         //--- Reverse the indexing order (... 3 2 1 0)
         ArraySetAsSeries(indicator_buffer1,true);
         //--- Get indicator values
         if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments)
           {
            Print("Failed to copy the values ("+
                  _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 array! Error ("+
                  IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));
            return(false);
           }
        }
      //--- For the MultiRange_PCH indicator
      if(Indicator==PCH)
        {
         //--- Reverse the indexing order (... 3 2 1 0)
         ArraySetAsSeries(indicator_buffer1,true);
         ArraySetAsSeries(indicator_buffer2,true);
         //--- Get indicator values
         if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments || 
            CopyBuffer(indicator_handle,1,0,AllowedNumberOfSegments,indicator_buffer2)<AllowedNumberOfSegments)
           {
            Print("Failed to copy the values ("+
                  _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 or indicator_buffer2 array! Error ("+
                  IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));
            return(false);
           }
        }
      //---
      return(true);
     }
//--- If the indicator handle has not been obtained, retry
   else
      GetIndicatorHandle();
//---
   return(false);
  }

La fonction GetTradingSignal() a considérablement changé. Les conditions sont différentes en l'absence du poste et là où le poste existe. Pour les indicateurs Moyenne Mobile et CCI, les conditions sont les mêmes. Pour MultiRange_PCH, ils sont disposés dans un bloc séparé. Pour rendre le code plus lisible et éviter les répétitions, nous créons une fonction auxiliaire, GetSignal(), qui renvoie un signal d'ouverture ou d'inversion de position, à condition qu'une telle position existe et que l'action pertinente soit autorisée par le paramètre externe.

Voici le code de la fonction GetSignal() :

//+------------------------------------------------------------------+
//| Checking the condition and returning a signal                    |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetSignal()
  {
//--- Check conditions for the Moving Average and CCI indicators
   if(Indicator==MA || Indicator==CCI)
     {
      //--- A Sell signal
      if(AllowedNumberOfSegments==3 && 
         indicator_buffer1[1]<indicator_buffer1[2])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==4 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==5 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==6 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4] && 
         indicator_buffer1[4]<indicator_buffer1[5])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments>=7 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4] && 
         indicator_buffer1[4]<indicator_buffer1[5] && 
         indicator_buffer1[5]<indicator_buffer1[6])
         return(ORDER_TYPE_SELL);

      //--- A Buy signal
      if(AllowedNumberOfSegments==3 && 
         indicator_buffer1[1]>indicator_buffer1[2])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==4 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==5 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==6 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4] && 
         indicator_buffer1[4]>indicator_buffer1[5])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments>=7 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4] && 
         indicator_buffer1[4]>indicator_buffer1[5] && 
         indicator_buffer1[5]>indicator_buffer1[6])
         return(ORDER_TYPE_BUY);
     }
//--- Block that checks conditions for the MultiRange_PCH indicator
   if(Indicator==PCH)
     {
      //--- A Sell signal
      if(close_price[1]<indicator_buffer2[1] && 
         open_price[1]>indicator_buffer2[1])
         return(ORDER_TYPE_SELL);
      //--- A Buy signal
      if(close_price[1]>indicator_buffer1[1] && 
         open_price[1]<indicator_buffer1[1])
         return(ORDER_TYPE_BUY);
     }
//--- No signal
   return(WRONG_VALUE);
  }

Le code de la fonction GetTradingSignal() est désormais le suivant :

//+------------------------------------------------------------------+
//| Determining trading signals                                      |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetTradingSignal()
  {
//--- If there is no position
   if(!pos.exists)
     {
      //--- A Sell signal
      if(GetSignal()==ORDER_TYPE_SELL)
         return(ORDER_TYPE_SELL);
      //--- A Buy signal
      if(GetSignal()==ORDER_TYPE_BUY)
         return(ORDER_TYPE_BUY);
     }
//--- If the position exists
   if(pos.exists)
     {
      //--- Get the position type
      GetPositionProperties(P_TYPE);
      //--- Get the last deal price
      GetPositionProperties(P_PRICE_LAST_DEAL);
      //--- Block that checks conditions for the Moving Average and CCI indicators
      if(Indicator==MA || Indicator==CCI)
        {
         //--- A Sell signal
         if(pos.type==POSITION_TYPE_BUY && 
            GetSignal()==ORDER_TYPE_SELL)
            return(ORDER_TYPE_SELL);
         //---
         if(pos.type==POSITION_TYPE_SELL && 
            GetSignal()==ORDER_TYPE_SELL && 
            close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_SELL);
         //--- A Buy signal
         if(pos.type==POSITION_TYPE_SELL && 
            GetSignal()==ORDER_TYPE_BUY)
            return(ORDER_TYPE_BUY);
         //---
         if(pos.type==POSITION_TYPE_BUY && 
            GetSignal()==ORDER_TYPE_BUY && 
            close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_BUY);
        }
      //--- Block that checks conditions for the MultiRange_PCH indicator
      if(Indicator==PCH)
        {
         //--- A Sell signal
         if(pos.type==POSITION_TYPE_BUY && 
            close_price[1]<indicator_buffer2[1] && 
            open_price[1]>indicator_buffer2[1])
            return(ORDER_TYPE_SELL);
         //---
         if(pos.type==POSITION_TYPE_SELL && 

            close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_SELL);
         //--- A Buy signal
         if(pos.type==POSITION_TYPE_SELL && 
            close_price[1]>indicator_buffer1[1] && 
            open_price[1]<indicator_buffer1[1])
            return(ORDER_TYPE_BUY);
         //---
         if(pos.type==POSITION_TYPE_BUY && 
            close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_BUY);
        }
     }
//--- No signal
   return(WRONG_VALUE);
  }

Maintenant, il nous suffit de voir les modes d'exécution instantanée et d'exécution au marché qui font partie des propriétés du symbole et de modifier le code de la fonction d'ouverture de position OpenPosition() en conséquence. Les modes dont les noms sont explicites peuvent également être trouvés dans Référence MQL5 :

  • Exécution Instantanée
  • Execution au Marché

Veuillez noter que lorsque vous utilisez le mode d'exécution au marché, vous ne pouvez pas ouvrir une position avec les niveaux de Stop Loss et de Take Profit définis : vous devez d'abord ouvrir une position puis la modifier, en définissant les niveaux.

À partir de la version 803, Stop Loss et Take Profit peuvent être définis lors de l'ouverture d'une position pour les modes d'exécution au marché et d'exécution d'échange.

Ajoutons le mode d'exécution à la structure des propriétés du symbole :

//--- Symbol properties
struct symbol_properties
  {
   int               digits;           // Number of decimal places in the price
   int               spread;           // Spread in points
   int               stops_level;      // Stops level
   double            point;            // Point value
   double            ask;              // Ask price
   double            bid;              // Bid price
   double            volume_min;       // Minimum volume for a deal
   double            volume_max;       // Maximum volume for a deal
   double            volume_limit;     // Maximum permissible volume for a position and orders in one direction
   double            volume_step;      // Minimum volume change step for a deal
   double            offset;           // Offset from the maximum possible price for a transaction
   double            up_level;         // Upper Stop level price
   double            down_level;       // Lower Stop level price
   ENUM_SYMBOL_TRADE_EXECUTION execution_mode; // Execution mode
  };

En conséquence, nous devons modifier l'énumération ENUM_SYMBOL_PROPERTIES

//--- Enumeration of position properties
enum ENUM_SYMBOL_PROPERTIES
  {
   S_DIGITS          = 0,
   S_SPREAD          = 1,
   S_STOPSLEVEL      = 2,
   S_POINT           = 3,
   S_ASK             = 4,
   S_BID             = 5,
   S_VOLUME_MIN      = 6,
   S_VOLUME_MAX      = 7,
   S_VOLUME_LIMIT    = 8,
   S_VOLUME_STEP     = 9,
   S_FILTER          = 10,
   S_UP_LEVEL        = 11,
   S_DOWN_LEVEL      = 12,
   S_EXECUTION_MODE  = 13,
   S_ALL             = 14
  };

et la fonction GetSymbolProperties() :

case S_EXECUTION_MODE: symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE);   break;
      //---
      case S_ALL           :
         symb.digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
         symb.spread=(int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD);
         symb.stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);
         symb.point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
         symb.ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),symb.digits);
         symb.bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),symb.digits);
         symb.volume_min=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
         symb.volume_max=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
         symb.volume_limit=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_LIMIT);
         symb.volume_step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
         symb.offset=NormalizeDouble(CorrectValueBySymbolDigits(lot_offset*symb.point),symb.digits);
         symb.up_level=NormalizeDouble(symb.ask+symb.stops_level*symb.point,symb.digits);
         symb.down_level=NormalizeDouble(symb.bid-symb.stops_level*symb.point,symb.digits);
         symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE);                       break;
         //---

En conséquence, le code de la fonction OpenPosition() est désormais le suivant :

//+------------------------------------------------------------------+
//| Opening a position                                               |
//+------------------------------------------------------------------+
void OpenPosition(double lot,
                  ENUM_ORDER_TYPE order_type,
                  double price,
                  double sl,
                  double tp,
                  string comment)
  {
//--- Set the magic number in the trading structure
   trade.SetExpertMagicNumber(MagicNumber);
//--- Set the slippage in points
   trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation));
//--- The Instant Execution mode
//    A position can be opened with the Stop Loss and Take Profit levels set
   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT)
     {
      //--- If the position failed to open, print the relevant message
      if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
         Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
     }
//--- The Market Execution mode 
//    First open a position and only then set the Stop Loss and Take Profit levels
//    *** Starting with build 803, Stop Loss and Take Profit can be set upon position opening ***
   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET)
     {
      //--- If there is no position, first open a position and then set Stop Loss and Take Profit
      if(!pos.exists)
        {
         //--- If the position failed to open, print the relevant message
         if(!trade.PositionOpen(_Symbol,order_type,lot,price,0,0,comment))
            Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
         //--- Get the flag of presence/absence of the position
         pos.exists=PositionSelect(_Symbol);
         //--- If the position exists
         if(pos.exists)
           {
            //--- Set Stop Loss and Take Profit
            if(!trade.PositionModify(_Symbol,sl,tp))
               Print("Error modifying the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
           }
        }
      //--- If the position exists, increase its volume and leave the Stop Loss and Take Profit levels unchanged
      else
        {
         //--- If the position failed to open, print the relevant message
         if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
            Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
        }
     }
  }

Il nous reste à ajouter la touche finale, très importante, aux fonctions de gestion des événements :

  • OnInit
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- Adjust the input parameters
       CorrectInputParameters();
    //--- Get indicator handles
       GetIndicatorHandle();
    //--- Initialize the new bar
       CheckNewBar();
    //--- Get the properties
       GetPositionProperties(P_ALL);
    //--- Set the info panel
       SetInfoPanel();
    //---
       return(0);
      }
  • OnDeinit
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- Print the deinitialization reason to the journal
       Print(GetDeinitReasonText(reason));
    //--- When deleting from the chart
       if(reason==REASON_REMOVE)
         {
          //--- Delete all objects relating to the info panel from the chart
          DeleteInfoPanel();
          //--- Delete the indicator handle
          IndicatorRelease(indicator_handle);
         }
      }
  • OnTick
    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick()
      {
    //--- If the bar is not new, exit
       if(!CheckNewBar())
         {
          if(IsVisualMode() || IsRealtime())
            {
             //--- Get the properties and update the values on the panel
             GetPositionProperties(P_ALL);
             //--- Set/update the info panel
             SetInfoPanel();
            }
          return;
         }
    
    //--- If there is a new bar
       else
         {
          //--- If trading is allowed
          if(CheckTradingPermission()==0)
            {
             if(!GetIndicatorsData())
                return;
             GetBarsData();          // Get bar data
             TradingBlock();         // Check the conditions and trade
             ModifyTrailingStop();   // Modify the Trailing Stop level
            }
         }
    //--- Get the properties
       GetPositionProperties(P_ALL);
    //--- Update the info panel
       SetInfoPanel();
      }

Maintenant que toutes les fonctions sont prêtes, nous pouvons optimiser les paramètres. Gardez à l'esprit que vous devez compiler le code à partir du fichier principal du programme.

 

Optimisation des paramètres et test Expert Advisor

Le testeur de stratégie doit être configuré comme indiqué ci-dessous :

Fig. 1. Paramètres du testeur de stratégie.

Fig. 1. Paramètres du testeur de stratégie.

De plus, nous définissons les paramètres de l'Expert Advisor pour l'optimisation (voir également le fichier *.set joint avec les paramètres) :

Fig. 2. Paramètres de l'Expert Advisor.

Fig. 2. Paramètres de l'Expert Advisor.

L'optimisation a pris environ 40 minutes sur un processeur dual-core. Le tableau d'optimisation vous permet d'évaluer en partie la qualité d'un système de trading en fonction des résultats dans la zone de profit :

Fig. 3. Graphique d'optimisation.

Fig. 3. Graphique d'optimisation.

Les résultats du test du facteur de récupération maximal sont les suivants :

Fig. 4. Résultats du test du facteur de récupération maximal.

Fig. 4. Résultats du test du facteur de récupération maximal.

 

Conclusion

L'archive téléchargeable avec les codes sources de l'Expert Advisor est jointe à l'article. Une fois extrait, vous devez placer le dossier de fichiers \TestIndicatorConditions dans <Metatrader 5 terminal>\MQL5\Experts. Pour assurer le bon fonctionnement de l'Expert Advisor, l'indicateur MultiRange_PCH doit être téléchargé et placé dans <Metatrader 5 terminal>\MQL5\Indicators.

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

L'indicateur ZigZag : Approche novatrice et nouvelles solutions L'indicateur ZigZag : Approche novatrice et nouvelles solutions
L'article examine la possibilité de créer un indicateur ZigZag avancé. L'idée d'identifier les nœuds est basée sur l'utilisation de l'indicateur Enveloppes. Nous supposons que nous pouvons trouver une certaine combinaison de paramètres d'entrée pour une série d'enveloppes, où tous les nœuds ZigZag se trouvent dans les limites des bandes d'enveloppes. Par conséquent, nous pouvons essayer de prédire les coordonnées du nouveau nœud.
MQL5 Cookbook : L'historique des transactions et la bibliothèque de fonctions pour obtenir les propriétés de position MQL5 Cookbook : L'historique des transactions et la bibliothèque de fonctions pour obtenir les propriétés de position
Il est temps de résumer brièvement les informations fournies dans les articles précédents sur les propriétés de position. Dans cet article, nous allons créer quelques fonctions supplémentaires pour obtenir les propriétés qui ne peuvent être obtenues qu'après avoir accédé à l'historique des transactions. Nous nous familiariserons également avec les structures de données qui nous permettront d'accéder aux propriétés de position et de symbole de manière plus pratique.
MQL5 Cookbook : Développement d'un cadre pour un système de trading basé sur la stratégie du triple écran MQL5 Cookbook : Développement d'un cadre pour un système de trading basé sur la stratégie du triple écran
Dans cet article, nous allons développer un cadre pour un système de trading basé sur la stratégie Triple Screen dans MQL5. L’Expert Advisor ne sera pas développé à partir de zéro. Au lieu de cela, nous allons simplement modifier le programme de l’article précédent « MQL5 Cookbook : Utilisation des indicateurs pour définir les conditions de trading dans l’Expert Advisors" qui répond déjà largement à notre objectif. Ainsi, l’article montrera également comment vous pouvez facilement modifier des modèles de programmes prêts à l’emploi.
MQL5 Cookbook : Comment éviter les erreurs lors de la définition/modification des niveaux de trade MQL5 Cookbook : Comment éviter les erreurs lors de la définition/modification des niveaux de trade
Dans la continuité de notre travail sur l'Expert Advisor de l'article précédent de la série intitulée "MQL5 Cookbook : Analyse des propriétés des positions dans le testeur de stratégie MetaTrader 5", nous l'améliorerons avec de nombreuses fonctions utiles, ainsi que d'améliorer et d'optimiser celles existantes. L'Expert Advisor aura cette fois des paramètres externes qui peuvent être optimisés dans le testeur de stratégie MetaTrader 5 et ressemblera à certains égards à un simple système de trading.