
Integration von ML-Modellen mit dem Strategy Tester (Teil 3): Verwaltung von CSV-Dateien (II)
Einführung
In diesem Artikel werden wir uns auf den dritten Teil der Integration von Strategy Tester mit Python konzentrieren. Wir werden die Erstellung der Klasse CFileCSV für die effiziente Verwaltung von CSV-Dateien sehen. Wir werden einige Beispiele und den Code untersuchen, damit die Leser besser verstehen, wie diese Klasse in der Praxis implementiert werden kann.
Was also ist CSV?
CSV (Comma Separated Values) ist ein einfaches und weit verbreitetes Dateiformat zum Speichern und Austauschen von Daten. Sie ist vergleichbar mit einer Tabelle, in der jede Zeile einen Datensatz und jede Spalte ein Feld in diesen Daten darstellt. Die Werte werden durch ein Trennzeichen getrennt, damit sie in verschiedenen Tools und Programmiersprachen leichter zu lesen und zu schreiben sind.
Das CSV-Format erschien Anfang der 1970er Jahre und wurde zunächst auf Großrechnersystemen verwendet. CSV kann nicht auf einen bestimmten Urheber zurückgeführt werden, da es sich um einen weit verbreiteten Dateityp handelt.
Es wird häufig zum Importieren und Exportieren von Daten in verschiedenen Anwendungen wie Tabellenkalkulationen, Datenbanken, Datenanalyseprogrammen usw. verwendet. Seine Beliebtheit beruht sowohl auf der einfachen Handhabung und Verständlichkeit als auch auf der Kompatibilität mit vielen Systemen und Tools. Dies ist besonders nützlich, wenn Daten zwischen verschiedenen Anwendungen ausgetauscht werden müssen, z. B. um Informationen von einem System in ein anderes zu übertragen.
Die wichtigsten Vorteile der Verwendung von CSV sind also Nutzerfreundlichkeit und Kompatibilität. Es hat jedoch auch einige Einschränkungen, wie z. B. die fehlende Unterstützung für komplexe Datentypen und die eingeschränkte Fähigkeit, sehr große Datenmengen zu verarbeiten. Auch das Fehlen eines universellen Standards für das CSV-Format kann zu Kompatibilitätsproblemen zwischen verschiedenen Anwendungen führen. Außerdem können Sie versehentlich Daten verlieren oder verändern, da das Format keine Validierung vorsieht. Im Allgemeinen ist CSV eine vielseitige und einfach zu verwendende Option für die Speicherung und den Austausch von Daten. Dennoch ist es wichtig, seine Grenzen zu kennen und zu verstehen und Maßnahmen zu ergreifen, um die Genauigkeit der Daten zu gewährleisten.
Motivation
Die Erstellung der CFileCSV-Klasse wurde durch die Notwendigkeit verursacht, die MetaTrader 5 Strategy Tester-Umgebung mit Python zu integrieren. Bei der Entwicklung von Handelsstrategien unter Verwendung von Modellen des maschinellen Lernens (ML) stieß ich auf die Schwierigkeit, in Python erstellte Modelle zu verwenden. Ich müsste entweder eine Bibliothek für maschinelles Lernen in MQL5 erstellen, was über mein Hauptziel hinausging, oder einen Expert Advisor komplett in Python entwickeln.
Obwohl die Sprache MQL5 Ressourcen für die Erstellung von ML-Bibliotheken bereitstellt, wollte ich keine Zeit und Mühe in deren Entwicklung investieren, da mein Hauptziel darin bestand, Daten zu analysieren und Modelle auf schnelle und effiziente Weise zu erstellen.
Die Aufgabe bestand also darin, eine Zwischenlösung zu finden. Ich wollte die Vorteile der in Python erstellten ML-Modelle nutzen, aber auch in der Lage sein, sie direkt auf meine Arbeit mit MQL5 anzuwenden. Also suchte ich nach einer Möglichkeit, diese Einschränkung zu überwinden und eine Lösung für die Integration dieser beiden Umgebungen zu finden.
Die Idee war, ein Nachrichtensystem zu schaffen, mit dem MetaTrader 5 und Python zeitnah miteinander kommunizieren können. Damit können Sie die Initialisierung und den Datentransfer von MetaTrader 5 zu Python und das Senden von Vorhersagen von Python zu Meta Trader 5 steuern. Die Klasse CFileCSV wurde entwickelt, um diese Interaktion zu erleichtern, indem sie ein effizientes Speichern und Laden von Daten ermöglicht.
Einführung in die Klasse CFileCSV
CFileCSV ist eine Klasse für die Arbeit mit CSV-Dateien (Comma Separated Values). Die Klasse ist von CFile abgeleitet. Es bietet also spezielle Funktionen für die Arbeit mit CSV-Dateien. Der Zweck dieser Klasse ist es, das Lesen und Schreiben von CSV-Dateien zu erleichtern, indem die Arbeit mit verschiedenen Datentypen vereinfacht wird.
Einer der großen Vorteile der Verwendung von CSV-Dateien besteht darin, dass solche Dateien leicht weitergegeben werden können und eine bequeme Möglichkeit zum Import/Export von Daten bieten. Solche Dateien lassen sich leicht in Programmen wie Excel oder Google Sheets öffnen und bearbeiten, und sie können in verschiedenen Programmiersprachen gelesen werden. Da sie außerdem kein bestimmtes Format haben, können sie je nach Bedarf gelesen und geschrieben werden.
Die Klasse CFileCSV hat vier öffentliche Hauptmethoden: Öffnen, WriteHeader, WriteLine und Lesen. Darüber hinaus verfügt es über zwei private Hilfsmethoden, die Arrays oder Matrizen in Strings umwandeln und diese Werte in eine Datei schreiben.
class CFileCSV : public CFile { private: template<typename T> string ToString(const int, const T &[][]); template<typename T> string ToString(const T &[]); short m_delimiter; public: CFileCSV(void); ~CFileCSV(void); //--- methods for working with files int Open(const string,const int, const short); template<typename T> uint WriteHeader(const T &values[]); template<typename T> uint WriteLine(const T &values[][]); string Read(void); };
Bei der Verwendung dieser Klasse ist zu beachten, dass sie für die Arbeit mit bestimmten CSV-Dateien konzipiert wurde. Wenn die Daten in der Datei nicht korrekt formatiert sind, können die Ergebnisse unerwartet sein. Es ist auch sehr wichtig sicherzustellen, dass die Datei geöffnet wurde, bevor Sie versuchen, in sie zu schreiben, und dass sie Schreibrechte hat.
Als Beispiel für die Verwendung der Klasse CFileCSV können wir eine CSV-Datei aus einer Datenmatrix erstellen. Zunächst erstellen wir eine Instanz der Klasse und öffnen die Datei mit der Methode Open. In dieser Methode geben wir den Dateinamen und das Open-Flag an. Als Nächstes verwenden wir die WriteHeader-Methode, um die Kopfzeile in die Datei zu schreiben, und die WriteLine-Methode, um Datenzeilen aus der Matrix zu schreiben. Lassen Sie uns diese Schritte anhand einer Beispielfunktion veranschaulichen:
#include "FileCSV.mqh" void CreateCSVFile(string fileName, string &headers[], string &data[][]) { // Creates an object of the CFileCSV class CFileCSV csvFile; // Checks if the file can be opened for writing in the ANSI format if(csvFile.Open(fileName, FILE_WRITE|FILE_ANSI)) { int rows = ArrayRange(data, 0); int cols = ArrayRange(data, 1); int headerSize = ArraySize(headers); //Checks if the number of columns in the data matrix is equal to the number if elements in the header array and if the number of rows in the data matrix is greater than zero if(cols != headerSize || rows == 0) { Print("Error: Invalid number of columns or rows. Data array must have the same number of columns as the headers array and at least one row."); return; } // Writes header to file csvFile.WriteHeader(headers); // Writes data rows to file csvFile.WriteLine(data); // Closes the file csvFile.Close(); } else { // Shows an error message if the file cannot be opened Print("Error opening file!"); } }
Der Zweck dieser Methode ist es, eine CSV-Datei aus einem Array von Kopfzeilen und einem Array von Daten zu erstellen. Beginnen wir mit der Erstellung eines Objekts der Klasse CFileCSV. Prüfen Sie dann, ob die Datei zum Schreiben im ANSI-Format geöffnet werden kann. Wenn die Datei geöffnet werden kann, stellen Sie sicher, dass die Anzahl der Spalten in der Datenmatrix gleich der Anzahl der Elemente in der Kopfzeile der Matrix ist und dass die Anzahl der Zeilen in der Datenmatrix größer als Null ist. Wenn diese Bedingungen erfüllt sind, schreibt die Methode die Kopfzeile mit der Methode WriteHeader() in die Datei und anschließend die Datenzeilen mit der Methode WriteLine(). Schließlich schließt die Methode die Datei. Wenn die Datei nicht geöffnet werden kann, wird eine Fehlermeldung angezeigt.
Diese Methode wird in Kürze anhand eines Beispiels demonstriert. Achten Sie darauf, dass die Implementierung erweitert werden kann, um andere Aufgaben zu erfüllen. Sie können zum Beispiel weitere Validierungen hinzufügen: Prüfen Sie, ob die Datei existiert, bevor Sie versuchen, sie zu öffnen, oder fügen Sie eine Option hinzu, mit der Sie das zu verwendende Trennzeichen auswählen können.
Die Klasse CFileCSV bietet eine einfache und praktische Möglichkeit, mit CSV-Dateien zu arbeiten. Sie erleichtert das Lesen und Schreiben von Daten in CSV-Dateien. Sie sollten jedoch vorsichtig sein, wenn Sie sie verwenden: Sie sollten sicherstellen, dass die Dateien das erwartete Format haben und die Methodenrückgaben überprüfen, um sicherzustellen, dass sie erfolgreich ausgeführt wurden.
Umsetzung
Wie bereits erwähnt, hat die Klasse CFileCSV vier öffentliche Hauptmethoden: Open, WriteHeader, WriteLine und Read. Es hat auch zwei private Hilfsmethoden, die eine Namensüberladung haben: ToString.
-
Die Methode Open(const string file_name,const int open_flags, const short delimiter=';') wird zum Öffnen einer CSV-Datei verwendet. Die Methode erhält die folgenden Parameter: Dateiname, Open Flags (z. B. FILE_WRITE oder FILE_READ) und das in der Datei zu verwendende Trennzeichen (Standard ist ';'). Sie ruft die Open-Methode der Basisklasse CFile auf und speichert das angegebene Trennzeichen in einer privaten Variablen. Sie gibt auch eine ganze Zahl zurück, die den Erfolg oder Misserfolg der Operation anzeigt.
int CFileCSV::Open(const string file_name,const int open_flags, const short delimiter=';') { m_delimiter=delimiter; return(CFile::Open(file_name,open_flags|FILE_CSV|delimiter)); }
- Die Methode WriteHeader(const T &values[]) wird verwendet, um eine Kopfzeile in die geöffnete CSV-Datei zu schreiben. Sie erhält einen Parameter mit einem Array von Werten, die die Spaltenüberschriften der Datei darstellen. Mit der Methode ToString wird das Array in eine Zeichenkette umgewandelt und diese Zeichenkette mit der Methode FileWrite der Basisklasse CFile in die Datei geschrieben. Sie gibt auch eine ganze Zahl zurück, die die Anzahl der in die Datei geschriebenen Bytes angibt.
template<typename T> uint CFileCSV::WriteHeader(const T &values[]) { string header=ToString(values); //--- check handle if(m_handle!=INVALID_HANDLE) return(::FileWrite(m_handle,header)); //--- failure return(0); }
-
Die Methode WriteLine(const T &values[][]) wird verwendet, um Datenzeilen in die geöffnete CSV-Datei zu schreiben. Als Parameter erhält diese Methode eine Matrix von Werten, die die Datenzeilen in der Datei darstellen. Sie durchläuft jede Zeile der Matrix und wandelt mit der Methode ToString jede Zeile in eine Zeichenkette um und verkettet diese zu einer einzigen Zeichenkette. Anschließend wird diese Zeichenfolge mit der Methode FileWrite der Basisklasse CFile in eine Datei geschrieben. Sie gibt auch eine ganze Zahl zurück, die die Anzahl der in die Datei geschriebenen Bytes angibt.
template<typename T> uint CFileCSV::WriteLine(const T &values[][]) { int len=ArrayRange(values, 0); if(len<1) return 0; string lines=""; for(int i=0; i<len; i++) if(i<len-1) lines += ToString(i, values) + "\n"; else lines += ToString(i, values); if(m_handle!=INVALID_HANDLE) return(::FileWrite(m_handle, lines)); return 0; }
-
Die Methode Read(void) wird verwendet, um den Inhalt der geöffneten CSV-Datei zu lesen. Sie verwendet die Methode FileReadString der Basisklasse CFile, um den Inhalt der Datei zeilenweise zu lesen und in einem String zu speichern. Gibt eine Zeichenkette zurück, die den Inhalt der Datei enthält.
string CFileCSV::Read(void) { string res=""; if(m_handle!=INVALID_HANDLE) res = FileReadString(m_handle); return res;
Die ToString-Methoden sind private Hilfsmethoden der CFileCSV-Klasse und werden verwendet, um Matrizen oder Arrays in Strings zu konvertieren und diese Werte in eine Datei zu schreiben.
-
Die Methode ToString(const int row, const T &values[][]) wird verwendet, um eine Matrix in eine Zeichenkette umzuwandeln. Als Parameter erhält sie die Zeichenkette der zu konvertierenden Matrix und die Matrix selbst. Die Methode iteriert über jedes Element der Matrixzeile und fügt es der resultierenden Zeichenkette hinzu. Das Trennzeichen wird am Ende jedes Elements hinzugefügt, mit Ausnahme des letzten Elements in der Zeile.
template<typename T> string CFileCSV::ToString(const int row, const T &values[][]) { string res=""; int cols=ArrayRange(values, 1); for(int x=0; x<cols; x++) if(x<cols-1) res+=values[row][x] + ShortToString(m_delimiter); else res+=values[row][x]; return res; }
-
Die Methode ToString(const T &values[]) wandelt ein Array in eine Zeichenkette um. Sie durchläuft jedes Element des Arrays und fügt es der resultierenden Zeichenkette hinzu. Das Trennzeichen wird am Ende jedes Elements hinzugefügt, außer beim letzten Element im Array.
template<typename T> string CFileCSV::ToString(const T &values[]) { string res=""; int len=ArraySize(values); if(len<1) return res; for(int i=0; i<len; i++) if(i<len-1) res+=values[i] + ShortToString(m_delimiter); else res+=values[i]; return res; }
Diese Methoden werden von WriteHeader und Write Line verwendet, um als Parameter übergebene Werte in Zeichenketten umzuwandeln und diese Zeichenketten in die geöffnete Datei zu schreiben. Sie werden verwendet, um sicherzustellen, dass die Werte im erwarteten Format in die Datei geschrieben und durch das angegebene Trennzeichen getrennt werden. Sie sind von grundlegender Bedeutung, um sicherzustellen, dass die Daten korrekt und in geordneter Form in die CSV-Datei geschrieben werden.
Darüber hinaus bieten diese Methoden der Klasse CFileCSV mehr Flexibilität, da sie als Vorlagen implementiert sind und somit verschiedene Arten von Daten verarbeiten können. Das bedeutet, dass diese Methoden auf jede Art von Daten angewendet werden können, die in eine Zeichenkette umgewandelt werden können, einschließlich Ganzzahlen, Gleitkommazahlen, Zeichenketten und andere. Dies macht die Klasse CFileCSV sehr vielseitig und einfach zu verwenden.
Diese Methoden sollen vor allem sicherstellen, dass die Werte im richtigen Format in die Datei geschrieben werden. Sie enthalten ein Trennzeichen am Ende jedes Elements außer dem letzten Element in einer Zeile oder Matrix. Dadurch wird sichergestellt, dass die Werte in der CSV-Datei richtig getrennt sind, was für das spätere Lesen und Interpretieren der in der Datei gespeicherten Daten sehr wichtig ist.
Ein Beispiel für die Verwendung von ToString(const int row, const T &values[][]):
int data[2][3] = {{1, 2, 3}, {4, 5, 6}}; string str = csvFile.ToString(1, data); //str -> "4;5;6"
In diesem Beispiel wird die zweite Zeile der Datenmatrix an die Methode ToString übergeben. Die Methode durchläuft jedes Element in der Zeichenkette, hängt es an die resultierende Zeichenkette an und fügt am Ende jedes Elements außer dem letzten Element der Zeichenkette ein Trennzeichen ein. Die resultierende Zeichenkette lautet „4;5;6“.
Beispiel für die Verwendung von ToString(const T &values[]):
string headers[] = {"Name", "Age", "Gender"}; string str = csvFile.ToString(headers); //str -> "Name;Age;Gender"
In diesem Beispiel wird das Array „headers“ (Kopfzeilen) an die Methode ToString übergeben. Die Methode durchläuft jedes Element des Arrays, hängt es an die resultierende Zeichenkette an und fügt am Ende jedes Elements außer dem letzten Element des Arrays ein Trennzeichen ein. Die resultierende Zeichenkette lautet „Name;Age;Gender“ (Name;Alter;Geschlecht).
Dies sind nur Beispiele für die Verwendung der beiden Versionen der Methode ToString. Sie können auf jeden Datentyp angewendet werden, der in eine Zeichenkette konvertiert werden kann. Bitte beachten Sie jedoch, dass sie nur innerhalb der Klasse CFileCSV verfügbar sind, da sie als privat deklariert sind.
Algorithmische Komplexität
Wie können wir die Komplexität von Algorithmen messen und diese Informationen nutzen, um die Leistung von Algorithmen und Systemen zu optimieren?
Die Big-O-Notation ist ein wichtiges Instrument zur Analyse von Algorithmen, das seit den Anfängen der Informatik bekannt ist. Das Big-O-Konzept wurde in den 1960er Jahren formell definiert, ist aber auch heute noch weit verbreitet. Sie ermöglicht es Programmierern, die Komplexität eines Algorithmus auf der Grundlage seiner Eingaben und der für seine Ausführung erforderlichen Operationen grob abzuschätzen. Mit diesem Werkzeug lassen sich verschiedene Algorithmen vergleichen und diejenigen festlegen, die für bestimmte Aufgaben eine bessere Leistung erbringen.
Die Menge der Daten und die Komplexität der zu lösenden Probleme nehmen exponentiell zu. Aus diesem Grund ist die Notation Big O so wichtig. Da täglich immer mehr Daten erzeugt werden, benötigen wir effizientere Algorithmen zur Verarbeitung dieser Daten.
Das Big-O-Konzept basiert auf der Idee, dass die Ausführungszeit eines Algorithmus entsprechend einer bestimmten mathematischen Funktion, in der Regel einem Polynom, wächst. Diese Funktion wird in der Big-O-Notation ausgedrückt, die als O(f(n)) dargestellt werden kann, wobei f(n) die Komplexität des Algorithmus angibt.
Sehen wir uns nun einige Beispiele für die Verwendung der Big-O-Notation an:
- O(1), beschreibt einen Algorithmus mit konstanter Zeit, d.h. er ändert sich nicht in Abhängigkeit von der Größe der Daten.
- O(n), beschreibt einen Algorithmus mit linearen Zeitalgorithmus, bei dem die Ausführungszeit proportional zur Größe der Daten zunimmt.
- O(n^2), beschreibt einen quadratischen Zeitalgorithmus, bei dem die Ausführungszeit mit dem Quadrat des Datenumfangs wächst.
- O(log n), beschreibt einen Algorithmus mit logarithmischem Zeitaufwand, bei dem die Ausführungszeit als Funktion des Logarithmus der Datengröße wächst.
Big O hilft bei der Entscheidung, welcher Algorithmus für die Lösung Ihres speziellen Problems zu wählen ist, und auch bei der Optimierung der Leistung von Systemen.
Die Zeitkomplexität der einzelnen Methoden der Klasse CFileCSV hängt von der Größe der als Parameter übergebenen Daten ab.
- Die Open-Methode hat die Komplexität von O(1), da sie unabhängig von der Datengröße nur eine Operation zum Öffnen der Datei durchführt.
- Die Lesemethode hat die Komplexität von O(n), wobei n die Größe der Datei ist. Es liest den gesamten Inhalt einer Datei und speichert ihn in einer Zeichenkette.
- Die Methode WriteHeader ist ebenfalls O(n) komplex, wobei n die Größe des als Parameter übergebenen Arrays ist. Es wandelt ein Array in eine Zeichenkette um und schreibt sie in eine Datei.
- Die Methode WriteLine hat die Komplexität von O(mn), wobei m die Anzahl der Zeilen in der Matrix und n die Anzahl der Elemente in jeder Zeile ist. Er durchläuft jede Zeile, wandelt sie in eine Zeichenkette um und schreibt sie in eine Datei.
Bitte beachten Sie, dass es sich bei diesen Komplexitäten um Schätzungen handelt, da sie von weiteren Faktoren beeinflusst werden können, z. B. der Größe des Schreibpuffers der Datei, dem Dateisystem usw. Darüber hinaus schätzt die Big-O-Notation das Worst-Case-Szenario. Wenn zu viele Daten für die Methoden zur Verfügung stehen, kann die Komplexität zunehmen.
Im Allgemeinen hat die Klasse CFileCSV eine akzeptable Zeitkomplexität und ist effizient für die Arbeit mit nicht zu großen Dateien. Wenn Sie jedoch sehr große Dateien verarbeiten müssen, müssen Sie möglicherweise andere Ansätze wählen oder die Klasse für bestimmte Anwendungsfälle optimieren.
Beispiel für die Verwendung
//+------------------------------------------------------------------+ //| exemplo_2.mq5 | //| Copyright 2022, Lethan Corp. | //| https://www.mql5.com/pt/users/14134597 | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, Lethan Corp." #property link "https://www.mql5.com/pt/users/14134597" #property version "1.00" #include "FileCSV.mqh" CFileCSV csvFile; string fileName = "dados.csv"; string headers[] = {"Timestamp", "Close", "Last"}; string data[1][3]; //The OnInit function int OnStart(void) { //Fill the 'data' array with values timestamp, Bid, Ask, Indicador1 and Indicador2 data[0][0] = TimeToString(TimeCurrent()); data[0][1] = DoubleToString(iClose(Symbol(), PERIOD_CURRENT, 0), 2); data[0][2] = DoubleToString(SymbolInfoDouble(Symbol(), SYMBOL_LAST), 2); //Open the CSV file if(csvFile.Open(fileName, FILE_WRITE|FILE_ANSI)) { //Write the header csvFile.WriteHeader(headers); //Write data rows csvFile.WriteLine(data); //Close the file csvFile.Close(); } else { Print("File opening error!"); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+
Dieser Code ist eine Implementierung der Klasse CFileCSV in MQL5. Sie umfasst die folgenden Funktionen:
- Bietet eine Fehlerbehandlung in Situationen, in denen die Datei nicht geöffnet werden kann.
- Ermöglicht das Öffnen einer CSV-Datei mit dem angegebenen Namen und den entsprechenden Schreibberechtigungen.
- Ermöglicht das Schreiben einer Kopfzeile in die Datei, definiert als Array von Strings.
- Ermöglicht das Schreiben von Daten in eine Datei, auch definiert als Array von Strings.
- Schließt die Datei, wenn der Schreibvorgang abgeschlossen ist.
Schlussfolgerung
Die Klasse CFileCSV bietet eine praktische und effiziente Methode für die Arbeit mit CSV-Dateien. Sie enthält Methoden zum Öffnen, Schreiben von Kopfzeilen und Zeichenketten sowie zum Lesen von CSV-Dateien. Die Methoden Open, WriteHeader, WriteLine und Read gewährleisten den korrekten Umgang mit CSV-Dateien und stellen sicher, dass die Daten in einer lesbaren Form geschrieben und organisiert werden. Vielen Dank für Ihre Zeit! Im nächsten Artikel werden wir uns ansehen, wie ML-Modelle durch Dateifreigabe unter Verwendung der in diesem Artikel vorgestellten Klasse CFileCSV verwendet werden können.
Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/12069





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.