Português
preview
Desarrollo de un sistema de repetición (Parte 43): Proyecto Chart Trade (II)

Desarrollo de un sistema de repetición (Parte 43): Proyecto Chart Trade (II)

MetaTrader 5Ejemplos | 16 julio 2024, 16:02
18 0
Daniel Jose
Daniel Jose

Introducción

En el artículo anterior Desarrollo de un sistema de repetición (Parte 42): Proyecto del Chart Trade (I), mostré cómo podemos empezar a tener alguna interacción entre el indicador mouse y otros indicadores.

Allí di inicio a la codificación, que se realizará con el fin de lograr que el indicador Chart Trade pueda ser creado y mantenido en perfecta armonía con el indicador mouse. Sin embargo, a diferencia de lo que se hizo en las primeras versiones de este indicador Chart Trade, eso allá en los artículos:

Aquí haremos algo un poco más avanzado, y por consecuencia diferente. Pero de todas maneras el resultado será el que se ve en el video 01. Sugiero que veas el video, antes incluso de leer el artículo. Esto para que tengas una noción de lo que se hará aquí. No es algo que solo leyendo el código vayas a comprender. Dicen que una imagen vale más que mil palabras. Entonces mira el video para comprender mejor lo que se explicará en el artículo.


Video 01 - Video de demostración sobre este artículo.

En el video, puedes ver que estamos informando los datos a ser visualizados en la ventana Chart Trade. Debes haber notado que estamos haciendo las cosas exactamente como se vio en el artículo anterior. Pero aun así, la información se está actualizando sin que realmente estemos usando objetos para ello. Seguro te estarás preguntando: ¿Cómo es esto posible?

Este tipo debe estar haciendo algún tipo de trampa. Nunca vi a nadie haciendo este tipo de cosas. Esto no tiene sentido alguno. Otros deben estar pensando que soy algún tipo de brujo, o místico. Con capacidades más allá de la imaginación. No. No es nada de eso. Lo que estoy haciendo es usar tanto la plataforma MetaTrader 5, así como el lenguaje MQL5, a un nivel que muchos no buscan realmente comprender. Simplemente se quedan hablando y haciendo siempre las mismas cosas. No exploran el verdadero potencial y capacidades. Tanto del lenguaje MQL5, como de la plataforma MetaTrader 5.

Espero que hayas visto el video. Pues aquí mostraré cómo hacer algo que podrá cambiar tu noción de lo que realmente se puede hacer. Una observación: Explicaré solo y únicamente lo que se muestra en el video. Las cosas que no se muestran en él se verán más adelante.


Actualización del código del indicador

Los cambios que es necesario hacer no serán tan grandes. Pero aun así iré despacio. De lo contrario, todos quedarán sin comprender lo que está sucediendo.

Empecemos viendo las actualizaciones hechas en el código del indicador. Estas pueden verse en el código que se muestra íntegramente a continuación:

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. //+------------------------------------------------------------------+

Código fuente del Indicador Chart Trade

Si observas el código fuente del indicador que se puede ver en el artículo Desarrollando un sistema de repetición (Parte 42): Proyecto Chart Trade (I). Notarás que este código ha sufrido algunas pequeñas actualizaciones. Estas son, básicamente, la adición de medios para que el usuario pueda informar el valor a ser colocado inicialmente en el indicador. Aunque entre las líneas 14 y 16 tengamos esta forma de interacción, estos puntos no son del todo necesarios. A pesar de ser interesante tenerlos para fines de pruebas. Recuerda que el Chart Trade es un sistema de interacción con el usuario del sistema.

Puedes, en lugar de tener las líneas 14 a 16, simplemente introducir un valor "predeterminado" o default en el indicador. Esto se haría en la línea 20. Donde, en lugar de usar los valores informados por la interacción con el usuario, podríamos colocar los valores directamente en la llamada. Así tendríamos un Chart Trade con valores "predeterminados", y una vez que esté en el gráfico, el usuario podría modificar tales valores.

De hecho, esta edición no sucederá en este artículo. El motivo es que para hacerlo usaremos un proceso ligeramente diferente. Pero como puedes ver en el video de demostración, los valores informados por el usuario se transfieren dentro del Chart Trade y se muestran claramente. Como mencioné, es interesante tener esta interacción para fines de prueba.

Ahora que sabemos que el indicador puede realmente establecer una comunicación, vamos a entender cómo es posible hacer que los cambios se reflejen en el indicador, como se demostró en el vídeo, aunque en realidad no estemos utilizando objetos para ello. El único objeto presente en el gráfico, como queda claro en el video, es el OBJ_CHART. Entonces, ¿tienes alguna idea de cómo logré hacer tal cosa? ¿Cómo cambié los datos y valores usando solo y únicamente el OBJ_CHART?

Si no tienes la menor idea de cómo es esto posible, entonces aprenderemos cómo funcionan realmente la plataforma MetaTrader 5 y el lenguaje MQL5. Pero para que la explicación sea más clara, crearé un nuevo tema.


Objetos y Objetos

Gran parte de las personas que quieren, o desean aprender a programar, no tienen en realidad idea de lo que están haciendo. Lo que hacen es intentar crear las cosas de una determinada manera. Sin embargo, cuando programamos no estamos realmente intentando crear una solución. Si intentas hacerlo de esta manera, generarás más problemas que soluciones.

Tal vez esto no haya quedado claro. Pero intentaré transmitir un poco de mi experiencia de años de programación, en diversos tipos de lenguajes, plataformas y sistemas.

Siempre que comenzamos a usar un sistema, sea cual sea, la primera cosa que de hecho debemos intentar hacer, es conocer lo que el sistema nos ofrece. Esto en términos básicos. Es decir, tienes que intentar comprender por qué fue creado de esa manera y no de otra forma. Después de saber cómo funcionan las funcionalidades más básicas, ahí sí, puedes empezar a profundizar en el mismo.

Esta profundización no se da comenzando a buscar formas de mejorar o programar algo en él. En realidad, esta profundización se da intentando usar recursos poco explorados naturalmente por otros. Muchas personas se limitan a usar solo lo que todos usan normalmente. Esto no está mal. Pero, ¿cómo puedes querer proponer mejoras en algo, si solo conoces superficialmente lo que se puede hacer en ese sistema? Este tipo de pensamiento no tiene sentido. Es como un niño queriendo proponer un nuevo método de producción solo mirando una cinta transportadora en funcionamiento. Este tipo de cosa no tiene futuro y estará destinado a generar más problemas que soluciones.

Tal vez no hayas logrado comprender la idea. Algunas personas ven MetaTrader 5 y ya creen saber lo suficiente sobre la plataforma como para decir que es o no posible hacer cosas en ella. Y luego van a MQL5 intentando solucionar algunas cuestiones. Esto es un error. No debes mirar MQL5, así como cualquier otro lenguaje, como una solución mágica a tus deseos o necesidades. El MQL5 no es, y repetiré, NO es un lenguaje mágico. Es un lenguaje que amplía lo que podemos hacer en MetaTrader 5. No fue construido de manera que haga funcionar MetaTrader 5 de forma diferente a lo que fue diseñado.

Lo correcto es comprender profundamente cómo funciona MetaTrader 5, para solo después buscar formas de adaptarlo a tu manera de ver y analizar el mercado. Cuando comprendas esto, verás qué es necesario hacer para convertir MetaTrader 5 en una herramienta más adecuada a tu forma de ver el mercado. Para hacer esto, usarás MQL5, que abrirá las puertas del MetaTrader 5, de modo que te facilite la vida a ti o a otros operadores.

Teniendo esto en mente, podemos abordar una cuestión. Muchos usuarios desprecian MetaTrader 5 por no conocer detalles básicos de su funcionamiento. Uno de estos detalles, y no solo del MetaTrader 5, pero aquí me enfocaré en él, es el concepto de templates, o plantillas. Estos se usan como forma de permitirnos configurar, ajustar y organizar de manera práctica y sencilla ciertas cosas. Estas cosas van desde anotaciones, llegando en algunos momentos a hacer más simple que mires el mercado de una forma específica en un momento específico.

Los templates pueden contener diversas cosas. Ya he mostrado cómo explorar algunas de estas cosas antes. En el artículo Múltiples indicadores en un gráfico (Parte 03): Desarrollando definiciones para usuarios, mostré cómo puedes colocar diversos indicadores uno al lado del otro, como se puede ver en la figura 01.

Figura 01

Figura 01 - Usando múltiples indicadores en una subventana.

Este concepto, mostrado anteriormente, solo es posible cuando se usan plantillas. Por muy buen programador que seas y tengas amplio conocimiento en MQL5, nunca conseguirás obtener el resultado visto en la figura 01 sin comprender cómo funciona MetaTrader 5. Esto se debe a que no todo es programación. La programación solo te ayuda a montar la solución que de otra manera no es posible. No es, y no debe ser, tu primer intento en tratar de crear algo, sino una herramienta para lograr el resultado deseado.

¿Y por qué estoy diciendo esto? El motivo es justamente lo que se ve en el video 01, que se encuentra al inicio de este artículo. Por más que sepas programar, o por más que entiendas cómo funciona MQL5, no conseguirás hacer lo que se ve en el video sin entender cómo funciona MetaTrader 5.

El detalle en esta historia es que cuando el artículo Múltiples indicadores en un gráfico (Parte 06): Convirtamos MetaTrader 5 en un sistema RAD (II) se publicó, en aquella época no usaba ciertos conceptos de MetaTrader 5. Todavía estaba encadenado a algunas ideas y conceptos que, con el tiempo, se mostraron menos adecuados. No estoy diciendo que eran erróneos, sino menos adecuados. Existen soluciones mucho mejores que aquella. Y esto pasa justamente por lo mismo que se vio en aquel artículo, así como en el artículo anterior, Múltiples indicadores en un gráfico (Parte 05): Convirtamos MetaTrader 5 en un sistema RAD (I).

En ambos casos, se puede notar que se abrió la plantilla y hubo un intento de trabajar en ella. Pero todo ese trabajo no pasó de un simple rasguño en la superficie, ya que mucho de lo que ves allí es una reprogramación de la misma plantilla. Esto de manera que emulara un sistema RAD que se lograría mediante programación en MQL5.

A pesar de que aquello funcionaba, puedes notar que, en realidad, la plantilla creada como MetaTrader 5, era después, cuando se colocaba el indicador en el gráfico, recreada por el propio indicador. Con esto, todos los objetos que existían en la plantilla fueron recreados por el indicador. De esta manera, MetaTrader 5 tenía acceso a los objetos presentes allí, pudiendo así ajustar y modificar los valores presentes en cada uno de los objetos.

Sin embargo, el tiempo pasó, y aquella idea mostró ser susceptible de mejoras. Por eso es que conseguí un modelo más adecuado del Chart Trade, donde usamos un mínimo de objetos para suplir toda la demanda. Es cierto que aún será necesario hacer algunas cosas más, además de lo que se verá en este artículo. Pero aun así, puedes notar en el video 01 que hubo cambios en los valores, y aun así solo tenemos un único objeto en la pantalla.

Y es justamente esto lo que la programación nos permite hacer. Sin ella, la programación, estaríamos limitados a lo que está disponible en MetaTrader 5. Pero al usar la programación, expandimos lo que MetaTrader 5 puede hacer. Esto usando lo que ya existe en MetaTrader 5. Es decir, creamos una plantilla con exactamente lo que deseamos. Colocamos dicha plantilla en un OBJ_CHART. Pero sin una programación adecuada, no sería posible cambiar los valores presentes en los objetos dentro de la plantilla. Sin embargo, usando la programación de manera correcta, resolvemos este inconveniente, expandiendo así lo que puede ser posible hacer en MetaTrader 5.

Para comprender esto adecuadamente, será necesario abrir el archivo de plantilla usado en Chart Trade. Este puede verse íntegramente a continuación:

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>

Archivo Chart Trade (Plantilla)

Sé que el contenido puede parecer totalmente innecesario. Pero recuerda lo siguiente: NO HABRÁ ARCHIVO EN EL ANEXO, todo el sistema será publicado de manera que los archivos puedan obtenerse al transcribir los códigos a los respectivos archivos. El motivo por el cual lo hago así es para que realmente leas y entiendas el artículo. No quiero que simplemente descargues los archivos en el anexo y uses el sistema sin saber lo que estás usando. Aunque parezca que el artículo se hace considerablemente más largo, en realidad no es así. Lo que pasa es que la explicación se vuelve mucho más detallada.

Ahora quiero que observes con mucha atención el archivo de plantilla del Chart Trade. Si lo haces con la debida atención, notarás que hay líneas donde se encuentra el siguiente contenido:

descr=?

Esto ocurre en varios puntos del archivo template. Y esto se hace de manera intencionada. Pero, ¿por qué? Aunque descr se vea en varios puntos, los puntos donde aparece como se muestra arriba se refieren básicamente a objetos del tipo 107. ¿Y qué son estos objetos del tipo 107?

Esta descripción sobre los tipos de objetos apareció por primera vez en el artículo:  Múltiples indicadores en un gráfico (Parte 05): Convirtamos MetaTrader 5 en un sistema RAD (I), pero para facilitar, puedes ver la tabla presente en ese artículo aquí nuevamente, a continuación:

Valor de la variable TYPE Objeto referenciado
102 OBJ_LABEL
103 OBJ_BUTTON
106 OBJ_BITMAP_LABEL
107  OBJ_EDIT
110  OBJ_RECTANGLE_LABEL


Es decir, un objeto 107 es un objeto OBJ_EDIT. Estos son objetos donde el usuario puede escribir alguna información.

Está bien, pero no es posible que accedas, o mejor dicho, escribas directamente un valor en un objeto que esté presente en una plantilla. Esto es un hecho. Entonces, ¿cómo resolví este problema para conseguir que el objeto 107 presente en la plantilla pudiera recibir valores del indicador? Para responder a esta pregunta, es necesario ver el código de la clase responsable de usar la plantilla.


Actualización de la clase C_ChartFloatingRAD

Para que el Chart Trade refleje los valores introducidos por el usuario, es necesario realizar algunas operaciones básicas nada más poner el indicador en funcionamiento en el gráfico. Tales operaciones tienen como objetivo resolver algunos problemas que no se pueden resolver sin el uso de programación. Por ese motivo, es fundamental que comprendas a fondo el funcionamiento de MetaTrader 5. Si no comprendes el funcionamiento de la plataforma, no podrás crear el código necesario para sortear estos inconvenientes, que no se pueden resolver sin programación.

El código completo de la clase C_ChartFloatingRAD se puede ver a continuación. Este código, tal y como está actualmente, permite que el indicador funcione como se vio en el vídeo 01. La pregunta es: ¿puedes entender cómo está ocurriendo esto?

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. //+------------------------------------------------------------------+

Código fuente de la clase C_ChartFloatingRAD

Observa que prácticamente el archivo C_ChartFloatingRAD no ha tenido grandes adiciones desde el artículo anterior. Esto también es intencional. Ya que si se mostrara la versión final de este archivo, no podrías comprender cómo y por qué MetaTrader 5 está logrando modificar los valores en la plantilla. Esto es para que al abrir la ventana de listado de objetos, CTRL + B, solo veas el OBJ_CHART siendo listado. Pero aun así, los valores y la ventana serían modificados.

Muy bien. Entonces vamos a entender cómo y por qué MetaTrader 5 puede informarnos lo que está ocurriendo. Esto mediante la plantilla. Recuerda este detalle: en ningún momento dejaremos de usar la plantilla, y esta se aplicará en el objeto OBJ_CHART. Esto sucede en el momento exacto en que la línea 94 se ejecuta y la línea 95 informa a MetaTrader 5 que actualice el OBJ_CHART. Si olvidas este hecho, estarás buscando cosas que no existen en el código. Y no existen, porque no están en el código. Están, de hecho, en el archivo de plantilla.

Básicamente, el código añadido se puede ver entre las líneas 38 y 123. Está estructurado de manera que las próximas cosas que se harán en el próximo artículo no necesitarán muchos cambios, lo cual es muy bueno. Así que presta atención a la explicación en este artículo, y entenderás el próximo con mucha facilidad. Tal vez incluso puedas prever lo que se hará en el próximo artículo en términos de programación.

Comencemos con el constructor de la clase. Esto porque facilita bastante la comprensión de las demás partes. Este constructor se inicia en la línea 105. Pero es en la línea 109 donde realmente comienzan los cambios. En esta línea, garantizamos que el valor de apalancamiento sea siempre mayor o igual a 1 usando el operador ternario. Nada muy difícil o complicado.

Ahora vamos a la línea 110. Esta línea, al igual que la línea 111, realiza un ajuste en el valor a mostrar en la ventana Chart Trade. El motivo de esto es que el usuario puede ingresar un valor que, para el activo en el cual se encuentra el indicador de Chart Trade, no tiene sentido. Por ejemplo, en el caso del dólar futuro, los movimientos son siempre de R$ 5,00 en R$ 5,00 por contrato. En este caso, no tiene sentido decir que el take profit o stop loss será un valor no múltiplo de 5; por ejemplo, indicar un take profit de R$ 76,00 no tiene sentido, ya que este valor jamás será alcanzado.

Entonces, las líneas 110 y 111 hacen dos llamadas. La primera convertirá el valor financiero en puntos. La segunda revertirá esto, transformando el valor en puntos en un valor financiero. Puedes pensar que esto hace que el valor vuelva al valor original. Sí, es cierto, pero aquí las matemáticas se manipularán para convertir y ajustar los valores. La primera llamada hará uso de una función presente en la clase C_Terminal. En el caso de la segunda, ejecutaremos la función presente en la línea 98.

Esta función en la línea 98 usa solo una única línea. La línea 100 es, en realidad, un cálculo que transformará una cantidad dada de puntos en un valor financiero.

Esta fue la parte fácil. Ahora veamos la parte más complicada de este sistema actual.

Una vez que el constructor alcance la línea 113, tendremos algo bastante curioso. Esta línea 113 creará un nombre de archivo temporal. Recuerda, este archivo es y será temporal. Tal archivo estará presente en el área definida en MQL5\Files, más otra información, creada precisamente en esta línea 113.

Una vez que ya tenemos el nombre del archivo, creado en la línea 113, pasamos a la línea 114. En esta línea, copiaremos íntegramente el contenido del archivo de plantilla (que se puede ver en el tema anterior) a un nombre nuevo. Si tenemos éxito, seguiremos adelante. Si esta copia falla, informaremos esto al autor de llamada.

Entre las líneas 116 y 119 es donde ocurre la magia. Es precisamente en esta parte que hacemos que el indicador Chart Trade reciba los valores informados por MetaTrader 5 y/o por el usuario. Estas líneas hacen la llamada a la línea 60 del código de la clase. Así que, a partir de ahora, trabajaremos en esta parte del código, ya que el resto del constructor se explicó en el artículo anterior. Pero antes de saltar definitivamente a la línea 60, hay otra línea que se añadió al código, la línea 128. Esta eliminará el archivo creado en el constructor. Por esto mencioné que el archivo creado era temporal.

Bien, pasemos a la línea 60. Aquí haremos algo un poco repetitivo (todavía estoy explicando lo básico, así que ten paciencia). Lo primero será abrir el archivo "original" (notad las comillas en la palabra), esto se hace en la línea 66. Si tenemos éxito, continuaremos. En caso de fallo, volveremos al autor de llamada.

En la línea 71, crearemos un archivo temporal del archivo temporal (esto suena extraño, pero no hay otra forma de decirlo). Si esto falla, cerraremos el archivo que se abrió y volveremos al autor de llamada. Hasta la línea 77, todo lo que hemos hecho es abrir un archivo y crear otro. Y, si la ejecución llega a la línea 77, entraremos en un bucle para copiar todo el archivo.

Pero espera un momento. ¿Copiar todo el archivo? ¿De nuevo? Sí, pero esta vez en la línea 81, probaremos una condición. Esta condición verificará si el proceso de copia encontró un objeto en el archivo de plantilla. Cuando esto ocurra, pasaremos a la línea 38, donde nos ocuparemos del objeto encontrado. De cualquier manera, si la plantilla que se está analizando es la del tema anterior, haremos este salto a la línea 38 con toda certeza. Así que, aunque quieras usar tu propia plantilla, podrás hacerlo, siempre y cuando definas correctamente los nombres que se usan en los objetos.

Una vez que la rutina presente en la línea 38 haya sido llamada, navegaremos hasta que la ejecución llegue a la línea 44. Aquí continuaremos el proceso de copiar el archivo. De la misma manera que se estaba haciendo antes. Sin embargo, cuando en esta misma línea 44 se encuentre la línea que cierra el objeto, retornaremos al autor de llamada, es decir, a la línea 81. Pero vamos a detenernos por unos instantes en esta rutina que aparece en la línea 38.

Durante el proceso de copia, leeremos el archivo de origen, en la línea 46. Después de esto, descompondremos el contenido de esta línea. Si la línea 47, que realiza esta descomposición, informa de que tenemos dos instrucciones presentes, se generará un nuevo flujo de ejecución. De lo contrario, la línea leída será grabada, y esto se hace en la línea 56.

Ahora presta atención al siguiente punto: Durante la descomposición que se hace en la línea 47, tenemos en el primer momento, la variable i0, con un valor igual a cero. Mucha atención a esto. Pues en el momento que se encuentre el nombre del objeto, la variable i0 pasará a tener un valor igual a 1. Es en este punto donde reside el peligro. Si editas manualmente el archivo de plantilla, debes asegurarte de que el nombre del objeto sea encontrado antes que cualquier parámetro del mismo. El único parámetro que puede venir antes del nombre es el tipo de objeto. Ningún otro parámetro debe venir antes del nombre. Si esto ocurre, todo el proceso fallará.

En la línea 50, verificaremos si i0 está indicando que el objeto buscado fue encontrado. Esto sucede cuando el valor de esta variable es igual a 1. Pero tenemos una segunda condición, que es el parámetro buscado, en este caso, siempre buscaremos la cadena descr. Cuando ocurran estas dos condiciones, grabaremos el valor que queremos, esto durante el proceso de copia. Este tipo de modificación sucede justamente en la línea 52. Después de esto, retornaremos al autor de llamada, es decir, retornaremos a la línea 81.

Observa cómo se da el proceso. Copiamos todo el archivo, excepto una línea específica. Precisamente esta línea se modificará, haciendo que la plantilla tenga nuevos datos o una apariencia diferente.

Cuando todo el archivo haya sido copiado y modificado, cerraremos ambos, esto se hace en las líneas 83 y 84. Y justo después, en la línea 85, intentaremos renombrar el archivo temporal al archivo que la clase espera usar. Y el funcionamiento será exactamente como se vio en el video 01.


Conclusión

En esta publicación expliqué los primeros pasos que debemos seguir para manipular una plantilla. De este modo, se adecuará a lo que necesitamos y queremos. Esto nos permitirá usar una programación mucho más sencilla, al mismo tiempo que aprovechamos mejor MetaTrader 5. Sin embargo, el gran truco no consiste exactamente en usar más o menos objetos en el gráfico. Sino comprender que MQL5 existe para que podamos convertir MetaTrader 5 en una plataforma adecuada a nuestras necesidades, no para crear una plataforma competidora.


Traducción del portugués realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/pt/articles/11664

Archivos adjuntos |
Anexo.zip (420.65 KB)
Desarrollo de un sistema de repetición (Parte 44): Proyecto Chart Trade (III) Desarrollo de un sistema de repetición (Parte 44): Proyecto Chart Trade (III)
En el artículo anterior, expliqué cómo puedes manipular los datos de la plantilla para usarlos en un OBJ_CHART. Allí solo introduje el tema sin entrar en muchos detalles, ya que en esa versión el trabajo se hizo de una manera muy simplificada. Sin embargo, se hizo de esa forma precisamente para facilitar la explicación del contenido. Pues, a pesar de parecer simple hacer ciertas cosas, algunas no son tan evidentes, y sin comprender la parte más simple y básica, no entenderás realmente lo que estoy haciendo.
Creamos un asesor multidivisa sencillo utilizando MQL5 (Parte 6): Dos indicadores RSI se cruzan entre sí Creamos un asesor multidivisa sencillo utilizando MQL5 (Parte 6): Dos indicadores RSI se cruzan entre sí
Por asesor multidivisa en este artículo nos referimos a un asesor o robot comercial que utiliza dos indicadores RSI con líneas de intersección: un RSI rápido que se cruza con uno lento.
Desarrollo de un sistema de repetición (Parte 45): Proyecto Chart Trade (IV) Desarrollo de un sistema de repetición (Parte 45): Proyecto Chart Trade (IV)
Lo principal en este artículo es precisamente la presentación y explicación de la clase C_ChartFloatingRAD. Tenemos el indicador Chart Trade, que funciona de una manera bastante interesante. No obstante, si te das cuenta, aún tenemos un número bastante reducido de objetos en el gráfico. Y aun así, tenemos exactamente el comportamiento esperado. Se pueden editar los valores presentes en el indicador. La pregunta es: ¿Cómo es esto posible? En este artículo comenzarás a entenderlo.
Modelos de regresión de la biblioteca Scikit-learn y su exportación a ONNX Modelos de regresión de la biblioteca Scikit-learn y su exportación a ONNX
En este artículo exploraremos la aplicación de modelos de regresión del paquete Scikit-learn e intentaremos convertirlos al formato ONNX y utilizaremos los modelos resultantes dentro de programas MQL5. Adicionalmente, compararemos la precisión de los modelos originales con sus versiones ONNX tanto para precisión flotante como doble. Además, examinaremos la representación ONNX de los modelos de regresión con el fin de comprender mejor su estructura interna y sus principios de funcionamiento.