Experts: Programmation MQL5 pour les Traders - Codes Source du livre. Partie 6 - page 2

 
Stanislav Korotky #:
Les ordres, les transactions et les positions ne sont en aucun cas liés aux délais. Soit vous avez mal compris quelque chose, soit votre formulation est incorrecte.
Je suis désolé, je pense que mon choix de mots prête à confusion : par"période", j'entends "plage de dates". Supposons que je veuille sélectionner les transactions/commandes effectuées dans une plage de dates donnée, par exemple entre le 2025-10-01 00:00:00 et le 2025-10-22 23:59:59.
 
pauldic #:
Je suis désolé, je pense que mon choix de mots prête à confusion : par"période", j'entends "plage de dates". Disons que je souhaite sélectionner les transactions/commandes effectuées dans une plage de dates donnée, par exemple entre le 2025-10-01 00:00:00 et le 2025-10-22 23:59:59.

Si vous souhaitez analyser une partie de l'historique des transactions, il est alors plus efficace de ne demander que cette partie de l'historique avant le filtrage, sans affecter le code de filtrage lui-même :

input datetime SubrangeFrom = 0;
input datetime SubrangeTo = 0;

...

{
   HistorySelect(SubrangeFrom, SubrangeTo);
   // ... le code du filtre est placé ici tel quel
}

Si, pour une raison quelconque, vous souhaitez sélectionner une sous-plage (plus étroite) dans la plage globale que vous avez appliquée avec HistorySelect, vous pouvez toujours le faire dans le code de filtrage comme suit :

{
      // certains d'entre eux se trouvent ici

      // HistorySelect(0, LONG_MAX) ;
      // HistorySelectByPosition(PositionID) ;
      ...
      DealTuple deals[];
      if(SubrangeFrom != SubrangeTo && SubrangeFrom < SubrangeTo)
      {
         filter.let(DEAL_TIME, SubrangeFrom - 1, IS::GREATER).let(DEAL_TIME, SubrangeTo + 1, IS::LESS);
      }
      filter.let(DEAL_POSITION_ID, PositionID).select(deals, true);
      ...
}

La ligne surlignée en jaune définit 2 conditions pour l'intervalle de dates [SubrangeFrom, SubrangeTo] en utilisant les qualificateurs supplémentaires IS::GREATER et IS::LESS (par défaut, ils ne sont pas spécifiés dans d'autres appels à let(), et IS::EQUAL est normalement utilisé pour les champs à valeur unique).

Je ne connais qu'une seule raison d'appliquer le sous-filtre par plage de dates - c'est pour le temps de préparation des ordres (ORDER_TIME_SETUP), parce que HistorySelect est appliqué à une autre propriété temporelle des ordres - à savoir le temps d'exécution de l'ordre (ORDER_TIME_DONE). Il peut également être intéressant de filtrer un sous-ensemble d'ordres actifs (ne figurant pas dans l'historique), s'ils sont nombreux.

Vous pouvez consulter le script d'exemple MQL5/Scripts/MQL5Book/p6/TradeHistoryPrint.mq5, comme point de départ.
 
Stanislav Korotky #:

Si vous souhaitez analyser un sous-groupe de l'historique des transactions, il est alors plus efficace de ne demander que cette partie de l'historique avant le filtrage, sans affecter le code de filtrage lui-même :

Si, pour une raison quelconque, vous souhaitez sélectionner une sous-plage (plus étroite) dans la plage globale que vous avez appliquée avec HistorySelect, vous pouvez toujours le faire dans le code de filtrage comme suit :

La ligne surlignée en jaune définit 2 conditions pour l'intervalle de dates [SubrangeFrom, SubrangeTo] en utilisant les qualificateurs supplémentaires IS::GREATER et IS::LESS (par défaut, ils ne sont pas spécifiés dans d'autres appels à let(), et IS::EQUAL est normalement utilisé pour les champs à valeur unique).

Je ne connais qu'une seule raison d'appliquer le sous-filtre par plage de dates - c'est pour le temps de préparation des ordres (ORDER_TIME_SETUP), parce que HistorySelect est appliqué à une autre propriété temporelle des ordres - à savoir le temps d'exécution de l'ordre (ORDER_TIME_DONE). Il peut également être intéressant de filtrer un sous-ensemble d'ordres actifs (ne figurant pas dans l'historique), s'ils sont nombreux.

Vous pouvez consulter le script d'exemple MQL5/Scripts/MQL5Book/p6/TradeHistoryPrint.mq5, comme point de départ.
@StanislavKorotky Merci encore une fois... C'est un excellent point de départ pour moi et je vais commencer à travailler avec.
 

Correction du bug MQL5/Include/MQL5Book/TradeUtils.mqh.

   bool Equal(const double v1, const double v2)
   {
      return v1 == v2 || fabs(v1 - v2) < DBL_EPSILON * fmax(1.0, fmax(fabs(v1), fabs(v2)));
   }
Dossiers :
TradeUtils.mqh  12 kb
 
pauldic #:

Utilisez lebouton CODE (Alt-S) lorsque vous insérez du code.

Un modérateur a formaté le code incorrectement collé. En général, ce type de code est supprimé.

@StanislavKorotky S'il vous plaît, pouvez-vous nous aider à examiner cette erreur, je crois qu'elle a commencé après les mises à jour de MT5 parce que je savais que le code fonctionnait dans les mois précédents sans aucune modification.

parameter convertion type 'long[][2]' to 'string[][] &' is not allowed SymbolFilter.mqh 199 20

la conversion du paramètre 'double[][2]' en 'string[][] &' n'est pas autorisée TradeFilter.mqh 332 20
la conversion du paramètre 'long[][2]' en 'string[][] &' n'est pas autorisée TradeFilter.mqh 163 17


Je pense que le code ci-dessous aidera à reproduire le problème :


Bonjour @Paul Dick

Essayez ce https://www.mql5.com/fr/code/57233 pour trier les tableaux

Introsort (Introspective sort) using Function Pointers
Introsort (Introspective sort) using Function Pointers
  • 2025.03.18
  • www.mql5.com
A hybrid sorting algorithm that provide fast performance for sorting arrays of simple types, structures or object pointers.
 

Je joins une version mise à jour du fichier de calcul du critère d'optimisation personnalisé basé sur R2 - RSquared.mqh, dans lequel le calcul pour le cas des lots variables a été corrigé.

La qualité de l'estimation a été significativement améliorée - à en juger par le tableau des résultats de l'optimisation, la combinaison du facteur de récupération et des paramètres de Sharpe a été obtenue.

Exemple d'utilisation.

double OnTester()
{
   HistorySelect(0, LONG_MAX);
   
   #define  STAT_PROPS 5
   
   const ENUM_DEAL_PROPERTY_DOUBLE props[STAT_PROPS] =
   {
      DEAL_PROFIT, DEAL_SWAP, DEAL_COMMISSION, DEAL_FEE, DEAL_VOLUME
   };
   double expenses[][STAT_PROPS];
   ulong tickets[]; // utilisé ici uniquement pour correspondre au prototype "select", mais utile pour le débogage
   
   DealFilter filter;
   filter.let(DEAL_TYPE, (1 << DEAL_TYPE_BUY) | (1 << DEAL_TYPE_SELL), IS::OR_BITWISE)
      .let(DEAL_ENTRY, (1 << DEAL_ENTRY_OUT) | (1 << DEAL_ENTRY_INOUT) | (1 << DEAL_ENTRY_OUT_BY), IS::OR_BITWISE)
      .select(props, tickets, expenses);

   const int n = ArraySize(tickets);
   
   double balance[];
   double volumes[]; // prendre en compte les volumes d'échanges pour utiliser le critère R2
   
   ArrayResize(balance, n + 1);
   balance[0] = 0;
   ArrayResize(volumes, n + 1);
   volumes[0] = 0;
   
   for(int i = 0; i < n; ++i)
   {
      double result = 0;
      for(int j = 0; j < STAT_PROPS - 1; ++j)
      {
         result += expenses[i][j];
      }
      // utiliser les volumes comme modèle - plus d'investissements - plus de retours attendus
      volumes[i + 1] = expenses[i][STAT_PROPS - 1] + volumes[i];
      balance[i + 1] = result + balance[i];
   }
   
   const double r2 = RSquaredTest(balance, volumes);
   
   #undef  STAT_PROPS
   
   return r2 * 100;
}
Dossiers :
RSquared.mqh  4 kb