Besonderheiten von Expert Advisors
Das Schreiben und Testen von Experten im Handelssystem MetaTrader hat einige Besonderheiten.
Bevor man eine Position eröffnet, muss man überprüfen, ob es verfügbares Geld auf dem Konto gibt. Wenn das Geld nicht ausreichend ist, wird die Aufgabe "Positioneröffnung"misslingen. Dabei muss der "FreeMargin"-Wert beim Testen mindestens 1000 betragen, denn der Preis eines Lots macht beim Testen 1000 aus.
if(AccountFreeMargin() < 1000) return(0); // kein Geld - beenden
Den Zugang zu historischen Daten kann man durch die indizierten und vorgegebenen Arrays Time, Open, Low, High, Close und Volume bekommen. Der Index nimmt in diesen Arrays historisch bedingt vom Ende zum Beginn zu. D.h die letzten Daten haben den Index 0. Der Index 1 bedeutet Daten mit der Verschiebung um eine Periode zurück, der Index 2 - zwei Perioden zurück, 3 - drei Perioden zurück usw.
// wenn Close auf dem vorherigen Balken weniger als // Close auf dem Balken vor diesem Balken ist if(Close[1] < Close[2]) return(0);
Man kann auch den Zugang zu historischen Daten über andere Zeitintervallen sowie andere Währungspaare bekommen. Um diese Daten zu erhalten, muss man zuerst ein eindimensionales Array definieren und anhand der Funktion "ArrayCopySeries" kopieren. Dabei kann man beim Funktionsaufruf weniger Parameter mitteilen und voreingestellte Parameter nicht angeben.
double eur_close_m1[]; int number_copied = ArrayCopySeries(eur_close_m1, MODE_CLOSE, "EURUSD", PERIOD_M1);
Beim Schreiben eines Expert Advisors, wie beim Schreiben jedes beliebigen Programms, muss man manchmal zusätzliche Debug-Informationen ausgeben. Die Programmiersprache MQL4 gibt mehrere Möglichkeiten für die Ausgabe dieser Informationen.
Die Funktion "Alert" öffnet ein Dialogfenster, das die vom Nutzer angegebenen Daten enthält.
Alert("FreeMargin grows to ", AccountFreeMargin(), "!");
Die Funktion "Comment" zeigt die vom Nutzer angegebenen Daten in der linken oberen Ecke des Charts an. Die Reihenfolge der Symbole "\n" wird für den Zeilenvorschub genutzt.
Comment("FreeMargin is ", AccountFreeMargin(), ".");
Die Funktion "Print" listet die vom Nutzer angegebenen Daten im Systemprotokoll auf.
Print("FreeMargin is ", AccountFreeMargin(), ".");
Die Funktion "GetLastError" lässt Informationen über Fehler in Programmen erhalten und ist sehr hilfreich. z.B. Eine Orderoperation liefert immer die Ticketnummer. Beträgt die Ticketnummer 0 (ein Fehler trat auf), ruft man die Funktion "GetLastError" auf, um zusätzliche Informationen zu bekommen:
int iTickNum = 0 int iLastError = 0; ... iTickNum = OrderSend(Symbol(), OP_BUY, g_Lots, Ask, 3, 0, Ask + g_TakeProfit * g_Points); if(iTickNum <= 0) { iLastError = GetLastError(); if(iLastError != ERR_NO_ERROR) Alert("Some Message"); }
Man sollte nicht vergessen, dass der Aufruf der Funktion "GetLastError" den Code des letzten Fehlers anzeigt und seinen Wert auf Null setzt. Deswegen liefert der erneute darauf folgende Aufruf dieser Funktion immer den Wert 0.Wie bestimmt man den Beginn des nächsten Balkens? (Das braucht man, um zu erfahren, dass der vorangehende Balken gerade eben endete.) Dafür gibt es mehrere Möglichkeiten.
Die erste beruht auf der Überprüfung der Balkenanzahl:
static int prevbars = 0; ... if(prevbars == Bars) return(0); prevbars = Bars; ...
Dieses Verfahren kann erfolglos sein, während man die Historie lädt. D.h. die Balkenanzahl hat sich verändert, der vorangehende Balkenist noch nicht vollendet. In diesem Fall kann man die Überprüfung auf den Werteunterschied=1 erweitern.
Das nächste Verfahren basiert darauf, dass sich der Wert "Volume" aufgrund der Tickanzahl für jeden Balken bildet. Der erste Tick bedeutet, dass der Wert "Volume" des bildenden Balkens 1 beträgt:if( Volume[0] > 1) return(0); ...
Wenn sich die Preisticks zu intensiv verändern, kann dieses Verfahren scheitern. Denn es liegt daran, dass die eingehenden Preisticks in einem separaten Thread bearbeitet werden. Wenn dieser Thread besetzt ist, während ein weiterer Tick eingeht, wird dieser Tick nicht bearbeitet, um die Rechnerkapazität nicht zu überfordern! In diesem Fall kann man auch die Überprüfung vertiefen und den gespeicherten vorangehenden Wert "Volume" zu nutzen.
Das dritte Verfahren beruht auf der Eröffnungszeit des Balkens:static datetime prevtime=0; ... if(prevtime == Time[0]) return(0); prevtime = Time[0]; ...
Das ist das zuverlässigste Verfahren. Es funktioniert unter allen Umständen.
Beispiel mit dem Dateityp "CSV":
int h1; h1 = FileOpen("my_data.csv", MODE_CSV | MODE_WRITE, ";"); if(h1 < 0) { Print("Unable to open file my_data.csv"); return(false); } FileWrite(h1, High[1], Low[1], Close[1], Volume[1]); FileClose(h1);
Einige Erläuterungen zum Code. Zuerst die CSV-Datei öffnen. Tritt bei der Öffnung der Datei ein Fehler auf, wird das Programm beendet. Wenn die Datei erfolgreich geöffnet wurde, wird ihr Inhalt gelöscht, Daten werden in die Datei gespeichert und die Datei wird anschließend geschlossen. Wenn man den Inhalt der Datei speichern will, ist der Öffnungsmodus MODE_READ zu nutzen:
int h1; h1 = FileOpen("my_data.csv", MODE_CSV | MODE_WRITE | MODE_READ, ";"); if(h1 < 0) { Print("Unable to open file my_data.csv"); return(false); } FileSeek(h1, 0, SEEK_END); FileWrite(h1, High[1], Low[1], Close[1], Volume[1]); FileClose(h1);
In diesem Fall ist der Satz am Ende der Datei zu finden. Dafür haben wir nach der Eröffnung der Datei die Funktion "FileSeek" genutzt.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/1494
- 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.