preview
Desenvolvendo um sistema de Replay (Parte 45): Projeto do Chart Trade (IV)

Desenvolvendo um sistema de Replay (Parte 45): Projeto do Chart Trade (IV)

MetaTrader 5Exemplos | 28 março 2024, 08:58
151 0
Daniel Jose
Daniel Jose

Introdução

No artigo anterior Desenvolvendo um sistema de Replay (Parte 44): Projeto do Chart Trade (III), mostrei como podemos adicionar uma certa interatividade, de modo a fazer com que a janela do Chart Trade se comporte como se ali tivesse objetos presentes. Mesmo quando o único e real objeto presente no gráfico, estava sendo o OBJ_CHART.

Mas apesar daquela interação, está se dando, de maneira bastante agradável, a mesma ainda não está tão perfeita. Ainda faltam detalhes que serão finalmente resolvidos neste artigo. No final, iremos ter um código bastante interessante, que será capaz de efetuar o que pode ser visto no vídeo 01, logo abaixo:


Vídeo 01 - Demonstrando as funcionalidade desta versão.

Este vídeo 01, demonstra exatamente, o que poderemos fazer neste atual estágio de desenvolvimento. Apesar de tudo, ainda não iremos contar com o sistema de ordens. Ainda não, pois precisamos criar outras coisas, antes de fazer com que o indicador Chart Trade, possa de fato enviar ordens, ou fechar posições.


Um novo indicador.

Apesar do titulo deste tópico, dar a entender que iremos criar um indicador novo. Isto não é de fato o que faremos. Mas iremos adicionar algumas coisa, o que faz com que o indicador Chart Trade, venha a ser de fato um novo modelo de construção. O código fonte do indicador pode ser visto na integra logo abaixo:

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/pt/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 fonte do indicador Chart Trade

Você pode observar que o código praticamente não sofreu grandes mudanças, desde a última vez que ele foi visto. Mas as mudanças que ocorreram, mudam drasticamente a maneira como o indicador funciona.

Primeiramente foi adicionada uma macro. Esta se encontra na linha 18 do código fonte. O que esta macro faz, é basicamente, padronizar uma mensagem de erro para ser mostrada no terminal. Mas notem que ela recebe um parâmetro, este tem como objetivo, dizer que a macro irá ou não zerar a constante de erro. Você pode ver isto, nos pontos em que a macro é usada. O primeiro ponto, é na linha 24, logo depois da tentativa de inicializar o indicador. Neste caso não queremos, e não desejamos zerar a constante, por conta disto, o argumento é falso. O segundo ponto é na linha 38. Neste caso, pode ser que o erro ocorrido, é algo tolerável, então o argumento é verdadeiro, a fim de zerar o valor da constante. Então é importante ficar de olho nas mensagens impressas no terminal, a fim de permanecer ciente do que esteja acontecendo.

Existe uma outra questão, também bastante interessante que é justamente na linha 45. Isto é uma medida de proteção, que será melhor compreendida durante a explicação do código da classe C_ChartFloatingRAD. Mas basicamente o motivo é o fato de que precisamos manter o indicador Chart Trade, funcionado de alguma forma. Se você observar, irá notar que estou usando justamente a chamada de atualização do gráfico, este evento acontece, sempre que trocamos o tempo gráfico. Além de outras coisas também, mas o nosso principal problema é a mudança de tempo gráfico.

Quando acontece a mudança de tempo gráfico, todo e qualquer indicador, é removido do gráfico, e então reposto. Neste momento, os dados editados diretamente no gráfico, são perdidos. Existem algumas forma de nos precaver desta perda de dados. Uma delas é a que iremos usar. Então a respeito do código fonte presente no indicador, não existem mais coisas a serem ditas. Já que a classe C_AdjustTemplate não sofreu nenhuma mudança, podemos passar para a explicação do código da classe C_ChartFloatingRAD.


Tornando a classe C_ChartFloatingRAD, quase totalmente funcional

O principal neste artigo, é justamente a apresentação e explicação da classe C_ChartFloatingRAD. Como você pode ter visto, no vídeo presente no inicio do artigo. Temos o indicador Chart Trade, funcionando de uma maneira bastante interessante. No entanto, se você prestou atenção ao vídeo, deve ter notado que ainda assim estamos com um número bastante reduzido de objetos gráfico. E mesmo assim temos exatamente o comportamento esperado. Podendo editar os valores presentes no indicador. A pergunta é: Como isto é possível ?!?!

Para responder esta, e outras questões, precisamos ver o código fonte da classe. Este código pode ser visto na integra logo abaixo. Lembrando que não existirá nenhum arquivo de anexo, mas mesmo assim você conseguirá usar o sistema como mostrado no vídeo. Desde é claro esteja acompanhando estes artigos, não terá problemas em fazer isto.

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 fonte da classe C_ChartFloatingRAD

Apesar de parecer ser um código extenso, o mesmo não é assim tão extenso, isto se você estiver acompanhando esta serie de artigos. O motivo é que ele tem sofrido mudanças gradativas, tenho me esforçado para fazer tais mudanças, aos poucos. O motivo é permitir que a explicação e entendimento do código seja feito de forma a que todos entendam o que está acontecendo.

A primeira coisa que se pode notar no código da classe, é a linha 8, onde temos uma definição de macro, a fim de construir um nome. Este será usado para definir o nome das variáveis globais de terminal. Em breve vamos ver com mais detalhe como iremos usar tais variáveis. Mas por hora não se preocupe com isto, apenas saiba que estamos definindo uma macro que será usada em um futuro próximo.

Existem pequenas mudanças no código, mas já que não faz sentido, ficar falando das mesmas, vamos focar no que realmente é importante. Desta forma iremos para a linha 51, onde temos um procedimento que será bastante usado. Este não existia antes, mas é importante para o que iremos fazer.

Observe que iremos usar um laço for a fim de reduzir um pouco o numero de linhas e declarações. Isto por conta que as mesmas serão bastante repetitivas, e as chances de se cometer um erro é bem grande. Mas independentemente disto, observe que este laço conta com um operador if else, isto por conta que em um momento, iremos buscar e em outro definir as coisas.

Quando a linha 54 executar, poderemos estar buscando informações. Se este for o caso, as linhas 56 a 58, definem quais são os parâmetros que iremos procurar no template. Este tipo de coisa já foi explicada no artigo anterior. Mas agora iremos buscar as propriedades dos objetos que se encontram definidas no template. Tais propriedades são necessárias para que os objetos que serão criados no indicador, trabalhem da mesma forma como foi pensado no template.

No segundo caso, que se dá quando não estamos buscando as informações do template. Faremos o armazenamento local de tais valores. Isto agiliza bastante a execução posterior do código. Estas informações são armazenadas entre as linhas 62 a 64, podendo ser acessadas facilmente depois, como você poderá ver no decorrer da explicação.

A próxima coisa que temos é o procedimento visto na linha 68. Aqui a coisa começa a ficar mais interessante, isto por que agora temos outras informações que serão ajustadas neste procedimento. Por conta que antes tudo que era informado no indicador estava vindo do momento em que o usuário lançava o indicador no gráfico, não havia necessidade de tomar certas atitudes. Mas agora que podemos interagir diretamente com o indicador, precisamos garantir que os dados sejam de alguma forma representativos.

Por conta disto foi adicionado uma nova macro neste procedimento, esta pode ser vista na linha 82. O fato desta macro existir, faz com que a antiga função que ela representava deixa-se de existir. Além desta macro, você pode notar que o código passou por algumas mudanças, entre elas, temos agora a linha 90. Esta faz uso do procedimento visto acima, mas observem que estamos dizendo para o indicador capturar os parâmetros. Isto será feito, apenas e somente uma única vez. E o momento que será feito, é justamente quando o indicador está sendo iniciado. Detalhe: Existe uma segunda questão neste fato, mas isto será visto mais para frente neste artigo.

Feito isto, entre as linhas 92 e 94, ajustamos e corrigimos os valores que serão apresentados no indicador Chart Trade. Anteriormente isto era feito no constructor da classe, mas não havia nenhuma interação com o usuário. No entanto agora temos esta interação, e devido a isto, precisamos garantir que os valores sejam representativos. Desta forma ajustamos os valores aqui, no momento em que o template irá ser atualizado.

É importante que você esteja o tempo todo, ciente do seguinte fato: Não estamos de modo algum editado valores diretamente nos objetos, mesmo por que você terá apenas o OBJ_CHART no gráfico. Assim precisamos fazer com que o template, seja atualizado e apresentado no gráfico. Por este motivo é que a atualização terá que ser feita neste ponto.

As demais linhas, já foram explicadas no artigo anterior, Desenvolvendo um sistema de Replay (Parte 44): Projeto do Chart Trade (III), no entanto, na linha 105, fazemos algo que não estava presente antes aqui. Nesta linha corrigimos uma pequena falha, onde era possível arrastar a janela flutuante, clicando e arrastando o botão de maximizar e minimizar. Esta linha faz com que esta falha deixe de existir. Logo depois na linha 106, obtemos os valores que desejamos do template. Observem que agora informamos a chamada como sendo falsa. Assim os valores serão armazenados nos locais corretos, para uso posterior.

Na linha 108 temos algo engraçado, que é justamente o fato de que damos a capacidade da janela flutuante, ser maximizada ou minimizada. Isto antes era feito em outro ponto do código. Mas por motivos de praticidade, decidi colocar este controle aqui. Isto facilita muito as coisas em termos de modelagem, já que todas as coisas referentes a janela ficam todas no mesmo ponto.

Da mesma forma, as linhas 109 e 110, nos permite trabalhar de uma maneira mais conveniente com a janela flutuante. É muito comum, alguns usuários desejarem ter a janela flutuante em um dado ponto, dependendo do status da mesma. Ou seja quando ela se encontra maximizada, o usuário deseja a janela em uma posição, já quando ela esta minimizada, ele deseja ela em outro local. E é justamente isto que estas linhas 109 e 110 fazem. Elas posicionam a janela flutuante no último ponto onde ela se encontrava, dependendo do fato de ela estava maximizada ou minimizada.

A linha 112 já foi comentada no artigo anterior, então podemos ver as linhas 114 e 115, que antes se encontravam em um procedimento a parte. Pois bem na linha 114 lançamos o template, já modificado, no objeto OBJ_CHART. Assim quando a linha 115 for executada teremos a visualização e atualização do template no gráfico. O fato é que agora, todo o procedimento está concentrado nesta rotina. Então não precisaremos nos preocupar em informar coisas extras a fim de fazer com que os dados sejam informados ao usuário da maneira correta.

Talvez, mas ainda não é provável, este sistema venha a ser colocado em uma classe separada. Mas devido ao fato de ele está sendo usado apenas e somente no Chart Trade, irei deixa-lo aqui. Mas pode ser que seja interessante coloca-lo em uma outra classe. Isto devido ao fato de que eu decida tornar outras coisas um template. Mas por hora, irei manter o código assim.

Agora temos algo, um pouco diferente. Na linha 137, você pode ver um tipo de código pouco comum. Isto em grande parte das vezes. Mas este tipo de código é bastante comum, quando temos procedimentos idênticos, mas para tipos diferentes. E o que isto quer dizer 🤔 ?!?! Bem, primeiro é preciso entender o seguinte: Por que você precisa criar uma rotina para mostrar um valor double, uma outra para valores int e uma terceira para strings ?!?! Não seria muito mais simples criar uma única rotina, já que essencialmente o código previsto em todas seria sempre o mesmo ?!?!  A única diferença seria o fato de que em um o valor seria de um tipo ou de outro ?!?! Pois bem, é justamente isto que a linha 137 faz.

Mas espera um pouco. Se a ideia seria representar o valor. Não poderíamos simplesmente passar ele como sendo uma string diretamente ?!?! Sim. Poderíamos, mas existe uma coisa que você não está levando em conta. E se você desejar fazer com que o valor seja apresentado de uma maneira especifica, e fosse lançado de diversos pontos diferentes do código ?!?! Pense só no trabalho que você teria. Mas fazendo assim, podemos simplesmente informar o valor em seu tipo original. Deixar que o compilador crie a rotina para nos, e apresenta-lo como desejamos. Caso venhamos a mudar a apresentação, tudo que iriamos precisar, seria mudar apenas e somente um único ponto no código. O compilador é que ficaria com o trabalho de justar as coisas para nos. 

Trabalhe menos e produza mais.

Caso você, não faça assim, irá apenas aumentar o seu trabalho. Minha dica é: Procure sempre que possível, fazer com que o compilador, trabalhe para você. Você irá notar, que seus códigos ficarão bem mais simples de serem corrigidos, e sua produtividade irá aumentar exponencialmente.

Mas para que a linha 137 de fato faça algum sentido, é preciso fazer uso da mesma. Assim na linha 138 você pode notar como a linha 137 está sendo usada. Fora este ponto, você pode notar que em nenhum outro momento fazemos uso da linha 137. No entanto na linha 151, usamos o valor passado como parâmetro. Notem que faço a conversão explicita para o tipo string. Então apesar de podemos fazer a conversão durante a passagem, ou depois, isto não irá fazer diferença. Não neste caso especifico.

Agora prestem atenção a seguinte fato: Aqui, neste procedimento estamos criando um objeto extra, um OBJ_EDIT. Por que estamos fazendo isto ?!?! O motivo é facilitar a usabilidade do indicador Chart Trade. De fato não precisaríamos criar tal objeto. Mas isto deixaria o indicador difícil de ser utilizado. Não que seria complexo codificar a lógica necessária. Mas o usuário teria dificuldades em trabalhar e usar o indicador. Por este motivo, pedimos assistência ao MetaTrader 5, dizendo a ele para criar um objeto de edição.

Mas, porém, toda via e entretanto, precisamos que este objeto, esteja no local correto, com a formatação correta e no estilo correto. Isto é feito, fazendo o seguinte: Quando este procedimento é chamado, iremos remover, caso exista, o objeto de edição criado. Isto é feito na linha 141. Mas tem um detalhe, este objeto somente irá existir quando houver necessidade do mesmo. Então entre as linhas 142 e 150, iremos usar os valores que estão sendo definidos no template. Assim o objeto criado irá ser igual que está sendo usado no template.

Existe um detalhe que está presente nas linhas 143 e 144. Este é um pequeno ajuste onde somamos 3 as dimensões. Este valor não é por um acaso, ele é devido ao fato de que o OBJ_CHART, usa 3 pixels em suas bordas, e o objeto OBJ_EDIT terá que ser deslocado exatamente este 3 pixels. Assim ele ficará no local exato onde o template se encontra no gráfico.

Agora na linha 155, temos uma função que irá nos auxiliar no momento em que o indicador irá ser recolocado no gráfico. Atenção:Esta função não trabalha sozinha, ela trabalha em conjunto com uma outra, que será vista mais a frente. O que fazemos nesta função é o seguinte: Todos os dados, sensíveis do indicador será guardados e depois recuperados. Aqui fazemos a recuperação de tais dados. Existem diversas formas de se fazer isto, entre elas a que está sendo usada aqui. O fato de fazer desta maneira especifica, tem haver com o motivo de eu não querer usar DLL's sem uma real necessidade para isto. Então fazemos uso das variáveis globais de terminal, a fim que que o MetaTrader 5 possa nos auxiliar na transação.

Cada uma das linhas, entre elas: 160, 165, 170, 175,  177 e 178 irão recuperar os dados presentes nas variáveis globais de terminal. Tais variáveis são do tipo double, mas podemos armazenar valores diferentes nelas. Já demonstrei diversas vezes como fazer isto. Mas aqui fazemos de uma forma bem especifica. Então caso em alguma destas linhas indicadas, a variável global de terminal não possa ser acessada ou lida, iremos retornar um valor falso para o chamador. E o único ponto em que esta função será de fato chamada é no constructor, mas veremos isto em breve.

A cada chamada executada nas linhas informadas, iremos repor o valor anteriormente armazenado. Assim caso você mude o tempo gráfico, poderá continuar com o indicador Chart Trade, da mesma forma. Ou seja, seria como se ele não tivesse sofrido nenhum tipo de mudança. Aqui existe uma questão, que é mais de ordem pessoal do que prática em si. No entanto irei falar disto no momento que for feita a explicação sobre a forma de armazenar os dados.

Mas independentemente, se a leitura foi bem sucedida ou não. Na linha 180 iremos remover todas as variáveis globais de terminal, que estiverem ligadas ao indicador Chart Trade. Porém notem que pode haver mais destas mesmas variáveis presentes no MetaTrader 5. Para saber quais eliminar, usamos aquela macro, definida no inicio do código da classe,

Agora vamos para o constructor da classe. Este se inicia na linha 187, mas no entanto, o que merece explicação é justamente a interação que é feita na linha 192. Esta irá chamar o procedimento explicado acima. No entanto, se ele for mal sucedido, teremos a execução das linhas entre 194 e 200. Estas irão gerar os valores default do indicador Chart Trade. Mas já que o processo de remoção e recolocação do indicador, pelo motivo de troca de tempo gráfico, é algo muito rápido. É quase improvável que os valores a serem usados sejam os default. Mas pode acontecer, então é bom sempre ficar atento a isto.

Notem que diferente do que acontecia antes, agora os valores default, são lançados sem nenhum tipo de ajuste nos mesmos. Isto por que, agora que irá fazer tais ajuste é justamente o procedimento que atualiza o template.

Bem, mas vamos agora ver o que se passa no procedimento presente na linha 214. Neste ponto estaremos salvando temporariamente o status do indicador Chart Trade. Mas por que estamos fazendo isto ?!?! E por que estamos salvando este status nas variáveis globais de terminal ?!?! Não daria para fazer isto de outra maneira ?!?! Bem, vamos por partes.

Primeiro. Sim poderíamos fazer isto de outra maneira. Na verdade, existem diversas maneiras possíveis de se fazer isto. A questão, não é como guardar, mas sim como recuperar os dados armazenados. O fato de estamos usado as variáveis globais de terminal, se deve ao fato de que o acesso a elas é bem mais simples. Isto tendo em vista que em alguns casos seria mais complicado, não armazenar, mas sim recuperar os dados. Pensei seriamente em colocar os dados diretamente no template. Na verdade eles já estariam ali, salvo os dados relacionados a posição. Já que temos um posicionamento para a janela maximizada e um para minimizada.

O fato de termos esta diferença entre a posição maximizada e minimizada, torna a questão do uso do template complicada. Poderíamos também usar outros meios. Mas de qualquer forma, isto poderia complicar inutilmente o sistema. Não valendo assim o trabalho. Mais uma vez, os dados já estão sempre presentes no template. No entanto, quando a linha 209 fosse executada, ela irá remover o template, fazendo com que os dados desapareçam. Mesmo que você não use posicionamentos diferentes para a janela maximizada e para quando ela estivesse minimizada, teria problemas em resolver a questão da linha 209.

Uma solução para isto, seria colocar esta chamada que remove o template, no código fonte do indicador. Se isto fosse feito o código do indicador ficaria conforme mostrado logo abaixo:

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

E esta função RemoveTemplate, ter uma única chamada, que iria ser o que está na linha 209, do código da classe. Apesar disto funcionar relativamente bem, teríamos outros problemas. Um deles seria quando o indicador desse algum erro mais grave, o arquivo do mesmo não seria removido, permanecendo ainda no disco. Quando você tenta-se recolocar o indicador novamente no gráfico, os dados estariam incorretos, podendo fazer o indicador ser removido novamente. E as coisas ficariam desta maneira, até que você remove-se o arquivo defeituoso.

Por conta desta e de outas coisas, é que prefiro fazer uso das variáveis globais de terminal. Mas notem que não as estou usando diretamente. Para fazer uso delas, utilizo uma macro. Mas ai vem uma questão. Por que ?!?! O motivo é o tempo de vida da variável global de terminal.

Observe na macro, que está presente na linha 216, o que está acontecendo. Note, que primeiro tentamos criar, a variável como sendo uma variável global de terminal temporária. Isto faz com que caso o terminal MetaTrader 5, seja fechado, a variável seja destruída junto. Assim garantimos a integridade do indicador Chart Trade.

Observe que cada uma das variáveis globais de terminal, irá armazenar um valor. A ordem que você lança tais variáveis não importa. O que de fato importa é o nome e o valor. Lembrando que o nome não pode conter mais que 64 caracteres. Por isto que fazemos uso da macro para criar o nome, assim garantimos uma certa hegemonia na criação dos nomes.

Não há muito o que falhar sobre esta rotina de salvar os dados do template. O fato é que sem ela, cada vez que você modifica-se o tempo gráfico, teria que sempre se preocupar em reajustar os dados presentes no indicador. Já que muitos usuários, costumam trocar diversas vezes o tempo gráfico, ao longo do período de negociação, seria uma tremenda chatice ter que ficar toda hora ajustando os valores no indicador Chart Trade. Mas com o auxilio da programação e do MetaTrader 5, podemos deixar isto de lado, e focar em outras coisas. Mas para isto fazemos uso deste procedimento da linha 214.

Existe um outra forma de se manter as coisas, em "memória", mas não vou entrar em detalhes agora, pois envolve o trabalho com os objetos gráfico. E isto é assunto para um outro momento.

Muito bem, estamos praticamente terminando este artigo. Mas antes temos uma última coisa a ser vista. A função de tratamento de mensagens. Esta começa na linha 237, e ao contrário do que pode parecer. Ela é bem mais simpática e simples do que muitos imaginam. No entanto, você deve estar se perguntando: Mas por que esta rotina de tratamento de mensagens conta com 4 tipos de evento ?!?! Se na verdade iremos usar apenas o indicador de mouse ?!?!

Tenho reiterado o fato de que o MetaTrader 5, é uma plataforma baseada em eventos. Por conta disto, precisamos entender como trabalhar desta maneira. No artigo anterior, falei do fato de que poderíamos usar outros eventos, a fim de tornar a nossa lógica mais simples. Mesmo que o código presente lá, tenha ficado um pouco confuso em relação ao tratamento de determinados eventos. Ainda assim o mesmo é funcional. No entanto, podemos deixar grande parte dos testes, que precisam de fato estar presentes naquele código, visto no artigo anterior. Sendo feitos pelo MetaTrader 5. Desta maneira, se você comparar ambos os códigos da classe, irá notar que este daqui, contém menos testes. Mas por que ?!?!

O motivo é que estes testes estarão sendo feitos pelo MetaTrader 5. Assim aqueles eventos de clicar em um objeto no Chart Trade, agora foi substituído por uma versão onde analisamos o clique em um objeto, e não mais o clique do indicador de mouse. Isto facilita bastante a codificação. Assim conseguimos colocar mais eventos, em um código mais legível. Você pode ver a questão dos cliques, ao olhar o código presente entre as linhas 315 e 343. Ali estamos tratando de clique em todos os objetos presentes no template. Todos. Inclusive os que ainda não tem rotinas relacionadas a eles. Como é o caso dos botões de compra, venda e encerramento de posição.

Uma das questões, que merece algum destaque aqui no tratador de mensagens, é o evento CHARTEVENT_CHART_CHANGE, presente na linha 258. Existe um detalhe, que é quando o terminal sofre alguma mudança nas suas dimensões. Quando isto ocorre o MetaTrader 5, lança um evento informado isto ao nossos programas. Este evento é tratado pelo CHARTEVENT_CHART_CHANGE, assim podemos verificar se a janela flutuante ainda permanece visível no gráfico. Caso não tratemos este evento, poderia acontecer da janela ficar oculta, mas o indicador ainda permanece-se ativo. Já que este tratamento é igual tanto para o caso da janela esta minimizada, quanto para o modo maximizado. Faço uso de uma macro para efetuar os ajustes necessários. Assim se ocorrer qualquer mudança que necessite de reposicionar a janela adequadamente, a linha 265 irá fazer isto para nos.

O outro evento que também merece algum destaque é o CHARTEVENT_OBJECT_ENDEDIT. Neste caso sempre que o MetaTrader 5, notar que o objeto OBJ_EDIT teve sua edição encerrada, ele irá lançar um evento. Desta maneira podemos atualizar os dados diretamente no template. Isto é feito na linha 309. Mas atenção, esta atualização faz com que os dados venham a ser modificados, de maneira a ser de alguma forma representativos. Ou seja, se você tentar colocar um valor, ou quantidade que não se adeque ao ativo, o código irá fazer com que o valor passe a se adequar. Assim evitamos contradições e problemas futuros.


Conclusão

Apesar de toda a complicação que possa estar envolvida na criação do Chart Trade, frente ao que foi visto no passado. Esta versão daqui é consideravelmente muito mais estável e escalonável do que era na versão antiga. Apesar de manter grande parte do princípio que foi apresentando lá atrás, aqui a ideia de fato é criar um sistema mais modular. Visto que temos agora, além do mercado real e da conta demo, um sistema de simulação e replay de mercado. Este exige que o sistema seja criado de forma totalmente diferente. Caso isto não seja feito de maneira adequada, teremos grandes problemas em trabalhar com as mesmas ferramentas, em sistemas tão diversos e mercados tão diferentes.

Mesmo que o indicador Chart Trade, ainda não esteja 100% funcional, devido a ausência de funcionalidades dos botões de compra, venda e fechar posição. A essência do código já está bem encaminhada. Iremos voltar a este indicador em breve, para fazer tais botões funcionarem. Mas por hora, o indicador já se adequa ao que está sendo esperado.

Admito que muitos podem se encontrar chateados por não ter acesso aos anexos. Mas tenho motivos para fazer isto. Quero que você veja, leia, compreenda o código e o sistema. Notei ao logo do tempo, que muitos de fato não leem os artigos, ou entendem o que estão usando. Isto é perigoso e não é a melhor forma de se usar de fato algo. Mesmo que não pareça, todo o código está sendo postado e colocado no artigo. É tudo uma questão de você entender e edita-lo no MetaEditor. Assim terei a certeza de que ele não será usado, sem que a pessoa saiba do que está sendo feito.


Arquivos anexados |
Indicators.zip (149.46 KB)
Funcionalidades do assistente MQL5 que você precisa conhecer (Parte 07): Dendrogramas Funcionalidades do assistente MQL5 que você precisa conhecer (Parte 07): Dendrogramas
A classificação de dados para análise e previsão é uma área muito diversificada do aprendizado de máquina, que compreende um grande número de abordagens e métodos. Neste artigo, examinaremos uma dessas abordagens, nomeadamente o agrupamento hierárquico aglomerativo (Agglomerative Hierarchical Clustering).
Adicionando um LLM personalizado a um robô investidor (Parte 2): Exemplo de implementação de ambiente Adicionando um LLM personalizado a um robô investidor (Parte 2): Exemplo de implementação de ambiente
Os modelos de linguagem (LLMs) são uma parte importante da inteligência artificial que evolui rapidamente. E para aproveitar isso devemos pensar em como integrar LLMs avançados em nossa negociação algorítmica Muitos acham desafiador ajustar esses modelos de acordo com suas necessidades, implantá-los localmente e, logo, aplicá-los à negociação algorítmica. Esta série de artigos explorará uma abordagem passo a passo para alcançar esse objetivo.
Redes neurais de maneira fácil (Parte 61): O problema do otimismo no aprendizado por reforço off-line Redes neurais de maneira fácil (Parte 61): O problema do otimismo no aprendizado por reforço off-line
Durante o aprendizado off-line, otimizamos a política do Agente com base nos dados da amostra de treinamento. A estratégia resultante confere ao Agente confiança em suas ações. Mas, essa confiança nem sempre é justificada, já que pode acarretar maiores riscos durante a utilização prática do modelo. Hoje vamos examinar um dos métodos para reduzir esses riscos.
Permutação das barras de preços no MQL5 Permutação das barras de preços no MQL5
Neste artigo, apresentamos um algoritmo de permutação das barras de preços e detalhamos como os testes de permutação podem ser usados para identificar casos em que o desempenho de uma estratégia é inventado com o objetivo de enganar potenciais compradores de Expert Advisors.