English Русский 中文 Español 日本語 Português
preview
Entwicklung eines Replay Systems (Teil 54): Die Geburt des ersten Moduls

Entwicklung eines Replay Systems (Teil 54): Die Geburt des ersten Moduls

MetaTrader 5Beispiele | 16 Dezember 2024, 11:43
154 0
Daniel Jose
Daniel Jose

Einführung

Im vorherigen Artikel „Entwicklung eines Replay Systems (Teil 53): Die Dinge werden kompliziert (V)“ habe ich einige Konzepte erklärt, die von nun an Teil unserer Programmierung sein werden und die wir in MQL5 und der MetaTrader 5 Plattform verwenden werden. Mir ist klar, dass viele dieser Konzepte für die meisten Leser neu sind, und ich weiß auch, dass jeder, der Erfahrung in der Systemprogrammierung hat (z. B. diejenigen, die Windows-Systeme programmieren), mit diesen Konzepten vertraut sein wird.

Wenn Sie also wirklich eintauchen und verstehen wollen, warum und wie das, was ich Ihnen jetzt zeige, funktioniert, schlage ich vor, dass Sie ein wenig Windows-Programmierung lernen, um zu wissen, wie Nachrichten zwischen Programmen ausgetauscht werden. Diese Informationen in diesem Artikel würden uns weit weg von dem führen, was ich wirklich zeigen möchte: wie man in MQL5 und MetaTrader 5 auf einem fortgeschrittenen Niveau entwickelt und arbeitet.

Sie werden keine Probleme haben, Programme zu finden, die diese Nachrichtenübermittlung zur Kommunikation in der Windows-Umgebung verwenden, aber um sie richtig zu verstehen, sind einige Vorkenntnisse und eine solide Grundlage in der C-Programmierung erforderlich. Wenn Sie diese Kenntnisse nicht haben, rate ich Ihnen, zunächst die C-Programmierung zu erlernen und dann zu lernen, wie Nachrichten zwischen Programmen unter Windows ausgetauscht werden. Auf diese Weise wird es möglich sein, eine breite und solide Grundlage für das Verständnis unserer weiteren Arbeit zu schaffen.


Dinge ermöglichen

Wenn Sie den vorigen Artikel aufmerksam gelesen haben, ist Ihnen wahrscheinlich aufgefallen, dass ich über einen langen Zeitraum versucht habe, etwas zu tun. Doch auch wenn alle diese Elemente teilweise funktionierten, konnten sie in einem größeren System nicht nebeneinander bestehen, zumindest nicht so, wie sich die Dinge entwickelten.

Mein vielleicht größter Fehler war, den ich über mehrere Wochen ignoriert habe, dass unsere Anwendungen auf Ereignisse in der MetaTrader 5-Plattform reagieren, aber der Fehler war ein anderer: Ich betrachtete MetaTrader 5 nicht als Plattform, sondern als ein einfaches Programm, in dem andere Prozesse ablaufen würden.

Dieser Mangel in der Art und Weise, wie ich den MetaTrader 5 sehe, ist darauf zurückzuführen, dass andere Plattformen uns nicht die gleiche Flexibilität bieten wie der MetaTrader 5. Aus diesem Grund habe ich bei der Entwicklung fortgeschrittener Anwendungen etwas Zeit und Geschwindigkeit verloren. Da sich jedoch herausgestellt hat, dass dieses Replay-/Simulatorsystem besser in modularer Weise entwickelt werden sollte (anders als viele es normalerweise tun), bin ich auf einige Probleme gestoßen. Aber es waren nicht wirklich die Probleme, sondern etwas, das ich ignoriert habe.

Sie können in den Videos im vorherigen Artikel sehen, dass MetaTrader 5 viel mehr bietet, als viele von Ihnen erforscht haben. Aber heute werden wir das, was einst nur ein Traum war, in etwas Erreichbares verwandeln. Wir werden anfangen, weniger zu programmieren und mehr zu bauen. In diesem Artikel werden wir uns mit dem Austausch von Nachrichten befassen, um den MetaTrader 5 noch besser für uns arbeiten zu lassen, wobei wir uns darauf konzentrieren, dass die Anwendung harmonisch mit anderen Dingen auf dem Chart zusammenarbeitet.

Als erstes werden wir den Mausindikator anpassen, um diese neue Phase in der Entwicklung von MetaTrader 5-Anwendungen zu beginnen.

Da der Kodex erhebliche Änderungen erfahren wird, müssen viele Teile davon geändert werden. Wenn Sie jedoch alle Schritte befolgt haben, werden Sie keine Schwierigkeiten haben, diese Änderungen vorzunehmen.

Deshalb werden wir ab sofort eine gemeinsame Datei für alle künftig erscheinenden Anträge erstellen. So können wir Nachrichten adressieren, die von nun an von jedem Code verarbeitet werden können, den wir erstellen. Wir haben die Kontrolle darüber, was passiert, wenn sich zwei Anwendungen, die einen Message-Handler haben, im Chart befinden. Auf diese Weise ist jede Anwendung in der Lage, die Nachricht korrekt zu verarbeiten.

Der ursprüngliche Inhalt dieser Datei wird im Folgenden dargestellt. Sie sollte unter dem Namen Defines.mqh gespeichert werden. Sein Standort wird demnächst bekannt gegeben. Wenn Sie also absolut keine Ahnung vom Programmieren haben, tut es mir leid, aber von nun an werden Sie nicht in der Lage sein, dem zu folgen, was ich implementieren werde. Von diesem Moment an befindet sich eine Barriere vor Ihnen, die Sie daran hindert, weiterzugehen. Wenn Sie das, was wir heute behandeln, wirklich nutzen wollen, müssen Sie einige grundlegende Programmierkenntnisse haben.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_VERSION_DEBUG
05. //+------------------------------------------------------------------+
06. #ifdef def_VERSION_DEBUG
07.     #define macro_DEBUG_MODE(A) \
08.                             Print(__FILE__, " ", __LINE__, " ", __FUNCTION__ + " " + #A + " = " + (string)(A));
09. #else
10.     #define macro_DEBUG_MODE(A)
11. #endif
12. //+------------------------------------------------------------------+
13. #define def_SymbolReplay            "RePlay"
14. #define def_MaxPosSlider            400
15. //+------------------------------------------------------------------+
16. union uCast_Double
17. {
18.     double   dValue;
19.     long     _long;                                  // 1 Information
20.     datetime _datetime;                              // 1 Information
21.     int      _int[sizeof(double) / sizeof(int)];     // 2 Informations
22.     char     _char[sizeof(double) / sizeof(char)];   // 8 Informations
23. };
24. //+------------------------------------------------------------------+
25. enum EnumEvents    {
26.                     evHideMouse,        //Hide mouse price line
27.                     evShowMouse,        //Show mouse price line
28.                     evHideBarTime,      //Hide bar time
29.                     evShowBarTime,      //Show bar time
30.                     evHideDailyVar,     //Hide daily variation
31.                     evShowDailyVar,     //Show daily variation
32.                     evHidePriceVar,     //Hide instantaneous variation
33.                     evShowPriceVar,     //Show instantaneous variation
34.                     evSetServerTime,    //Replay/simulation system timer
35.                     evCtrlReplayInit    //Initialize replay control
36.                    };
37. //+------------------------------------------------------------------+

Quellcode der Datei Defines.mqh

In Zeile 4 dieser Datei können Sie sehen, dass wir etwas definiert haben. Wenn Sie also Ihren Code zur Laufzeit debuggen wollen, fügen Sie das Makro _DEBUG_MODE hinzu und übergeben die Variable, die Sie debuggen wollen, als Parameter. Dann können Sie das System schnell hinzufügen und entfernen, um zur Laufzeit zu analysieren, was passiert. Prüfen Sie einfach, ob der Compiler Zeile 4 verwendet.

In Zeile 13 definieren wir den Namen, der in unserem nutzerdefinierten Symbol verwendet wird und der vom Replay-/Simulationsdienst verwendet wird, wie wir es seit Beginn dieser Artikelserie getan haben. In Zeile 14 deklarieren wir etwas, das nur vom Kontrollindikator verwendet werden soll.

Diese beiden Zeilen sowie das, was zwischen den Zeilen 16 und 23 steht, waren bereits Teil des zuvor geschriebenen Codes. Da die Header-Datei InterProcess.mqh jedoch nicht mehr existiert, war es notwendig, diese Informationen in die Definitionsdatei zu verschieben.

Was uns in dieser Datei wirklich interessiert, beginnt in Zeile 25. Wir geben hier eine Liste bekannt, die mit der Einführung und Hinzufügung neuer Veranstaltungen wachsen wird. Es besteht eine kleine Gefahr, die aber nicht so ernst ist, wenn Sie die entsprechenden Vorsichtsmaßnahmen treffen: Fügen Sie immer am Ende einer Enumeration etwas hinzu. Wenn Sie dies tun, müssen Sie alte Codes nicht neu kompilieren, aber wenn Sie etwas in der Mitte der Liste hinzufügen, dann müssen Sie alle alten Codes neu kompilieren. So lassen sich Probleme vermeiden.

Beachten Sie, dass wir in jeder Zeile einen Wert definieren und einen kurzen Kommentar zu dem entsprechenden Ereignis abgeben.

Sie werden sehen, dass die angezeigten Codes angeben, wo und wie jedes dieser Ereignisse eintreten wird. Aber das Wichtigste wird etwas sein, das nur im Code sichtbar sein wird. Wenn Sie also etwas von dem, was ich hier zeige, verwenden wollen, sollten Sie sich die Message-Handler ansehen.

Und damit beginnen wir, das ganze System vollständig modular zu gestalten. Achten Sie von nun an genau auf den Code und auf das, was auf dem Chart zu sehen sein wird: Es ist an der Zeit, den MetaTrader 5 wie ein echter Profi zu nutzen.

Wie Sie bereits wissen, war es notwendig, den Code der Mausindikator-Klassen erneut zu ändern, aber diese Änderungen sind notwendig, um die korrekte Verwendung und Implementierung dessen, was wir tun werden, zu erleichtern. Bevor wir den Code des Mausindikators ändern, müssen wir eine kleine Änderung am Code der Klasse C_Terminal vornehmen. Daher müssen wir in der Header-Datei C_Terminal.mqh wie im folgenden Fragment gezeigt vorgehen.
01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Macros.mqh"
05. #include "..\Defines.mqh"
06. #include "Interprocess.mqh"
07. //+------------------------------------------------------------------+
08. class C_Terminal
09. {
10. //+------------------------------------------------------------------+
11.     protected:
12.             enum eErrUser {ERR_Unknown, ERR_FileAcess, ERR_PointerInvalid, ERR_NoMoreInstance};
13. //+------------------------------------------------------------------+
14.             struct st_Terminal

Code aus der Datei C_Terminal.mqh

Schauen Sie sich Zeile 5 genau an, in der der Speicherort der oben erwähnten Header-Datei Defines.mqh relativ zur Header-Datei C_Terminal.mqh angegeben ist. Aber das ist nicht alles, was ich Ihnen ans Herz legen möchte. Beachten Sie, dass Zeile 6 aus dem Code entfernt wurde. Das bedeutet, dass Sie die Header-Datei InterProcess.mqh jetzt aus dem Projekt entfernen können, da sie nicht mehr verwendet wird.

Da diese Änderung recht einfach ist und keine weiteren Änderungen am Code der Datei C_Terminal.mqh vorgenommen wurden, sehe ich keine Notwendigkeit, die gesamte Datei zu duplizieren. Es gibt zwar keine größeren Änderungen, aber eine muss erwähnt werden, da es sonst zu Problemen bei der Kompilierung der angezeigten Codes kommen wird.

Zeile 12 enthält eine Enumeration, der ein neuer Wert zugewiesen wurde. Es sollte während des Tests verwendet werden, um zu prüfen, ob derselbe Indikator bereits auf dem Chart vorhanden ist. Daher ist es notwendig, eine weitere kleine Änderung an der gleichen Header-Datei C_Terminal.mqh vorzunehmen. Diese Änderung ist im folgenden Code dargestellt.

157. //+------------------------------------------------------------------+
158.            bool IndicatorCheckPass(const string szShortName)
159.                    {
160.                            string szTmp = szShortName + "_TMP";
161.                            
162.                            if (_LastError != ERR_SUCCESS) return false;
163.                            IndicatorSetString(INDICATOR_SHORTNAME, szTmp);
164.                            if (ChartWindowFind(m_Infos.ID, szShortName) != -1)
165.                            {
166.                                    ChartIndicatorDelete(m_Infos.ID, 0, szTmp);
167.                                    Print("Only one instance is allowed...");
168.                                    SetUserError(C_Terminal::ERR_NoMoreInstance);
169.                                    
170.                                    return false;
171.                            }
172.                            IndicatorSetString(INDICATOR_SHORTNAME, szShortName);
173.                            ResetLastError();
174.    
175.                            return true;
176.                    }
177. //+------------------------------------------------------------------+

Der Pfad, der in der Datei C_Terminal.mqh geändert werden muss

Wir müssen die ursprüngliche Funktion in der Datei C_Terminal.mqh durch den in Fragment 2 dargestellten Code ersetzen. Daher wird das System während der Prüfung die Konstante _LastError korrekt setzen, was anzeigt, dass ein Fehler aufgetreten ist. Dieser Fehler wurde durch das Vorhandensein einer anderen Instanz desselben Indikators im Chart verursacht. Abgesehen von diesen beiden einfachen Änderungen wurden keine weiteren Modifikationen vorgenommen, sodass wir mit der Entwicklung der Mauszeigerklassen beginnen können.

Nachstehend finden Sie den vollständigen Code für die Header-Datei C_Mouse.mqh. Da es für einige schwierig sein kann, den Code richtig zu verstehen, werde ich kurz erklären, was vor sich geht. Dann können Sie besser erkennen, wie alles zu einem Baukasten wird.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #include "C_Terminal.mqh"
005. //+------------------------------------------------------------------+
006. #define def_MousePrefixName "MouseBase_"
007. #define def_NameObjectLineH def_MousePrefixName + "H"
008. #define def_NameObjectLineV def_MousePrefixName + "TV"
009. #define def_NameObjectLineT def_MousePrefixName + "TT"
010. #define def_NameObjectStudy def_MousePrefixName + "TB"
011. //+------------------------------------------------------------------+
012. class C_Mouse : public C_Terminal
013. {
014.    public  :
015.            enum eStatusMarket {eCloseMarket, eAuction, eInTrading, eInReplay};
016.            enum eBtnMouse {eKeyNull = 0x00, eClickLeft = 0x01, eClickRight = 0x02, eSHIFT_Press = 0x04, eCTRL_Press = 0x08, eClickMiddle = 0x10};
017.            struct st_Mouse
018.            {
019.                    struct st00
020.                    {
021.                            int      X_Adjusted,
022.                                     Y_Adjusted,
023.                                     X_Graphics,
024.                                     Y_Graphics;
025.                            double   Price;
026.                            datetime dt;
027.                    }Position;
028.                    uint     ButtonStatus;
029.                    bool     ExecStudy;
030.                    datetime TimeDevice;
031.            };
032. //+------------------------------------------------------------------+
033.    protected:
034. //+------------------------------------------------------------------+
035.            void CreateObjToStudy(int x, int w, string szName, color backColor = clrNONE) const
036.                    {
037.                            if (m_Mem.szShortName != NULL) return;
038.                            CreateObjectGraphics(szName, OBJ_BUTTON, clrNONE);
039.                            ObjectSetInteger(GetInfoTerminal().ID, szName, OBJPROP_STATE, true);
040.                            ObjectSetInteger(GetInfoTerminal().ID, szName, OBJPROP_BORDER_COLOR, clrBlack);
041.                            ObjectSetInteger(GetInfoTerminal().ID, szName, OBJPROP_COLOR, clrBlack);
042.                            ObjectSetInteger(GetInfoTerminal().ID, szName, OBJPROP_BGCOLOR, backColor);
043.                            ObjectSetString(GetInfoTerminal().ID, szName, OBJPROP_FONT, "Lucida Console");
044.                            ObjectSetInteger(GetInfoTerminal().ID, szName, OBJPROP_FONTSIZE, 10);
045.                            ObjectSetInteger(GetInfoTerminal().ID, szName, OBJPROP_CORNER, CORNER_LEFT_UPPER); 
046.                            ObjectSetInteger(GetInfoTerminal().ID, szName, OBJPROP_XDISTANCE, x);
047.                            ObjectSetInteger(GetInfoTerminal().ID, szName, OBJPROP_YDISTANCE, TerminalInfoInteger(TERMINAL_SCREEN_HEIGHT) + 1);
048.                            ObjectSetInteger(GetInfoTerminal().ID, szName, OBJPROP_XSIZE, w); 
049.                            ObjectSetInteger(GetInfoTerminal().ID, szName, OBJPROP_YSIZE, 18);
050.                    }
051. //+------------------------------------------------------------------+
052.    private :
053.            enum eStudy {eStudyNull, eStudyCreate, eStudyExecute};
054.            struct st01
055.            {
056.                    st_Mouse Data;
057.                    color    corLineH,
058.                             corTrendP,
059.                             corTrendN;
060.                    eStudy   Study;
061.            }m_Info;
062.            struct st_Mem
063.            {
064.                    bool     CrossHair,
065.                             IsFull;
066.                    datetime dt;
067.                    string   szShortName;
068.            }m_Mem;
069.            bool m_OK;
070. //+------------------------------------------------------------------+
071.            void GetDimensionText(const string szArg, int &w, int &h)
072.                    {
073.                            TextSetFont("Lucida Console", -100, FW_NORMAL);
074.                            TextGetSize(szArg, w, h);
075.                            h += 5;
076.                            w += 5;
077.                    }
078. //+------------------------------------------------------------------+
079.            void CreateStudy(void)
080.                    {
081.                            if (m_Mem.IsFull)
082.                            {
083.                                    CreateObjectGraphics(def_NameObjectLineV, OBJ_VLINE, m_Info.corLineH);
084.                                    CreateObjectGraphics(def_NameObjectLineT, OBJ_TREND, m_Info.corLineH);
085.                                    ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineT, OBJPROP_WIDTH, 2);
086.                                    CreateObjToStudy(0, 0, def_NameObjectStudy);
087.                            }
088.                            m_Info.Study = eStudyCreate;
089.                    }
090. //+------------------------------------------------------------------+
091.            void ExecuteStudy(const double memPrice)
092.                    {
093.                            double v1 = GetInfoMouse().Position.Price - memPrice;
094.                            int w, h;
095.                            
096.                            if (!CheckClick(eClickLeft))
097.                            {
098.                                    m_Info.Study = eStudyNull;
099.                                    ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, true);
100.                                    if (m_Mem.IsFull) ObjectsDeleteAll(GetInfoTerminal().ID, def_MousePrefixName + "T");
101.                            }else if (m_Mem.IsFull)
102.                            {
103.                                    string sz1 = StringFormat(" %." + (string)GetInfoTerminal().nDigits + "f [ %d ] %02.02f%% ",
104.                                            MathAbs(v1), Bars(GetInfoTerminal().szSymbol, PERIOD_CURRENT, m_Mem.dt, GetInfoMouse().Position.dt) - 1, MathAbs((v1 / memPrice) * 100.0)));
105.                                    GetDimensionText(sz1, w, h);
106.                                    ObjectSetString(GetInfoTerminal().ID, def_NameObjectStudy, OBJPROP_TEXT, sz1);                                                                                                                          
107.                                    ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectStudy, OBJPROP_BGCOLOR, (v1 < 0 ? m_Info.corTrendN : m_Info.corTrendP));
108.                                    ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectStudy, OBJPROP_XSIZE, w);
109.                                    ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectStudy, OBJPROP_YSIZE, h);
110.                                    ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectStudy, OBJPROP_XDISTANCE, GetInfoMouse().Position.X_Adjusted - w);
111.                                    ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectStudy, OBJPROP_YDISTANCE, GetInfoMouse().Position.Y_Adjusted - (v1 < 0 ? 1 : h));                          
112.                                    ObjectMove(GetInfoTerminal().ID, def_NameObjectLineT, 1, GetInfoMouse().Position.dt, GetInfoMouse().Position.Price);
113.                                    ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineT, OBJPROP_COLOR, (memPrice > GetInfoMouse().Position.Price ? m_Info.corTrendN : m_Info.corTrendP));
114.                            }
115.                            m_Info.Data.ButtonStatus = eKeyNull;
116.                    }
117. //+------------------------------------------------------------------+
118.    public  :
119. //+------------------------------------------------------------------+
120.            C_Mouse(const long id, const string szShortName)
121.                    :C_Terminal(id),
122.                    m_OK(false)
123.                    {
124.                            m_Mem.szShortName = szShortName;
125.                    }
126. //+------------------------------------------------------------------+
127.            C_Mouse(const long id, const string szShortName, color corH, color corP, color corN)
128.                    :C_Terminal(id)
129.                    {
130.                            if (!(m_OK = IndicatorCheckPass(szShortName))) SetUserError(C_Terminal::ERR_Unknown);
131.                            if (_LastError != ERR_SUCCESS) return;
132.                            m_Mem.szShortName = NULL;
133.                            m_Mem.CrossHair = (bool)ChartGetInteger(GetInfoTerminal().ID, CHART_CROSSHAIR_TOOL);
134.                            ChartSetInteger(GetInfoTerminal().ID, CHART_EVENT_MOUSE_MOVE, true);
135.                            ChartSetInteger(GetInfoTerminal().ID, CHART_CROSSHAIR_TOOL, false);
136.                            ZeroMemory(m_Info);
137.                            m_Info.corLineH  = corH;
138.                            m_Info.corTrendP = corP;
139.                            m_Info.corTrendN = corN;
140.                            m_Info.Study = eStudyNull;
141.                            if (m_Mem.IsFull = (corP != clrNONE) && (corH != clrNONE) && (corN != clrNONE))
142.                                    CreateObjectGraphics(def_NameObjectLineH, OBJ_HLINE, m_Info.corLineH);
143.                    }
144. //+------------------------------------------------------------------+
145.            ~C_Mouse()
146.                    {
147.                            if (!m_OK) return;
148.                            ChartSetInteger(GetInfoTerminal().ID, CHART_EVENT_OBJECT_DELETE, false);
149.                            ChartSetInteger(GetInfoTerminal().ID, CHART_EVENT_MOUSE_MOVE, false);
150.                            ChartSetInteger(GetInfoTerminal().ID, CHART_CROSSHAIR_TOOL, m_Mem.CrossHair);
151.                            ObjectsDeleteAll(GetInfoTerminal().ID, def_MousePrefixName);
152.                    }
153. //+------------------------------------------------------------------+
154. inline bool CheckClick(const eBtnMouse value) 
155.                    {
156.                            return (GetInfoMouse().ButtonStatus & value) == value;
157.                    }
158. //+------------------------------------------------------------------+
159. inline const st_Mouse GetInfoMouse(void)
160.                    {
161.                            if (m_Mem.szShortName != NULL)
162.                            {
163.                                    double Buff[];
164.                                    uCast_Double loc;
165.                                    int handle = ChartIndicatorGet(GetInfoTerminal().ID, 0, m_Mem.szShortName);
166.                                    
167.                                    ZeroMemory(m_Info.Data);
168.                                    if (CopyBuffer(handle, 0, 0, 6, Buff) == 6)
169.                                    {
170.                                            m_Info.Data.Position.Price = Buff[0];
171.                                            loc.dValue = Buff[1];
172.                                            m_Info.Data.Position.dt = loc._datetime;
173.                                            loc.dValue = Buff[2];
174.                                            m_Info.Data.Position.X_Adjusted = loc._int[0];
175.                                            m_Info.Data.Position.Y_Adjusted = loc._int[1];
176.                                            loc.dValue = Buff[3];
177.                                            m_Info.Data.Position.X_Graphics = loc._int[0];
178.                                            m_Info.Data.Position.Y_Graphics = loc._int[1];
179.                                            loc.dValue = Buff[4];
180.                                            m_Info.Data.ButtonStatus = loc._char[0];
181.                                            m_Info.Data.TimeDevice = (datetime)Buff[5];
182.                                            IndicatorRelease(handle);
183.                                    }
184.                            }
185. 
186.                            return m_Info.Data;
187.                    }
188. //+------------------------------------------------------------------+
189.            void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
190.                    {
191.                            int w = 0;
192.                            static double memPrice = 0;
193.                            
194.                            if (m_Mem.szShortName == NULL)
195.                            {
196.                                    C_Terminal::DispatchMessage(id, lparam, dparam, sparam);
197.                                    switch (id)
198.                                    {
199.                                            case (CHARTEVENT_CUSTOM + evHideMouse):
200.                                                    if (m_Mem.IsFull) ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, clrNONE);
201.                                                    break;
202.                                            case (CHARTEVENT_CUSTOM + evShowMouse):
203.                                                    if (m_Mem.IsFull) ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, m_Info.corLineH);
204.                                                    break;
205.                                            case (CHARTEVENT_CUSTOM + evSetServerTime):
206.                                               m_Info.Data.TimeDevice = (datetime)dparam;
207.                                               break;
208.                                            case CHARTEVENT_MOUSE_MOVE:
209.                                                    ChartXYToTimePrice(GetInfoTerminal().ID, m_Info.Data.Position.X_Graphics = (int)lparam, m_Info.Data.Position.Y_Graphics = (int)dparam, w, m_Info.Data.Position.dt, m_Info.Data.Position.Price);
210.                                                    if (m_Mem.IsFull) ObjectMove(GetInfoTerminal().ID, def_NameObjectLineH, 0, 0, m_Info.Data.Position.Price = AdjustPrice(m_Info.Data.Position.Price));
211.                                                    m_Info.Data.Position.dt = AdjustTime(m_Info.Data.Position.dt);
212.                                                    ChartTimePriceToXY(GetInfoTerminal().ID, w, m_Info.Data.Position.dt, m_Info.Data.Position.Price, m_Info.Data.Position.X_Adjusted, m_Info.Data.Position.Y_Adjusted);
213.                                                    if ((m_Info.Study != eStudyNull) && (m_Mem.IsFull)) ObjectMove(GetInfoTerminal().ID, def_NameObjectLineV, 0, m_Info.Data.Position.dt, 0);
214.                                                    m_Info.Data.ButtonStatus = (uint) sparam;
215.                                                    if (CheckClick(eClickMiddle))
216.                                                            if ((!m_Mem.IsFull) || ((color)ObjectGetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR) != clrNONE)) CreateStudy();
217.                                                    if (CheckClick(eClickLeft) && (m_Info.Study == eStudyCreate))
218.                                                    {
219.                                                            ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false);
220.                                                            if (m_Mem.IsFull) ObjectMove(GetInfoTerminal().ID, def_NameObjectLineT, 0, m_Mem.dt = GetInfoMouse().Position.dt, memPrice = GetInfoMouse().Position.Price);
221.                                                            m_Info.Study = eStudyExecute;
222.                                                    }
223.                                                    if (m_Info.Study == eStudyExecute) ExecuteStudy(memPrice);
224.                                                    m_Info.Data.ExecStudy = m_Info.Study == eStudyExecute;
225.                                                    break;
226.                                            case CHARTEVENT_OBJECT_DELETE:
227.                                                    if ((m_Mem.IsFull) && (sparam == def_NameObjectLineH)) CreateObjectGraphics(def_NameObjectLineH, OBJ_HLINE, m_Info.corLineH);
228.                                                    break;
229.                                    }
230.                            }
231.                    }
232. //+------------------------------------------------------------------+
233. };
234. //+------------------------------------------------------------------+
235. #undef def_NameObjectLineV
236. #undef def_NameObjectLineH
237. #undef def_NameObjectLineT
238. #undef def_NameObjectStudy
239. //+------------------------------------------------------------------+

Quellcode der Datei C_Mouse.mqh

Im Gegensatz zu früheren Versionen wird jetzt nur noch die Datei C_Terminal.mqh als notwendig erachtet. Sie sollten jedoch auf andere Details achten, die in dieser Klasse geändert wurden, wie oben gezeigt.

Wie Sie sehen, haben wir jetzt eine neue Variable in Zeile 30. Sie ist nur sinnvoll, wenn der Replay/Simulator-Dienst verwendet wird. Über diese Variable haben wir Zugriff auf den vom Replay/Simulator-Dienst bereitgestellten Wert, der zuvor über die globale Terminal-Variable abgerufen wurde. Obwohl diese Variable in Zeile 30 deklariert wird, wird sie an anderer Stelle verwendet. Aber wegen eines anderen Problems, das wir später erklären werden, mussten wir es hier hinzufügen, in der Klasse C_Mouse.

Wie Sie sehen können, bleibt der größte Teil des Codes identisch mit dem vorherigen, bis zu Zeile 168, wo wir etwas anderes finden. Jetzt werden wir sechs Pufferpositionen verwenden. Die sechste Position sollte von der in Zeile 30 deklarierten Variablen belegt werden. In Zeile 181 geben wir also den Wert ein, wenn wir ihn lesen und herausfinden müssen, wie hoch der Wert dieser Variablen ist. Hier muss ich kurz innehalten und etwas erklären. Die einzige Prozedur, die den Inhalt der in Zeile 30 deklarierten Variablen tatsächlich verwendet, ist der Replay/Simulator-Dienst und der Mausanzeiger. Letzterer verwendet diesen Wert, um den Nutzer über die verbleibende Zeit bis zur Eröffnung des nächsten Taktes zu informieren. Wenn wir sie jedoch nicht verwenden wollen, können wir sie aus dem Mausanzeiger oder dem Replay-/Simulationsdienst entfernen. Es wird keine Probleme geben, wenn Sie dies tun. Wenn Sie diese Informationen verwenden wollen, sollten Sie sich darüber im Klaren sein, dass der Dienst nicht weiß, wann diese Daten wieder aktualisiert werden sollen, es sei denn, wir verwenden eine globale Terminalvariable oder ein anderes Mittel, um den Zeitwert im Replay-/Simulationsdienst zu speichern.

Aus diesem Grund legen wir den Wert in den Mauszeigerpuffer. Aber dann denkt man: „Wird dieser Wert nicht gelöscht und zurückgesetzt, wenn MetaTrader 5 den Indikator im Chart wiederherstellt, nachdem der Nutzer den Chart-Zeitrahmen geändert hat?“ Dann macht es keinen Sinn, sie im Indikatorpuffer zu speichern. Das ist genau das, was wir wollen. Wenn der Dienst feststellt, dass der Wert im Puffer nicht mehr gültig ist, sendet er ein Ereignis an den Mauszeiger, um den Wert erneut zu aktualisieren. Auf diese Weise wird alles so bleiben, wie wir es erwarten.

Das heißt, die Tatsache, dass MetaTrader 5 den Indikator zwingt, den Puffer auf Null zu setzen, gibt dem Replay/Simulator-Dienst zu verstehen, dass der Nutzer eine Änderung vorgenommen hat, die vom Replay/Simulator-Dienst neu bewertet werden muss. Auf diese Weise wird unsere Anwendung leicht erkennen, dass etwas passiert ist, und MetaTrader 5 wird alles für uns tun.

Aber die Frage wird noch interessanter, wenn wir uns den Code ab Zeile 189 ansehen, wo sich der Message-Handler der Klasse C_Mouse befindet.

In diesem Verfahren zur Behandlung von Nachrichten haben wir die ersten drei Nachrichten, mit deren Verarbeitung unser modulares System beginnen wird. Achten Sie also darauf, was passiert. Um sicherzustellen, dass die Nachrichtenbehandlung durch den Indikator und nicht durch einen anderen Code erfolgt, der die Klasse verwendet, müssen wir zunächst prüfen, ob wir genau den Indikator aufrufen. Diese Prüfung wird in Zeile 194 durchgeführt. Wenn die Prüfung erfolgreich ist, gehen wir davon aus, dass es sich um einen Indikator handelt, sodass wir nur einen Mausindikator auf dem Chart haben müssen, um einen möglichen Interessenkonflikt zu vermeiden. Ich habe dies bereits in anderen Artikeln behandelt, also lassen Sie uns fortfahren.

In Zeile 199 behandeln wir das Ereignis, bei dem der Mausindikator die als Preislinie verwendete Linie ausblenden soll.

In Zeile 202 behandeln wir das Ereignis, das dem Mausindikator mitteilt, dass die Kurslinie wieder im Chart angezeigt werden soll. Auf diese Weise kann jede Anwendung dem Mauszeiger mitteilen, wann er die von ihm verwendete Kurslinie ein- oder ausblenden soll.

In beiden Ereignissen müssen keine zusätzlichen Parameter angegeben werden, sodass jede Anwendung, die die Mauslinie ein- oder ausblenden möchte, lediglich ein nutzerdefiniertes Ereignis mit den angegebenen Werten erzeugen und dieses Ereignis an das Chart leiten muss, in dem sich der Mauszeiger befindet. Ich werde später mehr dazu sagen. Fürs Erste können wir es so verstehen: Wenn zu einem bestimmten Zeitpunkt ein Mausindikator im Chart erscheint und Sie die Mauslinie ausblenden möchten, müssen Sie ein nutzerdefiniertes Ereignis mit dem gewünschten Wert erzeugen, um die Mauslinie ein- oder auszublenden. Dieses Ereignis kann z.B. durch einen Expert Advisor ausgelöst werden.

Das dritte Ereignis, das wir auch hier implementieren werden, ist in Zeile 205 dargestellt. In diesem Fall geben wir den Wert an, der als Laufzeit des Dienstes platziert werden soll, d.h. es ist der Replay/Simulator-Dienst, der dies tatsächlich tun wird. Denn nur der Dienst kann einen Vorteil aus der Erzeugung eines solchen Ereignisses ziehen. Aber es gibt einen wichtigen Punkt: Wenn dieses Ereignis ausgelöst wird, muss es einen Zeitwert angeben. Dieser Wert muss in dem Parameter „dparam“ vom Typ „double“ enthalten sein.

Auch hier müssen Sie die Dinge aus einer breiteren Perspektive betrachten. Ein Double-Wert besteht aus 8 Bytes, genau wie ein Datetime-Wert, der ebenfalls aus 8 Bytes besteht. Wir führen also eine Typumwandlung durch, damit der Compiler versteht, was wir tun. Aber für den Prozessor ist alles, was wir tun, 8 Bytes in eine Variable zu stecken. Der Inhalt dieser Bytes spielt keine Rolle.

Es ist wichtig, dies zu verstehen, denn es gibt Situationen, in denen wir ganze Zeichenketten von Werten, manchmal auch ganze Strukturen, übergeben müssen, und da wir in MetaTrader 5, oder genauer gesagt in MQL5, keine Zeiger wie in C/C++ verwenden können, brauchen wir einen Trick, um diese Daten zwischen unseren in MetaTrader 5 laufenden Anwendungen zu übergeben.

Okay, der erste Teil der Arbeit ist erledigt. Aber wir werden die Dinge noch verbessern. Wenn Sie gut aufgepasst haben, ist Ihnen wahrscheinlich aufgefallen, dass es noch andere Ereignisse gibt, die mit dem Mauszeiger verbunden sind. Diese Ereignisse befinden sich jedoch nicht in der Header-Datei C_Mouse.mqh, sondern in der Datei C_Study.mqh. Um diese Ereignisse zu sehen und zu verstehen, was passieren wird, sehen wir uns diesen Code an. Der vollständige Code ist nachstehend aufgeführt:

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #include "..\C_Mouse.mqh"
005. //+------------------------------------------------------------------+
006. #define def_ExpansionPrefix def_MousePrefixName + "Expansion_"
007. #define def_ExpansionBtn1 def_ExpansionPrefix + "B1"
008. #define def_ExpansionBtn2 def_ExpansionPrefix + "B2"
009. #define def_ExpansionBtn3 def_ExpansionPrefix + "B3"
010. //+------------------------------------------------------------------+
011. class C_Study : public C_Mouse
012. {
013.    private :
014. //+------------------------------------------------------------------+
015.            struct st00
016.            {
017.                    eStatusMarket  Status;
018.                    MqlRates       Rate;
019.                    string         szInfo;
020.                    color          corP,
021.                                   corN;
022.                    int            HeightText;
023.                    bool           bvT, bvD, bvP;
024.            }m_Info;
025. //+------------------------------------------------------------------+
026.            const datetime GetBarTime(void)
027.                    {
028.                            datetime dt;
029.                            int i0 = PeriodSeconds();
030.                            
031.                            if (m_Info.Status == eInReplay)
032.                            {
033.                                    if ((dt = GetInfoMouse().TimeDevice) == ULONG_MAX) return ULONG_MAX;
034.                            }else dt = TimeCurrent();
035.                            if (m_Info.Rate.time <= dt)
036.                                    m_Info.Rate.time = (datetime)(((ulong) dt / i0) * i0) + i0;
037. 
038.                            return m_Info.Rate.time - dt;
039.                    }
040. //+------------------------------------------------------------------+
041.            void Draw(void)
042.                    {
043.                            double v1;
044.                            
045.                            if (m_Info.bvT)
046.                            {
047.                                    ObjectSetInteger(GetInfoTerminal().ID, def_ExpansionBtn1, OBJPROP_YDISTANCE, GetInfoMouse().Position.Y_Adjusted - 18);
048.                                    ObjectSetString(GetInfoTerminal().ID, def_ExpansionBtn1, OBJPROP_TEXT, m_Info.szInfo);
049.                            }
050.                            if (m_Info.bvD)
051.                            {
052.                                    v1 = NormalizeDouble(100.0 - ((m_Info.Rate.close / GetInfoMouse().Position.Price) * 100.0), 2);
053.                                    ObjectSetInteger(GetInfoTerminal().ID, def_ExpansionBtn2, OBJPROP_YDISTANCE, GetInfoMouse().Position.Y_Adjusted - 1);
054.                                    ObjectSetInteger(GetInfoTerminal().ID, def_ExpansionBtn2, OBJPROP_BGCOLOR, (v1 < 0 ? m_Info.corN : m_Info.corP));
055.                                    ObjectSetString(GetInfoTerminal().ID, def_ExpansionBtn2, OBJPROP_TEXT, StringFormat("%.2f%%", MathAbs(v1)));
056.                            }
057.                            if (m_Info.bvP)
058.                            {
059.                                    v1 = NormalizeDouble(100.0 - ((m_Info.Rate.close / iClose(GetInfoTerminal().szSymbol, PERIOD_D1, 0)) * 100.0), 2);
060.                                    ObjectSetInteger(GetInfoTerminal().ID, def_ExpansionBtn3, OBJPROP_YDISTANCE, GetInfoMouse().Position.Y_Adjusted - 1);
061.                                    ObjectSetInteger(GetInfoTerminal().ID, def_ExpansionBtn3, OBJPROP_BGCOLOR, (v1 < 0 ? m_Info.corN : m_Info.corP));
062.                                    ObjectSetString(GetInfoTerminal().ID, def_ExpansionBtn3, OBJPROP_TEXT, StringFormat("%.2f%%", MathAbs(v1)));
063.                            }
064.                    }
065. //+------------------------------------------------------------------+
066. inline void CreateObjInfo(EnumEvents arg)
067.                    {
068.                            switch (arg)
069.                            {
070.                                    case evShowBarTime:
071.                                            C_Mouse::CreateObjToStudy(2, 110, def_ExpansionBtn1, clrPaleTurquoise);
072.                                            m_Info.bvT = true;
073.                                            break;
074.                                    case evShowDailyVar:
075.                                            C_Mouse::CreateObjToStudy(2, 53, def_ExpansionBtn2);
076.                                            m_Info.bvD = true;
077.                                            break;
078.                                    case evShowPriceVar:
079.                                            C_Mouse::CreateObjToStudy(58, 53, def_ExpansionBtn3);
080.                                            m_Info.bvP = true;
081.                                            break;
082.                            }
083.                    }
084. //+------------------------------------------------------------------+
085. inline void RemoveObjInfo(EnumEvents arg)
086.                    {
087.                            string sz;
088.                            
089.                            switch (arg)
090.                            {
091.                                    case evHideBarTime:
092.                                            sz = def_ExpansionBtn1;
093.                                            m_Info.bvT = false;
094.                                            break;
095.                                    case evHideDailyVar:
096.                                            sz = def_ExpansionBtn2;
097.                                            m_Info.bvD      = false;
098.                                            break;
099.                                    case evHidePriceVar:
100.                                            sz = def_ExpansionBtn3;
101.                                            m_Info.bvP = false;
102.                                            break;
103.                            }
104.                            ChartSetInteger(GetInfoTerminal().ID, CHART_EVENT_OBJECT_DELETE, false);
105.                            ObjectDelete(GetInfoTerminal().ID, sz);
106.                            ChartSetInteger(GetInfoTerminal().ID, CHART_EVENT_OBJECT_DELETE, true);
107.                    }
108. //+------------------------------------------------------------------+
109.    public  :
110. //+------------------------------------------------------------------+
111.            C_Study(long IdParam, string szShortName, color corH, color corP, color corN)
112.                    :C_Mouse(IdParam, szShortName, corH, corP, corN)
113.                    {
114.                            if (_LastError != ERR_SUCCESS) return;
115.                            ZeroMemory(m_Info);
116.                            m_Info.Status = eCloseMarket;
117.                            m_Info.Rate.close = iClose(GetInfoTerminal().szSymbol, PERIOD_D1, ((GetInfoTerminal().szSymbol == def_SymbolReplay) || (macroGetDate(TimeCurrent()) != macroGetDate(iTime(GetInfoTerminal().szSymbol, PERIOD_D1, 0))) ? 0 : 1));
118.                            m_Info.corP = corP;
119.                            m_Info.corN = corN;
120.                            CreateObjInfo(evShowBarTime);
121.                            CreateObjInfo(evShowDailyVar);
122.                            CreateObjInfo(evShowPriceVar);
123.                    }
124. //+------------------------------------------------------------------+
125.            void Update(const eStatusMarket arg)
126.                    {
127.                            datetime dt;
128.                            
129.                            switch (m_Info.Status = (m_Info.Status != arg ? arg : m_Info.Status))
130.                            {
131.                                    case eCloseMarket :
132.                                            m_Info.szInfo = "Closed Market";
133.                                            break;
134.                                    case eInReplay    :
135.                                    case eInTrading   :
136.                                            if ((dt = GetBarTime()) < ULONG_MAX)
137.                                            {
138.                                                    m_Info.szInfo = TimeToString(dt, TIME_SECONDS);
139.                                                    break;
140.                                            }
141.                                    case eAuction     :
142.                                            m_Info.szInfo = "Auction";
143.                                            break;
144.                                    default           :
145.                                            m_Info.szInfo = "ERROR";
146.                            }
147.                            Draw();
148.                    }
149. //+------------------------------------------------------------------+
150. virtual void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
151.                    {
152.                            C_Mouse::DispatchMessage(id, lparam, dparam, sparam);
153.                            switch (id)
154.                            {
155.                                    case CHARTEVENT_CUSTOM + evHideBarTime:
156.                                            RemoveObjInfo(evHideBarTime);
157.                                            break;
158.                                    case CHARTEVENT_CUSTOM + evShowBarTime:
159.                                            CreateObjInfo(evShowBarTime);
160.                                            break;
161.                                    case CHARTEVENT_CUSTOM + evHideDailyVar:
162.                                            RemoveObjInfo(evHideDailyVar);
163.                                            break;
164.                                    case CHARTEVENT_CUSTOM + evShowDailyVar:
165.                                            CreateObjInfo(evShowDailyVar);
166.                                            break;
167.                                    case CHARTEVENT_CUSTOM + evHidePriceVar:
168.                                            RemoveObjInfo(evHidePriceVar);
169.                                            break;
170.                                    case CHARTEVENT_CUSTOM + evShowPriceVar:
171.                                            CreateObjInfo(evShowPriceVar);
172.                                            break;
173.                                    case CHARTEVENT_MOUSE_MOVE:
174.                                            Draw();
175.                                            break;
176.                            }
177.                            ChartRedraw(GetInfoTerminal().ID);
178.                    }
179. //+------------------------------------------------------------------+
180. };
181. //+------------------------------------------------------------------+
182. #undef def_ExpansionBtn3
183. #undef def_ExpansionBtn2
184. #undef def_ExpansionBtn1
185. #undef def_ExpansionPrefix
186. #undef def_MousePrefixName
187. //+------------------------------------------------------------------+

Quellcode der Datei C_Study.mqh

Im Gegensatz zu C_Mouse.mqh gibt es hier viele Unterschiede. Beginnen wir mit der Tatsache, dass wir neue Variablen, Prüfungen und andere Dinge haben, die jetzt implementiert werden. Da die meisten von ihnen jedoch einfach sind, werden wir uns nur mit einigen der „ungewöhnlichsten“ befassen. Dazu gehört auch Zeile 33, in der wir sehen, dass die Funktion für den Zugriff auf die globale Variable im Terminal nicht mehr verwendet wird. Jetzt fragen wir den Mauszeiger nach etwas, das zuvor in der globalen Variable des Terminals gesucht wurde. Das ist genau die Art und Weise, wie wir Dinge tun wollen: Wir wollen Dinge tun, ohne etwas zu nutzen, das der Nutzer kontrollieren kann und ohne auf externe Programmierung zurückzugreifen. Die Idee ist, alles in reinem MQL5 zu implementieren.

Wenn man sich den Code ansieht, ist es vielleicht nicht ganz klar, dass unsere Implementierung viel mehr Einstellungen hat als die vorherige. Wir haben dies getan, um unseren Mauszeiger zu einer Art Standard zu machen, der in anderen Anwendungen auf der Plattform verwendet werden kann. Hier gibt es einen wichtigen Punkt: Als Programmierer können Sie Nachrichten an den Mauszeiger senden, um etwas ein- oder auszuschalten, das bereits in ihm definiert ist.

Dazu müssen wir bestimmte Teile des Codes isolieren, damit das Objekt, auf das wir zugreifen, die gewünschten Änderungen erfährt, wenn ein Ereignis eintritt, bei dem etwas ein- oder ausgeschaltet werden muss. In diesem Fall geht es um etwas Einfaches, z. B. darum, wie etwas im Chart angezeigt oder nicht angezeigt werden kann. Nun, es hätte auch etwas noch Komplizierteres sein können. Der Freiheitsgrad, den wir nach und nach einführen, macht viele Dinge möglich. Um sie zu implementieren, müssen Sie nur geringfügige Änderungen an dem vornehmen, was bereits fertig ist. Dies bedeutet auch, dass das Sicherheitsniveau und die Zuverlässigkeit der Anwendung immer auf dem höchstmöglichen Niveau bleiben.

Der Großteil des Codes in der Datei C_Study.mqh tut genau dies. Aber jetzt sind wir wirklich daran interessiert, was ab Zeile 150 passiert, wo wir das implementieren werden, was in dieser Header-Datei beschrieben ist. Beachten Sie, dass die ausstehenden Teile, die wir hier nicht behandeln wollen, an die Klasse C_Mouse übergeben werden, damit dort Ereignisse behandelt werden können. Dies ist aus Zeile 152 ersichtlich.

Achten Sie jetzt auf eine Sache. Jedes der Nutzerereignisse, die in dieser Ereignisbehandlung zu sehen sind, schaltet etwas in der Mausanzeige ein oder aus, sodass sie ein wenig anders aussieht, aber dies geschieht zur Laufzeit, ohne dass der Nutzer den Code neu kompilieren oder eine große Liste von Optionen konfigurieren muss. Bitte beachten Sie diese Tatsache. Sie können einfach kleine Skriptdateien erstellen, die nutzerdefinierte Ereignisse an den Mauszeiger senden, sodass sich sein Aussehen während der Verwendung ändert.

Wenn Sie kreativ genug sind, werden Sie schon beim Anblick dieses Codes und seiner Funktionsweise an verschiedene Tricks denken und diese planen. Aber ich rate Ihnen, nichts zu überstürzen, denn zum jetzigen Zeitpunkt ist noch nicht ganz klar, in welche Richtung sich das Replay/Simulator-System entwickeln wird. Der Grund dafür ist, dass die Umwandlung verschiedener Elemente in Module eine Vielzahl von Möglichkeiten eröffnet. Und die Art und Weise, wie das System wachsen kann, zwingt uns dazu, vorsichtig zu sein, wenn wir über neue Möglichkeiten nachdenken. Aber im Moment konzentriere ich mich darauf, das System ohne die Verwendung von globalen Terminalvariablen zum Laufen zu bringen, während ich immer noch die gleichen Eigenschaften beibehalte, die es hatte, als die Module zum ersten Mal erstellt wurden.

Also gut. Nun, da dies alles gezeigt wird, können wir mit dem Code fortfahren, der den Mauszeiger tatsächlich erstellt. Sie können es unten sehen.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. #property description "This is an indicator for graphical studies using the mouse."
004. #property description "This is an integral part of the Replay / Simulator system."
005. #property description "However it can be used in the real market."
006. #property version "1.54"
007. #property icon "/Images/Market Replay/Icons/Indicators.ico"
008. #property link "https://www.mql5.com/pt/articles/11971"
009. #property indicator_chart_window
010. #property indicator_plots 0
011. #property indicator_buffers 1
012. //+------------------------------------------------------------------+
013. #include <Market Replay\Auxiliar\Study\C_Study.mqh>
014. //+------------------------------------------------------------------+
015. C_Study *Study     = NULL;
016. //+------------------------------------------------------------------+
017. input long user00  = 0;                                    //ID
018. input C_Study::eStatusMarket user01 = C_Study::eAuction;   //Market Status
019. input color user02 = clrBlack;                             //Price Line
020. input color user03 = clrPaleGreen;                         //Positive Study
021. input color user04 = clrLightCoral;                        //Negative Study
022. //+------------------------------------------------------------------+
023. C_Study::eStatusMarket m_Status;
024. int m_posBuff = 0;
025. double m_Buff[];
026. //+------------------------------------------------------------------+
027. int OnInit()
028. {
029.    ResetLastError();
030.    Study = new C_Study(user00, "Indicator Mouse Study", user02, user03, user04);
031.    if (_LastError != ERR_SUCCESS) return INIT_FAILED;
032.    if ((*Study).GetInfoTerminal().szSymbol != def_SymbolReplay)
033.    {
034.            MarketBookAdd((*Study).GetInfoTerminal().szSymbol);
035.            OnBookEvent((*Study).GetInfoTerminal().szSymbol);
036.            m_Status = C_Study::eCloseMarket;
037.    }else
038.            m_Status = user01;
039.    SetIndexBuffer(0, m_Buff, INDICATOR_DATA);
040.    ArrayInitialize(m_Buff, EMPTY_VALUE);
041.    
042.    return INIT_SUCCEEDED;
043. }
044. //+------------------------------------------------------------------+
045. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
046. {
047.    m_posBuff = rates_total - 6;
048.    (*Study).Update(m_Status);      
049.    
050.    return rates_total;
051. }
052. //+------------------------------------------------------------------+
053. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
054. {
055.    (*Study).DispatchMessage(id, lparam, dparam, sparam);
056.    SetBuffer();
057.    
058.    ChartRedraw((*Study).GetInfoTerminal().ID);
059. }
060. //+------------------------------------------------------------------+
061. void OnBookEvent(const string &symbol)
062. {
063.    MqlBookInfo book[];
064.    C_Study::eStatusMarket loc = m_Status;
065.    
066.    if (symbol != (*Study).GetInfoTerminal().szSymbol) return;
067.    MarketBookGet((*Study).GetInfoTerminal().szSymbol, book);
068.    m_Status = (ArraySize(book) == 0 ? C_Study::eCloseMarket : C_Study::eInTrading);
069.    for (int c0 = 0; (c0 < ArraySize(book)) && (m_Status != C_Study::eAuction); c0++)
070.            if ((book[c0].type == BOOK_TYPE_BUY_MARKET) || (book[c0].type == BOOK_TYPE_SELL_MARKET)) m_Status = C_Study::eAuction;
071.    if (loc != m_Status) (*Study).Update(m_Status);
072. }
073. //+------------------------------------------------------------------+
074. void OnDeinit(const int reason)
075. {
076.    if (reason != REASON_INITFAILED)
077.    {
078.            if ((*Study).GetInfoTerminal().szSymbol != def_SymbolReplay)
079.                    MarketBookRelease((*Study).GetInfoTerminal().szSymbol);
080.    }
081.    delete Study;
082. }
083. //+------------------------------------------------------------------+
084. inline void SetBuffer(void)
085. {
086.    uCast_Double Info;
087.    
088.    m_posBuff = (m_posBuff < 0 ? 0 : m_posBuff);
089.    m_Buff[m_posBuff + 0] = (*Study).GetInfoMouse().Position.Price;
090.    Info._datetime = (*Study).GetInfoMouse().Position.dt;
091.    m_Buff[m_posBuff + 1] = Info.dValue;
092.    Info._int[0] = (*Study).GetInfoMouse().Position.X_Adjusted;
093.    Info._int[1] = (*Study).GetInfoMouse().Position.Y_Adjusted;
094.    m_Buff[m_posBuff + 2] = Info.dValue;
095.    Info._int[0] = (*Study).GetInfoMouse().Position.X_Graphics;
096.    Info._int[1] = (*Study).GetInfoMouse().Position.Y_Graphics;
097.    m_Buff[m_posBuff + 3] = Info.dValue;
098.    Info._char[0] = ((*Study).GetInfoMouse().ExecStudy == C_Mouse::eStudyNull ? (char)(*Study).GetInfoMouse().ButtonStatus : 0);
099.    m_Buff[m_posBuff + 4] = Info.dValue;
100.    m_Buff[m_posBuff + 5] = (double)(*Study).GetInfoMouse().TimeDevice;
101. }
102. //+------------------------------------------------------------------+

Quellcode des Mauszeigers

Der Kodex hat keine wesentlichen Änderungen erfahren. Es gibt nur einen neuen Zusatz, der in Zeile 100 zu sehen ist, wo die Daten in den Indikatorpuffer gestellt werden. Auch diese Daten sind nur in der Anfangsphase für den Replay/Simulator-Dienst nützlich. Es hat keine andere Verwendung. Zumindest habe ich keine anderen bemerkt.


Schlussfolgerung

Damit Sie besser verstehen, was hier vor sich geht, füge ich die ausführbare Datei des Indikators sowie einige Skripte bei, mit denen der Indikator im Chart geändert werden kann. Es gibt aber auch diejenigen, die ein bereits kompiliertes Programm nicht auf ihrer Plattform ausführen wollen. Nun, ich verstehe warum. Im Video am Ende dieses Artikels können Sie sehen, was passiert, wenn Skripte ausgeführt werden.

Bitte beachten Sie, dass dies nur ein kleiner Teil dessen ist, was wir zu leisten imstande sind. Diejenigen, die eine engere Sichtweise haben, werden sagen, dass dies Unsinn ist und anders hätte gemacht werden können, aber ich werde ihnen keine Beachtung schenken. Ich sehe lieber das Funkeln in den Augen derjenigen, die über die Möglichkeiten dessen nachdenken, was ich zeige: was aus diesem modularen System werden kann und wie sich alles weiter entwickeln wird. Für sie schreibe ich diese Artikel. Darin zeige ich, dass viele nur an der Oberfläche dessen kratzen, was wir mit MQL5 tatsächlich tun können, und dass MetaTrader 5 tatsächlich eine großartige Plattform ist, die in den richtigen Händen unglaubliche Dinge leisten kann.

Ich entschuldige mich jedoch nochmals bei denjenigen, die keine Programmierkenntnisse haben. Es tut mir leid, aber ohne richtige Kenntnisse über das, was hier gezeigt wurde, wird der Zugang zum Quellcode dieses Replay/Simulator-Dienstes zu etwas Gefährlichem. Aber ich verspreche, Sie mit dem Problem nicht allein zu lassen, ich werde Ihnen die ausführbare Datei zur Verfügung stellen, sobald die Modulversion fertig ist und stabil wird, und werde die ausführbare Datei hier in den Artikeln bereitstellen. Wenn Sie jedoch den Quellcode kompilieren möchten, ist dieser immer im Artikel verfügbar. Ich weiß jedoch, dass Sie ohne die entsprechenden Kenntnisse nicht in der Lage sein werden, die für die Kompilierung des Systems erforderliche Verzeichnisstruktur zu erstellen.

Das ist genau das, was ich tun wollte, weil ich aus eigener Erfahrung gesehen habe, dass in früheren Artikeln Leute versucht haben, etwas zusammenzustellen, ohne zu verstehen, worüber sie reden. Solche Dinge sind nicht nur riskant, sondern auch gefährlich. Man sollte Dinge nicht nutzen, ohne ihren Zweck zu verstehen.


Video 01 - Demonstration der Funktionsweise des Moduls

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

Beigefügte Dateien |
Anexo.zip (420.65 KB)
Neuronale Netze leicht gemacht (Teil 94): Optimierung der Eingabereihenfolge Neuronale Netze leicht gemacht (Teil 94): Optimierung der Eingabereihenfolge
Wenn wir mit Zeitreihen arbeiten, verwenden wir die Quelldaten immer in ihrer historischen Reihenfolge. Aber ist das die beste Option? Es besteht die Meinung, dass eine Änderung der Reihenfolge der Eingabedaten die Effizienz der trainierten Modelle verbessern wird. In diesem Artikel lade ich Sie ein, sich mit einer der Methoden zur Optimierung der Eingabereihenfolge vertraut zu machen.
Integrieren Sie Ihr eigenes LLM in EA (Teil 5): Handelsstrategie mit LLMs(II)-LoRA-Tuning entwickeln und testen Integrieren Sie Ihr eigenes LLM in EA (Teil 5): Handelsstrategie mit LLMs(II)-LoRA-Tuning entwickeln und testen
Angesichts der rasanten Entwicklung der künstlichen Intelligenz sind Sprachmodelle (language models, LLMs) heute ein wichtiger Bestandteil der künstlichen Intelligenz, sodass wir darüber nachdenken sollten, wie wir leistungsstarke LLMs in unseren algorithmischen Handel integrieren können. Für die meisten Menschen ist es schwierig, diese leistungsstarken Modelle auf ihre Bedürfnisse abzustimmen, sie lokal einzusetzen und sie dann auf den algorithmischen Handel anzuwenden. In dieser Artikelserie werden wir Schritt für Schritt vorgehen, um dieses Ziel zu erreichen.
Neuronales Netz in der Praxis: Pseudoinverse (I) Neuronales Netz in der Praxis: Pseudoinverse (I)
Heute werden wir uns damit beschäftigen, wie man die Berechnung der Pseudoinverse in der reinen MQL5-Sprache implementiert. Der Code, den wir uns ansehen werden, wird für Anfänger viel komplexer sein, als ich erwartet hatte, und ich bin noch dabei herauszufinden, wie ich ihn auf einfache Weise erklären kann. Betrachten Sie dies also als eine Gelegenheit, einen ungewöhnlichen Code zu lernen. Ruhig und aufmerksam. Obwohl es nicht auf eine effiziente oder schnelle Anwendung abzielt, soll es so didaktisch wie möglich sein.
Erstellen eines Administrator-Panels für den Handel in MQL5 (Teil III): Erweiterung der installierten Klassen für die Theme-Verwaltung (II) Erstellen eines Administrator-Panels für den Handel in MQL5 (Teil III): Erweiterung der installierten Klassen für die Theme-Verwaltung (II)
In dieser Diskussion werden wir die bestehende Dialogbibliothek sorgfältig erweitern, um die Logik der Verwaltung der Farbmodi (Theme) zu integrieren. Darüber hinaus werden wir Methoden für den Theme-Wechsel in die Klassen CDialog, CEdit und CButton integrieren, die in unserem Admin-Panel-Projekt verwendet werden. Lesen Sie weiter für weitere aufschlussreiche Perspektiven.