English Русский 中文 Español 日本語 Português
preview
Marktsimulation (Teil 04): Erstellen der Klasse C_Orders (I)

Marktsimulation (Teil 04): Erstellen der Klasse C_Orders (I)

MetaTrader 5Beispiele |
13 0
Daniel Jose
Daniel Jose

Einführung

Im vorigen Artikel, Marktsimulation (Teil 82): Eine Frage der Leistung, haben wir einige Anpassungen an den Klassen vorgenommen, um zumindest vorübergehend bestimmte Probleme zu beheben, die bei uns auftraten. Diese Probleme verschlechterten die Gesamtleistung des Systems. Während wir diese Probleme vorerst gelöst haben, stehen wir nun vor einem wirklich komplexen Problem. Nicht in diesem ersten Teil, da ich das Thema bereits in früheren Artikeln behandelt habe. Allerdings gehen wir die Dinge jetzt etwas anders an. Daher wird auch die Art und Weise, wie wir dieses Thema behandeln, etwas anders sein.

Ich weiß, dass viele von Ihnen es kaum erwarten können, dass der Replay/Simulator endlich Aufträge ausführt. Zuvor müssen wir jedoch sicherstellen, dass das Auftragssystem voll funktionsfähig ist. Dies ist für die Kommunikation mit dem realen Handelsserver unerlässlich, egal ob über ein DEMO-Konto oder ein REAL-Konto. In jedem Fall müssen die beteiligten Anwendungen – nämlich der Chart Trade Indikator, der Mouse Indikator und der Expert Advisor – perfekt miteinander harmonieren und eine reibungslose Kommunikation mit dem realen Handelsserver gewährleisten.

Zusätzlich zu den oben genannten Anwendungen müssen wir weitere Komponenten erstellen. Diese können jedoch vorerst beiseite gelassen werden, da ihre Entwicklung (sowohl in der konzeptionellen Phase als auch während der Umsetzung) von mehreren Faktoren abhängt, die in dieser Entwicklungsphase behandelt werden.

In diesem Artikel werde ich zunächst erläutern, wie wir mit dem Handelsserver kommunizieren werden. Viele von Ihnen wissen vielleicht schon ganz gut, wie das geht. In diesem Fall bitte ich Sie um ein wenig Geduld, denn wir werden mit Bedacht vorgehen und nichts überstürzen. Es ist wichtig, dass Sie genau verstehen, was tatsächlich geschieht. Im Gegensatz zu vielen typischen Programmieransätzen wird dieses System in Modulen aufgebaut, von denen jedes für eine ganz bestimmte Aufgabe zuständig ist. Wenn ein Modul ausfällt, fällt das gesamte System aus, da es kein Backup-System gibt, das die Funktionalität auf andere Weise sicherstellt.


Verstehen des Konzepts

Wenn Sie diese Serie verfolgt haben, bemerkten Sie vielleicht in dem Artikel Entwicklung eines Wiedergabesystems (Teil 78): Neuer Chart Trade (V), wo ich anfing zu zeigen, wie die Interaktion stattfinden würde, dass der Expert Advisor nicht wirklich weiß, woher die Aufträge kommen. Allerdings weiß derselbe Expert Advisor, wie er die eingehenden Nachrichten zu interpretieren hat. Obwohl die damals angewandten Methoden ein ordnungsübergreifendes System nicht zuließen, haben wir uns in späteren Artikeln mit diesem Thema befasst. In Marktsimulation (Teil 02): Kreuzaufträge (II) habe ich demonstriert, wie das Nachrichtensystem für die Kommunikation mit dem Expert Advisor aufgebaut sein würde.

Dieser ganze Mechanismus ist Teil von etwas noch Größerem. Daher ist das Verständnis dieses Nachrichtenübermittlungsmechanismus von entscheidender Bedeutung für das Verständnis dessen, was wir in diesem Artikel erforschen werden. Unterschätzen oder übersehen Sie nicht, was in den vorangegangenen Artikeln erläutert wurde. Das Wichtigste: Gehen Sie nicht davon aus, dass Sie es vollständig verstehen, bevor Sie es nicht in Aktion gesehen haben.

Wenn Sie den zuvor vorgestellten Code des Expert Advisors verstanden haben, sollten Sie keine großen Schwierigkeiten haben zu verstehen, was hier programmiert werden soll. Aber auch hier gilt: Setzen Sie keine Kenntnisse voraus, nur weil Sie sich den Code ansehen. Sie sollten verstehen, wie jedes Detail funktioniert, um die Funktionsweise des Systems als Ganzes zu verstehen.


Marktaufträge einleiten

Da es viele Konzepte zu erklären gibt, werde ich im folgenden Code nicht gleich die ganze Klasse zeigen. Ebenso werde ich in diesem Artikel keine große Menge an Code unterbringen. Dieser Abschnitt erfordert ein sorgfältiges Verständnis. Denn der Code, den wir sehen werden, wird tatsächlich das Geld betreffen. Ihr Geld, lieber Leser. Wenn Sie verstehen, wie die einzelnen Teile funktionieren, können Sie sich mit dem vorgestellten Code sicher und zufrieden fühlen. Ich möchte nicht, dass Sie den Code ändern, nur weil Sie ihn nicht verstehen. Ich möchte, dass Änderungen nur dann vorgenommen werden, wenn Sie Funktionen hinzufügen müssen, die derzeit nicht vorhanden sind, und nicht, weil Sie an einen bestimmten Codierungsstil gewöhnt sind. Studieren Sie den Code sorgfältig, denn er wird auch bei der Durchführung der Auftragssimulation verwendet.

Um die Erklärung so weit wie möglich zu vereinfachen, beginnen wir mit der Untersuchung der Anfangsklasse, die für das Senden von Aufträgen an den Server verantwortlich ist – sei es der echte Server, mit dem wir uns jetzt beschäftigen, oder der simulierte Server, den wir später sehen werden. In jedem Fall beginnt der Code wie unten gezeigt. Der erste Codefragment lautet wie folgt.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #include "..\Defines.mqh"
005. //+------------------------------------------------------------------+
006. class C_Orders
007. {
008.    protected:
009. //+------------------------------------------------------------------+
010. inline const ulong GetMagicNumber(void) const {return m_MagicNumber;}
011. //+------------------------------------------------------------------+
012.    private   :
013. //+------------------------------------------------------------------+
014.       MqlTradeRequest   m_TradeRequest;
015.       ulong             m_MagicNumber;
016.       bool              m_bTrash;
017. //+------------------------------------------------------------------+
018.       struct stChartTrade
019.       {
020.          struct stEvent
021.          {
022.             EnumEvents  ev;
023.             string      szSymbol,
024.                         szContract;
025.             bool        IsDayTrade;
026.             ushort      Leverange;
027.             double      PointsTake,
028.                         PointsStop;
029.          }Data;
030. //---
031.          bool Decode(const EnumEvents ev, const string sparam)
032.             {
033.                string Res[];
034.       
035.                if (StringSplit(sparam, '?', Res) != 7) return false;
036.                stEvent loc = {(EnumEvents) StringToInteger(Res[0]), Res[1], Res[2], (bool)(Res[3] == "D"), (ushort) StringToInteger(Res[4]), StringToDouble(Res[5]), StringToDouble(Res[6])};
037.                if ((ev == loc.ev) && (loc.szSymbol == _Symbol)) Data = loc;
038.                
039.                return true;
040.             }
041. //---
042.       }m_ChartTrade;
043. //+------------------------------------------------------------------+
044.       ulong SendToPhysicalServer(void)
045.          {
046.             MqlTradeCheckResult  TradeCheck;
047.             MqlTradeResult       TradeResult;
048.             
049.             ZeroMemory(TradeCheck);
050.             ZeroMemory(TradeResult);
051.             if (!OrderCheck(m_TradeRequest, TradeCheck))
052.             {
053.                PrintFormat("Order System - Check Error: %d", GetLastError());
054.                return 0;
055.             }
056.             m_bTrash = OrderSend(m_TradeRequest, TradeResult);
057.             if (TradeResult.retcode != TRADE_RETCODE_DONE)
058.             {
059.                PrintFormat("Order System - Send Error: %d", TradeResult.retcode);
060.                return 0;
061.             };
062.             
063.             return TradeResult.order;
064.          }
065. //+------------------------------------------------------------------+   
066.       ulong ToMarket(const ENUM_ORDER_TYPE type)
067.          {
068.             double price  = SymbolInfoDouble(m_ChartTrade.Data.szContract, (type == ORDER_TYPE_BUY ? SYMBOL_ASK : SYMBOL_BID));
069.             double vol    = SymbolInfoDouble(m_ChartTrade.Data.szContract, SYMBOL_VOLUME_STEP);
070.             uchar  nDigit = (uchar)SymbolInfoInteger(m_ChartTrade.Data.szContract, SYMBOL_DIGITS);
071.             
072.             ZeroMemory(m_TradeRequest);
073.             m_TradeRequest.magic        = m_MagicNumber;
074.             m_TradeRequest.symbol       = m_ChartTrade.Data.szContract;
075.             m_TradeRequest.price        = NormalizeDouble(price, nDigit);
076.             m_TradeRequest.action       = TRADE_ACTION_DEAL;
077.             m_TradeRequest.sl           = NormalizeDouble(m_ChartTrade.Data.PointsStop == 0 ? 0 : price + (m_ChartTrade.Data.PointsStop * (type == ORDER_TYPE_BUY ? -1 : 1)), nDigit);
078.             m_TradeRequest.tp           = NormalizeDouble(m_ChartTrade.Data.PointsTake == 0 ? 0 : price + (m_ChartTrade.Data.PointsTake * (type == ORDER_TYPE_BUY ? 1 : -1)), nDigit);
079.             m_TradeRequest.volume       = NormalizeDouble(vol + (vol * (m_ChartTrade.Data.Leverange - 1)), nDigit);
080.             m_TradeRequest.type         = type;
081.             m_TradeRequest.type_time    = (m_ChartTrade.Data.IsDayTrade ? ORDER_TIME_DAY : ORDER_TIME_GTC);
082.             m_TradeRequest.stoplimit    = 0;
083.             m_TradeRequest.expiration   = 0;
084.             m_TradeRequest.type_filling = ORDER_FILLING_RETURN;
085.             m_TradeRequest.deviation    = 1000;
086.             m_TradeRequest.comment      = "Order Generated by Experts Advisor.";
087. 
088.             MqlTradeRequest TradeRequest[1];
089. 
090.             TradeRequest[0] = m_TradeRequest;
091.             ArrayPrint(TradeRequest);
092. 
093.             return (((type == ORDER_TYPE_BUY) || (type == ORDER_TYPE_SELL)) ? SendToPhysicalServer() : 0);
094.          };
095. //+------------------------------------------------------------------+
096.    public   :
097. //+------------------------------------------------------------------+
098.       C_Orders(const ulong magic)
099.          :m_MagicNumber(magic)
100.          {
101.          }
102. //+------------------------------------------------------------------+   
103.       void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
104.          {
105.             switch (id)
106.             {
107.                case CHARTEVENT_CUSTOM + evChartTradeBuy     :
108.                case CHARTEVENT_CUSTOM + evChartTradeSell    :
109.                case CHARTEVENT_CUSTOM + evChartTradeCloseAll:
110.                   if (m_ChartTrade.Decode((EnumEvents)(id - CHARTEVENT_CUSTOM), sparam)) switch (m_ChartTrade.Data.ev)
111.                   {
112.                      case evChartTradeBuy:
113.                         ToMarket(ORDER_TYPE_BUY);
114.                         break;
115.                      case evChartTradeSell:
116.                         ToMarket(ORDER_TYPE_SELL);
117.                         break;
118.                      case evChartTradeCloseAll:
119.                         break;
120.                   }
121.                   break;
122.             }
123.          }
124. //+------------------------------------------------------------------+   
125. };
126. //+------------------------------------------------------------------+

Der Quellcode der Datei C_Replay.mqh

Nun gut, lassen Sie uns verstehen, was dieser Code eigentlich tut. Obwohl es kompliziert erscheinen mag, ist es ganz einfach und erfüllt eine einzige Funktion: Es sendet Marktkauf- oder -verkaufsaufträge bei Interaktion zwischen dem Nutzer und dem Indikator Chart Trade. Aber wie schafft sie das? Sie werden vielleicht denken, dass wir den Indikator Chart Trade irgendwie verändern werden. Wenn das Ihr Gedanke war, dann haben Sie nicht ganz verstanden, wie das System funktioniert. Indikatoren können keine Aufträge an den Handelsserver senden. Sie dienen der Anzeige von Informationen auf der Karte. Im Falle des Indikators Chart Trade ermöglicht er die Interaktion des Nutzers mit dem übrigen System.

Bevor wir den Expert Advisor vorstellen, der diese Header-Datei verwenden wird, sollten wir einen Schritt zurückgehen und uns an das erinnern, was bereits erklärt wurde. Dies erleichtert das Verständnis der Header-Datei.

In Entwicklung eines Replay-Systems (Teil 78): Neuer Chart Trade (V) haben wir die Nachrichten erläutert, die der Expert Advisor abfangen soll. Sie haben vielleicht bemerkt, dass wir die Prozedur OnChartEvent verwendet haben, um diese Meldungen zu erfassen. Bei diesem Verfahren haben wir eine Klasse aufgerufen. Diese Klasse übersetzte die empfangene Nachricht und gab sie zur Analyse auf dem Terminal aus. Das war der einfache Teil, denn wir brauchten diese Daten nicht für die Kommunikation mit dem Handelsserver zu verwenden.

Wenn Sie sich den Quellcode des Expert Advisors ansehen, werden Sie feststellen, dass es in der Prozedur OnChartEvent einen Aufruf von DispatchMessage gibt. Dieser Aufruf ruft die Header-Datei auf. Insbesondere Zeile 103. Aber bevor wir dazu kommen, lassen Sie uns am Anfang beginnen – dem Klassenkonstruktor in Zeile 98.

Der Konstruktor ist recht einfach. Beim Aufruf erhält sie ein Argument. Dieses Argument wird verwendet, um die Klasse mit einer magischen Zahl zu identifizieren. Beachten Sie dieses Detail: Wir identifizieren nicht den Expert Advisor selbst, sondern die Klasse. Warum diese Unterscheidung? Manchmal ist es sinnvoll, ähnliche, aber getrennte Klassen zu verwenden, um die gleiche Art von Aufgabe zu erfüllen. Im Moment mag dies noch nicht notwendig erscheinen, aber es wird im weiteren Verlauf deutlich werden. Diese besondere Klasse verwendet bestimmte Elemente nicht, die später erläutert werden.

Wenn z. B. keine Aufträge mehr vorhanden sind und nur noch Positionen übrig sind, möchten Sie diese vielleicht auf eine bestimmte Weise behandeln. Die Verwendung mehrerer Expert Advisors für diese Zwecke ist fehleranfällig. Außerdem kann nur ein Expert Advisor pro Chart arbeiten. (Ich will damit nicht sagen, dass Sie nicht mehrere Expert Advisors für dasselbe Instrument verwenden können. Sie können nur nicht mehr als eine auf derselben Karte haben).

Das Öffnen mehrerer Charts für dasselbe Instrument, nur um verschiedene Expert Advisors auszuführen, ist schwierig zu handhaben. Manche Leute verstehen das, aber ich finde es sehr verwirrend. Es ist jedoch durchaus möglich, leicht unterschiedliche Klassen innerhalb desselben Expert Advisors zu platzieren, damit sie harmonisch zusammenarbeiten. Um dies zu erleichtern, wird der Klasse bei der Erstellung durch den Konstruktor eine magische Zahl zugewiesen. Diese Nummer wird später in Aufträgen und Positionen verwendet. Wir werden das später sehen.

Die magische Zahl wird in Zeile 99 initialisiert, und die Variable, die sie speichert, wird in Zeile 15 deklariert. Beachten Sie, dass Zeile 12 eine private Klausel enthält, die alles von Zeile 12 bis 96 innerhalb der Klasse kapselt, einschließlich der zwischen Zeile 14 und 16 deklarierten Variablen.

Bevor Sie fortfahren, beachten Sie bitte die Zeile 10. Sie enthält eine Funktion, die die für diese Klasse definierte magische Zahl zurückgibt. Da sich diese Zeile zwischen Zeile 8 (einer geschützten Klausel) und Zeile 12 (der privaten Klausel) befindet, kann diese Funktion nicht außerhalb des Vererbungssystems verwendet werden. Mit anderen Worten: Der Versuch, außerhalb einer Klasse, die von C_Orders abgeleitet wird, darauf zuzugreifen, führt zu einem Compilerfehler.

Diese Funktion existiert jetzt für zukünftige Zwecke und ist nur dazu gedacht, die magische Zahl zurückzugeben. Wir werden uns darauf vorerst nicht konzentrieren. Für den Moment genügt es zu wissen, dass diese Funktion in Zeile 10 außerhalb des Vererbungssystems nicht zugänglich ist und nur dazu dient, die magische Zahl dieser Klasse zurückzugeben.

Um den Rest des Codes leichter zu verstehen, werden wir ihn in Themen unterteilen. Jedes Thema bezieht sich jedoch auf denselben Code.


Ein Verfahren innerhalb einer Struktur?

In Entwicklung eines Replay-Systems (Teil 78): Neuer Chart Trade (V) habe ich eine Klasse verwendet, um das Übersetzungssystem zu implementieren. Hier verwende ich eine Struktur. Können wir das tun? Ja, denn Klassen sind im Wesentlichen komplexere Strukturen. Da das, was wir brauchen, einfacher modelliert werden kann, habe ich mich für eine Struktur entschieden. Dies ist zwischen den Zeilen 18 und 42 zu sehen.

Achten Sie darauf: In Zeile 18 wird die Struktur deklariert. Wenn es sich um eine Klasse handeln würde, wäre alles von Zeile 18 bis 42 privat. Dies würde eine öffentliche Klausel zur Anpassung des Zugangs erfordern. Damit gibt es kein Problem. Aber warum sollte man eine Klasse innerhalb einer anderen Klasse deklarieren? In der Regel wird der Code dadurch nur noch verwirrender.

Die Daten, die wir benötigen, stammen aus Nachrichten, die als eine Reihe von Variablen betrachtet werden können. Warum sollte man sich die Nachricht nicht als eine große Menge von Variablen vorstellen? Dies erleichtert das Verständnis. Richtig?

Die Nachrichtenstruktur befindet sich zwischen den Zeilen 20 und 29. Obwohl sich die gesamte Datenstruktur über die Zeilen 18-42 erstreckt, wird die eigentliche Nachricht als die Teilmenge zwischen 20-29 betrachtet. Wie in einem früheren Artikel erläutert, ist die Nachricht eine Zeichenkette. Wenn wir versuchen würden, die Zeichenkette allein auf der Grundlage der Strukturlänge zu analysieren, könnten wir sie leicht falsch interpretieren. Daher benötigen wir einen zusätzlichen Code, um die Nachricht zu entschlüsseln.

Die Zeilen 31-40 enthalten eine Funktion innerhalb der Hauptstruktur, die diese Aufgabe übernimmt. Sie ist jedoch nicht Teil der Nachrichtenstruktur, sondern trennt die Logik, wodurch das Fehlerrisiko verringert wird. Warum? Denn die Elemente existieren getrennt voneinander. Wir könnten alles zusammenfügen: Nachrichtenstruktur, Funktionen und Verfahren. Damit riskieren wir jedoch, bei der Umsetzung auf Probleme zu stoßen.

Seien Sie jetzt bitte aufmerksam, denn das ist ziemlich verwirrend. Wenn Sie dies verstehen, wird Ihnen klar, warum viele Programmierer die Verwendung von Strukturen vermeiden, selbst wenn sie es könnten. Und wenn einige Programmierer versuchen, Strukturen zu verwenden, verwandeln sie ihre Programme in Zeitbomben, insbesondere wenn der Code in der alten Sprache C geschrieben ist.

Achten Sie genau auf Zeile 36. Diese Linie birgt die reale Gefahr, dass alles durcheinandergeraten könnte. In dieser Zeile wird die Datenstruktur mit allen benötigten Werten gefüllt. Wenn es sich stattdessen um eine Funktion oder Prozedur handeln würde, was würde bei der Ausführung von Zeile 35 passieren? Oder noch schlimmer, was passiert, wenn Sie eine Funktion oder Prozedur im Speicher aufrufen, die in Zeile 36 überschrieben wurde? Das Überschreiben der Daten könnte schwerwiegende Folgen haben, was ein Hauptgrund dafür ist, dass Legacy C die Bedeutung der Verwendung von Klassen hervorhebt. Aber wenn Sie wissen, wie das geschieht, verstehen Sie, warum diese Klassen geschaffen wurden.

Wir werden nicht ins Detail gehen, was passieren könnte. Aber vergessen Sie nicht, dass ein wirklich böser Programmierer Dinge tun kann, die Sie sich nicht einmal vorstellen können. Doch zurück zu unserem Code. Die Funktion in Zeile 31 erfüllt die gleiche Aufgabe wie zuvor. Schauen Sie sich aber bitte die Zeile 110 an, in der die Funktion aufgerufen wird. Beachten Sie, dass wir eine Funktion nicht direkt über ihren Namen aufrufen, sondern einen zusätzlichen Verweis benötigen Dies ist ein Verweis auf die Variable, die die Daten enthält, die unsere Struktur darstellen. Dies mag zwar verwirrend erscheinen, ist es aber nicht. Vergessen Sie für einen Moment, dass wir eine Struktur verwenden, und betrachten Sie dies als Aufruf einer Klassenmethode. Die Logik ist dieselbe.

Manche mögen sich fragen, warum DECODE nicht Teil von C_Orders ist. Wäre dies der Fall, wäre der Aufruf in Zeile 110 nicht erforderlich. DECODE existiert jedoch separat, um die Nachricht, die unsere Daten enthält, zu entschlüsseln. Daher macht es keinen Sinn, sie in der Klasse C_Orders zu deklarieren. Denken Sie bei der Trennung von Elementen immer vom logischen Standpunkt aus, nicht vom Standpunkt der Bequemlichkeit aus. Wenn die Funktion DECODE in der Klasse C_Orders deklariert wäre, müssten wir, wenn wir in Zukunft eine Prozedur mit einem ähnlichen Namen verwenden wollten, die aber auf eine andere Datenstruktur abzielt, einen völlig anderen Namen erstellen, um Konflikte zu vermeiden. Schlimmer noch, mit der Zeit, wenn wir den Code ändern, wird es immer schwieriger zu verstehen, was was ist. Die logische Trennung der Zuständigkeiten verhindert also künftige Namenskonflikte und verringert das Fehlerpotenzial.


Kommunikation mit dem Server

Dieser Teil ist für neue Programmierer oft verwirrend. Wenn Sie diesen Abschnitt verwirrend finden, bedeutet das, dass Sie noch nicht alles verstanden haben, was Sie eigentlich tun müssen. Im Gegensatz zu einem Händler, der sich ein Chart ansieht, muss ein Programmierer den Prozess wie das korrekte Ausfüllen eines Formulars betrachten. Wenn das Formular fehlerhaft ist, wird der Server (wie ein sorgfältiger Arbeitgeber) es ablehnen.

Der Server versteht keine Fehler. Sie lehnt unzulässige Anfragen einfach ab. Sie wird uns jedoch den Grund für die Ablehnung mitteilen. Ein gut strukturiertes Kommunikationsverfahren gewährleistet eine reibungslose Interaktion.

Die Zeilen 44-64 enthalten die Funktion für die Kommunikation mit dem Server. Trotz seiner Einfachheit umfasst es alle notwendigen Schritte. Achten Sie auf die logische Abfolge der Schritte, die zu befolgen sind. Wir können nicht einfach so weitermachen wie bisher. Dabei ist folgende Reihenfolge zu beachten: Zuerst wird der Antwortspeicher gelöscht. Dies geschieht in den Zeilen 49-50. Als Nächstes validieren wir die Anfrage. Das heißt, wir prüfen die Daten vor der Übermittlung. Diese Prüfung wird in Zeile 51 durchgeführt. Wenn ein Fehler auftritt, wird ein entsprechender Fehlercode zurückgegeben, damit wir den Fehler beheben und es erneut versuchen können. Wenn alles korrekt ist, wird die Anfrage an den Server gesendet (Zeile 56).

Die Antwort des Servers wird in einer Platzhaltervariablen gespeichert, um Compilerwarnungen zu vermeiden. Der Grund dafür ist, dass wir nicht an der Reaktion der Funktion selbst interessiert sind. Das eigentliche Problem ist der Inhalt der Antwortstruktur. In Zeile 57 wird geprüft, ob das Ergebnis von TRADE_RETCODE_DONE abweicht. Wenn ja, ist ein Fehler aufgetreten. Der entsprechende Fehlercode wird auf dem Terminal ausgedruckt. Dies geschieht in Zeile 59.

Tritt ein Fehler auf, gibt die Funktion in Zeile 44 Null zurück. Andernfalls wird das Antwortticket des Servers zurückgegeben, das den Auftrag oder die Position angibt. Wir werden später darüber sprechen, wenn wir anfangen, diese Positionen/Bestellungen zu manipulieren. Im Moment senden wir nur eine Marktauftragsanfrage.

Eine solche Anforderung erfolgt in einer anderen Funktion, die in Zeile 66 erscheint. Die Funktion benötigt ein einziges Argument, das Kauf oder Verkauf angibt. Sie wird in den Zeilen 113 und 116 aufgerufen, wenn eine Nachricht von Chart Trade eine Aktion im Markt anweist. Aber woher kennt der Server den Stop-Loss, den Take-Profit, den Leverage oder die Instrumentendetails? Oder ob wir Kreuzaufträge verwenden? Nun. Hier kommt der nächste Schritt ins Spiel.


Ausfüllen der Anfrage

Wenn Sie sich die Server-Kommunikationsfunktion in Zeile 44 angesehen haben, werden Sie feststellen, dass in den Zeilen 51 und 56 eine Struktur verwendet wird, die nicht in dieser Funktion deklariert ist. Diese Struktur wird in C_Orders in Zeile 14 deklariert. Diese private, globale Struktur für die Klasse. Das heißt, der gesamte Körper der Klasse kann auf diese Variable zugreifen, aber kein Code außerhalb der Klasse hat Zugang zu ihr.

Diese Variable, die in der Funktion in Zeile 44 verwendet wird, muss also korrekt ausgefüllt werden. Diese Population wird in den Zeilen 66-94 durchgeführt. Die korrekte Befüllung der Struktur gewährleistet, dass der Server die gewünschte Anfrage ausführt: als Marktorder entweder Kauf oder Verkauf. Schwebende Aufträge werden später behandelt, ebenso wie die Änderung von Stop-Loss- und Take-Profit-Levels.

Um die Struktur aufzufüllen, benötigen wir mehrere Daten. Einige stammen aus Chart Trade, andere aus MetaTrader 5. Es gibt jedoch eine bestimmte logische Reihenfolge, die eingehalten werden sollte. Ermitteln wir zunächst den aktuellen Preis (Zeile 68). Achten Sie auf jedes Detail in dieser Zeile, denn jedes davon ist sehr wichtig.

Wir müssen auch wissen, wie hoch das Handelsvolumen sein wird. Viele Menschen haben in dieser Phase Schwierigkeiten, da das Volumen, das der Server erwartet, ein Vielfaches einer anderen Zahl ist. Das auf dem Handels-Chart angezeigte Volumen ist nicht das Handelsvolumen, sondern die Höhe des Hebels. Diese beiden Konzepte sind unterschiedlich, aber miteinander verbunden. Die Hebelwirkung vervielfacht das Mindestvolumen. Verwechseln Sie also nicht die Begriffe. Der Server benötigt auch die Anzahl der Dezimalstellen für das Instrument. Diese Informationen sind in Zeile 70 zu finden.

Und jetzt kommt das Wichtigste. Wir können damit beginnen, die Struktur aufzufüllen. Zunächst müssen wir die Struktur löschen, was in Zeile 72 geschieht. In jeder der folgenden Zeilen wird angegeben, was der Server genau tun soll. Diese in den Zeilen 73-86 dargestellte Anfrage, bei der jedes Feld entsprechend ausgefüllt wird, funktioniert für Aktien, OTC-Märkte und Forex. Es ist wichtig zu wissen, dass jedes dieser Felder seine eigene Bedeutung hat. Missverständnisse in allen Bereichen können zu finanziellen Verlusten führen. Eine ausführliche Erläuterung wird in einem zukünftigen Artikel über ausstehende Aufträge gegeben.

Schließlich wird die gefüllte Struktur auf dem Terminal ausgegeben, wo wir sie überprüfen können. Dies ist in den Zeilen 88-91 dargestellt. Es gibt zwar verschiedene Möglichkeiten, dies zu tun, aber der Einfachheit halber rufen wir ArrayPrint aus der MQL5 Standardbibliothek auf. Die Funktion gibt dann die Antwort auf die Anfrage zurück (Zeile 93).


Abschließende Überlegungen

Obwohl dieser Artikel nur einen Teil des Codes behandelt – nämlich das Senden von Marktaufträgen – kann diese Kopfdatei zusammen mit dem Indikator Chart Trade bereits Marktkäufe und -verkäufe ausführen. Es können noch einige Fragen offen bleiben, insbesondere in Bezug auf die Struktur von MqlTradeRequest. Keine Sorge, die ausstehenden Aufträge werden dies alles klären. Im nächsten Artikel werden wir uns weiter mit dem Quellcode des Expert Advisors beschäftigen.

Datei Beschreibung
Experts\Expert Advisor.mq5
Demonstriert die Interaktion zwischen Chart Trade und dem Expert Advisor (für die Interaktion ist ein Mauszeiger erforderlich)
Indicators\Chart Trade.mq5 Erstellt das Fenster für die Konfiguration des zu versendenden Auftrags (Mouse Study ist für die Interaktion erforderlich)
Indicators\Market Replay.mq5 Erstellt Steuerelemente für die Interaktion mit dem Wiedergabe-/Simulationsdienst (Mouse Study ist für die Interaktion erforderlich)
Indicators\Mouse Study.mq5 Ermöglicht die Interaktion zwischen den grafischen Steuerelementen und dem Nutzer (erforderlich für den Betrieb des Replay-Simulators und des Live-Markthandels)
Services\Market Replay.mq5 Erstellt und pflegt den Marktwiedergabe- und Simulationsdienst (Hauptdatei des gesamten Systems)

Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/12589

Beigefügte Dateien |
Anexo.zip (490.53 KB)
Von der Grundstufe bis zur Mittelstufe: Template und Typename (V) Von der Grundstufe bis zur Mittelstufe: Template und Typename (V)
In diesem Artikel werden wir einen letzten einfachen Anwendungsfall für Vorlagen untersuchen und die Vorteile und die Notwendigkeit der Verwendung von typename in Ihrem Code diskutieren. Auch wenn dieser Artikel auf den ersten Blick etwas kompliziert erscheint, ist es wichtig, ihn richtig zu verstehen, um später Vorlagen und typename verwenden zu können.
Neuronale Netze im Handel: Ein multimodaler, werkzeuggestützter Agent für Finanzmärkte (letzter Teil) Neuronale Netze im Handel: Ein multimodaler, werkzeuggestützter Agent für Finanzmärkte (letzter Teil)
Wir entwickeln weiterhin die Algorithmen für FinAgent, einen multimodalen Finanzhandelsagenten, der multimodale Marktdynamikdaten und historische Handelsmuster analysiert.
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.
Neuronale Netze im Handel: Ein multimodaler, werkzeuggestützter Agent für Finanzmärkte (FinAgent) Neuronale Netze im Handel: Ein multimodaler, werkzeuggestützter Agent für Finanzmärkte (FinAgent)
Wir laden Sie ein, FinAgent kennenzulernen, ein multimodales Finanzhandelsagenten-Framework zur Analyse verschiedener Datentypen, die die Marktdynamik und historische Handelsmuster widerspiegeln.