English Русский
preview
Einführung in MQL5 (Teil 31): Beherrschung der API- und WebRequest-Funktion in MQL5 (V)

Einführung in MQL5 (Teil 31): Beherrschung der API- und WebRequest-Funktion in MQL5 (V)

MetaTrader 5Integration |
36 0
ALGOYIN LTD
Israel Pelumi Abioye

Einführung

Willkommen zurück zu Teil 31 der Serie „Einführung in MQL5“ In den vorherigen Artikeln haben wir die Grundlagen der API und der WebRequest-Funktion in MQL5 behandelt. Ich habe Ihnen gezeigt, wie man eine Anfrage an einen Server sendet, eine Antwort erhält und die Serverantwort analysiert, um wichtige Informationen zu erhalten. Im vorherigen Artikel haben wir die Kerzendaten der letzten fünf Tageskerzen von BTCUSDT über die Binance-API abgerufen. Wir haben auch besprochen, wie man zusammenhängende Daten in separate Arrays klassifiziert, z. B. Eröffnungs-, Höchst-, Tiefst- und Schlusskurse. Mit diesen organisierten Daten können Sie sowohl Expert Advisors als auch Indikatoren erstellen.

In diesem Artikel gehen wir noch einen Schritt weiter und arbeiten an einem komplexeren Projekt. Nachdem wir die Antwort des Servers analysiert haben, extrahieren wir die entscheidenden Kerzendaten aus den letzten zehn 30-Minuten-Kerzen von BTCUSDT. Aber es geht nicht nur darum, die Daten abzurufen. In diesem Artikel wird die Grundlage dafür gelegt, wie man einen Indikator erstellt, der die Daten im Kerzenformat visualisiert. Wir werden zunächst die Kerzeninformationen sammeln, sortieren und in einer Datei speichern, bevor wir einen nutzerdefinierten Indikator erstellen, der diese Datei liest und die gespeicherten Kerzendetails verwendet, um die Kerzen sofort im Chart anzuzeigen, da Indikatoren die WebRequest-Funktion nicht direkt in Echtzeit verwenden können. Mit dieser Methode können wir die API-Daten im MetaTrader 5 als echtes Chart sehen.

 

Abrufen der Kerzendaten vom API

Um Kerzendaten für unser Projekt zu erhalten, müssen wir zunächst eine GET-Anfrage an die Binance-API senden. Wir möchten die Eröffnungs-, Höchst-, Tiefst- und Schlusskurse wie im vorherigen Artikel erhalten. Dieses Mal konzentrieren wir uns jedoch auf die letzten zehn 30-Minuten-Kerzen des BTCUSDT. Wir werden die Ereignisbehandlung von OnTick von MQL5 verwenden, um die Effizienz unserer Software zu verbessern. Dadurch wird unser Code jedes Mal ausgeführt, wenn ein neuer Tick empfangen wird. Da dies jedoch überflüssig wäre und die API-Grenzen überschreiten könnte, wollen wir die API-Anfrage nicht bei jedem Tick übermitteln. Vielmehr werden wir die Anfrage nur einmal für jede neue 30-Minuten-Kerze, die sich auf dem MetaTrader 5 bildet, übermitteln.

Beispiel:

string method = "GET";
string url = "https://api.binance.com/api/v3/klines?symbol=BTCUSDT&interval=30m&limit=10";
string headers = "";
int time_out = 5000;
char   data[];
char   result[];
string result_headers;

datetime last_bar_time = 0;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   datetime current_m30_time = iTime(_Symbol,PERIOD_M30,0);

   if(current_m30_time != last_bar_time)
     {

      WebRequest(method, url, headers, time_out, data, result, result_headers);
      string server_result = CharArrayToString(result);

      Print(server_result);

      last_bar_time =  current_m30_time;

     }

  }

Ausgabe:

Abbildung 1. Server-Antwort

Erläuterung:

Um unsere Daten und die Serverantwort zu speichern, geben wir zunächst die Methode, die URL, die Headers, das Timeout und die Variablen an. Wir möchten die Binance-API um Informationen bitten; daher ist die Methode auf „GET“ eingestellt. Der Endpunkt für den Abruf von Kerzendaten für BTCUSDT wird durch die URL angegeben; das Intervall wird auf 30 Minuten festgelegt und ist auf die letzten zehn Kerzen beschränkt. Da Binance keine zusätzlichen Header für diese öffentliche Anfrage benötigt, sind die Header leer.  Die Anfrage wartet auf eine Antwort des Servers bis zum Timeout von fünf Sekunden. Die zu übertragenden Daten, die Antwort des Servers und alle zurückgegebenen Header werden in Variablen gespeichert. Außerdem wird eine Variable zur Überwachung des Zeitpunkts der letzten 30-Minuten-Kerze verwendet.

Eine Initialisierungsfunktion bereitet das Programm vor, wenn der Expert Advisor gestartet wird. In dieser Phase wird sichergestellt, dass der Experte korrekt startet und auf die Verarbeitung der eingehenden Daten vorbereitet ist, obwohl in diesem Fall keine zusätzliche Vorbereitung erforderlich ist. In ähnlicher Weise wird eine Deinitialisierungsfunktion ausgeführt, wenn der Experte ausgeschaltet oder das Chart geschlossen wird. Obwohl er hier leer ist, wird er zur Verfügung gestellt, damit eine eventuelle spätere Säuberung vorgenommen werden kann.

Jedes Mal, wenn ein neuer Preis-Tick erscheint, findet die primäre Logik statt. Zunächst ermittelt der EA die aktuelle 30-Minuten-Kerzeneröffnung auf dem Chart. Um festzustellen, ob eine neue Kerze begonnen hat, vergleicht er diese Zeit mit der zuvor notierten Kerzenzeit. Der EA fordert die neuesten Kerzendaten von der Binance-API an, wenn es sich um eine neue Kerze handelt. Anschließend wird die Antwort des Servers in ein lesbares Format umgewandelt und überprüft.

Der EA passt die aufgezeichnete Kerzenzeit an die aktuelle an, nachdem die Daten abgerufen wurden. Sie garantiert, dass die Anfrage nicht bei jedem Tick, sondern nur einmal bei jeder neuen 30-Minuten-Kerze gesendet wird. Diese Methode erhöht die Effizienz des Expert Advisors, da er die neuesten Kerzendaten nur bei Bedarf abrufen kann. Dies ist ideal, um einen Indikator oder EA zu entwickeln, der von externen API-Daten abhängt, ohne unnötige wiederholte Abfragen zu machen.

Analogie:

Stellen Sie sich die Binance-API als eine riesige Sammlung von Büchern vor. Die jüngsten Kerzen, die jeweils eine Momentaufnahme der Marktpreise darstellen, werden in jedem Buch beschrieben. Unser Ziel ist es, genau die Bücher zu erhalten, die wir benötigen. In diesem Fall sind es die letzten zehn 30-Minuten-Kerzen für BTCUSDT. Wir ordnen die Daten so an, dass wir sie zu einem späteren Zeitpunkt verwenden können. Unser „Antrag“ an die Bibliothek wird zunächst vorbereitet. So ähnlich ist es, wenn man der Bibliothek die gewünschten Bücher zusammen mit dem Symbol (BTCUSDT), dem Intervall (30 Minuten) und der Anzahl der Bände (10) mitteilt. Ähnlich wie bei der Einstellung eines Zeitlimits für unsere Anfrage wählen wir auch, wie lange wir bereit sind zu warten, bis die Bibliothek die Bücher gefunden hat.

Es ist, als würde man in die Bibliothek gehen und sich Notizen machen, wenn die EA beginnt. Bevor wir mit der Abholung der Bücher beginnen, gibt es einen Vorbereitungsprozess, um sicherzustellen, dass alles in Ordnung ist. Auch wenn es dieses Mal nichts Besonderes zu tun gibt, könnten wir beim Verlassen der Bibliothek unseren Schreibtisch aufräumen oder die Medien zurückgeben. Stellen Sie sich nun den Markt als eine sich ständig verändernde Uhr vor. Jeder Tick ist wie ein Bibliothekar, der uns eine neue Seite des Wissens gibt. Wir möchten vermeiden, dass immer dieselben Bücher angefordert werden. Vielmehr schauen wir auf die Uhr, um zu sehen, ob ein neuer Halbstundenabschnitt begonnen hat. Wenn ja, bitten wir den Bibliothekar, uns die neuesten Titel zur Verfügung zu stellen. Nachdem wir die Bücher aus der Bibliothek erhalten haben, notieren wir uns alle relevanten Informationen in einem Notizblock für die spätere Verwendung.

Sobald die Daten erfasst sind, vermerken wir auf einem Klebezettel, wann wir die Bücher zuletzt aus dem Regal geholt haben. Damit ist gewährleistet, dass wir bis zum Beginn des nächsten dreißigminütigen Abschnitts nicht noch einmal dieselben Bücher anfordern werden.

 

Sortieren von Kerzendaten für jede Kerze

Der nächste Schritt besteht darin, die Antwort des Servers in verschiedene Kerzen für jeden 30-Minuten-Balken zu unterteilen. Die Eröffnungs-, Höchst-, Tiefst- und Schlusskurse der ersten Kerze werden kombiniert. Das gleiche Verfahren wird für die übrigen Kerzen durchgeführt, um zu gewährleisten, dass für jeden 30-Minuten-Balken eine eigene systematische Datenerfassung erfolgt. Im letzten Beitrag habe ich darauf hingewiesen, dass Sie zunächst das JSON-Format verstehen müssen. Jetzt, wo wir wissen, wie Binance es macht, können wir die Kerzendaten richtig anordnen. Die Kerzendaten werden von Binance als Array von Arrays zurückgegeben, etwa so:

[
[array 1],
[array 2],
[array 3],
[array 4],
[array 5],
[array 6],
[array 7],
[array 8],
[array 9],
[array 10]
]

Eine einzelne 30-Minuten-Kerze mit all ihren Informationen wird durch jedes innere Array dargestellt. Die Sortierung dieser Serverantwort in einzelne Kerzen ist der nächste Schritt. Alle Informationen für die erste Kerze werden zusammengefasst, gefolgt von der zweiten und so weiter bis zur letzten Kerze. Das Format macht deutlich, dass das beste Zeichen für die Unterteilung der einzelnen Kerzendatensätze das Zeichen in der eckigen Klammer ist, das das Feld abschließt. Wir können keine Kommas verwenden, da sie Teil der Kerzendaten selbst sind, was zu Fehlern führen und die Zahlen durcheinanderbringen würde.

Daher ist die Verwendung der schließenden Klammer die sicherste Vorgehensweise. Der nächste Schritt besteht darin, jede Kerze einzeln zu behandeln, nachdem die Server-Antwort in verschiedene Abschnitte für jede Kerze unterteilt wurde. Sowohl die beginnende eckige Klammer als auch fremde Zeichen wie doppelte Anführungszeichen werden entfernt. Jede Kerze wird sauberer und einfacher in präzise Werte umgewandelt, die wir in unseren Arrays speichern können, indem wir diese Bereinigung durchführen.

Beispiel:
string candle_data[];
string first_bar_data;
string first_bar_data_array[];
string second_bar_data;
string second_bar_data_array[];
string third_bar_data;
string third_bar_data_array[];
string forth_bar_data;
string fourth_bar_data_array[];
string fifth_bar_data;
string fifth_bar_data_array[];
string sixth_bar_data;
string sixth_bar_data_array[];
string senventh_bar_data;
string seventh_bar_data_array[];
string eighth_bar_data;
string eighth_bar_data_array[];
string nineth_bar_data;
string nineth_bar_data_array[];
string tenth_bar_data;
string tenth_bar_data_array[];
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   datetime current_m30_time = iTime(_Symbol,PERIOD_M30,0);

   if(current_m30_time != last_bar_time)
     {

      WebRequest(method, url, headers, time_out, data, result, result_headers);
      server_result = CharArrayToString(result);

      Print(server_result);

      last_bar_time =  current_m30_time;


      int array_count = StringSplit(server_result,']', candle_data);

      //FIRST CANDLE
      first_bar_data = candle_data[0];
      StringReplace(first_bar_data,"[[","");
      StringReplace(first_bar_data,"\"","");

      StringSplit(first_bar_data,',',first_bar_data_array);

      //SECOND CANDLE
      second_bar_data = candle_data[1];
      StringReplace(second_bar_data,",[","");
      StringReplace(second_bar_data,"\"","");

      StringSplit(second_bar_data,',',second_bar_data_array);

      //THIRD CANDLE
      third_bar_data = candle_data[2];
      StringReplace(third_bar_data,",[","");
      StringReplace(third_bar_data,"\"","");

      StringSplit(third_bar_data,',',third_bar_data_array);

      //FORTH CANDLE
      forth_bar_data = candle_data[3];
      StringReplace(forth_bar_data,",[","");
      StringReplace(forth_bar_data,"\"","");

      StringSplit(forth_bar_data,',',fourth_bar_data_array);

      //FIFTH CANDLE
      fifth_bar_data = candle_data[4];
      StringReplace(fifth_bar_data,",[","");
      StringReplace(fifth_bar_data,"\"","");

      StringSplit(fifth_bar_data,',',fifth_bar_data_array);

      //SIXTH CANDLE
      sixth_bar_data = candle_data[5];
      StringReplace(sixth_bar_data,",[","");
      StringReplace(sixth_bar_data,"\"","");

      StringSplit(sixth_bar_data,',',sixth_bar_data_array);

      //SEVENTH CANDLE
      senventh_bar_data = candle_data[6];
      StringReplace(senventh_bar_data,",[","");
      StringReplace(senventh_bar_data,"\"","");

      StringSplit(senventh_bar_data,',',seventh_bar_data_array);

      //EIGHTH CANDLE
      eighth_bar_data = candle_data[7];
      StringReplace(eighth_bar_data,",[","");
      StringReplace(eighth_bar_data,"\"","");

      StringSplit(eighth_bar_data,',',eighth_bar_data_array);

      //NINETH CANDLE
      nineth_bar_data = candle_data[8];
      StringReplace(nineth_bar_data,",[","");
      StringReplace(nineth_bar_data,"\"","");

      StringSplit(nineth_bar_data,',',nineth_bar_data_array);

      //TENTH CANDLE
      tenth_bar_data = candle_data[9];
      StringReplace(tenth_bar_data,",[","");
      StringReplace(tenth_bar_data,"\"","");

      StringSplit(tenth_bar_data,',',tenth_bar_data_array);

     }
  }

Erläuterung:

Wir beginnen damit, dass wir einfach das akzeptieren, was uns der Server zur Verfügung stellt, häufig eine einzige große Textdatei mit allen Kerzendaten. Wir müssen zunächst die Grenzen zwischen den einzelnen Kerzen ermitteln, um sie zu verstehen. Wir verwenden ein Trennwerkzeug, um diesen langen Textblock zu unterteilen, wenn wir eine schließende eckige Klammer sehen, die als Trennzeichen dient. Auf diese Weise erhalten wir sofort eine übersichtliche Liste (ein Array) mit allen Rohdaten für eine einzelne Kerze, die durch jedes Element definiert ist. Wir konzentrieren uns jetzt auf die erste Kerze in unserer aktualisierten Liste. Die Rohdaten enthalten noch einige überflüssige Zeichen, wie Anführungszeichen und öffnende eckige Klammern, die von der Formatierung des Servers herrühren. Wir nehmen also die Daten dieser ersten Kerze und entfernen alle überflüssigen Zeichen. Danach haben wir eine Zeichenkette, die einwandfrei verständlich ist und nur die entscheidenden Zahlen enthält.

Um die tatsächlichen Preispunkte zu unterscheiden, müssen wir eine solche klare Terminologie verwenden. Noch einmal wird der Text geteilt, aber dieses Mal wird ein Komma verwendet, das von entscheidender Bedeutung ist, weil es die Daten der Kerzen voneinander trennt. Jeder Eintrag in der daraus resultierenden kurzen, gebrauchsfertigen Liste ist genau einer dieser Werte. Wir wiederholten den gleichen Vorgang für die übrigen Kerzen. Bei jeder Kerze werden unerwünschte Anführungszeichen und Klammern entfernt, bevor die verbleibenden Daten durch Kommata getrennt werden. Wenn wir fertig sind, haben wir erfolgreich zehn einzigartige, organisierte Listen erstellt. Jeder bezieht sich nur auf eine einzige Kerze und hat die übersichtlichen Werte für die Kerzendaten. Die Daten sind nun für die Analyse oder die Entwicklung von Charts bereit, da sie sauber und gut organisiert sind.

Analogie:

Stellen Sie sich die gesamte Serverantwort als ein einziges, langes Bücherregal vor, in dem nur wenig Platz zwischen den zahlreichen Bänden ist. Jedes Buch steht für eine 30-minütige Kerze. Sie begannen damit, dieses lange Bücherregal in zehn kleinere Bücher aufzuteilen, was bedeutete, dass die massive Zeichenkette der Kerzen in zehn Teile unterteilt wurde. So wie zehn Bücher nebeneinander in einem Regal stehen, so sind jetzt zehn verschiedene Kerzen in einer Reihe angeordnet.

Sie haben dann das erste Buch im Regal ausgewählt. Die Plastik- und Auszeichnungsaufkleber auf der Vorderseite stehen für die zusätzlichen Zeichen, die das JSON-Format mit sich bringt, wie die führenden doppelten Klammern und Anführungszeichen. Sie haben die Aufkleber und das Plastik entfernt, um das Buch vor dem Lesen sauber zu machen. Nachdem Sie den Einband gesäubert hatten, öffneten Sie das Buch und fanden die Kapitel darin. Diese Kapitel, die für den Eröffnungs-, den Höchst-, den Tiefst- und den Schlusskurs stehen, sind durch Kommas getrennt. Daraufhin haben Sie diese Kapitel in kleinere Abschnitte unterteilt und sie ordentlich auf einem anderen, kleineren Regal angeordnet, das nur für die erste Kerze verwendet wurde.

Das zweite Buch haben Sie aus dem Regal genommen, die Aufkleber entfernt, es aufgeschlagen, in Kapitel unterteilt und alles ordentlich in einem anderen kleinen Teil angeordnet. Das dritte, vierte, fünfte und zehnte Buch folgten alle demselben Prozess. Von jedem Buch wurden die überflüssigen Umschläge entfernt, bevor der Inhalt in handliche Stücke aufgeteilt wurde. Am Ende erhält man zehn äußerst aufgeräumte Teile, von denen jedes zu einer einzigen Kerze gehört, anstatt zu einem großen, unübersichtlichen Bücherregal. Die Werte innerhalb jeder Kerze sind leicht zugänglich und in den einzelnen Segmenten aufgeteilt. Anstatt mit einem einzigen, riesigen Textblock zu arbeiten, ist es so einfach, mit jeder Kerze einzeln zu arbeiten.

 

Umwandlung von Kerzenwerten in ihre korrekten Datentypen

Inzwischen ist jedes Kerzendetail in unseren Kerzenarrays bereits in verschiedene Textelemente unterteilt worden. Da wir alle Daten von der API als rohe Zeichenketten gesammelt haben, sind alle Werte noch im Textformat. Bevor wir sie für Berechnungen verwenden oder in einem Indikator anzeigen können, müssen wir sie in die entsprechenden Datentypen umwandeln, da sie Daten und Zahlen darstellen.

Beispiel:
//DATETIME
long bar1_time_s;
datetime bar1_time;
long bar2_time_s;
datetime bar2_time;
long bar3_time_s;
datetime bar3_time;
long bar4_time_s;
datetime bar4_time;
long bar5_time_s;
datetime bar5_time;
long bar6_time_s;
datetime bar6_time;
long bar7_time_s;
datetime bar7_time;
long bar8_time_s;
datetime bar8_time;
long bar9_time_s;
datetime bar9_time;
long bar10_time_s;
datetime bar10_time;

//OPEN
double bar1_open;
double bar2_open;
double bar3_open;
double bar4_open;
double bar5_open;
double bar6_open;
double bar7_open;
double bar8_open;
double bar9_open;
double bar10_open;

//HIGH
double bar1_high;
double bar2_high;
double bar3_high;
double bar4_high;
double bar5_high;
double bar6_high;
double bar7_high;
double bar8_high;
double bar9_high;
double bar10_high;

//LOW
double bar1_low;
double bar2_low;
double bar3_low;
double bar4_low;
double bar5_low;
double bar6_low;
double bar7_low;
double bar8_low;
double bar9_low;
double bar10_low;

//CLOSE
double bar1_close;
double bar2_close;
double bar3_close;
double bar4_close;
double bar5_close;
double bar6_close;
double bar7_close;
double bar8_close;
double bar9_close;
double bar10_close;

//TIME
bar1_time_s = (long)StringToInteger(first_bar_data_array[0])/1000;
bar1_time = (datetime)bar1_time_s;

bar2_time_s = (long)StringToInteger(second_bar_data_array[0])/1000;
bar2_time = (datetime)bar2_time_s;

bar3_time_s = (long)StringToInteger(third_bar_data_array[0])/1000;
bar3_time = (datetime)bar3_time_s;

bar4_time_s = (long)StringToInteger(fourth_bar_data_array[0])/1000;
bar4_time = (datetime)bar4_time_s;

bar5_time_s = (long)StringToInteger(fifth_bar_data_array[0])/1000;
bar5_time = (datetime)bar5_time_s;

bar6_time_s = (long)StringToInteger(sixth_bar_data_array[0])/1000;
bar6_time = (datetime)bar6_time_s;

bar7_time_s = (long)StringToInteger(seventh_bar_data_array[0])/1000;
bar7_time = (datetime)bar7_time_s;

bar8_time_s = (long)StringToInteger(eighth_bar_data_array[0])/1000;
bar8_time = (datetime)bar8_time_s;

bar9_time_s = (long)StringToInteger(nineth_bar_data_array[0])/1000;
bar9_time = (datetime)bar9_time_s;

bar10_time_s = (long)StringToInteger(tenth_bar_data_array[0])/1000;
bar10_time = (datetime)bar10_time_s;

//OPEN
bar1_open = StringToDouble(first_bar_data_array[1]);
bar2_open = StringToDouble(second_bar_data_array[1]);
bar3_open = StringToDouble(third_bar_data_array[1]);
bar4_open = StringToDouble(fourth_bar_data_array[1]);
bar5_open = StringToDouble(fifth_bar_data_array[1]);
bar6_open = StringToDouble(sixth_bar_data_array[1]);
bar7_open = StringToDouble(seventh_bar_data_array[1]);
bar8_open = StringToDouble(eighth_bar_data_array[1]);
bar9_open = StringToDouble(nineth_bar_data_array[1]);
bar10_open = StringToDouble(tenth_bar_data_array[1]);

//HIGH
bar1_high = StringToDouble(first_bar_data_array[2]);
bar2_high = StringToDouble(second_bar_data_array[2]);
bar3_high = StringToDouble(third_bar_data_array[2]);
bar4_high = StringToDouble(fourth_bar_data_array[2]);
bar5_high = StringToDouble(fifth_bar_data_array[2]);
bar6_high = StringToDouble(sixth_bar_data_array[2]);
bar7_high = StringToDouble(seventh_bar_data_array[2]);
bar8_high = StringToDouble(eighth_bar_data_array[2]);
bar9_high = StringToDouble(nineth_bar_data_array[2]);
bar10_high = StringToDouble(tenth_bar_data_array[2]);

//LOW
bar1_low = StringToDouble(first_bar_data_array[3]);
bar2_low = StringToDouble(second_bar_data_array[3]);
bar3_low = StringToDouble(third_bar_data_array[3]);
bar4_low = StringToDouble(fourth_bar_data_array[3]);
bar5_low = StringToDouble(fifth_bar_data_array[3]);
bar6_low = StringToDouble(sixth_bar_data_array[3]);
bar7_low = StringToDouble(seventh_bar_data_array[3]);
bar8_low = StringToDouble(eighth_bar_data_array[3]);
bar9_low = StringToDouble(nineth_bar_data_array[3]);
bar10_low = StringToDouble(tenth_bar_data_array[3]);

//CLOSE
bar1_close = StringToDouble(first_bar_data_array[4]);
bar2_close = StringToDouble(second_bar_data_array[4]);
bar3_close = StringToDouble(third_bar_data_array[4]);
bar4_close = StringToDouble(fourth_bar_data_array[4]);
bar5_close = StringToDouble(fifth_bar_data_array[4]);
bar6_close = StringToDouble(sixth_bar_data_array[4]);
bar7_close = StringToDouble(seventh_bar_data_array[4]);
bar8_close = StringToDouble(eighth_bar_data_array[4]);
bar9_close = StringToDouble(nineth_bar_data_array[4]);
bar10_close = StringToDouble(tenth_bar_data_array[4]);

Erläuterung:

Wir generieren Variablen für die Kerzenwerte für jede Kerze. Um einen geeigneten Datum-Zeit-Wert in MQL5 zu erstellen, müssen die Zeitwerte zunächst von Textnummern, die Millisekunden darstellen, in lange Zahlen umgewandelt werden. Es ist notwendig, die numerischen Preiswerte von Text in reelle Zahlen umzuwandeln. Aus diesem Grund wird im Vorfeld eine Reihe von Variablen festgelegt. Zu einem späteren Zeitpunkt wird der umgerechnete Wert für jede dieser Variablen ermittelt. Die Zeichenkette muss zunächst in eine Zahl vom Typ long umgewandelt und dann durch 1.000 geteilt werden. Der Grund dafür ist, dass die Zeit jeder Kerze von der API in Millisekunden empfangen wird. Das Ergebnis wird dann in einen korrekten Datum-Zeit-Wert umgewandelt, den MQL5 verstehen kann, und in einer langen Variablen gespeichert. So erhalten wir die passende Zeit der Kerze für das Chart. Jede der zehn Kerzen durchläuft das gleiche Verfahren.

Nach der Festlegung der Zeitwerte folgt die Umrechnung dem Eröffnungskurs. Jeder Eröffnungskurs wird aus seiner Position in der Zeichenkette extrahiert und mit Hilfe einer Konvertierungsfunktion in eine Doppelzahl umgewandelt. Um sicherzustellen, dass jede Kerze ihren realen numerischen Eröffnungswert hat, wird dieser Vorgang für jede Kerze durchgeführt. Die Hochs werden dann demselben Prozess unterzogen. Jedes Hoch wird von seinem Ort in der Zeichenkette in die Konvertierungsfunktion und dann in die entsprechende Variable vom Typ double übertragen. Danach wird das Verfahren für die Tiefs und schließlich für den Schlusskurs wiederholt. In jedem Fall soll sichergestellt werden, dass jeder Preis aus dem reinen Text in ein geeignetes numerisches Format umgewandelt wird, damit er für Berechnungen, das Zeichnen von Kerzen und den Vergleich von Preisbewegungen verwendet werden kann.

Analogie:

Stellen Sie sich jede Kerze als ein Buch vor, dessen Kapitel bereits sortiert und bereinigt sind. Das Buch ist in einer Sprache geschrieben, die die Bibliothek nicht versteht, und das ist das einzige Problem. Das Buch ist fertig, aber solange wir die Worte nicht in die Sprache übersetzen, die unser System versteht, ist es nutzlos. Wir müssen nun mit dieser Übersetzung fortfahren. In jedem Kerzenbuch gibt es fünf Schlüsselseiten. Die Öffnungszeit der Kerze erscheint auf der ersten Seite, gefolgt vom Eröffnungskurs auf der zweiten, dem Höchstkurs auf der dritten, dem Tiefstkurs auf der vierten und dem Schlusskurs auf der fünften Seite. Anstatt korrekte Zahlenwerte zu verwenden, ist jede dieser Seiten jedoch in Sprache verfasst. Stellen Sie sich vor, dass die Zahl in Worten und nicht in Zahlen geschrieben ist, wenn Sie das Buch aufschlagen. Sie müssen jede dieser Zahlen in das entsprechende Format umschreiben, bevor Ihr Bibliothekssystem sie speichern oder damit rechnen kann. Die Konvertierungsphase ist dieses Umschreibungsverfahren.

In jedem Buch ist die Zeit auf der ersten Seite in Millisekunden angegeben, was dem Ausdruck des Datums in einem Kalendersystem entspricht, das Ihre Bibliothek nicht versteht. Der erste Schritt besteht darin, das Datum in Sekunden umzuschreiben; dies ist vergleichbar mit der Übersetzung des ausländischen Kalenders in Ihren lokalen Kalender. Das Datum wird dann schließlich im offiziellen Datumsformat Ihrer Bibliothek geschrieben, wenn Sie das Ergebnis erneut in das Datetime-Format konvertieren. Für jedes Buch der Kerzen wiederholen Sie diesen Vorgang und geben für die Bücher eins bis zehn das entsprechende Datum in Ihr Bibliothekssystem ein.

Danach fahren Sie mit den übrigen Seiten fort. Die Eröffnungs-, Höchst-, Tiefst- und Schlusswerte werden auf jeder Preisseite gespeichert, sind aber immer noch Zeichenketten. Stellen Sie sich diese als handgeschriebene Seiten vor, die der Bibliotheksscanner nicht lesen kann. Damit der Algorithmus jeden Preis vollständig versteht, müssen Sie ihn mit reinen Ziffern umschreiben. Das Bibliothekssystem kann nun nach der Konvertierung problemlos Preise vergleichen, Werte speichern und Berechnungen durchführen. Für jede Seite in jedem Kerzenbuch tun Sie dies. Am Ende dieses Prozesses ist jedes Kerzenbuch kein handgeschriebenes fremdes Dokument mehr. Alles wurde in genaue Daten und Zahlen umgewandelt, die das Indexierungssystem Ihrer Bibliothek verstehen kann. Sie können nun mit den vollständig lesbaren Büchern in Ihrem Kerzenregal eine Anzeige erstellen, Kerzen zeichnen oder alle notwendigen Berechnungen durchführen.

 

Gruppierung von Kerzenwerten in separaten Arrays

Zu diesem Zeitpunkt sind die Werte jeder Kerze korrekt in die entsprechenden Datentypen umgewandelt worden, wobei die Preise Doppelwerte und die Zeitangaben Datetime sind. Der nächste Schritt besteht darin, diese Werte so zu organisieren, dass alle vergleichbaren Datenarten in Gruppen zusammengefasst werden. Mit anderen Worten: Die Eröffnungskurse jeder der zehn Kerzen werden in ein Array eingetragen, die Schlusskurse in ein anderes, und so weiter für die Hoch-, Tief- und Zeitwerte. Bei der Erstellung von Indikatoren oder der Durchführung von Berechnungen können wir leichter mit der Struktur arbeiten, die durch die Gruppierung der Variablen auf diese Weise entsteht. Wir können nun mit dem gesamten Datensatz auf einmal arbeiten, indem wir einfach auf das Array der Eröffnungskurse, das Array der Schlusskurse oder das Array der Zeiten verweisen, anstatt jedes Mal separat auf jede Kerze zuzugreifen.

Außerdem erhöht dieser Ansatz die Effizienz und Klarheit. So kann die Software beispielsweise die Eröffnungs-, Höchst-, Tiefst- und Schlussstände jeder Kerze darstellen, indem sie die Arrays nach und nach ausliest, während die Kerzen in einem Chart angezeigt werden. Da alle Werte desselben Typs bereits gruppiert sind, vereinfacht dies auch Berechnungen wie gleitende Durchschnitte, Kerzenvergleiche und andere technische Analyseoperationen.

Beispiel:
datetime OpenTime[10] = {bar1_time, bar2_time, bar3_time, bar4_time, bar5_time,bar6_time, bar7_time, bar8_time, bar9_time, bar10_time};
double   OpenPrice[10] = {bar1_open, bar2_open, bar3_open, bar4_open, bar5_open,bar6_open, bar7_open, bar8_open, bar9_open, bar10_open};
double   ClosePrice[10] = {bar1_close, bar2_close, bar3_close, bar4_close, bar5_close,bar6_close, bar7_close, bar8_close, bar9_close, bar10_close};
double   LowPrice[10] = {bar1_low, bar2_low, bar3_low, bar4_low, bar5_low,bar6_low, bar7_low, bar8_low, bar9_low, bar10_low};
double   HighPrice[10] = {bar1_high, bar2_high, bar3_high, bar4_high, bar5_high,bar6_high, bar7_high, bar8_high, bar9_high, bar10_high};

Erläuterung:

In diesem Schritt werden alle einzelnen Kerzenwerte in Arrays zusammengefasst, sodass alle ähnlichen Daten gemeinsam gespeichert werden. Wir haben jetzt ein einziges Array für jede Art von Daten, anstatt verschiedene Variablen für jede Kerze. Die spätere Arbeit mit den Kerzeninformationen im Programm wird dadurch wesentlich vereinfacht. Die Öffnungszeiten der 10 Kerzen werden in der gleichen Reihenfolge beibehalten, in der sie in der ursprünglichen Anordnung eingegangen sind. Jede Kerzenzeit hat ihren eigenen Platz. Anstatt zehn verschiedene Zeitvariablen zu verwalten, erleichtert diese Konfiguration die Bezugnahme auf eine beliebige Kerzenzeit, indem sie einfach auf ihren Index verweist.

Die Technik bleibt bei den Preiswerten unverändert. Von Kerze eins bis Kerze zehn sind die Eröffnungskurse in einem einzigen Array angeordnet. Die gleiche Methode wird verwendet, um die Schluss-, Höchst- und Tiefststkurse zu speichern. Die erste Kerze wird immer mit dem ersten Index bezeichnet, und die übrigen Indizes folgen der gleichen Reihenfolge. Auf diese Weise wird sichergestellt, dass die Elemente jedes Preisfeldes alle der gleichen Kerzennummer entsprechen. Durch die Verwendung von Arrays können wir Kerzendaten auf organisierte und zuverlässige Weise handhaben. Wir können jede Kerze automatisch verarbeiten, indem wir die Arrays in Schleifen durchlaufen, anstatt jede Kerze einzeln zu verwalten. Ebenso wird eine Verwechslung vermieden und die korrekte Ausrichtung beibehalten, da jeder Kurswert denselben Index für dieselbe Kerze hat. Bei der Erstellung von Indikatoren, der Berechnung von Werten oder der Erstellung von Charts ist diese Anordnung entscheidend.

Analogie:

Stellen Sie sich eine Sammlung von Büchern vor, bei der jedes Buch für eine Kerze steht. Jedes Buch enthält alle Angaben zur Kerze, einschließlich der Zeit und der Preisspanne. Bis jetzt haben Sie die Informationen Seite für Seite und Buch für Buch durchgesehen. Es funktioniert, aber je größer die Sammlung wird, desto schwieriger wird es, jedes einzelne Dokument zu bearbeiten, was zu einer Verlangsamung führt. Sie unterteilen die Daten nach Kategorien, anstatt alles in einem Buch zu vereinen. Ein Regal wird für alle geöffneten Stunden, ein weiteres für die geöffneten Preise und ein weiteres für die Schlusskurse, Höchst- und Tiefstwerte erstellt. Die Nummer der Kerze in den Regalen wird durch jede Zeile dargestellt. Daher gehört Kerze 1 zu Reihe 1 auf jedem Regal, Kerze 2 zu Reihe 2 usw.

Dadurch müssen Sie nicht mehr jedes Buch einzeln öffnen, um ähnliche Inhalte zu vergleichen oder zu lesen. Besuchen Sie einfach das offene Preisregal, um alle verfügbaren Preise zu sehen. Sie besuchen das Zeitregal, wenn Sie alle Schließungszeiten benötigen. Diese Anordnung erleichtert die effiziente Berechnung, den Vergleich und die Anzeige der Daten.

 

Speichern von Kerzeninformationen für die Visualisierung

Der nächste Schritt besteht darin, eine Datei zu erstellen, in der alle zugehörigen Kerzendaten, die in Arrays gruppiert wurden, gespeichert werden. Die Datei hat die Aufgabe, alle Kerzendaten geordnet zu speichern, sodass die Kerzen anschließend in einem Chart angezeigt werden können. Der Indikator oder das Programm kann leicht auf die Daten zugreifen, indem es sie in einer Datei speichert, sodass sie nicht wiederholt vom Server angefordert werden müssen.

Die Datei ist als einfache Tabelle aufgebaut. Zeit, Eröffnung, Höchst-, Tiefst- und Schlusskurs gehören zu den Überschriften in der ersten Zeile, die deutlich machen, wofür jede Spalte steht. Jede Zeile enthält die Angaben für eine einzelne Kerze unterhalb der Überschriften. Alle Kerzenzeiten werden in der ersten Spalte gespeichert, gefolgt von den Eröffnungskursen in der zweiten Spalte, den Höchstkursen in der dritten Spalte und so weiter. Kerze eins wird durch die erste Datenzeile dargestellt, Kerze zwei durch die nächste, und jede weitere Zeile stellt nacheinander die nachfolgende Kerze dar. Mit dieser tabellarischen Anordnung sind die Kerzeninformationen übersichtlich und leicht zugänglich. Der Indikator kann die Kerzen auf dem Chart genau nachbilden, indem er jede Spalte liest. Künftige Aufgaben wie das Hinzufügen neuer Kerzen oder das Aktualisieren der Daten werden durch die Verwendung dieses Rahmens ebenfalls erleichtert.

Beispiel:

string filename;
int handle;
filename = "BTCUSDTM30_MQL5.csv";
handle = FileOpen(filename, FILE_WRITE|FILE_CSV|FILE_SHARE_READ|FILE_ANSI, ',');

if(handle != INVALID_HANDLE)
  {
// Write a header row
   FileWrite(handle, "Time", "Open", "High", "Low", "Close");

// Write the 5 days of data row by row
   for(int i = 0; i < 10; i++)
     {
      FileWrite(handle, OpenTime[i], OpenPrice[i], HighPrice[i], LowPrice[i], ClosePrice[i]);
     }

   FileClose(handle);
   Print("EA successfully wrote the data to " + filename);
  }
else
  {
   Print("Error opening file for writing. Error code: ", + GetLastError());
  }

Erläuterung:

Die Auswahl eines Dateinamens für die Datei ist der erste Schritt zur Speicherung der Kerzendaten. Ein prägnanter Dateiname erleichtert den Umgang mit mehreren Dateien, da er einen schnellen Überblick über die darin enthaltenen Daten wie das Symbol der Kerzen und die Zeitleiste bietet. Anschließend wird versucht, die Datei zum Schreiben durch das Programm zu öffnen. Bestimmte Einstellungen werden verwendet, um einen ordnungsgemäßen Betrieb zu gewährleisten. Wenn die Datei im CSV-Format (Comma Separated Values) geöffnet wird, werden die Daten in einer Tabellenstruktur angeordnet, die sowohl für Programme als auch für Menschen einfach zu verstehen ist. Zusätzlich werden Freigabe- und Verschlüsselungsparameter konfiguriert, um einen sicheren Zugriff und eine angemessene Interpretation durch verschiedene Programme zu ermöglichen. Anschließend schreibt das Programm eine Kopfzeile, nachdem die Datei geöffnet wurde. Diese Zeile gibt einen klaren Hinweis auf die Art der in der Datei gespeicherten Daten und identifiziert jede Spalte. Die Kopfzeile erleichtert das spätere Lesen und sorgt für die Organisation der Datei.

Das Programm füllt die Datei nach der Kopfzeile zeilenweise mit Kerzendaten. In den Spalten sind alle relevanten Werte übersichtlich angeordnet, wobei jede Zeile eine einzelne Kerze darstellt. Um alle zehn Kerzen in der richtigen Reihenfolge zu erfassen, durchläuft das Programm die Arrays in der gleichen Reihenfolge wie das Chart. Anschließend wird die Datei geschlossen, sobald alle Kerzendaten hinzugefügt wurden, um sicherzustellen, dass keine Ressourcen unnötig zurückgehalten werden und alles gespeichert wird. Die Anwendung zeigt eine Erfolgsmeldung an, um anzuzeigen, dass die Datei ordnungsgemäß verarbeitet wurde. 

Das Kompilieren und Ausführen des Codes erfolgt nach der Erstellung. Der Expert Advisor beginnt sofort mit der Dateierstellung, nachdem er in Ihrem Chart initialisiert wurde. Alle Kerzendaten werden in einer strukturierten CSV-Datei gespeichert, die von der Software erstellt wird. Auf Ihrem Computer wird die Datei im Dateiordner des MQL5-Verzeichnisses erzeugt. MQL5 speichert die vom Programm erzeugten Dateien in diesem Standardverzeichnis, sodass sie später leicht zu finden sind. Wenn die Datei eintrifft, können Sie sich vergewissern, dass alle Kerzendaten korrekt gespeichert wurden, bevor Sie sie zur Erstellung Ihrer Indikation oder zur Durchführung anderer Analysen verwenden.

Analogie:

Stellen Sie sich 10 Bücher in einem Regal vor, die jeweils seitenweise Informationen über jede Kerze enthalten. Die Seiten sind je nach Art in verschiedene Stapel aufgeteilt worden. Stellen Sie sich nun vor, dass Sie all diese Stapel in einem neuen Hefter ablegen, sodass Sie jederzeit leicht auf die Daten zugreifen können, wenn Sie sie brauchen. Um zu verdeutlichen, welche Art von Informationen er enthält, z. B. das Symbol und den Zeitraum der Kerzen, beschriften Sie den Hefter zunächst deutlich. Danach öffnen Sie den Hefter und bereiten ihn für die geordnete Aufnahme der Seiten vor. Als Orientierungshilfe für jeden, der das Buch durchblättert, befindet sich auf der Vorderseite eine Titelseite, auf der die Bedeutung der einzelnen Spalten erklärt wird.

Danach ordnen Sie die Seiten in dem Hefter nacheinander an, wobei jede Reihe eine Kerze darstellt. Die erste Reihe steht für die erste Kerze, die zweite Reihe für die zweite und so weiter. Durch diese Anordnung der Seiten wird sichergestellt, dass alle Kerzeninformationen geordnet und bei Bedarf schnell verfügbar sind. Um sicherzustellen, dass alle Daten sicher aufbewahrt werden, schließen Sie den Hefter, nachdem Sie alles sortiert haben. Dies ist vergleichbar mit der Software, die die Datei vervollständigt, sodass die Informationen dauerhaft auf Ihrem Computer gespeichert werden.

Sie müssen die Prozedur kompilieren und ausführen, damit Ihr Bibliothekssystem diesen Hefter verwenden kann. In der Programmiersprache bedeutet dies „Kompilierung des EA und Initialisierung auf Ihrem Chart“. Der Hefter, d. h. die Datei mit allen Kerzendaten, wird sofort auf Ihrem Computer erstellt, sobald der EA in Betrieb geht. Sie befindet sich im Dateiordner Ihres MQL5-Verzeichnisses. Der Hefter kann nun geöffnet und verwendet werden, sodass Ihr Indikator oder Programm auf die angeordneten Kerzendaten zur Analyse oder Visualisierung zugreifen kann.

Pfad:
C:\Users\Dell\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Files

Abbildung 2. Kerzendaten in der Datei

Um Ihnen nicht zu viele Informationen auf einmal zu geben, machen wir hier erst einmal eine Pause. Im nächsten Artikel werden wir den nächsten Schritt machen und einen Indikator entwickeln, der die Kerzen im richtigen Kerzenformat auf dem Chart anzeigt, indem er die Daten aus der Datei verwendet. Damit können Sie die von Ihnen gespeicherten und angeordneten Daten als echte Kerzenständer anzeigen.


Schlussfolgerung

Um unseren Umgang mit Binance-API-Daten zu verbessern, haben wir in diesem Artikel die letzten zehn 30-Minuten-Kerzen abgerufen und die Serverantwort in einzelne Kerzen unterteilt. Wir haben zusammengehörige Werte in Arrays gruppiert und in die entsprechenden Datentypen umgewandelt, um die Daten leichter handhaben zu können. Um die Daten der Kerzen in einer geordneten Tabelle zu speichern, auf die man in Zukunft leicht zugreifen kann, haben wir schließlich eine Datei vorbereitet. Dieser Prozess bereitet die Daten für die Visualisierung vor und bietet eine strukturierte Grundlage für die Erstellung von Indikatoren oder EAs. Im nächsten Artikel werden wir diese Datei verwenden, um einen Indikator zu erstellen, der die Kerzen auf dem Chart im richtigen Format anzeigt, sodass Sie das Marktverhalten visuell und effizient analysieren können.

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/20546

Die Übertragung der Trading-Signale in einem universalen Expert Advisor. Die Übertragung der Trading-Signale in einem universalen Expert Advisor.
In diesem Artikel wurden die verschiedenen Möglichkeiten beschrieben, um die Trading-Signale von einem Signalmodul des universalen EAs zum Steuermodul der Positionen und Orders zu übertragen. Es wurden die seriellen und parallelen Interfaces betrachtet.
Entwicklung einer Handelsstrategie: Verwendung eines volumenabhängigen Ansatzes Entwicklung einer Handelsstrategie: Verwendung eines volumenabhängigen Ansatzes
In der Welt der technischen Analyse steht der Preis oft im Mittelpunkt. Händler zeichnen akribisch Unterstützung, Widerstand und Muster auf, ignorieren aber häufig die entscheidende Kraft, die diese Bewegungen antreibt: das Volumen. Dieser Artikel befasst sich mit einem neuartigen Ansatz zur Volumenanalyse: dem Volume Boundary Indikator. Diese Transformation, bei der ausgefeilte Glättungsfunktionen wie die Schmetterlings- und Triple-Sinuskurve zum Einsatz kommen, ermöglicht eine klarere Interpretation und die Entwicklung systematischer Handelsstrategien.
Eine alternative Log-datei mit der Verwendung der HTML und CSS Eine alternative Log-datei mit der Verwendung der HTML und CSS
In diesem Artikel werden wir eine sehr einfache, aber leistungsfähige Bibliothek zur Erstellung der HTML-Dateien schreiben, dabei lernen wir auch, wie man eine ihre Darstellung einstellen kann (nach seinem Geschmack) und sehen wir, wie man es leicht in seinem Expert Advisor oder Skript hinzufügen oder verwenden kann.
Kagi-Chart in MQL5 beherrschen (Teil 2): Implementierung des automatisierten Kagi-basierten Handels Kagi-Chart in MQL5 beherrschen (Teil 2): Implementierung des automatisierten Kagi-basierten Handels
Lernen Sie, wie man einen kompletten Kagi-basierten Expert Advisor in MQL5 aufbaut, von der Signalerstellung bis zur Auftragsausführung, visuellen Markern und einem dreistufigen Trailing-Stop. Enthalten ist der vollständige Code, Testergebnisse und eine herunterladbare Datei.