English Русский 中文 Español 日本語 Português
preview
Erstellen eines EA, der automatisch funktioniert (Teil 08): OnTradeTransaktion

Erstellen eines EA, der automatisch funktioniert (Teil 08): OnTradeTransaktion

MetaTrader 5Handel | 5 April 2023, 14:34
619 0
Daniel Jose
Daniel Jose

Einführung

In früheren Artikeln: Erstellen eines EA, der automatisch funktioniert (Teil 06): Kontotypen (I) und Erstellen eines EA, der automatisch arbeitet (Teil 07): Kontotypen (II), haben wir uns darauf konzentriert, wie wichtig es ist, bei der Entwicklung eines EA, der automatisch handelt, vorsichtig zu sein.

Bevor wir wirklich verstehen können, wie der EA-Code für die Automatisierung funktionieren sollte, müssen wir verstehen, wie er mit dem Handelsserver interagiert. Schauen Sie sich die Abbildung 01 an:

Abbildung 01

Abbildung 01. Nachrichtenfluss


Abbildung 01 zeigt den Nachrichtenfluss, mit dem der EA Aufträge oder Anfragen an den Handelsserver senden kann. Achten Sie auf die Richtung der Pfeile.

Der einzige Moment, in dem die Pfeile bidirektional sind, ist, wenn die Klasse C_Orders mit der Funktion OrderSend eine Bestellung an den Server sendet, da sie zu diesem Zeitpunkt eine Antwort vom Server über die Struktur erhält. Abgesehen von diesem Punkt sind alle anderen Punkte richtungsweisend. Hier zeige ich jedoch nur den Prozess für die Übermittlung von Marktaufträgen oder für die Platzierung von Aufträgen im Orderbuch. Wir haben also ein sehr einfaches System.

Im Falle eines zu 100 % automatisierten EA gibt es immer noch einige Dinge, die wir brauchen. Und bei einem EA mit minimaler Automatisierung müssen wir noch einige Details hinzufügen. Alles findet zwischen dem EA und der Klasse C_Manager statt. Wir werden keinen Code in einem anderen Teil des EA hinzufügen. Nun, es gibt noch eine andere Sache. In einem zu 100 % automatisierten EA müssen wir die Klasse C_Mouse entfernen (da sie für einen zu 100 % automatisierten EA nicht von Nutzen ist). Es ist sehr wichtig zu verstehen, was ein Nachrichtenfluss ist, da wir sonst nicht in der Lage sein werden, mit weiteren Themen fortzufahren.


Hinzufügen von Kontroll- und Zugänglichkeitsfunktionen

Das größte Problem besteht darin, dass viele Nutzer der Sprache MQL5 einige der Funktionen zur Erstellung von EAs nicht nutzen, obwohl diese Sprache solche Funktionen bietet. Vielleicht geschieht dies aus Unwissenheit oder aus anderen Gründen, aber das spielt keine Rolle. Wenn Sie alle Funktionen von MQL5 nutzen wollen, müssen Sie zur Erhöhung der Robustheit und Zuverlässigkeit des Codes wirklich darüber nachdenken, einige der Ressourcen zu nutzen, die Ihnen diese Sprache zur Verfügung stellt.

Als erstes werden wir drei neue Funktionen in die Klasse C_Manager einfügen. Sie dienen der Klasse dazu, den EA freizugeben oder zu erfahren, was der EA zu tun gedenkt. Die erste dieser Funktionen ist unten dargestellt:

inline void EraseTicketPendig(const ulong ticket)
                        {
                                m_TicketPending = (ticket == m_TicketPending ? 0 : m_TicketPending);
                        }

Diese Funktion löscht den Wert des ausstehenden Tickets, wenn das informierte Ticket gleich dem ausstehenden Ticket ist. Normalerweise wird dies nicht passieren. Ein schwebender Auftrag wird vom EA nicht entfernt. Die Entfernung erfolgt in der Regel durch die Einmischung des Händlers oder des EA-Nutzers, was nicht ratsam ist. Stellt der EA jedoch fest, dass ein von ihm in das Orderbuch eingestellter schwebender Auftrag vom Nutzer gelöscht wurde, muss er die Klasse C_Manager informieren, damit diese dem EA ermöglicht, gegebenenfalls einen neuen schwebenden Auftrag in das Orderbuch einzustellen.

Die nächste neue Funktion ist unten dargestellt:

                void PedingToPosition(void)
                        {
                                ResetLastError();
                                if ((m_bAccountHedging) && (m_Position.Ticket > 0)) SetUserError(ERR_Unknown);
                                        else m_Position.Ticket = (m_Position.Ticket == 0 ? m_TicketPending : m_Position.Ticket);
                                m_TicketPending = 0;
                                if (_LastError != ERR_SUCCESS) UpdatePosition(m_Position.Ticket);
                                CheckToleranceLevel();
                        }

Der EA verwendet diesen Code, um der Klasse C_Manager mitzuteilen, dass ein schwebender Auftrag gerade in eine Position umgewandelt wurde oder dass Änderungen an der Position vorgenommen wurden. Bitte beachten Sie, dass die Klasse C_Manager bei der Ausführung dieser Funktion das Ticket für die schwebende Order löscht, damit der EA eine neue schwebende Order platzieren kann. Der Fall wird jedoch nur dann fortgesetzt, wenn kein kritischer Fehler vorliegt, der von der Funktion analysiert wird, die wir im vorherigen Artikel besprochen haben. Aber diese Funktion funktioniert nicht allein, sondern es wird eine weitere benötigt, die unten dargestellt ist:

                void UpdatePosition(const ulong ticket)
                        {
                                int ret;
                                
                                if ((ticket == 0) || (ticket != m_Position.Ticket)) return;
                                if (PositionSelectByTicket(m_Position.Ticket))
                                {
                                        ret = SetInfoPositions();
                                        m_StaticLeverage += (ret > 0 ? ret : 0);
                                }else ZeroMemory(m_Position);
                                ResetLastError();
                        }

Es gibt zwei weitere Funktionen, die in der Klasse C_Manager fehlen. Da es sich dabei aber um Automatisierungsfunktionen handelt, werden wir sie jetzt nicht im Detail behandeln.

Jetzt haben wir endlich die Klasse C_Manager und den EA, die miteinander befreundet sind, in einer viel vollständigeren Form. Beides kann funktionieren und dafür sorgen, dass sie nicht aggressiv oder unfreundlich werden. Der Nachrichtenfluss zwischen dem EA und der Klasse C_Manager entspricht somit dem in Abbildung 02:

Abbildung 02

Abbildung 02. Nachrichtenfluss mit neuen Funktionen


Dieser Ablauf mag zu kompliziert oder völlig unfunktional erscheinen, aber genau das ist bisher umgesetzt worden.

Wenn man sich Abbildung 02 ansieht, könnte man meinen, dass der EA-Code sehr komplex ist. Aber es ist viel einfacher als das, was viele Leute für einen notwendigen Code für einen EA halten. Vor allem, wenn es sich um einen automatisierten EA handelt. Denken Sie an das Folgende: Der EA generiert eigentlich keine Trades. Es ist lediglich ein Mittel oder Werkzeug für die Kommunikation mit dem Handelsserver. Es reagiert also eigentlich nur auf Auslöser, die auf es angewendet werden.

Auf der Grundlage dieses Verständnisses wollen wir nun den EA-Code in seinem aktuellen Zustand durchgehen, bevor er automatisiert wird. Aber für diejenigen, die es nicht gesehen haben, der EA-Code hat keine großen Änderungen seit dem letzten Artikel, in dem es erschienen war, die Erstellen eines EA, die automatisch funktioniert (Teil 05): Manuelle Auslöser (II). Die einzigen Änderungen, die tatsächlich vorgenommen wurden, sind nachstehend aufgeführt:

int OnInit()
{
        manager = new C_Manager(def_MAGIC_NUMBER, user03, user02, user01, user04, user08);
        mouse = new C_Mouse(user05, user06, user07, user03, user02, user01);
        (*manager).CheckToleranceLevel();

        return INIT_SUCCEEDED;
}

Eigentlich mussten wir nur eine neue Zeile hinzufügen. Dadurch konnte geprüft werden, ob ein schwerwiegender oder kritischer Fehler aufgetreten ist. Es stellt sich jedoch die Frage, wie der EA die Klasse C_Manager darüber informieren kann, was im Zusammenhang mit dem Auftragssystem geschieht. Viele Menschen wissen nicht, was sie in dieser Situation tun sollen und versuchen herauszufinden, wie sie erfahren können, was auf dem Handelsserver geschieht. Doch hier liegt die Gefahr.

Das erste, was Sie wirklich verstehen sollten, ist, dass die MetaTrader 5-Plattform und die MQL5-Sprache keine gewöhnlichen Werkzeuge sind. Sie werden nicht wirklich ein Programm erstellen, das ständig nach Informationen suchen muss. Der Grund dafür ist, dass das System auf Ereignissen und nicht auf Prozessen basiert. Bei der ereignisbasierten Programmierung muss man nicht in Schritten denken, sondern anders.

Um dies zu verstehen, denken Sie bitte an Folgendes: Wenn Sie mit dem Auto unterwegs sind, haben Sie im Grunde die Absicht, ein bestimmtes Ziel zu erreichen. Aber auf dem Weg dorthin werden Sie einige Dinge lösen müssen, die passieren werden und die scheinbar nicht miteinander verbunden sind. Aber all diese Dinge beeinflussen Ihre Fahrtrichtung, z. B. wenn Sie bremsen, beschleunigen oder den Weg ändern müssen, weil etwas Unvorhergesehenes passiert ist. Sie wissen, dass diese Ereignisse eintreten können, aber Sie haben keine Ahnung, wann sie eintreten werden.

Genau darum geht es bei der ereignisbasierten Programmierung: Wir erhalten Zugang zu einigen Ereignissen, die von der jeweiligen Sprache für eine bestimmte Aufgabe vorgesehen sind. Alles, was wir tun müssen, ist, eine Logik zu entwickeln, die die Probleme lösen kann, die ein bestimmtes Ereignis aufwirft, um zu einem brauchbaren Ergebnis zu kommen.

MQL5 bietet einige Ereignisse, die wir für jede Art von Situation behandeln können (und andere, die wir behandeln müssen). Viele Menschen sind ratlos, wenn sie versuchen, die Logik dahinter zu verstehen, aber es ist nicht kompliziert. Sobald Sie dies verstanden haben, wird das Programmieren viel einfacher werden. Denn die Sprache selbst gibt Ihnen die notwendigen Mittel an die Hand, um alle Probleme zu bewältigen.

Dies ist der erste Punkt: Sie verwenden hauptsächlich die Sprache MQL5, um Probleme zu lösen. Wenn das noch nicht ausreicht, fügen wir spezielle Funktionsweisen hinzu. Wir könnten eine andere Sprache wie C/C++ oder sogar Python verwenden, aber versuchen wir es zunächst mit MQL5.

Der zweite Punkt: Wir dürfen nicht versuchen, Informationen abzufangen, ganz gleich, woher sie kommen. Wir sollten, wann immer möglich, einfach die Ereignisse, die die MetaTrader 5 Plattform generiert, nutzen und darauf reagieren.

Der dritte Punkt: Wir verwenden keine Funktionen oder versuchen nicht, Ereignisse zu verwenden, die für unseren Code nicht wirklich nützlich sind. Wir verwenden genau das, was wir brauchen, und versuchen, immer das richtige Ereignis für die richtige Aufgabe zu nutzen.

Basierend auf diesen 3 Punkten haben wir 3 Optionen zur Auswahl, damit der EA mit der C_Manager Klasse oder einer anderen Klasse, die Daten von der MetaTrader 5 Plattform erhalten muss, interagieren kann. Die erste Option ist die Verwendung eines Ereignisauslösers für jedes neu eingegangene Ticket. Dieses Ereignis ruft die Funktion OnTick auf. Ich empfehle jedoch, diese Funktion nicht zu verwenden. Wir werden den Grund ein anderes Mal sehen.

Die zweite Möglichkeit ist die Verwendung eines Zeitereignisses, das die Funktion OnTime auslöst. Diese Option eignet sich jedoch nicht für das, was wir jetzt tun. Dies liegt daran, dass wir die Liste der Aufträge oder Positionen bei jedem Auslösen des Zeitereignisses überprüfen müssten. Dies ist überhaupt nicht effektiv und macht den EA zu einem toten Gewicht für die MetaTrader 5 Plattform.

Die letzte Option ist die Verwendung des Handelsereignisses, das die Funktion OnTrade auslöst. Sie wird jedes Mal aktiviert, wenn es eine Änderung im Auftragssystem gibt, d.h. wenn ein neuer Auftrag oder eine Änderung der Position vorliegt. Aber die Funktion OnTrade ist in einigen Fällen nicht sehr geeignet, während sie uns in anderen Fällen bestimmte Aufgaben ersparen kann und somit die Dinge viel einfacher macht. Anstelle von OnTrade verwenden wir OnTradeTransaction.


Was ist OnTradeTransaction und wofür wird es verwendet?

Es ist vielleicht die komplexeste Funktion zur Behandlung von Ereignissen, die MQL5 hat, daher sollten Sie diesen Artikel als gute Quelle nutzen, um mehr darüber zu erfahren. Ich werde versuchen, so viele Informationen wie möglich darüber zu geben, was ich über die Verwendung dieser Funktion verstanden und gelernt habe.

Um die Dinge einfacher zu erklären, zumindest in dieser Anfangsphase, lassen Sie uns den Funktionscode im EA betrachten:

void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result)
{
        switch (trans.type)
        {
                case TRADE_TRANSACTION_POSITION:
                        manager.UpdatePosition(trans.position);
                        break;
                case TRADE_TRANSACTION_ORDER_DELETE:
                        if (trans.order == trans.position) (*manager).PendingToPosition();
                        else (*manager).UpdatePosition(trans.position);
                        break;
                case TRADE_TRANSACTION_REQUEST: if ((request.symbol == _Symbol) && (result.retcode == TRADE_RETCODE_DONE) && (request.magic == def_MAGIC_NUMBER)) switch (request.action)
                        {
                                case TRADE_ACTION_DEAL:
                                        (*manager).UpdatePosition(request.order);
                                        break;
                                case TRADE_ACTION_SLTP:
                                        (*manager).UpdatePosition(trans.position);
                                        break;
                                case TRADE_ACTION_REMOVE:
                                        (*manager).EraseTicketPending(request.order);
                                        break;
                        }
                        break;
        }
}

Ich weiß, dass dieser Code vielen ziemlich seltsam vorkommt, vor allem denjenigen, die es gewohnt sind, andere Methoden zu verwenden, um herauszufinden, was mit ihren Aufträgen und Positionen geschieht. Aber ich garantiere Ihnen, wenn Sie wirklich verstehen, wie die Funktion OnTradeTransaction funktioniert, dann werden Sie sie in all Ihren EAs verwenden, weil sie wirklich sehr hilfreich ist.

Um zu erklären, wie dies funktioniert, werden wir es jedoch nach Möglichkeit vermeiden, in Form von Logdateidaten zu sprechen, denn wenn man versucht, die Logik anhand von Dateien oder Mustern in Logdateien zu erkennen, kann man verrückt werden. Das liegt daran, dass die Daten manchmal kein Muster aufweisen. Der Grund dafür ist, dass diese Funktion als eine Ereignisbehandlung agiert. Diese Ereignisse kommen vom Handelsserver, also vergessen Sie die Protokolldateien. Konzentrieren wir uns auf die Behandlung der Ereignisse, die vom Handelsserver gesendet werden, unabhängig von der Reihenfolge, in der sie erscheinen.

Im Wesentlichen werden wir uns hier mit drei Strukturen und deren Inhalten befassen. Diese Strukturen werden durch den Handelsserver gefüllt. Sie müssen sich darüber im Klaren sein, dass alles, was Sie hier tun, eine Verarbeitung dessen ist, was der Server bereitgestellt hat. Die Handelskonstanten, die wir hier überprüfen, sind das, was wir tatsächlich im EA brauchen. Je nachdem, was Sie erstellen, benötigen Sie möglicherweise mehr Konstanten. Welche das sind, können Sie in der Dokumentation Trade Transaction Types nachlesen. Sie werden sehen, dass es 11 verschiedene Enumerationen gibt, jede davon für etwas Bestimmtes.

Bitte beachten Sie, dass ich an einigen Stellen eine Variable verwende, die sich auf die MqlTradeTransaction-Struktur bezieht. Diese Struktur ist recht komplex, aber komplex in Bezug auf das, was der Server sieht und versteht. Aber für uns hängt es davon ab, welche Art von Dingen wir tatsächlich überprüfen, analysieren und wissen wollen. Was uns interessiert, ist das Feld „Typ“ dieser Struktur, denn es ermöglicht weitere Systeme. In diesem Code befassen wir uns mit drei Transaktionsarten, die vom Server ausgeführt werden: TRADE_TRANSACTION_REQUEST, TRADE_TRANSACTION_ORDER_DELETE und TRADE_TRANSACTION_POSITION. Aus diesem Grund werden sie hier verwendet.

Da es schwierig ist, eine Vorgangsart ohne ein Beispiel zu erklären, sehen wir uns zunächst TRADE_TRANSACTION_POSITION an, das nur eine Zeile hat:

                case TRADE_TRANSACTION_POSITION:
                        manager.UpdatePosition(trans.position);
                        break;

Dieses Ereignis wird immer dann ausgelöst, wenn in einer offenen Position etwas passiert — nicht in jeder Position, sondern nur in derjenigen, die in irgendeiner Weise verändert wurde. Der Server informiert darüber, und wir übergeben sie an die Klasse C_Manager, damit sie aktualisiert wird, wenn dies die vom EA beobachtete Position ist. Andernfalls wird sie ignoriert. Das spart uns viel Zeit, wenn wir herausfinden wollen, welche Position tatsächlich geändert wurde.

Der nächste Punkt auf der Liste ist TRADE_TRANSACTION_ORDER_DELETE. Der Code mag für viele verwirrend sein:

                case TRADE_TRANSACTION_ORDER_DELETE:
                        if (trans.order == trans.position) (*manager).PendingToPosition();
                        else (*manager).UpdatePosition(trans.position);
                        break;

Wenn ein Auftrag in eine Position umgewandelt wird, löst dieser Auftrag ein Ereignis aus, bei dem der Server meldet, dass der Auftrag gelöscht wurde. Dasselbe geschieht, und dasselbe Ereignis wird ausgelöst, wenn eine Position geschlossen wird. Der Unterschied zwischen dem Ereignis, das die Umwandlung eines Auftrags in eine Position meldet, und der Schließung der Position liegt in dem vom Server bereitgestellten Wert.

Wenn ein Auftrag in eine Position umgewandelt wird, erhalten wir den im Positionsticket angegebenen Wert, sodass wir C_Manager mitteilen, dass ein Auftrag in eine Position umgewandelt wurde. Wenn eine Position geschlossen wird, werden diese Werte anders sein. Es kann aber auch vorkommen, dass wir eine offene Position haben und ein Auftrag hinzugefügt wurde, durch den sich das Positionsvolumen verändert hat. In solchen Fällen sind die Werte in trans.order und trans.position unterschiedlich. In diesem Fall stellen wir eine Aktualisierungsanfrage an C_Manager.

In einigen Fällen kann dieses Ereignis von TRADE_TRANSACTION_POSITION begleitet werden. Dies ist jedoch nicht immer der Fall. Um die Erklärung zu erleichtern, werden die Informationen getrennt, da sie für das Verständnis dieses Codes sehr wichtig sind.

Betrachten wir zunächst den Fall, dass trans.order gleich trans.position ist — sie können gleich sein. Erwarten Sie also nicht, dass sie immer anders sein werden. Wenn sie gleich sind, startet der Server die Enumeration TRADE_TRANSACTION_ORDER_DELETE, die jedoch nicht allein erfolgt, sondern von anderen Aufzählungen begleitet wird. Wir müssen uns nicht mit allen befassen, sondern nur mit diesem einen. Der Server teilt uns mit, dass der Auftrag soeben in eine Position umgewandelt wurde. Zu diesem Zeitpunkt wird der Auftrag geschlossen und die Position wird mit demselben Ticketwert wie der geschlossene Auftrag eröffnet.

Es kann jedoch vorkommen, dass der Server uns die Enumeration TRADE_TRANSACTION_POSITION nicht sendet. Es kann sein, dass wir zunächst auf diese Enumeration warten, aber der Server wird sie einfach nicht auslösen. Aber mit Sicherheit wird er die Entfernung auslösen. Die angegebenen Werte sind gleich. In diesem Fall wissen wir, dass es sich um einen Auftrag handelt, der im Auftragsbuch stand und zu einer Position wurde, aber bei Marktaufträgen funktioniert alles ein wenig anders. Wir werden diesen Fall später sehen.

Wenn nun trans.order von trans.position abweicht, wird der Server auch andere Enumerationen auslösen. Aber auch hier gilt: Verlassen Sie sich nicht darauf, dass etwas Bestimmtes kommt. Es kann vorkommen, dass der Server das nicht auslöst, aber die, die ich verwende, wird ausgelöst. In diesem Fall bedeutet dies, dass die Position aus irgendeinem Grund, den wir hier nicht analysieren, gerade geschlossen wurde. In jedem Fall erhalten wir Informationen über die Strukturen, die durch das Ereignis TradeTransaction empfangen werden. Deshalb ist diese Ereignisbehandlung so interessant: Man muss nicht auf die Suche nach den Informationen gehen. Die Veranstaltungen sind da, man muss nur die richtige Struktur aufsuchen und die Informationen lesen. Ist es klar, dass die Kontrollen auf diese Weise durchgeführt werden?

In Programmen, die diese Ereignisbehandlung nicht verwenden, erstellt der Programmierer normalerweise eine Schleife, um alle offenen Positionen oder schwebenden Aufträge durchzugehen und herauszufinden, welche ausgeführt oder geschlossen wurden. Das ist reine Zeitverschwendung, denn dadurch ist der EA mit völlig nutzlosen Dingen beschäftigt, die leichter zu erfassen sind. Das liegt daran, dass der Handelsserver bereits die ganze Arbeit für uns erledigt hat und uns darüber informiert, welcher schwebende Auftrag geschlossen, welche Position eröffnet oder welche Position geschlossen wurde. Und wir hier erstellen Schleifen, um diese Informationen herauszufinden.

Jetzt kommen wir zu dem Teil, der am längsten dauern wird, und dennoch werde ich nicht alle Fälle behandeln. Der Grund ist derselbe wie im vorherigen Fall: Es ist nicht einfach, alle Fälle zu erklären, ohne Beispiele zu haben. Was hier erklärt wird, wird jedoch vielen Menschen helfen. Der Einfachheit halber sehen wir uns das Fragment an, das wir jetzt untersuchen werden. Es lautet wie folgt:

                case TRADE_TRANSACTION_REQUEST: if ((request.symbol == _Symbol) && (result.retcode == TRADE_RETCODE_DONE) && (request.magic == def_MAGIC_NUMBER)) switch (request.action)
                        {
                                case TRADE_ACTION_DEAL:
                                        (*manager).UpdatePosition(request.order);
                                        break;
                                case TRADE_ACTION_SLTP:
                                        (*manager).UpdatePosition(trans.position);
                                        break;
                                case TRADE_ACTION_REMOVE:
                                        (*manager).EraseTicketPending(request.order);
                                        break;
                        }
                        break;

Diese Enumeration TRADE_TRANSACTION_REQUEST wird in fast allen Fällen ausgelöst. Es wäre ziemlich seltsam, wenn es nicht so wäre. Vieles, was wir an Tests durchführen können, lässt sich also damit erledigen. Da es sich aber um eine Enumeration handelt, die der Server häufig abfeuert, müssen wir die Dinge darin filtern.

Normalerweise löst der Server diese Enumeration nach einer Anforderung durch den EA oder die Plattform aus. Dies ist der Fall, wenn der Nutzer etwas im Zusammenhang mit dem Auftragssystem tut. Verlassen Sie sich aber nicht jedes Mal darauf, denn manchmal löst der Server diese Aufzählung einfach aus. Manchmal ohne ersichtlichen Grund, deshalb müssen wir filtern, was uns mitgeteilt wird.

Zuerst filtern wir das Asset. Sie können dafür jede beliebige Struktur verwenden, aber ich bevorzuge diese. Als Nächstes prüfen wir, ob die Anfrage vom Server akzeptiert wird, wozu wir diesen Test verwenden. Und schließlich prüfen wir die magische Zahl, um die Dinge weiter zu filtern. Jetzt kommt der verwirrendste Teil. Weil Sie nicht wissen, wie Sie den Rest des Codes ausfüllen sollen.

Wenn wir einen Schalter verwenden, um den Aktionstyp zu prüfen, analysieren wir nicht (und werden es auch nicht tun) die auf dem Server durchgeführte Aktion. Das ist nicht das, was wir tatsächlich tun werden. In der Tat werden wir genau eine Gegenprüfung dessen durchführen, was entweder vom EA oder von der Plattform an den Server gesendet wurde. Es gibt 6 Arten von Aktionen, die klassisch sind. Sie sind Teil der Enumeration ENUM_TRADE_REQUEST_ACTIONS. Um die Aufgabe zu vereinfachen, sehen wir uns die folgende Tabelle an. Sie ist dieselbe wie in der Dokumentation. Ich habe es verwendet, um die Erklärung zu erleichtern, aber meine Beschreibung weicht etwas von der Dokumentation ab.

Art der Aktion Beschreibung der Aktion
TRADE_ACTION_DEAL Einen Handelsauftrag erteilen, der zum Marktpreis ausgeführt werden soll
TRADE_ACTION_PENDING Einen Auftrag in das Auftragsbuch stellen, der gemäß den angegebenen Parametern ausgeführt werden soll
TRADE_ACTION_SLTP Ändern von Stop-Loss- und/oder Take-Profit einer Position
TRADE_ACTION_MODIFY Ändern der Parameter eines schwebenden Auftrags, der sich im Auftragsbuch befindet
TRADE_ACTION_REMOVE Löschen eines schwebenden Auftrags, der sich noch im Auftragsbuch befindet
TRADE_ACTION_CLOSE_BY Position schließen

Tabelle 01

Wenn Sie wirklich verfolgen, was wir seit Beginn dieser Artikelserie programmiert haben, aber nicht richtig aufgepasst haben, dann müssen Sie beim Programmieren nachsehen, wo das Feld Aktionstyp in unserem Code verwendet wurde. Die Ereignisbehandlung von OnTradeTransaction wird hier nicht erwähnt, da sie nicht zählt. Diese Zähler wurden bereits verwendet. Aber wo? In der Klasse C_Orders.

Öffnen Sie den Quellcode und achten Sie auf die folgenden Prozeduren in der Klasse C_Orders: CreateOrder, ToMarket, ModifyPricePoints und ClosePosition. Wir werden jede von ihnen besprechen, außer ClosePosition, wo ich die Enumeration TRADE_ACTION_CLOSE_BY nicht verwende.

Warum ist sie hier in der Ereignisbehandlung durch OnTradeTransaction so wichtig? Der Grund dafür ist, dass es sich um dieselbe Enumeration handelt, die wir sehen werden, wenn wir analysieren, auf welche Aktionsart sich die Enumeration TRADE_TRANSACTION_REQUEST bezieht. Deshalb sehen wir im Code der Ereignisbehandlung OnTradeTransaction TRADE_ACTION_DEAL und TRADE_ACTION_SLTP, sowie TRADE_ACTION_REMOVE — der EA sollte genau darauf achten.

Aber was ist mit dem Rest? Für die Erstellung eines automatisierten EA sind andere Typen nicht wichtig, da sie für andere Dinge verwendet werden. Wenn Sie sehen möchten, wie andere Typen angewandt werden, lesen Sie den Artikel Entwicklung eines Trading EA von Grund auf (Teil 25): Bereitstellung von Systemrobustheit (II), in dem ich zeige, wie die anderen Enumerationen verwendet werden können. 

Nachdem ich erklärt habe, woher diese Fälle kommen, wollen wir nun aufschlüsseln, was die einzelnen Fälle bewirken, beginnend mit dem unten abgebildeten Fall:

        case TRADE_ACTION_DEAL:
                (*manager).UpdatePosition(request.order);
                break;

Der Enumerator wird aufgerufen, wenn ein Marktauftrag ausgeführt wird. Aber nicht nur in diesem Fall. Es gibt eine zweite, in der es auch heißt. Als ich über TRADE_TRANSACTION_ORDER_DELETE sprach, erwähnte ich, dass es einen Fall gibt, in dem trans.order und trans.postion gleich sein können. Dies ist der zweite Fall, wenn der Server TRADE_ACTION_DEAL auslöst. Wir können also jetzt den Wert des Tickets als offene Position hinzufügen. Beachten Sie aber, dass, wenn etwas passiert, z.B. eine andere Position noch offen ist, ein Fehler auftritt, der zum Abbruch des EAs führt. Es wird hier nicht gezeigt, ist aber im Code von UpdatePosition zu sehen. 

Siehe den nächsten Code unten:

        case TRADE_ACTION_SLTP:
                (*manager).UpdatePosition(trans.position);
                break;

Diese Enumeration wird ausgelöst, wenn die Grenzwerte, bekannt als Take-Profit und Stop-Loss, geändert werden. Es werden lediglich die Werte von Stop-Loss und Take-Profit aktualisiert. Diese Version ist sehr einfach, und es gibt Möglichkeiten, sie ein wenig interessanter zu gestalten, aber das reicht erst einmal aus. Und die letzte Enumeration, die wir im Code haben werden, ist direkt darunter:

        case TRADE_ACTION_REMOVE:
                (*manager).EraseTicketPending(request.order);
                break;

Dieser Code wird ausgelöst, wenn ein Auftrag gelöscht wird, und wir müssen die Klasse C_Manager benachrichtigen, damit der EA einen ausstehenden Auftrag senden kann. Normalerweise wird ein schwebender Auftrag nicht aus dem Auftragsbuch entfernt, aber es kann sein, dass der Nutzer dies getan hat. Wenn ein Auftrag versehentlich oder absichtlich aus dem Auftragsbuch entfernt wird und der EA die C_Manager-Klasse nicht benachrichtigt, verhindert dies, dass der EA einen weiteren schwebenden Auftrag sendet.


Schlussfolgerung

In diesem Artikel haben wir uns angesehen, wie man das Ereignisbehandlungssystem nutzen kann, um Probleme im Zusammenhang mit dem Auftragssystem schneller und besser zu bearbeiten. Mit diesem System wird der EA schneller arbeiten, sodass er nicht ständig nach den benötigten Daten suchen muss. Wir haben es zwar noch mit einem EA zu tun, der über keinerlei Automatisierungsgrad verfügt, aber bald werden wir eine - wenn auch einfache - Automatisierung hinzufügen, damit der EA Breakeven und Trailing Stop verwalten kann.

Die angehängte Datei enthält die vollständige Version des Codes, den wir in den letzten drei Artikeln behandelt haben. Ich empfehle Ihnen, diesen Code sorgfältig zu studieren, um zu verstehen, wie alles tatsächlich funktioniert, da er Ihnen bei den nächsten Schritten unserer Arbeit sehr helfen wird.


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

Beigefügte Dateien |
Neuronale Netze leicht gemacht (Teil 34): Vollständig parametrisierte Quantilfunktion Neuronale Netze leicht gemacht (Teil 34): Vollständig parametrisierte Quantilfunktion
Wir untersuchen weiterhin verteilte Q-Learning-Algorithmen. In früheren Artikeln haben wir verteilte und Quantil-Q-Learning-Algorithmen besprochen. Im ersten Algorithmus haben wir die Wahrscheinlichkeiten für bestimmte Wertebereiche trainiert. Im zweiten Algorithmus haben wir Bereiche mit einer bestimmten Wahrscheinlichkeit trainiert. In beiden Fällen haben wir a priori Wissen über eine Verteilung verwendet und eine andere trainiert. In diesem Artikel wenden wir uns einem Algorithmus zu, der es dem Modell ermöglicht, für beide Verteilungen trainiert zu werden.
Datenwissenschaft und maschinelles Lernen (Teil 10): Ridge-Regression Datenwissenschaft und maschinelles Lernen (Teil 10): Ridge-Regression
Die Ridge-Regression ist ein einfaches Verfahren zur Reduzierung der Modellkomplexität und zur Vermeidung einer Überanpassung, die bei einer einfachen linearen Regression auftreten kann.
Neuronale Netze leicht gemacht (Teil 35): Modul für intrinsische Neugier Neuronale Netze leicht gemacht (Teil 35): Modul für intrinsische Neugier
Wir untersuchen weiterhin Algorithmen für das verstärkte Lernen. Alle bisher betrachteten Algorithmen erfordern die Erstellung einer Belohnungspolitik, die es dem Agenten ermöglicht, jede seiner Aktionen bei jedem Übergang von einem Systemzustand in einen anderen zu bewerten. Dieser Ansatz ist jedoch ziemlich künstlich. In der Praxis gibt es eine gewisse Zeitspanne zwischen einer Handlung und einer Belohnung. In diesem Artikel werden wir einen Algorithmus zum Trainieren eines Modells kennenlernen, der mit verschiedenen Zeitverzögerungen zwischen Aktion und Belohnung arbeiten kann.
MQL5 Kochbuch — Datenbank für makroökonomische Ereignisse MQL5 Kochbuch — Datenbank für makroökonomische Ereignisse
Der Artikel behandelt die Möglichkeiten des Umgangs mit Datenbanken, die auf der SQLite-Engine basieren. Die Klasse CDatabase wurde aus Gründen der Bequemlichkeit und der effizienten Nutzung von OOP-Prinzipien entwickelt. Anschließend ist sie an der Erstellung und Verwaltung der Datenbank für makroökonomische Ereignisse beteiligt. Der Artikel enthält Beispiele für die Verwendung mehrerer Methoden der CDatabase-Klasse.