English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Création d’un Expert Advisor, qui trade sur un certain nombre d’instruments

Création d’un Expert Advisor, qui trade sur un certain nombre d’instruments

MetaTrader 5Exemples | 17 novembre 2021, 15:27
265 0
Nikolay Kositsin
Nikolay Kositsin

Introduction

L’aspect technique de l’implémentation du code du programme afin qu’un seul Expert Advisor, lancé sur un seul graphique, puisse trader avec différents actifs financiers en même temps. En général, ce n’était pas un problème, même dans MQL4. Mais ce n’est qu’avec l’avènement du terminal client MetaTrader 5 que les traders ont finalement eu la possibilité d’effectuer une analyse complète du travail de tels automates, en utilisant des testeurs de stratégie.

Donc, maintenant, les automates multi-devises deviendront plus populaires que jamais, et nous pouvons prévoir un regain d’intérêt pour l’élaboration de tels systèmes de trading. Mais le principal problème de l’implémentation de tels robots réside dans le fait que leurs dimensions dans le code du programme s’étendent, au mieux, dans une progression arithmétique, ce qui n’est pas facile à accepter pour un programmeur typique.

Dans cet article, nous allons écrire un Expert Advisor multi-devises simple, dans lequel les défauts de structure, s’ils ne sont pas absents, du moins sont minimisés.


1. Implémentation d’un système simple de suivi des tendances

En fait, nous pourrions commencer avec un système de trading extrêmement simple, en suivant la tendance sur la base d’un terminal intégré d’un indicateur technique Triple Moyenne Mobile Exponentielle. Il s’agit d’un algorithme très simple, qui ne nécessite pas de commentaires spéciaux, et que nous allons maintenant incarner dans le code du programme.

Mais avant tout, je voudrais tirer les conclusions les plus générales sur l’Expert Advisor. Il est normal de commencer par le bloc de paramètres Expert Advisor entrants, déclarés au niveau mondial.

Donc, tout d’abord, nous devons choisir les actifs financiers avec lesquels nous allons travailler. Cela peut être fait en utilisant des variables d’entrée de ligne, dans lesquels les symboles de la ressource peuvent être stockés. Maintenant, il serait bien d’avoir un commutateur d’interdiction de trade pour chaque actif financier, ce qui permettrait de désactiver les opérations de trading par l’actif.

Évidemment , chaque actif doit être associé à ses paramètres de trading individuels de Excédents de Perte ,Prise de Bénéfice , le volume de la position ouverte et glissement. Et pour des raisons évidentes, les paramètres d’entrée de l’indicateur Triple Moyenne Mobile Exponentielle pour chaque puce de trading doivent être individuels.

Voici un dernier bloc de variables d’entrée pour une seule puce, exécuté conformément à ces arguments. Les blocs restants ne diffèrent que par les nombres dans les noms des paramètres d’entrée de l’Expert Advisor. Pour cet exemple, je me suis limité à seulement douze actifs financiers, bien qu’idéalement il n’y ait pas de limitations logicielles pour le nombre de tels blocs.

Nous avons seulement besoin de quelque chose pour trader! Et le plus important - notre PC doit disposer de suffisamment de ressources pour résoudre ce problème.

input string                Symb0 = "EURUSD";
input  bool                Trade0 = true; 
input int                    Per0 = 15; 
input ENUM_APPLIED_PRICE ApPrice0 = PRICE_CLOSE;
input int                 StLoss0 = 1000;
input int               TkProfit0 = 2000;
input double                Lots0 = 0.1;
input int               Slippage0 = 30;

Maintenant que nous avons compris les variables au niveau mondial, nous pouvons procéder à l’élaboration du code dans la fonction OnTick(). L’option la plus rationnelle ici serait la division de l’algorithme de réception des signaux de trading et la partie trading réelle de l’Expert Advisor en deux fonctions personnalisées.

Et puisque l’Expert Advisor fonctionne avec douze actifs financiers en même temps, il doit également y avoir douze appels de ces fonctions dans le bloc OnTick(). 

Évidemment, le premier paramètre d’entrée de ces fonctions devrait être un numéro unique, sous lequel ces actifs de trading seront répertoriés. Pour des raisons évidentes,le deuxième paramètre d’entrée sera le nom de ligne de l’actif financier de trading.

Pour le rôle du troisième paramètre, nous allons définir une variable logique pour résoudre le trade. Ensuite, pour l’algorithme de détermination des signaux de trading, suivez les signaux indicateurs d’entrée, et pour une fonction de trading - la distance aux ordres en attente, le volume de position et le glissement (glissement admissible de la position ouverte du prix).

Afin de transférer les signaux de trading d’une fonction à une autre, les tableaux statiques doivent être définis comme paramètres de la fonction, qui dérivent leurs valeurs par une référence. Il s’agit de la version finale du code proposé pour la fonction OnTick().

void OnTick()
  {
//--- declare variables arrays for trade signals 
   static bool UpSignal[12], DnSignal[12], UpStop[12], DnStop[12];
  
//--- get trade signals
   TradeSignalCounter( 0, Symb0,  Trade0,  Per0,  ApPrice0,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 1, Symb1,  Trade1,  Per1,  ApPrice1,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 2, Symb2,  Trade2,  Per2,  ApPrice2,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 3, Symb3,  Trade3,  Per3,  ApPrice3,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 4, Symb4,  Trade4,  Per4,  ApPrice4,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 5, Symb5,  Trade5,  Per5,  ApPrice5,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 6, Symb6,  Trade6,  Per6,  ApPrice6,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 7, Symb7,  Trade7,  Per7,  ApPrice7,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 8, Symb8,  Trade8,  Per8,  ApPrice8,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter( 9, Symb9,  Trade9,  Per9,  ApPrice9,  UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter(10, Symb10, Trade10, Per10, ApPrice10, UpSignal, DnSignal, UpStop, DnStop);
   TradeSignalCounter(11, Symb11, Trade11, Per11, ApPrice11, UpSignal, DnSignal, UpStop, DnStop);
  
//--- perform trade operations
   TradePerformer( 0, Symb0,  Trade0,  StLoss0,  TkProfit0,  Lots0,  Slippage0,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 1, Symb1,  Trade1,  StLoss1,  TkProfit1,  Lots1,  Slippage1,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 2, Symb2,  Trade2,  StLoss2,  TkProfit2,  Lots2,  Slippage2,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 3, Symb3,  Trade3,  StLoss3,  TkProfit3,  Lots3,  Slippage3,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 4, Symb4,  Trade4,  StLoss4,  TkProfit4,  Lots4,  Slippage4,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 5, Symb5,  Trade5,  StLoss5,  TkProfit5,  Lots5,  Slippage5,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 6, Symb6,  Trade6,  StLoss6,  TkProfit6,  Lots6,  Slippage6,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 7, Symb7,  Trade7,  StLoss7,  TkProfit7,  Lots7,  Slippage7,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 8, Symb8,  Trade8,  StLoss8,  TkProfit8,  Lots8,  Slippage8,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 9, Symb9,  Trade9,  StLoss9,  TkProfit9,  Lots9,  Slippage9,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer(10, Symb10, Trade10, StLoss10, TkProfit10, Lots10, Slippage10, UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer(11, Symb11, Trade11, StLoss11, TkProfit11, Lots11, Slippage11, UpSignal, DnSignal, UpStop, DnStop); 
//---
  }

Dans la fonction TradeSignalCounter(), il suffit d’obtenir la poignée de l’indicateur technique Triple Moyenne Mobile Exponentielle une fois au début de chaque puce, puis à chaque remplacement de barre pour calculer les signaux de trading.

Ce schéma relativement simple avec l’implémentation dans le code commence à déborder de détails mineurs.

bool TradeSignalCounter(int Number,
                        string Symbol_,
                        bool Trade,
                        int period,
                        ENUM_APPLIED_PRICE ApPrice,
                        bool &UpSignal[],
                        bool &DnSignal[],
                        bool &UpStop[],
                        bool &DnStop[])
  {
//--- check if trade is prohibited
   if(!Trade)return(true);

//--- declare variable to store final size of variables arrays
   static int Size_=0;

//--- declare array to store handles of indicators as static variable
   static int Handle[];

   static int Recount[],MinBars[];
   double TEMA[4],dtema1,dtema2;

//--- initialization
   if(Number+1>Size_) // Entering the initialization block only on first start
     {
      Size_=Number+1; // For this number entering the block is prohibited

      //--- change size of variables arrays
      ArrayResize(Handle,Size_);
      ArrayResize(Recount,Size_);
      ArrayResize(MinBars,Size_);

      //--- determine minimum number of bars, sufficient for calculation 
      MinBars[Number]=3*period;

      //--- setting array elements to 0
      DnSignal[Number] = false;
      UpSignal[Number] = false;
      DnStop  [Number] = false;
      UpStop  [Number] = false;

      //--- use array as timeseries
      ArraySetAsSeries(TEMA,true);

      //--- get indicator's handle
      Handle[Number]=iTEMA(Symbol_,0,period,0,ApPrice);
     }

//--- check if number of bars is sufficient for calculation 
   if(Bars(Symbol_,0)<MinBars[Number])return(true);
//--- get trade signals 
   if(IsNewBar(Number,Symbol_,0) || Recount[Number]) // Entering the block on bar change or on failed copying of data
     {
      DnSignal[Number] = false;
      UpSignal[Number] = false;
      DnStop  [Number] = false;
      UpStop  [Number] = false;

      //--- using indicator's handles, copy values of indicator's
      //--- buffers into static array, specially prepared for this purpose
      if(CopyBuffer(Handle[Number],0,0,4,TEMA)<0)
        {
         Recount[Number]=true; // As data were not received, we should return 
                               // into this block (where trade signals are received) on next tick!
         return(false);        // Exiting the TradeSignalCounter() function without receiving trade signals
        }

      //--- all copy operations from indicator buffer are successfully completed
      Recount[Number]=false; // We may not return to this block until next change of bar

      int Digits_ = int(SymbolInfoInteger(Symbol_,SYMBOL_DIGITS)+4);
      dtema2 = NormalizeDouble(TEMA[2] - TEMA[3], Digits_);
      dtema1 = NormalizeDouble(TEMA[1] - TEMA[2], Digits_);

      //---- determining the input signals
      if(dtema2 > 0 && dtema1 < 0) DnSignal[Number] = true;
      if(dtema2 < 0 && dtema1 > 0) UpSignal[Number] = true;

      //---- determining the output signals
      if(dtema1 > 0) DnStop[Number] = true;
      if(dtema1 < 0) UpStop[Number] = true;
     }
//----+
   return(true);
  }

Dans cet aspect, le code de la fonction TradePerformer() s’avère être assez simple:

bool TradePerformer(int    Number,
                    string Symbol_,
                    bool   Trade,
                    int    StLoss,
                    int    TkProfit,
                    double Lots,
                    int    Slippage,
                    bool  &UpSignal[],
                    bool  &DnSignal[],
                    bool  &UpStop[],
                    bool  &DnStop[])
  {
//--- check if trade is prohibited
   if(!Trade)return(true);

//--- close opened positions 
   if(UpStop[Number])BuyPositionClose(Symbol_,Slippage);
   if(DnStop[Number])SellPositionClose(Symbol_,Slippage);

//--- open new positions
   if(UpSignal[Number])
      if(BuyPositionOpen(Symbol_,Slippage,Lots,StLoss,TkProfit))
         UpSignal[Number]=false; //This trade signal will be no more on this bar!
//---
   if(DnSignal[Number])
      if(SellPositionOpen(Symbol_,Slippage,Lots,StLoss,TkProfit))
         DnSignal[Number]=false; //This trade signal will be no more on this bar!
//---
   return(true);
  }
Mais c’est seulement parce que les commandes réelles pour la performance des opérations de trading sont emballées dans quatre fonctions supplémentaires:
BuyPositionClose();
SellPositionClose();
BuyPositionOpen();
SellPositionOpen();

Les quatre fonctions opèrent de manière complètement analogue pour que nous puissions nous limiter à l’examen d’une seule d’entre elles:

bool BuyPositionClose(const string symbol,ulong deviation)
  {
//--- declare structures of trade request and result of trade request
   MqlTradeRequest request;
   MqlTradeResult result;
   ZeroMemory(request);
   ZeroMemory(result);

//--- check if there is BUY position
   if(PositionSelect(symbol))
     {
      if(PositionGetInteger(POSITION_TYPE)!=POSITION_TYPE_BUY) return(false);
     }
   else  return(false);

//--- initializing structure of the MqlTradeRequest to close BUY position
   request.type   = ORDER_TYPE_SELL;
   request.price  = SymbolInfoDouble(symbol, SYMBOL_BID);
   request.action = TRADE_ACTION_DEAL;
   request.symbol = symbol;
   request.volume = PositionGetDouble(POSITION_VOLUME);
   request.sl = 0.0;
   request.tp = 0.0;
   request.deviation=(deviation==ULONG_MAX) ? deviation : deviation;
   request.type_filling=ORDER_FILLING_FOK;
//---
   string word="";
   StringConcatenate(word,
                     "<<< ============ BuyPositionClose():   Close Buy position at ",
                     symbol," ============ >>>");
   Print(word);

//--- send order to close position to trade server
   if(!OrderSend(request,result))
     {
      Print(ResultRetcodeDescription(result.retcode));
      return(false);
     }
//----+
   return(true);
  }

Fondamentalement, c’est à peu près tout l’Expert Advisor multi-devises (Exp_TEMA.mq5)!

Outre les fonctions considérées, il contient deux fonctions utilisateur supplémentaires:

bool IsNewBar(int Number, string symbol, ENUM_TIMEFRAMES timeframe);
string ResultRetcodeDescription(int retcode);

La première de ces fonctions renvoie la valeur réelle au moment du changement de barre, en fonction du symbole et de la période sélectionnés, et la seconde renvoie la ligne par le code de résultat de la transaction de trading, dérivé du champ retcode de la structure de demande de transaction MqlTradeResult

L’Expert Advisor est prêt, il est temps d’entamer les tests ! Il n’y a pas de différences majeures visibles dans le test de l’Expert Advisor multi-devises par rapport à son homologue Expert Advisor à monnaie unique.

Déterminez les configurations dans l’onglet " Paramètres " du Testeur de Stratégie :

Figure 1. Onglet " Paramètres du testeur de stratégie

Figure 1. Onglet " Paramètres " du testeur de stratégie

Si nécessaire, ajustez les valeurs des paramètres d’entrée dans l’onglet " Paramètres d’entrée:

Figure 2. Onglet " Paramètres » du testeur de stratégie

Figure 2. Onglet " Paramètres" du testeur de stratégie

et puis cliquez sur le bouton " Démarrer " dans le testeur de stratégie sous l’onglet " Paramètres »:

Expert Advisor Figure 3. Exécution du test Expert Advisor

Figure 3. Exécution du test Expert Advisor

Le temps qui passe du premier test de l’Expert Advisor peut s’avérer très important, en raison du chargement de l’historique pour les douze symboles. Après accomplissement du test dans le testeur de stratégie, ouvrez l’onglet " Résultats ":

Figure 4. Résultats des tests

Figure 4. Résultats des tests

et analyser les données, en utilisant le contenu de l’onglet " Graphique ":

Figure 5. Graphique de la dynamique de l’équilibre et des capitaux propres

Figure 5. Graphique de la dynamique de l’équilibre et des capitaux propres

et le "Journal":

testeur de stratégie Figure 6. Journal du testeur de stratégie

Figure 6. Journal du testeur de stratégie

Tout naturellement, l’essence même des entrées et des sorties de l’algorithme sur le marché de cet Expert Advisor est trop simple, et il serait naïf de s’attendre à des résultats notables, lors de l’utilisation des premiers paramètres aléatoires. Mais notre objectif ici est de démontrer l’idée fondamentale d’élaborer un Expert Advisor multi-devises de la manière la plus simple possible.

Avec l’optimisation de cet Expert Advisor , certains inconvénients peuvent survenir dus à un trop grand nombre de paramètres d’entrée. L’algorithme génétique d’optimisation nécessite une quantité beaucoup plus petite de ces paramètres, de sorte que l’Expert Advisor doit être optimisé sur chaque puce individuellement, en désactivant les puces restantes des paramètres d’entrée TradeN.

Maintenant, lorsque l’essence même de l’approche a été définie, vous pouvez commencer à travailler avec l’algorithme de prise de décision plus intéressant pour le robot multi-devises.


2. Résonances sur les marchés financiers et leur application dans les systèmes de trading

L’idée de prendre en compte les corrélations entre les différents actifs financiers, en général, n’est pas nouvelle, et il serait intéressant d’implémenter l’algorithme, qui serait basé précisément sur l’analyse de telles tendances. Dans cet article, je vais implémenter un automate multi-devises, basé sur l’article de Vasily Yakimkin " Résonances - une Nouvelle Catégorie d’Indicateurs Techniques " publié dans la revue " Currency Speculator " (en russe) 04, 05, 2001.

L’essence même de cette approche en un mot se présente comme suit. Par exemple, pour la recherche sur EUR / USD, nous utilisons non seulement les résultats de certains indicateurs sur l’actif financier, mais également les résultats du même indicateur sur les actifs EUR / USD - EUR / JPY et USD / JPY. Il est préférable d’utiliser l’indicateur, dont les valeurs sont normalisées dans la même fourchette de changements pour la simplicité et la facilité des mesures et des calculs.

Compte tenu de ces exigences, l’indicateur stochastique convient bien à ce classique. Bien que, en réalité, il n’y ait pas de différence dans l’utilisation d’autres indicateurs. En vue de la direction de la tendance, nous considérerons le signe de différence entre la valeur du Stoh stochastique et son signe de ligne de signal .

 Figure7. Détermination de la direction de la tendance

Figure 7. Détermination de la direction de la tendance

Pour le symbole variable dStoh, il existe un tableau entier des combinaisons possibles et de leurs interprétations pour la direction de la tendance actuelle:

 Figure 8. Combinaisons du symbole variable dStoh et de la direction de la tendance

Figure 8. Combinaisons du symbole variable dStoh et de la direction de la tendance

Dans le cas où deux signaux des actifs EUR / JPY et USD / JPY ont des valeurs opposées, nous devons déterminer leur somme, et si cette somme est supérieure à zéro, considérez les deux signaux comme positifs, sinon - comme négatifs.

Ainsi, pour l’ouverture des Longs, utilisez la situation lorsque la tendance est croissante, et pour sortir, utilisez une tendance à la baisse, ou une tendance lorsque les signaux de l’indicateur de l’actif principal EUR / USD sont négatifs. En outre, quittez le long si l’actif principal n’a pas de signaux et si la somme de la variable dStoh pour les actifs restants est inférieure à zéro. Pour les courts-métrages, tout est absolument analogue, seule la situation est adverse.

La solution la plus rationnelle serait de placer toute la partie analytique de l’Expert Advisor dans l’indicateur multi-devises, et pour l’Expert Advisor à partir des tampons d’indicateurs, de ne prendre que les signaux prêts pour le contrôle des trades. La version de ce type d’indicateur est présentée par l’indicateur MultiStochastic.mq5, offrant une analyse visuelle des conditions du marché.

figure 9. Indicateur multi-stochastique

Figure 9. Indicateur Multi-stochastique

La barre verte signale l’ouverture et la rétention des longs, et les barres rouges - des courts, respectivement. Les points roses et vert clair sur le bord supérieur du graphique représentent les signaux de sortie des positions longues et courtes.

Cet indicateur peut être directement utilisé pour recevoir des signaux dans l’Expert Advisor, mais il serait toujours préférable de faciliter son travail et de supprimer tous les tampons et éléments de visualisation inutiles, ne laissant que ce qui est directement impliqué dans l’approvisionnement de signaux de trading. C’est précisément ce qui a été fait dans l’indicateur MultiStochastic_Exp.mq5.

Dans cet Expert Advisor, j’ai tradé avec seulement trois jetons, si bien que le code de la fonction OnTick() est devenue extrêmement simple:

void OnTick()
  {
//--- declare variables arrays for trade signals
  static bool UpSignal[], DnSignal[], UpStop[], DnStop[];
  
//--- get trade signals
  TradeSignalCounter(0, Trade0, Kperiod0, Dperiod0, slowing0, ma_method0, price_0, SymbolA0, SymbolB0, SymbolC0, UpSignal, DnSignal, UpStop, DnStop);
  TradeSignalCounter(1, Trade1, Kperiod1, Dperiod1, slowing1, ma_method1, price_1, SymbolA1, SymbolB1, SymbolC1, UpSignal, DnSignal, UpStop, DnStop);
  TradeSignalCounter(2, Trade2, Kperiod2, Dperiod2, slowing2, ma_method2, price_2, SymbolA2, SymbolB2, SymbolC2, UpSignal, DnSignal, UpStop, DnStop);
                             
//--- perform trade operations
   TradePerformer( 0, SymbolA0,  Trade0,  StopLoss0,  0,  Lots0,  Slippage0,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 1, SymbolA1,  Trade1,  StopLoss1,  0,  Lots1,  Slippage1,  UpSignal, DnSignal, UpStop, DnStop);
   TradePerformer( 2, SymbolA2,  Trade2,  StopLoss2,  0,  Lots2,  Slippage2,  UpSignal, DnSignal, UpStop, DnStop);
//---
  }

Cependant, le code de la fonction TradeSignalCounter() est un peu plus complexe : Le fait est qu’un indicateur multi-devises fonctionne directement avec trois séries chronologiques d’actifs financiers différents, et par conséquent, nous mettons en œuvre une vérification plus subtile des barres pour l’adéquation du nombre minimum d’entre elles dans l’une des trois séries chronologiques, en utilisant la fonction Rates_Total().

En outre, une vérification supplémentaire de la synchronisation des séries chronologiques est effectuée, à l’aide de la fonction SynchroCheck(), afin de garantir la précision de la détermination du moment où un changement de barre se produit simultanément dans toutes les séries chronologiques.

bool TradeSignalCounter(int Number,
                        bool Trade,
                        int Kperiod,
                        int Dperiod,
                        int slowing,
                        ENUM_MA_METHOD ma_method,
                        ENUM_STO_PRICE price_,
                        string SymbolA,
                        string SymbolB,
                        string SymbolC,
                        bool &UpSignal[],
                        bool &DnSignal[],
                        bool &UpStop[],
                        bool &DnStop[])
  {
//--- check if trade is prohibited
   if(!Trade)return(true);
//--- declare variable to store sizes of variables arrays
   static int Size_=0;
//--- declare arrays to store handles of indicators as static variables
   static int Handle[];
   static int Recount[],MinBars[];
//---
   double dUpSignal_[1],dDnSignal_[1],dUpStop_[1],dDnStop_[1];
//--- change size of variables arrays
   if(Number+1>Size_)
     {
      uint size=Number+1;
      //----
      if(ArrayResize(Handle,size)==-1
         || ArrayResize(Recount,size)==-1
         || ArrayResize(UpSignal, size) == -1
         || ArrayResize(DnSignal, size) == -1
         || ArrayResize(UpStop, size) == -1
         || ArrayResize(DnStop, size) == -1
         || ArrayResize(MinBars,size) == -1)
        {
         string word="";
         StringConcatenate(word,"TradeSignalCounter( ",Number,
                           " ): Error!!! Unable to change sizes of variables arrays!!!");
         int error=GetLastError();
         ResetLastError();
         //---
         if(error>4000)
           {
            StringConcatenate(word,"TradeSignalCounter( ",Number," ): Error code ",error);
            Print(word);
           }
         Size_=-2;
         return(false);
        }

      Size_=int(size);
      Recount[Number] = false;
      MinBars[Number] = Kperiod + Dperiod + slowing;

      //--- get indicator's handle
      Handle[Number]=iCustom(SymbolA,0,"MultiStochastic_Exp",
                             Kperiod,Dperiod,slowing,ma_method,price_,
                             SymbolA,SymbolB,SymbolC);
     }
//--- check if number of bars is sufficient for calculation 
   if(Rates_Total(SymbolA,SymbolB,SymbolC)<MinBars[Number])return(true);
//--- check timeseries synchronization
   if(!SynchroCheck(SymbolA,SymbolB,SymbolC))return(true);
//--- get trade signals 
   if(IsNewBar(Number,SymbolA,0) || Recount[Number])
     {
      DnSignal[Number] = false;
      UpSignal[Number] = false;
      DnStop  [Number] = false;
      UpStop  [Number] = false;

      //--- using indicators' handles, copy values of indicator's 
      //--- buffers into static arrays, specially prepared for this purpose
      if(CopyBuffer(Handle[Number], 1, 1, 1, dDnSignal_) < 0){Recount[Number] = true; return(false);}
      if(CopyBuffer(Handle[Number], 2, 1, 1, dUpSignal_) < 0){Recount[Number] = true; return(false);}
      if(CopyBuffer(Handle[Number], 3, 1, 1, dDnStop_  ) < 0){Recount[Number] = true; return(false);}
      if(CopyBuffer(Handle[Number], 4, 1, 1, dUpStop_  ) < 0){Recount[Number] = true; return(false);}

      //--- convert obtained values into values of logic variables of trade commands
      if(dDnSignal_[0] == 300)DnSignal[Number] = true;
      if(dUpSignal_[0] == 300)UpSignal[Number] = true;
      if(dDnStop_  [0] == 300)DnStop  [Number] = true;
      if(dUpStop_  [0] == 300)UpStop  [Number] = true;

      //--- all copy operations from indicator's buffers completed successfully
      //--- unnecessary to return into this block until next bar change
      Recount[Number]=false;
     }
//----+
   return(true);
  }

Il n’y a pas d’autres différences idéologiques radicales du code de cet Expert Advisor (Exp_ResonanceHunter.mq5) en raison du fait qu’il est compilé sur la base des mêmes composants fonctionnels. Par conséquent, je ne pense pas qu’il sera nécessaire de passer plus de temps sur sa structure interne.


Conclusion

À mon avis, le code de l’Expert Advisor multi-devises dans MQL5 est absolument similaire au code d’un Expert Advisor régulier.


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

Fichiers joints |
multistochastic.mq5 (17.47 KB)
exp_tema.mq5 (25.17 KB)
Tester la performance du Calcul des Moyennes Mobiles dans MQL5 Tester la performance du Calcul des Moyennes Mobiles dans MQL5
Un certain nombre d'indicateurs sont apparus depuis la création du premier indicateur de Moyenne Mobile. Beaucoup d'entre eux utilisent des méthodes de lissage similaires, mais la performance de différents algorithmes de Moyennes Mobiles n'ont pas été étudiées. Dans cet article, nous examinerons les différentes manières d'utiliser les Moyennes Mobiles dans MQL5 et comparerons leurs performance.
Analyser  les modèles de chandeliers Analyser les modèles de chandeliers
La réalisation d'un graphique en chandeliers japonais et l'analyse des modèles de chandeliers constituent un domaine passionnant d'analyse technique. L'avantage des chandeliers est qu'ils représentent les données de sorte que vous puissiez suivre la dynamique à l'intérieur des données. Dans cet article, nous analysons les types de chandeliers, la classification des modèles de chandeliers et présentons un indicateur pouvant déterminer les modèles de chandeliers.
Les Principes du Calcul Économique des Indicateurs Les Principes du Calcul Économique des Indicateurs
Les appels aux utilisateurs et les indicateurs techniques occupent très peu de place dans le code de programme des systèmes de trading automatisés. Souvent, il s’agit simplement de quelques lignes de code. Mais il arrive souvent ces quelques lignes de code utilisant plus de temps, qui doivent être consacrées au test de l’Expert Advisor. Par conséquent, tout ce qui est lié aux calculs de données dans un indicateur doit être considéré de manière beaucoup plus approfondie qu’il n’y paraît à première vue. Cet article en parlera précisément
Guide d'écriture d'une DLL pour MQL5 en Delphi Guide d'écriture d'une DLL pour MQL5 en Delphi
L'article examine le mécanisme de création d'un module DLL, en utilisant le langage de programmation populaire d' ObjectPascal, dans un environnement de programmation Delphi. La documentation, fournie dans cet article, est conçue pour cibler principalement les programmeurs débutants, qui travaillent avec des problèmes, qui dépassent les limites du langage de programmation intégré de MQL5, en connectant les modules DLL externes.