Von der Grundstufe zur Mittelstufe: Objekte (IV)
Einführung
Im vorigen Artikel „ Von der Grundstufe zur Mittelstufe: Objekte (III)“ haben wir gezeigt, wie man einen Indikator mit einem sehr einfachen Zweck implementiert: eine Trendlinie einfach auf dem Chart zu platzieren, ohne das MetaTrader 5-Menü zu öffnen.
Ich weiß, dass viele Leute diesen Inhalt für völlig unnötig halten. Denken Sie jedoch daran, dass es hier nicht darum geht, eine bestimmte Sache zu implementieren, sondern zu zeigen, wie wir es tun können. Ob es implementiert wird und ob es einen praktischen Nutzen bringt, ist nur ein Detail. Am wichtigsten ist, dass Sie, lieber Leser, verstehen, dass jeder Ideen in die Praxis umsetzen kann, indem er das studiert und anwendet, was diese Artikel zeigen.
Was wir im vorigen Artikel gesehen und getan haben, ist nur ein kleiner Teil dessen, was wir wirklich erreichen können, sobald wir anfangen, unsere eigenen Anwendungen für spezifische Zwecke zu programmieren. In diesem Artikel werden wir versuchen, etwas sehr Interessantes zu zeigen: einen in MetaTrader 5 versteckten Indikator, von dessen Existenz fast niemand weiß.
Lassen Sie uns also unserem üblichen Ritual folgen: Legen Sie alles beiseite, was Sie beim Studium des Artikels ablenken könnte, und gehen Sie zum nächsten Abschnitt über, um zu sehen, was dieser Indikator ist.
Ein versteckter Indikator in MetaTrader 5
Viele Leute behaupten, dass MetaTrader 5 nur wenige Indikatoren oder Werkzeuge für die Marktanalyse hat. Ich bin entschieden anderer Meinung. Nicht die Plattform oder ihre Inhalte sind begrenzt, sondern die eingeschränkte Sichtweise der meisten Menschen, die immer erwarten, Dinge fertig und genau so zu finden, wie sie sie sich vorstellen.
MetaTrader 5 enthält ein Element, das fast niemand bemerkt, weil es in einem anderen Indikator versteckt ist. Tatsächlich ist es eigentlich kein Indikator, sondern eher ein Analyseobjekt. Wir müssen dieses Objekt so sichtbar machen, dass der verborgene Indikator – oder besser gesagt, dieses Analyseobjekt – erkennbar wird. Standardmäßig kann es in der Form verwendet werden, in der es in MetaTrader 5 implementiert ist, aber wenn wir es korrekt modifizieren, werden die angezeigten Informationen viel klarer, da sein Zweck ein völlig anderer sein wird als der ursprüngliche.
Ich beziehe mich dabei speziell auf das Fibonacci-Objekt. Natürlich könnten wir das, was wir gleich implementieren werden, mit Trendlinien erstellen, aber mit dem Fibonacci-Objekt ist es viel einfacher, das benötigte Objekt zu erstellen.
Beginnen wir also damit, uns den Indikator-Code anzusehen, den wir im vorherigen Artikel erstellt haben. Er ist unten dargestellt und dient als Ausgangspunkt für die Erstellung eines anderen Indikatortyps:
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. #include <Tutorial\File 01.mqh> 09. //+------------------------------------------------------------------+ 10. st_Cross gl_Cross; 11. //+------------------------------------------------------------------+ 12. int OnInit() 13. { 14. gl_Cross.Init(); 15. 16. IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix); 17. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); 18. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false); 19. 20. return INIT_SUCCEEDED; 21. }; 22. //+------------------------------------------------------------------+ 23. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 24. { 25. return rates_total; 26. }; 27. //+------------------------------------------------------------------+ 28. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 29. { 30. st_TimePrice tp; 31. static string isPaint = ""; 32. 33. switch (id) 34. { 35. case CHARTEVENT_KEYDOWN: 36. if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) gl_Cross.Hide(); 37. break; 38. case CHARTEVENT_MOUSE_MOVE: 39. if (((uchar)sparam & MOUSE_MIDDLE) != 0) 40. { 41. tp = gl_Cross.Move((ushort)lparam, (ushort)dparam); 42. if (isPaint == "") 43. { 44. ObjectCreate(0, isPaint = macro_NameObject, OBJ_TREND, 0, tp.Time, tp.Price); 45. ObjectSetInteger(0, isPaint, OBJPROP_SELECTABLE, true); 46. ObjectSetInteger(0, isPaint, OBJPROP_COLOR, clrMagenta); 47. ObjectSetInteger(0, isPaint, OBJPROP_WIDTH, 3); 48. ObjectSetInteger(0, isPaint, OBJPROP_RAY_RIGHT, true); 49. } 50. ObjectMove(0, isPaint, 1, tp.Time, tp.Price); 51. gl_Cross.Show(); 52. }else 53. { 54. isPaint = ""; 55. gl_Cross.Hide(); 56. } 57. break; 58. case CHARTEVENT_MOUSE_WHEEL: 59. break; 60. } 61. ChartRedraw(); 62. }; 63. //+------------------------------------------------------------------+ 64. void OnDeinit(const int reason) 65. { 66. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); 67. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true); 68. 69. gl_Cross.Hide(); 70. 71. if (reason == REASON_REMOVE) 72. ObjectsDeleteAll(0, def_Prefix); 73. }; 74. //+------------------------------------------------------------------+
Code 01
Obwohl dieser Code funktioniert, hat er für die meisten Benutzer einen kleinen Nachteil: Er erstellt das Objekt, das wir dem Chart hinzufügen möchten, mit der mittleren Maustaste. Das ist eher ungewohnt, da für solche Aktionen normalerweise die linke Taste verwendet wird. Dies ist jedoch nur ein kleines Detail, das uns im Moment nicht betrifft. Um die linke Taste verwenden zu können, müssten wir einige Aspekte der Funktionsweise des Codes ändern, aber das werden wir später tun.
Im Moment wollen wir das Objekt OBJ_TREND durch OBJ_FIBO ersetzen. Mit diesem einfachen Austausch erhalten wir Folgendes:

Animation 01
Bitte beachten Sie, dass wir von einer Trendlinie zu einem Fibonacci-Objekt gewechselt sind. Wir beabsichtigen jedoch nicht, das erstellte Objekt in dieser Form zu verwenden, da das Objekt, das wir entwickeln wollen, auf diesem Fibonacci-Objekt basiert, aber nicht exakt dasselbe ist. Wir werden eine Modifikation des Fibonacci-Objekts erstellen. Um diese Aufgabe zu vereinfachen, 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. st_Cross gl_Cross; 011. //+------------------------------------------------------------------+ 012. int OnInit() 013. { 014. gl_Cross.Init(); 015. 016. IndicatorSetString(INDICATOR_SHORTNAME, def_Prefix); 017. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); 018. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, false); 019. 020. return INIT_SUCCEEDED; 021. }; 022. //+------------------------------------------------------------------+ 023. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 024. { 025. return rates_total; 026. }; 027. //+------------------------------------------------------------------+ 028. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 029. { 030. st_TimePrice tp; 031. static string isPaint = ""; 032. 033. switch (id) 034. { 035. case CHARTEVENT_KEYDOWN: 036. if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) gl_Cross.Hide(); 037. break; 038. case CHARTEVENT_MOUSE_MOVE: 039. if (((uchar)sparam & MOUSE_MIDDLE) != 0) 040. { 041. tp = gl_Cross.Move((ushort)lparam, (ushort)dparam); 042. if (isPaint == "") 043. { 044. ObjectCreate(0, isPaint = macro_NameObject, OBJ_FIBO, 0, tp.Time, tp.Price); 045. Modifier_OBJ_FIBO(isPaint); 046. } 047. ObjectMove(0, isPaint, 1, tp.Time, tp.Price); 048. gl_Cross.Show(); 049. }else 050. { 051. isPaint = ""; 052. gl_Cross.Hide(); 053. } 054. break; 055. case CHARTEVENT_MOUSE_WHEEL: 056. break; 057. } 058. ChartRedraw(); 059. }; 060. //+------------------------------------------------------------------+ 061. void OnDeinit(const int reason) 062. { 063. ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); 064. ChartSetInteger(0, CHART_CROSSHAIR_TOOL, true); 065. 066. gl_Cross.Hide(); 067. 068. if (reason == REASON_REMOVE) 069. ObjectsDeleteAll(0, def_Prefix); 070. }; 071. //+------------------------------------------------------------------+ 072. void Modifier_OBJ_FIBO(const string szNameObj) 073. { 074. const double nLevels[] = 075. { 076. 0, 077. 1, 078. 2.5 079. }; 080. const string sLevels[] = 081. { 082. "Stop", 083. "Enter", 084. "Take" 085. }; 086. const color cLevels[] = 087. { 088. clrRed, 089. clrBlue, 090. clrGreen 091. }; 092. 093. ObjectSetInteger(0, szNameObj, OBJPROP_SELECTABLE, false); 094. ObjectSetInteger(0, szNameObj, OBJPROP_COLOR, clrNONE); 095. ObjectSetInteger(0, szNameObj, OBJPROP_WIDTH, 3); 096. ObjectSetInteger(0, szNameObj, OBJPROP_RAY_RIGHT, true); 097. 098. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELS, nLevels.Size()); 099. for (uint c = 0; c < nLevels.Size(); c++) 100. { 101. ObjectSetDouble(0, szNameObj, OBJPROP_LEVELVALUE, c, nLevels[c]); 102. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELCOLOR, c, cLevels[c]); 103. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELWIDTH, c, 2); 104. ObjectSetString(0, szNameObj, OBJPROP_LEVELTEXT, c, sLevels[c]); 105. } 106. } 107. //+------------------------------------------------------------------+
Code 02
Code 02 ist sehr interessant, vor allem deshalb, weil er das Objekt, das ich zeigen möchte, fast vollständig implementiert. Wie ist das möglich? Lieber Leser, wenn Sie genau hinsehen, werden Sie feststellen, dass wir in Zeile 45 eine Prozedur aufrufen, die sich in Zeile 72 befindet. Diese Prozedur wirkt, sagen wir, etwas unordentlich, da sie viel weniger organisiert ist, als ich es mir ursprünglich wünschen würde. Dennoch denke ich, dass man dadurch leichter versteht, wie sie funktioniert.
Bevor wir erklären, wie das Verfahren funktioniert, schauen wir uns das Ergebnis in der Animation unten an:

Animation 02
Wie Sie sehen können, ist das Ziel, das wir umsetzen möchten, recht einfach. Wofür kann dieses Tool verwendet werden? Viele Menschen verwenden bestimmte Handelsstrategien auf dem Markt, und bei vielen dieser Strategien sind Take Profit und Stop Loss sehr klar definiert. Es ist wichtig, dies zu verstehen, um genau zu begreifen, was implementiert wird und vor allem, wie diese Implementierung für bestimmte Zwecke modifiziert werden kann.
Dieses modifizierte OBJ_FIBO ermöglicht es uns, genau diese Art von Bedingungen zu überprüfen: Bevor wir einen Trade eingehen, können wir sehen, wo die Einstiegsorder sein wird, wo der Stop Loss sein sollte und wo das Take Profit sein wird. Damit können wir beurteilen, ob der Trade sinnvoll ist oder nicht; ein falsch platzierter Stop Loss wird sicherlich ausgelöst werden, genauso wie ein falsch berechnetes Take Profit höchstwahrscheinlich nicht erreicht wird.
Da einige professionelle Trader ihre Analyse einige Minuten vor dem tatsächlichen Eingehen eines Trades durchführen, erweist sich dieses Tool als sehr nützlich und unverzichtbar, da es eine genaue Vorstellung davon vermittelt, was während des Trades zu erwarten ist.
In Ordnung, aber wie wurde dieses Tool erstellt? Und wie können wir es verbessern oder an unseren Arbeitsstil anpassen? Um dies zu verstehen, konzentrieren wir uns nun auf die Prozedur Modifier_OBJ_FIBO, die in Zeile 72 von Code 02 beginnt.
Dort sehen wir, dass drei Arrays erstellt wurden. Jedes von ihnen hat seinen eigenen Zweck, und sie sind miteinander verbunden. Bevor wir uns den Zweck jedes einzelnen ansehen, betrachten wir andere Aspekte derselben Prozedur. In Zeile 93 haben wir eine Eigenschaft des OBJ_FIBO-Objekts geändert, sodass der Benutzer es nicht mit einem Mausklick auswählen kann. Dies ist wichtig, da wir nicht möchten, dass das Objekt verschoben wird, nachdem es platziert wurde.
Dies schafft jedoch ein weiteres Problem: Wir werden das Objekt nicht löschen können, indem wir darauf klicken und dann die ENTF-Taste drücken. Dennoch kann es über das Fenster gelöscht werden, das die Liste der Chartobjekte anzeigt, oder indem der Indikator aus dem Chart entfernt wird.
Zeile 94 verhindert, dass die gepunktete Linie im Chart sichtbar ist. Diese gepunktete Linie erscheint in Animation 01 in Magenta, aber wenn ihr die Farbe clrNONE zugewiesen wird, ist sie nicht mehr sichtbar, obwohl die Objektlinie selbst weiterhin existiert. Die nächsten beiden Zeilen, 95 und 96, ändern nur Eigenschaften des Objekts OBJ_FIBO; hier gibt es nichts weiter zu beachten. Nun kommen wir zu dem Teil, der uns wirklich interessiert, nämlich Zeile 98.
Das Objekt OBJ_FIBO besteht aus Ebenen. Es spielt keine Rolle, welche Variante des Fibonacci-Objekts wir verwenden: In allen Fällen wird es aus diesen Ebenen erstellt. Da MetaTrader 5 nicht weiß, wie viele Ebenen erstellt werden sollen, legen wir in Zeile 98 fest, wie viele Ebenen erstellt werden sollen. An diesem Punkt weiß die Plattform, wie viele Ebenen es geben soll. Wir können mehr oder weniger Ebenen angeben; da wir hier jedoch die in Animation 02 gezeigte Modifikation anstreben, werden wir nur wenige Ebenen verwenden, nämlich drei.
Und jetzt aufgepasst. Jede Ebene hat ihre eigenen Eigenschaften. Da diese Ebenen durch Trendlinien oder sogar Kurven mit demselben Zweck dargestellt werden können, können wir festlegen, wie jede dieser Linien im Chart gezeichnet werden soll, und so das gewünschte Muster aufbauen.
Und wie wird dieses Muster gebildet? An dieser Stelle wird das Objekt, das wir gerade modifizieren, interessant. Bitte beachten Sie, dass wir innerhalb der Schleife die kurz zuvor definierten Arrays durchlaufen. Jedes dieser Arrays weist einen Wert einer der Eigenschaften der zu erstellenden Linie zu, was ziemlich leicht zu verstehen ist. Es gibt jedoch ein Detail, das etwas schwieriger sein könnte: das in Zeile 74 definierte Array nLevels.
Der schwierigste Teil dieses Arrays sind genau seine Werte. „Warum verwenden wir genau diese Werte? Könnten wir nicht andere Optionen verwenden?“ Um dies zu verstehen, müssen wir zunächst einen weiteren Aspekt der Fibonacci-Zahlen kennenlernen. Im Fibonacci-Objekt arbeiten wir mit Werten von null bis eins; alles innerhalb dieses Bereichs wird innerhalb des jedem bekannten Standard-Fibonacci-Rasters angezeigt. Wir können jedoch Werte kleiner als null und größer als eins zuweisen und so eine erweiterte Projektion des Objekts selbst erstellen. Beachten Sie Folgendes: Wenn wir mit dem Zeichnen des OBJ_FIBO-Objekts im Chart beginnen, entspricht der erste Ankerpunkt dem Wert eins, und wenn wir das Objekt ziehen, um es zu erstellen, erhalten wir die Position des Nullwerts.
Das mag seltsam erscheinen, aber so funktioniert es. Wenn wir also den Wert 2,5 hinzufügen, wie in Zeile 78 gezeigt, weisen wir das Programm nicht an, eine Projektion zu erstellen, die das Zweieinhalbfache der Distanz zwischen Punkt eins und null beträgt, sondern das Eineinhalbfache dieser Distanz.
Auf diese Weise berechnen wir die Projektion, an der sich das Take Profit eines möglichen Trades befinden wird. Wenn Sie ein Take Profit-Verhältnis von 1:1 verwenden möchten, sollten Sie in Zeile 78 den Wert zwei angeben; somit wird die gleiche Distanz, die zwischen dem Einstiegspunkt und dem Stop Loss-Punkt besteht, als Take Profit-Distanz für den Trade projiziert.
Sie mögen denken, das sei verrückt, und das ist es auch wirklich, denn es ist zum Beispiel sehr einfach, zusätzliche Zwischenebenen einzubeziehen. Sie müssen nur die entsprechenden Werte zu dem in Zeile 74 deklarierten Array hinzufügen. Denken Sie daran, dass Sie auch die anderen beiden Arrays anpassen müssen, damit die Anzeige im Chart nicht von dem abweicht, was bei der Verwendung des benutzerdefinierten Indikators in MetaTrader 5 erwartet wird.
Sehen Sie? Es ist nicht viel nötig. Alles, was wir wirklich brauchen, sind Kreativität und der Wunsch, etwas zu erschaffen. Dann entwickeln und implementieren wir unsere Ideen unter Anwendung der grundlegenden Kenntnisse, die in den anderen Artikeln dieser Serie vorgestellt wurden. So einfach ist das.
Was wir hier tun, ist so interessant, dass wir nicht auf das oben Gezeigte beschränkt sind: Wir können noch viel weiter gehen. Um dies zu beweisen, lassen Sie uns Folgendes tun: Zunächst erzeugt der als Code 02 vorgestellte Code etwas Ähnliches wie das, was wir in Animation 02 gesehen haben; aber was passiert, wenn wir nur den Inhalt der Prozedur Modifier_OBJ_FIBO durch etwas anderes ersetzen, wie im Codefragment unten?
. . . 71. //+------------------------------------------------------------------+ 72. void Modifier_OBJ_FIBO(const string szNameObj) 73. { 74. #define macro_Mod_OBJ_FIBO(txt, pos, cor, width, style) { \ 75. ObjectSetDouble(0, szNameObj, OBJPROP_LEVELVALUE, levels, pos); \ 76. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELCOLOR, levels, cor); \ 77. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELWIDTH, levels, width); \ 78. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELSTYLE, levels, style); \ 79. ObjectSetString(0, szNameObj, OBJPROP_LEVELTEXT, levels, txt); \ 80. levels++; \ 81. } 82. 83. int levels = 0; 84. 85. ObjectSetInteger(0, szNameObj, OBJPROP_SELECTABLE, false); 86. ObjectSetInteger(0, szNameObj, OBJPROP_COLOR, clrNONE); 87. ObjectSetInteger(0, szNameObj, OBJPROP_RAY_RIGHT, true); 88. 89. macro_Mod_OBJ_FIBO("Stop", 0, clrRed, 2, STYLE_SOLID); 90. macro_Mod_OBJ_FIBO("Enter", 1, clrBlue, 2, STYLE_DASH); 91. macro_Mod_OBJ_FIBO("Partial", 1.5, clrYellowGreen, 1, STYLE_DASHDOTDOT); 92. macro_Mod_OBJ_FIBO("Take", 2, clrGreen, 2, STYLE_SOLID); 93. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELS, levels); 94. 95. #undef macro_Mod_OBJ_FIBO 96. } 97. //+------------------------------------------------------------------+
Code 03
Da der Rest des Codes unverändert bleibt, zeigen wir in Code 03 nur den Teil, der uns wirklich interessiert. Wenn wir das Programm jedoch mit den in Code 03 vorgenommenen Änderungen ausführen, wird das Ergebnis völlig anders sein, wie in der folgenden Abbildung zu sehen ist.

Abbildung 01
Bitte beachten Sie, dass das, was wir tun, wie in Abbildung 01 gezeigt, nicht durch die direkte Manipulation des Fibonacci-Objekts im Chart erreicht werden kann. In diesem Fall beträgt das Verhältnis zwischen dem Stop Loss und dem Take Profit 1:1, mit einem Teilausstieg bei 50 % der Distanz.
Der schwierigste Teil ist genau die Kombination von Farben und Linien. Wenn Sie es nicht glauben, versuchen Sie, dies mit einem Fibonacci-Objekt nachzubilden, das über das MetaTrader 5-Menü eingefügt wurde, und Sie werden sehen, dass es unmöglich ist.
In diesem Szenario von Code 03 ist die Prozedur Modifier_OBJ_FIBO meiner Ansicht nach viel einfacher zu modifizieren und zu konfigurieren, da wir ein Makro verwenden, das das Erstellen von Ebenen sehr einfach macht. Jede neue Ebene kann hinzugefügt werden, indem sie vor Zeile 93 platziert wird, damit MetaTrader 5 weiß, wie viele und welche Ebenen im Chart angezeigt werden sollen.
„Was Sie gezeigt haben, ist ziemlich interessant, aber ich habe eine Frage. Ich verstehe, dass das Ziel dieser Artikel nicht darin besteht, die Erstellung einer vollwertigen Anwendung zu lehren, aber wenn wir möchten, dass der Benutzer mit diesem letzten Indikator interagiert, wie könnten wir das bereitstellen? Ich frage, weil sich die fest vorgegebenen Werte nach dem Kompilieren nicht mehr ändern lassen. Wie könnten wir zumindest das Verhältnis zwischen Stop Loss und Take Profit anpassen?“ Das ist leicht zu erklären; wir haben Zeit zu sehen, wie das gemacht werden kann. Um die Themen zu trennen, lassen Sie uns dies genauer betrachten.
Anpassung des Stop Loss-Take Profit-Verhältnisses
Es gibt verschiedene Möglichkeiten, dem Benutzer zu ermöglichen, das Verhältnis zwischen Stop Loss und Take Profit festzulegen. Eine einfache Möglichkeit ist die Verwendung eines Double-Werts, wie unten dargestellt:
. . . 09. //+------------------------------------------------------------------+ 10. input double user01 = 1.5; //Stop-Target Relationship 11. //+------------------------------------------------------------------+ . . . 73. //+------------------------------------------------------------------+ 74. void Modifier_OBJ_FIBO(const string szNameObj) 75. { 76. #define macro_Mod_OBJ_FIBO(txt, pos, cor, width, style) { \ 77. ObjectSetDouble(0, szNameObj, OBJPROP_LEVELVALUE, levels, pos); \ 78. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELCOLOR, levels, cor); \ 79. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELWIDTH, levels, width); \ 80. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELSTYLE, levels, style); \ 81. ObjectSetString(0, szNameObj, OBJPROP_LEVELTEXT, levels, txt); \ 82. levels++; \ 83. } 84. 85. int levels = 0; 86. 87. ObjectSetInteger(0, szNameObj, OBJPROP_SELECTABLE, false); 88. ObjectSetInteger(0, szNameObj, OBJPROP_COLOR, clrNONE); 89. ObjectSetInteger(0, szNameObj, OBJPROP_RAY_RIGHT, true); 90. 91. macro_Mod_OBJ_FIBO("Stop", 0, clrRed, 2, STYLE_SOLID); 92. macro_Mod_OBJ_FIBO("Enter", 1, clrBlue, 2, STYLE_DASH); 93. macro_Mod_OBJ_FIBO("Partial", 1 + (user01 / 2), clrYellowGreen, 1, STYLE_DASHDOTDOT); 94. macro_Mod_OBJ_FIBO("Take", 1 + user01, clrGreen, 2, STYLE_SOLID); 95. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELS, levels); 96. 97. #undef macro_Mod_OBJ_FIBO 98. } 99. //+------------------------------------------------------------------+
Code 04
Dieses Code 04-Fragment ist der einfachste Weg, eine direkte Beziehung zwischen dem Stop Loss und seinem Take Profit herzustellen. Alles, was erforderlich war, war das Hinzufügen von Zeile 10 zum Fragment und die Anpassung der Zeilen 93 und 94, um die Beziehung zu generieren. Wenn wir Code 04 ausführen, erhalten wir das in der folgenden Abbildung dargestellte Ergebnis:

Abbildung 02
Nach der Anpassung des in Abbildung 02 gezeigten Verhältnisses kann es direkt im Chart verwendet werden, und das Ergebnis wird ähnlich dem sein, was in der Abbildung unten gezeigt wird:

Abbildung 03
Das ist wirklich bemerkenswert, wenn man bedenkt, wie einfach der Ansatz ist. Sie fragen sich vielleicht, was passiert, wenn der Benutzer einen Verhältniswert unter eins eingibt; das heißt, wenn er in einem Kontext handeln möchte, in dem das Verhältnis zwischen Stop Loss und Take Profit ungünstig ist. Was wird passieren und welcher Wert sollte angegeben werden, damit der Indikator funktioniert? Ich beabsichtige nicht, eine solche Situation zu fördern, aber um ein Verhältnis zu erhalten, bei dem der Stop Loss größer als das endgültige Take Profit ist, können wir etwas Ähnliches verwenden, wie in der Abbildung unten gezeigt:

Abbildung 04
Da der Wert kleiner als eins ist, ist das Verhältnis ungünstig. Wenn Sie den Indikator auf den Chart anwenden, werden Sie ein Ergebnis sehen, das diesem ähnelt:

Abbildung 05
In diesem Beispiel haben wir dieselben Daten als Einstiegspunkte verwendet; das resultierende Ergebnis ist jedoch sehr unterschiedlich, wie beim Vergleich der Abbildungen zu sehen ist. So erhalten wir ein praktisches und funktionelles Werkzeug: Wir können die Anwendung auf dem Chart einzeichnen, eine Analyse durchführen, den Wert ändern (wie in Abbildung 04) und die Analyse wiederholen, was es uns ermöglicht, mehrere Analysen gleichzeitig auf dem Chart zu behalten.
Der einzige Nachteil mag sein, dass sich die Linien überschneiden, aber dies lässt sich leicht lösen, indem der Benutzer die Linienverlängerung nach rechts aktivieren oder deaktivieren kann. Dazu reicht es aus, den Code wie unten gezeigt zu ändern:
. . . 09. //+------------------------------------------------------------------+ 10. input double user01 = 1.5; //Stop-Target Relationship 11. input bool user02 = true; //Extend lines to the right 12. //+------------------------------------------------------------------+ . . . 73. //+------------------------------------------------------------------+ 74. void Modifier_OBJ_FIBO(const string szNameObj) 75. { 76. #define macro_Mod_OBJ_FIBO(txt, pos, cor, width, style) { \ 77. ObjectSetDouble(0, szNameObj, OBJPROP_LEVELVALUE, levels, pos); \ 78. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELCOLOR, levels, cor); \ 79. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELWIDTH, levels, width); \ 80. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELSTYLE, levels, style); \ 81. ObjectSetString(0, szNameObj, OBJPROP_LEVELTEXT, levels, txt); \ 82. levels++; \ 83. } 84. 85. int levels = 0; 86. 87. ObjectSetInteger(0, szNameObj, OBJPROP_SELECTABLE, false); 88. ObjectSetInteger(0, szNameObj, OBJPROP_COLOR, clrNONE); 89. ObjectSetInteger(0, szNameObj, OBJPROP_RAY_RIGHT, user02); 90. 91. macro_Mod_OBJ_FIBO("Stop", 0, clrRed, 2, STYLE_SOLID); 92. macro_Mod_OBJ_FIBO("Enter", 1, clrBlue, 2, STYLE_DASH); 93. macro_Mod_OBJ_FIBO("Partial", 1 + (user01 / 2), clrYellowGreen, 1, STYLE_DASHDOTDOT); 94. macro_Mod_OBJ_FIBO("Take", 1 + user01, clrGreen, 2, STYLE_SOLID); 95. ObjectSetInteger(0, szNameObj, OBJPROP_LEVELS, levels); 96. 97. #undef macro_Mod_OBJ_FIBO 98. } 99. //+------------------------------------------------------------------+
Code 05
Auch dies ist eine einfache Änderung im Fragment Code 05; in diesem Fall fügen wir Zeile 11 hinzu. Ihr Wert wird in Zeile 89 verwendet, um zu steuern, ob die Linie bis zum äußersten rechten Rand verlängert wird. Die folgende Abbildung zeigt eine Einstellung, bei der die Linie nicht verlängert wird.

Abbildung 06
Als Ergebnis erhalten wir auf dem Chart so etwas wie das hier:

Abbildung 07
Bitte beachten Sie: Wir fügen in Abbildung 05 eine neue Analyse hinzu, und obwohl wir die Indikatoreinstellungen (Abbildung 06) geändert haben, ohne sie vom Chart zu entfernen, löscht oder beeinträchtigt dies nicht das, was bereits vorhanden war. Mit nur wenig Aufwand haben wir etwas wirklich Interessantes geschaffen.
Obwohl viele Leute behaupten, dass manche Dinge in MetaTrader 5 unmöglich seien, haben wir gerade gesehen, dass mit minimalem und grundlegendem Wissen fast alles möglich ist, ohne Tricks oder komplexe Methoden anzuwenden.
Das alles war also sehr unterhaltsam, aber es gibt noch ein weiteres Thema, das wir im nächsten Abschnitt analysieren werden.
Verwendung der linken Maustaste zum Erstellen der Zeichnung
Es mag unnatürlich erscheinen, die mittlere Maustaste zum Zeichnen auf dem Chart zu verwenden. Die meisten Benutzer sind es gewohnt, mit der linken Taste zu interagieren, daher fühlt sich die mittlere Taste ungewohnt an. Obwohl mit dem von uns getesteten Code alles perfekt funktioniert, ist dies nicht die vertrauteste Option, und wir als Programmierer müssen dies beheben. Es gibt jedoch eine kleine Nuance.
Wenn die mittlere Maustaste gedrückt wird, werden alle Mausereignisse an Zeile 38 weitergeleitet, wie in Code 02 dargestellt. Während die Taste gedrückt gehalten wird, bleibt das Fadenkreuz sichtbar, was das Erstellen der Zeichnung ermöglicht. Wenn die mittlere Taste losgelassen wird, entfernt Zeile 52 von Code 02 das Fadenkreuz, was darauf hinweist, dass wir nicht mehr mit dem Zeichensystem interagieren können.
Wenn Sie dies verstehen, wird klar, was wir tun müssen: Wenn die mittlere Maustaste gedrückt wird, entsteht ein Ereignis, das auf ein zweites Ereignis warten muss – entweder das Drücken der ESC-Taste oder das Klicken der linken Maustaste –, um die Zeichnung zu erstellen und das Objekt wie zuvor zu positionieren, jedoch unter Verwendung der linken statt der mittleren Taste.
Das ist das Ziel. Es gibt viele Möglichkeiten, dies zu tun, einige arbeitsintensiver als andere; da die Klarheit für Lehrzwecke hier die Hauptpriorität hat, wählen wir den einfachsten Weg, auch wenn wir wissen, dass er nicht in allen Fällen ideal ist. Dies ist im folgenden Codefragment Code 06 zu sehen:
. . . 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. } 037. 038. st_TimePrice tp; 039. static string isPaint = ""; 040. static bool bMouseL = false; 041. 042. switch (id) 043. { 044. case CHARTEVENT_KEYDOWN: 045. if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) macro_CLEAN_EVENT; 046. break; 047. case CHARTEVENT_MOUSE_MOVE: 048. tp = gl_Cross.Move((ushort)lparam, (ushort)dparam); 049. if (((uchar)sparam & MOUSE_LEFT) != 0) 050. { 051. if (isPaint != "") 052. { 053. bMouseL = true; 054. if (!ObjectGetInteger(0, isPaint, OBJPROP_TIME)) ObjectMove(0, isPaint, 0, tp.Time, tp.Price); 055. ObjectMove(0, isPaint, 1, tp.Time, tp.Price); 056. } 057. }else if (bMouseL) macro_CLEAN_EVENT; 058. if ((((uchar)sparam & MOUSE_MIDDLE) != 0) && (isPaint == "")) 059. { 060. ObjectCreate(0, isPaint = macro_NameObject, OBJ_FIBO, 0, 0, 0); 061. Modifier_OBJ_FIBO(isPaint); 062. gl_Cross.Show(); 063. } 064. break; 065. case CHARTEVENT_MOUSE_WHEEL: 066. break; 067. } 068. ChartRedraw(); 069. 070. #undef macro_CLEAN_EVENT 071. }; 072. //+------------------------------------------------------------------+ . . .
Code 06
Darin aktivieren wir das Zeichnen mit der mittleren Taste, zeichnen aber nur, wenn die linke Taste gedrückt wird. Nicht alles ist perfekt: Die Idee funktioniert, aber sie hat ein Problem, das in Animation 03 zu sehen ist:

Animation 03
In dieser Animation ist die Schwierigkeit beim Zeichnen bemerkbar, weil sich das Chart verschiebt. Eine solche Bewegung ist manchmal wünschenswert, aber in diesem Fall behindert sie mehr, als sie hilft. Bevor ich zeige, wie man dies löst, lassen Sie uns die Änderungen betrachten, die erforderlich sind, um die linke Taste zu verwenden, wie in Animation 03 gezeigt.
Zuerst habe ich in Zeile 32 ein Makro hinzugefügt, das es ermöglicht, den aktuellen Zeichenvorgang zu beenden. Dann habe ich bei der Behandlung von Mausereignissen die Ausführungsreihenfolge geändert, damit die Ereignisse korrekt verarbeitet werden: Zuerst wird die mittlere Maustaste gedrückt; in diesem Moment erstellt Zeile 60 das Objekt OBJ_FIBO, konfiguriert es wie erforderlich und zeigt das Fadenkreuz an.
Wenn wir an diesem Punkt die linke Maustaste drücken, wird die Prüfung in Zeile 51 ausgeführt und in Zeile 53 ein neuer Punkt markiert; gleichzeitig platzieren die Zeilen 54 und 55 das Objekt OBJ_FIBO im Chart. Die in Zeile 53 erstellte Markierung ermöglicht es Zeile 57, das Fadenkreuz unmittelbar nach dem Zeichnen des Objekts OBJ_FIBO aus dem Chart zu entfernen, das heißt, wenn die linke Taste losgelassen wird.
Um das zu beheben, was in Animation 03 gezeigt wurde, müssen wir das Fragment Code 06 durch Hinzufügen von zwei neuen Zeilen ändern. Die Änderungen spiegeln sich im folgenden Codefragment wider:
. . . 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. } 070. ChartRedraw(); 071. 072. #undef macro_CLEAN_EVENT 073. }; 074. //+------------------------------------------------------------------+ . . .
Code 07
Bei der Verwendung von Code 07 erhalten wir das Ergebnis, das in der folgenden Animation gezeigt wird:

Animation 04
Es mag merkwürdig erscheinen, dass die einfache Verwendung der Zeilen 36 und 62 im Fragment Code 07 das Problem aus Animation 03 löst. Wenn Sie das denken, liegt es wahrscheinlich daran, dass Sie möglicherweise nicht das ausprobiert haben, was in früheren Artikeln vorgestellt wurde, in denen ich bereits genau diese Funktionen unter anderem gezeigt habe. Allerdings hatten wir zu diesem Zeitpunkt die Standardkonfiguration von MetaTrader 5 noch nicht aktiviert und deaktiviert, um eine Interaktion wie die aktuelle zu ermöglichen.
Schlussfolgerung
Vielleicht war dieser Artikel bisher der unterhaltsamste. Indem wir nur einen kleinen Teil dessen verwenden, was gesehen und erklärt wurde, ist es uns gelungen, etwas zu implementieren, das in MetaTrader 5 standardmäßig nicht verfügbar ist, was es uns ermöglichte, einen sehr beeindruckenden Indikator zu erstellen, indem wir ein bestehendes Objekt auf der Plattform für andere Zwecke modifizierten.
Ich weiß, dass viele Leute dachten, sie müssten viel mehr lernen, bevor sie etwas so Interessantes und gleichzeitig so Angenehmes programmieren könnten. Die Arbeit endet hier jedoch nicht: Der von uns vorgestellte Indikator enthält noch einen kleinen Fehler. Wir haben ihn absichtlich so gelassen, damit Sie das Beheben von Fehlern üben können. Wir werden erklären, worin das Problem besteht, aber die Lösung liegt bei Ihnen.
Im Code 07-Fragment erstellt Zeile 61 das OBJ_FIBO-Objekt, bevor das Fadenkreuz in Zeile 64 angezeigt wird. Das Problem ist, dass, wenn der Benutzer oder Sie die ESCAPE-Taste drücken, Zeile 46 ausgeführt und das Fadenkreuz aus dem Chart entfernt wird, das in Zeile 61 erstellte OBJ_FIBO-Objekt jedoch in der Objektliste verbleibt, obwohl es nicht sichtbar ist, da es nicht positioniert wurde.
Ihre Aufgabe ist es, dies so zu lösen, dass das OBJ_FIBO-Objekt nur dann zur Objektliste hinzugefügt wird, wenn die linke Maustaste gedrückt wird, nachdem die mittlere Maustaste gedrückt wurde. Erinnern Sie sich an das Problem, das bei der Erstellung des Objekts nach der Generierung des Fadenkreuzes auftrat, und daran, wie wir einen Weg aufgezeigt haben, es zu lösen?
Die Lösung für dieses Problem ist sehr ähnlich: Es reicht aus, die Ausführungsreihenfolge bestimmter Operationen im Code 07-Fragment zu ändern; es ist nicht notwendig, Unterroutinen zu erstellen oder neue Funktionen oder Prozeduren hinzuzufügen. Wenn die Operationen korrekt neu angeordnet werden, kann das Fadenkreuz entfernt und die unnötige Erstellung des OBJ_FIBO-Objekts verhindert werden. Somit kann der Benutzer die ESCAPE-Taste drücken, und die Objektliste wird kein unsichtbares Objekt enthalten, das nicht auf dem Chart angezeigt wird.
Der in diesem Artikel verwendete Code ist im Anhang zu finden. Üben Sie die Lösung dieser Aufgabe, und wir sehen uns im nächsten Artikel wieder.
| MQ5-Datei | Beschreibung |
|---|---|
| Code 01 | Objektdemonstration |
| Code 02 | Objektdemonstration |
| Code 03 | Objektdemonstration |
| Code 04 | Objektdemonstration |
| Code 05 | Objektdemonstration |
Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/16026
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Die Übertragung der Trading-Signale in einem universalen Expert Advisor.
Marktsimulation (Teil 24): Positionsansicht (II)
Eine alternative Log-datei mit der Verwendung der HTML und CSS
Neuronale Netze im Trading: LSTM-Optimierung zur Prognose multivariater Zeitreihen (DA-CG-LSTM)
- 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.