English Русский 中文 Español 日本語 Português
preview
Die Magie der Zeit von Handelsintervallen mit dem Instrument Frames Analyzer

Die Magie der Zeit von Handelsintervallen mit dem Instrument Frames Analyzer

MetaTrader 5Tester | 10 Januar 2023, 11:01
341 0
Anatoli Kazharski
Anatoli Kazharski

Inhalt


Einführung

In diesem Artikel möchte ich Ihnen ein recht interessantes Tool vorstellen, mit dem Sie die Optimierungsergebnisse eines beliebigen Handelsalgorithmus genauer unter die Lupe nehmen können. Es ist sogar möglich, die Ergebnisse Ihres echten automatisierten Handels mit einem Minimum an Aufwand und Kosten zu verbessern.

Was ist der Frames Analyzer? Dies ist eine Plug-in-Bibliothek für jeden Expert Advisor zur Analyse von Optimierungsrahmen während der Parameteroptimierung im Tester, aber auch außerhalb des Testers, durch das Lesen einer MQD-Datei oder einer Datenbank, die unmittelbar nach der Parameteroptimierung erstellt wird.

Dies ist eine exklusive Lösung, die in dieser Form noch nirgendwo gezeigt wurde, obwohl sie bereits vor mehr als drei Jahren eingeführt wurde. Zum ersten Mal wurde die Idee von einem aktiven Mitglied der MQL-Community fxsaber detailliert formuliert und in Code umgesetzt.

Einige Zwischenimplementierungen von Anwendungen der Optimierungsrahmenanalyse sind in einigen meiner Artikel behandelt worden:

Durch die Kombination all dieser Ideen wurde ein recht interessantes und informatives Instrument geschaffen. Sie wird in diesem Artikel ausführlich behandelt.


Beschreibung des Instruments

Das Modul enthält eine eingebettete grafische Oberfläche, die mit der Bibliothek EasyAndFastGUI v2.0 erstellt wurde und keine zusätzliche Codierung erfordert. Wir müssen eine Verbindung zu mehreren Hauptfunktionen der MQL-Anwendung herstellen (siehe unten).

Die grafische Oberfläche besteht aus mehreren Abschnitten. Schauen wir es uns mal an.


Die Registerkarte Frames

Elemente:

  • Mit der Schaltfläche Open DB können Sie eine Datenbank öffnen, die Optimierungsrahmen enthält. Diese Schaltfläche erscheint nur im Frames Analyzer. Außerhalb des Testers arbeitet der EA also im Lesemodus der DB-Datei, die vom EA nach der Parameteroptimierung erstellt wurde. 
  • Die Schaltfläche Open MQD-file öffnet eine MQD-Datei, die Optimierungsrahmen enthält. Diese Schaltfläche gibt es nur im Frames Analyzer. Außerhalb des Testers arbeitet der EA also im Lesemodus der MQD-Datei, die vom Tester nach der Parameteroptimierung erstellt wurde (dies soll in der für den kostenpflichtigen Vertrieb bestimmten Version beseitigt werden).
  • Das Eingabefeld Curves total dient der Angabe der Anzahl der gleichzeitig im Diagramm angezeigten Saldendiagramme.
  • Die Schaltfläche Replay frames startet die Wiedergabe der Frames.
  • Saldendiagramm (Optimierungsergebnis).
  • Graphische Darstellung aller Ergebnisse (Gewinn/Verlust).

Ist das Modul Frames Analyzer als Bibliothek mit dem EA verbunden, so wird während der Parameteroptimierung der Graph mit Frames Analyzer EA im Tester geöffnet und es ist möglich, alle Zwischenergebnisse (Salden) sofort zu beobachten. 

Visualisierung der Ergebnisse während der Parameteroptimierung

Visualisierung der Ergebnisse während der Parameteroptimierung


Die Registerkarte Results

Oben befinden sich zwei Tabellen:

  • Die Schaltfläche Add to favorites fügt die Ergebnisse zu den Favoriten.
  • Das Eingabefeld Removed intervals zur Angabe der Anzahl der ausgeschlossenen Intervalle mit unrentablen Serien wurde entfernt.
  • Die Combobox mit der Dropdown-Liste Criterion dient der Auswahl der Ergebnisse nach den angegebenen Kriterien:
    • Profit - 100 Ergebnisse werden aus der Gesamtzahl nach dem maximalen Saldo ausgewählt (dasselbe gilt für andere Kriterien).
    • Trades - 100 Ergebnisse werden nach der maximalen Anzahl der Positionen ausgewählt.
    • DD (Drawdown) - 100 Ergebnisse werden nach dem Mindestdrawdown ausgewählt.
    • RF (recovery factor) - 100 Ergebnisse werden nach dem maximalen Erhgolungsfaaktor ausgewählt.
    • Die gleichen Kriterien mit dem Präfix BI_ zeigen die gleichen Werte nach dem Ausschluss der unrentablen Handelsreihen.
  • Die Tabelle mit den 100 besten Ergebnissen der maximalen Balance. Die Zellen in den Spalten, die sich auf verbesserte Ergebnisse beziehen (mit dem Präfix BI_ ), haben eine andere Farbe, um sie schnell visuell zu unterscheiden (siehe Screenshot unten). Zellen der Spalten mit externen Parametern werden ebenfalls in einer eigenen Farbe hervorgehoben, um sie schnell zu erkennen.
  • Die Tabelle mit den Ergebnissen nach dem Löschen von Verlustperioden aus der Handelshistorie mit allen Zwischenergebnissen.

Wenn der Mauszeiger über einer bestimmten Tabelle schwebt, können Sie mit den Tasten die Zeilen wechseln: UP, DOWN, PAGE UP, PAGE DOWN, HOME und END. Mit den Tasten LINKS und RECHTS können Sie die Tabellen schnell horizontal von Anfang bis Ende durchblättern.

Am unteren Rand befindet sich ein Bereich mit zwei Registerkarten: Balances und Top 100 results. Schauen wir es uns das einmal an.


Die Registerkarte Balances

Hier gibt es zwei Diagramme:

  • Auf der linken Seite sehen Sie das Diagramm mit der Anfangsbilanz und allen Zwischenergebnissen, die sich nach dem Löschen der Verlustgeschäfte verbessert haben. Wir können sehen, wie sich die Saldenkurve nach dem Ausschluss der unrentablen Reihen verändert.
  • Auf der rechten Seite befindet sich ein Diagramm mit einem verbesserten Endergebnis der Bilanz (das im linken Diagramm das beste ist) und allen Bilanzen für jeden Handelszeitraum separat.

Die Diagramme werden auch aktualisiert, indem die Zeilen in den Tabellen hervorgehoben werden.

Die endgültige Salden der Ergebnisse und verbesserte Salden nach Streichung unrentabler Zeitintervalle

Die endgültige Salden der Ergebnisse und verbesserte Salden nach Streichung unrentabler Zeitintervalle


Die Registerkarte „Top 100 results“

Auch hier gibt es zwei Diagramme:

  • Auf der linken Seite finden Sie eine Grafik mit den 100 besten Ergebnissen (100 profit results).
  • Auf der rechten Seite wird eine Grafik der 100 besten Ergebnisse für das angegebene Kriterium angezeigt: Profit, Trades, DD, RF, BI_Profit, BI_Trades, BI_DD and BI_RF.

Durch das Hervorheben von Zeilen in Tabellen werden die Ergebnisse in Diagrammen aktualisiert. Unten sehen wir zum Beispiel, welches Ergebnis auf der linken Seite hervorgehoben wird (schwarze Saldenkurve) und wie das Ergebnis nach dem Ausschluss von Verlustserien auf der rechten Seite aussieht.

100 beste endgültige und verbesserte Salden nach Entfernung unrentabler Intervalle

100 beste endgültige und verbesserte Salden nach Entfernung unrentabler Intervalle

Wir können auch die Anzahl der unrentablen Intervalle angeben, die aus der Historie entfernt werden sollen, um das Ergebnis zu verbessern.

Es wird davon ausgegangen, dass Händler ihre Handelsergebnisse erheblich verbessern können, wenn sie weiterhin mit diesen EA-Parametern handeln und dabei die Zeitintervalle ausschließen, in denen unrentable Handelsreihen festgestellt wurden. Sogar ein scheinbar unrentabler Handelsalgorithmus kann sich mit diesem Ansatz manchmal als profitabel erweisen.

Wie bereits erwähnt, können Sie Ihre bevorzugten Ergebnisse in der entsprechenden Tabelle speichern. Verwenden Sie dazu die Schaltfläche Add to favorites (zu Favoriten hinzufügen). Die hinzugefügten Ergebnisse werden in der Tabelle der Gesamtergebnisse farblich hervorgehoben.

Zu den Favoriten hinzugefügte Ergebnisse werden farblich hervorgehoben

Zu den Favoriten hinzugefügte Ergebnisse werden in einer anderen Farbe hervorgehoben


Die Registerkarte Favorites

Diese Registerkarte enthält auch zwei Tabellen und zwei Diagramme. Die Idee hinter allen Parametern ist dieselbe wie auf der Registerkarte Results. Der einzige Unterschied besteht darin, dass diese ausgewählten Ergebnisse in Dateien (EA-Sets) und in der Datenbank gespeichert werden können. Hier befinden sich neben Tabellen und Diagrammen die folgenden Schaltflächen im oberen Teil des Fensters:

  • Deleted selected - löscht ein ausgewähltes Ergebnis aus den Favoriten in der Tabelle auf der linken Seite, sowie aus der Datenbank.
  • Delete all - löscht alle Ergebnisse aus den Favoriten in der Tabelle auf der linken Seite sowie aus der Datenbank.
  • Save parameters - speichert Parameter in der Datei und in der Datenbank.

Daten und Diagramme zu ausgewählten Ergebnissen

Daten und Diagramme zu ausgewählten Ergebnissen

Klicken Sie auf Save parameters, um alle ausgewählten Ergebnisse als Favoriten zu speichern:

  • in der Datenbank in der Tabelle FAVORITE_RESULTS
  • in den Dateien in MQL5/Files/Reports/FramesA/[CURRENT_TIME] im Falle des MQD-Dateilesemodus
  • MQL5/Files/Reports/[CURRENT_TIME] [EXPERT_NAME] im Falle von FRAME_MODE (unmittelbar nach der Optimierung).

Alle Ergebnisse werden in separaten Ordnern gespeichert, wobei die Durchlaufnummer als Ordnername verwendet wird. Dabei handelt es sich um eine Set-Datei mit externen EA-Parametern und mehreren Screenshots der oben besprochenen Tabellen und Charts. Die Durchlaufnummer wird als Präfix im Namen aller Dateien verwendet:

  • 422462.set - set-Datei mit externen EA-Parametern.
  • 422462_balance_sub_bi.png - Salden-Screenshot nach Ausschluss aller Zeitintervalle mit unrentablen Handelsreihen, sowie alle Salden separat für jedes verbleibende Zeitintervall.
  • 422462_balances_bi.png - Screenshot aller Salden nach Ausschluss aller Zeitintervalle mit unrentablen Handelsreihen.
  • 422462_bi_table.png - Screenshot der Tabelle mit allen Endergebnissen nach Ausschluss aller Zeitintervalle mit unrentablen Handelsreihen.
  • 422462_gui.png - Vollständiger Screenshot der grafischen Nutzeroberfläche.

Eine Beispieldatei mit den Parametern des EAs:

; this file contains last used input parameters for testing/optimizing FA expert advisor
; Experts\Advisors\ExpertMACD.ex5
;
Inp_Expert_Title=ExpertMACD||0.0||0.0||0.0||N
Inp_Signal_MACD_PeriodFast=15||5.0||5.0||30.0||Y
Inp_Signal_MACD_PeriodSlow=25||5.0||5.0||30.0||Y
Inp_Signal_MACD_PeriodSignal=25||5.0||5.0||30.0||Y
Inp_Signal_MACD_TakeProfit=270||30.0||5.0||300.0||Y
Inp_Signal_MACD_StopLoss=115||20.0||5.0||200.0||Y


Datenbank der Optimierungsergebnisse

Wie bereits erwähnt, speichert Frames Analyzer alle Optimierungsergebnisse sofort nach der Optimierung der Parameter im Tester in der Datenbank. Aber das ist noch nicht alles! Nach jeder Optimierung der Parameter wird eine neue Datenbank im lokalen Verzeichnis des Terminals MQL5/Files/DB angelegt. Der Name der Datenbank setzt sich aus der aktuellen Uhrzeit zum Zeitpunkt der Erstellung und dem Namen des EA zusammen: [AKTUELLE_ZEIT] [EXPERT_NAME].db.

Insgesamt gibt es drei Tabellen:

In der Tabelle OPTIMIZATION_RESULTS werden die folgenden Daten (Spalten) gespeichert:

  • Pass - Index des Durchlaufs
  • Gewinn - erzielter Gewinn.
  • Gewerke - Anzahl der Positionen.
  • PF - Profitfaktor.
  • DD - Drawdown.
  • RF - Recovery-Faktor.
  • Spalten mit allen externen EA-Parametern:
    • Parameter 1
    • Parameter 2
    • usw.
  • Deals - Historie der Geschäfte, die zur Berechnung der Salden für jeden Durchgang verwendet werden.

Tabelle mit Daten zu allen Optimierungsdurchläufen

Tabelle mit Daten zu allen Optimierungsdurchläufen

EXPERT_PARAMETERS Tabelle. Die Tabelle enthält die externen EA-Parameter sowie ihren Namen und den Pfad zu dem Verzeichnis, in dem sie sich während der Parameteroptimierung befanden. Die Tabelle hat zwei Spalten:

  • Parameter - Name des Parameters
  • Value - Wert des Parameters.

Nachfolgend sehen Sie ein Beispiel für ExpertMACD EA aus der Standardauslieferung des Terminals. Bei externen Parametern(INPUT_n) wird in der Spalte Value der Name des externen Parameters und der Optimierungsparameter (getrennt durch ||) gespeichert, die für diese Optimierung verwendet werden.

EA-Daten-Tabelle

EA-Daten-Tabelle

Einige andere Parameter, die für das Funktionieren des EAs erforderlich sind, können der Tabelle später hinzugefügt werden.

Tabelle FAVORITE_RESULTS. Die als Favoriten ausgewählte Optimierungsergebnisse werden hier gespeichert. Hier gibt es nur drei Spalten:

  • FavoriteID - ID der Position.
  • Pass - Index des Durchlaufs, für den wir alle Daten in der Tabelle OPTIMIZATION_RESULTS abrufen wollen.
  • RemovedIntervals - entfernte Intervalle, in denen der reale Handel deaktiviert werden soll.

Tabelle der ausgewählten Optimierungsergebnisse mit entfernten Zeitintervallen

Tabelle ausgewählter Optimierungsergebnisse mit entfernten Zeitintervallen

So können wir alles, was wir nach der Optimierung und Analyse der Ergebnisse für die EA-Operation benötigen, später einmal aus der Datenbank holen.


Wie wird Frames Analyzer verwendet?

Laden Sie zuerst Frames Analyzer von dieser Seite. Wenn Sie diesen EA nun in Ihrem Terminal ausführen, werden Sie sehen, dass alle Frames Analyzer Diagramme und Tabellen leer sind, da dieses Tool Optimierungsergebnisse benötigt. Wenn Sie es ausprobieren möchten, laden Sie die Datenbankdatei mit den Optimierungsergebnissen herunter, die unten angehängt ist. Kopiere Sie diese Datei in den Ordner MQL5/Files/DB. Jetzt können Sie die Ergebnisse über die grafische Oberfläche in den Frames Analyzer EA laden. Klicken Sie in der der Registerkarte Frames auf Open DB. Es öffnet sich ein Dialogfeld, in dem Sie die Datenbankdatei auswählen können (siehe unten). Ich habe bereits mehrere Datenbankdateien in diesem Verzeichnis.

Auswählen einer Datenbankdatei im Dialogfeld

Auswählen einer Datenbankdatei im Dialogfenster

Damit Frames Analyzer die Optimierungsergebnisse Ihres EAs speichern kann, müssen Sie ihn als Bibliothek in Ihren EA-Code einbinden. Nachstehend finden Sie ein ausführliches Beispiel.

Nachdem Sie Frames Analyzer auf Ihren Computer heruntergeladen haben, finden Sie ihn in MQL5/Experts/Market. Dann können Sie sie auf folgende Weise in die Hauptdatei (*.mq5) Ihres EA einfügen:

#import "..\Experts\Market\FramesA.ex5"
  void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
  void OnTesterEvent(void);
  void OnTesterInitEvent(void);
  void OnTesterPassEvent(void);
  void OnTesterDeinitEvent(void);
#import

Wie wir oben sehen können, müssen wir mehrere Funktionen aus dem EAFrames Analyzer importieren. Sie werden benötigt, um Ereignisse in der GUI-Bedienung zu verarbeiten und um Daten während der Optimierung der EA-Parameter im Tester zu sammeln. Alles, was Sie tun müssen, ist, diese Funktionen in ähnlichen EA-Funktionen aufzurufen, wie unten gezeigt:

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {
  FramesA::OnEvent(id, lparam, dparam, sparam);
}
//+------------------------------------------------------------------+
//| Test completion event handler                                    |
//+------------------------------------------------------------------+
double OnTester(void) {
  FramesA::OnTesterEvent();
  return(0.0);
}
//+------------------------------------------------------------------+
//| TesterInit function                                              |
//+------------------------------------------------------------------+
void OnTesterInit(void) {
  FramesA::OnTesterInitEvent();
}
//+------------------------------------------------------------------+
//| TesterPass function                                              |
//+------------------------------------------------------------------+
void OnTesterPass(void) {
  FramesA::OnTesterPassEvent();
}
//+------------------------------------------------------------------+
//| TesterDeinit function                                            |
//+------------------------------------------------------------------+
void OnTesterDeinit(void) {
  FramesA::OnTesterDeinitEvent();
}
//+------------------------------------------------------------------+

Wie Sie sehen können, ist alles ziemlich einfach.

Übrigens, wenn Sie die Bibliothek EasyAndFastGUI v2.0 in Ihren Projekten verwenden, um grafische Oberflächen zu erstellen (die Bibliothek ist Teil von Frames Analyzer), dann muss nichts weiter getan werden, damit sie in einer MQL-Anwendung zusammenarbeiten. Der in Ihrem EA integrierte Frames Analyzer arbeitet separat im Frame-Modus (FRAME_MODE) und beeinträchtigt nicht den Betrieb der grafischen Oberfläche Ihrer Anwendung.

Auch wenn Sie die Bibliothek EasyAndFastGUI v2.0 nicht haben, funktioniert Frames Analyzer trotzdem.

Ein Beispiel des EAs ExpertMACD aus der Standardauslieferung mit dem integrierten Frames Analyzer Modul ist unten angefügt.


Anwendung von gelöschten Intervallen in Expert Advisors

Sie verfügen also über das Instrument Frames Analyzer. Sie haben ihn mit Ihrem Trading EA verbunden, eine Parameteroptimierung durchgeführt und verfügen nun über eine Datenbank mit den Ergebnissen aller Durchläufe und den Werten aller externen Parameter. In einer separaten Tabelle haben Sie Ihre bevorzugten Optimierungsergebnisse mit entfernten Zeitintervallen gespeichert, die Sie nun auf Ihre Handelsstrategie anwenden können.

Schauen wir uns an, wie dies umgesetzt werden kann.

Angenommen, Sie möchten die Auswahl von Zeithandelsbereichen über die grafische Nutzeroberfläche implementieren. Es wäre schön, wenn es ein Element in der grafischen Oberfläche gäbe, das entfernte Zeitintervalle visualisiert, in denen es nicht empfehlenswert ist, zu handeln. Wenn Sie ein glücklicher Besitzer der Bibliothek EasyAndFastGUI 2.0 zur Erstellung fortgeschrittener GUIs sind, dann haben Sie bereits eine solche Möglichkeit. In einer der letzten Aktualisierungen wurde ein weiteres einzigartiges Element hinzugefügt - CTimeRanges. Es ermöglicht Ihnen, mit Zeitintervallen zu arbeiten. Als Nächstes werden wir eine grafische Nutzeroberfläche mit diesem Element erstellen und es genauer betrachten.

Die grafische Nutzeroberfläche besteht aus den folgenden Elementen:

  • Formular für Steuerungen - CWindow
  • Die Schaltfläche zum Öffnen der Datenbankdatei - CButton.
  • Die Dropdown-Liste mit den Durchlauf-Indizes aus der Tabelle der ausgewählten Optimierungsergebnisse - CComboBox.
  • Zeitskala mit Intervallen, die nicht für den Handel empfohlen werden - CTimeRanges.

Um eine solche grafische Nutzeroberfläche zu erstellen, benötigen Sie nur wenige Zeilen Code:

void CApp::CreateGUI(void) {

//--- Form
  m_window1.ResizeMode(true);
  m_window1.ThemeButtonIsUsed(true);
  CCoreCreate::CreateWindow(m_window1, "TIME TRADE RANGES", 1, 1, 350, 100, true, true, true, true);
  
//--- Button
  CCoreCreate::CreateButton(m_button1, m_window1, 0, "Open DB...", 10, 30, 100);
  
//--- Combobox
  string items1[] = {"12345", "19876", "45678", "23456", "67890"};
  CCoreCreate::CreateCombobox(m_combobox1, m_window1, 0, "Passes: ", 120, 30, 135, 90, items1, 103, 0);
  
//--- Time ranges
  string time_ranges[] = {
    "00:45:00 - 01:20:01",
    "08:55:00 - 09:25:01",
    "12:55:00 - 13:50:01",
    "15:30:00 - 17:39:59",
    "20:10:00 - 21:05:00"
  };
  m_time_ranges1.SetTimeRanges(time_ranges);
  m_time_ranges1.AutoXResizeMode(true);
  m_time_ranges1.AutoXResizeRightOffset(5);
  CCoreCreate::CreateTimeRanges(m_time_ranges1, m_window1, 0, 5, 60, 390);
}

Das obige Beispiel zeigt, wie Sie dem Element TimeRanges Zeitintervalle zuweisen können.

Wenn Sie eine MQL-Anwendung mit einer solchen grafischen Schnittstelle starten, sehen Sie Folgendes:

TimeRanges Element aus der EasyAndFastGUI v2.0 Bibliothek

TimeRanges Element aus der EasyAndFastGUI v2.0 Bibliothek

Die obige Abbildung zeigt ein GUI-Element, das eine Intraday-Zeitskala darstellt. Dies ist ein dynamisches Element, das sich automatisch an die Breite des übergeordneten Elements (in diesem Fall ist es das Formular) anpassen kann. Die gestrichelt-gepunktete Linie markiert die aktuelle Uhrzeit, neben der ein Textlabel mit der aktuellen Zeit angezeigt wird. Wenn der Mauszeiger über der Zeitskala schwebt, wird eine vertikale durchgezogene Linie unter dem Mauszeiger mit einer Textbeschriftung der Zeit, auf die der Mauszeiger zeigt, gezeichnet. 

Es ist recht informativ geworden, aber das ist noch nicht alles! Wenn wir auf die Skala klicken, erzeugt das Element ein nutzerdefiniertes Ereignis mit der ID ON_CLICK_TIME_RANGE, das in einer nutzerdefinierten MQL-Anwendung verarbeitet werden kann. Der Parameter dparam enthält die Anzahl der seit Beginn des Tages verstrichenen Sekunden, während der Parameter sparam den entfernten Zeitbereich oder eine leere Zeichenkette enthält, wenn keiner der eingestellten Bereiche während des Klicks unter den Cursor fiel. Außerdem können Sie den Modus aktivieren, in dem das Element TimeRanges durch einen einzigen Klick für das gesamte Diagramm erweitert werden kann.

Hier ist der Code, mit dem Sie dieses Ereignis abfangen und behandeln können:

void CApp::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {

  if(id == CHARTEVENT_CUSTOM + ON_CLICK_TIME_RANGE) {
    
    if(m_time_ranges1.Id() == lparam) {
      Print(__FUNCTION__, " > pressed time: ", ::TimeToString((datetime)dparam, TIME_MINUTES|TIME_SECONDS), "; pressed time range: ", sparam);
      
      string time_ranges[];
      m_time_ranges1.GetTimeRanges(time_ranges);
      
      ArrayPrint(time_ranges);
      return;
    }
    return;
  }
}

Wie Sie in der obigen Codeauflistung sehen können, prüfen wir zunächst die ID des Ereignisses, und wenn es sich um das Nutzerereignis ON_CLICK_TIME_RANGE handelt, prüfen wir die Element-ID, die im Parameter lparam des Ereignisses übergeben wurde. Anschließend werden die gewonnenen Daten an das Protokoll gesendet. Das Beispiel zeigt auch, wie man die eingestellten Intervalle im Element mit der Methode CTimeRanges::GetTimeRanges() erhält und das erhaltene Array auch im Journal anzeigt.

In den EA-Protokollen (Registerkarte Experts ) sehen Sie in etwa derartiges:

CApp::OnEvent > pressed time: 16:34:54; pressed time range: 15:30:00 - 17:39:59
"00:45:00-01:20:01" "08:55:00-09:25:01" "12:55:00-13:50:01" "15:30:00-17:39:59" "20:10:00-21:05:00"

Das folgende Beispiel zeigt, wie man das Array der Durchlauf-Indizes aus der Tabelle der favorisierten Ergebnisse(FAVORITE_RESULTS) in der Datenbank erhält.

void CApp::GetPassNumbersOfFavoriteResults(const string db_filename, ulong &passes[]) {

  ::ResetLastError();
  uint flags = DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE;
  int db_handle = ::DatabaseOpen(db_filename, flags);
  if(db_handle == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", db_filename, " open failed with code: ", ::GetLastError());
    return;
  }
  
  string command = "SELECT (Pass) FROM FAVORITE_RESULTS;";
  
  int db_query = ::DatabasePrepare(db_handle, command);
  if(db_query == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", db_filename, " request failed with code ", ::GetLastError());
    ::DatabaseClose(db_handle);
    return;
  }

  for(int i = 0; ::DatabaseRead(db_query); i++) {
    int pass_number;
    ::ResetLastError();
    if(::DatabaseColumnInteger(db_query, 0, pass_number)) {
      int prev_size = ::ArraySize(passes);
      ::ArrayResize(passes, prev_size + 1);
      passes[prev_size] = (ulong)pass_number;
    } 
    else {
      ::Print(__FUNCTION__, " > DatabaseColumnInteger() error: ", ::GetLastError());
    }
  }
//--- Finish working with the database
  ::DatabaseFinalize(db_query);
  ::DatabaseClose(db_handle);
}

Nachdem wir die Durchlauf-Indizes erhalten haben, können wir die entfernten Intervalle erhalten, indem wir den Durchlauf-Index der Methode GetFavoriteRemovedIntervalsByPassNumber() übergeben:

string CApp::GetFavoriteRemovedIntervalsByPassNumber(const ulong pass_number) {

  ::ResetLastError();
  uint flags = DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE;
  int db_handle = ::DatabaseOpen(m_db_filename, flags);
  if(db_handle == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", m_db_filename, " open failed with code: ", ::GetLastError());
    return(NULL);
  }
  
  string command = "SELECT (RemovedIntervals) FROM FAVORITE_RESULTS WHERE Pass=" + (string)pass_number + ";";
  
  int db_query = ::DatabasePrepare(db_handle, command);
  if(db_query == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", m_db_filename, " request failed with code ", ::GetLastError());
    ::DatabaseClose(db_handle);
    return(NULL);
  }
  
  string time_ranges = "";
  
  if(::DatabaseRead(db_query)) {
    ::ResetLastError();
    if(!::DatabaseColumnText(db_query, 0, time_ranges)) {
      ::Print(__FUNCTION__, " > DatabaseColumnText() error: ", ::GetLastError());
    }
  }
//--- Finish working with the database
  ::DatabaseFinalize(db_query);
  ::DatabaseClose(db_handle);
  
  return(time_ranges);
}

Wenn Sie auf Open DB... klicken, um eine Datei mit einer Datenbank zu öffnen, wird die Funktion OnClickOpenDB() aufgerufen. Dies ist die Methode, bei der das Programm das Dialogfenster zur Auswahl einer Datei in MQL5/Dateien/DB öffnet. Wenn die Datei ausgewählt wird, wird sie für die weitere Verwendung in anderen Methoden gespeichert. Als Nächstes verwenden wir die Methode GetPassNumbersOfFavoriteResults(), deren Code im vorherigen Listing gezeigt wurde, um die Indizes der Pässe aus der Tabelle der bevorzugten Ergebnisse zu erhalten. Fügen Sie diese Daten der Dropdown-Liste hinzu und wählen Sie das erste Element aus.

bool CApp::OnClickOpenDB(const int id) {

  if(m_button1.Id() != id) {
    return(false);
  }

  string filenames[];
  string folder = "DB";
  string filter = "DB files (*.db)|*.db|SQLite files (*.sqlite)|*.sqlite|All files (*.*)|*.*";
  if(::FileSelectDialog("Select database file to upload", folder, filter,
                        FSD_FILE_MUST_EXIST, filenames) > 0) {
    
    int filenames_total = ::ArraySize(filenames);
    if(filenames_total < 1) {
      return(false);
    }
    
    m_db_filename = filenames[0];
    
    ::Print(__FUNCTION__, " > m_db_filename: ", m_db_filename);
    
    ulong passes[];
    GetPassNumbersOfFavoriteResults(m_db_filename, passes);
    
    ::ArrayPrint(passes);
    
    CListView *list_view = m_combobox1.GetListViewPointer();
    
    int passes_total = ::ArraySize(passes);
    if(passes_total > 0) {
      list_view.Clear();
      for(int i = 0; i < passes_total; i++) {
        list_view.AddItem(i, (string)passes[i]);
      }
      m_combobox1.SelectItem(0);
      m_combobox1.GetButtonPointer().Update(true);
      list_view.Update(true);
    }
  }
  return(true);
}

Durch Auswahl des Durchlauf-Index in der Dropdown-Liste werden die entfernten Intervalle in der Methode SetTimeRange() abgerufen, im globalen Array gespeichert und im grafischen Element vom Typ CTimeRanges eingestellt.

void CApp::SetTimeRange(void) {

  CListView *list_view = m_combobox1.GetListViewPointer();
  
  int   index       = list_view.SelectedItemIndex();
  ulong pass_number = (int)list_view.GetValue(index);
  
  string removed_intervals = GetFavoriteRemovedIntervalsByPassNumber(pass_number);
  
  ::ArrayFree(m_time_ranges_str);
  ::StringSplit(removed_intervals, ::StringGetCharacter("|", 0), m_time_ranges_str);
  
  int ranges_total = ::ArraySize(m_time_ranges_str);
  for(int i = 0; i < ranges_total; i++) {
    ::StringReplace(m_time_ranges_str[i], " - ", "-");
  }
  
  ::ArrayPrint(m_time_ranges_str);
  
  m_time_ranges1.SetTimeRanges(m_time_ranges_str);
  m_time_ranges1.Update();
}

Als Nächstes benötigen wir eine Struktur zum Speichern von Zeitspannen. Wenn Sie die EasyAndFastGUI 2.0 Bibliothek verwenden, dann ist eine solche Struktur (TimeRange) bereits in der Elementdatei CTimeRanges vorhanden:

struct TimeRange {
  MqlDateTime start;
  MqlDateTime end;
};

Wenn Sie diese Grafikbibliothek nicht verwenden, können Sie eine solche Struktur in Ihrem Code separat deklarieren.

Da die entfernten Zeitspannen bereits in der Methode SetTimeRange() in Form von Zeichenketten gespeichert sind, müssen wir sie nun der Einfachheit halber in ein Array von Strukturen setzen. Dazu verwenden wir die Methode GetTimeRanges():

void CApp::GetTimeRanges(TimeRange &ranges[]) {
  
  ::ArrayFree(ranges);
  
  int ranges_total = ::ArraySize(m_time_ranges_str);
  for(int i = 0; i < ranges_total; i++) {
    
    string tr[];
    ::StringSplit(m_time_ranges_str[i], ::StringGetCharacter("-", 0), tr);
  
    int size = ::ArraySize(ranges);
    ::ArrayResize(ranges, size + 1);
    
    MqlDateTime start, end;
    ::TimeToStruct(::StringToTime(tr[0]), start);
    ::TimeToStruct(::StringToTime(tr[1]), end);
    
    datetime time1 = HourSeconds(start.hour) + MinuteSeconds(start.min) + start.sec;
    datetime time2 = HourSeconds(end.hour) + MinuteSeconds(end.min) + end.sec;
    ::TimeToStruct(time1, ranges[size].start);
    ::TimeToStruct(time2, ranges[size].end);
  }
}

Diese Methoden können z. B. wie folgt verwendet werden, wenn die entsprechenden Ereignisse behandelt werden (eine verkürzte Version der Anwendungsklasse):

class CApp : public CCoreCreate {
 private:
  TimeRange         m_time_ranges[];
  string            m_time_ranges_str[];
  
...

  virtual void      OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);

  void              SetTimeRange(void);
  void              GetTimeRanges(TimeRange &ranges[]);
  
  int               HourSeconds(const int hour)     { return(hour * 60 * 60); }
  int               MinuteSeconds(const int minute) { return(minute * 60);    }
};

void CApp::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {

  if(id == CHARTEVENT_CUSTOM + ON_CLICK_BUTTON) {
    if(OnClickOpenDB((int)lparam)) {
      SetTimeRange();
      GetTimeRanges(m_time_ranges);
      return;
    }
    return;
  }
  
  if(id == CHARTEVENT_CUSTOM + ON_CLICK_COMBOBOX_ITEM) {
    if(OnSelectPass((int)lparam)) {
      SetTimeRange();
      GetTimeRanges(m_time_ranges);
      return;
    }
    return;
  }
}

Jetzt können wir die Methode CheckTradeTime() implementieren, um zu prüfen, ob der Handel zur zulässigen Zeit durchgeführt wird:

bool CApp::CheckTradeTime(void) {

  bool     is_trade_time = true;
  datetime current_time  = ::TimeCurrent();
  
  MqlDateTime time;
  ::TimeToStruct(current_time, time);
  
  int ranges_total = ::ArraySize(m_time_ranges);
  for(int i = 0; i < ranges_total; i++) {
  
    MqlDateTime start = m_time_ranges[i].start;
    MqlDateTime end   = m_time_ranges[i].end;
    
    datetime time_c = HourSeconds(time.hour) + MinuteSeconds(time.min) + time.sec;
    datetime time_s = HourSeconds(start.hour) + MinuteSeconds(start.min) + start.sec;
    datetime time_e = HourSeconds(end.hour) + MinuteSeconds(end.min) + end.sec;
    
    if(time_c >= time_s && time_c <= time_e) {
      is_trade_time = false;
      break;
    }
  }
  return(is_trade_time);
}

Jetzt müssen wir nur noch den Aufruf der Methode CheckTradeTime() einrichten, zum Beispiel in der Funktion OnTick():

  if(CheckTradeTime()) {
    Print(__FUNCTION__, " > trade time!");
  }

Die vorgefertigte Anwendung ist am Ende des Artikels beigefügt.

Empfangen von aus dem Handel genommenen Zeitintervallen

Aus dem Handel genommene empfangene Zeiträume


Schlussfolgerung

Nachdem wir die Parameter im Strategietester optimiert haben, müssen wir einzelne Tests durchführen, um die Ergebnisse zu sehen. Dies ist sehr zeitaufwändig und ineffizient.

Was ist der Frames Analyzer? Dies ist ein Plug-in-Modul für jeden Expert Advisor zur Analyse von Optimierungsframes während der Parameteroptimierung im Strategietester, aber auch außerhalb des Testers, durch Lesen einer MQD-Datei oder einer Datenbank, die unmittelbar nach der Parameteroptimierung erstellt wird. Sie können diese Optimierungsergebnisse mit anderen Nutzern teilen, die Frames Analyzer haben, um die Ergebnisse zu diskutieren.

Mit dem Frames Analyzer können Sie die 100 besten Optimierungsergebnisse gleichzeitig in Form von Diagrammen anzeigen. Diese Top-100-Ergebnisse können anhand verschiedener Kriterien ermittelt werden: Profit, Trades, Drawdown, Profitfaktor und Recovery-Faktor. Darüber hinaus bietet Frames Analyzer das integrierte Modul Best Intervals, um unrentable Zeiträume zu ermitteln, die aus der Historie der Trades entfernt werden, sodass Sie sehen können, wie das Ergebnis ausgesehen hätte, wenn in diesen Zeiträumen nicht gehandelt worden wäre.

Sie können die gewünschten Ergebnisse sowohl in der Datenbank als auch in Form von vorgefertigten Set-Dateien mit externen EA-Parametern speichern. Gelöschte Zeitintervalle werden ebenfalls in der Datenbank gespeichert. So können Sie sie in Ihrem Handel anwenden, um Ihren Gewinn zu maximieren. Frames Analyzer lässt nur die Zeitintervalle übrig, die sich statistisch gesehen als die sichersten herausgestellt haben!


Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/11667

Beigefügte Dateien |
MQL5.zip (5545.43 KB)
Berg- oder Eisbergdiagramme Berg- oder Eisbergdiagramme
Was halten Sie von der Idee, der MetaTrader 5-Plattform einen neuen Chart-Typ hinzuzufügen? Einige Leute sagen, dass es an einigen Dingen mangelt, die andere Plattformen bieten. Aber die Wahrheit ist, dass MetaTrader 5 eine sehr praktische Plattform ist, da sie Ihnen Dinge ermöglicht, die auf vielen anderen Plattformen nicht (oder zumindest nicht ohne weiteres) möglich sind.
DoEasy. Steuerung (Teil 24): Das WinForms-Hilfsobjekt für Hinweise DoEasy. Steuerung (Teil 24): Das WinForms-Hilfsobjekt für Hinweise
In diesem Artikel werde ich die Logik der Angabe der Basis- und Hauptobjekte für alle WinForms-Bibliotheksobjekte überarbeiten, ein neues Basisobjekt Hint für Hinweise und mehrere seiner abgeleiteten Klassen entwickeln, um die mögliche Richtung der Bewegung des Trennzeichens anzugeben.
Algorithmen zur Optimierung mit Populationen Ameisenkolonie-Optimierung (ACO) Algorithmen zur Optimierung mit Populationen Ameisenkolonie-Optimierung (ACO)
Dieses Mal werde ich den Algorithmus der Ameisenkolonie-Optimierung analysieren. Der Algorithmus ist sehr interessant und komplex. In diesem Artikel versuche ich, eine neue Art von ACO zu schaffen.
Adaptive Indikatoren Adaptive Indikatoren
In diesem Artikel werde ich mehrere mögliche Ansätze zur Erstellung adaptiver Indikatoren betrachten. Adaptive Indikatoren zeichnen sich durch das Vorhandensein einer Rückkopplung zwischen den Werten der Eingangs- und Ausgangssignale aus. Diese Rückkopplung ermöglicht es dem Indikator, sich selbständig auf die optimale Verarbeitung von finanziellen Zeitreihenwerten einzustellen.