Português
preview
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)

MetaTrader 5Ejemplos | 16 julio 2024, 16:13
30 0
Daniel Jose
Daniel Jose

Introducción

En el artículo anterior Desarrollo de un sistema de repetición (Parte 44): Proyecto Chart Trade (III), mostré cómo podemos añadir cierta interactividad para que la ventana Chart Trade se comporte como si hubiera objetos presentes. Incluso cuando el único y real objeto presente en el gráfico era OBJ_CHART.

Pero, a pesar de esa interacción, que se está dando de manera bastante agradable, aún no está perfecta. Todavía faltan detalles que finalmente se resolverán en este artículo. Al final, tendremos un código bastante interesante, que será capaz de realizar lo que puede verse en el vídeo 01, justo abajo:


Vídeo 01 - Demostrando las funcionalidades de esta versión.

Este vídeo 01 demuestra exactamente lo que podremos hacer en esta etapa actual de desarrollo. A pesar de todo, aún no contaremos con el sistema de órdenes. Todavía no, porque necesitamos crear otras cosas antes de hacer que el indicador Chart Trade pueda de hecho enviar órdenes o cerrar posiciones.


Un nuevo indicador.

A pesar del título de este tema, que da a entender que crearemos un nuevo indicador. Esto no es, de hecho, lo que haremos. Añadiremos algunas cosas, lo que hará que el indicador Chart Trade sea de hecho un nuevo modelo de construcción. El código fuente del indicador se puede ver en su totalidad justo abajo:

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

Código fuente del indicador Chart Trade

Puedes observar que el código prácticamente no ha sufrido grandes cambios desde la última vez que se vio. Pero los cambios que ocurrieron cambian drásticamente la manera en que el indicador funciona.

Primero se añadió una macro. Esta se encuentra en la línea 18 del código fuente. Lo que hace esta macro es básicamente estandarizar un mensaje de error para ser mostrado en el terminal. Ahora nota que recibe un parámetro, cuyo objetivo es indicar si la macro va a resetear o no la constante de error. Puedes ver esto en los puntos donde se usa la macro. El primer punto es en la línea 24, justo después del intento de inicializar el indicador. En este caso no queremos ni necesitamos reiniciar la constante, por lo tanto, el argumento es falso. El segundo punto es en la línea 38. En este caso, puede ser que el error ocurrido sea algo tolerable, entonces el argumento es verdadero, para resetear el valor de la constante. Por tanto, es importante estar atento a los mensajes que aparecen en el terminal para permanecer consciente de lo que esté ocurriendo.

Hay otra cuestión también bastante interesante que está justamente en la línea 45. Esto es una medida de protección que se comprenderá mejor durante la explicación del código de la clase C_ChartFloatingRAD. Pero, básicamente, el motivo es que necesitamos mantener el indicador Chart Trade funcionando de alguna forma. Si observas, notarás que estoy utilizando precisamente la llamada de actualización del gráfico. Este evento ocurre siempre que cambiamos el marco temporal del gráfico. Además de otras cosas también, pero nuestro principal problema es el cambio de marco temporal.

Cuando ocurre el cambio de marco temporal, todo y cualquier indicador es removido del gráfico y luego reinstalado. En ese momento, los datos editados directamente en el gráfico se pierden. Existen algunas formas de prevenir esta pérdida de datos. Una de ellas es la que vamos a usar. Entonces, respecto al código fuente presente en el indicador, no hay más cosas que decir. Ya que la clase C_AdjustTemplate no ha sufrido ningún cambio, podemos pasar a explicar el código de la clase C_ChartFloatingRAD.


Haciendo la clase C_ChartFloatingRAD casi totalmente funcional

Lo principal en este artículo es precisamente la presentación y explicación de la clase C_ChartFloatingRAD. Como pudiste ver en el vídeo que presenté al inicio del artículo, tenemos el indicador Chart Trade, que funciona de una manera bastante interesante. No obstante, si prestaste atención al video, debes haber notado que 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?

Para responder esta y otras cuestiones, necesitamos ver el código fuente de la clase. Este código se muestra en su totalidad justo abajo. Recuerda que no habrá ningún archivo adjunto, pero aun así podrás usar el sistema como se mostró en el video. Siempre y cuando estés siguiendo estos artículos, no tendrás problemas en hacerlo.

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. 

Código fuente de la clase C_ChartFloatingRAD

Aunque parece ser un código extenso, no lo es tanto si has estado siguiendo esta serie de artículos. El motivo es que ha sufrido cambios graduales, me he esforzado por hacer tales cambios poco a poco. El motivo es permitir que la explicación y la comprensión del código se hagan de forma que todos entiendan lo que está ocurriendo.

Lo primero que se puede notar en el código de la clase es la línea 8, donde tenemos una definición de macro con el fin de construir un nombre. Este será usado para definir el nombre de las variables globales del terminal. En breve veremos con más detalle cómo usaremos tales variables. Pero por ahora no te preocupes por esto, solo sabe que estamos definiendo una macro que será usada en un futuro próximo.

Existen pequeños cambios en el código, pero ya que no tiene sentido hablar de ellos, vamos a centrarnos en lo que realmente es importante. De esta forma, iremos a la línea 51, donde tenemos un procedimiento que se usará bastante. Este no existía antes, pero es importante para lo que vamos a hacer.

Observa que usaremos un bucle for con el fin de reducir un poco el número de líneas y declaraciones. Esto porque las mismas serán bastante repetitivas y las posibilidades de cometer un error son muy altas. Pero independientemente de esto, observa que este bucle cuenta con un operador if else, debido a que en un momento estaremos buscando y en otro definiendo las cosas.

Cuando la línea 54 se ejecute, podremos estar buscando información. Si este es el caso, las líneas 56 a 58 definen cuáles son los parámetros que buscaremos en la plantilla. Este tipo de cosa ya fue explicada en el artículo anterior. Pero ahora buscaremos las propiedades de los objetos que se encuentran definidas en la plantilla. Tales propiedades son necesarias para que los objetos que serán creados en el indicador trabajen de la misma forma en que fueron pensados en la plantilla.

En el segundo caso, cuando no estamos buscando la información de la plantilla, haremos el almacenamiento local de tales valores. Esto agiliza bastante la ejecución posterior del código. Estas informaciones se almacenan entre las líneas 62 a 64, pudiendo ser accedidas fácilmente después, como podrás ver en el transcurso de la explicación.

La siguiente cosa que tenemos es el procedimiento visto en la línea 68. Aquí la cosa comienza a ponerse más interesante, porque ahora tenemos otra información que será ajustada en este procedimiento. Antes, todo lo que se informaba en el indicador provenía del momento en que el usuario colocaba el indicador en el gráfico, no había necesidad de tomar ciertas medidas. Pero ahora que podemos interactuar directamente con el indicador, necesitamos garantizar que los datos sean de alguna manera representativos.

Por esto se añadió una nueva macro en este procedimiento, que puede verse en la línea 82. El hecho de que esta macro exista hace que la antigua función que representaba dejara de existir. Además de esta macro, puedes notar que el código pasó por algunos cambios, entre ellos, ahora tenemos la línea 90. Este utiliza el procedimiento visto anteriormente, pero ten en cuenta que estamos indicando al indicador que capture los parámetros. Esto se hará solo una vez. Y el momento en que se hará es precisamente cuando el indicador está siendo iniciado. Detalle: Existe una segunda cuestión en este hecho, pero se tratará más adelante en este artículo.

Hecho esto, entre las líneas 92 y 94, ajustamos y corregimos los valores que se presentarán en el indicador Chart Trade. Anteriormente esto se hacía en el constructor de la clase, pero no había ninguna interacción con el usuario. Sin embargo, ahora tenemos esta interacción y debido a esto, necesitamos garantizar que los valores sean representativos. De esta forma, ajustamos los valores aquí, en el momento en que la plantilla será actualizada.

Es importante que estés todo el tiempo consciente del siguiente hecho: No estamos de ningún modo editando valores directamente en los objetos, ya que solo tendrás el OBJ_CHART en el gráfico. Así, necesitamos hacer que la plantilla sea actualizada y presentada en el gráfico. Por este motivo, la actualización deberá realizarse en este punto.

Las demás líneas ya fueron explicadas en el artículo anterior, Desarrollo de un sistema de repetición (Parte 44): Proyecto Chart Trade (III), sin embargo, en la línea 105, hacemos algo que no estaba presente antes aquí. En esta línea corregimos una pequeña falla, en la que era posible arrastrar la ventana flotante, haciendo clic y arrastrando el botón de maximizar y minimizar. Esta línea hace que esta falla deje de existir. Justo después, en la línea 106, obtenemos los valores que deseamos de la plantilla. Observen que ahora informamos la llamada como falsa. Así los valores serán almacenados en los lugares correctos, para uso posterior.

En la línea 108 tenemos algo curioso, que es precisamente el hecho de que damos la capacidad a la ventana flotante de ser maximizada o minimizada. Esto antes se hacía en otro punto del código. Pero por motivos de practicidad, decidí poner este control aquí. Esto facilita mucho las cosas en términos de modelado, ya que todo lo relacionado con la ventana se encuentra en el mismo punto.

De la misma manera, las líneas 109 y 110 nos permiten trabajar de una manera más conveniente con la ventana flotante. Es muy común que algunos usuarios deseen tener la ventana flotante en un punto dado, dependiendo de su estado. Es decir, cuando está maximizada, el usuario desea la ventana en una posición, y cuando está minimizada, la desea en otro lugar. Y es precisamente esto lo que hacen las líneas 109 y 110. Ellas posicionan la ventana flotante en el último punto donde se encontraba, dependiendo de si estaba maximizada o minimizada.

La línea 112 ya fue comentada en el artículo anterior, entonces podemos ver las líneas 114 y 115, que antes se encontraban en un procedimiento aparte. Pues bien, en la línea 114 iniciamos el template, ya modificado, en el objeto OBJ_CHART. Así, cuando la línea 115 se ejecute, tendremos la visualización y actualización del template en el gráfico. El hecho es que ahora, todo el procedimiento está concentrado en esta rutina. Entonces no necesitaremos preocuparnos en informar cosas extras para hacer que los datos sean informados al usuario de la manera correcta.

Tal vez, pero aún no es probable, este sistema sea colocado en una clase separada. Pero debido a que se está usando solo en el Chart Trade, lo dejaré aquí. Sin embargo, puede ser interesante colocarlo en otra clase. Esto debido a que decida convertir otras cosas en un template. Pero por ahora, mantendré el código así.

Ahora tenemos algo un poco diferente. En la línea 137, puedes ver un tipo de código poco común. Esto en la mayoría de las veces. Este tipo de código es bastante común cuando tenemos procedimientos idénticos, pero para tipos diferentes. ¿Y qué significa esto! 🤔 Bien, primero es necesario entender lo siguiente: ¿Por qué necesitas crear una rutina para mostrar un valor double, otra para valores int y una tercera para strings? ¿No sería mucho más simple crear una única rutina, ya que esencialmente el código previsto en todas sería siempre el mismo?  La única diferencia sería el hecho de que en uno el valor sería de un tipo u otro, ¿cierto? Pues bien, eso es precisamente lo que hace la línea 137.

Pero espera un momento. Si la idea es representar el valor, ¿no podríamos simplemente pasarlo como una string directamente? Sí. Podríamos, pero hay algo que no estás considerando. ¿Y si deseas hacer que el valor sea presentado de una manera específica y fuera ejecutado desde varios puntos diferentes del código? Piensa en el trabajo que tendrías. Pero haciendo así, podemos simplemente informar el valor en su tipo original, dejar que el compilador cree la rutina para nosotros y presentarlo como deseamos. Si cambiamos la presentación, todo lo que necesitaríamos hacer sería cambiar solo un único punto en el código. El compilador se encargaría de ajustar las cosas para nosotros. 

Trabaja menos y produce más.

Si no lo haces así, solo aumentarás tu trabajo. Mi consejo es: Siempre que sea posible, haz que el compilador trabaje para ti. Notarás que tus códigos serán mucho más fáciles de corregir y tu productividad aumentará exponencialmente.

Pero para que la línea 137 realmente tenga sentido, es necesario usarla. Así, en la línea 138 puedes notar cómo se está usando la línea 137. Fuera de este punto, puedes notar que en ningún otro momento usamos la línea 137. Sin embargo, en la línea 151, usamos el valor pasado como parámetro. Noten que hago la conversión explícita al tipo string. Entonces, aunque podamos hacer la conversión durante el paso o después, esto no hará diferencia. No en este caso específico.

Ahora presten atención al siguiente hecho: Aquí, en este procedimiento estamos creando un objeto extra, un OBJ_EDIT. ¿Por qué estamos haciendo esto? El motivo es facilitar la usabilidad del indicador Chart Trade. De hecho, no necesitaríamos crear tal objeto. Pero esto haría que el indicador fuera difícil de usar. No es que sea complejo codificar la lógica necesaria. Pero el usuario tendría dificultades para trabajar y usar el indicador. Por este motivo, pedimos asistencia a MetaTrader 5, diciéndole que cree un objeto de edición.

Sin embargo, necesitamos que este objeto esté en el lugar correcto, con el formato y el estilo correctos. Esto se hace de la siguiente manera: Cuando se llama este procedimiento, eliminaremos, si existe, el objeto de edición creado. Esto se hace en la línea 141. Pero hay un detalle, este objeto solo existirá cuando sea necesario. Entonces, entre las líneas 142 y 150, usaremos los valores que están definidos en el template. Así, el objeto creado será igual al que se está usando en el template.

Hay un detalle que está presente en las líneas 143 y 144. Este es un pequeño ajuste donde sumamos 3 a las dimensiones. Este valor no es accidental, es debido a que el OBJ_CHART usa 3 píxeles en sus bordes, y el objeto OBJ_EDIT tendrá que ser desplazado exactamente esos 3 píxeles. Así, se mantendrá en el lugar exacto donde el template se encuentra en el gráfico.

Ahora, en la línea 155, tenemos una función que nos ayudará cuando el indicador sea recolocado en el gráfico. Atención:Esta función no trabaja sola, funciona en conjunto con otra que veremos más adelante. Lo que hacemos en esta función es lo siguiente: Todos los datos sensibles del indicador serán guardados y luego recuperados. Aquí recuperamos esos datos. Existen varias formas de hacer esto, entre ellas la que se está usando aquí. El hecho de hacerlo de esta manera específica tiene que ver con no querer usar DLLs sin una necesidad real para ello. Entonces, hacemos uso de las variables globales del terminal, de modo que MetaTrader 5 pueda ayudarnos en la transacción.

Cada una de las líneas, entre ellas: 160, 165, 170, 175, 177 y 178, recuperarán los datos presentes en las variables globales del terminal. Tales variables son del tipo double, pero podemos almacenar valores diferentes en ellas. Ya he explicado en varias ocasiones cómo se hace. Pero aquí lo hacemos de una forma muy específica. Entonces, si en alguna de estas líneas indicadas, la variable global del terminal no puede ser accedida o leída, devolveremos un valor falso al llamador. Y el único punto en que esta función será llamada realmente es en el constructor, pero veremos esto en breve.

En cada llamada ejecutada en las líneas informadas, repondremos el valor previamente almacenado. Así, si cambias el marco temporal, podrás continuar con el indicador Chart Trade de la misma manera. Es decir, como si no hubiera sufrido ningún tipo de cambio. Aquí hay una cuestión que es más personal que práctica en sí. Sin embargo, hablaré de esto en el momento en que se explique cómo almacenar los datos.

Pero independientemente de si la lectura fue exitosa o no, en la línea 180 eliminaremos todas las variables globales del terminal que estén vinculadas al indicador Chart Trade. Sin embargo, noten que puede haber más de estas mismas variables presentes en MetaTrader 5. Para saber cuáles eliminar, usamos la macro definida al inicio del código de la clase.

Ahora vamos al constructor de la clase. Este comienza en la línea 187, pero lo que merece explicación es precisamente la interacción que se realiza en la línea 192. Esta llamará al procedimiento explicado anteriormente. Sin embargo, si no tiene éxito, ejecutaremos las líneas entre 194 y 200. Estas generarán los valores predeterminados del indicador Chart Trade. Sin embargo, dado que el proceso de eliminación y recolocación del indicador es muy rápido debido al cambio de marco temporal, es casi improbable que los valores a usar sean los predeterminados. Pero puede suceder, así que es bueno estar siempre atento a esto.

Noten que, a diferencia de lo que ocurría antes, ahora los valores predeterminados se inician sin ningún tipo de ajuste. Esto se debe a que ahora quien hará tales ajustes es precisamente el procedimiento que actualiza el template.

Bien, ahora veamos qué ocurre en el procedimiento presente en la línea 214. En este punto, estaremos guardando temporalmente el estado del indicador Chart Trade. Pero, ¿por qué estamos haciendo esto? ¿Y por qué estamos guardando este estado en las variables globales del terminal? ¿No se podría hacer esto de otra manera? Bien, vamos por partes.

Primero, sí, podríamos hacerlo de otra manera. De hecho, hay varias maneras posibles de hacerlo. La cuestión no es cómo guardar, sino cómo recuperar los datos almacenados. El hecho de que estamos usando las variables globales del terminal se debe a que su acceso es mucho más sencillo. Considerando que en algunos casos sería más complicado, no almacenar, sino recuperar los datos. Pensé seriamente en poner los datos directamente en el template. En realidad, ya estarían allí, salvo los datos relacionados con la posición. Dado que tenemos un posicionamiento para la ventana maximizada y otro para la minimizada.

La diferencia entre la posición maximizada y minimizada complica el uso del template. También podríamos usar otros medios. De cualquier manera, esto podría complicar innecesariamente el sistema y no valdría la pena realizar ese esfuerzo. Una vez más, los datos ya están siempre presentes en el template. Sin embargo, cuando se ejecutara la línea 209, eliminaría el template, haciendo que los datos desaparecieran. Incluso si no usas diferentes posicionamientos para la ventana maximizada y minimizada, tendrías problemas para resolver la cuestión de la línea 209.

Una solución para esto sería colocar esta llamada que elimina el template en el código fuente del indicador. Si esto se hiciera, el código del indicador sería como se muestra a continuación:

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

Y esta función RemoveTemplate tendría una única llamada, que sería lo que está en la línea 209 del código de la clase. Aunque esto funcione relativamente bien, tendríamos otros problemas. Uno de ellos sería que, cuando el indicador diera un error más grave, el archivo correspondiente no se eliminaría, sino que permanecería en el disco. Cuando intentaras volver a colocar el indicador en el gráfico, los datos estarían incorrectos, lo que podría hacer que el indicador se eliminara nuevamente. Y las cosas seguirían así hasta que eliminaras el archivo defectuoso.

Por estas y otras razones, prefiero usar las variables globales del terminal. Pero noten que no las estoy usando directamente. Para usarlas, utilizo una macro. Y aquí surge una pregunta: ¿Por qué? El motivo es el tiempo de vida de la variable global del terminal.

Observa en la macro, que está presente en la línea 216, lo que está ocurriendo. Nota que primero intentamos crear la variable como una variable global de terminal temporal. Esto hace que, si el terminal MetaTrader 5 se cierra, la variable se destruya junto con él. Así garantizamos la integridad del indicador Chart Trade.

Observa que cada una de las variables globales del terminal almacenará un valor. El orden en que ejecutas estas variables no importa. Lo que realmente importa es el nombre y el valor. Recordando que el nombre no puede contener más de 64 caracteres. Por este motivo, utilizamos la macro para crear el nombre, lo que nos garantiza una cierta hegemonía en la creación de nombres.

No hay mucho que destacar sobre esta rutina de guardar los datos del template. El hecho es que, sin ella, cada vez que se modificara el tiempo gráfico, tendrías que preocuparte siempre por reajustar los datos presentes en el indicador. Dado que muchos usuarios tienden a cambiar varias veces el tiempo gráfico a lo largo del período de negociación, sería una gran molestia tener que ajustar constantemente los valores en el indicador Chart Trade. Pero con la ayuda de la programación y de MetaTrader 5, podemos dejar esto de lado y enfocarnos en otras cosas. Para ello, usamos este procedimiento de la línea 214.

Existe otra forma de mantener las cosas en "memoria", pero no entraré en detalles ahora, ya que implica trabajar con los objetos gráficos. Esto será tema para otro momento.

Muy bien, estamos prácticamente terminando este artículo. Pero antes, tenemos una última cosa que ver. La función de manejo de mensajes. Esta comienza en la línea 237, y al contrario de lo que pueda parecer, es mucho más simple y amigable de lo que muchos imaginan. Sin embargo, te debes estar preguntando: ¿Por qué esta rutina de manejo de mensajes cuenta con 4 tipos de eventos si en realidad usaremos solo el indicador de mouse?

He reiterado el hecho de que MetaTrader 5 es una plataforma basada en eventos. Por esto, necesitamos entender cómo trabajar de esta manera. En el artículo anterior, mencioné que podríamos usar otros eventos para simplificar nuestra lógica. Aunque el código sea un poco confuso en algunos aspectos, sigue siendo funcional. Sin embargo, podemos dejar la mayoría de las pruebas, que realmente necesitan estar presentes en ese código, vistas en el artículo anterior. Estas serán realizadas por MetaTrader 5. Así, si comparas ambos códigos de la clase, verás que este contiene menos pruebas. ¿Por qué?

La razón es que estas pruebas se realizarán en MetaTrader 5. Así, aquellos eventos de clic en un objeto en el Chart Trade ahora se han sustituido por una versión donde analizamos el clic en un objeto, y no más el clic del indicador de mouse. Esto facilita bastante la codificación. De esta manera, podemos incluir más eventos en un código más legible. Puedes ver la cuestión de los clics al observar el código presente entre las líneas 315 y 343. Allí estamos manejando clics en todos los objetos presentes en el template. Todos. Incluso los que aún no tienen rutinas relacionadas con ellos, como es el caso de los botones de compra, venta y cierre de posición.

Una de las cuestiones que merece algún destaque aquí en el manejador de mensajes es el evento CHARTEVENT_CHART_CHANGE, presente en la línea 258. Hay un detalle que es cuando el terminal sufre algún cambio en sus dimensiones. Cuando esto ocurre, MetaTrader 5 inicia un evento informando esto a nuestros programas. Este evento es tratado por CHARTEVENT_CHART_CHANGE, de modo que podemos verificar si la ventana flotante aún permanece visible en el gráfico. Si no tratamos este evento, podría suceder que la ventana quede oculta, pero el indicador siga activo. Dado que este tratamiento es igual tanto para el caso de la ventana minimizada como para el modo maximizado. Utilizo una macro para realizar los ajustes necesarios. Así, si ocurre algún cambio que requiera reposicionar la ventana adecuadamente, la línea 265 lo hará por nosotros.

El otro evento que también merece algún destaque es CHARTEVENT_OBJECT_ENDEDIT. En este caso, siempre que MetaTrader 5 detecte que el objeto OBJ_EDIT ha terminado su edición, lanzará un evento. De esta manera, podemos actualizar los datos directamente en el template. Esto se hace en la línea 309. Pero atención, esta actualización hace que los datos sean modificados de manera que sean representativos. Es decir, si intentas poner un valor o cantidad que no se adecue al activo, el código hará que el valor se ajuste. Así evitamos contradicciones y problemas futuros.


Conclusión

A pesar de toda la complejidad que pueda entrañar la creación del Chart Trade, en comparación con lo visto hasta ahora, esta versión es considerablemente más estable y escalable que la versión antigua. Aunque mantiene gran parte del principio presentado anteriormente, en esta ocasión la idea es crear un sistema más modular. Dado que ahora tenemos, además del mercado real y la cuenta de demostración, un sistema de simulación y repetición de mercado. Esto exige que el sistema se cree de forma totalmente diferente. Si no se hace adecuadamente, tendremos grandes problemas a la hora de trabajar con las mismas herramientas en sistemas y mercados tan diversos.

Aunque el indicador Chart Trade aún no esté totalmente operativo debido a la ausencia de funcionalidades en los botones de compra, venta y cierre de posición, la esencia del código ya está bien encaminada. Volveremos a este indicador en breve para hacer que dichos botones funcionen. Por ahora, el indicador ya se adecúa a lo esperado.

Admito que muchos pueden sentirse frustrados por no tener acceso a los anexos. Pero tengo motivos para esto. Quiero que veas, leas y comprendas el código y el sistema. He notado a lo largo del tiempo que muchos, de hecho, no leen los artículos ni entienden lo que están usando. Esto es peligroso y no es la mejor forma de usar algo. Aunque no lo parezca, todo el código se está publicando y colocando en el artículo. Es solo cuestión de entenderlo y editarlo en el MetaEditor. Así tendré la certeza de que no se usará sin que la persona sepa de qué se trata.


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

Archivos adjuntos |
Indicators.zip (149.46 KB)
Utilizando redes neuronales en MetaTrader Utilizando redes neuronales en MetaTrader
En el artículo se muestra la aplicación de las redes neuronales en los programas de MQL, usando la biblioteca de libre difusión FANN. Usando como ejemplo una estrategia que utiliza el indicador MACD se ha construido un experto que usa el filtrado con red neuronal de las operaciones. Dicho filtrado ha mejorado las características del sistema comercial.
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.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
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)
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. Aquí haremos algo un poco más avanzado, y por consecuencia diferente.