English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
L'utilisation de ORDER_MAGIC pour trader avec différents Expert Advisors sur un seul instrument

L'utilisation de ORDER_MAGIC pour trader avec différents Expert Advisors sur un seul instrument

MetaTrader 5Exemples | 17 novembre 2021, 15:36
465 0
Mykola Demko
Mykola Demko


Introduction

Dans MQL5, nous avons la possibilité d’attribuer un nombre magique à chaque ordre en attente, afin d’utiliser ces informations dans l’identification de la commande. Cela ouvre les vastes possibilités d’interaction entre les différents Expert Advisors et le développement de systèmes encore plus complexes. Dans cet article, je voudrais informer le public sur les opportunités sous-estimées du nombre Magique.

Mais avant de passer à l’essence du sujet de cet article, nous devons mieux comprendre ce qui constitue le nombre magique. Qu’est-ce qui pourrait être magique dans un nombre, qui détermine quel Expert Advisor l’a défini ? Les "miracles" commencent par les opportunités, que les développeurs définissent dans le type ulong, qui est déclaré par le nombre magique.

Le type ulong est le plus long

Si nous observons en détail le type entier long, nous constatons que la valeur maximale de ce type est tout simplement phénoménale:

Type

Taille en Octets

Valeur Minimum

Valeur Maximum

Analogique dans le langage C + +

long

8

-9 223 372 036 854 775 808

9 223 372 036 854 775 807

__int64

ulong

8

0

18 446 744 073 709 551 615

unsigned __int64

Tableau 1. Propriétés des types de données long et ulong

mais le type ulong l’a surpassé en combinant la mantisse positive et négative.

Donc, la longueur indiquée est énorme, mais comment était-elle utilisée auparavant?

De par mon expérience de travail en mql 4, j’ai souvent remarqué l’absurdité du codage du nombre magique par de nombreux développeurs. Le nombre magique a été utilisé judicieusement, mais son codage semblait assez stupide. Ce que l’on peut dire de l’individualité du nombre magique 12345, une telle Magie est utilisée par près de la moitié de la confrérie en développement. La deuxième moitié utilise les nombres magiques 55555, 33333 et 77777, et c’est à peu près l’ensemble complet. Je veux attirer l’attention du lecteur sur le fait qu’il est peu probable que son ordinateur compte plus de 1 000 Expert Advisors, donc le nombre 1000 sera suffisant pour chiffrer le nom individuel de tous vos Expert Advisors.

1000 - n’est que 3 catégories complètes, alors que devrions-nous faire avec les 15 catégories complètes restantes, qui sont disponibles dans le type ulong? La réponse est simple : Chiffrez-les

Que dit Wikipidia à propos du mot code :

Le Code - règle (algorithme) la comparaison pour chaque message individuel d’une combinaison strictement spéciale symboles (caractères) (or signaux).

Par conséquent, nous allons établir les règles. Je propose de prescrire dans le code du nombre Magique, non seulement l’ID de l’Expert Advisor, mais aussi l’instrument sur lequel il fonctionne. Le fait que l’Expert Advisor fonctionne, par exemple, sur EURUSD, ne signifie pas que l’Expert Advisor affichera un ordre uniquement sur cet instrument. Aussi, je pense qu’il sera utile d’écrire le code d’interaction des Expert Advisors, quelque chose comme « le vôtre / étranger », afin que l’Expert Advisor, lors de la vérification des positions, puisse comprendre que l’ordre actuel est établi par un Expert Advisor amical. Je pense que ce sera suffisant pour élaborer un système très complexe.

Et résumons donc ce que nous avons: quelles opportunités mettons-nous dans le système:

  1. La possibilité de deux Expert Advisors ou plus de travailler sur un seul instrument et de ne pas interférer.
  2. La possibilité pour deux Expert Advisors ou plus de travailler sur des instruments différents et de se compléter.
  3. La capacité d’identifier l’ordre par l’instrument, en travaillant avec l’Expert Advisor.

Et donc, la tâche est définie, entamons dés à présent son implémentation.

Simple Expert Advisor

Rédigez le code de l’Expert Advisor simple - par exemple, maintenez la position dans la direction du Déplacement. Je pense que le lecteur, qui a décidé d’analyser le nombre magique, a déjà lu l’article Guide, étape par étape pour écrire un Expert Advisor dans MQL5 pour débutants, sinon, je recommande vivement de le faire, car je n’entrerai pas dans les détails de la création de l’Expert Advisor. En principe, l’Expert Advisor ouvrira la position une fois et la tournera pour toutes les autres fois. Par conséquent, nous aurons besoin de la fonction d’ouverture de la position, c’est-à-dire de placer la demande de trading (commande de trading).

Créez une classe auxiliaire, qui calculera les paramètres pour nous pour remplir les champs de la structure de demande de trading.

//+------------------------------------------------------------------+
//| The class provides auxiliary trading calculations                |
//+------------------------------------------------------------------+
class CProvision
  {
protected:
   MqlTradeRequest   trades;                 // pointer to the request structure of OrderSend
public:
   int               TYPE(const double &v[]);  // determines the type, in respect to the  readings of the moving
   double            pricetype(int type);     // calculates the level of the opening, in respect to the type 
   double            SLtype(int type);        // calculates the level of the stop-loss in respect to the type
   double            TPtype(int type);        // calculates the level of the take-profit, in respect to the type
   long              spread();               // returns the spread of the current instrument
   int               SendOrder(ENUM_ORDER_TYPE type,double volume);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CProvision::SendOrder(ENUM_ORDER_TYPE type,double volume)
  {
   trades.action          =TRADE_ACTION_DEAL;       // Type of the implemented actions
   trades.magic           =magic;                 // Stamp of the Expert Advisor (identifier of the magic number)
   trades.symbol          =_Symbol;                // Name of the trading instrument
   trades.volume          =volume;                // Request the volume of the trade in lots
   trades.price           =pricetype((int)type);  // Price       
   trades.sl              =SLtype((int)type);     // Level of Stop Loss order
   trades.tp              =TPtype((int)type);     // Level of Take Profit order         
   trades.deviation=(int)spread();                // Maximum acceptable deviation from the requested price
   trades.type=type;                              // Order type
   trades.type_filling=ORDER_FILLING_FOK;
   if(OrderSend(trades,res)){return(res.retcode);}
   return(-1);
  }
//+------------------------------------------------------------------+
//| Determines the type, in respect to the reading of the moving     |
//+------------------------------------------------------------------+
int CProvision::TYPE(const double &v[])
  {
   double t=v[0]-v[1];
   if(t==0.0)t=1.0;
   return((int)(0.5*t/fabs(t)+0.5));
  }
//+------------------------------------------------------------------+
//| Calculates the level of opening in respect to the type           |
//+------------------------------------------------------------------+
double CProvision::pricetype(int type)
  {
   if(SymbolInfoTick(_Symbol,tick))
     {
      if(type==0)return(tick.ask);
      if(type==1)return(tick.bid);
     }
   return(-1);
  }
//+------------------------------------------------------------------+
//| Calculates the level of stop-loss in respect to the type         |
//+------------------------------------------------------------------+
double CProvision::SLtype(int type)
  {
   if(SymbolInfoTick(_Symbol,tick))
     {
      if(type==0)return(tick.bid-SL*SymbolInfoDouble(Symbol(),SYMBOL_POINT));
      if(type==1)return(tick.ask+SL*SymbolInfoDouble(Symbol(),SYMBOL_POINT));
     }
   return(0);
  }
//+------------------------------------------------------------------+
//| Calculates the level of timeframe in respect to the type         |
//+------------------------------------------------------------------+
double CProvision::TPtype(int type)
  {
   if(SymbolInfoTick(_Symbol,tick))
     {
      if(type==0)return(tick.bid+TP*SymbolInfoDouble(Symbol(),SYMBOL_POINT));
      if(type==1)return(tick.ask-TP*SymbolInfoDouble(Symbol(),SYMBOL_POINT));
     }
   return(0);
  }
//+------------------------------------------------------------------+
//| Returns the spread                                               |
//+------------------------------------------------------------------+
long CProvision::spread() 
  {
   return(SymbolInfoInteger(_Symbol,SYMBOL_SPREAD));
  }

Ayant une telle classe, nous pouvons écrire un code pour un simple Expert Advisor sans problème: 

//+------------------------------------------------------------------+
//| Code of the Expert Advisor                                       |
//+------------------------------------------------------------------+

//--- Input parameters
input ulong              magic       =1;           // magic
input int                SL          =300;         // Stop Loss
input int                TP          =1000;        // Take Profit
input int                MA_Period   =25;         // MA period
input double             lot         =0.1;         // Volume of position
input int                MA_shift    =0;          // Shift of indicator
input ENUM_MA_METHOD     MA_smooth   =MODE_SMA;     // Smoothing type
input ENUM_APPLIED_PRICE price       =PRICE_OPEN;    // Price type 

//--- We will store the indicator's handle
int
MA_handle,     // Handle of the indicator
type_MA,       // Type that specify the direction of MA
rezult;        // The variable takes the value of the result of the OrderSend operation
double v[2];    // Buffer for receiving values of MA

MqlTradeResult   res;   // Pointer to the structure of responding by OrderSend
MqlTick         tick;  // Pointer to the structure of last market information
CProvision      prov;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Create the indicator's handle
   MA_handle=iMA(Symbol(),0,MA_Period,MA_shift,MA_smooth,price);
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(CopyBuffer(MA_handle,0,0,2,v)<=0)
     {Print("#",magic,"Error of copying");return;}
   type_MA=prov.TYPE(v); // Determine type depending on MA indication

   if(PositionSelect(_Symbol))// If there is an open position 
     {
      if(PositionGetInteger(POSITION_TYPE)!=type_MA)// Check if its time to close
        {
         Print("#",magic,"Position by magic number has volume ",PositionGetDouble(POSITION_VOLUME),
               " reverse position of type ",PositionGetInteger(POSITION_TYPE)," by ",type_MA);
         rezult=prov.SendOrder((ENUM_ORDER_TYPE)type_MA,PositionGetDouble(POSITION_VOLUME)+lot);
         // reverse the position
         if(rezult!=-1)Print("#",magic," Code of the operation result ",rezult," volume ",res.volume);
         else{Print("#",magic,"Error",GetLastError()); return;}
        }
     }
   else // If there is no open position then open
     {
      Print("#",magic,"Position by magic number has volume ",PositionGetDouble(POSITION_VOLUME),
            " open position of type ",type_MA);
      rezult=prov.SendOrder((ENUM_ORDER_TYPE)type_MA,lot);
      // open position 
      if(rezult!=-1)Print("#",magic," Code of operation result ",rezult," volume ",res.volume);
      else{Print("#",magic,"Error",GetLastError()); return;}
     }
  } 

Exécutez-le et assurez-vous que l’Expert Advisor ne diffère pas en rentabilité, mais trade exactement conformément à la logique indiquée, ce qui est précisément ce dont nous avons besoin.

Figure1. Le travail d’un Expert Advisor sur un seul instrument

Figure 1. Le travail d’un Expert Advisor sur un seul instrument

Maintenant, nous allons essayer d’exécuter cet EA, mais sur plusieurs délais d’un instrument (pour les expériences, nous avons choisi un instrument aléatoire, qui est EURUSD: o)

Figure 2. Le conflit de deux Expert Advisors sur le même instrument sur des délais différents

Figure 2. Le conflit de deux Expert Advisors sur le même instrument sur des délais différents

Étant donné que les deux Expert Advisors fonctionnent sur un seul instrument et que le code n’indique pas le partage des positions, donc les deux Expert Advisors tentent de corriger la position de trading, en fonction des lectures de leurs indicateurs, et par conséquent, - un conflit surgit. L’Expert Advisor qui fonctionne sur M1, tente de faire tourner la position dans la Cellule, tandis que son rival cherche à l’arrêter. Il est évident que nous avons besoin d’un calcul séparé des positions, ce que nous allons faire maintenant.


Position ou position virtuelle ?

Étant donné que dans MetaTrader 5, les développeurs sont passés des ordres à la prise en compte des positions, il est logique d’examiner plus en détail les fonctions associées à des positions d’enregistrement.

// Returns the number of open positions.
int     PositionsTotal();

// Returns the symbol of the open position by the number in the list of positions.
string  PositionGetSymbol(int  index);

// Selects the open position for further working with it.
bool    PositionSelect(string  symbol, uint timeout=0);

// Function returns the requested property of the open position.
double  PositionGetDouble(ENUM_POSITION_PROPERTY  property_id);

// The function returns the requested property of the open position.
long    PositionGetInteger(ENUM_POSITION_PROPERTY  property_id);

// The function returns the requested property of the open position.
string  PositionGetString(ENUM_POSITION_PROPERTY  property_id);

Identificateurs des énumérations pour les fonctions d’obtention de la demande des propriétés de position conformes PositionGetDouble, PositionGetInteger, et PositionGetString qui sont indiquées dans les tableaux 2-4.

Identifiant

Description

Type

POSITION_VOLUME

Volume d'une position

double

POSITION_PRIX_OUVERT

Prix de la position

double

POSITION_SL

Niveau d’Excédent de Pertes pour la position ouverte

double

POSITION_TP

Niveau de Prise de Bénéfices pour la position ouverte

double

POSITION_PRIX_ACTUEL

Prix actuel par le symbole

double

POSITION_COMMISSION

Commission

double

POSITION_ÉCHANGE

Échange accumulé

double

POSITION_BÉNÉFICE

Bénéfice actuel

double

Tableau 2. ENUM_POSITION_PROPERTY_DOUBLE de valeur d’énumération

Identifiant

Description

Type

POSITION_TEMPS

Heure d’ouverture des postes

date/heure

POSITION_TYPE

Type de poste

ENUM_POSITION_TYPE

POSITION_MAGIC

Nombre magique pour le poste (voir ORDER_MAGIC )

long

POSITION_IDENTIFIER

Identification de la position - il s’agit d’un numéro unique qui est attribué à chaque position rouverte et qui ne change pas tout au long de son cycle de vie. Le chiffre d’affaires d’une position ne change pas son identifiant.

long

Tableau 3. Valeurs d’énumération ENUM_POSITION_PROPERTY_INTEGER

Identifiant

Description

Type

POSITION_SYMBOL

Symbole, pour lequel la position est ouverte

chaîne

POSITION_COMMENT

Commentaire de la position

chaîne

Tableau 4. Valeurs d’énumération ENUM_POSITION_PROPERTY_STRING

D’après les fonctions, nous pouvons clairement constater que le langage ne comporte pas la division des positions, basée sur le principe de « qui a mis l’ordre », mais la possibilité de tels enregistrements est disponible puisque les ORDER_MAGIC, les POSITION_MAGIC et les DEAL_MAGIC sont le même nombre exact, et sont tirés du nombre magique, indiqué par l’utilisateur. La POSITION_MAGIC est prise à partir de la DEAL_MAGIC, qui ouvre la position, et la DEAL_MAGIC, à son tour, est prise à partir de la ORDER_MAGIC, de la commande passée.

Identifier une commande, une transaction ou une position peut se faire sans problème, mais il est impossible de diriger une position par un nombre magique particulier. Maintenant, nous allons essayer d’éliminer cette carence . élaborons des analogues de fonctions intégrées, mais avec identification par le nombre magique. Déclarez une classe pour travailler avec une position virtuelle sur le nombre Magic.

Puisque nous avons la possibilité de travailler avec la POO, déclarons également notre propre structure (en acquérant une pratique supplémentaire de l’écriture objective).

//+------------------------------------------------------------------+
//| Structure of the CPositionVirtualMagic class                     |
//+------------------------------------------------------------------+
struct SPositionVirtualMagic
  {
   double            volume; // volume of virt. position
   ENUM_POSITION_TYPE type;  // type of virt. position
  };
//+--------------------------------------------------------------------------------+
//| The class calculates the virtual position of an Expert Advisor by magic number |
//+--------------------------------------------------------------------------------+
class CPositionVirtualMagic
  {
protected:
   SPositionVirtualMagic pvm;
public:
   double               cVOLUME(){return(pvm.volume);}
   // Returns the volume of virtual position of an Expert Advisor
   ENUM_POSITION_TYPE   cTYPE(){return(pvm.type);}
   // Returns the type of virtual position of an Expert Advisor
   bool              PositionVirtualMagic(ulong Magic,
                                          string symbol,
                                          datetime CurrentTime
                                          );
   // the method of calculation virt. position returns the presence or absence of virt. position
private:
   void              prHistory_Deals(ulong &buf[],int HTD);
   // Fills the array of tickets
  };
//+-------------------------------------------------------------------------------------+
//| Method of calculation of virt. position, returns true if there is a virt. position  |
//+-------------------------------------------------------------------------------------+
bool  CPositionVirtualMagic::PositionVirtualMagic(ulong Magic,
                                                  string symbol,
                                                  datetime CurrentTime
                                                  )
  {
   int DIGITS=(int)-log10(SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP));
   if(DIGITS<0)DIGITS=0;
   ulong Dticket=0;
   int History_Total_Deals=-1;
   double volume=0,volume_BUY=0,volume_SELL=0;
   ulong DTicketbuf[];

   do
     {
      if(HistorySelect(0,TimeCurrent()))
        {
         History_Total_Deals=HistoryDealsTotal();
         prHistory_Deals(DTicketbuf,History_Total_Deals);
        }
      HistorySelect(0,TimeCurrent());
     }
   while(History_Total_Deals!=HistoryDealsTotal());

   for(int t=0;t<History_Total_Deals;t++)
     {
      Dticket=DTicketbuf[t];
      if(HistoryDealSelect(Dticket))
        {
         if(HistoryDealGetInteger(Dticket,DEAL_TIME)>=CurrentTime)
           {
            if(HistoryDealGetInteger(Dticket,DEAL_MAGIC)==Magic)
              {
               if(HistoryDealGetInteger(Dticket,DEAL_TYPE)==DEAL_TYPE_BUY)
                 {
                  volume_BUY+=HistoryDealGetDouble(Dticket,DEAL_VOLUME);
                 }
               else
                 {
                  if(HistoryDealGetInteger(Dticket,DEAL_TYPE)==DEAL_TYPE_SELL)
                    {
                     volume_SELL+=HistoryDealGetDouble(Dticket,DEAL_VOLUME);
                    }
                 }
              }
           }
        }
      else{HistorySelect(0,TimeCurrent());t--;}
      // if there is a fault, load history data and pass the step again
     }
   volume=NormalizeDouble(volume_BUY-volume_SELL,DIGITS);
   if(volume<0)pvm.type=POSITION_TYPE_SELL;
   else
     {
      if(volume>0)pvm.type=POSITION_TYPE_BUY;
     }
   pvm.volume=fabs(volume);
   if(pvm.volume==0)return(false);
   else return(true);
  }

Dans le texte ci-dessus (où le code de la classe CProvision est indiqué), il n’a pas été expliqué d’où tout vient et où cela va plus loin, puisque le développement de l’Expert Advisor n’est pas l’objet de cet article.

Mais nous allons considérer en détail la classe CPositionVirtualMagic.

La structure bénéficie de la classe:

struct SPositionVirtualMagic

qui est utilisée pour accepter les résultats des calculs, une telle déclaration globale au sein de la classe, grâce à pvm (variable de la structure), cette structure sera disponible partout, dans n’importe quelle méthode de la classe.

Suivez ensuite les deux méthodes de la classe :

double               cVOLUME(){return(pvm.volume);} // Returns the volume of the virtual position of the EA
ENUM_POSITION_TYPE   cTYPE()  {return(pvm.type);}   // Returns the type of the virtual position of the EA

Ces méthodes sont déclarées publiques et, par conséquent, elles seront disponibles via la variable de classe appelée, à n’importe quel endroit du programme, et sont conçues pour la sortie des valeurs de structure à l’emplacement demandé.

Il s’agit également de la section où la méthode suivante est déclarée :

bool              PositionVirtualMagic(ulong Magic,string symbol,datetime CurrentTime);

C’est la fonction principale de la classe, et nous nous concentrerons davantage sur ses analyses détaillées, et en attendant, je vais me présenter devant moi-même et décrire la fonction conformément au spécificateur de l’accès privé:

void              prHistory_Deals(ulong &buf[],int HTD);

Cette méthode produit un enregistrement de ticket des transactions dans le tableau, qui est essentiellement un cycle, et pourrait être décrit dans la fonction appelée, mais je voulais réduire la taille (afin d’augmenter la lisibilité du code) de la fonction PositionVirtualMagic(), et j’ai donc déplacé ce cycle au-delà des limites de la fonction, et j’ai donc démontré comment utiliser le spécificateur de l’accès privé.

Revenons donc à  positionVirtualMagic() . Cette fonction, à son tout début, a un calcul de précision d’une ligne, auquel vous devez arrondir la double valeur du volume de la position calculée.

int DIGITS=(int)-log10(SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP)); if(DIGITS<0)DIGITS=0;

Ceci est nécessaire pour faire l’opération de comparaison à zéro, sinon un certain équilibre dans les 8ème chiffres après la virgule, nous empêchera d’assimiler la valeur à zéro et entraînera une erreur d’exécution.

Le volume de position est arrondi à l’étape minimale. Et si l’étape minimale est supérieure à 1, l’arrondi est effectué par la partie intégrale. Vient ensuite le cycle pendant, mais il est utilisé d’une nouvelle manière (différente de celle de mql4), puisque la vérification de l’expression véridique se fait plutôt à la fin qu’au début du cycle :

    do
     {
      if(HistorySelect(0,TimeCurrent()))
        {
         History_Total_Deals=HistoryDealsTotal();
         prHistory_Deals(DTicketbuf,History_Total_Deals);
        }
      HistorySelect(0,TimeCurrent());  
     }
   while(History_Total_Deals!=HistoryDealsTotal());

Une telle approche est appliquée parce que l’expression de la véracité est calculée dans le cycle, et à son lancement, elle n’est pas encore préparée pour cette vérification.

Le cycle contient le téléchargement de l’historique , je veux attirer l’attention du lecteur sur le fait que c’est une condition requise afin de s’assurer que le travail des fonctions intégrées de travailler avec l’historique.

HistorySelect(0,TimeCurrent())

Je pense que je devrais expliquer mon système de choix des noms de variables.

Le lecteur attentif aurait dû remarquer que les noms des classes sont définis par la lettre initiale « C », ce n’est pas requis par la syntaxe et n’importe quel nom peut être attribué, mais une telle manière rend la lecture beaucoup plus facile. Si la lettre « C » apparaît avant le nom, nous nous rendons compte tout de suite que c’est le nom de la classe, et si la lettre est « S » - alors il s’agit une structure. Si la variable prend la valeur d’une fonction intégrée, alors je change simplement les composants du nom de la fonction et j’obtiens le nom de la variable, par exemple comme ceci:

CurrentTime = TimeCurrent();

Simple et lisible, on peut immédiatement constater ce que contient la variable. D’autant plus que MetaEditor contient la fonction permettant de faire glisser un élément de code particulier dans un emplacement spécifié.

En examinant davantage le code nous constatons qu’après le téléchargement de l’historique, suit l’appel à la fonction:

History_Total_Deals=HistoryDealsTotal();

avec le stockage du nombre de transactions dans la variable. À la même condition, nous implémentons la vérification de la sortie du cycle. Pour quoi avons-nous besoin de cette vérification? Et pourquoi ne pouvons-nous pas simplement télécharger l’historique, puis récupérer les transactions à partir de celui-ci?

Le problème réside dans le fait que pendant le travail des Expert Advisors, l’historique sera séparément demandé par chaque EA, et donc si les Expert Advisors fonctionnent à des moments différents,alors la profondeur de l’historique sera différente. Et cela signifie que lorsqu’un Expert Advisor entre dans le cycle et télécharge l’historique pour sa période, avant d’atteindre la fin du cycle, il peut découvrir que cet historique a déjà été téléchargé à la demande d’un autre Expert Advisor, et donc une vérification de l’authenticité doit être faite.

Incidemment, ce n’est peut-être pas le meilleur type de vérification, mais cela fonctionne. Et donc, poursuivons. Dans le cycle, nous appelons la méthode de classe, qui saisit les valeurs de ticket des transactions dans un tampon spécialement préparé. Après avoir appelé la fonction prHistory_Deals (), nous produisons à nouveau le téléchargement de l’historique.

C’est ainsi que l’on vérifie s’il y a eu ou non des changements dans l’historique des trades, au cours des travaux de la fonction prHistory_Deals (). S’il n’y a pas eu de modifications, la variable de History_Total_Deals sera donc égale à HistoryDealsTotal (), et une sortie du cycle à passage unique se produira. S’il y a eu des changements, le système lancera un deuxième cycle et continuera à répéter jusqu’à ce que l’historique des tickets soit téléchargé sans aucune erreur (et n’oubliez pas de mettre « ; » à la fin) :

while(History_Total_Deals!=HistoryDealsTotal());

Plus loin dans le cycle pour, le calcul des positions virtuelles intervient.

Si la transaction a passé avec succès une série de filtres (l’heure de la transaction et le numéro magique de la transaction),puis son volume augmente la partie de la position virtuelle, le type auquel appartient la transaction.

Je tiens à noter que je n’enregistre les calculs des positions virtuelles qu’à partir du lancement de l’Expert Advisor, bien que d’autres options soient envisageables.

Ici, il convient de noter comment exactement la position est calculée. Par le registre, que nous utilisons tous depuis des temps immémoriaux et à ce jour, nous avons des dépenses et des bénéfices, et le comptage du solde est conservé comme la différence entre ces valeurs, le même schéma s’applique au calcul d’une position: si vous ouvrez des lots, 0,2 à Vendre et 0,3 à Acheter, cela signifie que vous détenez la position de 0,1 pour Acheter. Le moment de l’ouverture et la différence de niveaux sont des catégories de profit, mais la position que vous occuperez est de 0,1 lot, le type d’Achat.

C’est pourquoi nous résumons simplement toutes les transactions effectuées par l’Expert Advisor sur Acheter et séparément, sur Vendre, puis nous les comparons et obtenons la position générale (en fait, c’est ce avec quoi le reste de la fonction examinée est engagée).

Calcul du volume de positions :

volume=NormalizeDouble(volume_BUY-volume_SELL,DIGITS);

Identification du type de position avec la sortie de la valeur dans la structure:

   if(volume<0)pvm.type=POSITION_TYPE_SELL;
   else
     {
      if(volume>0)pvm.type=POSITION_TYPE_BUY;
     }

Sortie du volume dans la structure:

pvm.volume=fabs(volume);

 La sortie de la valeur de la fonction: si le volume de position est 0, alors il est faux, sinon, si la position existe, alors il est vrai:

   if(pvm.volume==0)return(false);
   else return(true);

Maintenant, ayant la fonction de la position virtuelle, nous pouvons facilement établir le code de l’Expert Advisor, qui n’entrera pas en conflit avec ses « voisins ».

Pour gagner de l’espace, je vais fournir certaines parties du code, qui n’ont pas été présentées ci-dessus, plutôt que le code entier lui-même.

//+------------------------------------------------------------------+
//| Code of the Expert Advisor                                       |
//+------------------------------------------------------------------+

//--- input parameters
input ulong              magic       =1;           // magic
input int                SL          =300;         // Stop Loss
input int                TP          =1000;        // Take Profit
input int                MA_Period   =25;          // MA period
input double             lot         =0.1;         // Volume of position
input int                MA_shift    =0;          // Shift of indicator
input ENUM_MA_METHOD     MA_smooth   =MODE_SMA;     // Smoothing type
input ENUM_APPLIED_PRICE price       =PRICE_OPEN;    // Price type 
//--- we will store the indicator's handle
int MA_handle,type_MA,rezult;
double v[2];
datetime  CurrentTime;  // The variable stores the time of start of the Expert Advisor
MqlTradeResult    res;   // Pointer to the structure of responding by OrderSend
MqlTick          tick;  // Pointer to the structure of last market information
CPositionVirtualMagic cpvm;
CProvision prov;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   CurrentTime=TimeCurrent();// The variable stores the time of start of the Expert Advisor
//--- Create the indicator's handle
   MA_handle=iMA(Symbol(),0,MA_Period,MA_shift,MA_smooth,price);
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(CopyBuffer(MA_handle,0,0,2,v)<=0)
     {Print("#",magic,"Error of copying");return;}
   type_MA=prov.TYPE(v); // Determine type depending on MA indication

   if(cpvm.PositionVirtualMagic(magic,_Symbol,CurrentTime))// If there is ab open position 
     {
      if((int)cpvm.cTYPE()!=type_MA)// Check if it is time to close
        {
         Print("#",magic,"Position by magic number has volume ",cpvm.cVOLUME(),
               " reverse position of type ",(int)cpvm.cTYPE()," by ",type_MA);
         //cpvm.cVOLUME() - volume of virtual position
         rezult=prov.SendOrder((ENUM_ORDER_TYPE)type_MA,cpvm.cVOLUME()+lot);// reverse the poistion
         if(rezult!=-1)Print("#",magic," Code of the operation result ",rezult," volume ",res.volume);
         else{Print("#",magic,"Error",GetLastError()); return;}
        }
     }
   else // If there is no open position then open
     {
      Print("#",magic,"Poistion by magic number has volume ",cpvm.cVOLUME()," open position of type ",type_MA);
      rezult=prov.SendOrder((ENUM_ORDER_TYPE)type_MA,lot);// Open position 
      if(rezult!=-1)Print("#",magic," Code of the operation result ",rezult," volume ",res.volume);
      else{Print("#",magic,"Error",GetLastError()); return;}
     }
  }

Exécutez l’Expert Advisor trois fois sur un seul instrument, mais avec des délais différents, et également attribuez des nombres magiques différents à chaque fois :

 Figure 3. Attribuons des nombres magiques différents à deux Expert Advisors identiques,(un instrument, des délais différents) lancement du premier Expert Advisor

Figure 3. Attribuons des nombres magiques différents à deux Expert Advisors identiques, (un instrument, des délais différents) lancement du premier Expert Advisor

Figure 4. Attribuons des nombres magiques différents à deux Expert Advisors identiques (un instrument, des délais différents) lancement du deuxième Expert Advisor

Figure 4. Attribuons des nombres magiques différents à deux Expert Advisors identiques (un instrument, des délais différents) lancement du deuxième Expert Advisor

 Figure 5. Le résultat est un travail non conflictuel d’Expert Advisors sur un seul instrument, avec divers nombres magiques

Figure 5. Le résultat est un travail non conflictuel d’Expert Advisors sur un seul instrument, avec divers nombres magiques

L’essai a été réalisé avec succès, les Expert Advisors cèdent obligeamment la place les uns aux autres, et aucune question conflictuelle ne semble être présente.

Le premier point du Cahier des Charges a été implémenté, mais il y a plus à venir.


Coder la magie

Pour l’implémentation des parties suivantes, nous devrons élaborer une classe de méthodes, qui encodera / décodera les informations, ainsi que récupérer les valeurs des fonctions intégrées et les transformer dans un format spécifié.

Pour ce faire, répétez les termes du codage (pour ainsi dire, le cahier des charges pour élaboration):

  • Les méthodes doivent coder le nom de l’Expert Advisor (appelons-le le nom numérique),
  • Code d’identification du vôtre / étranger (appelons-le le code d’interaction)
  • Code de symbole, sur lequel l’Expert Advisor s’exécute (afin de pouvoir déterminer depuis la transaction à partir de laquelle l’EA travaille).

Pour commencer, sélectionnons le nom de la nouvelle classe, - que ce soit magique (un nom générique), assignons notre énumération, pour rendre le code plus compréhensible visuellement.

enum Emagic
  {
   ENUM_DIGITAL_NAME,    // digital name if the Expert Advisor
   ENUM_CODE_INTERACTION,// code of interaction
   ENUM_EXPERT_SYMBOL    // symbol, on which the EA is launched
  };

L’énumération fonctionne simplement : vous décrivez les noms, séparés par des virgules, et le compilateur leur attribue des numéros par l’enchainement.

Tout d’abord, si vous attribuez une variable d’un type différent (cela ne s’applique pas aux nombres), alors lors de la spécification d’un paramètre de l’énumération, vous recevrez une erreur lors de la compilation, et deuxièmement, vous obtenez de la clarté: vous n’attribuez pas simplement 0 , mais donnez plutôt la commande pour attribuer ENUM_DIGITAL_NAME .

Comme pour l’élaboration d’une structure ou d’une classe, j’ai choisi un nom simple pour l’énumération. J’ai simplement ajouté E au nom généralement sélectionné, et obtenu Emagic , respectivement, la structure correspondante sera Smagic , et la classe Cmagic .

Encore une fois, faites attention que cette question n’est pas obligatoire et que vous pouvez appeler l’énumérateur de l’énumération, le structureur de structure et le classificateur de classe. Mais cela ne fournira pas d’uniformité dans les noms, et la lecture de ce type de code sera inconfortable.

Ensuite, créons une structure pour stocker nos codes.

struct Smagic
  {
   ulong             magicnumber;      // magic in an assembled form - how it is written in the order
   int               digital_name;     // digital name
   int               code_interaction; // code of interaction
   int               expert_symbol;    // symbol, on which the Expert Advisor is launched
  };

Après cela, déclarez la classe Cmagic, dans laquelle nous enregistrons toutes les méthodes de codage et de décodage du Magic, y compris les méthodes de l’Expert Advisor précédent (il suffit de les déclarer dans la classe actuelle et de réécrire les en-têtes)

class Cmagic
  {
protected:
   Smagic            mag;
   SPositionVirtualMagic pvm;
public:
// the function returns the assembled magic, assembled from the incoming data
   ulong             SetMagic_request(int digital_name=0,int code_interaction=0);

// the function obtains the assembled magic and divides it according to the assembly logic
   ulong             SetMagic_result(ulong magicnumber);    

// the function obtains the return identification and returns the requested part of the assembled magic
   ulong             GetMagic_result(Emagic enum_); 

// the function obtains the return identification and returns the textual interpretation of the request part of the assembled magic
   string            sGetMagic_result(Emagic enum_);

// returns the voulme of the virtual position of the Expert Advisor
   double            cVOLUME(){return(pvm.volume);}
   
// returns the type of the virtual position of the Expert Advisor
   ENUM_POSITION_TYPE  cTYPE(){return(pvm.type);}
                                           
// method of calculating the virtual position, returns the presence of absence of the virtual position   
   bool              PositionVirtualMagic(Emagic enum_,
                                          string symbol,
                                          datetime CurrentTime);
private:
// function divides the magic into three parts  of three charges, and returns the part to which the category points to
   int               decodeMagic_result(int category); 

// interpretor of instrument symbols into the digital code                                                      
   int               symbolexpert();     
   
// interpretor of the digital code into the prescribed text (Expert Advisors)
   string            expertcode(int code);    
                                 
// interpretor of the digital code into the prescribed text (interaction)   
   string            codeinterdescript(int code);

// interpretor of the digital code into the instrument symbol                                         
   string            symbolexpert(int code);

// cycle of recording tickets into the buffer
   void              prHistory_Deals(ulong &buf[],int HTD);    
  };   

Maintenant, nous allons élaborer les méthodes.

La première méthode de la classe :

//+------------------------------------------------------------------+
//| Function returns the assembled magic, assembled from the input data    |
//+------------------------------------------------------------------+
ulong Cmagic::SetMagic_request(int digital_name=0,int code_interaction=0)
  {
   if(digital_name>=1000)Print("Incorrectly specified digital name of the Expert Advisor (more than 1000)");
   if(code_interaction>=1000)Print("Incorrectly specified the code of recognizing yours-foreign (more than 1000)");
   mag.digital_name     =digital_name;
   mag.code_interaction =code_interaction;
   mag.expert_symbol    =symbolexpert();
   mag.magicnumber      =mag.digital_name*(int)pow(1000,2)+
                         mag.code_interaction*(int)pow(1000,1)+
                         mag.expert_symbol;
   return(mag.magicnumber);
  }

Cette méthode reçoit deux valeurs : un nom numérique de l’Expert Advisor et le code d’interaction.

ulong Cmagic::SetMagic_request(int digital_name=0,int code_interaction=0)

Et vérifie immédiatement leur exactitude :

   if(digital_name>=1000)Print("Incorrectly specified the digital name of the Expert Advisor(more than 1000)");
   if(code_interaction>=1000)Print("Incorrectly specifies the code of recognizing yours-foreign (more than 1000)");

Mais il n’y a pas de représailles contre les actions de l’utilisateur, même en cas d’erreur, cela continue docilement à fonctionner.

Vient ensuite l’affectation dans la structure des données d’entrée, que l’utilisateur indique, mais le symbole de l’instrument n’est pas indiqué et est obtenu à partir de la méthode privée:

int Cmagic::symbolexpert()

Je ne fournirai pas son code, car il est très long et est donné dans le fichier joint. Permettez-moi simplement de dire que cette méthode n’est fondamentalement qu’un tableau, qui attribue à chaque symbole de la fenêtre « vue du marché » un nombre correspondant: pour EURUSD, par exemple, c’est 1, etc.

Vous pouvez certainement obtenir ces données de manière dynamique, en écrivant un code pour une étude sur les devises présentes dans la fenêtre « vue du marché », mais la solution doit correspondre à la complexité du problème, et cela n’a aucun sens de traiter l’appel des fenêtres, nous le ferons donc de manière simple, - composez une liste de devises et attribuez à chacune d’entre elles un index.

Et, enfin, la ligne la plus importante de toute la méthode:

mag.magicnumber      =mag.digital_name*(int)pow(1000,2)+
                      mag.code_interaction*(int)pow(1000,1)+
                      mag.expert_symbol;

assemblé à partir des parties disparates de l’ensemble de la Magie. C’est la Magie qui sera affectée à l’ordre de notre Expert Advisor.

La méthode publique suivante de la classe :

//+------------------------------------------------------------------+
//| Function obtains the assembled magic                             |
//| and divides it according to the logic of the assembly            |
//+------------------------------------------------------------------+
ulong Cmagic::SetMagic_result(ulong magicnumber)
  {
   mag.magicnumber      =magicnumber;
   mag.expert_symbol    =decodeMagic_result(1);
   mag.code_interaction =decodeMagic_result(2);
   mag.digital_name     =decodeMagic_result(3);
   return(mag.magicnumber);
  }

En fait, cette méthode sert de coquille, distribuant à travers la structure les résultats de trois appels d’une seule méthode privée. La déclaration sous ce spécificateur est bonne dans le fait qu’ils ne sont pas affichés dans le message d’invite contextuel, lorsque vous appelez une variable de classe, donnant l’impression que tout le travail a été effectué par une fonction publique.

Mais revenons à nos fonctions privées :

//+------------------------------------------------------------------+
//| Function divides the magic into three parts of three charges     |
//| and returns the part, which the category points to               |
//+------------------------------------------------------------------+
int Cmagic::decodeMagic_result(int category)
  {
   string string_value=(string)mag.magicnumber;
   int rem=(int)MathMod(StringLen(string_value),3);
   if(rem!=0)
     {
      rem=3-rem;
      string srem="0";
      if(rem==2)srem="00";
      string_value=srem+string_value;
     }
   int start_pos=StringLen(string_value)-3*category;
   string value=StringSubstr(string_value,start_pos,3);
   return((int)StringToInteger(value));
  }

Visuellement, cette méthode peut être représentée comme une lecture d’un nombre à trois chiffres à partir du champ indiqué, par exemple, si nous avons un Magic 123456789 , nous pouvons le représenter comme | 123 | 456 | 789 | si le champ indiqué est 1 , le résultat sera 789 puisque les champs sont numérotés de droite à gauche.

Ainsi, après avoir utilisé les trois champs de ladite méthode , nous distribuons toutes les données acquises vers la structure. Cela se fait par une procédure de faire basculer la Magie à une chaîne minuscule de type :

string string_value=(string)mag.magicnumber;

suivi du tri des composants de ligne individuels.

Suivent ensuite deux fonctions similaires, qui sont dans leur essence des commutateurs de commutateurs, et ne diffèrent que par le type des valeurs de sortie:

//+------------------------------------------------------------------+
//| Function obtains the identifier of the return                    |
//| and returns the requested part of the assembled magic            |
//+------------------------------------------------------------------+
ulong Cmagic::GetMagic_result(Emagic enum_)
  {
   switch(enum_)
     {
      case ENUM_DIGITAL_NAME     : return(mag.digital_name);     break;
      case ENUM_CODE_INTERACTION : return(mag.code_interaction); break;
      case ENUM_EXPERT_SYMBOL    : return(mag.expert_symbol);    break;
      default: return(mag.magicnumber); break;
     }
  }
//+------------------------------------------------------------------------------+
//| Function obtains the identifier of the return and returns                    |
//| a textual interpretation of the requested type of the assembled magic        |
//+------------------------------------------------------------------------------+
string Cmagic::sGetMagic_result(Emagic enum_)
  {
   switch(enum_)
     {
      case ENUM_DIGITAL_NAME     : return(expertcode(mag.digital_name));            break;
      case ENUM_CODE_INTERACTION : return(codeinterdescript(mag.code_interaction)); break;
      case ENUM_EXPERT_SYMBOL    : return(symbolexpert(mag.expert_symbol));         break;
      default: return((string)mag.magicnumber); break;
     }
  }

Les fonctions renvoient la partie de la Magie, qui indique le paramètre de type Emagic, la première donnant le résultat sous la forme de ulong, qui est utilisé dans les calculs, et la seconde donnant les résultats de type chaîne, qui peut être utilisée pour la visualisation.

Dans la fonction GetMagic_result () tout est organisé simplement, il distribue les valeurs de la structure à travers le commutateur, de branches , tandis que sGetMagic_result () est un peu plus compliqué. Chaque cas de branche appelle une fonction de table, qui transmet la valeur de la structure sous une forme visuelle. Ainsi, si la valeur mag.expert_symbol , = 1, alors la première fonction donnera 1 , et la seconde EURUSD .

J’ai déjà expliqué les avantages des fonctions de table dans le codage / décodage de l’information, donc je mentionnerai seulement que chaque cas doit être considéré séparément, en fonction de la complexité de l’implémentation d’une méthode sans tableau, et de ses avantages par rapport au temps nécessaire pour rédiger les tableaux. S’il est plus facile d’écrire une tableau des états, il n’est pas nécessaire de compliquer les choses. Mais si la rédaction du tableau prend beaucoup de temps, alors, évidemment, la préférence devrait être accordée aux méthodes procédurales. Je ne fournit pas les tableaux afin de gagner de l’espace (ils peuvent être trouvés dans les fichiers joints).

Fondamentalement, c’est ça, notre classe est élaborée, cependant, il y a encore les quatre fonctions restantes que nous avons utilisées dans l’élaboration du précédent l’Expert Advisor. 

Je les ai simplement re-déclarés dans une nouvelle classe, d’autant plus qu’ils devaient être légèrement modifiés.

Maintenant, la méthode principale:

bool  Cmagic::PositionVirtualMagic(Emagic enum_,
                                   string symbol,
                                   datetime CurrentTime)

non seulement est déclarée comme une méthode de classe Cmagic, mais dispose également d’un ensemble de paramètres différent.

Au lieu de la Magie, il obtient maintenant l’identification par le champ de la Magie, dont la position a été calculée. En outre, même si le symbole était présent dans la dernière option, il n’était utilisé que pour obtenir des informations sur l’étape du lot par le symbole. Et maintenant, il est prescrit dans le filtre et peut intervenir, sur un pied d’égalité avec les autres, dans la filtration du comptage de position.

Qu’est-ce que cela nous donne? Maintenant, nous pouvons filtrer simultanément les transactions, qui étaient ouvertes sur un instrument différent, mais par le même Expert Advisor. Ce faisant, elles ne seront pas confondues avec d’autres Expert Advisors similaires, fonctionnant sur un instrument différent. Pour être honnête, il est très difficile de décrire toutes les différentes façons d’utiliser ce nouveau système de calculs. Et le lecteur peut décider à titre personnel pour quoi il a besoin d’un système aussi compliqué. Je vous conseille vivement de ne pas compliquer les cas, où vous pouvez écrire simplement, et de ne pas craindre de telles complications lorsqu’il y a un besoin évident pour cela.

Eh bien, puisque la classe a été conçue, il est temps de la tester sur un nouvel Expert Advisor:

//+------------------------------------------------------------------+
//| Code of the Expert Advisor                                       |
//+------------------------------------------------------------------+
//--- input parameters
input ulong              digital_name_       =4;           // Digital name of Expert Advisor
input ulong              code_interaction_   =1;           // Code of interaction
input Emagic             _enum               =0;           // Model of magic number  
input int                SL                  =300;         // Stop Loss
input int                TP                  =1000;        // Take Profit
input int                MA_Period           =25;          // MA period
input double             lot                 =0.4;         // Volume of position
input int                MA_shift            =0;           // Shift of indicator
input ENUM_MA_METHOD     MA_smooth           =MODE_SMA;      // Smoothing type
input ENUM_APPLIED_PRICE price               =PRICE_OPEN;    // Price type 

//--- we will store the indicator's handle
int MA_handle,type_MA,rezult;
static ulong magic;
double v[2];
datetime  CurrentTime;// The variable stores the time of start of the Expert Advisor

MqlTradeResult  res;   // Pointer to the structure of responding by OrderSend
MqlTick         tick;  // Pointer to the structure of last market information
CProvision prov;
Cmagic mg;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   magic=mg.SetMagic_request(digital_name_,code_interaction_);
// Stamp of Expert Advisor (the magic number identifier) the magic variable is declared at the global scope
// used in int CProvision::SendOrder(ENUM_ORDER_TYPE type,double volume)
   CurrentTime=TimeCurrent();// The variable stores the time of start of the Expert Advisor
//--- Create the indicator's handle
   MA_handle=iMA(Symbol(),0,MA_Period,MA_shift,MA_smooth,price);
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(CopyBuffer(MA_handle,0,0,2,v)<=0)
     {Print("#",magic,"Error of copying");return;}
   type_MA=prov.TYPE(v); // Determine type depending on MA indication
   mg.SetMagic_result(magic);// put the information into the structure
   if(mg.PositionVirtualMagic(_enum,_Symbol,CurrentTime))// If three is an open position 
     {
      if((int)mg.cTYPE()!=type_MA)// Check if it is time to close
        {
         mg.SetMagic_result(magic);// put the information into the structure
         Print("#",mg.GetMagic_result(_enum),"Position by magic number has volume ",mg.cVOLUME(),
               " reverse position of type ",(int)mg.cTYPE()," by ",type_MA);
         //cpvm.cVOLUME() - volume of virtual position
         rezult=prov.SendOrder((ENUM_ORDER_TYPE)type_MA,mg.cVOLUME()+lot);// reverse position
         if(rezult!=-1)Print("№",magic," Code of the operation result ",rezult," volume ",res.volume);
         else{Print("№",magic,"Error",GetLastError()); return;}
        }
     }
   else // If there is no open position then open
     {
      Print("#",magic,"Position by magic number has volume  ",mg.cVOLUME()," open position of type",type_MA);
      rezult=prov.SendOrder((ENUM_ORDER_TYPE)type_MA,lot);// Open position 
      if(rezult!=-1)Print("#",magic," Code of the operation result ",rezult," volume ",res.volume);
      else{Print("#",magic,"Error",GetLastError()); return;}
     }
  }

Comme mentionné précédemment, cet Expert Advisor est extrêmement simple et a été élaboré uniquement pour démontrer les différentes capacités, exécutez-le trois fois sur un seul instrument:

Figure 6. Installation de trois Expert Advisors, avec différentes magies sur différents graphiques

Figure 6. Installation de trois Expert Advisors, avec différentes magies sur différents graphiques

Figure 7. Le résultat est le trading non conflictuel de trois Expert Advisors avec des magies différentes

Figure 7. Le résultat est le trading non conflictuel de trois Expert Advisors avec des magies différentes

Comme le montrent les impressions des messages des Expert Advisors, les trois participants ont été lancés avec succès et n’ont affiché aucun conflit.


Conclusion

En offrant la possibilité d’attribuer des ordres magiques aux opérations de trading, les créateurs de MQL5, ont grandement facilité la vie des rédacteurs Expert Advisor. Mais les développeurs ne peuvent vous fournir que des instruments - vous devez être celui qui obtient réellement les diamants.

Bonne chance et jusqu’à ce que nous nous retrouvions.


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

Fichiers joints |
magic_exp0_en.mq5 (8.34 KB)
magic_exp1_en.mq5 (11.84 KB)
magic_exp2_en.mq5 (25.39 KB)
Une bibliothèque pour créer un graphique via l'API Google Chart Une bibliothèque pour créer un graphique via l'API Google Chart
La création de différents types de diagrammes est une partie essentielle des analyses de l’état du marché et du test d'un système de trading. Fréquemment, afin de créer un beau diagramme, il est nécessaire d'organiser les données de sortie dans un fichier, après quoi elles sont utilisées dans des applications telles que MS Excel. Ce n'est pas très pratique et nous prive de la possibilité de mettre à jour dynamiquement les données. L'API Google Charts a fourni les moyens de créer des graphiques en mode en ligne, en envoyant une requête spéciale au serveur. Dans cet article, nous tentons d'automatiser le processus de création d'une telle demande et d'obtention d'un graphique du serveur Google.
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
Une solution sans DLL pour communiquer entre les terminaux MetaTrader 5 à l'aide de Canaux Nommés Une solution sans DLL pour communiquer entre les terminaux MetaTrader 5 à l'aide de Canaux Nommés
L'article décrit comment implémenter la communication inter-processus entre les terminaux clients MetaTrader 5 à l'aide de Canaux Nommés. Pour l'utilisation des Canaux Nommés, la classe CNamedPipes est élaborée. Pour tester son utilisation et mesurer le débit de la connexion, l'indicateur de coche, les scripts serveur et client sont présentés. L'utilisation de Canaux Nommés est suffisante pour les offres en temps réel.
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.