Bibliothèque: MT4Orders QuickReport - page 5

 
Forester #:

Serveur : MetaQuotes-Demo Hedge
Traiter le ticket 99 à la page deux.

Un peu localisé.

#include <MT4Orders.mqh>

void OnTick ()
{
  static int Count = 0;
  
  if (Count > 6)
    return;
  
  MqlTick Tick;
  SymbolInfoTick(_Symbol, Tick);
  
  const double Offset = 5 * _Point;
  bool Buy =  false;
  bool Sell =  false;

  for (uint i = OrdersTotal(); (bool)i--;)
    if (OrderSelect(i, SELECT_BY_POS))         
    {
      if(OrderMagicNumber())
        switch (OrderType())
        {
        case OP_BUY:
          OrderModify(OrderTicket(), OrderOpenPrice(), 0, Tick.bid + Offset, 0);
          Buy = true;
         
         break;
        case OP_SELL:
          OrderModify(OrderTicket(), OrderOpenPrice(), 0, Tick.ask - Offset, 0);
          Sell = true;
         
         break;
        case OP_BUYLIMIT:
          OrderModify(OrderTicket(), Tick.ask - Offset, 0, 0, 0);
          Buy = true;
         
         break;
        case OP_SELLLIMIT:          
          OrderModify(OrderTicket(), Tick.bid + Offset, 0, 0, 0);
          Sell = true;
         
         break;
        }
      else
        OrderDelete(OrderTicket());
    }

  if (!Buy)
    OrderSend(_Symbol, OP_BUYLIMIT, 1, Tick.ask - Offset, 0, 0, 0, NULL, ++Count);

  if (!Sell)
    OrderSend(_Symbol, OP_SELLLIMIT, 1, Tick.bid + Offset, 0, 0, 0, NULL, ++Count);
  
  OrderSend(_Symbol, OP_BUYLIMIT, 1,  Tick.ask - Offset, 0, Tick.ask - Offset, Tick.ask - Offset);
  Count++;
}

string TimeToString( const long Time )
{
  return((string)(datetime)(Time / 1000) + "." + IntegerToString(Time % 1000, 3, '0'));
}

void OnDeinit( const int )
{
  if (HistorySelect(0, INT_MAX))
    for (uint i = HistoryOrdersTotal(); (bool)i--;)
    {
      const ulong Ticket = HistoryOrderGetTicket(i);
      
      Print((string)i + ": " + (string)Ticket + " " + TimeToString(HistoryOrderGetInteger(Ticket, ORDER_TIME_DONE_MSC)));
    }
}


Ce que fait l'EA n'a pas d'importance. L'essentiel est le code mis en évidence, qui affiche simplement les ordres MT5 de l'historique des transactions : la place de l'ordre, son ticket et l'heure à laquelle il est entré dans l'historique.

11: 13 2023.05.29 23:54:39.425
10: 12 2023.05.29 00:04:25.870
 9: 11 2023.05.29 00:03:59.331
 8: 10 2023.05.29 00:03:59.430
 7: 9 2023.05.29 00:03:59.281
 6: 8 2023.05.29 00:03:59.281
 5: 7 2023.05.29 00:03:59.227
 4: 3 2023.05.29 00:03:59.331
 3: 6 2023.05.29 00:03:18.390
 2: 5 2023.05.29 00:03:18.390
 1: 4 2023.05.29 00:02:41.107
 0: 2 2023.05.29 00:02:41.107

Dans le tableau de l'historique, les ordres MT5 ne sont pas triés par ticket ou par heure. Je ne vois pas l'intérêt de signaler ce comportement de MQ-Tester aux développeurs. Après tout, "les tâches sont excessives".

Par conséquent, je ne normaliserais pas MQ-Tester.

 
fxsaber #:

Un peu localisé.


Ce que fait l'EA n'a pas d'importance. L'essentiel est un code dédié qui produit simplement les ordres MT5 à partir de l'historique des transactions : le lieu de l'ordre, son ticket et l'heure à laquelle il est apparu dans l'historique.

Dans le tableau de l'historique, les ordres MT5 ne sont pas triés par ticket ou par heure. Je ne vois pas l'intérêt de signaler ce comportement de MQ-Tester aux développeurs. Après tout, "les tâches sont excessives".

Par conséquent, je ne normaliserais pas MQ-Tester.

Je pense que les ordres à cours limité ont leur propre file d'attente de transfert vers l'historique lorsqu'ils sont fermés. Pas à chaque tic-tac.
S'ils n'ont pas besoin de corriger des bogues évidents avec les premiers tests de transactions et d'échanges (que j'ai écartés il y a quelques semaines), alors il s'agit simplement d'une fonctionnalité. La matrice de confusion est plus importante....
 
Il est parfois bon de le savoir.
// Durée maximale de l'abaissement à partir de l'heure fixée.
int MaxLengthDD( datetime &BeginDD, datetime &EndDD, const datetime From = 0 )
{
  const int Total = OrdersHistoryTotal();
  
  double Profit = 0;
  double MaxProfit = 0;
  datetime Begin = 0;
  
  BeginDD = 0;
  EndDD = 0;
  
  for (int i = 0; i < Total; i++)
    if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) && (OrderType() <= OP_SELL))
    {
      if (!Begin && (OrderOpenTime() > From))
        Begin = OrderOpenTime();
        
      Profit += OrderProfit() + OrderSwap() + OrderCommission();
      
      if ((Profit > MaxProfit) || (i == Total - 1))
      {
        MaxProfit = Profit;
        
        const datetime End = OrderCloseTime();        
        
        if (Begin && (End - Begin > EndDD - BeginDD))
        {
          BeginDD = Begin;
          EndDD = End;
        }
        
        if (Begin)
          Begin = End;
      }
    }
    
  return((int)(EndDD - BeginDD));
}

void PrintMaxLengthDD( const datetime &From[] )
{
  const int Size = ArraySize(From);
  
  datetime BeginDD, EndDD;
  
  for (int i = 0; i < Size; i++)
    Print("From " + TimeToString(From[i], TIME_DATE) + " MaxLengthDD = " + (string)(MaxLengthDD(BeginDD, EndDD, From[i]) / (25 * 3600)) + " days: " +
          (string)BeginDD + " - " + (string)EndDD);  
}
 

fxsaber #:
Иногда полезно знать.

Print("From " + TimeToString(From[i], TIME_DATE) + " MaxLengthDD = " + (string)(MaxLengthDD(BeginDD, EndDD, From[i]) / (25 * 3600)) + " days: " +
          (string)BeginDD + " - " + (string)EndDD);

Il est préférable de ne pas écrire de manière aussi compacte et frivole (non seulement ici, mais aussi dans d'autres sources). L'ordre de calcul des opérandes ayant la même priorité n'est pas fixé de manière rigide - le compilateur peut l'optimiser sur la base de ses propres considérations, ce qui peut avoir des effets secondaires différents. Si cela fonctionne aujourd'hui, cela ne signifie pas que cela ne cessera pas de fonctionner plus tard, car l'implémentation interne du compilateur change tout le temps.

 
Stanislav Korotky #:

Il est préférable de ne pas écrire de manière aussi compacte et frivole (non seulement ici, mais aussi dans d'autres sources). L'ordre de calcul des opérandes ayant la même priorité n'est pas fixé de manière rigide - le compilateur peut l'optimiser sur la base de ses propres considérations, ce qui peut avoir des effets secondaires différents. Si cela fonctionne aujourd'hui, cela ne signifie pas que cela ne cessera pas de fonctionner plus tard, car l'implémentation interne du compilateur change tout le temps.

Merci pour ces conseils judicieux ! Malheureusement, il est difficile de se forcer à abandonner le style "concis" en faveur du style correct. Il y a beaucoup de "mauvais" code écrit et utilisé.

 
fxsaber #:
// Durée maximale de l'amortissement à partir d'un moment donné.
À partir de la date de début du contrat ?
Stanislav Korotky #:

Il est préférable de ne pas écrire de manière aussi compacte et frivole (non seulement ici, mais aussi dans d'autres sources). L'ordre de calcul des opérandes ayant la même priorité n'est pas fixé de manière rigide - le compilateur peut l'optimiser sur la base de ses propres considérations, ce qui peut avoir des effets secondaires différents. Si cela fonctionne aujourd'hui, cela ne signifie pas que cela ne cessera pas de fonctionner plus tard, car l'implémentation interne du compilateur change tout le temps.

Quel est le problème ?

Je viens de

/ (25 * 3600)
Je n'aime pas ça. Il y a 24 heures dans une journée, pas 25.
 

Forester #:
C даты начала форварда?

N'importe qui.

Qu'est-ce qui ne va pas ?

Il n'y a pas d'ordre univoque dans lequel la chaîne de caractères Print sera formée. Si l'on procède de droite à gauche, le résultat sera différent de celui escompté.

    Print("From " + TimeToString(From[i], TIME_DATE) + " MaxLengthDD = " + (string)(MaxLengthDD(BeginDD, EndDD, From[i]) / (25 * 3600)) + " days: " +
          (string)BeginDD + " - " + (string)EndDD);  


J'aimerais qu'il n'y ait pas d'ambiguïté dans ce cas.

int MaxLengthDD( const datetime &BeginDD, const datetime &EndDD, const datetime From = 0 )
 
fxsaber #:

Merci pour ces conseils avisés ! Malheureusement, il est difficile de se forcer à abandonner le style "concis" au profit du style correct. Il y a beaucoup de "mauvais" code écrit et utilisé.

Je regroupe presque toujours les fonctions et autres codes en une seule ligne si le code est travaillé/testé et que je n'ai pas l'intention d'y revenir. Cela permet d'économiser de l'espace.
De plus, il est plus pratique de lire le code sans défiler d'avant en arrière lorsqu'on peut tout voir sur un seul écran. Surtout dans les éditeurs qui surlignent le mot surligné (malheureusement Metaeditor n'est pas l'un d'entre eux).
 
Forester #:
Je regroupe presque toujours les fonctions et autres codes en une seule ligne si le code est travaillé/testé et que je n'ai pas l'intention d'y revenir. C'est un gain de place.
De plus, il est plus pratique de lire le code sans défiler d'avant en arrière lorsqu'on peut tout voir sur un seul écran. Surtout dans les éditeurs qui surlignent le mot surligné (malheureusement Metaeditor n'est pas l'un d'entre eux).

Malheureusement, cette pratique peut conduire à des erreurs très difficiles à voir lorsque vous changez de compilateur.

Cependant, dans certaines situations, il est nécessaire d'utiliser l'ordre établi dans le compilateur. Et là, je ne sais pas comment contourner le problème pour qu'il n'y ait pas d'UB.

 
fxsaber #:

De n'importe qui.

L'information sur le max long drawdown est intéressante. Je l'ai fait pour l'ensemble du tableau de chaînes de caractères. Je n'ai pas encore mis à jour le code sur le site.
Mais l'utilité de la date n'est pas tout à fait claire. Si nous faisons un point sur la division en tests back/forward (comme je l'ai suggéré), alors nous devons calculer les statistiques sur eux séparément dans 2 tableaux (les périodes max drawdown seront là aussi).
Et juste pour une date, c'est d'une certaine manière trop spécifique et incompréhensible.