Bibliotheken: MT4Orders QuickReport - Seite 5

 
Forester #:

Server: MetaQuotes-Demo Hedge
Deal mit Ticket 99 auf Seite zwei.

Ein wenig lokalisiert.

#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)));
    }
}


Es spielt keine Rolle, was der EA macht. Die Hauptsache ist der hervorgehobene Code, der einfach MT5-Aufträge aus der Handelshistorie anzeigt: den Ort des Auftrags, sein Ticket und die Zeit, zu der er in die Historie eingegangen ist.

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

In der Verlaufstabelle sind die MT5-Aufträge nicht nach Ticket oder Zeit sortiert. Ich sehe keinen Sinn darin, dieses Verhalten von MQ-Tester an die Entwickler zu melden. Schließlich sind "die Aufgaben zu groß".

Daher würde ich MQ-Tester nicht standardisieren.

 
fxsaber #:

Ein wenig lokalisiert.


Es spielt keine Rolle, was der EA macht. Die Hauptsache ist ein dedizierter Code, der einfach MT5-Aufträge aus der Handelshistorie ausgibt: den Ort des Auftrags, sein Ticket und die Zeit, zu der er in die Historie gelangt ist.

In der Historientabelle sind die MT5-Aufträge nicht nach Ticket oder Zeit sortiert. Ich sehe keinen Sinn darin, dieses Verhalten von MQ-Tester an die Entwickler zu melden. Schließlich sind "die Aufgaben zu groß".

Daher würde ich MQ-Tester nicht standardisieren.

Ich denke, dass Limit-Orders eine eigene Warteschlange haben, um in die Historie übertragen zu werden, wenn sie geschlossen werden. Nicht bei jedem Tick.
Wenn sie keine offensichtlichen Fehler bei den ersten Test-Trades und Swaps beheben müssen (was ich vor ein paar Wochen abgelehnt habe), dann ist es nur ein Feature. Die Verwirrungsmatrix ist wichtiger....
 
Manchmal ist es gut, das zu wissen.
// Maximale Dauer der Inanspruchnahme ab dem festgelegten Zeitpunkt.
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);

Es ist besser, nicht so gepackt und leichtfertig zu schreiben (nicht nur hier, sondern auch in anderen Quellen). Die Reihenfolge der Berechnungen von Operanden mit gleicher Priorität ist nicht starr festgelegt - der Compiler kann sie aufgrund seiner eigenen Überlegungen optimieren, dann kann es zu unterschiedlichen Nebeneffekten kommen. Wenn es jetzt funktioniert, heißt das nicht, dass es später nicht mehr funktionieren wird, denn die interne Implementierung des Compilers ändert sich ständig.

 
Stanislav Korotky #:

Es ist besser, nicht so gepackt und leichtfertig zu schreiben (nicht nur hier, sondern auch in anderen Quellen). Die Reihenfolge der Berechnungen von Operanden mit gleicher Priorität ist nicht starr festgelegt - der Compiler kann sie aufgrund seiner eigenen Überlegungen optimieren, dann kann es zu unterschiedlichen Nebeneffekten kommen. Wenn es jetzt funktioniert, heißt das nicht, dass es später nicht mehr funktionieren wird, denn die interne Implementierung des Compilers ändert sich ständig.

Danke für den guten Ratschlag! Leider fällt es mir schwer, mich zu zwingen, den "prägnanten" Stil zugunsten des korrekten Stils aufzugeben. Es wird eine Menge "falscher" Code geschrieben und verwendet.

 
fxsaber #:
// Maximale Absenkungsdauer ab einem bestimmten Zeitpunkt.
Ab dem voraussichtlichen Startdatum?
Stanislav Korotky #:

Es ist besser, nicht so verpackt und leichtfertig zu schreiben (nicht nur hier, sondern auch in anderen Quellen). Die Reihenfolge der Berechnungen von Operanden mit der gleichen Priorität ist nicht starr festgelegt - der Compiler kann sie nach seinen eigenen Überlegungen optimieren, dann kann es zu unterschiedlichen Nebeneffekten kommen. Wenn es jetzt funktioniert, heißt das nicht, dass es später nicht mehr funktionieren wird, denn die interne Implementierung des Compilers ändert sich ständig.

Was ist daran falsch?

Ich habe gerade

/ (25 * 3600)
Ich mag das nicht. Ein Tag hat 24 Stunden, nicht 25.
 

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

Jeder.

Was ist da falsch?

Es gibt keine eindeutige Reihenfolge, in der die Zeichenfolge für Print gebildet wird. Wenn man von rechts nach links vorgeht, ist das Ergebnis ein anderes als das beabsichtigte.

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


Ich wünschte, es gäbe in einem solchen Fall Eindeutigkeit.

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

Danke für die guten Ratschläge! Leider fällt es mir schwer, mich zu zwingen, den "prägnanten" Stil zugunsten des korrekten Stils aufzugeben. Es wird eine Menge "falscher" Code geschrieben und verwendet.

Ich fasse Funktionen und anderen Code fast immer in einer Zeile zusammen, wenn der Code funktioniert/getestet ist und ich nicht vorhabe, zu ihm zurückzukehren. Einfach um Platz zu sparen.
Außerdem ist es bequemer, den Code zu lesen, ohne hin- und herzuscrollen, wenn man alles auf einem Bildschirm sehen kann. Besonders in Editoren, die das markierte Wort hervorheben (Metaeditor gehört leider nicht dazu).
 
Forester #:
Ich fasse Funktionen und anderen Code fast immer in einer Zeile zusammen, wenn der Code funktioniert/getestet ist und ich nicht vorhabe, zu ihm zurückzukehren. Einfach um Platz zu sparen.
Außerdem ist es bequemer, den Code zu lesen, ohne hin- und herzuscrollen, wenn man alles auf einem Bildschirm sehen kann. Besonders in Editoren, die das markierte Wort hervorheben (Metaeditor gehört leider nicht dazu).

Leider kann diese Praxis zu sehr schwer erkennbaren Fehlern führen, wenn man den Compiler wechselt.

Es gibt jedoch Situationen, in denen man einfach die im Compiler eingestellte Reihenfolge verwenden muss. Und da weiß ich nicht, wie man das umgehen kann, damit es keine UB gibt.

 
fxsaber #:

Von jedem.

Die Informationen über den maximalen Long Drawdown sind interessant. Ich habe sie für die gesamte Reihe von Strings gemacht. Ich habe den Code auf der Website noch nicht aktualisiert.
Aber es ist nicht ganz klar, wofür das Datum ist. Wenn wir eine Unterteilung in Rückwärts-/Vorwärts-Tests vornehmen (wie ich vorgeschlagen habe), dann müssen wir die Statistiken dazu separat in 2 Tabellen berechnen (die maximalen Drawdown-Perioden werden auch dort stehen).
Und nur für ein Datum ist es irgendwie zu spezifisch und unverständlich.