Datenkennzeichnung für Zeitreihenanalyse (Teil 1):Erstellen eines Datensatzes mit Trendmarkierungen durch den EA auf einem Chart
Zusammenfassung
Wenn wir Modelle der künstlichen Intelligenz entwerfen, müssen wir zunächst oft Daten aufbereiten. Eine gute Datenqualität ermöglicht es uns, mit der Hälfte des Aufwands für die Modellschulung und -validierung das doppelte Ergebnis zu erzielen. Aber unsere Devisen- oder Aktiendaten sind etwas Besonderes, da sie komplexe Markt- und Zeitinformationen enthalten, und die Kennzeichnung der Daten ist schwierig, aber wir können den Trend in den historischen Daten auf dem Chart leicht analysieren.
In diesem Abschnitt wird eine Methode zur Erstellung von Datensätzen mit Trendmarkierungen auf dem Chart durch den EA vorgestellt, mit der Sie Daten intuitiv nach Ihren eigenen Vorstellungen manipulieren können. Natürlich können Sie die gleiche Methode auch verwenden, um Ihre eigenen Datensätze zu erweitern und anzupassen!
Inhaltsverzeichnis
- Definieren des Formats der gekennzeichneten Daten
- Initialisieren der Charts und der Dateien
- Operationslogik entwerfen und kennzeichnen
- Organisieren der Daten und Speichern in einer Datei
- Anlage: Beispiel eines vollständigen EA-Codes
Definieren des Formats der gekennzeichneten Daten
Wenn wir Devisen- oder Aktiendaten vom Kunden erhalten (in diesem Artikel wird nicht auf externe Daten eingegangen, die aus Dateien gelesen oder von anderen Websites heruntergeladen werden), ist die allgemeine Situation wie folgt:
Zeit | Eröffnungskurs | Hoch | Tief | Schlusskurs | Tick_Volumen |
---|---|---|---|---|---|
2021-12-10 01:15:00 | 1775.94 | 1775.96 | 1775.58 | 1775.58 | 173 |
2021-12-10 01:30:00 | 1775.58 | 1776.11 | 1775.48 | 1775.88 | 210 |
2021-12-10 01:45:00 | 1775.88 | 1776.22 | 1775.68 | 1776.22 | 212 |
2021-12-10 02:00:00 | 1776.22 | 1777.57 | 1775.98 | 1777.02 | 392 |
2021-12-10 02:15:00 | 1776.99 | 1777.72 | 1776.89 | 1777.72 | 264 |
Oben sehen Sie, wie die 5 Zeitreihendaten aussehen. Ihre Eröffnungs- und Schlusskurse sind von Anfang bis Ende miteinander verbunden, und die Kohärenz ist sehr stark. Nehmen wir an, dass es sich bei den ersten beiden um einen Aufwärtstrend und bei den anderen um einen Abwärtstrend handelt (die obigen 5 Daten werden als Beispiel genommen). Bei der allgemeinen Kennzeichnungsmethode werden die Daten in zwei Teile unterteilt:
Zeit | Eröffnungskurs | Hoch | Tief | Schlusskurs | Tick_Volumen |
---|---|---|---|---|---|
2021-12-10 01:15:00 | 1775.94 | 1775.96 | 1775.58 | 1775.58 | 173 |
2021-12-10 01:30:00 | 1775.58 | 1776.11 | 1775.48 | 1775.88 | 210 |
Zeit | Eröffnungskurs | Hoch | Tief | Schlusskurs | Tick_Volumen |
---|---|---|---|---|---|
2021-12-10 01:45:00 | 1775.88 | 1776.22 | 1775.68 | 1776.22 | 212 |
2021-12-10 02:00:00 | 1776.22 | 1777.57 | 1775.98 | 1777.02 | 392 |
2021-12-10 02:15:00 | 1776.99 | 1777.72 | 1776.89 | 1777.72 | 264 |
Dann sagen wir unserem Modell, welcher Teil ein Aufwärtstrend und welcher Teil ein Abwärtstrend ist, aber das ignoriert ihre allgemeinen Attribute und zerstört die Integrität der Daten, wie lösen wir also dieses Problem?
Eine praktikable Methode ist das Hinzufügen einer Trendgruppierung in unseren Zeitreihen wie folgt (nehmen Sie die obigen 5 Daten als Beispiel oder folgen Sie den obigen Annahmen):
Time | Open | High | Low | Close | Tick_volume | Trend_group |
---|---|---|---|---|---|---|
2021-12-10 01:15:00 | 1775.94 | 1775.96 | 1775.58 | 1775.58 | 173 | 0 |
2021-12-10 01:30:00 | 1775.58 | 1776.11 | 1775.48 | 1775.88 | 210 | 0 |
2021-12-10 01:45:00 | 1775.88 | 1776.22 | 1775.68 | 1776.22 | 212 | 1 |
2021-12-10 02:00:00 | 1776.22 | 1777.57 | 1775.98 | 1777.02 | 392 | 1 |
2021-12-10 02:15:00 | 1776.99 | 1777.72 | 1776.89 | 1777.72 | 264 | 1 |
Wenn wir jedoch eine Trendentwicklungsanalyse in das Modell einbauen wollen, z. B. inwieweit sich der aktuelle Trend entwickelt hat (die Wellentheorie besagt beispielsweise, dass ein allgemeiner Trend im Allgemeinen ein Trendstadium und ein Anpassungsstadium umfasst, das Trendstadium hat 5 Wellenstufen und das Anpassungsstadium hat 3 Anpassungswellen usw.), müssen wir die Daten weiter kennzeichnen. Wir können dies tun, indem wir eine weitere Indexspalte hinzufügen, die die Entwicklung des Trends in den Daten wie folgt darstellt (unter der Annahme, dass die ersten 2 der folgenden 10 Daten ein Aufwärtstrend und die letzten 5 ein Aufwärtstrend sind, der Rest in der Mitte ist ein Abwärtstrend):
Time | Open | High | Low | Close | Tick_volume | Trend_group | Trend_index |
---|---|---|---|---|---|---|---|
2021-12-10 03:15:00 | 1776.38 | 1777.94 | 1775.47 | 1777.71 | 565 | 0 | 0 |
2021-12-10 03:30:00 | 1777.75 | 1778.93 | 1777.68 | 1778.61 | 406 | 0 | 1 |
2021-12-10 03:45:00 | 1778.58 | 1778.78 | 1777.65 | 1778.16 | 388 | 1 | 0 |
2021-12-10 04:00:00 | 1778.14 | 1779.42 | 1778.06 | 1779.14 | 393 | 1 | 1 |
2021-12-10 04:15:00 | 1779.16 | 1779.49 | 1778.42 | 1779.31 | 451 | 1 | 2 |
2021-12-10 04:30:00 | 1779.22 | 1779.42 | 1778.36 | 1778.37 | 306 | 0 | 0 |
2021-12-10 04:45:00 | 1778.42 | 1778.51 | 1777.60 | 1777.78 | 411 | 0 | 1 |
2021-12-10 05:00:00 | 1777.81 | 1778.68 | 1777.61 | 1778.57 | 372 | 0 | 2 |
2021-12-10 05:15:00 | 1778.54 | 1779.29 | 1778.42 | 1779.02 | 413 | 0 | 3 |
2021-12-10 05:30:00 | 1778.97 | 1779.49 | 1778.48 | 1778.50 | 278 | 0 | 4 |
Anmerkung:
1. Trend_group, ist bei einem Aufwärtstrend 0.
2. Trend_group, ist bei einem Abwärtstrend 1.
Als Nächstes beginnen wir mit der Manipulation des Charts auf der Client-Seite und kennzeichnen die Daten nach dem von uns gewünschten Muster.
Initialisieren der Charts und der Dateien
Da wir uns das Chart ansehen müssen, um die Daten zu markieren, kann das Chart nicht einfach gescrollt werden, sondern muss entsprechend unserer manuellen Bedienung gescrollt werden. Daher müssen wir CHART_AUTOSCROLL und CHART_SHIFT deaktivieren:
ChartSetInteger (0, CHART_AUTOSCROLL, false); ChartSetInteger (0, CHART_SHIFT, true); ChartSetInteger (0, CHART_MOUSE_SCROLL ,1);Anmerkung: Der grüne Teil des Codes soll es uns ermöglichen, das Chart mit dem Mausrad zu steuern
Bei der Initialisierung der Datei sollte zunächst geprüft werden, ob eine Labeldatei vorhanden ist, und wenn eine historische Datei vorhanden ist, sollte der Dateiname in der Variablen „reName“ gespeichert werden:
do { //---Find if there are files that match the chart if (StringFind(name, Symbol())!=-1 && StringFind(name,".csv")!=-1) reName=name; } while (FileFindNext(hd,name));Anmerkung: Hier ist zu beachten, dass wir eine „do - while“-Schleife verwenden, die sich von einer „while“-Schleife dadurch unterscheidet, dass sie zuerst den Operator ausführt und dann den Ausdruck auswertet Aber die Initialisierung von „name“ ist ein Problem, wir können Folgendes tun
int hd= FileFindFirst("*",name,0);
Wenn es eine markierte Originaldatei gibt, öffnen Sie die Datei und holen Sie den letzten Zeitpunkt der Markierung mit der Funktion read_csv() ab:
read_csv(file_handle,a);Blättern Sie dann im Chart bis zur letzten markierten Zeit:
shift = - iBarShift(Symbol(),PERIOD_CURRENT,(datetime)a[i-8]); ChartNavigate(0, CHART_END ,shift);
Erstellen Sie eine Datei, wenn keine Verlaufsdatei vorhanden ist:
file_handle = FileOpen(StringFormat("%s%d-%d.csv",Symbol(),Period(),start_t), FILE_WRITE | FILE_CSV | FILE_READ);Anschließend wird das Chart an die durch die globale Variable „start_t“ festgelegte Position verschoben.
shift = -iBarShift(Symbol(),PERIOD_CURRENT,(datetime)start_t); ChartNavigate(0,CHART_END,shift);Fügen Sie eine vertikale rote Linie hinzu, um die Anfangsspalte zu markieren:
ObjectCreate (0,"Start",OBJ_VLINE,0,(datetime)start_t,0)Die Logik dieses Teils ist folgendermaßen aufgebaut:
if (FileIsExist(reName)) { file_handle = FileOpen(reName, FILE_WRITE | FILE_CSV | FILE_READ ); string a[]; int i= 0 ; read_csv(file_handle,a); i = ArraySize (a); shift = -iBarShift(Symbol(), PERIOD_CURRENT,(datetime)a[i-8]); ChartNavigate(0,CHART_END,shift); } else { file_handle = FileOpen (StringFormat ("%s%d-%d.csv", Symbol(), Period(),start_t), FILE_WRITE | FILE_CSV | FILE_READ ); Print ("There is no history file,create file:" , StringFormat ( "%s%d-%d",Symbol(), Period(),start_t)); shift = - iBarShift (Symbol(), PERIOD_CURRENT ,(datetime)start_t); ChartNavigate (0, CHART_END ,shift); ObjectCreate (0,"Start", OBJ_VLINE,0,(datetime)start_t,0); }Achtung! Da wir das Chart nach links verschieben wollen, müssen wir ein „-“ vor der Funktion „iBarShift()“ hinzufügen
shift = -iBarShift(Symbol(), PERIOD_CURRENT ,(datetime)start_t);Natürlich kann es auch in der ChartNavigate() Funktion implementiert werden, wie z.B:
ChartNavigate(0,CHART_END,-shift);Der Code in diesem Artikel ist noch nach der ersten Methode implementiert.
int OnInit() { //---initial string name; string reName="1"; int hd=FileFindFirst("*",name,0); int shift; ChartSetInteger(0,CHART_AUTOSCROLL,false); ChartSetInteger(0,CHART_SHIFT,false); ChartSetInteger(0,CHART_MOUSE_SCROLL,1); do { //---check File if(StringFind(name,Symbol())!=-1 && StringFind(name,".csv")!=-1) reName=name; } while(FileFindNext(hd,name)); if(FileIsExist(reName)) { file_handle = FileOpen(reName,FILE_WRITE|FILE_CSV|FILE_READ); string a[]; int i=0; read_csv(file_handle,a); i = ArraySize(a); shift = -iBarShift(Symbol(),PERIOD_CURRENT,(datetime)a[i-8]); ChartNavigate(0,CHART_END,shift); } else { file_handle = FileOpen(StringFormat("%s%d-%d.csv",Symbol(),Period(),start_t),FILE_WRITE|FILE_CSV|FILE_READ); Print(FileTell(file_handle)); Print("No history file,create file:",StringFormat("%s%d-%d",Symbol(),Period(),start_t)); shift = -iBarShift(Symbol(),PERIOD_CURRENT,(datetime)start_t); ChartNavigate(0,CHART_END,shift); ObjectCreate(0,"Start",OBJ_VLINE,0,(datetime)start_t,0); } return(INIT_SUCCEEDED); }
Anmerkung:
1. start_t-Variable - Angabe des zu startenden Zeitrahmens;
2. die Variable shift - es ist die Angabe der Anzahl der zu verschiebenden Spalten, und das Code-Beispiel zeigt die Anzahl der zu verschiebenden Spalten durch Konvertierung der angegebenen Zeit;
3. Die Funktion read_csv() wird später definiert.
void read_csv(int hd, string &arry[]) { int i= 0; while(!FileIsEnding(hd)) { ArrayResize(arry,i+1); arry[i]= FileReadString(hd); i++; } }
Anmerkung: Wir verwenden die „while“-Schleife, um die Endzeile der historischen Datei mit den Anmerkungen zu finden, die letzte Datenzeile in der Datei zu erhalten und die Endzeit unserer letzten Anmerkung zu ermitteln. Mit dieser Anmerkung wird das Chart zu diesem SäulenChart verschoben, sodass wir von hier aus mit den Anmerkungen fortfahren können.
Operationslogik entwerfen und kennzeichnen
- Home — geht zum letzten Balken des Charts;
- End — geht zum ersten Balken des Charts;
- Seite nach oben — verschiebt das Chart um ein Fenster nach hinten;
- Seite nach unten — verschiebt das Chart um ein Fenster nach vorne;
- Ctrl+I — öffnet ein Fenster mit einer Liste von Indikatoren;
- Ctrl+B — öffnet ein Fenster mit einer Liste von Objekten;
- Alt+1 — Das Chart wird als eine Reihe von Balken angezeigt;
- Alt+2 — das Chart wird als eine Folge von japanischen Leuchtern angezeigt;
- Alt+3 — das Chart wird als Linie dargestellt, die die Schlusskurse verbindet;
- Strg+G — zeigt/versteckt das Gitter im Chartfenster;
- "+" — vergrößert das Chart;
- "-" — Zoom der Karte;
- F12 — Chart Schritt für Schritt scrollen;
- F8 — Chart-Eigenschaften öffnen;
- Backspace — entfernt das zuletzt hinzugefügte Objekt aus dem Chart;
- Entf — alle ausgewählten Objekte löschen;
- Ctrl+Z — Löscht das letzte Objekt zurück.
#define KEY_B 66 #define KEY_S 83
2) Drücken Sie „s“, um das Ende des Aufwärtstrends zu markieren, die Variable „typ“ ist immer noch 0, die Variable „tp“ ist auf „end“ gesetzt, die Pfeilfarbe ist immer noch „clrBlue“, und die Anzahl der Label „Num“ bleibt unverändert. Es ist zu beachten, dass wir nur die Variable am Anfang des Datensegments inkrementieren müssen, und die Umkehrung von first wird verwendet, um festzulegen, dass das erneute Drücken der Taste den „Start“-Teil des markierten Datensegments ausführt.
3) Rufen Sie nach der Ausführung der Switch-Anweisung die Funktion ChartRedraw() auf, um das Chart neu zu zeichnen.
if(id==CHARTEVENT_KEYDOWN) { switch(lparam) { case KEY_B: if(first) { col=clrBlue ; typ =0; Num+=1; tp = "start"; } else { col=clrRed ; typ = 1; tp = "end"; } ob =OBJ_ARROW_BUY; first = !first; Name = StringFormat("%d-%d-%s",typ,Num,tp); break; case KEY_S: if(first) { col=clrRed ; typ =1; Num+=1; tp = "start"; } else { col=clrBlue ; typ = 0; tp = "end"; } ob =OBJ_ARROW_SELL; first = !first; Name = StringFormat("%d-%d-%s",typ,Num,tp); break; default: Print("You pressed:"+lparam+" key, do nothing!"); } ChartRedraw(0); }
Anmerkung:
1. die Variable „typ“ - 0 bedeutet einen Aufwärtstrend, 1 bedeutet einen Abwärtstrend;
2. Die Variable „Num“ - die Anzahl der Markierungen - wird intuitiv auf dem Chart angezeigt;
3. die Variable „first“ steuert, dass unsere Beschriftungen immer paarweise sind, um sicherzustellen, dass jede Gruppe „b“ und „s“ oder „s“ und „b“ ohne Verwechslung ist;
4. die Variable „tp“, mit der der Anfang oder das Ende des Datensegments bestimmt wird.
2. Klicken Sie mit der linken Maustaste auf das Chart, um die Position der Markierung zu bestimmen
if(id==CHARTEVENT_CLICK) { //--- definition int x=(int)lparam; int y=(int)dparam; datetime dt =0; double price =0; int window=0; if(ChartXYToTimePrice(0,x,y,window,dt,price)) { ObjectCreate(0,Name,ob,window,dt,price); ObjectSetInteger(0,Name,OBJPROP_COLOR,col); //Print("time:",dt,"shift:",iBarShift(Symbol(),PERIOD_CURRENT,dt)); if(tp=="start") Start=dt; else { if(file_handle) file_write(Start,dt); } ChartRedraw(0); } else Print("ChartXYToTimePrice return error code: ",GetLastError()); } //--- object delete if(id==CHARTEVENT_OBJECT_DELETE) { Print("The object with name ",sparam," has been deleted"); } //--- object create if(id==CHARTEVENT_OBJECT_CREATE) { Print("The object with name ",sparam," has been created!"); }
Anmerkung:
1. Die Funktion ChartXYToTimePrice() wird hauptsächlich verwendet, um die Eigenschaften des Säulen-Charts unserer Mausklickposition zu erhalten, einschließlich der aktuellen Zeit und des Preises. Wir verwenden die globale Variable "dt", um die aktuelle Zeit zu erhalten;
2. Wenn wir mit der Maus klicken, müssen wir auch beurteilen, ob die aktuelle Aktion der Anfang oder das Ende des Datensegments ist. Wir verwenden die globale Variable „tp“ zur Beurteilung.
3. Spezifischer Betriebsprozess
Wenn Sie einen Aufwärtstrend markieren möchten, drücken Sie zunächst die Taste „b“, klicken Sie mit der linken Maustaste auf die Spalte, die im Chart markiert werden soll, drücken Sie dann die Taste „s“ und klicken Sie anschließend mit der linken Maustaste auf das Ende der Spalte auf dem Symbol, um die Beschriftung abzuschließen. Im Chart erscheinen Paare von blauen Pfeilen, wie in der Abbildung unten dargestellt:
Wenn Sie einen Abwärtstrend markieren möchten, drücken Sie zunächst die Taste „s“, klicken Sie mit der linken Maustaste auf die Spalte, die im Chart markiert werden soll, drücken Sie dann die Taste „b“ und klicken Sie anschließend mit der linken Maustaste auf das Ende der Spalte im Chart. Nachdem die Markierung abgeschlossen ist, werden zwei rote Pfeile angezeigt, wie in der folgenden Abbildung dargestellt:
In der Ausgabespalte für die Kennzeichnungen wird der Vorgang des Kennzeichens jederzeit angezeigt, was sehr intuitiv ist, um den Vorgang des Kennzeichens zu überwachen, wie in der Abbildung dargestellt:
Hinweis: Dieser Teil könnte eigentlich besser optimiert werden, z.B. durch Hinzufügen der Funktion, die letzte Aktion rückgängig zu machen, dann kann man die Position der Markierung jederzeit anpassen, und man kann auch falsche Operationen vermeiden, aber ich bin ein fauler Typ, also... (^o^)
Organisieren der Daten und Speichern in einer Datei
datetime Start; MqlRates rates[]; ArraySetAsSeries(rates, false);
if(id==CHARTEVENT_CLICK) { //--- definition int x=(int)lparam; int y=(int)dparam; datetime dt =0; double price =0; int window=0; if(ChartXYToTimePrice(0,x,y,window,dt,price)) { ObjectCreate(0,Name,ob,window,dt,price); ObjectSetInteger(0,Name,OBJPROP_COLOR,col); //Print("time:",dt,"shift:",iBarShift(Symbol(),PERIOD_CURRENT,dt)); if(tp=="start") Start=dt; else { if(file_handle) file_write(Start,dt); } ChartRedraw(0); } else Print("ChartXYToTimePrice return error code: ",GetLastError()); }
void file_write(datetime start, datetime end) { MqlRates rates[]; ArraySetAsSeries(rates,false); int n_cp=CopyRates(Symbol(),PERIOD_CURRENT,start,end,rates); if(n_cp>0) { if(FileTell(file_handle)==2) { FileWrite(file_handle,"time","open","high","low","close","tick_volume","trend_group","trend_index"); for(int i=0; i<n_cp; i++) { FileWrite(file_handle, rates[i].time, rates[i].open, rates[i].high, rates[i].low, rates[i].close, rates[i].tick_volume, typ, i); } } else { for(int i=0; i<n_cp; i++) { FileWrite(file_handle, rates[i].time, rates[i].open, rates[i].high, rates[i].low, rates[i].close, rates[i].tick_volume, typ, i); } } } else Print("No data copied!"); FileFlush(file_handle); typ=3; }
Anmerkung:
1. Wir müssen unseren Index-Header schreiben, wenn wir die Datei zum ersten Mal schreiben;
2. Trend_group ist eigentlich die globale Variable „typ“;
3. Wir haben die Funktion FileClose() in dieser Funktion nicht aufgerufen, da unsere Kennzeichnungen noch nicht abgeschlossen ist. Wir werden diese Funktion in der Funktion OnDeinit() aufrufen, um das Endergebnis in die Datei zu schreiben.
4. Besondere Aufmerksamkeit sollte dem gelben Teil des Codes gewidmet werden, der hier verwendet wird
if(FileTell(file_handle)==2)Um festzustellen, ob Daten in der Datei vorhanden sind (natürlich können auch andere Methoden verwendet werden, z. B. das Hinzufügen einer Variablen, um ihr während der Initialisierung einen Wert zuzuweisen), müssen wir, wenn keine Daten in der Datei vorhanden sind, eine Kopfzeile wie diese hinzufügen:
FileWrite(file_handle,"time","open","high","low","close","tick_volume","trend_group","trend_index");Wenn die Datei Daten enthält, darf keine Kopfzeile hinzugefügt werden, da sonst die Daten abgeschnitten werden. Das ist sehr wichtig.
Überprüfen wir die Kohärenz zwischen verschiedenen Datensegmenten und stellen wir fest, dass die Daten perfekt sind:
Anlage: Beispiel eines vollständigen EA-Codes
1. Die Definition von globalen Variablen und Konstanten. Der Parameter „start_t“ kann durch die Daten pro Sekunde ab 01.01.1970 definiert werden. Natürlich kann er auch durch den Standard „datetime“" definiert werden, oder er kann durch die Eingabevariable „input int start_t=1403037112;“ definiert werden, sodass er zu jeder Zeit geändert werden kann, wenn der EA später läuft:#define KEY_B 66 #define KEY_S 83 int Num= 0; int typ= 3; string Name; string tp; color col; bool first= true; ENUM_OBJECT ob; int file_handle=0; int start_t=1403037112; datetime Start;
Anmerkung: Natürlich können Sie die Schaltfläche auch als Eingabevariable nach Ihren persönlichen Vorlieben definieren.
input int KEY_B=66; input int KEY_S=83;
Das hat den Vorteil, dass Sie die Schaltflächen bei jeder Ausführung des EA nach Belieben ändern können, bis Sie zufrieden sind, und dass unser Code vorübergehend nicht geändert wird, wenn Sie der Meinung sind, dass die Schaltflächen nicht einfach zu bedienen sind.
2. OnInit()-Funktion, mit der wir unsere Vorbereitungen initialisieren:
int OnInit() { //---initial string name; string reName="1"; int hd=FileFindFirst("*",name,0); int shift; ChartSetInteger(0,CHART_AUTOSCROLL,false); ChartSetInteger(0,CHART_SHIFT,false); ChartSetInteger(0,CHART_MOUSE_SCROLL,1); do { //---check File if(StringFind(name,Symbol())!=-1 && StringFind(name,".csv")!=-1) reName=name; } while(FileFindNext(hd,name)); if(FileIsExist(reName)) { file_handle = FileOpen(reName,FILE_WRITE|FILE_CSV|FILE_READ); string a[]; int i=0; read_csv(file_handle,a); i = ArraySize(a); shift = -iBarShift(Symbol(),PERIOD_CURRENT,(datetime)a[i-8]); ChartNavigate(0,CHART_END,shift); } else { file_handle = FileOpen(StringFormat("%s%d-%d.csv",Symbol(),Period(),start_t),FILE_WRITE|FILE_CSV|FILE_READ); Print(FileTell(file_handle)); Print("No history file,create file:",StringFormat("%s%d-%d",Symbol(),Period(),start_t)); shift = -iBarShift(Symbol(),PERIOD_CURRENT,(datetime)start_t); ChartNavigate(0,CHART_END,shift); ObjectCreate(0,"Start",OBJ_VLINE,0,(datetime)start_t,0); } //--- Print("EA:",MQL5InfoString(MQL5_PROGRAM_NAME),"Working!"); //--- ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_CREATE,true); //--- ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_DELETE,true); //--- ChartRedraw(0); //--- return(INIT_SUCCEEDED); }
3. Da alle unsere Tastatur- und Mausoperationen auf dem Chart beendet sind, setzen wir die wichtigsten logischen Funktionen in die Funktion OnChartEvent(), um das zu erreichen:
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //Comment(__FUNCTION__,": id=",id," lparam=",lparam," dparam=",dparam," sparam=",sparam); if(id==CHARTEVENT_KEYDOWN) { switch(lparam) { case KEY_B: if(first) { col=clrBlue ; typ =0; Num+=1; tp = "start"; } else { col=clrRed ; typ = 1; tp = "end"; } ob =OBJ_ARROW_BUY; first = !first; Name = StringFormat("%d-%d-%s",typ,Num,tp); break; case KEY_S: if(first) { col=clrRed ; typ =1; Num+=1; tp = "start"; } else { col=clrBlue ; typ = 0; tp = "end"; } ob =OBJ_ARROW_SELL; first = !first; Name = StringFormat("%d-%d-%s",typ,Num,tp); break; default: Print("You pressed:"+lparam+" key, do nothing!"); } ChartRedraw(0); } //--- if(id==CHARTEVENT_CLICK&&(typ!=3)) { //--- definition int x=(int)lparam; int y=(int)dparam; datetime dt =0; double price =0; int window=0; if(ChartXYToTimePrice(0,x,y,window,dt,price)) { ObjectCreate(0,Name,ob,window,dt,price); ObjectSetInteger(0,Name,OBJPROP_COLOR,col); //Print("time:",dt,"shift:",iBarShift(Symbol(),PERIOD_CURRENT,dt)); if(tp=="start") Start=dt; else { if(file_handle) file_write(Start,dt); } ChartRedraw(0); } else Print("ChartXYToTimePrice return error code: ",GetLastError()); } //--- object delete if(id==CHARTEVENT_OBJECT_DELETE) { Print("The object with name ",sparam," has been deleted"); } //--- object create if(id==CHARTEVENT_OBJECT_CREATE) { Print("The object with name ",sparam," has been created!"); } }
Anmerkung: Bei der Implementierung dieser Funktion haben wir den obigen Code geändert
if (id==CHARTEVENT_CLICK&&(typ!=3))
Der Grund dafür ist ganz einfach: Wir vermeiden falsche Operationen, die durch versehentliche Mausklicks verursacht werden, und verwenden die Variable „typ“, um zu kontrollieren, ob die Mausaktion gültig ist. Wenn wir einen Trend markieren, führen wir die Funktion file_write() aus. Wir fügen diese Zeile am Ende der Funktion ein
typ=3;
Dann können Sie mit der Maus auf dem Chart arbeiten, bevor Sie den nächsten Abschnitt der Markierung beginnen, ohne etwas zu tun, bis Sie eine geeignete Position finden und bereit sind, den nächsten Trend zu markieren.
4. Implementierung der Funktion zum Schreiben von Daten - file_write():
void file_write(datetime start, datetime end) { MqlRates rates[]; ArraySetAsSeries(rates,false); int n_cp=CopyRates(Symbol(),PERIOD_CURRENT,start,end,rates); if(n_cp>0) { if(FileTell(file_handle)==2) { FileWrite(file_handle,"time","open","high","low","close","tick_volume","trend_group","trend_index"); for(int i=0; i<n_cp; i++) { FileWrite(file_handle, rates[i].time, rates[i].open, rates[i].high, rates[i].low, rates[i].close, rates[i].tick_volume, typ, i); } } else { for(int i=0; i<n_cp; i++) { FileWrite(file_handle, rates[i].time, rates[i].open, rates[i].high, rates[i].low, rates[i].close, rates[i].tick_volume, typ, i); } } } else Print("No data copied!"); FileFlush(file_handle); typ=3; }
5. Implementierung der Funktion zum Lesen von Dateien - read_csv():
void read_csv(int hd, string &arry[]) { int i=0; while(!FileIsEnding(hd)) { ArrayResize(arry,i+1); arry[i]=FileReadString(hd); i++; } }
6. Es gibt noch ein wichtiges Problem, das hier nicht behandelt wurde: Das Dateihandle „file_handle“, das bei der Initialisierung des EA geöffnet wurde, wird nicht freigegeben. Wir geben den Handle in der abschließenden Funktion OnDeinit() frei. Wenn Sie die Funktion „FileClose(file_handle)“ aufrufen, werden alle Daten tatsächlich in die csv-Datei geschrieben. Daher ist es besonders wichtig, dass Sie nicht versuchen, die csv-Datei zu öffnen, während der EA noch läuft:
void OnDeinit(const int reason) { FileClose(file_handle); Print("Write data!"); }
Anmerkung: Der in diesem Artikel gezeigte Code dient nur zur Demonstration. Wenn Sie es in der Praxis verwenden wollen, sollten Sie den Code weiter verbessern. Am Ende des Artikels werden die CSV-Datei und die endgültige MQL5-Datei für die Demonstration zur Verfügung gestellt. Der nächste Artikel in dieser Reihe wird zeigen, wie man Daten über den Client in Verbindung mit Python annotiert.
Ich danke Ihnen für Ihre Geduld beim Lesen, ich hoffe, Sie haben etwas davon und wünsche Ihnen ein glückliches Leben, und wir sehen uns im nächsten Kapitel!
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/13225
- 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.