English Русский Español Português
preview
Von der Grundstufe bis zur Mittelstufe: Objektereignisse (I)

Von der Grundstufe bis zur Mittelstufe: Objektereignisse (I)

MetaTrader 5Beispiele |
14 0
CODE X
CODE X

Einführung

Im vorigen Artikel „ Von der Grundstufe zur Mittelstufe: Objekte (IV)“ haben wir gezeigt, wie ein in MetaTrader 5 verfügbares Objekt modifiziert werden kann, um ein anderes Objekt zu erstellen. Dies geschah zu einem Zweck, der durchaus interessant und an sich recht faszinierend ist. In jenem Artikel, mein lieber Leser, wurde Ihnen auch eine kleine Herausforderung gestellt, deren Lösung ich nicht zeigen werde. Der Grund dafür ist, dass ich Sie dazu ermutigen möchte, das Artikelmaterial zu üben und zu studieren, damit Sie lernen, die Probleme, die beim Lernen und Implementieren neuer Ideen sicherlich auftreten werden, selbst zu lösen.

Obwohl diese Aufgabe sehr einfach zu lösen ist und das Problem selbst die Verwendung des Codes zu Studienzwecken nicht verhindert, denke ich, dass Sie viel stolzer auf sich sein werden und sich sicherer in dem fühlen, was Sie lernen, wenn Sie es selbst lösen können, indem Sie jede Situation erforschen und analysieren, bis Sie die bestmögliche Lösung finden. Daher werden wir uns in diesem Artikel mit einem weiteren Thema befassen, das in gewissem Sinne mit der Arbeit mit grafischen Objekten zusammenhängt, sich jedoch etwas von dem unterscheidet, was bisher gezeigt wurde.

Sie ahnen vielleicht schon, dass wir diesem Thema beträchtliche Aufmerksamkeit schenken, vielleicht sogar mehr, als viele Leute für wirklich notwendig halten würden. Bevor wir tiefer in die Möglichkeiten von MQL5 eintauchen können, müssen wir einige Dinge verstehen. All dies dient einem umfassenderen Ziel: der Erstellung komplexerer Anwendungen für spezifische Zwecke, Anwendungen, die sich von allem unterscheiden, was wir in anderen Programmen finden werden, zumindest wenn wir von MetaTrader 5 sprechen.

Gut, kommen wir zu einem neuen Thema. Dies wird es uns ermöglichen, mit der Erörterung des Hauptthemas dieses Artikels zu beginnen.


Objektereignisse

Bis zu diesem Punkt haben wir gezeigt und erklärt, wie man mit Ereignissen arbeitet, die vom Benutzer bei der Interaktion mit MetaTrader 5 generiert werden, und wie wir diese Ereignisse im Chart verarbeiten können. Zum Beispiel, wenn wir eine Taste drücken oder die Maus verwenden, um eine Aktion auszuführen. Das Platzieren eines Objekts auf dem Chart ist eine solche Aktion: Obwohl dies meist mit der Maus durchgeführt wird, generiert es auch andere damit verbundene Ereignisse.

Diese Ereignisse veranlassen MetaTrader 5 im Wesentlichen dazu, andere Ereignisse auszulösen, die in diesem Fall mit Objekten zusammenhängen. Aus diesem Grund werden sie anders behandelt, oder zumindest ist es das, was erwartet wird. MetaTrader 5 generiert diese Ereignisse speziell, um dem Programmierer und folglich der Anwendung selbst dabei zu helfen, jede Aktion zu verarbeiten, die an einem Objekt im Chart ausgeführt wird.

Diese Ereignisse können durch einen Mausklick, eine Bewegung, eine Erstellung, eine Löschung oder sogar durch das Ändern einer der Eigenschaften eines Objekts ausgelöst werden. Allerdings werden nicht alle Ereignisse ausgelöst, da einige davon aktiviert werden müssen. Der Grund ist sehr einfach: Standardmäßig sind sie in MetaTrader 5 deaktiviert. Dies funktioniert auf die gleiche Weise wie Mausereignisse. Die Anwendung ist möglicherweise nicht daran interessiert, Benachrichtigungen über solche Ereignisse zu erhalten, daher ignoriert MetaTrader 5 diese Ereignisse einfach. Das Ergebnis ist eine relativ performante Umgebung mit einer geringeren Wahrscheinlichkeit für Leistungsprobleme oder sogar Probleme mit der Stabilität der Plattform selbst.

Aber es gibt Fälle, in denen solche Ereignisse notwendig werden. In dieser Situation müssen wir verstehen, wie wir sie handhaben, da es notwendig sein kann, Korrekturen oder Anpassungen gerade aufgrund von Änderungen vorzunehmen, die der Benutzer an einem grafischen Objekt vorgenommen hat.

Änderungen an einem grafischen Objekt manuell zu analysieren, ist nichts, was Sie, lieber Leser, tun möchten: Abgesehen davon, dass es viel CPU-Zeit verbraucht, macht es den Code absurd kompliziert. Aber gerade weil MetaTrader 5 uns Informationen über Änderungen im Chart liefert, können wir den Arbeitsaufwand für die Überwachung jedes einzelnen darauf platzierten Objekts erheblich reduzieren. Dies ermöglicht es uns, genau zu wissen, wann, wo und warum der Benutzer ein Objekt geändert hat, dessen einziger Zweck darin besteht, Informationen bereitzustellen.

An diesem Punkt erkennen Sie vielleicht noch nicht, wie wichtig die von MetaTrader 5 generierten Ereignisse sind, um unsere Anwendung über Objektänderungen zu benachrichtigen. Darüber hinaus erkennen Sie vielleicht nicht vollständig, wie ernsthaft ein böswilliger Benutzer den Betrieb Ihrer Anwendung stören oder beschädigen kann, wenn er beginnt, bestimmte Eigenschaften einiger Objekte zu ändern. Genau deshalb müssen wir über Objektereignisse sprechen. Dies ist zweifellos ein Thema, das Ihnen helfen kann, Probleme zu vermeiden oder sogar die Ursachen bestimmter Fehler zu verstehen, die während der gesamten Lebensdauer Ihrer Anwendung auftreten können.

Durch die Aktualisierung Ihrer Anwendung können Sie auch das Risiko von Fehlern verringern. Gleichzeitig könnten Sie jedoch Probleme übersehen, deren Analyse wirklich wichtig ist.

Da bestimmte Ereignisse, die von MetaTrader 5 als Ergebnis von Aktionen an einem Objekt generiert werden, je nach Anwendung oft unterschiedlich interpretiert werden können, werden wir nicht versuchen, ein festes Modell oder Protokoll für die Implementierung zu erstellen. Ich möchte, dass Sie, lieber Leser, versuchen, das Konzept zu verstehen, das verwendet werden wird. Ich möchte auch, dass Sie verstehen, dass es Zeiten gibt, in denen jede Aktion überwacht werden muss, und Zeiten, in denen wir bestimmte Arten von Aktivitäten mit einem Objekt völlig ignorieren können, unabhängig davon, ob es sich um ein Objekt handelt, das unsere Anwendung auf dem Chart platziert hat, oder um eines, das der Benutzer manuell zum selben Chart hinzugefügt hat. Für alles gibt es eine Zeit. Versuchen Sie also zuerst, das Konzept selbst zu verstehen, anstatt den Code als solchen, da sich der Code radikal ändern kann.

Bevor wir also beginnen, muss eine Sache klargestellt werden. In der Regel ist die Standardmethode, mit der MetaTrader 5 ein Objekt handhabt, möglicherweise nicht die geeignetste, wenn wir es mit einer spezifischeren Aufgabe zu tun haben, bei der wir etwas implementieren, um ein ganz bestimmtes Ziel zu erreichen. In solchen Situationen müssen wir zusätzliche Regeln aufstellen, neben denen, die MetaTrader 5 bereits standardmäßig verwendet.

Und damit die Regeln, die wir in unserer Anwendung festlegen, befolgt werden, nutzen wir den integrierten Mechanismus von MetaTrader 5, der uns wissen lässt, was mit einem bestimmten Objekt passiert ist. Dies macht es überflüssig, ständig zu überwachen, was der Benutzer mit dem einen oder anderen Objekt tun könnte. Wenn mit einem Objekt etwas geschieht – egal ob der Benutzer ein neues Objekt auf dem Chart platziert, es ändert oder sogar löscht –, wird MetaTrader 5 uns benachrichtigen, und wir können die notwendigen Maßnahmen ergreifen.

Dies zu verstehen ist äußerst wichtig, vielleicht sogar wichtiger als das Verständnis des Codes selbst. Auf jeden Fall müssen einige Ereignisse aktiviert werden, während andere nicht aktiviert werden müssen. Den richtigen Zeitpunkt zu kennen, um diese Ereignisse zu aktivieren oder sogar zu deaktivieren, ist etwas, das Sie durch Übung lernen müssen. Auf jeden Fall müssen wir irgendwo anfangen. Gehen wir also so einfach und schrittweise wie möglich vor. Beginnen wir mit dem unten stehenden Code:

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #define def_Prefix  "Demo"
005. //+------------------------------------------------------------------+
006. #define macro_NameObject  def_Prefix + (string)(ObjectsTotal(0) + 1)
007. //+------------------------------------------------------------------+
008. #include <Tutorial\File 01.mqh>
009. //+------------------------------------------------------------------+
010. input double    user01 = 1.5;                   //Stop-Target Relationship
011. input bool      user02 = true;                  //Extend lines to the right
012. //+------------------------------------------------------------------+
013. st_Cross gl_Cross;
014. //+------------------------------------------------------------------+
015. int OnInit()
016. {
017.     gl_Cross.Init();
018.     IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix);
019.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
020.     ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false);
021. 
022.     return INIT_SUCCEEDED;
023. };
024. //+------------------------------------------------------------------+
025. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
026. {
027.     return rates_total;
028. };
029. //+------------------------------------------------------------------+
030. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
031. {
032. #define macro_CLEAN_EVENT   {                               \
033.             isPaint = "";                                   \
034.             gl_Cross.Hide();                                \
035.             bMouseL = false;                                \
036.             ChartSetInteger(0, CHART_MOUSE_SCROLL, true);   \
037.                             }
038. 
039.     st_TimePrice    tp;
040.     static string   isPaint = "";
041.     static bool     bMouseL = false;
042. 
043.     switch (id)
044.     {
045.         case CHARTEVENT_KEYDOWN:
046.             if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) macro_CLEAN_EVENT;
047.             break;
048.         case CHARTEVENT_MOUSE_MOVE:
049.             tp = gl_Cross.Move((ushort)lparam, (ushort)dparam);
050.             if (((uchar)sparam & MOUSE_LEFT) != 0)
051.             {
052.                 if (isPaint != "")
053.                 {
054.                     bMouseL = true;
055.                     if (!ObjectGetInteger(0, isPaint, OBJPROP_TIME)) ObjectMove(0, isPaint, 0, tp.Time, tp.Price);
056.                     ObjectMove(0, isPaint, 1, tp.Time, tp.Price);
057.                 }
058.             }else if (bMouseL) macro_CLEAN_EVENT;
059.             if ((((uchar)sparam & MOUSE_MIDDLE) != 0) && (isPaint == ""))
060.             {
061.                 ObjectCreate(0, isPaint = macro_NameObject, OBJ_FIBO, 0, 0, 0);
062.                 ChartSetInteger(0, CHART_MOUSE_SCROLL, false);
063.                 Modifier_OBJ_FIBO(isPaint);
064.                 gl_Cross.Show();
065.             }
066.             break;
067.         case CHARTEVENT_MOUSE_WHEEL:
068.             break;
069.         case CHARTEVENT_OBJECT_CLICK:
070.             Comment(StringFormat("CHARTEVENT_OBJECT_CLICK\nX: %03d    Y: %03d    Object: %s", (ushort)lparam, (ushort)dparam, sparam));
071.             break;
072.         case CHARTEVENT_OBJECT_DRAG :
073.             Comment(StringFormat("CHARTEVENT_OBJECT_DRAG\nObject: %s", sparam));
074.             break;
075.     }
076.     ChartRedraw();
077. 
078. #undef macro_CLEAN_EVENT
079. };
080. //+------------------------------------------------------------------+
081. void OnDeinit(const int reason)
082. {
083.     Comment("");
084.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
085.     ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true);
086. 
087.     gl_Cross.Hide();
088. 
089.     if (reason == REASON_REMOVE)
090.         ObjectsDeleteAll(0, def_Prefix);
091. };
092. //+------------------------------------------------------------------+
093. void Modifier_OBJ_FIBO(const string szNameObj)
094. {
095. #define macro_Mod_OBJ_FIBO(txt, pos, cor, width, style) {                       \
096.             ObjectSetDouble(0, szNameObj, OBJPROP_LEVELVALUE, levels, pos);     \
097.             ObjectSetInteger(0, szNameObj, OBJPROP_LEVELCOLOR, levels, cor);    \
098.             ObjectSetInteger(0, szNameObj, OBJPROP_LEVELWIDTH, levels, width);  \
099.             ObjectSetInteger(0, szNameObj, OBJPROP_LEVELSTYLE, levels, style);  \
100.             ObjectSetString(0, szNameObj, OBJPROP_LEVELTEXT, levels, txt);      \
101.             levels++;                                                           \
102.                                                         }
103. 
104.     int levels = 0;
105. 
106.     ObjectSetInteger(0, szNameObj, OBJPROP_SELECTABLE, false);
107.     ObjectSetInteger(0, szNameObj, OBJPROP_COLOR, clrNONE);
108.     ObjectSetInteger(0, szNameObj, OBJPROP_RAY_RIGHT, user02);
109. 
110.     macro_Mod_OBJ_FIBO("Stop", 0, clrRed, 2, STYLE_SOLID);
111.     macro_Mod_OBJ_FIBO("Enter", 1, clrBlue, 2, STYLE_DASH);
112.     macro_Mod_OBJ_FIBO("Partial", 1 + (user01 / 2), clrYellowGreen, 1, STYLE_DASHDOTDOT);
113.     macro_Mod_OBJ_FIBO("Take", 1 + user01, clrGreen, 2, STYLE_SOLID);
114.     ObjectSetInteger(0, szNameObj, OBJPROP_LEVELS, levels);
115. 
116. #undef macro_Mod_OBJ_FIBO
117. }
118. //+------------------------------------------------------------------+

Code 01

Hier ist der Code, den wir im vorherigen Artikel besprochen, erklärt und bereitgestellt haben. Nun, eigentlich stimmt das nicht ganz, denn hier fügen wir dem Quellcode zwei neue Elemente hinzu. Ich tue dies absichtlich und baue auf bekanntem Material auf, damit Sie sehen können, dass eine hochkomplexe Anwendung nicht von heute auf morgen entsteht. Es wird nach und nach, Schritt für Schritt, aufgebaut. Obwohl wir uns hier nicht auf die Erstellung einer bestimmten Anwendung konzentrieren. Unser Ziel ist es lediglich, Aspekte der Programmierung in MQL5 zu demonstrieren und zu erläutern, um die MetaTrader 5-Plattform selbst zu steuern.

Nachdem Code 01 kompiliert und in ein Chart eingefügt wurde, zeigt er ein recht interessantes Verhalten, das es wert ist, beobachtet zu werden. Er wird uns nun nützliche Informationen liefern. Denken Sie daran, dass diese Daten ursprünglich von MetaTrader 5 basierend auf den auf dem Chart durchgeführten Aktionen generiert werden. Die folgende Animation zeigt, was Sie bei der Verwendung der Anwendung auf einem beliebigen Chart erwartet:


Animation 01

Achten Sie auf die obere linke Ecke von Animation 01. Sie werden Meldungen sehen, die uns darüber informieren, wann ein Ereignis bei einem der auf dem Chart vorhandenen Objekte eingetreten ist. Bitte beachten Sie, dass wir im Fall des Ereignisses CHARTEVENT_OBJECT_CLICK nicht nur den Namen des Objekts und die Mausposition erfahren, sondern auch die Art des Ereignisses, das eingetreten ist. Solche Ereignisse eröffnen eine breite Palette an Anwendungsmöglichkeiten. Tatsächlich eröffnet allein die Beobachtung dieser beiden Ereignisse viele Möglichkeiten.

Da wir es jedoch mit etwas sehr Einfachem und Unkompliziertem zu tun haben, sehe ich keine Notwendigkeit, im Detail zu erklären, was in Code 01 geschieht. Es reicht aus, ihn in Ruhe zu studieren und das aus den vorherigen Artikeln gewonnene Wissen anzuwenden, um genau zu verstehen, was in der Anwendung passiert. Denken Sie jedoch daran, dass die Anwendung sogar Objekte beobachten kann, die sie nicht selbst erstellt hat.

Genau das möchte ich, dass Sie verstehen, lieber Leser. Wir analysieren das Standardverhalten von MetaTrader 5, um zu verstehen, wie es mit Objekten interagiert und wie es uns genau benachrichtigt, wenn Änderungen auftreten.

Obwohl wir Code 01 weiter um neue Elemente ergänzen könnten, werden wir dies nicht tun. Das würde letztendlich unser Hauptziel verschleiern, das genau darin besteht, Sie zu unterrichten und einen Teil meiner Programmiererfahrung und meines Wissens weiterzugeben, damit Sie die Plattform für sich arbeiten lassen können, nicht gegen sich. Lassen Sie uns also eine neue Art von Anwendung erstellen. Sie wird der Beschreibung der zu implementierenden Funktionalität gewidmet sein, vorausgesetzt natürlich, dass Sie verstehen, wie man MQL5 zur Steuerung von MetaTrader 5 verwendet.

Dazu müssen Sie das Wesentliche des im aktuellen Thema behandelten Materials erfassen. Ohne das Verständnis dieses Teils, der meiner Ansicht nach die Grundlage für alles Weitere bildet, wird es ziemlich schwierig sein, zu verstehen, was wir als Nächstes tun werden.


Vermeidung doppelter Objekte

Eines der Dinge, die mich wirklich stören, ist das berüchtigte STRG+C und STRG+V. Aber in MetaTrader 5 funktioniert das nicht so, zumindest nicht auf die Art und Weise, wie die meisten Leute es erwarten. Das liegt daran, dass wir bei der Auswahl eines Objekts und dem Aktionsmenü dieses Objekts sehen können, dass MetaTrader 5 standardmäßig KEIN STRG+C und STRG+V für die Anwendung dieser Aktionen auf Objekte hat. Was vielen Menschen vollkommen normal und natürlich erscheinen mag, kann auf andere etwas seltsam und verwirrend wirken. Sie können dies in der folgenden Abbildung sehen.


Abbildung 01

Ja, das mag etwas seltsam erscheinen. In MetaTrader 5 sind STRG+C und STRG+V jedoch auf eine andere Weise verfügbar. Und um ehrlich zu sein, glaube ich, dass nur sehr wenige Benutzer wissen, wie man STRG+C und STRG+V in MetaTrader 5 verwendet, um ein grafisches Objekt zu duplizieren.

Um zu verstehen, wie dies gemacht wird, müsste man andere Dinge erklären. Aber das würde den Artikel hier sehr langweilig machen und wäre meiner Meinung nach nicht besonders interessant. Tatsache ist, dass die meisten Benutzer mit der Plattform, so wie sie derzeit ist, recht zufrieden sind. Warum sollte man sie also ändern? Richtig?

Aber für das, was ich später erklären möchte, lohnt es sich definitiv, Ihnen zu zeigen, wie man STRG+C und STRG+V mit jedem beliebigen Objekt in MetaTrader 5 verwendet, da ich glaube, dass Sie nicht wissen, wie das geht. Es wird auch zu einer Art Bonusmaterial für diejenigen, die zufällig auf meine Artikel stoßen und beginnen, diese zu studieren. In der folgenden Animation können wir also sehen, wie man STRG+C und STRG+V auf jedes beliebige Objekt anwendet.


Animation 02

Bitte beachten Sie, dass dies sehr einfach, leicht und sogar unterhaltsam ist. Allerdings wissen nur wenige Leute, dass man zum Erstellen einer Kopie eines beliebigen Objekts im Chart lediglich die STRG-Taste gedrückt halten muss, während man das Objekt zieht. Dadurch erstellen wir eine exakte Kopie des Objekts. Obwohl es in Wirklichkeit keine wirklich exakte Kopie ist, wie in Kürze erläutert wird. Und zum Glück ist es das nicht, denn sonst wäre es schwierig, etwas anderes zu tun, von dem Sie vielleicht noch nicht einmal ahnen, dass es möglich ist.

Wenn wir dies also tun, wie in Animation 02 gezeigt, erstellen wir ein Duplikat eines Objekts, das bereits im Chart vorhanden war. Aber manchmal ist das überhaupt nicht das, was wir wollen. Oder genauer gesagt, es gibt bestimmte Arten von Objekten, für die WIR KEINE Duplikate im Chart haben WOLLEN. Der Grund dafür ist, dass solche Objekte Informationen enthalten können, die, wenn sie dupliziert werden, den Operator oder sogar den Benutzer irreführen können.

Dies ist umso wichtiger, wenn diese Objekte Informationen von unserer Anwendung empfangen können. In diesem Fall könnten wir am Ende widersprüchliche Informationen in zwei Objekten sehen, die identisch aussehen. Um dies zu verdeutlichen und damit Sie richtig verstehen können, wovon ich spreche, lassen Sie uns einen kleinen Test durchführen. Wir werden dies mit dem unten gezeigten Code tun:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_Prefix  "Demo"
05. //+------------------------------------------------------------------+
06. #define macro_NameObject  def_Prefix + (string)(ObjectsTotal(0) + 1)
07. //+------------------------------------------------------------------+
08. string gl_NameObj;
09. //+------------------------------------------------------------------+
10. int OnInit()
11. {
12.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
13. 
14.     ObjectCreate(0, gl_NameObj = macro_NameObject, OBJ_LABEL, 0, 0, 0);
15.     ObjectSetInteger(0, gl_NameObj, OBJPROP_SELECTABLE, true);
16.     ObjectSetInteger(0, gl_NameObj, OBJPROP_XDISTANCE, 50);
17.     ObjectSetInteger(0, gl_NameObj, OBJPROP_YDISTANCE, 50);
18.     ObjectSetInteger(0, gl_NameObj, OBJPROP_XSIZE, 150);
19.     ObjectSetInteger(0, gl_NameObj, OBJPROP_COLOR, clrMediumBlue);
20.     ObjectSetInteger(0, gl_NameObj, OBJPROP_FONTSIZE, 20);
21.     ObjectSetString(0, gl_NameObj, OBJPROP_FONT, "Lucida Console");
22. 
23.     return INIT_SUCCEEDED;
24. };
25. //+------------------------------------------------------------------+
26. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
27. {
28.     return rates_total;
29. };
30. //+------------------------------------------------------------------+
31. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
32. {
33.     switch (id)
34.     {
35.         case CHARTEVENT_MOUSE_MOVE:
36.             ObjectSetString(0, gl_NameObj, OBJPROP_TEXT, StringFormat("%03d : %03d", (ushort)lparam, (ushort)dparam));
37.             break;
38.     }
39.     ChartRedraw();
40. };
41. //+------------------------------------------------------------------+
42. void OnDeinit(const int reason)
43. {
44.     ObjectsDeleteAll(0, def_Prefix);
45.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
46.     ChartRedraw();
47. };
48. //+------------------------------------------------------------------+

Code 02

Code 02 hilft zu veranschaulichen, was ich meine, wenn ich über das Duplizieren von Objekten spreche. Da es sehr einfach ist und Sie alles leicht herausfinden können, mein lieber und geschätzter Leser, falls Sie meine Artikel verfolgt haben, werde ich nicht erklären, was er tut. Stattdessen zeigen wir nur die Art von Ergebnis, das wir sehen können, wenn die in den vorangegangenen Absätzen beschriebenen Ideen in der Praxis angewendet werden. Das Ergebnis ist in Animation 03 unten zu sehen:


Animation 03

Hier stoßen wir auf ein Problem im Zusammenhang mit der Geschwindigkeit, mit der Ereignisse verarbeitet werden. Da wir es mit Mausereignissen zu tun haben, ist die Verarbeitungsgeschwindigkeit ziemlich hoch, und wir bemerken schließlich, dass etwas Seltsames passiert. Aber denken Sie an Ereignisse, die alle fünf Minuten oder sogar jede Stunde auftreten können. In diesem Fall wäre es schwierig, dies zu bemerken. Vielleicht beginnen Sie jetzt zu verstehen, worauf ich hinaus will. Da Sie wahrscheinlich nicht wussten, wie man ein Objekt auf einem Chart dupliziert, würde eine Situation wie die, die wir in Animation 03 sehen, kaum jemals auftreten.

Aber jetzt, da wir wissen, wie einfach es ist, ein Duplikat eines Objekts in MetaTrader 5 zu erstellen, können solche Situationen recht häufig auftreten. Dies kann irgendwann zu ernsthaften Problemen führen, insbesondere wenn sich das duplizierte Objekt vor dem interessierenden Objekt befindet. Dies geschieht viel häufiger, als man sich vorstellen könnte, und führt zu noch mehr Verwirrung.

Wir können jedoch verhindern, dass ein Objekt dupliziert wird, oder zumindest die Wahrscheinlichkeit verringern, dass dadurch Konflikte entstehen. Dies liegt daran, dass einige Arten von Objekten andere Objekte verdecken können, je nachdem, wie sie konfiguriert sind. Hier ist das erstellte Objekt glücklicherweise völlig harmlos und dient ausschließlich Bildungszwecken.

Jetzt müssen Sie eines verstehen, lieber Leser. Wenn ein Objekt dupliziert wird, wie hier gezeigt, erstellt MetaTrader 5 einen Namen für dieses neue Objekt. Dieser Name folgt sozusagen einer Standardisierungsregel und ist in drei Teile unterteilt. Der erste Teil bezieht sich auf den Zeitrahmen, den wir im Chart verwenden. Der zweite Teil gibt die Art des verwendeten Objekts an. Der dritte Teil ist eine zufällig generierte Zahl. Wir ignorieren diesen dritten Teil, da sein Zweck darin besteht, Kollisionen zwischen Objekten desselben Typs zu vermeiden.

In Ordnung, aber was sagt uns das? Und wie können wir dieses Wissen zu unserem Vorteil nutzen? Jetzt kommt der interessanteste Teil, lieber Leser. Basierend auf bestimmten Merkmalen, die mithilfe von Code 01 überprüft werden können, während wir beobachten, wie ein Duplikat erstellt wird, können wir feststellen, ob ein Duplikat eines Objekts erstellt wurde oder nicht. Obwohl dies keine exakte Wissenschaft ist, da es Komplikationen gibt, wie wir dies tun können und wie weit wir gehen können, ohne reines MQL5 zu verlassen.

Eine dieser Komplikationen wird in Kürze deutlich werden. Aber zuerst können wir etwas Interessanteres tun: eine Funktionalität implementieren, die dazu dient, die Ereignisse zu analysieren, die MetaTrader 5 selbst als Reaktion auf die Interaktion des Benutzers mit einem Objekt generiert. Somit wird Code 02 zu dem Code, den wir unten sehen werden.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_Prefix  "Demo"
05. //+------------------------------------------------------------------+
06. #define macro_NameObject  def_Prefix + (string)(ObjectsTotal(0) + 1)
07. //+------------------------------------------------------------------+
08. enum eBtnMouse  {
09.         MOUSE_LEFT      = 0x01, 
10.         MOUSE_RIGHT     = 0x02,
11.         MOUSE_KEY_SHIFT = 0x04,
12.         MOUSE_KEY_CTRL  = 0x08,
13.         MOUSE_MIDDLE    = 0x10,
14.         MOUSE_EXTRA_1   = 0x20,
15.         MOUSE_EXTRA_2   = 0x40
16.                 };
17. //+------------------------------------------------------------------+
18. string gl_NameObj;
19. //+------------------------------------------------------------------+
20. int OnInit()
21. {
22.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
23. 
24.     ObjectCreate(0, gl_NameObj = macro_NameObject, OBJ_LABEL, 0, 0, 0);
25.     ObjectSetInteger(0, gl_NameObj, OBJPROP_SELECTABLE, true);
26.     ObjectSetInteger(0, gl_NameObj, OBJPROP_XDISTANCE, 50);
27.     ObjectSetInteger(0, gl_NameObj, OBJPROP_YDISTANCE, 50);
28.     ObjectSetInteger(0, gl_NameObj, OBJPROP_XSIZE, 150);
29.     ObjectSetInteger(0, gl_NameObj, OBJPROP_COLOR, clrMediumBlue);
30.     ObjectSetInteger(0, gl_NameObj, OBJPROP_FONTSIZE, 20);
31.     ObjectSetString(0, gl_NameObj, OBJPROP_FONT, "Lucida Console");
32. 
33.     ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, true);
34. 
35.     return INIT_SUCCEEDED;
36. };
37. //+------------------------------------------------------------------+
38. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
39. {
40.     return rates_total;
41. };
42. //+------------------------------------------------------------------+
43. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
44. {
45.     static bool check = true;
46. 
47.     switch (id)
48.     {
49.         case CHARTEVENT_MOUSE_MOVE:
50.             ObjectSetString(0, gl_NameObj, OBJPROP_TEXT, StringFormat("%03d : %03d", (ushort)lparam, (ushort)dparam));
51.             if (((uchar)sparam & (MOUSE_LEFT | MOUSE_KEY_CTRL)) == (MOUSE_LEFT | MOUSE_KEY_CTRL)) 
52.             {
53.                 if (check) Print(StringFormat("CHARTEVENT_MOUSE_MOVE\n%s", StringFormat("%03d : %03d", (ushort)lparam, (ushort)dparam)));
54.                 check = false;
55.             }else
56.                 check = true;
57.             break;
58.         case CHARTEVENT_OBJECT_CREATE:
59.             Print(StringFormat("CHARTEVENT_OBJECT_CREATE\nObject: %s", sparam));
60.             break;
61.         case CHARTEVENT_OBJECT_CLICK:
62.             Print(StringFormat("CHARTEVENT_OBJECT_CLICK\nX: %03d    Y: %03d    Object: %s", (ushort)lparam, (ushort)dparam, sparam));
63.             break;
64.         case CHARTEVENT_OBJECT_DRAG :
65.             Print(StringFormat("CHARTEVENT_OBJECT_DRAG\nObject: %s", sparam));
66.             break;
67.     }
68.     ChartRedraw();
69. };
70. //+------------------------------------------------------------------+
71. void OnDeinit(const int reason)
72. {
73.     Comment("");
74.     ObjectsDeleteAll(0, def_Prefix);
75.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
76.     ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, false);
77.     ChartRedraw();
78. };
79. //+------------------------------------------------------------------+

Code 03

Wenn Sie sich diesen Code ansehen, denken Sie vielleicht: „Moment mal, dieser Code ist sehr kompliziert. Brauchen wir wirklich so viel Komplexität, nur um zu vermeiden, dass Objekte auf dem Chart dupliziert werden?“ Nun, in Code 03 versuchen wir noch nicht, die Duplizierung von Objekten zu verhindern. Und nein, dieser Code ist nicht so kompliziert, wie er scheint. Es mag so erscheinen, weil Sie zufällig auf diesen Artikel gestoßen sind, ohne genügend Hintergrundwissen zu dem, was bereits in den vorherigen Veröffentlichungen erklärt wurde. Ja, Code 03 sieht nach einer ernsthaften Herausforderung aus.

Nichtsdestotrotz werde ich mich hier aus Respekt vor denjenigen, die meine Artikel verfolgen und studieren, nur auf das Neue konzentrieren. Alles andere, so glaube ich, werden auch Anfänger verstehen, wenn sie das Erklärte studieren und üben.

Der erste neue Teil, der uns hier interessiert, ist Zeile 33. Achten Sie darauf, lieber Leser. In MetaTrader 5 ist das Objekterstellungsereignis standardmäßig deaktiviert. Wenn wir jedoch nicht möchten, dass ein von der Anwendung erstelltes Objekt erkannt wird und ein Erstellungsereignis auslöst, müssen wir dieses Ereignis deaktiviert lassen, bis das Objekt erstellt wurde, wie es vor der Aktivierung in Zeile 33 getan wird. Da wir dieses Ereignis erst NACH der Erstellung des OBJ_LABEL-Objekts aktivieren, löst dieses Objekt nicht das Erstellungsereignis aus, das wiederum von der Prozedur OnChartEvent erfasst würde.

Nachdem dieses Ereignis nun aktiviert wurde, löst jedes auf dem Chart platzierte Objekt ein Erstellungsereignis aus. Diese Daten werden von Zeile 58 erfasst, die dann eine Nachricht an das Terminal ausgibt. Wenn schließlich Zeile 76 ausgeführt wird, deaktivieren wir dieses Erstellungsereignis und verhindern so, dass MetaTrader 5 dieses Ereignis weiterhin auf dem Chart auslöst.

Der Rest des Codes ist ziemlich leicht zu verstehen. Wir können dann zu dem Teil übergehen, in dem wir Code 03 in der Praxis anwenden. Beginnen wir mit dem, was in der folgenden Animation zu sehen ist:


Animation 04

In dieser Animation können wir sehen, welche Objekte auf dem Chart vorhanden sind. Wir können auch feststellen, dass der Code keine Meldungen ausgegeben hat, was darauf hindeutet, dass die Ereignisse wie erwartet ablaufen, wie bereits erläutert.

Sobald Code 03 läuft, können wir das Fenster mit der Objektliste öffnen, um zu überprüfen, welche Elemente auf dem Chart vorhanden sind. Nach dem Öffnen der Liste sehen wir das unten gezeigte Bild.


Abbildung 02

Achten Sie jetzt auf eine Sache, lieber Leser. Es gibt zwei Hauptmethoden, um die Duplizierung von Objekten zu verhindern. Die erste besteht darin, die Objektliste, die Sie in Abbildung 02 sehen, im Auge zu behalten und zu überprüfen. Dies kann mit Code erledigt werden. Meiner Ansicht nach führt dies jedoch zu einem unnötigen Ressourcenverbrauch, da wir jedes Mal, wenn Zeile 58 ein Erstellungsereignis erkennt, analysieren müssen, was mit dieser Objektliste geschehen ist. Dies verkompliziert den Code unnötig und erhöht die CPU-Auslastung.

Die andere Methode besteht darin, die in Zeile 49 erfassten Mausereignisse zu analysieren, insbesondere diejenigen, die dazu führen, dass der Filter in Zeile 51 als wahr ausgewertet wird. Dieser Mechanismus ist jedoch nicht zu 100 % perfekt, da es Situationen gibt, in denen derselbe Filter ein falsch positives Ergebnis auslösen kann.

Um zu verstehen, was falsch positive Ergebnisse verursachen kann, lesen Sie einen weiteren meiner Artikel „ Entwicklung eines Trading-Expert-Advisors von Grund auf (Teil 23): Ein neues Auftragssystem (VI)“. Dort verwenden wir diese Kombination, die Zeile 51 aktiviert und dazu dient, ein Objekt zu duplizieren, genau damit Pending-Orders an den Handelsserver gesendet werden können. Mit etwas Geduld, Sorgfalt und Aufmerksamkeit können wir dieses Problem der falsch positiven Ergebnisse jedoch umgehen. Wir werden uns das ein anderes Mal ansehen, da es bestimmte Manipulationen beinhaltet, die im Moment nicht demonstriert werden sollten. Der Fokus liegt hier auf etwas völlig anderem: zu verstehen, wie verhindert werden kann, dass ein doppeltes Objekt erstellt wird.

Lassen Sie uns nun genauer betrachten, wie Code 03 uns zeigt, was auf dem Chart passiert. Dies ist in der folgenden Animation zu sehen:


Animation 05

In diesem Fall wurden nur die Ereignisse CHARTEVENT_OBJECT_CLICK und CHARTEVENT_OBJECT_DRAG generiert, was bestätigt, dass alles wie erwartet verlief. Jetzt werden wir etwas leicht anderes mit der Schaltfläche auf dem Chart tun. Dies ist in der folgenden Animation zu sehen:


Animation 06

Beachten Sie hier ein Detail. Genau in dem Moment, in dem die Kopie erstellt wird, also wenn das Duplikat generiert wird, löst MetaTrader 5 zwei Ereignisse aus. Dies ist auf der folgenden Abbildung deutlicher zu sehen.


Abbildung 03

In Abbildung 03 können wir deutlich den Moment sehen, in dem das Objekt kopiert oder das Duplikat erstellt wird. Und jetzt aufgepasst! Bitte beachten Sie, dass das ursprüngliche Objekt an seiner Position blieb. Es war die Kopie, die sich bewegte, wie durch den Vergleich von Abbildung 02 mit Abbildung 04 unten zu sehen ist.


Abbildung 04

Warum ist das wichtig zu wissen? Der Grund dafür ist, dass wir je nach Aufgabe entweder die Kopie oder das ursprüngliche Objekt löschen müssen. Ich persönlich finde es einfacher, die Kopie zu löschen, da uns ihr Name mitgeteilt wird, wenn das Erstellungsereignis erfasst wird. Es hindert uns jedoch nichts daran, das Original zu löschen und dann die Kopie umzubenennen, damit alles so bleibt wie zuvor. Vielleicht war die Absicht, das Objekt zu verschieben, und stattdessen wurde eine Kopie davon erstellt. Dennoch denke ich, dass das zu viel Arbeit erfordert. Wir werden also den einfachsten Weg weiterverfolgen.

Da die geplanten Änderungen an Code 03 die zuvor implementierte und demonstrierte Funktionalität entfernen werden, werden wir einen anderen Ansatz wählen. Wir werden eine neue Datei erstellen. Auf diese Weise wird Code 03 in den Artikelanhang aufgenommen, sodass Sie ihn in Ruhe studieren können, ohne ihn manuell abtippen zu müssen. Der neue Code mit den notwendigen Änderungen ist unten dargestellt:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_Prefix  "Demo"
05. //+------------------------------------------------------------------+
06. #define macro_NameObject  def_Prefix + (string)(ObjectsTotal(0) + 1)
07. //+------------------------------------------------------------------+
08. enum eBtnMouse  {
09.         MOUSE_LEFT      = 0x01, 
10.         MOUSE_RIGHT     = 0x02,
11.         MOUSE_KEY_SHIFT = 0x04,
12.         MOUSE_KEY_CTRL  = 0x08,
13.         MOUSE_MIDDLE    = 0x10,
14.         MOUSE_EXTRA_1   = 0x20,
15.         MOUSE_EXTRA_2   = 0x40
16.                 };
17. //+------------------------------------------------------------------+
18. string gl_NameObj;
19. //+------------------------------------------------------------------+
20. int OnInit()
21. {
22.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
23. 
24.     ObjectCreate(0, gl_NameObj = macro_NameObject, OBJ_LABEL, 0, 0, 0);
25.     ObjectSetInteger(0, gl_NameObj, OBJPROP_SELECTABLE, true);
26.     ObjectSetInteger(0, gl_NameObj, OBJPROP_XDISTANCE, 50);
27.     ObjectSetInteger(0, gl_NameObj, OBJPROP_YDISTANCE, 50);
28.     ObjectSetInteger(0, gl_NameObj, OBJPROP_XSIZE, 150);
29.     ObjectSetInteger(0, gl_NameObj, OBJPROP_COLOR, clrMediumBlue);
30.     ObjectSetInteger(0, gl_NameObj, OBJPROP_FONTSIZE, 20);
31.     ObjectSetString(0, gl_NameObj, OBJPROP_FONT, "Lucida Console");
32. 
33.     ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, true);
34. 
35.     return INIT_SUCCEEDED;
36. };
37. //+------------------------------------------------------------------+
38. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
39. {
40.     return rates_total;
41. };
42. //+------------------------------------------------------------------+
43. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
44. {
45.     static bool check = true;
46.     static string szObjName = "";
47. 
48.     switch (id)
49.     {
50.         case CHARTEVENT_MOUSE_MOVE:
51.             ObjectSetString(0, gl_NameObj, OBJPROP_TEXT, StringFormat("%03d : %03d", (ushort)lparam, (ushort)dparam));
52.             if (((uchar)sparam & (MOUSE_LEFT | MOUSE_KEY_CTRL)) == (MOUSE_LEFT | MOUSE_KEY_CTRL)) 
53.             {
54.                 if (check)
55.                     if (ObjectDelete(0, szObjName))
56.                         Comment("Removing copy object: " + szObjName);
57.                 check = false;
58.             }else
59.                 check = true;
60.             break;
61.         case CHARTEVENT_OBJECT_CREATE:
62.             szObjName = sparam;
63.             break;
64.         case CHARTEVENT_OBJECT_CLICK:
65.             Comment(StringFormat("CHARTEVENT_OBJECT_CLICK\nX: %03d    Y: %03d    Object: %s", (ushort)lparam, (ushort)dparam, sparam));
66.             break;
67.         case CHARTEVENT_OBJECT_DRAG :
68.             Comment(StringFormat("CHARTEVENT_OBJECT_DRAG\nObject: %s", sparam));
69.             break;
70.     }
71.     ChartRedraw();
72. };
73. //+------------------------------------------------------------------+
74. void OnDeinit(const int reason)
75. {
76.     Comment("");
77.     ObjectsDeleteAll(0, def_Prefix);
78.     ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false);
79.     ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, false);
80.     ChartRedraw();
81. };
82. //+------------------------------------------------------------------+

Code 04

Wenn wir diesen Code 04 ausführen, erhalten wir ein Ergebnis, das dem folgenden sehr ähnlich ist:


Animation 07

Beachten Sie, dass ich hier problemlos ein neues Objekt hinzugefügt habe. Unmittelbar danach haben wir versucht, eine Kopie dieses Objekts mithilfe des in diesem Artikel beschriebenen Mechanismus zu erstellen. Und achten Sie darauf, was in der oberen linken Ecke des Charts angezeigt wird. Mit anderen Worten: Wir haben gerade einen Weg gefunden, die Duplizierung von Objekten zu verhindern, obwohl auch andere Maßnahmen zum gleichen Ergebnis führen könnten.


Schlussfolgerung

Obwohl sich dieser Artikel ausschließlich auf die Behandlung von Objektereignissen konzentrierte, müssen wir noch drei weitere Ereignisse im Zusammenhang mit Objekten untersuchen. Wir werden sie im nächsten Artikel besprechen. Ich möchte die Dinge für diejenigen, die gerade erst anfangen zu lernen, wie man MetaTrader 5 mit MQL5 steuert, nicht zu kompliziert machen.

Versuchen Sie also, lieber Leser, das in diesem Artikel Behandelte zu studieren und in die Praxis umzusetzen. Dieses Wissen wird Ihnen sicherlich helfen, viele Aspekte der Funktionsweise von MetaTrader 5 zu verstehen, und Sie müssen es sehr gut beherrschen, bevor Sie sagen können: „Ja, ich kann gut genug programmieren, um die Funktionen von MetaTrader 5 zu steuern.“

Üben Sie also mit dem Code aus dem Anhang und wir sehen uns im nächsten Artikel.

MQ5-Datei Beschreibung
Code 01 Demonstration von Objektereignissen
Code 02 Demonstration von Objektereignissen
Code 03 Demonstration von Objektereignissen 

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

Beigefügte Dateien |
Anexo.zip (3.8 KB)
Die Übertragung der Trading-Signale in einem universalen Expert Advisor. Die Übertragung der Trading-Signale in einem universalen Expert Advisor.
In diesem Artikel wurden die verschiedenen Möglichkeiten beschrieben, um die Trading-Signale von einem Signalmodul des universalen EAs zum Steuermodul der Positionen und Orders zu übertragen. Es wurden die seriellen und parallelen Interfaces betrachtet.
Neuronale Netze in der Praxis: Übung macht den Meister Neuronale Netze in der Praxis: Übung macht den Meister
Im heutigen Artikel werden wir sehen, wie eine einfache Codeänderung, die ein Neuron etwas spezialisierter macht, die Trainingsphase erheblich beschleunigen kann. Schließlich arbeitet ein Neuron oder ein neuronales Netz – wie wir später sehen werden – deutlich schneller, sobald es trainiert wurde. Wir werden auch ein Problem diskutieren, das existiert, aber selten erwähnt wird.
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 Trading: LSTM-Optimierung für die multivariate Zeitreihenprognose (letzter Teil) Neuronale Netze im Trading: LSTM-Optimierung für die multivariate Zeitreihenprognose (letzter Teil)
Wir setzen die Implementierung des DA-CG-LSTM-Frameworks fort, das innovative Methoden für die Zeitreihenanalyse und -prognose bietet. Die Verwendung von CG-LSTM und eines dualen Aufmerksamkeitsmechanismus ermöglicht eine genauere Erkennung sowohl langfristiger als auch kurzfristiger Abhängigkeiten in Daten, was besonders für die Arbeit mit Finanzmärkten nützlich ist.