Expert Advisors: MQL5 Programming for Traders – Quellcodes aus dem Buch. Teil 6 - Seite 2

 
Stanislav Korotky #:
Aufträge, Geschäfte und Positionen sind ohnehin nicht an Zeitrahmen gebunden. Entweder haben Sie etwas missverstanden oder Ihre Formulierung ist falsch.
Es tut mir leid, dass meine Wortwahl verwirrend ist: Mit"Zeitrahmen" meine ich "Datumsbereich". Angenommen, ich möchte Geschäfte/Aufträge auswählen, die innerhalb eines bestimmten Datumsbereichs getätigt wurden, z. B. Geschäfte vom 2025-10-01 00:00:00 bis 2025-10-22 23:59:59.
 
pauldic #:
Es tut mir leid, dass meine Wortwahl verwirrend ist, denn mit"Zeitrahmen" meine ich "Datumsbereich". Sagen wir, ich möchte Abschlüsse/Bestellungen auswählen, die innerhalb eines bestimmten Datumsbereichs getätigt wurden, z. B. Abschlüsse vom 2025-10-01 00:00:00 bis 2025-10-22 23:59:59.

Wenn Sie einen Teilbereich eines Handelsverlaufs analysieren wollen, ist es effizienter, nur diesen Teil des Verlaufs vor der Filterung abzufragen, ohne den Filterungscode selbst zu beeinflussen:

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

...

{
   HistorySelect(SubrangeFrom, SubrangeTo);
   // ... Filtercode geht hier unverändert weiter
}

Wenn Sie aus irgendeinem Grund einen (engeren) Teilbereich innerhalb des globalen Bereichs, den Sie mit HistorySelect angewendet haben, auswählen möchten, dann können Sie dies im Filterungscode immer noch wie folgt tun:

{
      // einige von ihnen gehen hier

      // 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);
      ...
}

Die gelb hervorgehobene Zeile setzt 2 Bedingungen für den Datumsbereich [SubrangeFrom, SubrangeTo] unter Verwendung der zusätzlichen Qualifikatoren IS::GREATER und IS::LESS (standardmäßig werden sie in anderen Aufrufen von let() nicht angegeben, und IS::EQUAL wird normalerweise für Einzelwertfelder verwendet).

Ich kenne nur einen Grund für die Anwendung des Subfilters nach Datumsbereich - es ist für die Einrichtungszeit von Aufträgen (ORDER_TIME_SETUP), weil HistorySelect auf eine andere datetime-Eigenschaft von Aufträgen angewendet wird - nämlich die Ausführungszeit von Aufträgen (ORDER_TIME_DONE). Es könnte auch interessant sein, einen Teilbereich von aktiven Aufträgen (nicht in der Historie) zu filtern, wenn es viele davon gibt.

Sie können sich das Beispielskript MQL5/Scripts/MQL5Book/p6/TradeHistoryPrint.mq5 als Ausgangspunkt ansehen.
 
Stanislav Korotky #:

Wenn Sie einen Teilbereich eines Handelsverlaufs analysieren wollen, ist es effizienter, nur diesen Teil des Verlaufs vor der Filterung abzufragen, ohne den Filterungscode selbst zu beeinflussen:

Wenn Sie aus irgendeinem Grund einen (engeren) Teilbereich innerhalb des globalen Bereichs, den Sie mit HistorySelect angewendet haben, auswählen möchten, können Sie dies im Filterungscode immer noch wie folgt tun:

Die gelb hervorgehobene Zeile setzt 2 Bedingungen für den Datumsbereich [SubrangeFrom, SubrangeTo] unter Verwendung der zusätzlichen Qualifikatoren IS::GREATER und IS::LESS (standardmäßig werden sie in anderen Aufrufen von let() nicht angegeben, und IS::EQUAL wird normalerweise für Einzelwertfelder verwendet).

Ich kenne nur einen Grund für die Anwendung des Subfilters nach Datumsbereich - es ist für die Einrichtungszeit von Aufträgen (ORDER_TIME_SETUP), weil HistorySelect auf eine andere datetime-Eigenschaft von Aufträgen angewendet wird - nämlich die Ausführungszeit von Aufträgen (ORDER_TIME_DONE). Es könnte auch interessant sein, einen Teilbereich von aktiven Aufträgen (nicht in der Historie) zu filtern, wenn es viele davon gibt.

Sie können sich das Beispielskript MQL5/Scripts/MQL5Book/p6/TradeHistoryPrint.mq5 als Ausgangspunkt ansehen.
@StanislavKorotky Nochmals vielen Dank... Es ist ein großartiger Ausgangspunkt für mich und ich werde anfangen, mit ihm zu arbeiten.
 

Fehlerbehebung 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)));
   }
Dateien:
TradeUtils.mqh  12 kb
 
pauldic #:

Verwenden Sie dieCODE-Taste (Alt-S), wenn Sie Code einfügen.

Ein Moderator hat den falsch eingefügten Code formatiert. Normalerweise wird solcher Code entfernt.

@StanislavKorotky Bitte können Sie helfen, in diesem Fehler zu suchen, ich glaube, es begann nach MT5 Updates, weil ich wusste, dass der Code funktioniert in den vergangenen Monaten ohne Änderungen.

Parameter Konvertierung Typ 'long[][2]' zu 'string[][] &' ist nicht erlaubt SymbolFilter.mqh 199 20

Parameter conversion type 'double[][2]' to 'string[][] &' is not allowed TradeFilter.mqh 332 20
Parameter Konvertierung Typ 'long[][2]' in 'string[][] &' ist nicht erlaubt TradeFilter.mqh 163 17


Ich vermute, dass der folgende Code helfen wird, das Problem zu lösen:


Hallo @Paul Dick

Versuchen Sie diese https://www.mql5.com/de/code/57233 für die Sortierung von Arrays

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.
 

Ich füge eine aktualisierte Version der Berechnungsdatei des benutzerdefiniertenOptimierungskriteriums auf der Grundlage von R2 - RSquared.mqh bei, in der die Berechnung für den Fall variabler Lose korrigiert wurde.

Die Qualität der Schätzung wurde deutlich verbessert - nach der Tabelle der Optimierungsergebnisse zu urteilen, wurde die Kombination aus Erholungsfaktor und Sharpe-Parametern erhalten.

Beispiel für die Anwendung.

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[]; // wird hier nur verwendet, um den 'select'-Prototyp abzugleichen, aber nützlich für die Fehlersuche
   
   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[]; // Berücksichtigung des Handelsvolumens bei der Anwendung des R2-Kriteriums
   
   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];
      }
      // Volumen als Modell verwenden - mehr Investitionen - mehr erwartete Erträge
      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;
}
Dateien:
RSquared.mqh  4 kb