English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Contrôler  la Pente de la Courbe d' Équilibre Pendant le Travail d'un Expert Advisor

Contrôler la Pente de la Courbe d' Équilibre Pendant le Travail d'un Expert Advisor

MetaTrader 5Trading | 17 novembre 2021, 16:01
339 0
Dmitriy Skub
Dmitriy Skub


Introduction

Cet article décrit l'une des approches qui permet d'améliorer les performances des Expert Advisors un feedback. Dans ce cas, le feedback sera basé sur la mesure de la pente de la courbe d'équilibre. Le contrôle de la pente s'effectue automatiquement en réglant le volume de travail. Un Expert Advisor peut trader dans les modes suivants : avec un volume de coupe, avec une quantité de travail de lots (selon celle initialement ajustée) et avec un volume intermédiaire. Le mode de fonctionnement est échangé automatiquement.

Différentes caractéristiques de régulation sont utilisées dans la chaîne de feedback : échelonnée, échelonnée avec hystérésis, linéaire. Il permet d'ajuster le système de contrôle de la pente de la courbe d'équilibre aux caractéristiques d'un certain système.

L'idée principale est d'automatiser le processus de prise de décision pour un trader tout en surveillant son propre système de trading Il est raisonnable de réduire les risques pendant les périodes défavorables de son fonctionnement. Au retour au mode de fonctionnement normal, les risques peuvent être rétablis à leur niveau initial.

Bien sûr, ce système n'est pas une panacée, et il ne transformera pas un Expert Advisor perdant en un conseiller rentable. D'une certaine manière, il s'agit d'un ajout au MM (gestion de l'argent) d'Expert Advisor qui l'empêche de subir des pertes considérables sur un compte.

L'article comprend une bibliothèque, qui permet d'intégrer cette fonction au code de n'importe quel Expert Advisor.


Principe de Fonctionnement

Examinons le principe de fonctionnement du système, qui contrôle la pente de la courbe d'équilibre. Supposons que nous ayons un Expert Advisor en trading. Sa courbe d'équilibre hypothétique se présente comme suit :

Principe de fonctionnement du système qui contrôle la pente de la courbe d'équilibre

Figure 1. Principe de fonctionnement du système qui contrôle la pente de la courbe d'équilibre

La courbe d'équilibre initiale pour l'Expert Advisor qui utilise un volume constant d'opérations de trade est illustrée ci-dessus. Les trades clos sont indiqués avec les points rouges. Connectons ces points avec une ligne courbe, qui représente le changement d'équilibre de l'Expert Advisor pendant le trading (ligne noire épaisse).

Nous allons maintenant surveiller en continu l'angle de pente de cette ligne par rapport à l'axe du temps (indiqué par de fines lignes bleues). Ou pour être plus précis, avant d'ouvrir chaque trade par un signal, nous calculerons l'angle de pente par deux trades précédemment clos (ou par deux trades, pour que la description soit plus simple). Si l'angle de pente devient inférieur à la valeur spécifiée, notre système de contrôle commence à fonctionner ; il diminue le volume en fonction de la valeur calculée de l'angle et de la fonction de régulation indiquée.

De cette manière, si le commerce entre dans une période infructueuse, le volume diminue à partir de Vmax. à Vmindurant la Т3...Т5 période de trading. Après le T5 points, le trading est effectué avec un volume minimal indiqué - dans le mode de rejet du volume de trade. Une fois que la rentabilité de l'Expert Advisor est rétablie et que l'angle de pente de la courbe d'équilibre s'élève au-dessus de la valeur indiquée, le volume commence à augmenter. Cela se produit dans l'intervalle Т8...Т10. Après le point Т10, le volume des opérations de trade revient à l'état initial Vmax.

La courbe d'équilibre formée à la suite d'une telle régulation est représentée dans la partie inférieure de la fig. 1. Vous pouvez constater que le prélèvement initial de B1 à B2 a diminué et est devenu de B1 à B2*. Vous pouvez également observer que le bénéfice a légèrement diminué pendant la période de rétablissement du volume maximum Т8...Т10 - c'est le revers de la médaille.

La couleur verte met en évidence la partie de la courbe d'équilibre lorsque le trading a été effectué avec un volume minimal indiqué. La couleur jaune représente les parties de transition du volume maximum au minimum et inversement. Plusieurs variantes de transition sont possibles ici :

  • échelonné - changements de volume par étapes discrètes du volume maximum au minimum et inversement ;
  • linéaire - le volume est modifié linéairement en fonction de l'angle de pente de la courbe d'équilibre dans l'intervalle régulé ;
  • échelonné avec hystérésis - la transition du volume maximum au minimum et inversement est effectuée à des valeurs de différence de l'angle de pente;

Illustrons-le en images :

Types de caractéristiques de régulation

Figure 2. Types de caractéristiques de régulation

Les caractéristiques de régulation affectent les taux du système de contrôle - le retard d'activation/désactivation, le processus de transition du volume maximum au volume minimum et inversement. Il est recommandé de choisir une caractéristique sur une base expérimentale pour obtenir les meilleurs résultats de test.

Ainsi, nous améliorons le système de trading avec le feedback basé sur l'angle de pente de la courbe d'équilibre. Notez qu'une telle régulation du volume ne convient qu'aux systèmes, qui n'ont pas le volume dans le cadre du système de trading lui-même. Par exemple, si le principe de la Martingale est utilisé, vous ne pouvez pas utiliser ce système directement sans modifier l'Expert Advisor initial.

De plus, nous devons attirer notre attention sur les points importants suivants :

  • l'efficacité de la gestion de la pente de la ligne d'équilibre dépend directement du rapport du volume de travail en mode de fonctionnement normal au volume en mode de rejet de volume. Plus grand ce ratio est, plus efficace la gestion est C'est la raison pour laquelle le volume de travail initial doit être largement supérieur au minimum possible.
  • la durée moyenne d'altération des hausses et baisses de la balance de l'Expert Advisor doit être largement plus grande que le temps de réaction du système de contrôle. Sinon, le système ne parviendra pas à régler la pente de la courbe d'équilibre. Plus le rapport entre la période moyenne et le temps de réaction est élevé, plus efficace le système est. Cette exigence touche presque chaque système de régulation automatique.

Implémentation en MQL5 à l'aide de la programmation orientée-objet

Rédigeons une bibliothèque qui assure l'approche décrite ci-dessus. Pour ce faire, utilisons la nouvelle fonctionnalité de MQL5 - l'approche orientée-objet. Cette approche permet d’élaborer et d'étendre facilement notre bibliothèque à l'avenir sans réécrire de grandes parties du code à partir de zéro.


Classe du TradeSymbol

Étant donné que le test en monnaies multiples est implémenté dans la nouvelle plate-forme MetaTrader 5, nous avons besoin d'une classe qui renferme en elle-même l'ensemble du travail avec n'importe quel symbole de travail. Il permet d'utiliser cette bibliothèque dans des Expert Advisors en monnaies multiples. Cette classe ne couvre pas directement le système de contrôle, elle est auxiliaire. Ainsi, cette classe sera utilisée pour les opérations avec le symbole de travail.

//---------------------------------------------------------------------
//  Operations with work symbol:
//---------------------------------------------------------------------
class TradeSymbol
{
private:
  string  trade_symbol;                          // work symbol

private:
  double  min_trade_volume;                      // minimum allowed volume for trade operations
  double  max_trade_volume;                      // maximum allowed volume for trade operations
  double  min_trade_volume_step;                 // minimum change of volume
  double  max_total_volume;                      // maximum change of volume
  double  symbol_point;                          // size of one point
  double  symbol_tick_size;                      // minimum change of price
  int     symbol_digits;                        // number of digits after decimal point

protected:

public:
  void    RefreshSymbolInfo( );                  // refresh market information about the work symbol
  void    SetTradeSymbol( string _symbol );      // set/change work symbol
  string  GetTradeSymbol( );                     // get work symbol
  double  GetMaxTotalLots( );                    // get maximum cumulative volume
  double  GetPoints( double _delta );            // get change of price in points

public:
  double  NormalizeLots( double _requied_lot );  // get normalized trade volume
  double  NormalizePrice( double _org_price );   // get normalized price with consideration of step of change of quote

public:
  void    TradeSymbol( );                       // constructor
  void    ~TradeSymbol( );                      // destructor
};

La structure de la classe est très simple. Le but est d'obtenir, de stocker et de traiter les informations actuelles du marché par un symbole indiqué. Les principales méthodes sont TradeSymbol::RefreshSymbolInfo, TradeSymbol::NormalizeLots, TradeSymbol::NormalizePrice.. Considérons-les un par un.


La méthode TradeSymbol::RefreshSymbolInfo est destinée à l’actualisation des informations du marché par le symbole de travail.

//---------------------------------------------------------------------
//  Refresh market information by work symbol:
//---------------------------------------------------------------------
void
TradeSymbol::RefreshSymbolInfo( )
{
//  If a work symbol is not set, don't do anything:
  if( GetTradeSymbol( ) == NULL )
  {
    return;
  }

//  Calculate parameters necessary for normalization of volume:
  min_trade_volume = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_VOLUME_MIN );
  max_trade_volume = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_VOLUME_MAX );
  min_trade_volume_step = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_VOLUME_STEP );

  max_total_volume = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_VOLUME_LIMIT );

  symbol_point = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_POINT );
  symbol_tick_size = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_TRADE_TICK_SIZE );
  symbol_digits = ( int )SymbolInfoInteger( GetTradeSymbol( ), SYMBOL_DIGITS );
}

Faites attention à un point important qui est utilisé dans plusieurs méthodes. Étant donné que la réalisation actuelle de MQL5 ne permet pas d'utiliser un constructeur avec des paramètres, vous devez faire appel à la méthode suivante pour le réglage principal des symboles de travail :

void    SetTradeSymbol( string _symbol );      // set/change work symbol


La méthode TradeSymbol::NormalizeLots est utilisée pour obtenir un volume correct et normalisé. Nous savons que la taille d'une position ne peut pas être inférieure à la valeur minimale possible autorisée par le courtier. L'étape minimale de changement d'une position est également déterminée par le courtier, et elle peut différer. Cette méthode renvoie la valeur de volume la plus proche à partir du bas.

EIle vérifie également si le volume de la position supposée dépasse la valeur maximale autorisée par le courtier.

//---------------------------------------------------------------------
//  Get normalized trade volume:
//---------------------------------------------------------------------
//  - input necessary volume;
//  - output is normalized volume;
//---------------------------------------------------------------------
double
TradeSymbol::NormalizeLots( double _requied_lots )
{
  double   lots, koeff;
  int      nmbr;

//  If a work symbol is not set, don't do anything:
  if( GetTradeSymbol( ) == NULL )
  {
    return( 0.0 );
  }

  if( this.min_trade_volume_step > 0.0 )
  {
    koeff = 1.0 / min_trade_volume_step;
    nmbr = ( int )MathLog10( koeff );
  }
  else
  {
    koeff = 1.0 / min_trade_volume;
    nmbr = 2;
  }
  lots = MathFloor( _requied_lots * koeff ) / koeff;

//  Lower limit of volume:
  if( lots < min_trade_volume )
  {
    lots = min_trade_volume;
  }

//  Upper limit of volume:
  if( lots > max_trade_volume )
  {
    lots = max_trade_volume;
  }

  lots = NormalizeDouble( lots, nmbr );
  return( lots );
}


La méthode TradeSymbol::NormalizePrice est utilisée pour obtenir un prix correct et normalisé. Étant donné que le nombre de chiffres significatifs après la virgule (précision du prix) doit être déterminé pour un symbole donné, nous devons tronquer le prix. En plus de cela, certains symboles (par exemple, les contrats à terme) ont une phase minimum de modification de prix supérieur à un point. C'est pourquoi nous devons faire en sorte que les valeurs de prix soient des multiples du minimum de discrétion.

//---------------------------------------------------------------------
//  Normalization of price with consideration of step of price change:
//---------------------------------------------------------------------
double
TradeSymbol::NormalizePrice( double _org_price )
{
//  Minimal step of quote change in points:
  double  min_price_step = NormalizeDouble( symbol_tick_size / symbol_point, 0 );

  double  norm_price = NormalizeDouble( NormalizeDouble(( NormalizeDouble( _org_price / symbol_point, 0 )) / min_price_step, 0 ) * min_price_step * symbol_point, symbol_digits );
  return( norm_price );
}

Le prix non-normalisé nécessaire est introduit dans la fonction. Et il renvoie le prix normalisé, qui est le plus proche du nécessaire.

Le but des autres méthodes est clairement décrit dans les commentaires ; il ne nécessite aucune description supplémentaire.


Classe TBalanceHistory

Cette classe, est destinée à fonctionner avec l'historique du solde d'un compte, qui est clair pour son nom. C'est aussi une classe de base pour plusieurs classes décrites ci-dessous. L'objectif principal de cette classe est d’accéder à l'historique du trade d'un Expert Advisor. De plus, vous pouvez filtrer l'historique par symbole de travail, par « nombre magique », par date de début de suivi de l'Expert Advisor ou par les trois éléments simultanément.

//---------------------------------------------------------------------
//  Operations with balance history:
//---------------------------------------------------------------------
class TBalanceHistory
{
private:
  long      current_magic;            // value of "magic number" when accessing the history of deals ( 0 - any number )
  long      current_type;             // type of deals ( -1 - all )
  int       current_limit_history;    // limit of depth of history ( 0 - all history )
  datetime   monitoring_begin_date;   // date of start of monitoring history of deals
  int       real_trades;              // number of actual trades already performed

protected:
  TradeSymbol  trade_symbol;          // operations with work symbol

protected:
//  "Raw" arrays:
  double    org_datetime_array[ ];    // date/time of trade
  double    org_result_array[ ];      // result of trade

//  Arrays with data grouped by time:
  double    group_datetime_array[ ];  // date/time of trade
  double    group_result_array[ ];    // result of trade

  double    last_result_array[ ];     // array for storing results of last trades ( points on the Y axis )
  double    last_datetime_array[ ];   // array for storing time of last trades ( points on the X axis )

private:
  void      SortMasterSlaveArray( double& _m[ ], double& _s[ ] );  // synchronous ascending sorting of two arrays

public:
  void      SetTradeSymbol( string _symbol );                      // set/change work symbol
  string    GetTradeSymbol( );                                    // get work symbol
  void      RefreshSymbolInfo( );                                 // refresh market information by work symbol
  void      SetMonitoringBeginDate( datetime _dt );                // set date of start of monitoring
  datetime  GetMonitoringBeginDate( );                            // get date of start of monitoring
  void      SetFiltrParams( long _magic, long _type = -1, int _limit = 0 );// set parameters of filtration of deals

public:
// Get results of last trades:
  int       GetTradeResultsArray( int _max_trades );

public:
  void      TBalanceHistory( );       // constructor
  void      ~TBalanceHistory( );      // destructor
};

Les paramètres de filtrage lors de l’interprétation des résultats des derniers trades et de l'historique sont définis à l'aide de la méthode TBalanceHistory::SetFiltrParams. Elle dispose des paramètres d'entrée suivants :

  • __magic - "nombre magique" de trade qui doit être lu depuis l’historique Si la valeur zéro est indiquée, donc les trades seront lus avec n’importe quel «nombre magique».
  • _type             -type de deals qui doivent être lus Il peut avoir les valeurs suivantes - DEAL_TYPE_BUY (pour la lecture des trades longs uniquement), DEAL_TYPE_SELL (pour la lecture des trades courts uniquement) et -1 (pour la lecture des trades longs et courts).
  • __limit - limite la profondeur de l’historique analysé des trades. S'il est égal à zéro, tout l'historique disponible est analysé.

Par défaut, les valeurs suivantes sont définies lors de la création de l'objet de la classe TBalanceHistory_magic = 0, _type = -1, __limit = 0.


La méthode principale de cette classe est TBalanceHistory::GetTradeResultsArray. EIle est destinée à remplir les tableaux de membres de classe last_result_array et last_datetime_array avec les résultats des derniers trades. La méthode dispose des paramètres d'entrée suivants :

  • __max_trades - nombre maximum de trades qui doivent être lus à partir de l'historique et écrits dans les tableaux de sortie. Vu que nous avons besoin d'au moins deux points pour calculer l'angle de pente, cette valeur ne doit pas être inférieure à deux. Si cette valeur est égale à zéro, tout l'historique disponible des trades est analysé. Le nombre de points nécessaires au calcul de la pente de la courbe d'équilibre est quasiment indiqué ici.
//---------------------------------------------------------------------
//  Reads the results of last (by time) trades to arrays:
//---------------------------------------------------------------------
//  - returns the number of actually read trades but not more than specified;
//---------------------------------------------------------------------
int
TBalanceHistory::GetTradeResultsArray( int _max_trades )
{
  int       index, limit, count;
  long      deal_type, deal_magic, deal_entry;
  datetime   deal_close_time, current_time;
  ulong     deal_ticket;                        // ticket of deal
  double    trade_result;
  string    symbol, deal_symbol;

  real_trades = 0;

//  Number of trades should be no less than two:
  if( _max_trades < 2 )
  {
    return( 0 );
  }

//  If a work symbol is not specified, don't do anything:
  symbol = trade_symbol.GetTradeSymbol( );
  if( symbol == NULL )
  {
    return( 0 );
  }

//  Request the history of deals and orders from the specified time to the current moment:
  if( HistorySelect( monitoring_begin_date, TimeCurrent( )) != true )
  {
    return( 0 );
  }

//  Calculate number of trades:
  count = HistoryDealsTotal( );

//  If there are less trades in the history than it is necessary, then exit:
  if( count < _max_trades )
  {
    return( 0 );
  }

//  If there are more trades in the history than it is necessary, then limit them:
  if( current_limit_history > 0 && count > current_limit_history )
  {
    limit = count - current_limit_history;
  }
  else
  {
    limit = 0;
  }

//  If needed, adjust dimension of "raw" arrays by the specified number of trades:
  if(( ArraySize( org_datetime_array )) != ( count - limit ))
  {
    ArrayResize( org_datetime_array, count - limit );
    ArrayResize( org_result_array, count - limit );
  }

//  Fill the "raw" array with trades from history base:
  real_trades = 0;
  for( index = count - 1; index >= limit; index-- )
  {
    deal_ticket = HistoryDealGetTicket( index );

//  If those are not closed deals, don't go further:
    deal_entry = HistoryDealGetInteger( deal_ticket, DEAL_ENTRY );
    if( deal_entry != DEAL_ENTRY_OUT )
    {
      continue;
    }

//  Check "magic number" of deal if necessary:
    deal_magic = HistoryDealGetInteger( deal_ticket, DEAL_MAGIC );
    if( current_magic != 0 && deal_magic != current_magic )
    {
      continue;
    }

//  Check symbol of deal:
    deal_symbol = HistoryDealGetString( deal_ticket, DEAL_SYMBOL );
    if( symbol != deal_symbol )
    {
      continue;
    }
                
//  Check type of deal if necessary:
    deal_type = HistoryDealGetInteger( deal_ticket, DEAL_TYPE );
    if( current_type != -1 && deal_type != current_type )
    {
      continue;
    }
    else if( current_type == -1 && ( deal_type != DEAL_TYPE_BUY && deal_type != DEAL_TYPE_SELL ))
    {
      continue;
    }
                
//  Check time of closing of deal:
    deal_close_time = ( datetime )HistoryDealGetInteger( deal_ticket, DEAL_TIME );
    if( deal_close_time < monitoring_begin_date )
    {
      continue;
    }

//  So, we can read another trade:
    org_datetime_array[ real_trades ] = deal_close_time / 60;
    org_result_array[ real_trades ] = HistoryDealGetDouble( deal_ticket, DEAL_PROFIT ) / HistoryDealGetDouble( deal_ticket, DEAL_VOLUME );
    real_trades++;
  }

//  if there are less trades than necessary, return:
  if( real_trades < _max_trades )
  {
    return( 0 );
  }

  count = real_trades;

//  Sort the "raw" array by date/time of closing the order:
  SortMasterSlaveArray( org_datetime_array, org_result_array );

// If necessary, adjust dimension of group arrays for the specified number of points:
  if(( ArraySize( group_datetime_array )) != count )
  {
    ArrayResize( group_datetime_array, count );
    ArrayResize( group_result_array, count );
  }
  ArrayInitialize( group_datetime_array, 0.0 );
  ArrayInitialize( group_result_array, 0.0 );

//  Fill the output array with grouped data ( group by the identity of date/time of position closing ):
  for( index = 0; index < count; index++ )
  {
//  Get another trade:
    deal_close_time = ( datetime )org_datetime_array[ index ];
    trade_result = org_result_array[ index ];

//  Now check if the same time already exists in the output array:
    current_time = ( datetime )group_datetime_array[ real_trades ];
    if( current_time > 0 && MathAbs( current_time - deal_close_time ) > 0.0 )
    {
      real_trades++;                      // move the pointer to the next element
      group_result_array[ real_trades ] = trade_result;
      group_datetime_array[ real_trades ] = deal_close_time;
    }
    else
    {
      group_result_array[ real_trades ] += trade_result;
      group_datetime_array[ real_trades ] = deal_close_time;
    }
  }
  real_trades++;                          // now this is the number of unique elements

//  If there are less trades than necessary, exit:
  if( real_trades < _max_trades )
  {
    return( 0 );
  }

  if( ArraySize( last_result_array ) != _max_trades )
  {
    ArrayResize( last_result_array, _max_trades );
    ArrayResize( last_datetime_array, _max_trades );
  }

//  Write the accumulated data to the output arrays with reversed indexation:
  for( index = 0; index < _max_trades; index++ )
  {
    last_result_array[ _max_trades - 1 - index ] = group_result_array[ index ];
    last_datetime_array[ _max_trades - 1 - index ] = group_datetime_array[ index ];
  }

//  In the output array replace the results of single trades with the accumulating total:
  for( index = 1; index < _max_trades; index++ )
  {
    last_result_array[ index ] += last_result_array[ index - 1 ];
  }

  return( _max_trades );
}

Des contrôles obligatoires sont effectués au début - si un symbole de travail est indiqué et si les paramètres d'entrée sont corrects.

Ensuite, nous lisons l'historique des trades et des commandes de la date indiquée à l’instant courant. Elle est réalisée dans la partie suivante du code :

//  Request the history of deals and orders from the specified time to the current moment:
  if( HistorySelect( monitoring_begin_date, TimeCurrent( )) != true )
  {
    return( 0 );
  }

//  Calculate number of trades:
  count = HistoryDealsTotal( );

//  If there are less trades in the history than it is necessary, then exit:
  if( count < _max_trades )
  {
    return( 0 );
  }

De plus, le nombre total de deals dans l'historique est vérifié. S'il est inférieur à ce qui est indiqué, d'autres actions n'ont aucun sens. Dès que les tableaux "bruts" sont préparés, le cycle de remplissage avec les informations de l'historique des trades est exécuté. Cela se fait de la manière suivante :

//  Fill the "raw" array from the base of history of trades:
  real_trades = 0;
  for( index = count - 1; index >= limit; index-- )
  {
    deal_ticket = HistoryDealGetTicket( index );

//  If the trades are not closed, don't go further:
    deal_entry = HistoryDealGetInteger( deal_ticket, DEAL_ENTRY );
    if( deal_entry != DEAL_ENTRY_OUT )
    {
      continue;
    }

//  Check "magic number" of deal if necessary:
    deal_magic = HistoryDealGetInteger( deal_ticket, DEAL_MAGIC );
    if( _magic != 0 && deal_magic != _magic )
    {
      continue;
    }

//  Check symbols of deal:
    deal_symbol = HistoryDealGetString( deal_ticket, DEAL_SYMBOL );
    if( symbol != deal_symbol )
    {
      continue;
    }
                
//  Check type of deal if necessary:
    deal_type = HistoryDealGetInteger( deal_ticket, DEAL_TYPE );
    if( _type != -1 && deal_type != _type )
    {
      continue;
    }
    else if( _type == -1 && ( deal_type != DEAL_TYPE_BUY && deal_type != DEAL_TYPE_SELL ))
    {
      continue;
    }
                
//  Check time of closing of deal:
    deal_close_time = ( datetime )HistoryDealGetInteger( deal_ticket, DEAL_TIME );
    if( deal_close_time < monitoring_begin_date )
    {
      continue;
    }

//  So, we can rad another trade:
    org_datetime_array[ real_trades ] = deal_close_time / 60;
    org_result_array[ real_trades ] = HistoryDealGetDouble( deal_ticket, DEAL_PROFIT ) / HistoryDealGetDouble( deal_ticket, DEAL_VOLUME );
    real_trades++;
  }

//  If there are less trades than necessary, exit:
  if( real_trades < _max_trades )
  {
    return( 0 );
  }

Au début, le ticket du deal de l'historique est lu à l'aide de la fonction HistoryDealGetTicket ; une lecture supplémentaire des détails du deal est effectuée à l'aide du ticket obtenu. Vu que nous ne nous intéressons qu'aux trades clos (nous allons analyser le solde), le type de deal est vérifié dans un premier temps. Cela se fait en appelant la fonction HistoryDealGetInteger avec le paramètre DEAL_ENTRY. Si la fonction renvoie DEAL_ENTRY_OUT, alors c'est la clôture d'une position.

Après ce "numéro magique" du deal, le type de deal (le paramètre d'entrée de la méthode est indiqué) et le symbole du deal sont vérifiés. Si tous les paramètres du deal répondent aux exigences, le dernier paramètre est vérifié - l'heure de clôture du deal. Cela se fait de la manière suivante :

//  Check the time of closing of deal:
    deal_close_time = ( datetime )HistoryDealGetInteger( deal_ticket, DEAL_TIME );
    if( deal_close_time < monitoring_begin_date )
    {
      continue;
    }

La date/heure du deal est comparée à la date/heure donnée de début de surveillance de l'historique. Si la date/heure du deal est supérieure à celle donnée, alors nous allons lire notre transaction dans le tableau - lisez le résultat du trade en points et l'heure du trade en minutes (dans ce cas, l'heure de clôture). Après cela, le compteur des deals lus real_trades est augmenté ; et le cycle continue.

Une fois que les tableaux "bruts" sont remplis avec la quantité d'informations nécessaire, nous devons trier le tableau où l'heure de clôture des deals est stockée. Dans le même temps, nous devons conserver la correspondance de l'heure de clôture dans le tableau org_datetime_array et les résultats des deals dans le tableau org_result_array. Cela se fait en utilisant la méthode spécialement écrite:

TBalanceHistory::SortMasterSlaveArray( double& _master[ ], double& _slave[ ] ). Le premier paramètre est _master - le tableau qui est trié par ordre croissant. Le deuxième paramètre est _slave - le tableau dont les éléments doivent être déplacés de manière synchronisée avec les éléments du premier tableau. Le tri est effectué via la méthode "bubble".

Après toutes les opérations décrites ci-dessus, nous avons deux tableaux avec le temps et les résultats des deals triés par temps. Puisqu'un seul point sur la courbe d'équilibre (point sur l'axe Y) peut correspondre à chaque instant du temps (point sur l'axe X), nous devons regrouper les éléments du tableau avec le même temps de clôture (s'il y en a) . La partie suivante du code assure cette opération :

//  Fill the output array with grouped data ( group by identity of date/time of closing of position ):
  real_trades = 0;
  for( index = 0; index < count; index++ )
  {
//  Get another trade:
    deal_close_time = ( datetime )org_datetime_array[ index ];
    trade_result = org_result_array[ index ];

//  Now check, if the same time already exists in the output array:
    current_time = ( datetime )group_datetime_array[ real_trades ];
    if( current_time > 0 && MathAbs( current_time - deal_close_time ) > 0.0 )
    {
      real_trades++;                      // move the pointer to the next element
      group_result_array[ real_trades ] = trade_result;
      group_datetime_array[ real_trades ] = deal_close_time;
    }
    else
    {
      group_result_array[ real_trades ] += trade_result;
      group_datetime_array[ real_trades ] = deal_close_time;
    }
  }
  real_trades++;                          // now this is the number of unique elements

Quasiment , tous les trades avec la "même" heure de clôture sont ajoutés ici. Les résultats sont écrits dans les tableaux TBalanceHistory::group_datetime_array (heure de clôture) et TBalanceHistory::group_result_array (résultats des trades). Ensuite , nous obtenons deux tableaux triés avec des éléments uniques. L'identité du temps dans ce cas est jugée en une minute. Cette transformation peut être graphiquement illustrée :

Groupement des deals avec la même heure

Figure 3. Groupement de deals en même temps

Tous les deals en moins d'une minute (partie gauche de la figure) sont regroupés en un ensemble avec arrondi du temps et ajoutant les résultats (partie droite de la figure). Il permet de lisser le « bavardage » du temps de clôture des deals et d'améliorer la stabilité de la régulation.

Ensuite, vous devez effectuer deux autres transformations des tableaux obtenus. Inversez l'ordre des éléments pour que le premier deal corresponde à l'élément zéro ; et remplacer les résultats des trades individuels par le total cumulé, c'est-à-dire par le solde. Cela se fait dans le fragment suivant du code:

//  Write the accumulated data into output arrays with reversed indexation:
  for( index = 0; index < _max_trades; index++ )
  {
    last_result_array[ _max_trades - 1 - index ] = group_result_array[ index ];
    last_datetime_array[ _max_trades - 1 - index ] = group_datetime_array[ index ];
  }

//  Replace the results of single trades with the cumulative total in the output array:
  for( index = 1; index < _max_trades; index++ )
  {
    last_result_array[ index ] += last_result_array[ index - 1 ];
  }


Classe TBalanceSlope

Cette classe est destinée à réaliser des opérations avec la courbe de solde d'un compte. Il est généré à partir de la classe TBalanceHistory ; et il hérite de toutes ses données et méthodes protégées et publiques. Examinons en détail sa structure :

//---------------------------------------------------------------------
//  Operations with the balance curve:
//---------------------------------------------------------------------
class TBalanceSlope : public TBalanceHistory
{
private:
  double    current_slope;               // current angle of slope of the balance curve
  int       slope_count_points;          // number of points ( trades ) for calculation of slope angle
        
private:
  double    LR_koeff_A, LR_koeff_B;      // rates for the equation of the straight-line regression
  double    LR_points_array[ ];          // array of point of the straight-line regression

private:
  void      CalcLR( double& X[ ], double& Y[ ] );  // calculate the equation of the straight-line regression

public:
  void      SetSlopePoints( int _number );        // set the number of points for calculation of angle of slope
  double    CalcSlope( );                         // calculate the slope angle

public:
  void      TBalanceSlope( );                     // constructor
  void      ~TBalanceSlope( );                    // destructor
};


Nous déterminerons l'angle de pente de la courbe d'équilibre par l'angle de pente de la ligne de régression linéaire tracée pour le nombre indiqué de points (trades) sur la courbe d'équilibre. Ainsi, tout d'abord, nous devons calculer l'équation de la régression linéaire de la forme suivante : A*x + B. La méthode suivante assure ce travail :

//---------------------------------------------------------------------
//  Calculate the equation of the straight-line regression:
//---------------------------------------------------------------------
//  input parameters:
//    X[ ] - arras of values of number series on the X axis;
//    Y[ ] - arras of values of number series on the Y axis;
//---------------------------------------------------------------------
void
TBalanceSlope::CalcLR( double& X[ ], double& Y[ ] )
{
  double    mo_X = 0, mo_Y = 0, var_0 = 0, var_1 = 0;
  int       i;
  int       size = ArraySize( X );
  double    nmb = ( double )size;

//  If the number of points is less than two, the curve cannot be calculated:
  if( size < 2 )
  {
    return;
  }

  for( i = 0; i < size; i++ )
  {
    mo_X += X[ i ];
    mo_Y += Y[ i ];
  }
  mo_X /= nmb;
  mo_Y /= nmb;

  for( i = 0; i < size; i++ )
  {
    var_0 += ( X[ i ] - mo_X ) * ( Y[ i ] - mo_Y );
    var_1 += ( X[ i ] - mo_X ) * ( X[ i ] - mo_X );
  }

//  Value of the A coefficient:
  if( var_1 != 0.0 )
  {
    LR_koeff_A = var_0 / var_1;
  }
  else
  {
    LR_koeff_A = 0.0;
  }

//  Value of the B coefficient:
  LR_koeff_B = mo_Y - LR_koeff_A * mo_X;

//  Fill the array of points that lie on the regression line:
  ArrayResize( LR_points_array, size );
  for( i = 0; i < size; i++ )
  {
    LR_points_array[ i ] = LR_koeff_A * X[ i ] + LR_koeff_B;
  }
}

Nous utilisons ici la méthode des moindres carrés pour calculer l'erreur minimale de position de la droite de régression par rapport aux données initiales. Le tableau qui stocke les coordonnées Y, qui se trouvent sur la ligne calculée, est également rempli. Ce tableau n'est pas utilisé pour le moment et est destiné à être élaboré ultérieurement


La méthode principale utilisée dans la classe donnée est TBalanceSlope::CalcSlope. Il renvoie l'angle de pente de la courbe d'équilibre, qui est calculé par le montant indiqué des derniers trades. Voici sa réalisation :

//---------------------------------------------------------------------
//  Calculate slope angle:
//---------------------------------------------------------------------
double
TBalanceSlope::CalcSlope( )
{
//  Get result of trading from the history of trades:
  int      nmb = GetTradeResultsArray( slope_count_points );
  if( nmb < slope_count_points )
  {
    return( 0.0 );
  }

//  Calculate the regression line by the results of last trades:
  CalcLR( last_datetime_array, last_result_array );
  current_slope = LR_koeff_A;

  return( current_slope );
}

Tout d'abord, la quantité indiquée de derniers points de la courbe d'équilibre est analysée. Cela se fait en appelant la méthode de la classe de base TBalanceSlope::GetTradeResultsArray. Si le nombre de points de lecture n'est pas inférieur à celui indiqué, la ligne de régression est calculée. Cela se fait à l'aide de la méthode TBalanceSlope::CalcLR. Rempli à l'étape précédente, les tableaux last_result_array et last_datetime_array, qui appartiennent à la classe de base, sont utilisés comme arguments.

Les méthodes restantes sont simples et ne nécessitent pas de description détaillée.


Class TBalanceSlopeControl

C'est la classe de base, qui gère la pente de la courbe d'équilibre en modifiant le volume de travail. Il est généré à partir de la classe TBalanceSlope et hérite de toutes ses méthodes et données publiques et protégées. Le seul but de cette classe est de calculer le volume de travail actuel en fonction de l'angle de pente actuel de la courbe d'équilibre. Examinons cela en détail :

//---------------------------------------------------------------------
//  Managing slope of the balance curve:
//---------------------------------------------------------------------
enum LotsState
{
  LOTS_NORMAL = 1,            // mode of trading with normal volume
  LOTS_REJECTED = -1,         // mode of trading with lowered volume
  LOTS_INTERMEDIATE = 0,      // mode of trading with intermediate volume
};
//---------------------------------------------------------------------
class TBalanceSlopeControl : public TBalanceSlope
{
private:
  double    min_slope;          // slope angle that corresponds to the mode of volume rejection
  double    max_slope;          // slope angle that corresponds to the mode of normal volume
  double    centr_slope;        // slope angle that corresponds to the mode of volume switching without hysteresis

private:
  ControlType  control_type;    // type of the regulation function

private:
  double    rejected_lots;      // volume in the rejection mode
  double    normal_lots;        // volume in the normal mode
  double    intermed_lots;      // volume in the intermediate mode

private:
  LotsState current_lots_state; // current mode of volume

public:
  void      SetControlType( ControlType _control );  // set type of the regulation characteristic
  void      SetControlParams( double _min_slope, double _max_slope, double _centr_slope );

public:
  double    CalcTradeLots( double _min_lots, double _max_lots );  // get trade volume

protected:
  double    CalcIntermediateLots( double _min_lots, double _max_lots, double _slope );

public:
  void      TBalanceSlopeControl( );   // constructor
  void      ~TBalanceSlopeControl( );  // destructor
};


Avant de calculer le volume actuel, nous devons définir les paramètres initiaux. Cela se fait en appelant les méthodes suivantes :

  void      SetControlType( ControlType _control );  // set type of the regulation characteristic

_Input parameter_control - c'est le type de la caractéristique de régulation. EIle peut avoir la valeur suivante :

  • STEP_WITH_HYSTERESISH - échelonnée avec caractéristique de régulation d'hystérésis ;
  • STEP_WITHOUT_HYSTERESIS - échelonnée sans caractéristique de régulation d'hystérésis ;
  • LINEAR   - caractéristique de régulation linéaire ;
  • NON_LINEAR - caractéristique de régulation non linéaire (non implémentée dans cette version) ;


  void      SetControlParams( double _min_slope, double _max_slope, double _centr_slope );

Les paramètres d'entrée sont les suivants :

  • _min_slope - angle de pente de la courbe d'équilibre qui correspond au trading avec un volume minimal ;
  • _max_slope - angle de pente de la courbe d'équilibre qui correspond au trading avec un volume maximal ;
  • _centr_slope - angle de pente de la courbe d'équilibre qui correspond à la caractéristique de régulation échelonnée sans hystérésis ;


Le volume est calculé selon la méthode suivante :

//---------------------------------------------------------------------
//  Get trade volume:
//---------------------------------------------------------------------
double
TBalanceSlopeControl::CalcTradeLots( double _min_lots, double _max_lots )
{
//  Try to calculate slope of the balance curve:
  double    current_slope = CalcSlope( );

//  If the specified amount of trades is not accumulated yet, trade with minimal volume:
  if( GetRealTrades( ) < GetSlopePoints( ))
  {
    current_lots_state = LOTS_REJECTED;
    rejected_lots = trade_symbol.NormalizeLots( _min_lots );
    return( rejected_lots );
  }

//  If the regulation function is stepped without hysteresis:
  if( control_type == STEP_WITHOUT_HYSTERESIS )
  {
    if( current_slope < centr_slope )
    {
      current_lots_state = LOTS_REJECTED;
      rejected_lots = trade_symbol.NormalizeLots( _min_lots );
      return( rejected_lots );
    }
    else
    {
      current_lots_state = LOTS_NORMAL;
      normal_lots = trade_symbol.NormalizeLots( _max_lots );
      return( normal_lots );
    }
  }

//  If the slope of linear regression for the balance curve is less than the allowed one:
  if( current_slope < min_slope )
  {
    current_lots_state = LOTS_REJECTED;
    rejected_lots = trade_symbol.NormalizeLots( _min_lots );
    return( rejected_lots );
  }

//  If the slope of linear regression for the balance curve is greater than specified:
  if( current_slope > max_slope )
  {
    current_lots_state = LOTS_NORMAL;
    normal_lots = trade_symbol.NormalizeLots( _max_lots );
    return( normal_lots );
  }

//  The slope of linear regression for the balance curve is within specified borders (intermediate state):
  current_lots_state = LOTS_INTERMEDIATE;

//  Calculate the value of intermediate volume:
  intermed_lots = CalcIntermediateLots( _min_lots, _max_lots, current_slope );
  intermed_lots = trade_symbol.NormalizeLots( intermed_lots );

  return( intermed_lots );
}

Les principaux points importants de l’implémentation de la méthode TBalanceSlopeControl::CalcTradeLots sont les suivants :

  • Jusqu'à ce que le montant minimal indiqué de trades soit accumulé, tradez avec un volume minimal. C'est logique, car on ne sait pas dans quelle période (rentable ou non) se trouve actuellement l'Expert Advisor, juste après l'avoir défini pour le trading.
  • Si la fonction de régulation est celle échelonnée sans hystérésis, alors pour définir l'angle de commutation entre les modes de trading via la méthode TBalanceSlopeControl::SetControlParams, vous devez utiliser uniquement le paramètre_ _centr_slope. Les paramètres_ _min_slope et __max_slopesont ignorés. Il est fait pour effectuer l'optimisation correcte par ce paramètre dans le testeur de stratégie MetaTrader 5.

Selon l'angle de pente calculé, le trading est effectué avec un volume minimal, maximal ou intermédiaire. Le volume intermédiaire est calculé via la méthode simple - TBalanceSlopeControl::CalcIntermediateLots. Cette méthode est protégée et elle est utilisée dans la classe. Son code est indiqué ci-dessous :

//---------------------------------------------------------------------
//  Calculation of intermediate volume:
//---------------------------------------------------------------------
double
TBalanceSlopeControl::CalcIntermediateLots( double _min_lots, double _max_lots, double _slope )
{
  double    lots;

//  If the regulation function is stepped with hysteresis:
  if( control_type == STEP_WITH_HYSTERESISH )
  {
    if( current_lots_state == LOTS_REJECTED && _slope > min_slope && _slope < max_slope )
    {
      lots = _min_lots;
    }
    else if( current_lots_state == LOTS_NORMAL && _slope > min_slope && _slope < max_slope )
    {
      lots = _max_lots;
    }
  }
//  If the regulation function is linear:
  else if( control_type == LINEAR )
  {
    double  a = ( _max_lots - _min_lots ) / ( max_slope - min_slope );
    double  b = normal_lots - a * .max_slope;
    lots = a * _slope + b;
  }
//  If the regulation function is non-linear ( not implemented yet ):
  else if( control_type == NON_LINEAR )
  {
    lots = _min_lots;
  }
//  If the regulation function is unknown:
  else
  {
    lots = _min_lots;
  }

  return( lots );
}

Autres méthodes de cette classe ne nécessitent aucune description.


Exemple d'Intégration du Système dans un Expert Advisor

Examinons le processus d’implémentation du système de contrôle de la pente de la courbe d'équilibre dans un Expert Advisor étape par étape.


Étape 1 - ajout de l'instruction pour connecter la bibliothèque élaborée à l'Expert Advisor :

#include  <BalanceSlopeControl.mqh>


Étape 2 - ajout des variables externes pour le réglage des paramètres du système de contrôle de la pente de la ligne d'équilibre à l'Expert Advisor :

//---------------------------------------------------------------------
//  Parameters of the system of controlling the slope of the balance curve;
//---------------------------------------------------------------------
enum SetLogic 
{
  No = 0,
  Yes = 1,
};
//---------------------------------------------------------------------
input SetLogic     UseAutoBalanceControl = No;
//---------------------------------------------------------------------
input ControlType  BalanceControlType = STEP_WITHOUT_HYSTERESIS;
//---------------------------------------------------------------------
//  Amount of last trades for calculation of LR of the balance curve:
input int          TradesNumberToCalcLR = 3;
//---------------------------------------------------------------------
//  Slope of LR to decrease the volume to minimum:
input double       LRKoeffForRejectLots = -0.030;
//---------------------------------------------------------------------
//  Slope of LR to restore the normal mode of trading:
input double       LRKoeffForRestoreLots = 0.050;
//---------------------------------------------------------------------
//  Slope of LR to work in the intermediate mode:
input double       LRKoeffForIntermedLots = -0.020;
//---------------------------------------------------------------------
//  Decrease the initial volume to the specified value when the LR is inclined down
input double       RejectedLots = 0.10;
//---------------------------------------------------------------------
//  Normal work volume in the mode of MM with fixed volume:
input double       NormalLots = 1.0;


Étape 3 - ajout de l'objet de type TBalanceSlopeControl à l'Expert Advisor :

TBalanceSlopeControl  BalanceControl;

Cette déclaration peut être ajoutée au début de l'Expert Advisor, avant les définitions des fonctions.


Etape 4 - ajout du code d'initialisation du système de pilotage de la courbe d'équilibre à la fonction OnInit de l'Expert Advisor :

//  Adjust our system of controlling the slope of the balance curve:
  BalanceControl.SetTradeSymbol( Symbol( ));
  BalanceControl.SetControlType( BalanceControlType );
  BalanceControl.SetControlParams( LRKoeffForRejectLots, LRKoeffForRestoreLots, LRKoeffForIntermedLots );
  BalanceControl.SetSlopePoints( TradesNumberToCalcLR );
  BalanceControl.SetFiltrParams( 0, -1, 0 );
  BalanceControl.SetMonitoringBeginDate( 0 );


Étape 5 - ajout de l'appel de méthode pour actualiser les informations courantes de marché à la fonction OnTick de l'Expert Advisor :

//  Refresh market information:
  BalanceControl.RefreshSymbolInfo( );

L'appel de cette méthode peut être ajouté au tout début de la fonction OnTick ou après la vérification de la nouvelle prochaine barre (pour les Expert Advisors avec une telle vérification).


Étape 6 - ajout du code pour le calcul du volume actuel avant le code où les positions sont ouvertes :

  if( UseAutoBalanceControl == Yes )
  {
    current_lots = BalanceControl.CalcTradeLots( RejectedLots, NormalLots );
  }
  else
  {
    current_lots = NormalLots;
  }

Si un système de gestion de l'argent est utilisé dans l'Expert Advisor, alors à la place des NormalLots, vous devez écrire la méthode TBalanceSlopeControl::CalcTradeLots - le volume actuel calculé par le système MM de l'Expert Advisor.

Test Expert Advisor BSCS-TestExpert.mq5 avec le système intégré décrit ci-dessus est joint à cet article. Le principe de son fonctionnement est basé sur l'intersection des niveaux de l'indicateur CCI Cet Expert Advisor est élaboré pour les tests et n'est pas adapté pour travailler sur des comptes réels. Nous allons le tester à l'horizon H4 (2008.07.01 - 2010.09.01) de l'EURUSD.

Analysons le résultat du travail de cette EA. Le graphique de changement d'équilibre avec le système de contrôle de la pente désactivé est présenté ci-dessous. Pour le voir, définissez la valeur No pour le paramètre externe UseAutoBalanceControl.

Graphique initial du changement d’équilibre

Figure 4. Graphique initial du changement d'équilibre


Définissez maintenant le paramètre externe UseAutoBalanceControl sur Oui et testez l'Expert Advisor. Vous obtiendrez le graphique avec le système activé de contrôle de la pente d'équilibre.

Graphique de changement  de l'équilibre avec le système de contrôle activé

Figure 5. Graphique de changement d'équilibre avec le système de contrôle activé

Vous pouvez constater que la plupart des périodes du graphique supérieur (fig.4) semblent coupées et qu'elles ont une forme plate dans le graphique inférieur (fig.5). C'est le résultat du fonctionnement de notre système. Vous pouvez comparer les principaux paramètres de fonctionnement de l'Expert Advisor :

 Paramètre
 UseAutoBalanceControl = No  UseAutoBalanceControl = Oui
 Total net de bénéfice  18 378.00 17 261.73
 Facteur de bénéfice  1.47 1.81
 Facteur de récupération  2.66  3.74
 Gain prévu:  117.81 110.65
 Prélèvement absolu du solde: 1 310.50 131.05
 Prélèvement absolu des capitaux propres :  1 390.50 514.85
 Prélèvement maximal du solde :  5 569.50 (5.04%) 3 762.15 (3.35%)
 Prélèvement maximal des capitaux propres : 6 899.50 (6.19%)
4 609.60 (4.08%)


Les meilleurs paramètres parmi ceux comparés sont mis en évidence avec la couleur verte. Les bénéfices et les gains prévus ont légèrement diminué ; c'est l'envers de la régulation, qui apparaît à la suite de décalages de commutation entre les états du volume de travail. En somme, il y a une amélioration des taux de travail de l'Expert Advisor. En particulier, amélioration du prélèvement et du facteur de bénéfice


Conclusion

Je vois plusieurs façons d'améliorer ce système :
  • Utilisation du trading virtuel lorsque l'Expert Advisor entre dans une période de travail défavorable. Ensuite, le volume de travail normal n'aura plus d'importance. Cela permettra de diminuer le prélèvement.
  • Utiliser des algorithmes plus complexes pour déterminer l'état actuel de fonctionnement de l'Expert Advisor (rentable ou non). Par exemple, nous pouvons essayer d'appliquer un réseau neuronal pour une telle analyse. Une enquête supplémentaire est nécessaire dans ce cas, bien sûr.

Ainsi, nous avons pris en compte le principe et le résultat de fonctionnement du système, qui permet d'améliorer les caractéristiques de qualité d'un Expert Advisor. Le fonctionnement conjoint avec le système de gestion de l'argent, dans certains cas, permet d'accroitre la rentabilité sans augmenter le risque.

Je tiens à vous rappeler encore une fois : aucun système auxiliaire ne peut rendre un Expert Advisor rentable à partir d’un perdant.


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

Fichiers joints |
Comment créer rapidement un Expert Advisor  pour le championnat de trading automatisé 2010 Comment créer rapidement un Expert Advisor pour le championnat de trading automatisé 2010
Afin d’élaborer un expert pour participer au Championnat de Trading Automatisé 2010, utilisons un modèle de conseiller expert prêt. Même le programmeur novice MQL5 sera en mesure d’assurer cette tâche, car pour vos stratégies les classes de base, les fonctions, les modèles sont déjà élaborés. Il suffit d'écrire un minimum de code pour implémenter votre idée de trading.
L'utilisation des bibliothèques MQL5 Standard de Cours de Trade  dans la rédaction d'un Expert Advisor L'utilisation des bibliothèques MQL5 Standard de Cours de Trade dans la rédaction d'un Expert Advisor
Cet article explique comment utiliser les principales fonctionnalités de la bibliothèque standard MQL5 de classes de trade dans la rédaction des conseillers experts qui implémente la fermeture de la position et la modification , la passation et la suppression de commande en attente et la vérification de la marge avant de passer un trade.. Nous avons également démontré comment les classes de trade peuvent être utilisés pour obtenir les détails des commandes et des deals.
Recherche d'erreurs et journalisation Recherche d'erreurs et journalisation
MetaEditor 5 dispose de la fonctionnalité de débogage. Mais lorsque vous écrivez vos programmes MQL5, vous souhaitez souvent afficher non pas les valeurs individuelles, mais tous les messages qui apparaissent lors des tests et du travail en ligne. Lorsque le contenu du fichier journal est de grande taille, il est évident d'automatiser la récupération rapide et facile du message requis. Dans cet article, nous examinerons les moyens de trouver des erreurs dans les programmes MQL5 et les méthodes de collecte de données. Nous simplifierons également la connexion aux fichiers et apprendrons à connaître un programme simple LogMon pour une visualisation confortable des fichiers journaux
Utilisation de la fonction TesterWithdrawal() pour modéliser les retraits de bénéfice. Utilisation de la fonction TesterWithdrawal() pour modéliser les retraits de bénéfice.
Cet article décrit l’utilisation de la fonction TesterWithDrawal() pour estimer les risques dans les systèmes de trade qui impliquent le retrait d’une certaine partie des actifs pendant leur fonctionnement. En outre, il décrit l’effet de cette fonction sur l’algorithme de calcul du prélèvement d’actions dans le testeur de stratégie. Cette fonction est utile lors de l’optimisation des paramètres de vos Expert Advisors.