English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Le MQL5 Cookbook : Ordres ОСО

Le MQL5 Cookbook : Ordres ОСО

MetaTrader 5Exemples | 13 janvier 2022, 16:30
781 0
Denis Kirichenko
Denis Kirichenko

Introduction

Cet article se concentre sur le traitement d’un type de paire d’ordres tel que les OCO. Ce mécanisme est implémenté dans certains terminaux de trading en concurrence avec MetaTrader 5. Je poursuis deux objectifs à travers l’exemple de la création d’un EA avec un panneau pour le traitement des ordres OCO. D’une part, je souhaite décrire les caractéristiques de la bibliothèque standard, d’autre part, je voudrais étendre l’ensemble des outils d’un trader.


1. Essence des ordres OCO

Les ordres OCO (une ordre annule l’autre) représentent une paire de deux ordres en attente.

Ils sont reliés par une fonction d’annulation mutuelle : si le premier se déclenche, le second doit être supprimé, et vice versa.

Fig. 1 Paire d’ordres OCO

Fig. 1 Paire d’ordres OCO

La Fig.1 montre un schéma simple d’interdépendance d’ordre. Elle reflète une définition essentielle : une paire existe tant que les deux ordres existent. En termes de logique, tout ordre de la paire est une condition essentielle mais non suffisante pour l’existence de la paire.

Certaines sources disent que la paire doit avoir un ordre à cours limité et un ordre stop, de plus les ordres doivent avoir une direction (achat ou vente). À mon avis, une telle restriction ne peut pas aider à créer des stratégies de trading flexibles. Je suggère que divers ordres OCO soient analysés dans la paire, et surtout nous essaierons de programmer cette paire.


2. Programmation de paire d’ordres

Dans ma pensée, l’ensemble d’outils de POO est adapté à la programmation de tâches liées au contrôle des ordres OCO de la meilleure façon possible.

Les sections suivantes sont consacrées aux nouveaux types de données qui serviront notre objectif. La classeCiOcoObject vient en premier.


2.1. Classe CiOcoObject

Nous devons donc trouver un objet logiciel responsable du contrôle de deux ordres interconnectés.

Traditionnellement, créons un nouvel objet sur la base de la classe abstraite CObject.

Cette nouvelle classe peut paraître comme suit :

//+------------------------------------------------------------------+
//| Class CiOcoObject                                                |
//| Purpose: a class for OCO orders                                  |            
//+------------------------------------------------------------------+
class CiOcoObject : public CObject
  {
   //--- === Data members === --- 
private:
   //--- tickets of pair
   ulong             m_order_tickets[2];
   //--- initialization flag
   bool              m_is_init;
   //--- id
   uint              m_id;

   //--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CiOcoObject(void){m_is_init=false;};
   void             ~CiOcoObject(void){};
   //--- copy constructor
   void              CiOcoObject(const CiOcoObject &_src_oco);
   //--- assignment operator
   void              operator=(const CiOcoObject &_src_oco);

   //--- initialization/deinitialization
   bool              Init(const SOrderProperties &_orders[],const uint _bunch_cnt=1);
   bool              Deinit(void);
   //--- get id
   uint              Id(void) const {return m_id;};

private:
   //--- types of orders
   ENUM_ORDER_TYPE   BaseOrderType(const ENUM_ORDER_TYPE _ord_type);
   ENUM_BASE_PENDING_TYPE PendingType(const ENUM_PENDING_ORDER_TYPE _pend_type);
   //--- set id
   void              Id(const uint _id){m_id=_id;};
  };

Chaque paire d’ordres OCO aura son propre identifiant. Sa valeur est définie au moyen du générateur de nombres aléatoires (objet de la classe CRandom ).

Les méthodes d’initialisation et de désinitialisation des paires sont préoccupantes dans le contexte de l’interface. Le premier crée (initialise) la paire, et le second la supprime (désinitialise).

La méthodeCiOcoObject::Init() accepte un tableau de structures de type SOrderProperties comme argument. Ce type de structure représente les propriétés de l’ordre dans la paire, c’est-à-dire l’ordre OCO.


2.2 Structure de SOrderProperties

Considérons les champs de la structure susmentionnée.

//+------------------------------------------------------------------+
//| Order properties structure                                       |
//+------------------------------------------------------------------+
struct SOrderProperties
  {
   double                  volume;           // order volume   
   string                  symbol;           // symbol
   ENUM_PENDING_ORDER_TYPE order_type;       // order type   
   uint                    price_offset;     // offset for execution price, points
   uint                    limit_offset;     // offset for limit price, points
   uint                    sl;               // stop loss, points
   uint                    tp;               // take profit, points
   ENUM_ORDER_TYPE_TIME    type_time;        // expiration type
   datetime                expiration;       // expiration
   string                  comment;          // comment
  }

Donc, pour que la méthode d’initialisation fonctionne, nous devons précédemment remplir le tableau de structures composé de deux éléments. En termes simples, nous devons expliquer au programme les ordres qu’il passera.

L’énumération du type ENUM_PENDING_ORDER_TYPE est utilisée dans la structure :

//+------------------------------------------------------------------+
//| Pending order type                                               |
//+------------------------------------------------------------------+
enum ENUM_PENDING_ORDER_TYPE
  {
   PENDING_ORDER_TYPE_BUY_LIMIT=2,       // Buy Limit
   PENDING_ORDER_TYPE_SELL_LIMIT=3,      // Sell Limit
   PENDING_ORDER_TYPE_BUY_STOP=4,        // Buy Stop
   PENDING_ORDER_TYPE_SELL_STOP=5,       // Sell Stop
   PENDING_ORDER_TYPE_BUY_STOP_LIMIT=6,  // Buy Stop Limit
   PENDING_ORDER_TYPE_SELL_STOP_LIMIT=7, // Sell Stop Limit
  };

D’une manière générale, elle ressemble à l’énumération standard ENUM _ORDER_TYPE, mais elle permet de sélectionner uniquement les ordres en attente ou, plus vraiment, les types de ces ordres.

Elle protège contre les erreurs lors de la sélection du type d’ordre correspondant dans les paramètres d’entrée (Fig.2).

Fig. 2. Le champ « Type » avec une liste déroulante des types d’ordre disponibles

Fig. 2. Le champ « Type » avec une liste déroulante des types d’ordres disponibles

Toutefois, si nous utilisons l’énumération standard ENUM _ORDER_TYPE , nous pourrions définir un type d’ordre boursier (ORDER_TYPE_BUY ou ORDER_TYPE_SELL), ce qui n’est pas nécessaire car nous traitons uniquement des ordres en attente.


2.3. Initialisation de la paire

Comme indiqué ci-dessus, la méthode CiOcoObject::Init() est engagée dans l’initialisation de la paire d’ordres.

En fait, elle place la paire d’ordre elle-même et enregistre le succès ou l’échec de l’émergence d’une nouvelle paire. Je dois dire qu’il s’agit d’une méthode active, car elle effectue des opérations de trading par elle-même. Nous pouvons également créer une méthode passive. Elle se connectera simplement à une paire d’ordres en attente déjà actifs qui ont été passés indépendamment.

Je ne fournirai pas de code de l’ensemble de la méthode. Mais je voudrais noter qu’il est important de calculer tous les prix (ouverture, arrêt, profit, limite), afin que la méthode de classe de trade CTrade::OrderOpen() puisse effectuer un ordre de trade. À cette fin, nous devrions considérer deux choses: la direction de l’ordre (achat ou vente) et la position d’un prix d’exécution de l’ordre par rapport à un prix actuel (supérieur ou inférieur).

Cette méthode appelle quelques méthodes privées : BaseOrderType() et PendingType(). La première définit la direction de l’ordre, la seconde détermine le type d’ordre en attente.

Si l’ordre est passé, son ticket est enregistré dans le tableau m_order_tickets[].

J’ai utilisé un script Init_OCO.mq5 simple pour tester cette méthode.

#property script_show_inputs
//---
#include "CiOcoObject.mqh"
//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
sinput string Info_order1="+===--Order 1--====+";   // +===--Order 1--====+
input ENUM_PENDING_ORDER_TYPE InpOrder1Type=PENDING_ORDER_TYPE_SELL_LIMIT; // Type
input double InpOrder1Volume=0.02;                  // Volume
input uint InpOrder1PriceOffset=125;                // Offset for execution price, points
input uint InpOrder1LimitOffset=50;                 // Offset for limit price, points
input uint InpOrder1SL=250;                         // Stop loss, points
input uint InpOrder1TP=455;                         // Profit, points
input string InpOrder1Comment="OCO Order 1";        // Comment
//---
sinput string Info_order2="+===--Order 2--====+";   // +===--Order 2--====+
input ENUM_PENDING_ORDER_TYPE InpOrder2Type=PENDING_ORDER_TYPE_SELL_STOP; // Type
input double InpOrder2Volume=0.04;                  // Volume    
input uint InpOrder2PriceOffset=125;                // Offset for execution price, points
input uint InpOrder2LimitOffset=50;                 // Offset for limit price, points
input uint InpOrder2SL=275;                         // Stop loss, points
input uint InpOrder2TP=300;                         // Profit, points
input string InpOrder2Comment="OCO Order 2";        // Comment

//--- globals
CiOcoObject myOco;
SOrderProperties gOrdersProps[2];
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- property of the 1st order
   gOrdersProps[0].order_type=InpOrder1Type;
   gOrdersProps[0].volume=InpOrder1Volume;
   gOrdersProps[0].price_offset=InpOrder1PriceOffset;
   gOrdersProps[0].limit_offset=InpOrder1LimitOffset;
   gOrdersProps[0].sl=InpOrder1SL;
   gOrdersProps[0].tp=InpOrder1TP;
   gOrdersProps[0].comment=InpOrder1Comment;

//--- property of the 2nd order
   gOrdersProps[1].order_type=InpOrder2Type;
   gOrdersProps[1].volume=InpOrder2Volume;
   gOrdersProps[1].price_offset=InpOrder2PriceOffset;
   gOrdersProps[1].limit_offset=InpOrder2LimitOffset;
   gOrdersProps[1].sl=InpOrder2SL;
   gOrdersProps[1].tp=InpOrder2TP;
   gOrdersProps[1].comment=InpOrder2Comment;

//--- initialization of pair
   if(myOco.Init(gOrdersProps))
      PrintFormat("Id of new OCO pair: %I32u",myOco.Id());
   else
      Print("Error when placing OCO pair!");
  }

Ici, vous pouvez définir diverses propriétés des ordres futurs de la paire. MetaTrader 5 a six différents types d’ordres en attente.

Dans ce contexte, il peut y avoir 15 variantes (combinaisons) de paires (à condition qu’il y ait différents ordres dans la paire).

C(k,N) = C(2,6) = 15

Toutes les variantes ont été testées à l’aide du script. Je vais donner un exemple pour la paire Buy Stop - Buy Stop Limit.

Les types d’ordres doivent être spécifiés dans les paramètres de script (Fig.3).


Fig. 3. Paire d’ordres « Buy Stop » avec ordres « Buy Stop Limit »

Fig. 3. Paire d’ordres « Buy Stop » avec ordre « Buy Stop Limit »

Les informations suivantes apparaîtront dans le registre « Experts »:

QO      0       17:17:41.020    Init_OCO (GBPUSD.e,M15) Code of request result: 10009
JD      0       17:17:41.036    Init_OCO (GBPUSD.e,M15) New order ticket: 24190813
QL      0       17:17:41.286    Init_OCO (GBPUSD.e,M15) Code of request result: 10009
JH      0       17:17:41.286    Init_OCO (GBPUSD.e,M15) New order ticket: 24190814
MM      0       17:17:41.379    Init_OCO (GBPUSD.e,M15) Id of new OCO pair: 3782950319

Mais nous ne pouvons pas travailler avec les ordres OCO au maximum à l’aide du script sans recourir à la boucle.


2.4. Désinitialisation de la paire

Cette méthode est responsable du contrôle de la paire d’ordres. La paire « meurt » lorsqu’un ordre quitte la liste des ordres actifs.

Je suppose que cette méthode devrait être placée dans les gestionnaires OnTrade() ou OnTradeTransaction() du code de l’EA. De cette manière, l’EA sera en mesure de traiter l’activation de toute ordre de la paire sans délai.

//+------------------------------------------------------------------+
//| Deinitialization of pair                                         |
//+------------------------------------------------------------------+
bool CiOcoObject::Deinit(void)
  {
//--- if pair is initialized
   if(this.m_is_init)
     {
      //--- check your orders 
      for(int ord_idx=0;ord_idx<ArraySize(this.m_order_tickets);ord_idx++)
        {
         //--- current pair order
         ulong curr_ord_ticket=this.m_order_tickets[ord_idx];
         //--- another pair order
         int other_ord_idx=!ord_idx;
         ulong other_ord_ticket=this.m_order_tickets[other_ord_idx];

         //---
         COrderInfo order_obj;

         //--- if there is no current order
         if(!order_obj.Select(curr_ord_ticket))
           {
            PrintFormat("Order #%d is not found in active orders list.",curr_ord_ticket);
            //--- attempt to delete another order                 
            if(order_obj.Select(other_ord_ticket))
              {
               CTrade trade_obj;
               //---
               if(trade_obj.OrderDelete(other_ord_ticket))
                  return true;
              }
           }
        }
     }
//---
   return false;
  }

J’aimerais mentionner un détail. L’indicateur d’initialisation de paire est vérifié dans le corps de la méthode de classe. Toute tentative de vérification des ordres ne sera pas effectuée si l’indicateur est effacé. Cette approche empêche la suppression d’un ordre actif lorsqu’un autre n’a pas encore été passé.

Ajoutons des fonctionnalités au script où quelques ordres ont été passés. À cette fin, nous allons créer Control_OCO_EA.mq5 EA de test.

D’une manière générale, l’EA ne diffère du script que par le bloc de gestion des événements Trade() dans son code :

//+------------------------------------------------------------------+
//| Trade function                                                   |
//+------------------------------------------------------------------+
void OnTrade()
  {
//--- OCO pair deinitialization
   if(myOco.Deinit())
     {
      Print("No more order pair!");
      //--- clear  pair
      CiOcoObject new_oco;
      myOco=new_oco;
     }
  }

La vidéo montre le travail des deux programmes dans le terminal MetaTrader 5.


Cependant, les deux programmes de test ont des faiblesses.

Le premier programme (script) ne peut que créer activement la paire, mais il perd ensuite le contrôle sur elle.

Le deuxième programme (Expert Advisor) contrôle la paire, mais il ne peut pas créer à plusieurs reprises d’autres paires après la création de la première. Pour rendre le programme d’ordre OCO (script) complet, nous devons élargir son ensemble d’outils avec la possibilité de passer des ordres. Nous le ferons dans la section suivante.


3. Contrôle de l’EA

Laissez-nous créer le panneau de gestion des ordres OCO sur le graphique pour placer et définir les paramètres des ordres de la paire.

Il fera partie de l’EA de contrôle (Fig.4). Le code source se trouve dans Panel_OCO_EA.mq5.

Fig. 4. Panneau de création des ordres OCO : état initial

Fig. 4. Panneau de création des ordres OCO : état initial


Nous devons sélectionner un type d’ordre future et remplir les champs pour passer la paire d’ordres OCO.

Ensuite, l’étiquette sur le seul bouton du panneau sera modifiée (propriété de texte, Fig.5).

Fig. 5. Panneau de création des ordres OCO : nouvelle paire

Fig. 5. Panneau de création des ordres OCO : nouvelle paire


Les classes suivantes de la bibliothèque standard ont été utilisées pour construire notre panneau :

  • CAppDialog est la boîte de dialogue principale de l’application ;
  • CPanel est une étiquette rectangulaire ;
  • CLabel est une étiquette de texte ;
  • CComboBox est un champ avec une liste déroulante ;
  • CEdit est un champ de saisie ;
  • CButton est un bouton.

Bien sûr, les méthodes de classe parent ont été appelées automatiquement.

Maintenant, nous passons au code. Il faut dire que la partie de la bibliothèque standard qui a été consacrée à la création de panneaux d’indication et de dialogues est assez grande.

Par exemple, si vous souhaitez attraper un événement de fermeture de la liste déroulante, vous devrez plonger profondément dans la pile d’appels (Fig. 6).

Fig. 6. Pile d’appels

Fig. 6. Pile d’appels


Un développeur définit des macros et une notation dans le fichier %MQL5\Include\Controls\Defines.mqh pour des événements spécifiques.

J’ai créé l’événement personnalisé ON_OCO pour créer la paire OCO.

#define ON_OCO (101) // OCO pair creation event 

Les paramètres des ordres futures sont remplis et la paire est générée dans le corps du gestionnaire OnChartEvent().  

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- handling all chart events by main dialog
   myDialog.ChartEvent(id,lparam,dparam,sparam);

//--- drop-down list handling
   if(id==CHARTEVENT_CUSTOM+ON_CHANGE)
     {
      //--- if it is Panel list
      if(!StringCompare(StringSubstr(sparam,0,7),"myCombo"))
        {
         static ENUM_PENDING_ORDER_TYPE prev_vals[2];
         //--- list index
         int combo_idx=(int)StringToInteger(StringSubstr(sparam,7,1))-1;

         ENUM_PENDING_ORDER_TYPE curr_val=(ENUM_PENDING_ORDER_TYPE)(myCombos[combo_idx].Value()+2);
         //--- remember order type change
         if(prev_vals[combo_idx]!=curr_val)
           {
            prev_vals[combo_idx]=curr_val;
            gOrdersProps[combo_idx].order_type=curr_val;
           }
        }
     }

//--- handling input fields
   else if(id==CHARTEVENT_OBJECT_ENDEDIT)
     {
      //--- if it is Panel's input field
      if(!StringCompare(StringSubstr(sparam,0,6),"myEdit"))
        {
         //--- find object
         for(int idx=0;idx<ArraySize(myEdits);idx++)
           {
            string curr_edit_obj_name=myEdits[idx].Name();
            long curr_edit_obj_id=myEdits[idx].Id();
            //--- if names coincide
            if(!StringCompare(sparam,curr_edit_obj_name))
              {
               //--- get current value of field
               double value=StringToDouble(myEdits[idx].Text());
               //--- define gOrdersProps[] array index
               int order_num=(idx<gEditsHalfLen)?0:1;
               //--- define gOrdersProps structure field number
               int jdx=idx;
               if(order_num)
                  jdx=idx-gEditsHalfLen;
               //--- fill up gOrdersProps structure field
               switch(jdx)
                 {
                  case 0: // volume
                    {
                     gOrdersProps[order_num].volume=value;
                     break;
                    }
                  case 1: // execution
                    {
                     gOrdersProps[order_num].price_offset=(uint)value;
                     break;
                    }
                  case 2: // limit
                    {
                     gOrdersProps[order_num].limit_offset=(uint)value;
                     break;
                    }
                  case 3: // stop
                    {
                     gOrdersProps[order_num].sl=(uint)value;
                     break;
                    }
                  case 4: // profit
                    {
                     gOrdersProps[order_num].tp=(uint)value;
                     break;
                    }
                 }
              }
           }
         //--- OCO pair creation flag
         bool is_to_fire_oco=true;
         //--- check structure filling 
         for(int idx=0;idx<ArraySize(gOrdersProps);idx++)
           {
            //---  if order type is set 
            if(gOrdersProps[idx].order_type!=WRONG_VALUE)
               //---  if volume is set  
               if(gOrdersProps[idx].volume!=WRONG_VALUE)
                  //---  if offset for execution price is set
                  if(gOrdersProps[idx].price_offset!=(uint)WRONG_VALUE)
                     //---  if offset for limit price is set
                     if(gOrdersProps[idx].limit_offset!=(uint)WRONG_VALUE)
                        //---  if stop loss is set
                        if(gOrdersProps[idx].sl!=(uint)WRONG_VALUE)
                           //---  if take profit is set
                           if(gOrdersProps[idx].tp!=(uint)WRONG_VALUE)
                              continue;

            //--- clear OCO pair creation flag 
            is_to_fire_oco=false;
            break;
           }
         //--- create OCO pair?
         if(is_to_fire_oco)
           {
            //--- complete comment fields
            for(int ord_idx=0;ord_idx<ArraySize(gOrdersProps);ord_idx++)
               gOrdersProps[ord_idx].comment=StringFormat("OCO Order %d",ord_idx+1);
            //--- change button properties
            myButton.Text("New pair");
            myButton.Color(clrDarkBlue);
            myButton.ColorBackground(clrLightBlue);
            //--- respond to user actions 
            myButton.Enable();
           }
        }
     }
//--- handling click on button
   else if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- if it is OCO pair creation button
      if(!StringCompare(StringSubstr(sparam,0,6),"myFire"))
         //--- if to respond to user actions
         if(myButton.IsEnabled())
           {
            //--- generate OCO pair creation event
            EventChartCustom(0,ON_OCO,0,0.0,"OCO_fire");
            Print("Command to create new bunch has been received.");
           }
     }
//--- handling new pair initialization command 
   else if(id==CHARTEVENT_CUSTOM+ON_OCO)
     {
      //--- OCO pair initialization
      if(gOco.Init(gOrdersProps,gOcoList.Total()+1))
        {
         PrintFormat("Id of new OCO pair: %I32u",gOco.Id());
         //--- copy pair
         CiOcoObject *ptr_new_oco=new CiOcoObject(gOco);
         if(CheckPointer(ptr_new_oco)==POINTER_DYNAMIC)
           {
            //--- add to list
            int node_idx=gOcoList.Add(ptr_new_oco);
            if(node_idx>-1)
               PrintFormat("Total number of bunch: %d",gOcoList.Total());
            else
               PrintFormat("Error when adding OCO pair %I32u to list!",gOco.Id());
           }
        }
      else
         Print("OCO-orders placing error!");

      //--- clear properties
      Reset();
     }
  }

Le code du gestionnaire n’est pas petit. Je voudrais mettre l’accent sur plusieurs blocs.

La première gestion de tous les événements de graphique est donnée à la boîte de dialogue principale.

Viennent ensuite les blocs de gestion de divers événements :

  • Modification des listes déroulantes pour définir un type d’ordre ;
  • Modification des champs de saisie pour remplir les propriétés des ordres ;
  • Cliquez sur le bouton pour la génération d’événements ON_OCO ;
  • ON_OCO réponse à l’événement : création d’une paire d’ordres.

L’EA ne vérifie pas l’exactitude du remplissage des champs du panneau. C’est pourquoi nous devons vérifier les valeurs par nous-mêmes, sinon l’EA affichera une erreur de passation des ordres OCO.

La nécessité de supprimer la paire et de fermer l’ordre restant est vérifiée dans le corps du gestionnaire OnTrade().


Conclusion

J’ai essayé de démontrer les richesses des classes de la bibliothèque standard qui peuvent être utilisées pour l’accomplissement de certaines tâches spécifiques.

En particulier, nous étions confrontés à un problème de traitement des ordres OCO. J’espère que le code de l’EA avec panneau de gestion des ordres OCO sera un point de départ pour la création de paires d’ordres plus compliquées.


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

Fichiers joints |
ciocoobject.mqh (27.71 KB)
crandom.mqh (5.19 KB)
init_oco.mq5 (6.42 KB)
control_oco_ea.mq5 (7.88 KB)
panel_oco_ea.mq5 (30.25 KB)
Création d'une application interactive pour afficher les flux RSS dans MetaTrader 5 Création d'une application interactive pour afficher les flux RSS dans MetaTrader 5
Dans cet article, nous examinons la possibilité de créer une application pour l'affichage de flux RSS. L'article montrera comment les aspects de la bibliothèque standard peuvent être utilisés pour créer des programmes interactifs pour MetaTrader 5.
Sur les méthodes d'analyse technique et de prévision du marché Sur les méthodes d'analyse technique et de prévision du marché
L'article démontre les capacités et le potentiel d'une méthode mathématique bien connue associée à une pensée visuelle et à des perspectives de marché « out of the box ». D'une part, il sert à attirer l'attention d'un large public car il peut amener les esprits créatifs à reconsidérer le paradigme de trading en tant que tel. Et d'autre part, il peut donner lieu à des développements alternatifs et à des implémentations de code de programme concernant un large éventail d'outils d'analyse et de prévision.
Idées de trading basées sur la direction des prix et la vitesse de déplacement Idées de trading basées sur la direction des prix et la vitesse de déplacement
L'article propose une revue d'idée basée sur l'analyse de la direction du mouvement des prix et de leur vitesse. Nous avons effectué sa formalisation dans le langage MQL4 présenté en tant qu'expert advisor pour explorer la viabilité de la stratégie envisagée. Nous déterminons également les meilleurs paramètres via la vérification, l'examen et l'optimisation d'un exemple donné dans l'article.
La règle d'or des Traders La règle d'or des Traders
Afin de réaliser des bénéfices basés sur des attentes élevées, nous devons comprendre trois principes de base d'un bon trading : 1) connaître votre risque en entrant sur le marché ; 2) réduisez vos pertes tôt et laissez courir vos bénéfices ; 3) connaître les attentes de votre système - tester et ajuster régulièrement. Cet article fournit un code de programme qui suit les positions ouvertes et actualise le deuxième principe d'or, car il permet aux bénéfices de courir au plus haut niveau possible.