English Русский Español 日本語 Português
preview
Entwicklung eines Replay Systems (Teil 45): Chart Trade Projekt (IV)

Entwicklung eines Replay Systems (Teil 45): Chart Trade Projekt (IV)

MetaTrader 5Beispiele | 9 September 2024, 10:52
60 0
Daniel Jose
Daniel Jose

Einführung

Im vorherigen Artikel Entwicklung eines Replay Systems (Teil 44): Chart Trade Project (III) habe ich gezeigt, wie Sie dem Chart Trade-Fenster eine gewisse Interaktivität hinzufügen können, sodass es sich so verhält, als befänden sich Objekte darin. Obwohl das einzige wirkliche Objekt, das auf dem Chart dargestellt wurde, OBJ_CHART war.

Aber trotz der bestehenden Interaktion, die recht angenehm ist, kann sie nicht als ideal bezeichnet werden. Es gibt noch einige Details, die in diesem Artikel abschließend geklärt werden sollen. Das Ergebnis ist ein ziemlich interessanter Code, der das tut, was Sie in Video 01 unten sehen können:


Video 01. Demonstration der Möglichkeiten dieser Version

Dieses Video zeigt genau, was wir in diesem Stadium der Entwicklung tun können. Trotz allem werden wir immer noch kein Bestellsystem haben. Noch nicht, denn wir müssen noch viele Dinge erstellen, bevor der Chart Trade Indikator tatsächlich Aufträge senden oder Positionen schließen kann.


Neuer Indikator

Trotz des Titels dieses Themas, der deutlich macht, dass wir einen neuen Indikator erstellen werden, ist dies nicht genau das, was wir tun werden. Wir werden einige Elemente hinzufügen, die den Chart Trade Indikator tatsächlich zu einem neuen Konstruktionsmodell machen. Nachstehend finden Sie den vollständigen Quellcode des Indikators:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Base version for Chart Trade (DEMO version)"
04. #property version   "1.45"
05. #property icon "/Images/Market Replay/Icons/Indicators.ico"
06. #property link "https://www.mql5.com/en/articles/11701"
07. #property indicator_chart_window
08. #property indicator_plots 0
09. //+------------------------------------------------------------------+
10. #include <Market Replay\Chart Trader\C_ChartFloatingRAD.mqh>
11. //+------------------------------------------------------------------+
12. C_ChartFloatingRAD *chart = NULL;
13. //+------------------------------------------------------------------+
14. input int           user01 = 1;             //Leverage
15. input double        user02 = 100.1;         //Finance Take
16. input double        user03 = 75.4;          //Finance Stop
17. //+------------------------------------------------------------------+
18. #define macro_ERROR(A) if (_LastError != ERR_SUCCESS) { Print(__FILE__, " - [Error]: ", _LastError); if (A) ResetLastError(); }
19. //+------------------------------------------------------------------+
20. int OnInit()
21. {
22.     chart = new C_ChartFloatingRAD("Indicator Chart Trade", new C_Mouse("Indicator Mouse Study"), user01, user02, user03);
23.     
24.     macro_ERROR(false);
25.             
26.     return (_LastError == ERR_SUCCESS ? INIT_SUCCEEDED : INIT_FAILED);
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 OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
35. {
36.     (*chart).DispatchMessage(id, lparam, dparam, sparam);
37. 
38.     macro_ERROR(true);
39.     
40.     ChartRedraw();
41. }
42. //+------------------------------------------------------------------+
43. void OnDeinit(const int reason)
44. {
45.     if (reason == REASON_CHARTCHANGE) (*chart).SaveState();
46. 
47.     delete chart;
48. }
49. //+------------------------------------------------------------------+

Chart Trade Indikator Quellcode

Wie Sie sehen können, hat sich der Code seit der letzten Demonstration kaum verändert. Aber die Veränderungen, die sich vollziehen, verändern das Funktionsprinzip des Indikators radikal.

Zuerst haben wir ein Makro hinzugefügt. Sie befindet sich in Zeile 18 des Quelltextes. Dieses Makro standardisiert die im Terminal angezeigte Fehlermeldung. Beachten Sie nun, dass es einen Parameter benötigt, der angibt, ob das Makro die Fehlerkonstante zurücksetzen soll. Sie können dies an den Stellen sehen, an denen das Makro verwendet wird. Der erste Punkt ist in Zeile 24, gleich nach dem Versuch, den Indikator zu initialisieren. In diesem Fall wollen oder müssen wir die Konstante nicht zurücksetzen, also ist das Argument falsch. Der zweite Punkt befindet sich in Zeile 38. Hier kann sich herausstellen, dass der Fehler bis zu einem gewissen Grad akzeptabel ist, sodass das Argument wahr ist, um den konstanten Wert zurückzusetzen. Daher ist es wichtig, die im Terminal erscheinenden Meldungen zu überwachen, um zu sehen, was passiert.

Es gibt noch einen weiteren interessanten Punkt, der sich in Zeile 45 befindet. Dies ist eine Sicherheitsmaßnahme. Ein besseres Verständnis wird im Zusammenhang mit der Erläuterung des C_ChartFloatingRAD-Klassencodes vermittelt. Der Grund dafür ist im Wesentlichen die Notwendigkeit, die Funktionalität des Chart Trade Indikators irgendwie aufrechtzuerhalten. Achten Sie darauf, dass ich den Aufruf zur Aktualisierung des Charts verwende. Dieses Ereignis tritt immer dann ein, wenn wir den Zeitrahmen des Charts ändern. Ich möchte darauf hinweisen, dass unser Hauptproblem, neben anderen Dingen, die Änderung des Zeitrahmens ist.

Wenn Sie den Zeitrahmen wechseln, werden alle Indikatoren aus dem Chart entfernt und dann wieder neu gestartet. An diesem Punkt gehen Daten, die direkt im Chart bearbeitet werden, verloren. Es gibt mehrere Möglichkeiten, diesen Datenverlust zu verhindern. Eine davon werden wir verwenden. Es gibt also nichts mehr über den Quellcode des Indikators zu sagen. Da die Klasse C_AdjustTemplate keine Änderungen erfahren hat, können wir mit der Erläuterung des Codes für die Klasse C_ChartFloatingRAD fortfahren.


Die Klasse C_ChartFloatingRAD fast voll funktionsfähig machen

Der Hauptzweck dieses Artikels ist die Einführung und Erläuterung der Klasse C_ChartFloatingRAD. Wie Sie vielleicht in dem Video gesehen haben, das ich zu Beginn des Artikels vorgestellt habe, haben wir einen Chart Trade-Indikator, der auf recht interessante Weise funktioniert. Wie Sie vielleicht bemerkt haben, haben wir immer noch eine relativ kleine Anzahl von Objekten im Chart, und dennoch erhalten wir die erwartete Funktionalität. Die im Indikator enthaltenen Werte können bearbeitet werden. Die Frage ist, wie ist das möglich?

Um diese und andere Fragen zu beantworten, müssen wir uns den Quellcode der Klasse ansehen. Dieser Code ist weiter unten vollständig dargestellt. Bitte beachten Sie, dass es keine angehängten Dateien gibt, aber Sie können das System trotzdem wie im Video gezeigt verwenden. Wenn Sie diese Artikelserie verfolgt haben, sollten Sie keine Probleme haben.

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #include "../Auxiliar/C_Mouse.mqh"
005. #include "../Auxiliar/Interprocess.mqh"
006. #include "C_AdjustTemplate.mqh"
007. //+------------------------------------------------------------------+
008. #define macro_NameGlobalVariable(A) StringFormat("ChartTrade_%u%s", GetInfoTerminal().ID, A)
009. //+------------------------------------------------------------------+
010. class C_ChartFloatingRAD : private C_Terminal
011. {
012.    private :
013.            enum eObjectsIDE {MSG_LEVERAGE_VALUE, MSG_TAKE_VALUE, MSG_STOP_VALUE, MSG_MAX_MIN, MSG_TITLE_IDE, MSG_DAY_TRADE, MSG_BUY_MARKET, MSG_SELL_MARKET, MSG_CLOSE_POSITION, MSG_NULL};
014.            struct st00
015.            {
016.                    int     x, y, minx, miny;
017.                    string  szObj_Chart,
018.                            szObj_Editable,
019.                            szFileNameTemplate;
020.                    long    WinHandle;
021.                    double  FinanceTake,
022.                            FinanceStop;
023.                    int     Leverage;
024.                    bool    IsDayTrade,
025.                            IsMaximized;
026.                    struct st01
027.                    {
028.                            int    x, y, w, h;
029.                            color  bgcolor;
030.                            int    FontSize;
031.                            string FontName;
032.                    }Regions[MSG_NULL];
033.            }m_Info;
034. //+------------------------------------------------------------------+
035.            C_Mouse *m_Mouse;
036. //+------------------------------------------------------------------+
037.            void CreateWindowRAD(int w, int h)
038.                    {
039.                            m_Info.szObj_Chart = "Chart Trade IDE";
040.                            m_Info.szObj_Editable = m_Info.szObj_Chart + " > Edit";
041.                            ObjectCreate(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJ_CHART, 0, 0, 0);
042.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, m_Info.x);
043.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, m_Info.y);
044.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XSIZE, w);
045.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YSIZE, h);
046.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_DATE_SCALE, false);
047.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_PRICE_SCALE, false);
048.                            m_Info.WinHandle = ObjectGetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_CHART_ID);
049.                    };
050. //+------------------------------------------------------------------+
051.            void AdjustEditabled(C_AdjustTemplate &Template, bool bArg)
052.                    {
053.                            for (eObjectsIDE c0 = 0; c0 <= MSG_STOP_VALUE; c0++)
054.                                    if (bArg)
055.                                    {
056.                                            Template.Add(EnumToString(c0), "bgcolor", NULL);
057.                                            Template.Add(EnumToString(c0), "fontsz", NULL);
058.                                            Template.Add(EnumToString(c0), "fontnm", NULL);
059.                                    }
060.                                    else
061.                                    {
062.                                            m_Info.Regions[c0].bgcolor = (color) StringToInteger(Template.Get(EnumToString(c0), "bgcolor"));
063.                                            m_Info.Regions[c0].FontSize = (int) StringToInteger(Template.Get(EnumToString(c0), "fontsz"));
064.                                            m_Info.Regions[c0].FontName = Template.Get(EnumToString(c0), "fontnm");
065.                                    }
066.                    }
067. //+------------------------------------------------------------------+
068. inline void AdjustTemplate(const bool bFirst = false)
069.                    {
070. #define macro_AddAdjust(A) {                     \
071.              (*Template).Add(A, "size_x", NULL); \
072.              (*Template).Add(A, "size_y", NULL); \
073.              (*Template).Add(A, "pos_x", NULL);  \
074.              (*Template).Add(A, "pos_y", NULL);  \
075.                            }
076. #define macro_GetAdjust(A) {                                                                                                                                                                                                                                               \
077.              m_Info.Regions[A].x = (int) StringToInteger((*Template).Get(EnumToString(A), "pos_x"));  \
078.              m_Info.Regions[A].y = (int) StringToInteger((*Template).Get(EnumToString(A), "pos_y"));  \
079.              m_Info.Regions[A].w = (int) StringToInteger((*Template).Get(EnumToString(A), "size_x")); \
080.              m_Info.Regions[A].h = (int) StringToInteger((*Template).Get(EnumToString(A), "size_y")); \
081.                            }
082. #define macro_PointsToFinance(A) A * (GetInfoTerminal().VolumeMinimal + (GetInfoTerminal().VolumeMinimal * (m_Info.Leverage - 1))) * GetInfoTerminal().AdjustToTrade
083.                            
084.                            C_AdjustTemplate *Template;
085.                            
086.                            if (bFirst)
087.                            {
088.                                    Template = new C_AdjustTemplate("Chart Trade/IDE_RAD.tpl", m_Info.szFileNameTemplate = StringFormat("Chart Trade/%u.tpl", GetInfoTerminal().ID));
089.                                    for (eObjectsIDE c0 = 0; c0 <= MSG_CLOSE_POSITION; c0++) macro_AddAdjust(EnumToString(c0));
090.                                    AdjustEditabled(Template, true);
091.                            }else Template = new C_AdjustTemplate(m_Info.szFileNameTemplate);
092.                            m_Info.Leverage = (m_Info.Leverage <= 0 ? 1 : m_Info.Leverage);
093.                            m_Info.FinanceTake = macro_PointsToFinance(FinanceToPoints(MathAbs(m_Info.FinanceTake), m_Info.Leverage));
094.                            m_Info.FinanceStop = macro_PointsToFinance(FinanceToPoints(MathAbs(m_Info.FinanceStop), m_Info.Leverage));
095.                            (*Template).Add("MSG_NAME_SYMBOL", "descr", GetInfoTerminal().szSymbol);
096.                            (*Template).Add("MSG_LEVERAGE_VALUE", "descr", (string)m_Info.Leverage);
097.                            (*Template).Add("MSG_TAKE_VALUE", "descr", (string)m_Info.FinanceTake);
098.                            (*Template).Add("MSG_STOP_VALUE", "descr", (string)m_Info.FinanceStop);
099.                            (*Template).Add("MSG_DAY_TRADE", "state", (m_Info.IsDayTrade ? "1" : "0"));
100.                            (*Template).Add("MSG_MAX_MIN", "state", (m_Info.IsMaximized ? "1" : "0"));
101.                            (*Template).Execute();
102.                            if (bFirst)
103.                            {
104.                                    for (eObjectsIDE c0 = 0; c0 <= MSG_CLOSE_POSITION; c0++) macro_GetAdjust(c0);
105.                                    m_Info.Regions[MSG_TITLE_IDE].w = m_Info.Regions[MSG_MAX_MIN].x;
106.                                    AdjustEditabled(Template, false);
107.                            };
108.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YSIZE, (m_Info.IsMaximized ? 210 : m_Info.Regions[MSG_TITLE_IDE].h + 6));
109.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, (m_Info.IsMaximized ? m_Info.x : m_Info.minx));
110.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, (m_Info.IsMaximized ? m_Info.y : m_Info.miny));
111.                            
112.                            delete Template;
113.                            
114.                            ChartApplyTemplate(m_Info.WinHandle, "/Files/" + m_Info.szFileNameTemplate);
115.                            ChartRedraw(m_Info.WinHandle);
116. 
117. #undef macro_PointsToFinance
118. #undef macro_GetAdjust
119. #undef macro_AddAdjust
120.                    }
121. //+------------------------------------------------------------------+
122.            eObjectsIDE CheckMousePosition(const int x, const int y)
123.                    {
124.                            int xi, yi, xf, yf;
125.                            
126.                            for (eObjectsIDE c0 = 0; c0 <= MSG_CLOSE_POSITION; c0++)
127.                            {
128.                                    xi = (m_Info.IsMaximized ? m_Info.x : m_Info.minx) + m_Info.Regions[c0].x;
129.                                    yi = (m_Info.IsMaximized ? m_Info.y : m_Info.miny) + m_Info.Regions[c0].y;
130.                                    xf = xi + m_Info.Regions[c0].w;
131.                                    yf = yi + m_Info.Regions[c0].h;
132.                                    if ((x > xi) && (y > yi) && (x < xf) && (y < yf)) return c0;
133.                            }
134.                            return MSG_NULL;
135.                    }
136. //+------------------------------------------------------------------+
137.            template <typename T >
138.            void CreateObjectEditable(eObjectsIDE arg, T value)
139.                    {
140.                            long id = GetInfoTerminal().ID;
141.                            ObjectDelete(id, m_Info.szObj_Editable);
142.                            CreateObjectGraphics(m_Info.szObj_Editable, OBJ_EDIT, clrBlack, 0);
143.                            ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_XDISTANCE, m_Info.Regions[arg].x + m_Info.x + 3);
144.                            ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_YDISTANCE, m_Info.Regions[arg].y + m_Info.y + 3);
145.                            ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_XSIZE, m_Info.Regions[arg].w);
146.                            ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_YSIZE, m_Info.Regions[arg].h);
147.                            ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_BGCOLOR, m_Info.Regions[arg].bgcolor);
148.                            ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_ALIGN, ALIGN_CENTER);
149.                            ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_FONTSIZE, m_Info.Regions[arg].FontSize - 1);
150.                            ObjectSetString(id, m_Info.szObj_Editable, OBJPROP_FONT, m_Info.Regions[arg].FontName);
151.                            ObjectSetString(id, m_Info.szObj_Editable, OBJPROP_TEXT, (string)value);
152.                            ChartRedraw();
153.                    }
154. //+------------------------------------------------------------------+
155.            bool RestoreState(void)
156.                    {
157.                            uCast_Double info;
158.                            bool bRet;
159.                            
160.                            if (bRet = GlobalVariableGet(macro_NameGlobalVariable("P"), info.dValue))
161.                            {
162.                                    m_Info.x = info._int[0];
163.                                    m_Info.y = info._int[1];
164.                            }
165.                            if (bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("M"), info.dValue) : bRet))
166.                            {
167.                                    m_Info.minx = info._int[0];
168.                                    m_Info.miny = info._int[1];
169.                            }
170.                            if (bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("B"), info.dValue) : bRet))
171.                            {
172.                                    m_Info.IsDayTrade = info._char[0];
173.                                    m_Info.IsMaximized = info._char[1];
174.                            }
175.                            if (bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("L"), info.dValue) : bRet))
176.                                    m_Info.Leverage = info._int[0];
177.                            bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("T"), m_Info.FinanceTake) : bRet);
178.                            bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("S"), m_Info.FinanceStop) : bRet);
179.                            
180.                            GlobalVariablesDeleteAll(macro_NameGlobalVariable(""));
181.                            
182.                            return bRet;
183.                    }
184. //+------------------------------------------------------------------+
185.    public  :
186. //+------------------------------------------------------------------+
187.            C_ChartFloatingRAD(string szShortName, C_Mouse *MousePtr, const int Leverage, const double FinanceTake, const double FinanceStop)
188.                    :C_Terminal()
189.                    {
190.                            if (!IndicatorCheckPass(szShortName)) SetUserError(C_Terminal::ERR_Unknown);
191.                            m_Mouse = MousePtr;
192.                            if (!RestoreState())
193.                            {
194.                                    m_Info.Leverage = Leverage;
195.                                    m_Info.FinanceTake = FinanceTake;
196.                                    m_Info.FinanceStop = FinanceStop;
197.                                    m_Info.IsDayTrade = true;
198.                                    m_Info.IsMaximized = true;
199.                                    m_Info.minx = m_Info.x = 115;
200.                                    m_Info.miny = m_Info.y = 64;
201.                            }
202.                            CreateWindowRAD(170, 210);
203.                            AdjustTemplate(true);
204.                    }
205. //+------------------------------------------------------------------+
206.            ~C_ChartFloatingRAD()
207.                    {
208.                            ObjectsDeleteAll(GetInfoTerminal().ID, m_Info.szObj_Chart);
209.                            FileDelete(m_Info.szFileNameTemplate);
210.                                                            
211.                            delete m_Mouse;
212.                    }
213. //+------------------------------------------------------------------+
214.            void SaveState(void)
215.                    {
216. #define macro_GlobalVariable(A, B) if (GlobalVariableTemp(A)) GlobalVariableSet(A, B);
217.                            
218.                            uCast_Double info;
219.                            
220.                            info._int[0] = m_Info.x;
221.                            info._int[1] = m_Info.y;
222.                            macro_GlobalVariable(macro_NameGlobalVariable("P"), info.dValue);
223.                            info._int[0] = m_Info.minx;
224.                            info._int[1] = m_Info.miny;
225.                            macro_GlobalVariable(macro_NameGlobalVariable("M"), info.dValue);
226.                            info._char[0] = m_Info.IsDayTrade;
227.                            info._char[1] = m_Info.IsMaximized;
228.                            macro_GlobalVariable(macro_NameGlobalVariable("B"), info.dValue);
229.                            info._int[0] = m_Info.Leverage;
230.                            macro_GlobalVariable(macro_NameGlobalVariable("L"), info.dValue);
231.                            macro_GlobalVariable(macro_NameGlobalVariable("T"), m_Info.FinanceTake);
232.                            macro_GlobalVariable(macro_NameGlobalVariable("S"), m_Info.FinanceStop);
233.                            
234. #undef macro_GlobalVariable
235.                    }
236. //+------------------------------------------------------------------+
237.            void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
238.                    {
239. #define macro_AdjustMinX(A, B) {                             \
240.              B = (A + m_Info.Regions[MSG_TITLE_IDE].w) > x;  \
241.              mx = x - m_Info.Regions[MSG_TITLE_IDE].w;       \
242.              A = (B ? (mx > 0 ? mx : 0) : A);                \
243.                                }
244. #define macro_AdjustMinY(A, B) {                             \
245.              B = (A + m_Info.Regions[MSG_TITLE_IDE].h) > y;  \
246.              my = y - m_Info.Regions[MSG_TITLE_IDE].h;       \
247.              A = (B ? (my > 0 ? my : 0) : A);                \
248.                                }
249.                                                                            
250.                            static int sx = -1, sy = -1;
251.                            int x, y, mx, my;
252.                            static eObjectsIDE obj = MSG_NULL;
253.                            double dvalue;
254.                            bool b1, b2, b3, b4;
255.    
256.                            switch (id)
257.                            {
258.                                    case CHARTEVENT_CHART_CHANGE:
259.                                            x = (int)ChartGetInteger(GetInfoTerminal().ID, CHART_WIDTH_IN_PIXELS);
260.                                            y = (int)ChartGetInteger(GetInfoTerminal().ID, CHART_HEIGHT_IN_PIXELS);
261.                                            macro_AdjustMinX(m_Info.x, b1);
262.                                            macro_AdjustMinY(m_Info.y, b2);
263.                                            macro_AdjustMinX(m_Info.minx, b3);
264.                                            macro_AdjustMinY(m_Info.miny, b4);
265.                                            if (b1 || b2 || b3 || b4) AdjustTemplate();
266.                                            break;
267.                                    case CHARTEVENT_MOUSE_MOVE:
268.                                            if ((*m_Mouse).CheckClick(C_Mouse::eClickLeft)) switch (CheckMousePosition(x = (int)lparam, y = (int)dparam))
269.                                            {
270.                                                    case MSG_TITLE_IDE:
271.                                                            if (sx < 0)
272.                                                            {
273.                                                                    ObjectDelete(GetInfoTerminal().ID, m_Info.szObj_Editable);
274.                                                                    ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false);
275.                                                                    sx = x - (m_Info.IsMaximized ? m_Info.x : m_Info.minx);
276.                                                                    sy = y - (m_Info.IsMaximized ? m_Info.y : m_Info.miny);
277.                                                            }
278.                                                            if ((mx = x - sx) > 0) ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, mx);
279.                                                            if ((my = y - sy) > 0) ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, my);
280.                                                            if (m_Info.IsMaximized)
281.                                                            {
282.                                                                    m_Info.x = (mx > 0 ? mx : m_Info.x);
283.                                                                    m_Info.y = (my > 0 ? my : m_Info.y);
284.                                                            }else
285.                                                            {
286.                                                                    m_Info.minx = (mx > 0 ? mx : m_Info.minx);
287.                                                                    m_Info.miny = (my > 0 ? my : m_Info.miny);
288.                                                            }
289.                                                            break;
290.                                            }else if (sx > 0)
291.                                            {
292.                                                    ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, true);                                                
293.                                                    sx = sy = -1;
294.                                            }
295.                                            break;
296.                                    case CHARTEVENT_OBJECT_ENDEDIT:
297.                                            switch (obj)
298.                                            {
299.                                                    case MSG_LEVERAGE_VALUE:
300.                                                    case MSG_TAKE_VALUE:
301.                                                    case MSG_STOP_VALUE:
302.                                                            dvalue = StringToDouble(ObjectGetString(GetInfoTerminal().ID, m_Info.szObj_Editable, OBJPROP_TEXT));
303.                                                            if (obj == MSG_TAKE_VALUE)
304.                                                                    m_Info.FinanceTake = (dvalue <= 0 ? m_Info.FinanceTake : dvalue);
305.                                                            else if (obj == MSG_STOP_VALUE)
306.                                                                    m_Info.FinanceStop = (dvalue <= 0 ? m_Info.FinanceStop : dvalue);
307.                                                            else
308.                                                                    m_Info.Leverage = (dvalue <= 0 ? m_Info.Leverage : (int)MathFloor(dvalue));
309.                                                            AdjustTemplate();
310.                                                            obj = MSG_NULL;
311.                                                            ObjectDelete(GetInfoTerminal().ID, m_Info.szObj_Editable);
312.                                                            break;
313.                                            }
314.                                            break;
315.                                    case CHARTEVENT_OBJECT_CLICK:
316.                                            if (sparam == m_Info.szObj_Chart) switch (obj = CheckMousePosition(x = (int)lparam, y = (int)dparam))
317.                                            {
318.                                                    case MSG_DAY_TRADE:
319.                                                            m_Info.IsDayTrade = (m_Info.IsDayTrade ? false : true);
320.                                                            ObjectDelete(GetInfoTerminal().ID, m_Info.szObj_Editable);
321.                                                            break;
322.                                                    case MSG_MAX_MIN:
323.                                                            m_Info.IsMaximized = (m_Info.IsMaximized ? false : true);
324.                                                            ObjectDelete(GetInfoTerminal().ID, m_Info.szObj_Editable);
325.                                                            break;
326.                                                    case MSG_LEVERAGE_VALUE:
327.                                                            CreateObjectEditable(obj, m_Info.Leverage);
328.                                                            break;
329.                                                    case MSG_TAKE_VALUE:
330.                                                            CreateObjectEditable(obj, m_Info.FinanceTake);
331.                                                            break;
332.                                                    case MSG_STOP_VALUE:
333.                                                            CreateObjectEditable(obj, m_Info.FinanceStop);
334.                                                            break;
335.                                                    case MSG_BUY_MARKET:
336.                                                            ObjectDelete(GetInfoTerminal().ID, m_Info.szObj_Editable);
337.                                                            break;
338.                                                    case MSG_SELL_MARKET:
339.                                                            ObjectDelete(GetInfoTerminal().ID, m_Info.szObj_Editable);
340.                                                            break;
341.                                                    case MSG_CLOSE_POSITION:
342.                                                            ObjectDelete(GetInfoTerminal().ID, m_Info.szObj_Editable);
343.                                                            break;
344.                                            }
345.                                            if (obj != MSG_NULL) AdjustTemplate();
346.                                            break;
347.                            }
348.                    }
349. //+------------------------------------------------------------------+
350. };
351. //+------------------------------------------------------------------+
352. #undef macro_NameGlobalVariable
353. //+------------------------------------------------------------------+
354. 

Quellcode der Klasse C_ChartFloatingRAD

Der Code scheint zwar umfangreich zu sein, aber eigentlich ist es gar nicht so viel, wenn Sie diese Serie verfolgt haben. Der Grund dafür ist, dass sie schrittweise Veränderungen erfährt, die ich versuche, nach und nach einzuführen, eine nach der anderen. So kann ich den Code so demonstrieren und erklären, dass jeder versteht, was vor sich geht.

Das erste, was Ihnen im Klassencode auffallen wird, ist Zeile 8, wo die Makrodefinition für die Erstellung des Namens steht. Er wird verwendet, um den Namen von globalen Terminalvariablen zu definieren. Auf die Verwendung dieser Variablen werden wir in Kürze näher eingehen. Im Moment müssen Sie nur wissen, dass wir ein Makro definieren, das in naher Zukunft verwendet werden wird.

Es gibt einige geringfügige Änderungen im Code, aber da es keinen Sinn hat, darüber zu reden, sollten wir uns auf das Wesentliche konzentrieren. Gehen wir zu Zeile 51, wo wir eine Prozedur haben, die recht häufig verwendet werden wird. Das gab es vorher nicht, aber es ist wichtig für das, was wir tun werden.

Wir werden eine for-Schleife verwenden, um die Anzahl der Zeilen und Deklarationen ein wenig zu reduzieren. Das liegt daran, dass sie sich ziemlich oft wiederholen und die Wahrscheinlichkeit, einen Fehler zu machen, sehr hoch ist. Diese Schleife enthält die if else-Anweisung, die es uns ermöglicht, sowohl zu suchen als auch Dinge zu identifizieren.

Wenn Zeile 54 ausgeführt wird, können wir die Informationen nachschlagen. In diesem Fall legen die Zeilen 56 - 58 fest, nach welchen Parametern wir in der Vorlage suchen werden. Dieser Aspekt wurde bereits im vorherigen Artikel erläutert. Nun werden wir aber nach Eigenschaften von Objekten suchen, die in der Vorlage definiert sind. Solche Eigenschaften sind notwendig, damit die Objekte, die im Indikator erstellt werden, so funktionieren, wie sie in der Vorlage vorgesehen waren.

Im zweiten Fall, wenn wir nicht nach Informationen aus der Vorlage suchen, werden wir solche Werte lokal speichern. Dadurch wird die anschließende Codeausführung erheblich beschleunigt. Diese Daten werden in den Zeilen 62 und 64 gespeichert und können später leicht abgerufen werden, wie Sie bei der Erklärung sehen werden.

Sehen Sie sich als Nächstes Zeile 68 an. Jetzt wird es interessant, denn jetzt gibt es weitere Informationen, die angepasst werden müssen. Zuvor wurde alles, was auf dem Indikator angezeigt wurde, in dem Moment getan, in dem der Nutzer den Indikator auf dem Chart platzierte, und es war keine Aktion erforderlich. Da wir nun aber direkt mit dem Indikator interagieren können, müssen wir sicherstellen, dass die Daten einigermaßen repräsentativ sind.

Aus diesem Grund haben wir ein neues Makro hinzugefügt, das in Zeile 82 zu sehen ist. Allein die Existenz dieses Makros bedeutet, dass die alte Funktion nicht mehr existiert. Abgesehen von diesem Makro werden Sie feststellen, dass der Code einige Änderungen erfahren hat, einschließlich des Erscheinungsbildes von Zeile 90. Hier wird das oben beschriebene Verfahren angewendet. Beachten Sie auch, dass wir den Indikator anweisen, die Parameter festzulegen. Dies geschieht nur einmal, und zwar genau zu dem Zeitpunkt, zu dem der Indikator startet. Einzelheiten: Es gibt noch ein zweites Problem mit diesem Umstand, auf das wir später in diesem Artikel zurückkommen werden.

Danach werden in den Zeilen 92 bis 94 die Werte festgelegt und angepasst, die im Indikator Chart Trade angezeigt werden sollen. Zuvor wurde dies im Klassenkonstruktor erledigt, aber es gab keine Nutzerinteraktion. Jetzt haben wir diese Interaktion, also müssen wir sicherstellen, dass die Werte repräsentativ sind. Wir konfigurieren also die Werte hier zum Zeitpunkt der Aktualisierung der Vorlage.

Es ist wichtig, immer daran zu denken, dass wir die Werte nicht direkt in den Objekten bearbeiten, da nur OBJ_CHART in unserem Chart erscheinen wird. Wir müssen also dafür sorgen, dass die Vorlage aktualisiert und im Chart angezeigt wird. Dazu muss die Aktualisierung genau an dieser Stelle erfolgen.

Der Rest der Zeilen wurde bereits im vorherigen Artikel Entwicklung eines Replay Systems (Teil 44) erklärt: Chart Trade Project (III). In Zeile 105 tun wir nun etwas, das es vorher nicht gab. In dieser Zeile beheben wir einen kleinen Fehler, bei dem es möglich war, das schwebende Fenster durch Anklicken und Ziehen der Maximieren/Minimieren-Schaltfläche zu verschieben. In dieser Zeile wird sie entfernt, und unmittelbar danach, in Zeile 106, erhalten wir die erforderlichen Werte aus der Vorlage. Bitte beachten Sie, dass wir den Aufruf jetzt als falsch melden. Auf diese Weise werden die Werte zur späteren Verwendung an den richtigen Stellen gespeichert.

In Zeile 108 gibt es etwas Interessantes: Wir geben dem schwebenden Fenster die Möglichkeit, zu maximieren oder zu minimieren. Früher wurde dies an anderer Stelle im Code getan, aber aus praktischen Gründen habe ich beschlossen, dieses Steuerelement hier zu platzieren. Dies erleichtert den Modellierungsprozess erheblich, da sich alles, was mit dem Fenster zu tun hat, am selben Ort befindet.

In ähnlicher Weise ermöglichen die Zeilen 109 und 110 ein bequemeres Arbeiten mit dem schwebenden Fenster. Sehr oft möchten Nutzer, dass ein schwebendes Fenster seine Position je nach Zustand ändert. Das heißt, sie befindet sich in einer Position, wenn sie maximiert ist und in einer anderen, wenn sie minimiert ist. Und genau das tun die Zeilen 109 und 110: Sie positionieren das schwebende Fenster an dem Punkt, an dem es sich zuletzt befand, je nachdem, ob es maximiert oder minimiert war.

Die Zeile 112 wurde bereits im vorigen Artikel besprochen. Betrachten wir nun die Zeilen 114 und 115, die zuvor in einer separaten Funktion enthalten waren. In Zeile 114 führen wir also die bereits geänderte Vorlage im Objekt OBJ_CHART aus. Wenn also Zeile 115 ausgeführt wird, wird die Vorlage im Chart angezeigt und aktualisiert. Der Punkt ist, dass nun das gesamte Verfahren in dieser Unterroutine konzentriert ist. Wir müssen uns also keine Gedanken über die Übermittlung zusätzlicher Daten machen, um sicherzustellen, dass die Informationen für den Nutzer korrekt dargestellt werden.

Es ist möglich, aber im Moment noch unwahrscheinlich, dass dieses System in eine eigene Klasse aufgenommen wird. Da sie nur in Chart Trade verwendet wird, lasse ich sie hier stehen. Die Implementierung in einer Klasse könnte interessant sein, weil ich beschlossen habe, andere Dinge in eine Vorlage zu verwandeln. Aber im Moment werde ich den Code so lassen, wie er ist.

Jetzt haben wir etwas ganz anderes. Zeile 137 enthält eine eher ungewöhnliche Art von Code. Diese Art von Code kommt häufig vor, wenn wir dieselben Verfahren haben, aber für verschiedene Typen. Und was bedeutet das? 🤔 Nun, zunächst müssen Sie Folgendes verstehen: Warum ein Unterprogramm für die Anzeige eines Double-Werts, ein anderes für Int-Werte und ein drittes für Strings erstellen? Wäre es nicht viel einfacher, ein einziges Unterprogramm zu erstellen, da der darin enthaltene Code im Grunde immer derselbe wäre? Der einzige Unterschied bestünde darin, dass der Wert in einem Fall von einem Typ und im anderen Fall von einem anderen Typ wäre. Dies ist genau das, was die Linie 137 tut.

Aber Moment mal, wenn es darum geht, den Wert darzustellen, könnten wir ihn dann nicht einfach direkt als String übergeben? Ja, das könnten wir, aber es gibt etwas, das wir nicht bedacht haben. Was ist, wenn der Wert auf eine bestimmte Weise dargestellt und an verschiedenen Stellen im Code aufgerufen werden soll? Denken Sie an die Arbeit, die zu leisten wäre. Aber auf diese Weise können wir den Wert einfach in seinem ursprünglichen Typ übergeben, den Compiler ein Unterprogramm für uns erstellen lassen und es so darstellen, wie wir es wollen. Wenn wir die Ansicht ändern, müssen wir nur einen einzigen Punkt im Code ändern. Der Compiler kümmert sich darum, alles einzurichten. 

Weniger arbeiten und mehr produzieren.

Andernfalls würde der Arbeitsaufwand nur zunehmen. Mein Rat: Wann immer möglich, lassen Sie den Compiler die Arbeit für Sie erledigen. Sie werden feststellen, dass Ihre Codes viel einfacher zu pflegen sind und Ihre Produktivität exponentiell steigt.

Zeile 137 wird in Zeile 138 verwendet. An keiner anderen Stelle nach diesem Punkt wird die Zeile 137 verwendet. In Zeile 151 wird jedoch der als Parameter übergebene Wert verwendet. Beachten Sie, dass ich eine explizite Konvertierung in den Typ String durchführe. Wir können diese Umwandlung während oder nach diesem Schritt durchführen, es macht keinen Unterschied. In diesem speziellen Fall.

Beachten Sie nun, dass wir in dieser Prozedur ein zusätzliches Objekt OBJ_EDIT erstellen. Warum tun wir das? Um die Verwendung des Indikators Chart Trade zu erleichtern. Tatsächlich ist es nicht notwendig, ein solches Objekt zu erstellen. Aber ohne sie wäre der Indikator schwieriger zu nutzen. Der Punkt ist nicht, dass es schwierig ist, die notwendige Logik zu programmieren, sondern dass der Nutzer Schwierigkeiten mit der Bedienung und Verwendung des Indikators haben wird. Aus diesem Grund bitten wir MetaTrader 5 um Hilfe und bitten ihn, ein Bearbeitungsobjekt zu erstellen.

Dieses Objekt muss an der richtigen Stelle, im richtigen Format und Stil erscheinen. Dies geschieht folgendermaßen: Beim Aufruf dieser Prozedur löschen wir das erstellte Bearbeitungsobjekt, falls es existiert. Dies geschieht in Zeile 141. Aber es gibt eine Nuance: dieses Objekt wird nur existieren, wenn es gebraucht wird. In den Zeilen 142 bis 150 werden wir also die Werte verwenden, die in der Vorlage definiert sind. Auf diese Weise wird das erstellte Objekt mit dem in der Vorlage verwendeten Objekt identisch sein.

Es gibt ein Detail, das in den Zeilen 143 und 144 zu finden ist. Dies ist eine kleine Anpassung, bei der wir 3 zu den Abmessungen hinzufügen. Diese Bedeutung ist nicht zufällig, denn OBJ_CHART verwendet 3 Pixel an den Kanten, und das OBJ_EDIT-Objekt muss um genau diese 3 Pixel verschoben werden. Auf diese Weise wird sie genau an der Stelle platziert, an der sich die Vorlage auf der Karte befindet.

Zeile 155 enthält eine Funktion, die uns hilft, die Position des Indikators im Chart zu ändern. Achtung! Diese Funktion funktioniert nicht allein, sondern in Kombination mit einer anderen, die wir später sehen werden. Die Funktion bewirkt Folgendes: Alle sensiblen Indikatordaten werden gespeichert und anschließend wiederhergestellt. Hier stellen wir diese Daten wieder her. Es gibt verschiedene Möglichkeiten, dies zu tun, darunter die hier verwendete. Die Tatsache, dass ich es so mache, liegt daran, dass ich keine DLLs verwenden möchte, es sei denn, es ist wirklich notwendig. Aus diesem Grund verwende ich globale Terminalvariablen, damit MetaTrader 5 bei der Transaktion helfen kann.

Die Zeilen 160, 165, 170, 175, 177 und 178 stellen die in den globalen Variablen des Terminals vorhandenen Daten wieder her. Solche Variablen sind vom Typ double, aber wir können verschiedene Werte in ihnen speichern. Ich habe bereits mehrfach erklärt, wie dies geschieht. Aber hier tun wir es auf eine ganz bestimmte Weise. Wenn also in einer dieser Zeilen auf die globale Terminalvariable nicht zugegriffen werden kann, wird ein falscher Wert an den Aufrufer zurückgegeben. Der einzige Punkt, an dem diese Funktion tatsächlich aufgerufen wird, ist der Konstruktor, und darauf werden wir in Kürze zurückkommen.

Bei jedem Aufruf in den angegebenen Zeilen wird der zuvor gespeicherte Wert wiederhergestellt. Wenn Sie also den Zeitrahmen ändern, können Sie mit dem Chart Trade Indikator weiterarbeiten, als ob es keine Änderungen gäbe. Hier stellt sich eine Frage, die eher persönlich als praktisch ist, aber darüber sprechen wir, wenn ich erkläre, wie man Daten speichert.

Unabhängig davon, ob die Daten erfolgreich gelesen werden konnten oder nicht, entfernen wir in Zeile 180 alle globalen Terminalvariablen, die mit dem Indikator Chart Trade verknüpft sind. Bitte beachten Sie jedoch, dass MetaTrader 5 mehr solcher Variablen haben kann. Um zu wissen, welche zu entfernen sind, verwenden wir ein Makro, das am Anfang des Klassencodes definiert ist.

Gehen wir nun zum Klassenkonstruktor über. Sie beginnt in Zeile 187. Erklärungsbedürftig ist die Interaktion, die in Zeile 192 stattfindet. Sie ruft das oben beschriebene Verfahren auf. Schlägt dies fehl, führen wir die Zeilen 194 - 200 aus, die Standardwerte für den Chart Trade Indikator generieren. Da der Prozess des Entfernens und Neuinstallierens des Indikators aufgrund des Wechsels des Zeitrahmens jedoch sehr schnell abläuft, ist es sehr unwahrscheinlich, dass die voreingestellten Werte verwendet werden. Aber es kann passieren, also ist es hilfreich, darauf vorbereitet zu sein.

Beachten Sie, dass im Gegensatz zu früher die Standardwerte jetzt ohne Anpassungen initialisiert werden. Dies ist darauf zurückzuführen, dass solche Anpassungen nun von dem Verfahren durchgeführt werden, das die Vorlage aktualisiert.

Schauen wir uns nun an, was in Zeile 214 passiert. Hier speichern wir vorübergehend den Status von Chart Trade. Warum tun wir das? Warum speichern wir diesen Zustand in globalen Terminalvariablen? Gibt es keine andere Möglichkeit, dies zu tun? Schauen wir es uns Schritt für Schritt an.

Zunächst einmal: Ja, wir hätten es anders machen können. Im Grunde gibt es mehrere Möglichkeiten. Die Frage ist nicht, wie man speichert, sondern wie man gespeicherte Daten wiederherstellt. Der Grund, warum wir globale Terminalvariablen verwenden, ist, dass sie viel einfacher zugänglich sind. In Anbetracht der Tatsache, dass es in manchen Fällen schwieriger wäre, die Daten wiederherzustellen, als sie zu speichern, habe ich ernsthaft erwogen, die Daten direkt in die Vorlage aufzunehmen. Eigentlich wären sie bereits vorhanden, abgesehen von den Daten, die sich auf die Position beziehen. Denn wir haben eine Positionierung für das maximierte Fenster und eine andere für das minimierte Fenster.

Der Unterschied zwischen der ausgeklappten und der eingeklappten Position erschwert die Verwendung der Vorlage. Wir könnten auch andere Methoden verwenden, aber das würde das System unnötig verkomplizieren und wäre den Aufwand nicht wert. Ich wiederhole: Die Daten sind immer schon in der Vorlage vorhanden. Bei der Ausführung von Zeile 209 wird die Vorlage jedoch gelöscht, wodurch die Daten verschwinden. Selbst wenn Sie keine unterschiedlichen Positionen für das maximierte und das minimierte Fenster verwenden, hätten Sie Probleme in Bezug auf Zeile 209.

Eine Lösung wäre, den Aufruf zum Entfernen der Vorlage in den Quellcode des Indikators aufzunehmen. In diesem Fall würde der Indikatorcode wie folgt aussehen:

43. void OnDeinit(const int reason)
44. {
45.     if (reason != REASON_CHARTCHANGE) (*chart).RemoveTemplate();
46. 
47.     delete chart;
48. }

Diese Funktion RemoveTemplate würde einen Aufruf enthalten, der dem in Zeile 209 des Klassencodes entspricht. Das würde zwar (relativ gut) funktionieren, aber wir hätten andere Probleme. Wenn der Indikator einen schwerwiegenderen Fehler anzeigt, wird die entsprechende Datei nicht gelöscht, sondern verbleibt auf der Festplatte. Wenn Sie versuchen würden, den Indikator erneut auf dem Chart zu platzieren, wären die Daten falsch, was dazu führen könnte, dass der Indikator wieder entfernt wird. Dies wird so lange fortgesetzt, bis die fehlerhafte Datei gelöscht wurde.

Aus diesen und anderen Gründen ziehe ich es vor, globale Terminalvariablen zu verwenden. Aber beachten Sie, dass ich sie nicht direkt verwende. Um die Variablen zu verwenden, verwende ich ein Makro. Warum? Der Grund dafür ist die Lebensdauer der globalen Terminalvariablen.

Sehen Sie sich an, was in dem Makro in Zeile 216 passiert. Beachten Sie, dass wir zunächst versuchen, die Variable als temporäre globale Terminalvariable zu erstellen. Das bedeutet, dass die Variable beim Schließen des MetaTrader 5 Terminals mit diesem zusammen zerstört wird. Auf diese Weise garantieren wir die Integrität des Chart Trade Indikators.

Beachten Sie, dass jede globale Terminalvariable einen Wert speichert. Die Reihenfolge, in der diese Variablen ausgeführt werden, ist nicht wichtig, nur der Name und der Wert sind von Bedeutung. Wir erinnern daran, dass der Name nicht mehr als 64 Zeichen enthalten darf. Aus diesem Grund verwenden wir ein Makro, um einen Namen zu erstellen, was uns einen gewissen Vorteil bei der Erstellung von Namen verschafft.

Bei der Speicherung von Vorlagendaten gibt es nichts Besonderes zu beachten. Ohne diese Funktion müssten Sie sich jedes Mal, wenn sich der Zeitrahmen ändert, um die Neukonfiguration der im Indikator enthaltenen Daten kümmern. Wenn man bedenkt, dass viele Nutzer dazu neigen, den Zeitrahmen während einer Handelsperiode mehrmals zu ändern, wäre es ein großes Problem, die Werte des Chart Trade Indikators ständig anzupassen. Durch die Nutzung der Programmier- und MetaTrader 5-Funktionen können wir das beiseite lassen und uns auf andere Dinge konzentrieren. Dazu verwenden wir das Verfahren in Zeile 214.

Es gibt noch eine andere Möglichkeit, Daten im „Speicher“ zu speichern, aber ich werde jetzt nicht auf Einzelheiten eingehen, da es sich um die Arbeit mit grafischen Objekten handelt. Wir werden ein anderes Mal darüber sprechen.

Wir sind fast fertig mit diesem Artikel. Doch zunächst müssen wir etwas anderes bedenken. Dies ist die Funktion zur Behandlung von Nachrichten. Sie beginnt in Zeile 237 und ist im Gegensatz zu dem, was es scheinen mag, viel einfacher und freundlicher, als viele Leute denken. Sie werden sich jedoch fragen: Warum umfasst diese Funktion zur Behandlung von Nachrichten 4 Arten von Ereignissen, wenn wir eigentlich nur den Mauszeiger verwenden wollen?

Ich möchte noch einmal betonen, dass MetaTrader 5 eine ereignisbasierte Plattform ist. Deshalb müssen Sie wissen, wie Sie in diesem Stil arbeiten können. Im vorigen Artikel habe ich erwähnt, dass wir andere Ereignisse verwenden können, um unsere Logik zu vereinfachen. Obwohl der Code in einigen Aspekten etwas verwirrend ist, ist er dennoch funktional. Wir können jedoch die meisten der im vorigen Artikel besprochenen Prüfungen, die in diesem Code wirklich vorhanden sein sollten, weglassen. Diese Prüfungen werden von MetaTrader 5 durchgeführt. Wenn Sie also beide Klassencodes vergleichen, werden Sie feststellen, dass dieser Code weniger Kontrollen enthält. Warum?

Denn MetaTrader 5 wird sie ausführen. Die Objekt-Klick-Ereignisse in Chart Trade werden nun durch eine Version ersetzt, bei der wir den Objekt-Klick und nicht nur den Mausklick analysieren. Das macht die Codierung viel einfacher. Auf diese Weise können wir mehr Ereignisse in einen besser lesbaren Code aufnehmen. Sie können die Sache mit den Klicks sehen, wenn Sie sich den Code in den Zeilen 315 bis 343 ansehen. In diesen Zeilen werden Klicks auf alle in der Vorlage vorhandenen Objekte behandelt. Alle, auch die, denen noch keine Funktionen zugeordnet sind, wie die Schaltflächen zum Kaufen, Verkaufen und Schließen von Positionen.

Im Message-Handler ist unter anderem das Ereignis CHARTEVENT_CHART_CHANGE in Zeile 258 erwähnenswert. Es gibt ein Detail, bei dem sich die Abmessungen des Terminals ändern. Wenn dies geschieht, löst der MetaTrader 5 ein Ereignis aus und informiert unsere Programme darüber. Dieses Ereignis wird über CHARTEVENT_CHART_CHANGE abgewickelt, sodass wir prüfen können, ob das schwebende Fenster im Chart sichtbar bleibt. Wenn Sie dieses Ereignis nicht behandeln, kann es passieren, dass das Fenster ausgeblendet bleibt, der Indikator aber weiterhin aktiv ist. Da diese Handhabung sowohl im minimierten als auch im maximierten Modus gleich ist, verwende ich ein Makro, um die notwendigen Anpassungen vorzunehmen. Wenn also eine Änderung eintritt, die eine entsprechende Änderung der Fensterposition erfordert, wird dies in Zeile 265 für uns erledigt.

Ein weiteres Ereignis, das ebenfalls erwähnt werden sollte, ist CHARTEVENT_OBJECT_ENDEDIT. In diesem Fall löst MetaTrader 5 ein Ereignis aus, wenn er feststellt, dass das Objekt OBJ_EDIT die Bearbeitung beendet hat. Auf diese Weise können wir Daten direkt in der Vorlage aktualisieren. Dies geschieht in Zeile 309. Aber bitte beachten Sie: Dieses Update passt die Daten gegebenenfalls an. Wenn Sie versuchen, einen Wert oder eine Menge einzugeben, der/die nicht mit dem Vermögenswert übereinstimmt, wird der Code diesen Wert anpassen. Auf diese Weise vermeiden wir künftige Probleme.


Schlussfolgerung

Trotz aller Komplexität, die Chart Trade bei der Erstellung aufweisen kann, ist diese Version im Vergleich zu dem, was wir bisher gesehen haben, wesentlich stabiler und skalierbarer als die alte Version. Das Konzept wurde zwar weitgehend beibehalten, aber wir haben versucht, ein modulareres System zu schaffen. Neben dem realen Markt und dem Demokonto verfügen wir nun über ein System zur Simulation und Nachbildung des Marktes. Dazu muss das System auf eine völlig andere Art und Weise erstellt werden. Wenn dies nicht richtig gemacht wird, werden wir große Probleme haben, mit denselben Instrumenten in so unterschiedlichen Systemen und Märkten zu arbeiten.

Obwohl der Chart Trade-Indikator noch nicht voll funktionsfähig ist, da er keine Funktion der Schaltflächen zum Kaufen, Verkaufen und Schließen von Positionen hat, ist der Kern des Codes bereits korrekt ausgerichtet. Wir werden bald auf diesen Indikator zurückkommen, um diese Schaltflächen zu aktivieren. Derzeit entspricht der Indikator bereits den Erwartungen.

Ich gebe zu, dass sich viele frustriert fühlen, weil es keine Anhänge zu dem Artikel gibt. Aber ich habe meine Gründe. Ich möchte, dass Sie den Code und das System sehen, lesen und verstehen. Ich habe festgestellt, dass viele Leute die Artikel nicht wirklich lesen und nicht verstehen, was sie verwenden. Das ist gefährlich und nicht die beste Art, etwas zu nutzen. Obwohl es nicht offensichtlich ist, ist der gesamte Code veröffentlicht und im Artikel platziert, die Aufgabe besteht nur darin, ihn zu verstehen und ihn in MetaEditor zu bearbeiten. So wird sichergestellt, dass der Code nicht von jemandem verwendet wird, der nicht weiß, worum es geht.


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

Beigefügte Dateien |
Indicators.zip (149.46 KB)
Matrix-Faktorisierung: Die Grundlagen Matrix-Faktorisierung: Die Grundlagen
Da das Ziel hier didaktisch ist, werden wir so einfach wie möglich vorgehen. Das heißt, wir werden nur das implementieren, was wir brauchen: Matrixmultiplikation. Sie werden heute sehen, dass dies ausreicht, um die Matrix-Skalar-Multiplikation zu simulieren. Die größte Schwierigkeit, auf die viele Menschen bei der Implementierung von Code mit Matrixfaktorisierung stoßen, ist folgende: Im Gegensatz zur skalaren Faktorisierung, bei der in fast allen Fällen die Reihenfolge der Faktoren das Ergebnis nicht verändert, ist dies bei der Verwendung von Matrizen nicht der Fall.
Entwicklung eines Replay Systems (Teil 44): Chart Trade Projekt (III) Entwicklung eines Replay Systems (Teil 44): Chart Trade Projekt (III)
Im vorherigen Artikel habe ich erklärt, wie Sie Vorlagedaten zur Verwendung in OBJ_CHART manipulieren können. In diesem Artikel habe ich das Thema nur umrissen, ohne auf Einzelheiten einzugehen, da die Arbeit in dieser Version sehr vereinfacht war. Dies geschah, um die Erklärung des Inhalts zu erleichtern, denn trotz der scheinbaren Einfachheit vieler Dinge waren einige davon nicht so offensichtlich, und ohne das Verständnis des einfachsten und grundlegendsten Teils wäre man nicht in der Lage, das gesamte Bild wirklich zu verstehen.
DoEasy. Dienstfunktionen (Teil 2): Das Muster der „Inside-Bar“ DoEasy. Dienstfunktionen (Teil 2): Das Muster der „Inside-Bar“
In diesem Artikel werden wir uns weiter mit den Preismustern in der DoEasy-Bibliothek beschäftigen. Wir werden auch die Klasse für das Muster der „Inside-Bar“ der Price Action Formationen erstellen.
Entwicklung eines Expert Advisors (EA) auf Basis der Consolidation Range Breakout Strategie in MQL5 Entwicklung eines Expert Advisors (EA) auf Basis der Consolidation Range Breakout Strategie in MQL5
Dieser Artikel beschreibt die Schritte zur Erstellung eines Expert Advisors (EA), der Kursausbrüche nach Konsolidierungsphasen ausnutzt. Durch die Identifizierung von Konsolidierungsbereichen und die Festlegung von Ausbruchsniveaus können Händler ihre Handelsentscheidungen auf der Grundlage dieser Strategie automatisieren. Der Expert Advisor zielt darauf ab, klare Einstiegs- und Ausstiegspunkte zu bieten und gleichzeitig falsche Ausbrüche zu vermeiden.