![Erstellen eines EA, der automatisch funktioniert (Teil 07): Kontoarten (II)](https://c.mql5.com/2/50/aprendendo_construindo_007_600x314.jpg)
Erstellen eines EA, der automatisch funktioniert (Teil 07): Kontoarten (II)
Einführung
Im vorangegangenen Artikel Erstellen eines EA, der automatisch funktioniert (Teil 06): Kontotypen (I), haben wir damit begonnen, einen Weg zu entwickeln, der sicherstellt, dass der automatisierte EA korrekt und im Rahmen seiner Zweckbestimmung arbeitet. In diesem Artikel haben wir die Klasse C_Manager erstellt, die als Administrator fungiert, sodass im Falle eines seltsamen oder fehlerhaften EA-Verhaltens der EA aus dem Chart entfernt wird.
Zu Beginn dieses Artikels haben wir erklärt, wie man verhindern kann, dass schwebende (pending) oder Markt-Aufträge (market orders) des EAs ausgelöst werden. Obwohl der dort gezeigte Mechanismus in der Lage ist, den EA zu unterstützen, haben wir einige andere Probleme im Zusammenhang mit der Interaktion zwischen dem EA und der Klasse C_Orders. Das Problem bezieht sich hauptsächlich auf NETTING-Konten. Dies ist eines der Themen, die in diesem Artikel behandelt werden.
Aber so oder so sollten Sie den automatisierten EA NIEMALS unbeaufsichtigt laufen lassen.
Erwarten Sie nicht, dass es ausreicht, den EA intelligent zu programmieren, denn das ist nicht der Fall. Sie sollten sich immer darüber im Klaren sein, was der automatische EA tut, und wenn er über seine vorgesehene Aktivität hinausgeht, sollten Sie ihn so schnell wie möglich aus dem Chart entfernen, bevor er außer Kontrolle gerät.
Neue Routinen für die Interaktion zwischen dem EA und der Klasse C_Orders
Alles, was in den vorangegangenen Artikeln gesagt wurde, ist wertlos, wenn der EA weiterhin in der Lage ist, auf die Klasse C_Orders zuzugreifen, wie unten dargestellt:
//+------------------------------------------------------------------+ void CreateOrder(const ENUM_ORDER_TYPE type, const double Price) { C_Orders::CreateOrder(type, Price, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade); } //+------------------------------------------------------------------+ void ToMarket(const ENUM_ORDER_TYPE type) { C_Orders::ToMarket(type, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade); } //+------------------------------------------------------------------+
Beachten Sie, dass der EA auch dann, wenn wir versuchen, die Dinge zu begrenzen und zu kontrollieren, immer noch Orders an den Markt und neue Orders an das Orderbuch senden kann. Dies ist eine Sicherheitslücke, denn wenn die C_Manager-Klasse während der EA-Initialisierung durchsetzen konnte, dass sie bestimmte Regeln befolgt, warum erlauben wir ihr dann danach, Orders zu platzieren und Marktoperationen durchzuführen? Wir müssen hier eine Grenze setzen, auch wenn sie sehr einfach ist. Ein einfacher Test verhindert oft viele mögliche Probleme. Fügen wir also etwas Kontrolle über diesen ganzen Bereich in Form einer Interaktion zwischen dem EA und dem in der Klasse C_Orders vorhandenen Auftragssystem hinzu.
//+------------------------------------------------------------------+ void CreateOrder(const ENUM_ORDER_TYPE type, const double Price) { if ((m_TicketPending > 0) || (m_bAccountHedging && (m_Position.Ticket > 0))) return; m_TicketPending = C_Orders::CreateOrder(type, Price, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade); } //+------------------------------------------------------------------+ void ToMarket(const ENUM_ORDER_TYPE type) { ulong tmp; if (m_bAccountHedging && (m_Position.Ticket > 0)) return; tmp = C_Orders::ToMarket(type, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade); m_Position.Ticket = (m_bAccountHedging ? tmp : (m_Position.Ticket > 0 ? m_Position.Ticket : tmp)); if (PositionSelectByTicket(m_Position.Ticket)) SetInfoPositions(); else m_Position.Ticket = 0; } //+------------------------------------------------------------------+
Wir haben einige Regeln hinzugefügt, damit der EA nicht so viele Freiheiten bei der Verwendung der Klasse C_Orders hat. Schauen wir uns an, was hier passiert. Beginnen wir mit der Funktion CreateOrder. Wenn wir einen Wert in der Variable haben, der das Ticket für schwebende Aufträge informiert, wird eine neue Order verweigert, aber er wird auch verweigert, wenn wir auf einem HEDGING-Konto mit einer offenen Position sind. So einfach ist das. Aber wenn diese Bedingungen es zulassen, können wir eine Anfrage senden, um einen schwebenden Auftrag zum Orderbuch hinzuzufügen, und wenn die Anfrage erfolgreich ist, erhalten wir das Ticket der Order, der platziert worden ist. Danach ist es uns nicht mehr möglich, eine neue Orders zu platzieren.
Jetzt kommt ein großes Detail, das sich in der Funktion ToMarket befindet. In diesem Fall wird die Order als Marktauftrag erteilt, d.h. zum besten verfügbaren Preis. Schauen wir uns nun die Bedingungen an, die es uns ermöglichen, einen Marktauftrag zu senden. Die Übermittlung einer Order ist nur möglich, wenn wir keine offene Position auf einem HEDGING-Konto haben. Hier sind die Einzelheiten: Wenn es möglich ist, einen Marktauftrag zu senden, wird dies getan, aber wir können den vom Aufruf zurückgegebenen Wert gar nicht erst verwenden. Dies ist darauf zurückzuführen, dass die Nummer des Tickets der Position abweichen kann, wenn wir auf dem NETTING-Konto sind. Wenn wir die Nummer direkt in die Nummer des Positionstickets setzen, können wir die aktuellen Ticketnummer verlieren, da es möglich ist, dass der Rückgabewert in diesem Fall nur vorübergehend ist. Das ist der Grund, warum wir hier diese neue Kontrolle haben. Handelt es sich um ein HEDGING-Konto, dann kann der zurückgegebene Wert sicher im Positionsticket gespeichert werden. Im Falle eines NETTING-Kontos wird er jedoch nur gespeichert, wenn das Positionsticket Null ist; andernfalls wird der Wert ignoriert. Sobald dies geschehen ist, können wir die Positionsdaten aktualisieren oder die Nummer des Positionstickets zurücksetzen, aber das hängt alles von der Prüfung ab.
Probleme mit dem NETTING-Konto im automatisierten EA
Es gibt ein potenziell gefährliches Problem bei der Verwendung eines automatisierten EA auf einem NETTING-Konto. Im letzten Artikel habe ich ein Problem aufgezeigt, das im HEDGING-Konto auftreten kann. Aber jetzt wollen wir ein anderes Problem untersuchen, das nur bei NETTING-Konten auftritt. Wenn der EA keine Sperre hat, wird er irgendwann auf dieses Schlupfloch stoßen, das viele EAs haben, von dem ihre Nutzer aber nichts wissen.
Das Problem ist das folgende: Bei einem NETTING-Konto erstellt der Handelsserver automatisch einen durchschnittlichen Positionspreis, wenn sich der Geldkurs (bid) bei einer Kauf- oder Verkaufsposition ändert. Wenn Sie auf die eine oder andere Weise SHORT gehen (verkaufen), werden sich sowohl der Durchschnittspreis als auch das Volumen der Position ändern.
Für einen EA, der manuell betrieben wird, gibt es hier kein Problem, da der Händler für das Senden aller Anfragen an den Server verantwortlich ist. Das Problem tritt bei einem automatisierten EA auf. In diesem Fall kann er ausgelöst werden, wenn eine bestimmte Lücke oder Schwachstelle in seiner Programmierung vorhanden ist. Einzelheiten: Das Problem liegt weder im Handelsserver noch in der MetaTrader 5-Plattform; das Problem liegt im EA.
Ich werde versuchen, es so zu erklären, dass es jeder verstehen kann, aber idealerweise sollten Sie ein wenig Wissen darüber haben, wie der Markt funktioniert, damit es leichter zu verstehen ist. Aber ich werde versuchen, die Frage so klar wie möglich zu formulieren.
Wenn der automatisierte EA einen Kauf- oder Verkaufsauftrag sendet, um eine Position zu eröffnen, tut er dies auf der Grundlage einer Art von Auslöser. Obwohl wir noch nicht über Auslöser gesprochen haben, werden wir bald dazu kommen. Aber das Problem ist nicht der Auslöser, denn in den allermeisten Fällen ist der Auslöser nicht verantwortlich.
Sobald die Position eröffnet ist, und zwar in einem NETTING-Konto, kann der EA aus dem einen oder anderen Grund die folgende Strategie anwenden: einen Teil des Volumens schließen und einen anderen eröffnen. Auf diese Weise wird der Durchschnittspreis in Bewegung geraten. Das Problem ist nur, dass der EA vielleicht anfängt, dies in einer wilden, verrückten und halluzinierten Weise zu tun. Wenn dies geschieht, kann er innerhalb von Minuten, manchmal sogar Sekunden, je nach Handelsvolumen, große Geldsummen verlieren.
Und genau das ist das Problem: Der EA startet eine Order, und dann bleibt er dort, ohne die Position zu schließen, und sendet neue Anfragen an den Server, um den Durchschnittspreis zu ändern. Dies geschieht oft ohne den Händler, der den EA überwacht oder überwachen sollte, da sich das angezeigte Volumen nicht ändert, wohl aber der Preis, und manche Händler bemerken diese Änderung nicht. Es kommt oft vor, dass die Position bereits einen großen Verlust verursacht, bevor der Händler überhaupt merkt, dass etwas nicht stimmt.
Obwohl einige automatisierte EAs absichtlich so programmiert sind, dass sie diese Art von Strategie verwenden, wissen oder erkennen einige Leute nicht, dass diese Art von Fehler in ihrem automatisierten EA vorhanden ist. In manchen Fällen, und hier stellt sich die Frage nach dem Auslöser, kann die Person eine Art von Auslöser verwenden, der den EA zum Kauf oder Verkauf veranlasst, und zwar in einer ganz bestimmten Marktsituation, und der EA kann genau das tun, was oben beschrieben wurde. Wenn der Händler sich dieser Tatsache bewusst ist, wird er aufmerksam sein. Wenn dieses Verhalten jedoch nicht erwartet wird, könnte der Händler, der den EA überwacht, am Ende durch das, was der EA tut, erschreckt werden.
Unterschätzen Sie das System nicht, auch wenn Sie ihm noch so sehr vertrauen und glauben, dass Ihr automatisierter EA sicher ist. Unterschätzen Sie das nicht. Denn es kann passieren, dass der EA eine Lücke hat, die Sie bei der Programmierung nicht vorgesehen haben. Aber zum Glück gibt es eine relativ einfache Möglichkeit, diesen Mangel zu beheben oder zumindest den Schaden ein wenig zu minimieren. Schauen wir uns also an, wie man das programmiertechnisch umsetzen kann.
Begrenzung des Handelsvolumens im EA
Die einfachste Möglichkeit, das im vorherigen Thema beschriebene Problem zumindest ein wenig zu reduzieren, besteht darin, das Volumen zu begrenzen, mit dem der EA tatsächlich arbeiten kann. Es gibt keine hundertprozentig ideale Methode, aber wir können versuchen, so weit wie möglich eine Form zu finden, die uns etwas Trost spendet. Die einfachste Möglichkeit besteht darin, das Volumen zu begrenzen, mit dem der EA während der gesamten Laufzeit arbeiten kann.
Achten Sie auf Folgendes: Ich spreche nicht davon, das Volumen einer offenen Position zu begrenzen, sondern das Volumen, das der EA während des gesamten Zeitraums handeln kann. Das heißt, der EA kann das x-fache des Mindestvolumens handeln, aber sobald das Limit erreicht ist, kann der EA keine neue Position mehr eröffnen. Es spielt keine Rolle, ob er eine Position hat, die einem Mindestvolumen entspricht, während das Limit das 50-fache dieses Volumens beträgt. Wenn der EA diese Quote von 50 bereits erreicht hat, kann er keine weiteren Positionen eröffnen oder die offene Position erhöhen.
Die Sperre basiert genau auf dieser Tatsache. Aber wir haben hier ein Detail: Ein 100%ig sichere Sperre gibt es aber nicht. Alles hängt von dem Händler ab, der den EA überwacht. Wenn der Händler versehentlich die Sperre ausschaltet und den EA neu startet, ist der Händler für jeden Fehler verantwortlich, der auftreten kann. Es kann vorkommen, dass der EA die Quote erreicht hat und der Händler den EA auf dem Chart neu starten möchte. In diesem Fall gibt es keine Sperre.
Um die Sperre zu implementieren, benötigen wir eine statische, globale und private Variable innerhalb der Klasse C_Manager. Das ist im folgenden Code dargestellt:
static uint m_StaticLeverage;
Um eine statische Variable innerhalb einer Klasse zu initialisieren, können wir jedoch nicht den Klassenkonstruktor verwenden. Die Initialisierung wird in diesem Fall außerhalb des Klassenkörpers implementiert, aber normalerweise innerhalb der Quelldatei, nämlich in der Header-Datei C_Manager.mqh. Außerhalb des Klassenkörpers wird dann folgender Code stehen:
uint C_Manager::m_StaticLeverage = 0;
Keine Angst, es ist nur eine statische Variable, die initialisiert wird. Für diejenigen, die es nicht wissen: Diese Initialisierung findet statt, noch bevor der Klassenkonstruktor tatsächlich referenziert wird. Bei einigen Arten von Code ist dies also recht nützlich. Die Tatsache, dass die Variable außerhalb des Klassenkörpers initialisiert wird, bedeutet jedoch nicht, dass sie auch außerhalb der Klasse zugänglich ist. Vergessen Sie nicht: Der Grund ist die Kapselung, alle Variablen müssen als privat deklariert werden. Dies macht die Klasse so robust wie möglich. So vermeiden wir Sicherheitslücken oder den Verlust der Zuverlässigkeit bei der Arbeit der Klasse.
Doch hier stellt sich eine weitere wichtige Frage: Warum verwenden wir eine private und statische globale Variable in der Klasse C_Manager? Könnten wir nicht eine Variable verwenden, die nicht zumindest statisch ist? Die Antwort ist NEIN. Der Grund dafür ist folgender: Wenn die MetaTrader 5 Plattform den EA unter irgendwelchen Umständen neu startet, gehen alle außerhalb einer statischen Variable gespeicherten Daten verloren. Das sollten Sie beachten. Ich meine, dass MetaTrader 5 den EA neu starten kann, nicht, dass Sie ihn löschen und dann erneut auf dem Chart ausführen. Dies sind zwei unterschiedliche Situationen. Wenn der EA aus dem Chart entfernt und dann neu gestartet wird, gehen alle Informationen, auch über statische Variablen, verloren. In diesen Fällen besteht die einzige Möglichkeit darin, die Daten in einer Datei zu speichern und sie dann durch Lesen dieser Datei wiederherzustellen. Ein Neustart bedeutet nicht, dass der EA wirklich gelöscht wurde. Dies kann in verschiedenen Situationen geschehen, die alle mit dem Auslösen des DeInit-Ereignisses zusammenhängen, das die Funktion OnDeInit im Code aufruft. Dieses Zurücksetzen betrifft nicht nur den EA, sondern auch die Indikatoren. Daher können die auf dem Chart laufenden Skripte gelöscht werden, wenn das Ereignis DeInit aktiviert ist. Da Skripte nicht zurückgesetzt werden (sie haben diese Eigenschaft nicht), „verlassen“ sie einfach das Chart, und MetaTrader 5 setzt sie nicht automatisch zurück.
Nun müssen wir eine Definition in den Code der Klasse einfügen, um den maximalen Faktor festzulegen, mal dem das Mindestvolumen vom EA höchstens gehandelt werden kann. Diese Definition wird im Folgenden dargestellt:
#define def_MAX_LEVERAGE 10
Wir haben bereits einen Ort, um das Mindestvolumen zu speichern, das der EA gehandelt hat, und wir haben eine Definition des maximalen Volumens, das verwendet werden kann. Jetzt können wir also eine Methode zur Berechnung dieses Volumens entwickeln, was der interessanteste Teil der Arbeit ist. Zuvor müssen wir jedoch noch einige Änderungen am Code aus dem vorherigen Artikel vornehmen:
//+------------------------------------------------------------------+ void CreateOrder(const ENUM_ORDER_TYPE type, const double Price) { if ((m_StaticLeverage >= def_MAX_LEVERAGE) || (m_TicketPending > 0) || (m_bAccountHedging && (m_Position.Ticket > 0))) return; m_TicketPending = C_Orders::CreateOrder(type, Price, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade); } //+------------------------------------------------------------------+ void ToMarket(const ENUM_ORDER_TYPE type) { ulong tmp; if ((m_StaticLeverage >= def_MAX_LEVERAGE) || (m_bAccountHedging && (m_Position.Ticket > 0))) return; tmp = C_Orders::ToMarket(type, m_InfosManager.FinanceStop, m_InfosManager.FinanceTake, m_InfosManager.Leverage, m_InfosManager.IsDayTrade); m_Position.Ticket = (m_bAccountHedging ? tmp : (m_Position.Ticket > 0 ? m_Position.Ticket : tmp)); if (PositionSelectByTicket(m_Position.Ticket)) SetInfoPositions(); else m_Position.Ticket = 0; } //+------------------------------------------------------------------+
Indem ich diese Prüfungen hinzufüge, sage ich, dass der EA die Operation nicht durchführen kann, wenn das platzierte Volumen das angegebene maximale Volumen überschreitet. Es gibt noch einige Details, die in der Zukunft geklärt werden müssen, aber für den Moment wird es so gemacht werden. Beachten Sie auch, dass eine Zeile aus dem Code entfernt wurde, weil sie die Kontoführung stört.
Nun brauchen wir einige Routinen, die uns helfen, mit dem EA zu kommunizieren, damit die Klasse C_Manager verwalten kann, was der EA tun wird. Zu diesem Zweck erstellen wir zunächst eine sehr unauffällige, aber dringend benötigte Funktion, wie im folgenden Code gezeigt:
inline void UpdatePosition(const bool bSwap = false) { int ret; if ((m_bAccountHedging) && (m_Position.Ticket > 0) && (bSwap)) SetUserError(ERR_Unknown); m_Position.Ticket = ((m_Position.Ticket == 0) && (bSwap) ? m_TicketPending : m_Position.Ticket); m_TicketPending = (bSwap ? 0 : m_TicketPending); if (PositionSelectByTicket(m_Position.Ticket)) { ret = SetInfoPositions(); m_StaticLeverage += (ret > 0 ? ret : 0); } }
Unterschätzen Sie diesen Code nicht. Obwohl es sich um einen Code von geringer Komplexität zu handeln scheint, ist es für die Klasse C_Manager äußerst wichtig, dass sie in der Lage ist zu verwalten, was der EA tut. Um diesen Code zu verstehen, muss man wissen, wie und wann der EA ihn aufrufen wird. Aber das werden wir später sehen, denn das Verfahren innerhalb des EA unterscheidet sich deutlich von dem, was viele Menschen tun.
Wenn wir uns den obigen Code ansehen, können wir einige Dinge feststellen. Wenn wir uns auf einem HEDGING-Konto mit einer offenen Position befinden und bSwap ‚true‘ ist, wird dies ein Fehler sein. In diesem Fall melden wir nur den Fehler, da er an anderer Stelle behandelt wird. Wenn die Variable für das Positionsticket leer ist und bSwap „true“ ist, bedeutet dies, dass der schwebende Auftrag zu einer Position wird. Hätten wir jedoch bereits eine offene Position, würde der schwebende Auftrag (auf dem NETTING-Konto) das Positionsvolumen und möglicherweise auch den Einstiegskurs verändern. Derartige Situationen werden in dieser Reihe analysiert.
Wenn bSwap auf true gesetzt ist, bedeutet dies, dass der schwebende Auftrag nicht mehr existiert, und dies wird hier korrigiert. Führen wir nun die folgende Prüfung durch: Wir prüfen, ob es eine offene Stelle gibt. Wenn dies der Fall ist, führen wir eine Prozedur aus, die die Daten aktualisiert. Dieses Verfahren berechnet die Differenz zwischen dem Volumen vor und nach der Aktualisierung und gibt dieses Volumen zurück.. Wenn die zurückgegebenen Daten positiv sind, bedeutet dies, dass das Volumen oder der Volumenfaktor der Partie gestiegen ist. Diese Situation ist bei NETTING-Konten üblich, aber bei HEDGING-Konten ist der Rückgabewert immer die aktuelle Losgröße. Wir fügen diesen zurückgegebenen Wert zu dem Wert hinzu, der sich zuvor in der statischen Variable befand. So können wir das Volumen berücksichtigen, das der EA während seiner Arbeit verwenden wird oder bereits verwendet hat.
Aber ohne zu viel darüber nachzudenken, werden Sie bald feststellen, dass wir eine andere Routine brauchen. Sie dient dazu, eine Position zu entfernen oder zu schließen. Er ist unten aufgeführt:
inline void RemovePosition(void) { if (m_Position.Ticket == 0) return; if (PositionSelectByTicket(m_Position.Ticket)) ClosePosition(m_Position.Ticket); ZeroMemory(m_Position); }
Hier liegt kein Fehler vor: Der EA schließt die offene Position oder informiert einfach die Klasse C_Manager, dass der Server die Position geschlossen hat, entweder weil die Limits (Take-Profit oder Stop-Loss) erreicht wurden oder weil etwas passiert ist, das das Schließen der Position veranlasst hat, das spielt keine Rolle. Aber wenn der EA diese Funktion fälschlicherweise aufruft, obwohl es keine offene Position gibt, rollen wir einfach zurück. Wenn es eine offene Position gibt, wird sie geschlossen, und am Ende werden alle Daten im Speicherbereich, in dem die Positionsdaten gespeichert sind, gelöscht.
Obwohl diese beiden Funktionen gut funktionieren, sind sie in vielen verschiedenen Situationen nicht sehr geeignet für das, was wir tatsächlich tun müssen. Seien Sie also nicht zu begeistert, wenn Sie diese Funktionen sehen. Stellen Sie sich nicht vor, dass sie für einen automatisierten EA mit einem hohen Maß an Robustheit geeignet sind, denn wie ich gerade sagte, sie funktionieren, aber sie sind nicht angemessen. Wir brauchen andere, bessere Funktionen für das, was wir hier aufbauen. In diesem Artikel werden wir dies jedoch nicht sehen, da ich zeigen muss, warum man eine andere Art von Funktion verwenden sollte. Für ein richtiges Verständnis ist es notwendig, den EA-Code zu zeigen — dies wird im nächsten Artikel geschehen.
Auf der Grundlage all dieser Arbeit haben wir nun ein System, das theoretisch robust und recht zuverlässig ist, sodass wir endlich damit beginnen können, es zu automatisieren, sodass es nur noch von einem menschlichen Händler überwacht werden muss. Achten Sie aber darauf, dass ich „theoretisch“ gesagt habe, denn es kann immer noch zu Fehlern im System kommen. Aber jetzt werden diese Probleme mit der Variablen _LastError überprüft, sodass wir sehen können, ob etwas schief gelaufen ist. Wenn es sich um einen schwerwiegenden Fehler handelt, wie z. B. bei der Verwendung der nutzerdefinierten Fehleraufzählung, die im vorherigen Artikel besprochen wurde, müssen wir den EA aus dem Chart entfernen.
Einen EA aus einem Chart zu entfernen, ist keine schwierige Aufgabe. Dies kann sogar ganz einfach durch den Aufruf der Funktion ExpertRemove geschehen. Aber diese Aufgabe ist nicht unser größtes Problem. Die eigentliche Schwierigkeit besteht darin, was mit der offenen Position und dem schwebenden Auftrag zu tun ist, die wahrscheinlich noch existieren.
Im schlimmsten Fall schließen Sie sie einfach oder löschen sie manuell. Aber was ist, wenn Sie 2 oder mehr EAs haben, die automatisch in einem Konto vom Typ HEDGING für denselben Vermögenswert laufen, und einer dieser EAs beschließt einfach, die Linie zu verlassen, und hier wird er aus dem Chart entfernt. Jetzt müssen Sie die Orders und Positionen im Toolbox-Fenster auf der Registerkarte „Handel“ (Abbildung 01) überprüfen und versuchen, die von dem schlechten EA, der geschlossen wurde, eröffneten Geschäfte zu schließen. In diesem Fall bedeutet „schlecht“ nicht, dass der EA schlecht programmiert ist. Ich denke, die Idee ist klar.
Abbildung 01 - Wo Sie auf der MetaTrader 5-Plattform nach Orders und Positionen suchen können
Hier kann uns die Programmierung ein wenig helfen, aber erwarten Sie keine Wunder. Sie hilft uns nur im Rahmen ihrer Möglichkeiten. Sehen wir uns also an, wie wir die Programmierung in diesem speziellen Fall anwenden können, in dem ein schlechter EA beschloss, herumzugehen und seine verrückten Dinge zu tun, und schließlich wegen seiner schlechten Gewohnheiten und seines Fehlverhaltens aus dem Chart ausgeschlossen wurde.
Verwendung des Destruktors
Der Destruktor ist eine Klassenfunktion, die zu keinem Zeitpunkt wirklich durch Code aufgerufen werden kann. Tatsächlich wird der Konstruktor, ebenso wie sein „Kollege“ Destruktor, nur einmal während der Lebensdauer der Klasse aufgerufen. Der Konstruktor wird aufgerufen, wenn die Klasse geboren wird, und der Destruktor wird aufgerufen, wenn die Klasse stirbt. In beiden Situationen werden Sie als Programmierer kaum sagen können, wann eine Klasse geboren wird und wann sie stirbt. Normalerweise wird dies vom Compiler erledigt, aber in bestimmten Fällen kann der Programmierer durch die Verwendung einiger Dinge im Code bestimmen, wann eine Klasse geboren wird und wann sie stirbt. Aber der Aufruf, ihm Leben einzuhauchen, kann sogar aufgrund der Parameter erfolgen, die wir in den Konstruktoren verwenden. Das Gleiche kann man nicht darüber sagen, was passiert, wenn sie stirbt.
Aber machen Sie sich darüber erst einmal keine Gedanken, Sie werden es besser verstehen, wenn wir zum EA-Code kommen.
Unabhängig davon, wann die Klasse stirbt, können wir ihr sagen, was sie tun soll, wenn das passiert. Auf diese Weise können wir der Klasse C_Manager mitteilen, dass sie, wenn sie den EA aus dem Chart entfernt, alles, was der EA getan und hinterlassen hat, beseitigen soll, d. h. die offene Position schließen und den schwebenden Auftrag im Orderbuch entfernen soll. Denken Sie jedoch daran, dies anhand der Toolbox, Abbildung 01, zu überprüfen, da es sein könnte, dass der EA aus dem Chart herausgeworfen wurde, der Destruktor jedoch nicht in der Lage war, seine Aufgabe auszuführen.
Zu diesem Zweck fügen wir der Fehleraufzählung einen neuen Wert hinzu:
class C_Manager : private C_Orders { enum eErrUser {ERR_Unknown, ERR_Excommunicate}; private :
Dieser Wert teilt dem Destruktor mit, dass der EA aus dem Chart entfernt wurde und alles, wofür der EA verantwortlich ist, rückgängig gemacht werden muss. Um zu verstehen, wie ein Destruktor diesen Wert erhalten kann, wenn er eigentlich keinen Wert über einen Parameter erhalten kann, sehen Sie sich den folgenden Code an:
~C_Manager() { if (_LastError == (ERR_USER_ERROR_FIRST + ERR_Excommunicate)) { if (m_TicketPending > 0) RemoveOrderPendent(m_TicketPending); if (m_Position.Ticket > 0) ClosePosition(m_Position.Ticket); Print("EA was kicked off the chart for making a serious mistake."); } }
Der Code ist sehr einfach. Wir werden den Wert _LastError überprüfen, um zu verstehen, was passieren könnte. Wenn also der Fehlerwert gleich dem Wert ist, den wir gerade zur Enumeration hinzugefügt haben, sollte der EA wegen schlechten Verhaltens aus dem Chart entfernt werden. In diesem Fall wird, wenn es einen schwebenden Auftrag gibt, ein Auftrag zur Löschung der Order an den Server gesendet. Wenn eine Position offen ist, wird außerdem eine Aufforderung zum Schließen an den Server gesendet. Schließlich werden wir Sie im Terminal über das Geschehene informieren.
Aber denken Sie daran, dass dies überhaupt nicht sicher ist. Wir versuchen nur, Hilfe bei der Programmierung zu bekommen. Als Händler müssen Sie aufmerksam sein und alle Oders oder Positionen entfernen, die der EA möglicherweise zurückgelassen hat, als er aus dem Chart entfernt wurde. Damit schließen wir dieses Thema ab, das sehr kurz war, aber ich hoffe, es war deutlich genug. Aber bevor wir diesen Artikel beenden, wollen wir noch eine Sache sehen, die wir im nächsten Thema behandeln werden.
Erstellen einer Fehlertoleranzstufe
Wenn Sie sich den gesamten Code in diesem und im vorherigen Artikel angeschaut haben und es geschafft haben, zu verstehen, was ich erkläre, müssen Sie sich vorstellen, dass die Klasse C_Manager sehr hart zum EA ist und keine Art von Fehler zulässt, auch nicht den kleinsten. Ja, das ist tatsächlich der Fall, aber wir können das ein wenig ändern. Es gibt einige Arten von Fehlern und Irrtümern, die nicht so schwerwiegend sind oder für die der EA nicht verantwortlich ist.
Ein solcher Fehler tritt auf, wenn der Server TRADE_RETCODE_MARKET_CLOSED meldet, weil der Markt geschlossen ist. Diese Art von Fehlern kann toleriert werden, da sie nicht vom EA verschuldet sind. Ein anderer Typ ist TRADE_RETCODE_CLIENT_DISABLES_AT, der erscheint, weil Algo-Handel auf der Plattform deaktiviert ist.
Es gibt verschiedene Arten von Fehlern, die ohne Verschulden des EA auftreten können, d.h. sie können aus unterschiedlichen Gründen auftreten. Daher ist es nicht ganz fair, zu hart mit dem EA umzugehen und ihn für alles verantwortlich zu machen, was schief gehen kann. Daher müssen wir einen Mechanismus schaffen, um bestimmte Arten von Fehlern zu kontrollieren und zu tolerieren. Wenn der Fehler nicht schwerwiegend zu sein scheint, können wir ihn ignorieren und den EA auf dem Chart belassen. Wenn es sich jedoch um einen wirklich schwerwiegenden Fehler handelt, können wir eine Entscheidung treffen, die von der Schwere des Fehlers abhängt.
Daher erstellen wir in der Klasse C_Manager eine öffentliche Funktion, damit der EA sie aufrufen kann, wenn er Zweifel an der Schwere eines möglichen Fehlers hat. Der Funktionscode ist unten abgebildet:
void CheckToleranceLevel(void) { switch (_LastError) { case ERR_SUCCESS: return; case ERR_USER_ERROR_FIRST + ERR_Unknown: Print("A serious error has occurred in the EA system. This one cannot continue on the chart."); SetUserError(ERR_Excommunicate); ExpertRemove(); break; default: Print("A low severity error has occurred in the EA system. Your code is:", _LastError); ResetLastError(); } }
Ich biete hier keine endgültige Lösung an, und sie ist auch nicht zu 100 % korrekt. Ich zeige nur, wie man vorgeht, um eine Möglichkeit zu schaffen, Fehler in einem EA zuzulassen. Der obige Code zeigt 2 Beispiele, bei denen die Toleranzen unterschiedlich sind.
Es besteht die Möglichkeit, dass ein schwerwiegenderer Fehler vorliegt, in diesem Fall wird der EA aus dem Chart entfernt. Die korrekte Vorgehensweise besteht darin, zwei Funktionen zu verwenden, von denen eine den EA-Ausnahmefehler konfiguriert und die andere einen Befehl zum Löschen des Fehlers festlegt. Daher wird der Destruktor der Klasse C_Manager versuchen, zu entfernen oder rückgängig zu machen, was der EA getan hat. Es gibt eine zweite Möglichkeit, bei der der Fehler weniger schwerwiegend ist. In diesem Fall zeigen wir dem Händler einfach eine Warnung an und entfernen die Fehleranzeige, sodass der Wert klar bleibt, wenn der Aufruf ohne Fehler erfolgt und die Funktion einfach zurückkehrt.
Idealerweise sollten wir hier die Fehlerbehandlung erleichtern, indem wir einzeln festlegen, welche Fehler gültig sind und welche nicht. Eine andere Sache ist, dass wir diesen Aufruf nicht innerhalb der C_Manager-Klasse haben, und die Fehlertoleranz wäre sehr hoch. Sie sollten das wirklich nicht tun. Sie können einen Aufruf der oben genannten Funktion zu bestimmten Zeiten hinzufügen, damit Sie nicht vergessen, dem EA Aufrufe hinzuzufügen. Im Moment wird dieser Aufruf jedoch innerhalb des EA-Codes an ganz bestimmten Stellen erfolgen.
Schlussfolgerung
Dieser Artikel ergänzt den vorherigen, sodass sein Inhalt nicht allzu schwer zu lesen und zu verstehen ist. Ich denke, es war genug Material vorhanden, um die Aufgabe zu erfüllen.
Ich weiß, dass viele Leute bereits einen Blick auf den EA-Code werfen möchten, um das hier Gezeigte zu nutzen, aber die Dinge sind nicht so einfach, wenn es sich um einen automatisierten EA handelt. Im nächsten Artikel werde ich versuchen, einige meiner Erfahrungen in diesem Bereich weiterzugeben, und wir werden die Vorsichtsmaßnahmen, Probleme und Risiken im Zusammenhang mit der EA-Kodierung betrachten. Wir werden uns nur auf den EA-Code konzentrieren, denn auf der Grundlage dieser beiden letzten Artikel werde ich im nächsten Teil dieser Serie etwas zu zeigen haben. Lernen Sie also in Ruhe und versuchen Sie zu verstehen, wie dieses Klassensystem funktioniert, denn im nächsten Artikel wird es noch viel mehr Material geben.
Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/11256
![Wie man einen Expert Advisor auswählt: Zwanzig starke Kriterien für die Ablehnung eines Handelsroboter](https://c.mql5.com/2/0/Avatar_Twenty_strong_criteria_to_reject_a_trading_bot.png)
![Erstellen eines EA, der automatisch funktioniert (Teil 06): Kontoarten (I)](https://c.mql5.com/2/50/aprendendo_construindo_006_avatar.png)
![Messen der Information von Indikatoren](https://c.mql5.com/2/51/Measuring_Indicator_Information_avatar.png)
![Neuronale Netze leicht gemacht (Teil 33): Quantilsregression im verteilten Q-Learning](https://c.mql5.com/2/50/Neural_Networks_Made_Easy_q-learning_avatar.png)
![MQL5 - Sprache von Handelsstrategien, eingebaut ins Kundenterminal MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.