Marktsimulation: Positionsdarstellung (III)
Einführung
Hallo und herzlich willkommen zu einem weiteren Artikel in der Serie über die Erstellung eines Replikations-/Simulationssystems.
Im vorherigen Artikel, Marktsimulation: Positionsansicht (II), haben wir eine sehr einfache Lösung erstellt, die dazu dient, die mit einer offenen Position verbundenen Preislinien im Chart anzuzeigen. Obwohl dieser Indikator uns die notwendigen Informationen liefern kann, ist er noch nicht für den praktischen Einsatz bereit, da einige kleinere Probleme gelöst werden müssen. Aber daran ist nichts kompliziert. Es ist lediglich etwas, das Sie, lieber Leser, verstehen müssen, bevor wir bei der Implementierung des Codes ein wenig weitergehen können.
Um die Dinge ein wenig einfacher und verständlicher zu machen, werden wir uns dies in einem separaten Thema ansehen, das nur dieser Aufgabe gewidmet ist. Lassen Sie uns also ohne weiteres Zögern zur Sache kommen.
Die Eigenschaft ZOrder verstehen
Ich weiß nicht, ob Sie, lieber Leser, bemerkt haben, dass MQL5-Objekte eine Eigenschaft haben, die selten verwendet oder explizit im Code definiert wird. Ich selbst habe viel Code studiert und niemanden gefunden, der diese Objekteigenschaft in der Praxis tatsächlich definiert. Ich spreche von der Eigenschaft ZOrder. Wenn Sie dieser Artikelserie gefolgt sind, haben Sie wahrscheinlich bemerkt, dass diese Eigenschaft schon seit geraumer Zeit in der Klasse C_Terminal definiert wird, wenn Objekte über den Aufruf CreateObjectGraphics erstellt werden, was eine Prozedur dieser Klasse ist.
Und in diesen letzten Artikeln habe ich erwähnt, dass wir in bestimmten Momenten einen Wert für diese Eigenschaft festlegen müssen. Aber warum? Der Grund dafür ist, dass viele Codeteile, die Objekte in einem Chart hinzufügen, einfach keinen Wert für diese Eigenschaft verwenden oder, genauer gesagt, nicht definieren. Es geht mir nicht darum, zu sagen, was Programmierer tun oder lassen sollen und wie sie ihren Code schreiben sollten. Ich bin hier, um Ihnen, lieber Leser, und jedem, der wirklich verstehen will, wie diese Prozesse intern funktionieren, zu zeigen, was tatsächlich hinter den Kulissen passiert.
Ohne zu verstehen, was ich erklären werde, oder ohne sich bestimmte Konzepte der Verwendung von MetaTrader 5 oder sogar der Programmierung in MQL5 sicher anzueignen, werden Sie zweifellos mit der Plattform sehr schlechte Erfahrungen machen. Und eines dieser Konzepte steht in direktem Zusammenhang mit der Eigenschaft ZOrder.
Um so deutlich wie möglich zu zeigen, wovon wir sprechen, verwenden wir den folgenden Code:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property version "1.00" 04. #property indicator_chart_window 05. #property indicator_plots 0 06. //+------------------------------------------------------------------+ 07. input char user00 = 0; //ZOrder to Chart #01 08. input char user01 = 0; //ZOrder to Chart #02 09. //+------------------------------------------------------------------+ 10. void ChartOfTest(string sz1, int x, int y, int zOrder) 11. { 12. long id = ChartID(); 13. 14. ObjectCreate(id, sz1, OBJ_CHART, 0, 0, 0); 15. ObjectSetInteger(id, sz1, OBJPROP_XDISTANCE, x); 16. ObjectSetInteger(id, sz1, OBJPROP_YDISTANCE, y); 17. ObjectSetInteger(id, sz1, OBJPROP_ZORDER, zOrder); 18. ObjectSetInteger(id, sz1, OBJPROP_SELECTABLE, true); 19. } 20. //+------------------------------------------------------------------+ 21. int OnInit() 22. { 23. ChartOfTest("Chart #01", 160, 140, user00); 24. ChartOfTest("Chart #02", 200, 200, user01); 25. 26. return INIT_SUCCEEDED; 27. } 28. //+------------------------------------------------------------------+ 29. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 30. { 31. return rates_total; 32. } 33. //+------------------------------------------------------------------+ 34. void OnDeinit(const int reason) 35. { 36. ObjectsDeleteAll(ChartID(), "Chart #"); 37. } 38. //+------------------------------------------------------------------+
Quellcode des Indikators
Dieser einfache Code tut genau das, was wir brauchen, um zu verstehen, wie die Eigenschaft ZOrder die Benutzererfahrung in MetaTrader 5 beeinflussen kann und wird. Beachten Sie, dass wir in den Zeilen 23 und 24 die Prozedur aufrufen, die für die Erstellung von zwei Objekten und deren Platzierung auf dem aktuell geöffneten Chart verantwortlich ist. Die erstellten Objekte sind vom Typ OBJ_CHART, wie in Zeile 14 zu sehen ist. Der Einfachheit halber haben wir, lieber Leser, in den Zeilen 07 und 08 zwei Eingabeparameter bereitgestellt. Ihr Zweck ist es, uns das ständige Anpassen der ZOrder-Werte der Objekte zu ersparen.
Standardmäßig sind die Werte immer null. Also lassen wir sie vorerst so, wie sie sind. Das Ergebnis ist in der folgenden Abbildung zu sehen:

Etwas Einfaches und Offensichtliches, wie erwartet. „Aber was passiert, wenn wir den Zeitrahmen des Charts ändern? Was wird in diesem Chartfenster passieren, in dem wir einen Indikator haben, dessen Zweck es ist, einen Hintergrund für den Chart zu erstellen? Könnte es dazu kommen, dass wir in einer Situation landen, in der wir nicht mehr mit den OBJ_CHART-Objekten interagieren können?“ Nun, dies ist in der folgenden Animation zu sehen:

Beachten Sie, dass dies normalerweise Probleme verursachen würde, obwohl sich das Hintergrundbild, also ein Objekt vom Typ OBJ_BITMAPLABEL, über den OBJ_CHART-Objekten befindet. Der Hintergrund des OBJ_CHART-Objekts ist nicht mehr schwarz, sondern zeigt den Inhalt des Bereichs, in dem es sich befindet, über dem OBJ_BITMAPLABEL-Objekt an. Da wir jedoch in Zeile 17 einen Wert von null für ZOrder festgelegt haben, während der ZOrder-Wert des Objekts mit dem Hintergrundbild niedriger ist, in diesem Fall -1, wie wir in früheren Artikeln gesehen haben, werden das Klickverhalten und das Auswahlverhalten der OBJ_CHART-Objekte nicht beeinträchtigt, wie in der obigen Animation zu sehen ist.
Wir werden jedoch die klare Illusion haben, dass das Objekt im Vordergrund Priorität hat, wie in der folgenden Animation zu sehen ist:

Wie ich gerade sagte, ist dies eine Illusion, da das Objekt, das sich tatsächlich im Vordergrund befindet, das OBJ_BITMAPLABEL ist, das das Bild enthält, welches das gesamte Chart ausfüllt und dadurch das Hintergrundbild erzeugt. Aber diese Illusion wird noch faszinierender, wenn wir die Priorität der Objekte ändern. Um dies mit dem obigen Code zu tun, schlage ich vor, sich die folgende Animation anzusehen:

Beachten Sie, dass wir die Priorität des darunter liegenden Objekts, nämlich CHART #01, geändert haben. Da es also eine höhere Priorität hat, erhalten wir das in der Animation gezeigte Ergebnis. Wenn Sie dies nicht verstanden haben, testen Sie es in Ihrem eigenen MetaTrader 5-Terminal. Sie werden feststellen, dass selbst wenn Sie auf einen Bereich klicken, der zu CHART #02 gehört, aber auch zu CHART #01 gehört, CHART #01 ausgewählt wird. Sie können CHART #02 nur dann auswählen, wenn Sie auf einen Bereich außerhalb von CHART #01 klicken, der jedoch zu CHART #02 gehört. Wenn sich beide im exakt gleichen Bereich befinden, hat CHART #01 Priorität, selbst wenn es von CHART #02 verdeckt wird.
Dies wird zweifellos viel interessanter, wenn Sie versuchen, Werte für OBJ_CHART festzulegen, die kleiner oder gleich dem Wert des OBJ_BITMAPLABEL-Objekts sind, das als Hintergrundbild fungiert. Oder wenn Sie ein weiteres Objekt mithilfe des unten in der folgenden Abbildung gezeigten Tastenkürzels bzw. Schnellbefehls platzieren.

Versuchen Sie Folgendes: Fügen Sie ein weiteres OBJ_CHART hinzu, diesmal jedoch unter Verwendung des zuvor gezeigten Tastaturkürzels, und spielen Sie mit den Indikatorwerten, wie in der vorherigen Animation gezeigt. Ohne Zweifel werden Sie beginnen, die Bedeutung der Verwendung eines geeigneten Wertes in der ZOrder-Eigenschaft zu verstehen. Aber wo genau wird dies bei dem, was wir derzeit entwickeln, angewendet? Nun, um dies auf die angemessenste Weise zu beantworten und die Themen dadurch zu trennen, werden wir uns dies in einem neuen Thema ansehen.
Anwendung des gewonnenen Wissens
Nun, das Wissen und Verständnis dessen, was erklärt wurde, sind äußerst wichtig, damit Sie verstehen können, was wir während der Implementierung tun werden. Später wird dies seine Bedeutung verlieren, da wir einen anderen Ansatz verfolgen werden. Aber für den Moment ist es wichtig, insbesondere abhängig davon, wie Sie den Code für Ihren persönlichen Gebrauch ändern oder anpassen.
Im vorherigen Artikel haben wir drei Linien erstellt: eine für den Eröffnungskurs der Position, eine für das Stop-Loss-Niveau und eine für das Take-Profit-Niveau. Sehr gut. Bis zu diesem Punkt ist an dem, was getan wurde, nichts auszusetzen. Die horizontale Linie, die den Eröffnungskurs markiert, sollte niemals verschiebbar sein. Wir werden das in Kürze korrigieren. Im Gegensatz dazu können die horizontalen Linien für Stop-Loss und Take-Profit frei verschoben werden. Und hier haben wir ein Problem, wenn beide Linien, die Stop-Loss-Linie und die Take-Profit-Linie, auf demselben Kursniveau liegen.
Welche Linie sollte in diesem Fall Vorrang haben, wenn man versucht, eine von ihnen auszuwählen? Dies ist notwendig, damit das System ein bestimmtes Ereignis empfängt, zum Beispiel, dass die Linie verschoben oder sogar gelöscht wird. Sie könnten sagen, dass es der Stop-Loss sein sollte, während ein anderer Trader sagen könnte, dass es der Take-Profit sein sollte. Wer hätte in einer solchen Situation tatsächlich recht?
Verstehen Sie jetzt das Problem? In gewisser Weise hängt diese Entscheidung von der Reihenfolge ab, in der die Linien erstellt werden, wenn beide Linien denselben ZOrder-Wert haben. Daher würde eine einfache Änderung der Erstellungsreihenfolge viele der Probleme lösen. Lassen Sie uns diese Situation jedoch auf eine noch extremere Ebene heben. Es ist nichts Ungewöhnliches daran, dass einige Trader, insbesondere bei HEDGING-Konten, mehr als eine offene Position haben. In diesem Fall kann es erforderlich sein, einen unterschiedlichen ZOrder-Wert zwischen der Stop-Loss-Linie und der Take-Profit-Linie festzulegen. Aber selbst wenn dies getan wird, was das Problem des Zusammenfallens von Stop-Loss-Linie und Take-Profit-Linie beseitigen würde, würde ein weiteres Problem entstehen: wenn zwei Linien, zum Beispiel zwei Stop-Loss-Linien, versehentlich überlappen.
Ist Ihnen aufgefallen, dass jede Änderung des ZOrder-Werts bedeutungslos wird? Selbst wenn Sie unterschiedliche Werte verwenden, um eine Aufgabe zu lösen, wird es immer eine andere geben, die gelöst werden muss. Laut einigen professionellen Tradern, die mich bei einer Reihe von Aspekten im Zusammenhang mit der Entwicklung und Implementierung des Replikations-/Simulationssystems beraten, gibt es jedoch keinen praktischen Grund, mehr als zwei, drei oder höchstens vier solcher Entitäten/Einträge auf dem Server zu führen. Mit anderen Worten, nach ihrer Meinung ist es bei Verwendung eines HEDGING-Kontos nicht sinnvoll, mehr als zwei, drei oder höchstens vier offene Positionen gleichzeitig zu halten, da dieses Problem bei einem NETTING-Konto nicht existiert. In diesem Anfangsstadium werde ich nur HEDGING-Konten berücksichtigen. Dies bedeutet jedoch nicht, dass der Indikator auf NETTING-Konten nicht funktioniert.
Kehren wir also zu dem Code zurück, den wir im vorherigen Artikel untersucht haben. Dort haben wir die Stop-Loss- und Take-Profit-Linien mit derselben ZOrder implementiert. Um dies zu ändern, müssen wir kleine Änderungen am Code vornehmen. Die Änderungen sind so geringfügig, dass wir nicht ins Detail gehen werden. Sehen Sie sich einfach an, wie der modifizierte Code aussehen wird:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Indicator for tracking an open position on the server." 04. #property version "1.00" 05. #property indicator_chart_window 06. #property indicator_plots 0 07. //+------------------------------------------------------------------+ 08. #define def_SufixLinePrice "Price" 09. #define def_SufixLineTake "Take" 10. #define def_SufixLineStop "Stop" 11. //+------------------------------------------------------------------+ 12. #include <Market Replay\Auxiliar\C_Terminal.mqh> 13. //+------------------------------------------------------------------+ 14. input color user00 = clrRoyalBlue; //Color Line Price 15. input color user01 = clrForestGreen; //Color Line Take Profit 16. input color user02 = clrFireBrick; //Color Line Stop Loss 17. //+------------------------------------------------------------------+ 18. C_Terminal *Terminal; 19. struct st 20. { 21. long id; 22. string szPrefixName; 23. }glVariables; 24. //+------------------------------------------------------------------+ 25. void CreateLineInfos(const string szObjName, const double price, const color cor, const string szDescription = "\n") 26. { 27. if (price <= 0) return; 28. (*Terminal).CreateObjectGraphics(szObjName, OBJ_HLINE, cor, (EnumPriority)(cor == user00 ? ePriorityNull : (ePriorityOrders + (cor == user02)))); 29. ObjectSetDouble(glVariables.id, szObjName, OBJPROP_PRICE, price); 30. ObjectSetString(glVariables.id, szObjName, OBJPROP_TEXT, szDescription); 31. ObjectSetString(glVariables.id, szObjName, OBJPROP_TOOLTIP, szDescription); 32. ObjectSetInteger(glVariables.id, szObjName, OBJPROP_SELECTABLE, cor != user00); 33. } 34. //+------------------------------------------------------------------+ 35. int OnInit() 36. { 37. ZeroMemory(glVariables); 38. Terminal = new C_Terminal(); 39. if (!PositionSelect((*Terminal).GetInfoTerminal().szSymbol)) return INIT_FAILED; 40. glVariables.id = (*Terminal).GetInfoTerminal().ID; 41. glVariables.szPrefixName = IntegerToString(PositionGetInteger(POSITION_TICKET)); 42. CreateLineInfos(glVariables.szPrefixName + def_SufixLinePrice, PositionGetDouble(POSITION_PRICE_OPEN), user00, "Position opening price."); 43. CreateLineInfos(glVariables.szPrefixName + def_SufixLineTake, PositionGetDouble(POSITION_TP), user01, "Take Profit point."); 44. CreateLineInfos(glVariables.szPrefixName + def_SufixLineStop, PositionGetDouble(POSITION_SL), user02, "Stop Loss point."); 45. 46. return INIT_SUCCEEDED; 47. } 48. //+------------------------------------------------------------------+ 49. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 50. { 51. return rates_total; 52. } 53. //+------------------------------------------------------------------+ 54. void OnDeinit(const int reason) 55. { 56. delete Terminal; 57. if (glVariables.id > 0) 58. ObjectsDeleteAll(glVariables.id, glVariables.szPrefixName); 59. } 60. //+------------------------------------------------------------------+
Position View Indikator
Bitte beachten Sie, dass die Stop-Loss-Linie nun Vorrang vor der Take-Profit-Linie hat. Dies erklärt sich durch den höheren ZOrder-Wert. Wenn wir dann zwei offene Positionen haben und die Stop-Loss-Linie auf demselben Preisniveau wie die Take-Profit-Linie liegt, hat bei jedem Versuch, mit diesen Linien zu interagieren, die Stop-Loss-Linie Vorrang. Beachten Sie, dass die einzige Änderung, die dazu führte, in Zeile 28 erfolgte. Vergleichen Sie diese Zeile mit der gleichen Zeile im vorherigen Code, um die Änderung zu verstehen.
Obwohl dieser Indikator jedoch funktioniert, ist er nicht für die Verwendung auf HEDGING-Konten geeignet. Der Grund dafür ist, dass das System immer entweder nach der ersten oder der letzten offenen Position sucht. Und selbst wenn Sie etwas unternehmen, um dies zu ändern, wird es so oder so keine wirkliche Auswirkung haben. Wir müssen eine Lösung implementieren, die effektivere Ergebnisse liefert und allgemeiner verwendbar ist. Darüber hinaus können Sie sehen, dass wir verschiedene Farben verwenden, damit der Indikator versteht, wofür jede Linie steht. Solche Lösungen sind für Tests nützlich. Sie sind jedoch für einen allgemeineren Einsatz völlig ungeeignet. Daher haben wir immer noch viele Probleme zu lösen und zu korrigieren.
In diesem Stadium geben viele Leute, die gerade erst mit dem Programmieren anfangen, oft auf oder nehmen so viele Änderungen vor, dass sie schließlich die Kontrolle über den Code verlieren, den sie erstellen. Wenn Sie also bereits programmieren können und über das richtige Grundwissen verfügen, bitte ich Sie, geduldig mit denjenigen zu sein, die weniger Erfahrung haben, denn ich werde zeigen, wie Anfänger anfangen sollten zu denken, damit sie sich aufrichtig in die Kunst des Programmierens verlieben und lernen können, ihre eigenen Lösungen zu erstellen.
Beginn der Korrektur der Situation
Wenn Sie, lieber Leser, auf Code wie den oben gezeigten stoßen, der verbessert werden muss, beginnen Sie nicht planlos mit der Änderung. Beginnen Sie damit, die Aufgabe in Teile zu unterteilen, aber stellen Sie immer sicher, dass der Code funktionsfähig bleibt. Nein, und ich wiederhole: ÄNDERN SIE NICHTS, bis Sie die Komponenten getrennt haben. Eine der einfachsten und geeignetsten Methoden hierfür ist es, einige Teile des Codes in einer Header-Datei zu platzieren, damit Sie dann sofort mit der Änderung beginnen können. Da es jedoch viel einfacher ist, alle Teile in einer Klasse zusammenzufassen, werden wir genau das tun. Aber warum ist es einfacher, den Code in einer Klasse zu platzieren, als ihn in Header-Dateien aufzuteilen?
Der Grund ist einfach: Wenn Sie den Code in einer Klasse platzieren, können Sie ihn später in eine Header-Datei verschieben. Das bloße Verschieben in eine Header-Datei erleichtert die Verwaltung jedoch nicht. Dies liegt daran, dass in Zukunft Namenskonflikte auftreten können. Solche Konflikte sind in Codebasen, die viele Dateien enthalten, keine Seltenheit. Wenn wir Elemente stattdessen in eine Klasse verschieben, wird die Wahrscheinlichkeit von Konflikten erheblich verringert. Das bedeutet nicht, dass sie vollständig beseitigt sind, wie Sie selbst sehen werden, wenn Sie in der Programmierung vorankommen. Die Lösung solcher Konflikte wird jedoch viel einfacher und schneller. Vor diesem Hintergrund beginnen wir damit, die Elemente in eine neue Klasse innerhalb des Replikations-/Simulationssystems zu verschieben.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Indicator for tracking an open position on the server." 04. #property version "1.00" 05. #property indicator_chart_window 06. #property indicator_plots 0 07. //+------------------------------------------------------------------+ 08. #define def_SufixLinePrice "Price" 09. #define def_SufixLineTake "Take" 10. #define def_SufixLineStop "Stop" 11. //+------------------------------------------------------------------+ 12. #include <Market Replay\Auxiliar\C_Terminal.mqh> 13. //+------------------------------------------------------------------+ 14. input color user00 = clrRoyalBlue; //Color Line Price 15. input color user01 = clrForestGreen; //Color Line Take Profit 16. input color user02 = clrFireBrick; //Color Line Stop Loss 17. //+------------------------------------------------------------------+ 18. class C_IndicatorPosition 19. { 20. private : 21. struct st00 22. { 23. long id; 24. string szPrefixName; 25. }m_Infos; 26. //+------------------------------------------------------------------+ 27. void CreateLineInfos(const string szObjName, const double price, const color cor, const string szDescription = "\n") 28. { 29. if (price <= 0) return; 30. (*Terminal).CreateObjectGraphics(szObjName, OBJ_HLINE, cor, (EnumPriority)(cor == user00 ? ePriorityNull : (ePriorityOrders + (cor == user02)))); 31. ObjectSetDouble(m_Infos.id, szObjName, OBJPROP_PRICE, price); 32. ObjectSetString(m_Infos.id, szObjName, OBJPROP_TEXT, szDescription); 33. ObjectSetString(m_Infos.id, szObjName, OBJPROP_TOOLTIP, szDescription); 34. ObjectSetInteger(m_Infos.id, szObjName, OBJPROP_SELECTABLE, cor != user00); 35. } 36. //+------------------------------------------------------------------+ 37. public : 38. //+------------------------------------------------------------------+ 39. C_IndicatorPosition(const long Id) 40. { 41. ZeroMemory(m_Infos); 42. m_Infos.id = Id; 43. m_Infos.szPrefixName = IntegerToString(PositionGetInteger(POSITION_TICKET)); 44. CreateLineInfos(m_Infos.szPrefixName + def_SufixLinePrice, PositionGetDouble(POSITION_PRICE_OPEN), user00, "Position opening price."); 45. CreateLineInfos(m_Infos.szPrefixName + def_SufixLineTake, PositionGetDouble(POSITION_TP), user01, "Take Profit point."); 46. CreateLineInfos(m_Infos.szPrefixName + def_SufixLineStop, PositionGetDouble(POSITION_SL), user02, "Stop Loss point."); 47. } 48. //+------------------------------------------------------------------+ 49. ~C_IndicatorPosition() 50. { 51. if (m_Infos.id > 0) 52. ObjectsDeleteAll(m_Infos.id, m_Infos.szPrefixName); 53. } 54. //+------------------------------------------------------------------+ 55. }; 56. //+------------------------------------------------------------------+ 57. C_Terminal *Terminal; 58. C_IndicatorPosition *Positions; 59. //+------------------------------------------------------------------+*/ 60. int OnInit() 61. { 62. Terminal = new C_Terminal(); 63. if (!PositionSelect((*Terminal).GetInfoTerminal().szSymbol)) return INIT_FAILED; 64. Positions = new C_IndicatorPosition((*Terminal).GetInfoTerminal().ID); 65. 66. return INIT_SUCCEEDED; 67. } 68. //+------------------------------------------------------------------+ 69. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 70. { 71. return rates_total; 72. } 73. //+------------------------------------------------------------------+ 74. void OnDeinit(const int reason) 75. { 76. delete Terminal; 77. delete Positions; 78. } 79. //+------------------------------------------------------------------+
Quellcode der Positionsansicht
Im folgenden Code könnte man meinen, wir hätten die Komplexität erhöht. Tatsächlich haben wir jedoch lediglich den Code, der sich zuvor außerhalb der Klasse befand, in die Klasse verschoben. Entgegen dem Anschein fügen wir also keine Komplexität hinzu, sondern verbessern die Art und Weise, wie die Elemente implementiert sind, da derselbe Code, der zuvor existierte, nun besser geschützt ist und es uns ermöglicht, Aufgaben effektiver zu trennen. Ich spreche von einem höheren Grad an Schutz, da die Funktion CreateLineInfos jetzt privat ist. Das heißt, der aufrufende Code oder der Benutzer muss nicht genau wissen, wie der Indikator erstellt wird. Er fordert einfach die Erstellung des Indikators an. Die Art und Weise, wie dies implementiert ist, kann sich im Laufe der Zeit erheblich ändern, aber für den Benutzer bleibt sie immer gleich.
Das, was ich gerade gezeigt habe, löst jedoch keines unserer Probleme. Es macht es lediglich einfacher, den Code effizienter zu implementieren. Beachten Sie, dass der gesamte Code exakt derselbe bleibt wie zuvor und sich seine Funktionsweise überhaupt nicht geändert hat. Dies ist das Erste, was wir immer sicherstellen müssen. Ändern Sie den Code nicht, bis er exakt so funktioniert wie vor dem Einfügen in die Klasse. Danach hängen weitere Schritte davon ab, was Sie zuerst benötigen oder tun möchten. Da die Klasse jedoch bereits erstellt wurde, können wir sie sofort in eine Header-Datei einfügen. Auf diese Weise vermeiden wir es, den Hauptcode unnötig zu überladen. Dann erstellen wir eine Datei mit demselben Namen wie die Klasse, die darin platziert wird. Obwohl dies eine gute Programmierpraxis ist, ist sie nicht zwingend erforderlich. Der neue Hauptcode ist daher unten zu sehen:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Indicator for tracking an open position on the server." 04. #property version "1.00" 05. #property indicator_chart_window 06. #property indicator_plots 0 07. //+------------------------------------------------------------------+ 08. #include <Market Replay\Auxiliar\C_Terminal.mqh> 09. #include <Market Replay\Order System\C_IndicatorPosition.mqh> 10. //+------------------------------------------------------------------+ 11. input color user00 = clrRoyalBlue; //Color Line Price 12. input color user01 = clrForestGreen; //Color Line Take Profit 13. input color user02 = clrFireBrick; //Color Line Stop Loss 14. //+------------------------------------------------------------------+ 15. C_Terminal *Terminal; 16. C_IndicatorPosition *Positions; 17. //+------------------------------------------------------------------+ 18. int OnInit() 19. { 20. Terminal = new C_Terminal(); 21. if (!PositionSelect((*Terminal).GetInfoTerminal().szSymbol)) return INIT_FAILED; 22. Positions = new C_IndicatorPosition((*Terminal).GetInfoTerminal().ID); 23. 24. return INIT_SUCCEEDED; 25. } 26. //+------------------------------------------------------------------+ 27. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 28. { 29. return rates_total; 30. } 31. //+------------------------------------------------------------------+ 32. void OnDeinit(const int reason) 33. { 34. delete Terminal; 35. delete Positions; 36. } 37. //+------------------------------------------------------------------+
Quellcode der Positionsansicht
Wo ist der Klassencode geblieben? Nun, er befindet sich jetzt in der Datei, deren Speicherort in Zeile 09 des obigen Codes angegeben ist. Bitte beachten Sie, dass die Klasse einige Daten mitgenommen hat, die zuvor hier im Hauptcode vorhanden waren. Dies liegt daran, dass der Benutzer, wie bereits erwähnt, nicht wissen muss, wie alles angeordnet ist. Sie müssen nur wissen, was genau aufgerufen werden muss und welche Parameter an den Klassencode übergeben werden sollten. Wie die Klasse die Daten verarbeitet, ist für den aufrufenden Code nicht von Interesse. Schauen Sie sich also den unten gezeigten Code der Header-Datei C_IndicatorPosition an:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #define def_SufixLinePrice "Price" 05. #define def_SufixLineTake "Take" 06. #define def_SufixLineStop "Stop" 07. //+------------------------------------------------------------------+ 08. class C_IndicatorPosition 09. { 10. private : 11. struct st00 12. { 13. long id; 14. string szPrefixName; 15. }m_Infos; 16. //+------------------------------------------------------------------+ 17. void CreateLineInfos(const string szObjName, const double price, const color cor, const string szDescription = "\n") 18. { 19. if (price <= 0) return; 20. (*Terminal).CreateObjectGraphics(szObjName, OBJ_HLINE, cor, (EnumPriority)(cor == user00 ? ePriorityNull : (ePriorityOrders + (cor == user02)))); 21. ObjectSetDouble(m_Infos.id, szObjName, OBJPROP_PRICE, price); 22. ObjectSetString(m_Infos.id, szObjName, OBJPROP_TEXT, szDescription); 23. ObjectSetString(m_Infos.id, szObjName, OBJPROP_TOOLTIP, szDescription); 24. ObjectSetInteger(m_Infos.id, szObjName, OBJPROP_SELECTABLE, cor != user00); 25. } 26. //+------------------------------------------------------------------+ 27. public : 28. //+------------------------------------------------------------------+ 29. C_IndicatorPosition(const long Id) 30. { 31. ZeroMemory(m_Infos); 32. m_Infos.id = Id; 33. m_Infos.szPrefixName = IntegerToString(PositionGetInteger(POSITION_TICKET)); 34. CreateLineInfos(m_Infos.szPrefixName + def_SufixLinePrice, PositionGetDouble(POSITION_PRICE_OPEN), user00, "Position opening price."); 35. CreateLineInfos(m_Infos.szPrefixName + def_SufixLineTake, PositionGetDouble(POSITION_TP), user01, "Take Profit point."); 36. CreateLineInfos(m_Infos.szPrefixName + def_SufixLineStop, PositionGetDouble(POSITION_SL), user02, "Stop Loss point."); 37. } 38. //+------------------------------------------------------------------+ 39. ~C_IndicatorPosition() 40. { 41. if (m_Infos.id > 0) 42. ObjectsDeleteAll(m_Infos.id, m_Infos.szPrefixName); 43. } 44. //+------------------------------------------------------------------+ 45. }; 46. //+------------------------------------------------------------------+ 47. #undef def_SufixLinePrice 48. #undef def_SufixLineTake 49. #undef def_SufixLineStop 50. //+------------------------------------------------------------------+
Quellcode für C_IndicatorPosition.mqh
Beachten Sie, dass der Code gleich geblieben ist. Am Ende der Datei wurden nur drei neue Zeilen hinzugefügt. Ihr Zweck ist es, Definitionen zu entfernen, die nur innerhalb dieser Header-Datei sinnvoll sind. Mit anderen Worten: Wir wenden das Prinzip der minimalen Rechtevergabe an. Oder, um es klarer auszudrücken: Niemand muss wissen, was ihn nichts angeht. Dies verhindert, dass Informationen ohne Ihr Wissen nach außen dringen. Darüber hinaus ist dies natürlich eine gute Programmierpraxis, da andere Codeteile dieselben Namen verwenden könnten, die Sie hier definiert haben. Und wenn Sie diese hier nicht entfernen, müssen Sie dies an anderer Stelle tun, was bei der Verbesserung sehr umfangreicher Codes viele Unannehmlichkeiten verursacht, da Definitionskonflikte zu unsinnigen Fehlern führen.
Gut. Wenn Sie sich jedoch jetzt nur den Code in der Header-Datei ansehen, werden Sie feststellen, dass er Werte deklariert und verwendet, die vom Hauptcode abhängen. Dies schafft ein Problem, da bei Änderungen am Hauptcode auch diese Header-Datei geändert werden muss. Mit anderen Worten: Das ist ein enormer Arbeitsaufwand, also müssen wir das beheben. Eine gute Lösung besteht darin, dass der Hauptcode diese Werte unabhängig übergibt. Daher finden Sie unten die neue Header-Datei mit den bereits vorgenommenen Änderungen.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #define def_SufixLinePrice "Price" 05. #define def_SufixLineTake "Take" 06. #define def_SufixLineStop "Stop" 07. //+------------------------------------------------------------------+ 08. class C_IndicatorPosition 09. { 10. private : 11. struct st00 12. { 13. long id; 14. string szPrefixName; 15. color corPrice, corTake, corStop; 16. }m_Infos; 17. //+------------------------------------------------------------------+ 18. void CreateLineInfos(const string szObjName, const double price, const color cor, const string szDescription = "\n") 19. { 20. if (price <= 0) return; 21. (*Terminal).CreateObjectGraphics(szObjName, OBJ_HLINE, cor, (EnumPriority)(cor == m_Infos.corPrice ? ePriorityNull : (ePriorityOrders + (cor == m_Infos.corStop)))); 22. ObjectSetDouble(m_Infos.id, szObjName, OBJPROP_PRICE, price); 23. ObjectSetString(m_Infos.id, szObjName, OBJPROP_TEXT, szDescription); 24. ObjectSetString(m_Infos.id, szObjName, OBJPROP_TOOLTIP, szDescription); 25. ObjectSetInteger(m_Infos.id, szObjName, OBJPROP_SELECTABLE, cor != m_Infos.corPrice); 26. } 27. //+------------------------------------------------------------------+ 28. public : 29. //+------------------------------------------------------------------+ 30. C_IndicatorPosition(const long Id, color corPrice, color corTake, color corStop) 31. { 32. ZeroMemory(m_Infos); 33. m_Infos.id = Id; 34. m_Infos.szPrefixName = IntegerToString(PositionGetInteger(POSITION_TICKET)); 35. CreateLineInfos(m_Infos.szPrefixName + def_SufixLinePrice, PositionGetDouble(POSITION_PRICE_OPEN), m_Infos.corPrice = corPrice, "Position opening price."); 36. CreateLineInfos(m_Infos.szPrefixName + def_SufixLineTake, PositionGetDouble(POSITION_TP), m_Infos.corTake = corTake, "Take Profit point."); 37. CreateLineInfos(m_Infos.szPrefixName + def_SufixLineStop, PositionGetDouble(POSITION_SL), m_Infos.corStop = corStop, "Stop Loss point."); 38. } 39. //+------------------------------------------------------------------+ 40. ~C_IndicatorPosition() 41. { 42. if (m_Infos.id > 0) 43. ObjectsDeleteAll(m_Infos.id, m_Infos.szPrefixName); 44. } 45. //+------------------------------------------------------------------+ 46. }; 47. //+------------------------------------------------------------------+ 48. #undef def_SufixLinePrice 49. #undef def_SufixLineTake 50. #undef def_SufixLineStop 51. //+------------------------------------------------------------------+
C_IndicatorPosition.mqh
Bitte beachten Sie, dass der Konstruktor nun drei neue Argumente akzeptieren muss. Sie übergeben die Farben für jede der Linien. Daher muss der Hauptcode an der folgenden Stelle geändert werden, die im Fragment unten dargestellt ist:
17. //+------------------------------------------------------------------+ 18. int OnInit() 19. { 20. Terminal = new C_Terminal(); 21. if (!PositionSelect((*Terminal).GetInfoTerminal().szSymbol)) return INIT_FAILED; 22. Positions = new C_IndicatorPosition((*Terminal).GetInfoTerminal().ID, user00, user01, user02); 23. 24. return INIT_SUCCEEDED; 25. } 26. //+------------------------------------------------------------------+
Fragment aus dem Indikator
Alles ist einfach. Wir haben jetzt einen Code, der fast vollständig unabhängig ist. Dies liegt daran, dass wir immer noch davon abhängen, dass der Hauptcode Informationen darüber liest, ob eine Position existiert. Dies geschieht in Zeile 21 im vorherigen Fragment. Lassen Sie uns dies also beheben, da wir möchten, dass der Indikator auf HEDGING-Konten funktioniert. Auf solchen Konten können wir mehr als eine offene Position gleichzeitig und für dasselbe Symbol haben. Um dieses Problem jedoch zu lösen, müssen wir etwas umfangreichere Änderungen am Code vornehmen. Da wir die Dinge jedoch getrennt haben, wird diese Änderung viel einfacher und angenehmer. Der neue Code des Indikators ist daher unten zu sehen:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Indicator for tracking an open position on the server." 04. #property version "1.00" 05. #property indicator_chart_window 06. #property indicator_plots 0 07. //+------------------------------------------------------------------+ 08. #define def_ShortName "Position View" 09. //+------------------------------------------------------------------+ 10. #include <Market Replay\Order System\C_IndicatorPosition.mqh> 11. //+------------------------------------------------------------------+ 12. input color user00 = clrRoyalBlue; //Color Line Price 13. input color user01 = clrForestGreen; //Color Line Take Profit 14. input color user02 = clrFireBrick; //Color Line Stop Loss 15. //+------------------------------------------------------------------+ 16. C_IndicatorPosition *Positions; 17. //+------------------------------------------------------------------+*/ 18. int OnInit() 19. { 20. IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName); 21. Positions = new C_IndicatorPosition(user00, user01, user02); 22. if (!Positions.CheckCatch()) 23. { 24. ChartIndicatorDelete(ChartID(), 0, def_ShortName); 25. return INIT_FAILED; 26. } 27. 28. return INIT_SUCCEEDED; 29. } 30. //+------------------------------------------------------------------+ 31. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 32. { 33. return rates_total; 34. } 35. //+------------------------------------------------------------------+ 36. void OnDeinit(const int reason) 37. { 38. delete Positions; 39. } 40. //+------------------------------------------------------------------+
Quellcode der Positionsansicht
Beachten Sie, dass am Code der OnInit-Prozedur recht einfache Änderungen vorgenommen wurden. Im Wesentlichen arbeiten wir jetzt so, dass der Indikator aus dem Chart entfernt wird, wenn die Initialisierung fehlschlägt. Dies wird mit den Zeilen 20 und 24 erreicht. Zeile 24 ist genau diejenige, die den Indikator entfernt, wenn er nicht auf dem Chart bleiben kann. Was genau kann also verhindern, dass der Indikator auf dem Chart bleibt? Nun, in diesem Stadium ist nur noch eine Bedingung übrig. Um dies zu verstehen, schauen wir uns den Code an, der in Zeile 22 aufgerufen wird. Gehen wir also zum neuen Klassencode über:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #define def_SufixLinePrice "Price" 05. #define def_SufixLineTake "Take" 06. #define def_SufixLineStop "Stop" 07. //+------------------------------------------------------------------+ 08. #include "..\Auxiliar\C_Terminal.mqh" 09. //+------------------------------------------------------------------+ 10. class C_IndicatorPosition : private C_Terminal 11. { 12. private : 13. struct st00 14. { 15. ulong ticket; 16. string szPrefixName; 17. color corPrice, corTake, corStop; 18. }m_Infos; 19. //+------------------------------------------------------------------+ 20. void CreateLineInfos(const string szObjName, const double price, const color cor, const string szDescription = "\n") 21. { 22. if (price <= 0) return; 23. CreateObjectGraphics(szObjName, OBJ_HLINE, cor, (EnumPriority)(cor == m_Infos.corPrice ? ePriorityNull : (ePriorityOrders + (cor == m_Infos.corStop)))); 24. ObjectSetDouble(GetInfoTerminal().ID, szObjName, OBJPROP_PRICE, price); 25. ObjectSetString(GetInfoTerminal().ID, szObjName, OBJPROP_TEXT, szDescription); 26. ObjectSetString(GetInfoTerminal().ID, szObjName, OBJPROP_TOOLTIP, szDescription); 27. ObjectSetInteger(GetInfoTerminal().ID, szObjName, OBJPROP_SELECTABLE, cor != m_Infos.corPrice); 28. } 29. //+------------------------------------------------------------------+ 30. public : 31. //+------------------------------------------------------------------+ 32. C_IndicatorPosition(color corPrice, color corTake, color corStop) 33. :C_Terminal() 34. { 35. ZeroMemory(m_Infos); 36. m_Infos.corPrice = corPrice; 37. m_Infos.corTake = corTake; 38. m_Infos.corStop = corStop; 39. } 40. //+------------------------------------------------------------------+ 41. ~C_IndicatorPosition() 42. { 43. if (m_Infos.ticket != 0) 44. ObjectsDeleteAll(GetInfoTerminal().ID, m_Infos.szPrefixName); 45. } 46. //+------------------------------------------------------------------+ 47. bool CheckCatch(void) 48. { 49. for (int count = PositionsTotal() - 1; count >= 0; count--, m_Infos.ticket = 0) 50. if ((m_Infos.ticket = PositionGetTicket(count)) > 0) 51. if (PositionGetString(POSITION_SYMBOL) == GetInfoTerminal().szSymbol) 52. { 53. m_Infos.szPrefixName = IntegerToString(m_Infos.ticket); 54. if (ObjectFind(GetInfoTerminal().ID, m_Infos.szPrefixName + def_SufixLinePrice) < 0) 55. break; 56. } 57. if (m_Infos.ticket == 0) return false; 58. IndicatorSetString(INDICATOR_SHORTNAME, IntegerToString(m_Infos.ticket)); 59. CreateLineInfos(m_Infos.szPrefixName + def_SufixLinePrice, PositionGetDouble(POSITION_PRICE_OPEN), m_Infos.corPrice, "Position opening price."); 60. CreateLineInfos(m_Infos.szPrefixName + def_SufixLineTake, PositionGetDouble(POSITION_TP), m_Infos.corTake, "Take Profit point."); 61. CreateLineInfos(m_Infos.szPrefixName + def_SufixLineStop, PositionGetDouble(POSITION_SL), m_Infos.corStop, "Stop Loss point."); 62. 63. return true; 64. } 65. //+------------------------------------------------------------------+ 66. }; 67. //+------------------------------------------------------------------+ 68. #undef def_SufixLinePrice 69. #undef def_SufixLineTake 70. #undef def_SufixLineStop 71. //+------------------------------------------------------------------+
C_IndicatorPosition.mqh
Bitte beachten Sie, dass der Code wächst und immer komplexer wird. Dennoch gehe ich Schritt für Schritt vor, damit Sie wirklich nachvollziehen können, was wir tun. Dies liegt daran, dass ein tiefes Verständnis dieses Codes in Zukunft sehr wichtig sein wird. Nur keine Eile. Verfolgen Sie ruhig und aufmerksam die Änderungen, die stattfinden, da ich sie nach und nach zeigen und erklären werde, damit das Verständnis so vollständig wie möglich ist.
Beachten Sie, dass dieser Code beim letzten Mal, als wir ihn uns angesehen haben, keine Include-Direktiven enthielt. Jetzt ist das der Fall. Und genau das ermöglicht es dem Hauptcode, weniger Code schreiben zu müssen, und hilft natürlich auch bei anderen Aspekten des Codierens. In Zeile 10 binden wir die Klasse C_Terminal durch Vererbung in die Klasse C_IndicatorPosition ein. Diese Vererbung ermöglicht es uns zumindest vorerst, die öffentlichen Methoden der Klasse C_Terminal direkt in der Klasse C_IndicatorPosition zu verwenden. Es erweckt den Eindruck, dass die Klasse C_IndicatorPosition über mehr Funktionen verfügt, als in MQL5 existieren, aber das ist nur eine Illusion, da die verwendeten Funktionen tatsächlich in der Klasse C_Terminal enthalten sind.
Beachten Sie jedoch, dass Sie dieselben Funktionen der Klasse C_Terminal außerhalb der Klasse C_IndicatorPosition nicht verwenden können. Dies liegt daran, dass die Vererbung privat ist, was den externen Zugriff auf die Methoden der Klasse C_Terminal über die Klasse C_IndicatorPosition verhindert.
Da wir jedoch die Klasse C_Terminal erben, müssen wir sie initialisieren, bevor wir die Klasse C_IndicatorPosition verwenden. Dies geschieht in Zeile 33. Beachten Sie nun, dass wir im Konstruktor den Code entfernt haben, der sich zuvor dort befand, und nur den Code belassen haben, der die internen Variablen der Klasse initialisiert. Gut. Gehen wir nun zu Zeile 47 über, wo wir die Funktion haben, die während der Initialisierung prüft, ob der Indikator auf dem Chart bleiben soll.
Ab diesem Punkt beginnen wir in der Schleife in Zeile 49, Positionen auf HEDGING-Konten zu berücksichtigen. Bis zu diesem Punkt hatten wir nur NETTING-Konten berücksichtigt. Beachten Sie, dass wir die Liste der offenen Positionen durchlaufen und nach einer Position suchen, die noch keinem Indikator zugewiesen wurde. Wie können wir das tun? Nun, bei jeder Iteration der Schleife führen wir die Prüfung in Zeile 50 durch. Wenn diese Prüfung positiv ist, führen wir eine neue in Zeile 51 durch. Passen Sie jetzt auf: Wenn diese zweite Prüfung in Zeile 51 positiv ist, generieren wir in Zeile 53 ein Präfix für die Namen der zu erstellenden Objekte. Bis zu diesem Punkt bleibt alles gleich. Natürlich mit der Ausnahme, dass wir jetzt mehr als eine offene Position auf demselben Symbol berücksichtigen/handhaben können, was genau das ist, was auf HEDGING-Konten passiert.
Sehr gut. Und jetzt beginnt der interessanteste Teil. Woher weiß der Indikator, ob die Position bereits analysiert wurde oder nicht? Achten Sie auf Folgendes: Jeder im Chart vorhandene Positionsindikator verfolgt eine bestimmte Position oder bezieht sich genauer gesagt auf diese. Es können mehrere Positionen offen sein. Jeder Indikator bezieht sich jedoch nur auf eine Position. Derselbe Indikator wird NICHT mehr als eine Position verfolgen. Damit der Indikator also weiß, ob eine Position bereits von einem anderen Positionsindikator analysiert wird oder nicht, iterieren wir durch die Chartobjekte. Dies geschieht in Zeile 54.
Wenn MetaTrader 5 meldet, dass das Objekt bereits im Chart vorhanden ist, suchen wir nach einer neuen offenen Position auf demselben Symbol. Die Schleife in Zeile 49 wird erneut ausgeführt. Solche Situationen wiederholen sich, bis eine von zwei Bedingungen erfüllt ist. Die erste ist, dass wir keine offenen Positionen mehr haben. Die zweite ist die Ausführung von Zeile 55.
Auf jeden Fall wird Zeile 57 irgendwann ausgeführt. Wenn die Variable ticket keinen Wert enthält, geben wir false zurück und teilen dem Hauptcode mit, dass der Indikator aus dem Chart entfernt werden muss. Wenn die Ticket-Variable einen Wert hat, weisen wir dem Indikator einen neuen Kurznamen zu, damit wir später darauf verweisen können, und wir erstellen die Linien wie zuvor gezeigt. Schließlich geben wir in Zeile 63 true zurück. Somit stellen wir sicher, dass der Indikator sowohl auf HEDGING- als auch auf NETTING-Konten auf die gleiche Weise funktioniert, ohne dass zusätzliche Prüfungen erforderlich sind.
Abschließende Überlegungen
In diesem Artikel haben wir die notwendigen Änderungen eingeführt, um den Indikator für offene Positionen sowohl auf HEDGING- als auch auf NETTING-Konten wirklich funktionsfähig zu machen. Tatsächlich, und das ist leicht zu erkennen, tut dieser Indikator immer noch nichts, außer die Linien zu den Preisen anzuzeigen, die der jeweiligen Position entsprechen. Darüber hinaus kann dieser Indikator nicht feststellen, dass die Position nicht mehr existiert. Damit Sie als Trader dies wirklich bemerken, müssen Sie den Chart-Zeitrahmen ändern.
Somit wird der Indikator erkennen, dass die Position geschlossen wurde. Sobald dies erkannt wurde, wird der Indikator aus dem Chart entfernt und dadurch verschwindet er automatisch vom Chart, ohne zusätzliches Eingreifen. Im nächsten Artikel werden wir diesen Indikator weiter verbessern, indem wir ihm mehrere neue Funktionen hinzufügen.
| Datei | Beschreibung |
|---|---|
| Experts\Expert Advisor.mq5 | Zeigt die Interaktion zwischen Chart Trade und dem Expert Advisor (für die Interaktion ist „Mouse Study“ erforderlich). |
| Indicators\Chart Trade.mq5 | Erstellt ein Fenster zur Konfiguration des zu versendenden Auftrags (für die Interaktion ist „Mouse Study“ erforderlich). |
| Indicators\Market Replay.mq5 | Erstellt Steuerelemente für die Interaktion mit dem Replikations-/Simulationsdienst (für die Interaktion ist „Mouse Study“ erforderlich). |
| Indicators\Mouse Study.mq5 | Ermöglicht die Interaktion zwischen grafischen Steuerelementen und dem Benutzer (sowohl für das Replikations-/Simulationssystem als auch für den realen Markt erforderlich). |
| Indicators\Order Indicator.mq5 | Verantwortlich für die Anzeige von Marktorders, die Bereitstellung der Interaktion mit ihnen und die Kontrolle über sie. |
| Indicators\Position View.mq5 | Verantwortlich für die Anzeige von Marktpositionen, die Bereitstellung der Interaktion mit ihnen und die Kontrolle über sie. |
| Services\Market Replay.mq5 | Erstellt und verwaltet den Markt-Replikations-/Simulationsdienst (die Hauptdatei des gesamten Systems). |
Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/13167
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.
Algorithmus für künstliche Atome (A3)
Risk Manager für Handelsroboter (Teil I): Include-Datei zur Risikokontrolle für Expert Advisors
Eine alternative Log-datei mit der Verwendung der HTML und CSS
Community of Scientists Optimization (CoSO): Praxis
- 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.