Русский Español Português
preview
Developing a Replay System (Part 43): Chart Trader Project (II)

Developing a Replay System (Part 43): Chart Trader Project (II)

MetaTrader 5Examples | 5 August 2024, 11:38
260 0
Daniel Jose
Daniel Jose

Introduction

In the previous article Developing a Replay System (Part 42): Chart Trader Project (I), I showed how you can arrange interaction between the mouse indicator and other indicators.

We began writing code to ensure that the Chart Trade indicator exists in perfect harmony with the mouse indicator. However, unlike what was done in the first versions of this Chart Trade indicator, described in the articles:

here we will be doing something more advanced and therefore different. But in any case, the result will be the same as in video 01. I suggest you watch this video before you start reading the article so that you have an idea of what exactly we will be doing. This is not something that can be understood just by reading the code. They say an image is worth a thousand words, so watch the video to better understand what will be explained in the article.


Video 01 - Demo video

The video shows that data is displayed in the Chart Trade window. You may have noticed that we do everything exactly as shown in the previous article, but the information is updated without actually using the objects. And you're probably wondering: how is this possible?

"This guy must be running some kind of trick. I've never seen anyone do things like this. This doesn't make any sense..." Others probably think that I am some kind of sorcerer or magician, with powers beyond the imagination. No. Nothing like this. I simply use both the MetaTrader 5 platform and the MQL5 language at a level that many people do not strive to understand. They always continue to say and do the same thing, without exploring the real potential and capabilities of either the MQL5 language or the MetaTrader 5 platform.

I hope everyone watched the video. Because in this article I'll show you how to do something that will fundamentally change the way you think about what's possible and what's impossible. Important: I will only explain what is shown in the video. The things not shown in the video will be discussed later.


Updating the indicator code

The changes that need to be made will not be that big. But we will still move forward gradually, otherwise everyone will be left without a clear understanding of what is happening.

Let's start by looking at the changes made to the indicator code. The changes are shown in the code below.

Chart Trade indicator source code:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Base version for Chart Trade (DEMO version)"
04. #property version   "1.43"
05. #property icon "/Images/Market Replay/Icons/Indicators.ico"
06. #property link "https://www.mql5.com/es/articles/11664"
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. int OnInit()
19. {
20.     chart = new C_ChartFloatingRAD("Indicator Chart Trade", new C_Mouse("Indicator Mouse Study"), user01, user02, user03);
21.     if (_LastError != ERR_SUCCESS)
22.     {
23.             Print("Error number:", _LastError);
24.             return INIT_FAILED;
25.     }
26.     
27.     return INIT_SUCCEEDED;
28. }
29. //+------------------------------------------------------------------+
30. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
31. {
32.     return rates_total;
33. }
34. //+------------------------------------------------------------------+
35. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
36. {
37.     (*chart).DispatchMessage(id, lparam, dparam, sparam);
38.     
39.     ChartRedraw();
40. }
41. //+------------------------------------------------------------------+
42. void OnDeinit(const int reason)
43. {
44.     delete chart;
45.     
46.     ChartRedraw();
47. }
48. //+------------------------------------------------------------------+

If you compare it with the source code of the indicator, which was given in the article Developing a Replay System (Part 42): Chart Trader Project (I), you can see that it has undergone some changes. We have added a way to allow the user to specify the value that will initially be placed in the indicator. Although we have this form of interaction between lines 14 and 16, these points are not entirely necessary, although they are interesting for testing. Remember that Chart Trade is a system of interaction with the user.

Instead of lines 14 to 16, you can simply enter the default value into the indicator. This can be done on line 20, where instead of using values obtained from user interaction, we could put the values directly into the call. Thus, we will have Chart Trade with default values that can be changed by the user after the indicator appears on the chart.

In fact, this article will not cover that. The reason is that we will use a slightly different process to do this. But as you can see in the demo video, the values reported by the user are transferred to Chart Trade and displayed clearly. As already mentioned, the presence of such interaction is interesting for testing purposes.

We have seen that the indicator is capable of establishing communication. Now, let's figure out how to make changes reflected in the indicator, as shown in the video, albeit without actually using objects. The only object present on the graph, as seen in the video, is OBJ_CHART. Any ideas how I managed to do this? How did I change data and values using only OBJ_CHART?

If you have no idea how this is possible, you will have to study how the MetaTrader 5 platform and the MQL5 language actually work. To make the explanation clearer, let's start a new topic.


Objects and objectives

Most people who want or dream of learning to program don't actually have a clue what they're doing. Their activity consists of trying to create things in a certain way. However, programming is not about tailoring suitable solutions Doing it this way can create more problems than solutions.

Perhaps this is not entirely clear. Well, I will try to convey a little of my many years of programming experience in various languages, platforms and systems.

Whenever we start using a system, whatever it may be, the first thing we should do is evaluate its capabilities, understand what the system offers us. This is in general terms. That is, we must try to understand why everything was created this way and not otherwise. Having understood how the most basic functions work, you can move on and begin to delve deeper.

Going deeper is not looking for ways to improve these functions or simply programming with them. The depth lies in trying to use those resources that have not yet been explored by others. Many people limit themselves to using only what everyone else usually uses, and that's not a bad thing. But how can you suggest improvements without only superficially familiarizing yourself with the capabilities of the system? This type of thinking makes no sense. It's like a child wanting to suggest a new production method just by looking at a running assembly line. This kind of thing has no future and is doomed to create more problems than solutions.

Perhaps I'm still not being clear enough. When seem MetaTrader 5, some people think they know enough about the platform to say what is possible or impossible to do with it. And then they turn to MQL5, trying to solve some of their issues. This is a mistake. You should not consider MQL5, like any other language, as a magical way to satisfy your needs or desires. MQL5 is not a magic language. This language extends the capabilities of MetaTrader 5. However, it is not capable of making the platform work differently than intended.

The right approach is to take a deep dive into how MetaTrader 5 works and then look for ways to adapt it to your own way of viewing and analyzing the market. As you explore MetaTrader 5, you'll see what you need to do to turn it into a tool that better suits your view of the market. To do this, you will have to use MQL5, which will open the doors of MetaTrader 5 in a way that makes life easier for you or other traders.

With this in mind, we can consider one question. Many users underestimate MetaTrader 5 due to ignorance of the basic details of its operation. One of these details, and not only in MetaTrader 5, is the concept of templates. They allow us to customize, adjust and organize certain things in a simple and practical way. From annotations to simplifying the process of viewing the market in a certain way at a certain moment.

Templates can contain a variety of things, and I've shown before how to explore some of them. In the article Multiple indicators on one chart (Part 03): Developing custom definitions, I showed how different indicators can be placed next to each other, as shown in Figure 01.

Figure 01

Figure 01 – Using several indicators in one subwindow

The concept shown above is only possible using templates. No matter how good a programmer you are and how extensive your knowledge of MQL5 is, you will never be able to achieve the result shown in Figure 01 without understanding how MetaTrader 5 functions. This is because not everything comes down to writing code. Programming only helps create a solution that would otherwise not be possible. However, it should not be the first attempt when you need something new, but rather a tool to achieve the desired result.

Why am I saying this? The reason is exactly what is shown in video 01 at the beginning of this article. No matter how well you can program or understand how MQL5 works, you will not be able to do what is shown in the video without understanding how MetaTrader 5 functions.

An important thing of this story is that when I published the article Multiple indicators on one chart (Part 06): Turning MetaTrader 5 into a RAD system (II), at that time I was not using certain MetaTrader 5 concepts. I was still stuck with some ideas and concepts that eventually turned out to be unsuitable. I'm not saying they were wrong, just less appropriate. There are much better solutions. This is due precisely to what was shown in that article, as well as in the previous one Multiple indicators on one chart (Part 05): Turning MetaTrader 5 into a RAD system (I).

In both cases, we opened the template and tried to work on it. But all this work was nothing more than a mere scratch on the surface, since much of what you see is reprogramming of the same template. This was done in such a way as to emulate the RAD system, which can be implemented by programming in MQL5.

Although this worked, you will notice that in fact the template created as in MetaTrader 5 was later recreated by the indicator itself when the indicator was placed on the chart. Consequently, all objects that existed in the template were recreated by the indicator. In this way, MetaTrader 5 gained access to the objects located there, which allowed it to configure and change the values present in each of them.

However, as time passed, it became clear that the idea could be improved. So, I found a more suitable Chart Trade model, which uses a minimum of objects. Well, we still need to do something more besides what will be shown in this article. However, video 01 shows that there have been changes in the values. At the same time, we only have one object on the screen.

This is exactly what programming allows us to do. Without it, we would be limited to what is available in MetaTrader 5. Through programming, we expand the capabilities of the platform. this is achieved by using what already exists in MetaTrader 5. we create a template with exactly what we need and place it in OBJ_CHART. But without proper programming, it would be impossible to change the values present in the objects inside the template. By using programming correctly, we solve this problem, thereby expanding the capabilities of MetaTrader 5.

To make this clearer, open the template file used in Chart Trade. It is presented in full below.

Chart Trade file (template):

001. <chart>
002. fore=0
003. grid=0
004. volume=0
005. ticker=0
006. ohlc=0
007. one_click=0
008. one_click_btn=0
009. bidline=0
010. askline=0
011. lastline=0
012. descriptions=0
013. tradelines=0
014. tradehistory=0
015. background_color=16777215
016. foreground_color=0
017. barup_color=16777215
018. bardown_color=16777215
019. bullcandle_color=16777215
020. bearcandle_color=16777215
021. chartline_color=16777215
022. volumes_color=16777215
023. grid_color=16777215
024. bidline_color=16777215
025. askline_color=16777215
026. lastline_color=16777215
027. stops_color=16777215
028. windows_total=1
029. 
030. <window>
031. height=100.000000
032. objects=18
033. 
034. <indicator>
035. name=Main
036. path=
037. apply=1
038. show_data=1
039. scale_inherit=0
040. scale_line=0
041. scale_line_percent=50
042. scale_line_value=0.000000
043. scale_fix_min=0
044. scale_fix_min_val=0.000000
045. scale_fix_max=0
046. scale_fix_max_val=0.000000
047. expertmode=0
048. fixed_height=-1
049. </indicator>
050. 
051. <object>
052. type=110
053. name=MSG_NULL_000
054. color=0
055. pos_x=0
056. pos_y=0
057. size_x=170
058. size_y=210
059. bgcolor=16777215
060. refpoint=0
061. border_type=1
062. </object>
063. 
064. <object>
065. type=110
066. name=MSG_NULL_001
067. color=0
068. pos_x=5
069. pos_y=30
070. size_x=152
071. size_y=26
072. bgcolor=12632256
073. refpoint=0
074. border_type=1
075. </object>
076. 
077. <object>
078. type=110
079. name=MSG_NULL_002
080. color=0
081. pos_x=5
082. pos_y=58
083. size_x=152
084. size_y=26
085. bgcolor=15130800
086. refpoint=0
087. border_type=1
088. </object>
089. 
090. <object>
091. type=110
092. name=MSG_NULL_003
093. color=0
094. pos_x=5
095. pos_y=86
096. size_x=152
097. size_y=26
098. bgcolor=10025880
099. refpoint=0
100. border_type=1
101. </object>
102. 
103. <object>
104. type=110
105. name=MSG_NULL_004
106. color=0
107. pos_x=5
108. pos_y=114
109. size_x=152
110. size_y=26
111. bgcolor=8036607
112. refpoint=0
113. border_type=1
114. </object>
115. 
116. <object>
117. type=102
118. name=MSG_NULL_007
119. descr=Lever ( x )
120. color=0
121. style=1
122. angle=0
123. pos_x=10
124. pos_y=63
125. fontsz=16
126. fontnm=System
127. anchorpos=0
128. refpoint=0
129. </object>
130. 
131. <object>
132. type=102
133. name=MSG_NULL_008
134. descr=Take ( $ )
135. color=0
136. style=1
137. angle=0
138. pos_x=10
139. pos_y=91
140. fontsz=16
141. fontnm=System
142. anchorpos=0
143. refpoint=0
144. </object>
145. 
146. <object>
147. type=102
148. name=MSG_NULL_009
149. descr=Stop ( $ )
150. color=0
151. style=1
152. angle=0
153. pos_x=10
154. pos_y=119
155. fontsz=16
156. fontnm=System
157. anchorpos=0
158. refpoint=0
159. </object>
160. 
161. <object>
162. type=107
163. name=MSG_TITLE_IDE
164. descr=Chart Trade
165. color=16777215
166. style=1
167. pos_x=0
168. pos_y=0
169. size_x=164
170. size_y=28
171. bgcolor=16748574
172. fontsz=16
173. fontnm=System
174. refpoint=0
175. readonly=1
176. align=0
177. </object>
178. 
179. <object>
180. type=106
181. name=MSG_BUY_MARKET
182. size_x=70
183. size_y=25
184. offset_x=0
185. offset_y=0
186. pos_x=5
187. pos_y=145
188. bmpfile_on=\Images\Market Replay\Chart Trade\BUY.bmp
189. bmpfile_off=\Images\Market Replay\Chart Trade\BUY.bmp
190. state=0
191. refpoint=0
192. anchorpos=0
193. </object>
194. 
195. <object>
196. type=106
197. name=MSG_SELL_MARKET
198. size_x=70
199. size_y=25
200. offset_x=0
201. offset_y=0
202. pos_x=85
203. pos_y=145
204. bmpfile_on=\Images\Market Replay\Chart Trade\SELL.bmp
205. bmpfile_off=\Images\Market Replay\Chart Trade\SELL.bmp
206. state=0
207. refpoint=0
208. anchorpos=0
209. </object>
210. 
211. <object>
212. type=103
213. name=MSG_CLOSE_POSITION
214. descr=Close Position
215. color=0
216. style=1
217. pos_x=5
218. pos_y=173
219. fontsz=16
220. fontnm=System
221. state=0
222. size_x=152
223. size_y=26
224. bgcolor=1993170
225. frcolor=-1
226. refpoint=0
227. </object>
228. 
229. <object>
230. type=107
231. name=MSG_NAME_SYMBOL
232. descr=?
233. color=0
234. style=1
235. pos_x=7
236. pos_y=34
237. size_x=116
238. size_y=20
239. bgcolor=12632256
240. fontsz=14
241. fontnm=Tahoma
242. refpoint=0
243. readonly=1
244. align=1
245. </object>
246. 
247. <object>
248. type=107
249. name=MSG_LEVERAGE_VALUE
250. descr=?
251. color=0
252. style=1
253. pos_x=80
254. pos_y=61
255. size_x=70
256. size_y=18
257. bgcolor=15130800
258. fontsz=12
259. fontnm=Tahoma
260. refpoint=0
261. readonly=0
262. align=1
263. </object>
264. 
265. <object>
266. type=107
267. name=MSG_TAKE_VALUE
268. descr=?
269. color=0
270. style=1
271. pos_x=80
272. pos_y=91
273. size_x=70
274. size_y=18
275. bgcolor=10025880
276. fontsz=12
277. fontnm=Tahoma
278. refpoint=0
279. readonly=0
280. align=1
281. </object>
282. 
283. <object>
284. type=107
285. name=MSG_STOP_VALUE
286. descr=?
287. color=0
288. style=1
289. pos_x=80
290. pos_y=119
291. size_x=70
292. size_y=18
293. bgcolor=8036607
294. fontsz=12
295. fontnm=Tahoma
296. refpoint=0
297. readonly=0
298. align=1
299. </object>
300. 
301. <object>
302. type=106
303. name=MSG_DAY_TRADE
304. size_x=32
305. size_y=22
306. offset_x=0
307. offset_y=0
308. pos_x=123
309. pos_y=33
310. bmpfile_on=\Images\Market Replay\Chart Trade\DT.bmp
311. bmpfile_off=\Images\Market Replay\Chart Trade\SW.bmp
312. state=0
313. refpoint=0
314. anchorpos=0
315. </object>
316. 
317. <object>
318. type=106
319. name=MSG_MAX_MIN
320. size_x=20
321. size_y=20
322. offset_x=0
323. offset_y=0
324. pos_x=140
325. pos_y=3
326. bmpfile_on=\Images\Market Replay\Chart Trade\Maximize.bmp
327. bmpfile_off=\Images\Market Replay\Chart Trade\Minimize.bmp
328. state=1
329. refpoint=0
330. anchorpos=0
331. </object>
332. 
333. </window>
334. </chart>

I know its content may seem completely unnecessary. Please note THERE WILL BE NO FILES IN THE ATTACHMENT, the entire system will be published in such a way that the files can be obtained by rewriting the codes into the corresponding files. I do this to ensure that you read and understand the article. I don't want you to just download attached files and use the system without knowing what you are doing. While it may seem like this makes the article significantly longer, it actually isn't, it just makes the explanation much more detailed.

Now let's take a closer look at the Chart Trade template file. Pay attention to the lines containing the following:

descr=?

It occurs in several places in the template file, and is done intentionally. Why? Although descr appears in different places, these places, as shown above, mainly refer to type 107 objects. What are objects of type 107?

A description of these types of objects first appeared in the article Multiple indicators on one chart (Part 05): Turning MetaTrader 5 into a RAD (I) system. For convenience, I will provide the table presented in this article below:

The value of the TYPE variable Referenced object
102 OBJ_LABEL
103 OBJ_BUTTON
106 OBJ_BITMAP_LABEL
107  OBJ_EDIT
110  OBJ_RECTANGLE_LABEL

So, object 107 is OBJ_EDIT. These are objects into which the user can enter some information.

But it's not possible to directly access or enter a value into an object that is in a template. It is a fact. How did I solve this problem so that object 107 present in the template can receive values from the indicator? To answer this question, you need to look at the code of the class responsible for using the template.


Updating the C_ChartFloatingRAD class

To make Chart Trade display user-entered values, you need to perform some basic operations immediately after launching the indicator on the chart. These operations are aimed at solving some problems that cannot be solved without the use of programming. For this reason, it is very important to have a good understanding of how MetaTrader 5 works. Without knowing platform operation principles, you will not be able to create the code necessary to overcome such obstacles that cannot be solved without programming.

The complete code for the C_ChartFloatingRAD class can be seen below. This code, in its current form, allows the indicator to work as shown in video 01. Can you understand how this happens?

C_ChartFloatingRAD class source code:

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #include "../Auxiliar/C_Terminal.mqh"
005. #include "../Auxiliar/C_Mouse.mqh"
006. //+------------------------------------------------------------------+
007. class C_ChartFloatingRAD : private C_Terminal
008. {
009.    private :
010.            struct st00
011.            {
012.                    int     x, y, cx, cy;
013.                    string  szObj_Chart,
014.                            szFileNameTemplate;
015.                    long    WinHandle;
016.                    double  FinanceTake,
017.                            FinanceStop;
018.                    int     Leverage;
019.            }m_Info;
020. //+------------------------------------------------------------------+
021.            C_Mouse *m_Mouse;
022. //+------------------------------------------------------------------+
023.            void CreateWindowRAD(int x, int y, int w, int h)
024.                    {
025.                            m_Info.szObj_Chart = (string)ObjectsTotal(GetInfoTerminal().ID);
026.                            ObjectCreate(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJ_CHART, 0, 0, 0);
027.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, m_Info.x = x);
028.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, m_Info.y = y);
029.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XSIZE, w);
030.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YSIZE, h);
031.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_DATE_SCALE, false);
032.                            ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_PRICE_SCALE, false);
033.                            m_Info.WinHandle = ObjectGetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_CHART_ID);
034.                            m_Info.cx = w;
035.                            m_Info.cy = 26;
036.                    };
037. //+------------------------------------------------------------------+
038.            void Level_1(int &fpIn, int &fpOut, const string szFind, const string szWhat, const string szValue)
039.                    {
040.                            string sz0 = "";
041.                            int i0 = 0;
042.                            string res[];
043.                            
044.                            while ((!FileIsEnding(fpIn)) && (sz0 != "</object>"))
045.                            {
046.                                    sz0 = FileReadString(fpIn);
047.                                    if (StringSplit(sz0, '=', res) > 1)
048.                                    {
049.                                            i0 = (res[1] == szFind ? 1 : i0);
050.                                            if ((i0 == 1) && (res[0] == szWhat))
051.                                            {
052.                                                    FileWriteString(fpOut, szWhat + "=" + szValue + "\r\n");
053.                                                    return;
054.                                            }
055.                                    }
056.                                    FileWriteString(fpOut, sz0 + "\r\n");
057.                            };
058.                    }
059. //+------------------------------------------------------------------+
060.            void SwapValueInTemplate(const string szFind, const string szWhat, const string szValue)
061.                    {
062.                            int fpIn, fpOut;
063.                            string sz0;
064.                            
065.                            if (_LastError != ERR_SUCCESS) return;
066.                            if ((fpIn = FileOpen(m_Info.szFileNameTemplate, FILE_READ | FILE_TXT)) == INVALID_HANDLE)
067.                            {
068.                                    SetUserError(C_Terminal::ERR_FileAcess);
069.                                    return;
070.                            }
071.                            if ((fpOut = FileOpen(m_Info.szFileNameTemplate + "_T", FILE_WRITE | FILE_TXT)) == INVALID_HANDLE)
072.                            {
073.                                    FileClose(fpIn);
074.                                    SetUserError(C_Terminal::ERR_FileAcess);
075.                                    return;
076.                            }
077.                            while (!FileIsEnding(fpIn))
078.                            {
079.                                    sz0 = FileReadString(fpIn);
080.                                    FileWriteString(fpOut, sz0 + "\r\n");
081.                                    if (sz0 == "<object>") Level_1(fpIn, fpOut, szFind, szWhat, szValue);
082.                            };
083.                            FileClose(fpIn);
084.                            FileClose(fpOut);
085.                            if (!FileMove(m_Info.szFileNameTemplate + "_T", 0, m_Info.szFileNameTemplate, FILE_REWRITE))
086.                            {
087.                                    FileDelete(m_Info.szFileNameTemplate + "_T");
088.                                    SetUserError(C_Terminal::ERR_FileAcess);
089.                            }
090.                    }
091. //+------------------------------------------------------------------+
092. inline void UpdateChartTemplate(void)
093.                    {
094.                            ChartApplyTemplate(m_Info.WinHandle, "/Files/" + m_Info.szFileNameTemplate);
095.                            ChartRedraw(m_Info.WinHandle);
096.                    }
097. //+------------------------------------------------------------------+
098. inline double PointsToFinance(const double Points)
099.                    {                               
100.                            return Points * (GetInfoTerminal().VolumeMinimal + (GetInfoTerminal().VolumeMinimal * (m_Info.Leverage - 1))) * GetInfoTerminal().AdjustToTrade;
101.                    };
102. //+------------------------------------------------------------------+
103.    public  :
104. //+------------------------------------------------------------------+
105.            C_ChartFloatingRAD(string szShortName, C_Mouse *MousePtr, const int Leverage, const double FinanceTake, const double FinanceStop)
106.                    :C_Terminal()
107.                    {
108.                            m_Mouse = MousePtr;
109.                            m_Info.Leverage = (Leverage < 0 ? 1 : Leverage);
110.                            m_Info.FinanceTake = PointsToFinance(FinanceToPoints(MathAbs(FinanceTake), m_Info.Leverage));
111.                            m_Info.FinanceStop = PointsToFinance(FinanceToPoints(MathAbs(FinanceStop), m_Info.Leverage));
112.                            if (!IndicatorCheckPass(szShortName)) SetUserError(C_Terminal::ERR_Unknown);
113.                            m_Info.szFileNameTemplate = StringFormat("Chart Trade/%u.tpl", GetInfoTerminal().ID);
114.                            if (!FileCopy("Chart Trade/IDE_RAD.tpl", 0, m_Info.szFileNameTemplate, FILE_REWRITE)) SetUserError(C_Terminal::ERR_FileAcess);
115.                            if (_LastError != ERR_SUCCESS) return;
116.                            SwapValueInTemplate("MSG_NAME_SYMBOL", "descr", GetInfoTerminal().szSymbol);
117.                            SwapValueInTemplate("MSG_LEVERAGE_VALUE", "descr", (string)m_Info.Leverage);
118.                            SwapValueInTemplate("MSG_TAKE_VALUE", "descr", (string)m_Info.FinanceTake);
119.                            SwapValueInTemplate("MSG_STOP_VALUE", "descr", (string)m_Info.FinanceStop);
120.                            if (_LastError != ERR_SUCCESS) return;
121.                            CreateWindowRAD(0, 0, 170, 210);
122.                            UpdateChartTemplate();
123.                    }
124. //+------------------------------------------------------------------+
125.            ~C_ChartFloatingRAD()
126.                    {
127.                            ObjectDelete(GetInfoTerminal().ID, m_Info.szObj_Chart);
128.                            FileDelete(m_Info.szFileNameTemplate);
129.                            
130.                            delete m_Mouse;
131.                    }
132. //+------------------------------------------------------------------+
133.            void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
134.                    {
135.                            static int sx = -1, sy = -1;
136.                            int x, y, mx, my;
137.    
138.                            switch (id)
139.                            {
140.                                    case CHARTEVENT_MOUSE_MOVE:
141.                                            if ((*m_Mouse).CheckClick(C_Mouse::eClickLeft))
142.                                            {
143.                                                    x = (int)lparam;
144.                                                    y = (int)dparam;
145.                                                    if ((x > m_Info.x) && (x < (m_Info.x + m_Info.cx)) && (y > m_Info.y) && (y < (m_Info.y + m_Info.cy)))
146.                                                    {
147.                                                            if (sx < 0)
148.                                                            {
149.                                                                    ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false);
150.                                                                    sx = x - m_Info.x;
151.                                                                    sy = y - m_Info.y;
152.                                                            }
153.                                                            if ((mx = x - sx) > 0) ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, m_Info.x = mx);
154.                                                            if ((my = y - sy) > 0) ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, m_Info.y = my);
155.                                                    }
156.                                            }else if (sx > 0)
157.                                            {
158.                                                    ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, true);                                                
159.                                                    sx = sy = -1;
160.                                            }
161.                                            break;
162.                            }
163.                    }
164. //+------------------------------------------------------------------+
165. };
166. //+------------------------------------------------------------------+

Please note that the C_ChartFloatingRAD file has received virtually no significant additions since the previous article. This is intentional. If I showed the final version of this file, you would not be able to understand how and why MetaTrader 5 manages to modify the values in the template. This is done so that when opening the object list window with CTRL+B, you only see OBJ_CHART in the list, but the values and window would still be changed.

Now let's try to understand how and why MetaTrader 5 can inform us about what is happening through a template. Remember this point: we do not stop using the template, and it will be applied to the OBJ_CHART object. This happens when line 94 is executed and line 95 tells MetaTrader 5 to update OBJ_CHART. If you do not consider this fact, you can spend a long time looking for something in the code that is not there. For example, for the things that are actually in the template file.

The added code can be seen between lines 38 and 123. It is structured in such a way that the further steps that will be performed in the next article will not require a lot of changes, which is very good. So, pay attention to the explanations from this article and you will understand the next one very easily. You might even be able to predict what will be done in the next article from a programming perspective.

Let's start with the class constructor, as this makes the other parts much easier to understand. This constructor starts on line 105. But the real change starts on line 109. In this line, we guarantee that the leverage value will always be greater than or equal to 1. For this, we use the ternary operator. So, there is nothing particularly complicated or confusing here.

Now let's move on to line 110. This line, like line 111, implements an adjustment to the value displayed in the Chart Trade window. The reason for this is that the user may enter a value that does is not valid for the asset on which the Chart Trade indicator is running. For example, in the case of dollar futures, movements are always between R$5.00 and R$5.00 per contract. In this case, specifying take profit or stop loss as a value that is not a multiple of 5, for example, take profit=R$76.00, does not make sense, since this value will never be reached.

So, lines 110 and 111 make two calls. The first one converts the financial value into points, and the second one does the opposite, converting the point value into a financial value. You might think that this returns the value to its original value. This is true, but here mathematical methods will be used to convert and adjust the values. The first call will use the function present in the C_Terminal class. In the second one, we execute the function present in line 98.

This function at 98 uses only one line. Line 100 actually performs a calculation that converts the given number of pips into a financial value.

This was the easy part. Now let's look at the most difficult part of the current system.

Once the constructor reaches line 113, we get something very interesting. This line 113 will create the name of the temporary file. Remember, this file will be temporary. It will be present in the area defined in MQL5\Files, along with other information created specifically on this line 113.

Once we have the filename created on line 113, we move on to line 114. In this line, we will completely copy the contents of the template file (which can be seen in the previous topic) under a new name. If we succeed, we will continue further. But if copying fails, we will report this to the caller.

The real magic happens between lines 116 and 119. Here we make the Chart Trade indicator receive values provided by MetaTrader 5 and/or the user. These lines call line 60 of the class code. From now on, we will work on this part of the code as the rest of the constructor was explained in the previous article. But before we finally move on to line 60, let me draw your attention to another line that was added to the code: line 128. It deletes the file created in the constructor. That's why I emphasized that the file created is temporary.

Let's move on to line 60. I need to repeat something here (I'm still explaining the basics, so be patient). The first step is to open the "original" file (note the quotes in the word), this is done on line 66. If we succeed, we will continue. If we fail, we will return to the caller.

On line 71, we will create a temporary file from a temporary file (sounds strange, but there's no other way to say it). If this fails, we will close the open file and return to the caller. Until line 77, all we did was open one file and create another. If execution reaches line 77, we will enter a loop to copy the entire file.

Wait, copying the entire file? Again? Yes, but this time we'll test one condition on line 81. This condition will check whether an object in the template file was found during the copy process. When this happens, we will move to line 38, where we will deal with the found object. In any case, if the pattern being analyzed is a pattern from the previous topic, we will jump to line 38. So, even if you want to use your own template, you can do so as long as you define the names used for the objects correctly.

After calling the function presented on line 38, we will move until execution reaches line 44. Here we will continue the process of copying the file in the same way as we did earlier. However, when the line that closes the object is found on this very line 44, we will return to the calling object, that is, line 81. Let's stop and take a moment to see the function that appears on line 38.

During the copying process, we will read the source file at line 46. After that, we will expand the contents of this line. If line 47, which performs this decomposition, reports that we have two instructions available, a new execution thread will be generated. Otherwise, the read line will be written, and this happens on line 56.

Now pay attention to the following point: during the decomposition performed on line 47, the i0 variable has the initial value of 0. Pay special attention to this. Once the object name is found, the i0 variable will be set to 1. This is where the danger lies. If you manually edit a template file, you must ensure that the object name appears before any of its parameters. The only parameter that can appear before the name is the type of the object. No other parameters should come before the name. If this happens, the entire process will fail.

On line 50, we check if i0 indicates that the desired object has been found. In this case, the value of this variable is 1. But we have a second condition, which concerns the parameter we are looking for. In this case, we will always search for descr. If these two conditions occur, we write the desired value during the copy process. This type of modification occurs on line 52. After that, we return to the caller, that is, line 81.

Watch how this process happens. We copy the entire file, except for one specific line. It is this line that will be changed, as a result of which new data will appear in the template or it will take on a different appearance.

When the entire file has been copied and modified, we will close both files, which is done on lines 83 and 84. After that, on line 85, we will try to rename the temporary file to the file that the class expects to use. The operation will be exactly the same as shown in video 01.


Conclusion

In this material, I explained the first steps that you need to follow in order to be able to manage the template. This way it adapts to what we need. This will allow us to better use the capabilities of MetaTrader 5 using fairly simple programming. However, the important thing is not to use more or fewer objects on the chart. What's really important, is to understand that MQL5 allows everyone to turn MetaTrader 5 into a platform suitable for their needs, and not to create a different competing platform.


Translated from Portuguese by MetaQuotes Ltd.
Original article: https://www.mql5.com/pt/articles/11664

Attached files |
Anexo.zip (420.65 KB)
Features of Custom Indicators Creation Features of Custom Indicators Creation
Creation of Custom Indicators in the MetaTrader trading system has a number of features.
Integrating MQL5 with data processing packages (Part 1): Advanced Data analysis and Statistical Processing Integrating MQL5 with data processing packages (Part 1): Advanced Data analysis and Statistical Processing
Integration enables seamless workflow where raw financial data from MQL5 can be imported into data processing packages like Jupyter Lab for advanced analysis including statistical testing.
Features of Experts Advisors Features of Experts Advisors
Creation of expert advisors in the MetaTrader trading system has a number of features.
Build Self Optimizing Expert Advisors With MQL5 And Python (Part II): Tuning Deep Neural Networks Build Self Optimizing Expert Advisors With MQL5 And Python (Part II): Tuning Deep Neural Networks
Machine learning models come with various adjustable parameters. In this series of articles, we will explore how to customize your AI models to fit your specific market using the SciPy library.