
Desenvolvendo um sistema de Replay (Parte 75): Um novo Chart Trade (II)
Introdução
No artigo anterior Desenvolvendo um sistema de Replay (Parte 74): Um novo Chart Trade (I), fiquei basicamente explicando sobre o código do indicador Chart Trade. Expliquei os motivos pelos quais você deveria utilizar, este ou aquele modo de programar o Chart Trade. Expliquei algumas coisas relacionadas ao código, mas ficou faltando falar e explicar o código principal.
Um dos motivos, de ter ficado faltando mostrar o código principal, é o fato de que ele teve mais de 100 linhas removidas do mesmo. Então fiquei pensando em uma forma, prática e simples de mostrar o que aconteceu no código. A melhor forma que encontrei, é a que será apresentada neste artigo.
Então aqui vamos ver como é o código principal do Chart Trade. Mas você deve ter em mente, que se desejar, poderá colocar este código diretamente em um Expert Advisor. Claro que fazendo algumas poucas mudanças. Estas serão explicadas no momento adequado durante este artigo. Mas não se esqueça dos motivos, explicados no artigo anterior, em se colocar o código em um indicador e não em um Expert Advisor. Mas você é livre para utilizar o código da melhor forma que lhe for conveniente.
Então, sem mais delongas vamos para o tópico do código.
Entendendo o código fonte da classe C_ChartFloatingRAD
O código da classe C_ChartFloatingRAD, se encontra no arquivo de cabeçalho com o mesmo nome. E este código pode ser visto, praticamente na íntegra logo abaixo. A única coisa que estará faltando é o procedimento DispatchMessage.
001. //+------------------------------------------------------------------+ 002. #property copyright "Daniel Jose" 003. //+------------------------------------------------------------------+ 004. #include "../Auxiliar/C_Mouse.mqh" 005. #include "C_AdjustTemplate.mqh" 006. //+------------------------------------------------------------------+ 007. #define macro_NameGlobalVariable(A) StringFormat("ChartTrade_%u%s", GetInfoTerminal().ID, A) 008. #define macro_CloseIndicator(A) { \ 009. OnDeinit(REASON_INITFAILED); \ 010. SetUserError(A); \ 011. return; \ 012. } 013. //+------------------------------------------------------------------+ 014. class C_ChartFloatingRAD : private C_Terminal 015. { 016. private : 017. 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}; 018. struct st00 019. { 020. short x, y, minx, miny, 021. Leverage; 022. string szObj_Chart, 023. szObj_Editable, 024. szFileNameTemplate; 025. long WinHandle; 026. double FinanceTake, 027. FinanceStop; 028. bool IsMaximized, 029. IsDayTrade, 030. IsSaveState; 031. struct st01 032. { 033. short x, y, w, h; 034. color bgcolor; 035. int FontSize; 036. string FontName; 037. }Regions[MSG_NULL]; 038. }m_Info; 039. C_Mouse *m_Mouse; 040. //+------------------------------------------------------------------+ 041. void CreateWindowRAD(int w, int h) 042. { 043. m_Info.szObj_Chart = "Chart Trade IDE"; 044. m_Info.szObj_Editable = m_Info.szObj_Chart + " > Edit"; 045. ObjectCreate(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJ_CHART, 0, 0, 0); 046. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, m_Info.x); 047. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, m_Info.y); 048. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XSIZE, w); 049. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YSIZE, h); 050. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_DATE_SCALE, false); 051. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_PRICE_SCALE, false); 052. m_Info.WinHandle = ObjectGetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_CHART_ID); 053. }; 054. //+------------------------------------------------------------------+ 055. void AdjustEditabled(C_AdjustTemplate &Template, bool bArg) 056. { 057. for (eObjectsIDE c0 = 0; c0 <= MSG_STOP_VALUE; c0++) 058. if (bArg) 059. { 060. Template.Add(EnumToString(c0), "bgcolor", NULL); 061. Template.Add(EnumToString(c0), "fontsz", NULL); 062. Template.Add(EnumToString(c0), "fontnm", NULL); 063. } 064. else 065. { 066. m_Info.Regions[c0].bgcolor = (color) StringToInteger(Template.Get(EnumToString(c0), "bgcolor")); 067. m_Info.Regions[c0].FontSize = (int) StringToInteger(Template.Get(EnumToString(c0), "fontsz")); 068. m_Info.Regions[c0].FontName = Template.Get(EnumToString(c0), "fontnm"); 069. } 070. } 071. //+------------------------------------------------------------------+ 072. inline void AdjustTemplate(const bool bFirst = false) 073. { 074. #define macro_PointsToFinance(A) A * (GetInfoTerminal().VolumeMinimal + (GetInfoTerminal().VolumeMinimal * (m_Info.Leverage - 1))) * GetInfoTerminal().AdjustToTrade 075. 076. C_AdjustTemplate *Template; 077. 078. if (bFirst) 079. { 080. Template = new C_AdjustTemplate(m_Info.szFileNameTemplate = IntegerToString(GetInfoTerminal().ID) + ".tpl", true); 081. for (eObjectsIDE c0 = 0; c0 <= MSG_CLOSE_POSITION; c0++) 082. { 083. (*Template).Add(EnumToString(c0), "size_x", NULL); 084. (*Template).Add(EnumToString(c0), "size_y", NULL); 085. (*Template).Add(EnumToString(c0), "pos_x", NULL); 086. (*Template).Add(EnumToString(c0), "pos_y", NULL); 087. } 088. AdjustEditabled(Template, true); 089. }else Template = new C_AdjustTemplate(m_Info.szFileNameTemplate); 090. if (_LastError >= ERR_USER_ERROR_FIRST) 091. { 092. delete Template; 093. 094. return; 095. } 096. m_Info.Leverage = (m_Info.Leverage <= 0 ? 1 : m_Info.Leverage); 097. m_Info.FinanceTake = macro_PointsToFinance(FinanceToPoints(MathAbs(m_Info.FinanceTake), m_Info.Leverage)); 098. m_Info.FinanceStop = macro_PointsToFinance(FinanceToPoints(MathAbs(m_Info.FinanceStop), m_Info.Leverage)); 099. (*Template).Add("MSG_NAME_SYMBOL", "descr", GetInfoTerminal().szSymbol); 100. (*Template).Add("MSG_LEVERAGE_VALUE", "descr", IntegerToString(m_Info.Leverage)); 101. (*Template).Add("MSG_TAKE_VALUE", "descr", DoubleToString(m_Info.FinanceTake, 2)); 102. (*Template).Add("MSG_STOP_VALUE", "descr", DoubleToString(m_Info.FinanceStop, 2)); 103. (*Template).Add("MSG_DAY_TRADE", "state", (m_Info.IsDayTrade ? "1" : "0")); 104. (*Template).Add("MSG_MAX_MIN", "state", (m_Info.IsMaximized ? "1" : "0")); 105. if (!(*Template).Execute()) 106. { 107. delete Template; 108. 109. macro_CloseIndicator(C_Terminal::ERR_FileAcess); 110. }; 111. if (bFirst) 112. { 113. for (eObjectsIDE c0 = 0; c0 <= MSG_CLOSE_POSITION; c0++) 114. { 115. m_Info.Regions[c0].x = (short) StringToInteger((*Template).Get(EnumToString(c0), "pos_x")); 116. m_Info.Regions[c0].y = (short) StringToInteger((*Template).Get(EnumToString(c0), "pos_y")); 117. m_Info.Regions[c0].w = (short) StringToInteger((*Template).Get(EnumToString(c0), "size_x")); 118. m_Info.Regions[c0].h = (short) StringToInteger((*Template).Get(EnumToString(c0), "size_y")); 119. } 120. m_Info.Regions[MSG_TITLE_IDE].w = m_Info.Regions[MSG_MAX_MIN].x; 121. AdjustEditabled(Template, false); 122. }; 123. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YSIZE, (m_Info.IsMaximized ? 210 : m_Info.Regions[MSG_TITLE_IDE].h + 6)); 124. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, (m_Info.IsMaximized ? m_Info.x : m_Info.minx)); 125. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, (m_Info.IsMaximized ? m_Info.y : m_Info.miny)); 126. 127. delete Template; 128. 129. ChartApplyTemplate(m_Info.WinHandle, "/Files/" + m_Info.szFileNameTemplate); 130. ChartRedraw(m_Info.WinHandle); 131. 132. #undef macro_PointsToFinance 133. } 134. //+------------------------------------------------------------------+ 135. eObjectsIDE CheckMousePosition(const short x, const short y) 136. { 137. int xi, yi, xf, yf; 138. 139. for (eObjectsIDE c0 = 0; c0 <= MSG_CLOSE_POSITION; c0++) 140. { 141. xi = (m_Info.IsMaximized ? m_Info.x : m_Info.minx) + m_Info.Regions[c0].x; 142. yi = (m_Info.IsMaximized ? m_Info.y : m_Info.miny) + m_Info.Regions[c0].y; 143. xf = xi + m_Info.Regions[c0].w; 144. yf = yi + m_Info.Regions[c0].h; 145. if ((x > xi) && (y > yi) && (x < xf) && (y < yf)) return c0; 146. } 147. return MSG_NULL; 148. } 149. //+------------------------------------------------------------------+ 150. inline void DeleteObjectEdit(void) 151. { 152. ChartRedraw(); 153. ObjectsDeleteAll(GetInfoTerminal().ID, m_Info.szObj_Editable); 154. } 155. //+------------------------------------------------------------------+ 156. template <typename T > 157. void CreateObjectEditable(eObjectsIDE arg, T value) 158. { 159. long id = GetInfoTerminal().ID; 160. 161. DeleteObjectEdit(); 162. CreateObjectGraphics(m_Info.szObj_Editable, OBJ_EDIT, clrBlack, 0); 163. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_XDISTANCE, m_Info.Regions[arg].x + m_Info.x + 3); 164. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_YDISTANCE, m_Info.Regions[arg].y + m_Info.y + 3); 165. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_XSIZE, m_Info.Regions[arg].w); 166. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_YSIZE, m_Info.Regions[arg].h); 167. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_BGCOLOR, m_Info.Regions[arg].bgcolor); 168. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_ALIGN, ALIGN_CENTER); 169. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_FONTSIZE, m_Info.Regions[arg].FontSize - 1); 170. ObjectSetString(id, m_Info.szObj_Editable, OBJPROP_FONT, m_Info.Regions[arg].FontName); 171. ObjectSetString(id, m_Info.szObj_Editable, OBJPROP_TEXT, (typename(T) == "double" ? DoubleToString(value, 2) : (string) value)); 172. ChartRedraw(); 173. } 174. //+------------------------------------------------------------------+ 175. bool RestoreState(void) 176. { 177. uCast_Double info; 178. bool bRet; 179. C_AdjustTemplate *Template; 180. 181. if (bRet = GlobalVariableGet(macro_NameGlobalVariable("POST"), info.dValue)) 182. { 183. m_Info.x = (short) info._16b[0]; 184. m_Info.y = (short) info._16b[1]; 185. m_Info.minx = (short) info._16b[2]; 186. m_Info.miny = (short) info._16b[3]; 187. Template = new C_AdjustTemplate(m_Info.szFileNameTemplate = IntegerToString(GetInfoTerminal().ID) + ".tpl"); 188. if (_LastError >= ERR_USER_ERROR_FIRST) bRet = false; else 189. { 190. (*Template).Add("MSG_LEVERAGE_VALUE", "descr", NULL); 191. (*Template).Add("MSG_TAKE_VALUE", "descr", NULL); 192. (*Template).Add("MSG_STOP_VALUE", "descr", NULL); 193. (*Template).Add("MSG_DAY_TRADE", "state", NULL); 194. (*Template).Add("MSG_MAX_MIN", "state", NULL); 195. if (!(*Template).Execute()) bRet = false; else 196. { 197. m_Info.IsDayTrade = (bool) StringToInteger((*Template).Get("MSG_DAY_TRADE", "state")) == 1; 198. m_Info.IsMaximized = (bool) StringToInteger((*Template).Get("MSG_MAX_MIN", "state")) == 1; 199. m_Info.Leverage = (short)StringToInteger((*Template).Get("MSG_LEVERAGE_VALUE", "descr")); 200. m_Info.FinanceTake = (double) StringToDouble((*Template).Get("MSG_TAKE_VALUE", "descr")); 201. m_Info.FinanceStop = (double) StringToDouble((*Template).Get("MSG_STOP_VALUE", "descr")); 202. } 203. }; 204. delete Template; 205. }; 206. 207. GlobalVariablesDeleteAll(macro_NameGlobalVariable("")); 208. 209. return bRet; 210. } 211. //+------------------------------------------------------------------+ 212. public : 213. //+------------------------------------------------------------------+ 214. C_ChartFloatingRAD(string szShortName, C_Mouse *MousePtr, const short Leverage, const double FinanceTake, const double FinanceStop) 215. :C_Terminal(0) 216. { 217. m_Mouse = MousePtr; 218. m_Info.IsSaveState = false; 219. if (!IndicatorCheckPass(szShortName)) return; 220. if (!RestoreState()) 221. { 222. m_Info.Leverage = Leverage; 223. m_Info.IsDayTrade = true; 224. m_Info.FinanceTake = FinanceTake; 225. m_Info.FinanceStop = FinanceStop; 226. m_Info.IsMaximized = true; 227. m_Info.minx = m_Info.x = 115; 228. m_Info.miny = m_Info.y = 64; 229. } 230. CreateWindowRAD(170, 210); 231. AdjustTemplate(true); 232. } 233. //+------------------------------------------------------------------+ 234. ~C_ChartFloatingRAD() 235. { 236. ChartRedraw(); 237. ObjectsDeleteAll(GetInfoTerminal().ID, m_Info.szObj_Chart); 238. if (!m_Info.IsSaveState) 239. FileDelete(m_Info.szFileNameTemplate); 240. 241. delete m_Mouse; 242. } 243. //+------------------------------------------------------------------+ 244. void SaveState(void) 245. { 246. #define macro_GlobalVariable(A, B) if (GlobalVariableTemp(A)) GlobalVariableSet(A, B); 247. 248. uCast_Double info; 249. 250. info._16b[0] = m_Info.x; 251. info._16b[1] = m_Info.y; 252. info._16b[2] = m_Info.minx; 253. info._16b[3] = m_Info.miny; 254. macro_GlobalVariable(macro_NameGlobalVariable("POST"), info.dValue); 255. m_Info.IsSaveState = true; 256. 257. #undef macro_GlobalVariable 258. } 259. //+------------------------------------------------------------------+ 260. void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) 261. { .... The internal code of this procedure will be seen in the next article 386. } 387. //+------------------------------------------------------------------+ 388. }; 389. //+------------------------------------------------------------------+ 390. #undef macro_NameGlobalVariable 391. #undef macro_CloseIndicator 392. //+------------------------------------------------------------------+
Código fonte do arquivo C_ChartFloatingRAD.mqh
Este código fonte, já se encontra sem as linhas, que foram removidas do código original. Assim como também, já contém as mudanças necessárias para que as coisas funcionem de forma como seria esperado. Já que acredito que muitos não tenham visto o código original. Quero que se atentem as explicações que serão dadas, para entender como este código acima, funciona. Mas principalmente, como ele consegue fazer com que o Chart Trade trabalhe e seja criado. Pois se você olhar e procurar, não irá de fato conseguir, encontrar os elementos que são vistos no Chart Trade. Então como isto é possível? Como um código que não contem, praticamente nenhum elemento gráfico, consegue exibir elementos gráficos? Que tipo de mágica, ou magia está sendo feita aqui?
Bem, meu caro leitor, não é magia. É programação e uso de diversas técnicas diferentes. Mas que no final garante que o Chart Trade seja apresentado da maneira correta. Mas o principal, faz com que ele seja funcional e o mais seguro e estável quanto for possível.
Na versão original, existiam algumas coisas que eram públicas. Tais como estruturas e a enumeração que é vista na linha 17.Mas já havia o cuidado de não deixar variáveis vazarem do código. Então o encapsulamento já era uma medida tomada e adotada. Mas então por que motivo agora não temos mais aquelas mesmas coisas públicas? O motivo é que a ideia é gerar um protocolo e fazer uso do mesmo. Mas sem de fato necessitar da classe C_ChartFloatingRAD para decodificar os dados. Iremos de fato ver isto, mais a frente neste artigo.
Tudo, absolutamente tudo que precisamos neste código em termos de variáveis, está declarado dentro da estrutura que se inicia na linha 18. Agora preste bastante atenção, aos tipos que estão sendo usados. Observe que em sua grande maioria, não estamos fazendo uso de tipos de 32 bits. Ou para melhor entender, tipos do grupo INT. Mas por que? Mesmo as variáveis, que sabiamente serão usadas como coordenadas de tela, são do tipo 16 bits, ou do grupo SHORT.
Diferente do que muitos costumam fazer, ao colocar tais variáveis como o tipo padrão INT, não vejo necessidade de tal coisa. No caso de resolução de tela, um valor de 16 bits já consegue dar conta da atual tecnologia. O valor máximo de 65535, é mais do que o suficiente para plotagem de uma tela de 4K de resolução. Para dizer a verdade tal valor conseguiria tranquilamente plotar coordenadas em uma tela de 8K ou até mesmo maior do que isto. Então não vejo motivo para usar um tipo INT aqui. Mesmo por que usar o tipo SHORT, nos permite compactar as coisas como será visto depois.
Então explicado este pequeno detalhe, você pode ver que na linha 31 temos uma outra estrutura, interna a primeira. Muito bem, esta estrutura interna, conterá a posição relativa aos elementos gráficos. Tais elementos são parte integrante do Chart Trade, com os quais o usuário irá de fato interagir.
Existem duas macros aqui, logo no início do código. Não se preocupe por hora com elas. Apenas saiba que elas existem. Mas o principal, é você saber onde elas estão declaradas. Pois durante o código iremos de fato fazer uso destas macros. Talvez a que lhe deixe mais desconfortável no momento, seja a macro que está sendo definida na linha oito. Mas logo chegaremos a entender, o que está macro na verdade faz.
De qualquer forma, tudo se resume a isto. Na linha 14, herdamos de forma privativa a classe C_Terminal. De forma a expandir as funcionalidades desta a fim de criar o Chart Trade. Entre as linhas 20 e 39, temos as declarações das variáveis internas, ou seja, privativas da classe. Assim, agora podemos entrar na parte, onde o código será descrito. Para simplificar, vamos ver função, por função conforme elas aparecem no código. Começando com o procedimento CreateWindowRAD, que é declarado na linha 41.
Este procedimento é chamado apenas e somente, pela linha 230. Não existe nenhum outro ponto, do qual este procedimento é chamado. E o que este procedimento faz é muito simples. Ele cria um objeto OBJ_CHAT no gráfico. Apenas isto. Mas por que colocar um objeto do tipo OBJ_CHAT no gráfico? O motivo é que assim não precisaremos criar todos os objetos. Este tipo de coisa, pode parecer bastante confusa, para quem está acostumado a desenhar no gráfico usando código. Mas é algo que já expliquei em outros artigos no passado. No final neste artigo, deixarei alguns artigos meus, como uma forma de você estudar isto com mais calma. Neles foi explicado como e por que fazer isto. Caso você deseje e sinta que o tema não foi completamente compreendido, aqui neste artigo. Pode usar as referências como um bom suporte.
Mas a parte realmente importante para nosso trabalho, é justamente a linha 52. Nela armazenamos o valor da ID que o MetaTrader 5 nos informar, assim que o objeto OBJ_CHART for criado. Precisamos guardar esta informação, pois ela será importante para nós. Dito tais coisas, podemos passar para o próximo procedimento na lista. Este é o AdjustEditabled, que se inicia na linha 55. O que este procedimento faz? Por mais estranho que possa parecer, este procedimento, serve para ajustar e capturar o status dos objetos. Justamente os objetos que serão apresentados no OBJ_CHAT. Mas como assim? Para entender como isto funciona, é preciso compreender em minucias como o procedimento AdjustTemplate funciona. Pois é justamente ali, que o AdjustEditabled é usado. Então vamos entender, o que acontece entre as linhas 72 e 133. Este é um dos procedimentos mais complicados desta classe. Já que aqui é onde a mágica realmente acontece.
Na linha 74, definimos uma macro que será usada apenas neste procedimento. Observe que no final no procedimento, isto na linha 132, esta mesma macro é removida, não podendo mais ser usada. Já na linha 78, testamos o que iremos de fato fazer. Se a ideia é criar o Chart Trade, este teste passará, e teremos toda uma série de coisas a fazer. Caso o Chart Trade já exista, iremos de fato executar a linha 89. Agora é preciso que você recorra ao artigo anterior. Isto para que possa entender o tipo de coisa a ser feita no template. Já que de qualquer forma, tanto a linha 80, quanto a linha 89 iniciarão a construção do template. Mas o que de fato será feito dependerá da linha 78.
Agora vem a primeira das partes complicadas. Caso estejamos criando o template, o laço na linha 81, criará uma preparação a fim de sabermos onde os objetos estão. Faremos uso desta mesma técnica depois. Mas que objetos são estes? Os objetos que serão colocados no Chart Trade. Note que não sabemos onde eles estão. Mas sabemos quantos objetos são. Isto por conta da enumeração que foi feita na linha 17. Agora na linha 88, chamamos o procedimento AdjustEditabled, de forma que o teste na linha 58 seja verdadeiro. Isto irá de fato fazer com que adicionemos mais coisas a serem obtidas do template.
Assim se a classe C_AdjustTemplate, obteve sucesso, a linha 90 permitirá que o código continue. Caso falhe, faremos com que tudo retorne ao código chamador. Este pode ser visto no artigo anterior. Mas calma, até este ponto, não fizemos absolutamente nada. Tudo que foi feito até esta linha 90, foi pedir para que a classe C_AdjustTemplate, conseguisse abrir o arquivo de template para nós. Nada mais do que isto.
Mas entre as linhas 96 e 98, ajustamos alguns dados que serão apresentados. Logo depois entre as linhas 99 e 104, adicionamos algumas coisas que serão ajustadas na chamada da linha 105. Neste exato momento a mágica acontece. Para entender, volte ao artigo anterior e veja a função Execute da classe C_AdjustTemplate. O que estaremos de fato fazendo, neste momento é modificando os valores que originalmente se encontravam no arquivo template. Mas não iremos de fato mudar os valores, estaremos acessando uma cópia deste arquivo. Por isto é que fazemos o teste na linha 78. Sem fazer aquele teste, não saberíamos qual arquivo modificar nesta linha 105.
Não sei se você, aspirante a programador, conseguiu de fato entender o que está acontecendo. Mas vou tentar explicar. Tudo que foi feito até aqui, entre as linhas 78 e 104, geram dados para que a classe C_AdjustTemplate, modifique o arquivo que contém o Chart Trade. Qualquer informação que você vier a visualizar no Chart Trade, é colocada lá por conta das linhas 99 a 104. Parece estanho, mas funciona.
Então minha dica é: Estude esta região do código para entender como isto realmente funciona. Pois todos os objetos são criados e manipulados da mesma forma.
Muito bem, vou considerar que você conseguiu entender o que aconteceu até a linha 105. Caso tenhamos sucesso, o código prosseguirá sua execução. Caso falhe, teremos algo que não é muito comum de ser observado. Então mais uma vez, preste atenção, ao que irei de fato explicar. Pois é importante.
Se a chamada da linha 105 falhar, temos que destruir o template e encerrar o Chart Trade. Destruir o template é simples, para isto usamos a linha 107. Quanto a isto não há mistérios. Mas isto não removerá o indicador do gráfico. Para fazer isto temos que chamar o procedimento OnDeInit. Agora vem a parte complicada, que você precisa prestar atenção. Então vamos ver o fragmento de código OnDeInit. Este pode ser visto logo abaixo:
41. void OnDeinit(const int reason) 42. { 43. switch (reason) 44. { 45. case REASON_INITFAILED: 46. ChartIndicatorDelete(ChartID(), 0, def_ShortName); 47. break; 48. case REASON_CHARTCHANGE: 49. (*chart).SaveState(); 50. break; 51. } 52. 53. delete chart; 54. }
Fragmento do código do indicador Chart Trade
Este fragmento está aqui apenas para facilitar a explicação. Então vamos entender o seguinte: Quando a linha 109 for executada, você cairá no código da macro. Esta pode ser vista no início do código na linha oito. Nesta macro, temos a linha nove, que ao executar, irá de fato estar executado o conteúdo da linha 46 do fragmento.
Ao mesmo tempo teremos a execução da linha 53 do fragmento, o que irá de fato garantir que o indicador Chart Trade seja removido. Porém o código retornará e a linha dez da macro será executada. Isto garantirá que teremos a marcação de erro, impedindo que o código continue posteriormente. Então na linha 11 retornamos ao chamador. Não importa quem chamou o procedimento AdjustTemplate. Se a modificação do template, não poder ser executada, o indicador será removido sem falhas adicionais. Esta é uma das partes complicadas deste sistema. Mas ainda não acabou, temos outras coisas ainda a serem vistas.
Agora suponhamos que a modificação do template, tenha ocorrido com sucesso. Neste caso faremos um novo teste na linha 111. Isto para capturar as posições dos objetos clicáveis. Este tipo de coisa só é feito, apenas e somente durante a criação do template. Então o laço da linha 113 faz justamente isto. Ele captura onde estão os objetos clicáveis, e as linhas 120 e 121 complementam esta captura.
A próxima coisa que fazemos é posicionar o objeto OBJ_CHAT no gráfico. Isto é feito entre as linhas 123 e 125. Já a linha 127, encerra a manipulação do template. Nos permitindo assim, fazer com que a linha 129 diga ao OBJ_CHAT, qual template usar e a linha 130 forçamos a atualização do conteúdo do objeto OBJ_CHAT. Com isto finalizamos a construção de tudo dentro do objeto OBJ_CHAT, e todos os objetos são apresentados, construindo assim o Chart Trade.
Se você não conseguiu entender como o template pode ser atualizado, a ponto de você não precisar programar o Chart Trade, via código. Reveja todo este código AdjustTemplate. Pois é nele que controla e mostra o Chart Trade. Todos os objetos que aparecem no Chart Trade, estão sendo criados, posicionados e ajustados neste procedimento.
Não adianta você querer vasculhar o código, em busca de objetos como botões, ícones, imagens ou qualquer outra coisa. Pois eles não existem em forma de código. O que o código faz é procurar onde os objetos estão, e tornar tais objetos acessíveis ao usuário. Não procure entender a criação convencional de objetos via código. Aqui estou fazendo exatamente o contrário. Primeiro crio a aparência que desejo, e logo depois peço ao código para tornar aquele conceito funcional. Sem entender esta ideia, você irá de fato ficar totalmente perdido.
A coisa aqui é tão, mas tão elaborada, que você pode mudar a forma, a disposição e até mesmo as fontes dos objetos, sem precisar codificar nenhuma única linha se quer. Tudo que será preciso fazer, será abrir o MetaTrader 5, carregar o template do Chart Trade e mudar como o mesmo irá de fato ser apresentado no gráfico. Todo o restante, é feito justamente por este procedimento AdjustTemplate.
Mas como sempre temos algo para complicar a nossa vida. Assim precisamos de mais procedimentos, para dar suporte a este conceito de aplicação RAD ( Rápido Desenvolvimento de Aplicações ). Desta forma, a próxima coisa a ser vista é a função CheckMousePosition, presente na linha 135. Esta função é muito simples e bastante direta. Ela irá só e tão somente, testar se o mouse se encontra dentro de algum dos objetos clicáveis ou selecionáveis. Se isto for verdadeiro, a linha 145 retornará o objeto em questão. Caso seja falso, a linha 147 irá de fato reportar que o mouse não se encontra, dentro de um objeto que possa receber um clique ou que seja selecionável.
Agora temos dois procedimentos em sequência, que servem para dar suporte a algo que não temos, como trabalhar de outra forma. Pois sim, existe um caso específico, em que o procedimento AdjustTemplate, não consegue suprir sozinho com qualidade. Tal caso se trata do objeto OBJ_EDIT. Ou um objeto, onde podemos permitir ao usuário inserir um texto qualquer.
Pois bem, o procedimento na linha 150, serve apenas para remover os objetos OBJ_EDIT, que vierem a ser criados. Já o procedimento definido na linha 156, irá de fato criar um e somente um OBJ_EDIT, para que o usuário venha a conseguir interagir, ou melhor, introduzir um valor no Chart Trade.
Talvez a declaração do procedimento CreateObjectEditable, possa lhe parecer estranho. Mas isto não tem nada de fantástico ou extraordinário. A declaração apenas cria uma sobrecarga na chamada, permitindo que a linha 171, possa fazer com que OBJ_EDIT, se adéque ao tipo de variável que será editada. Ou seja, caso venhamos a ter um valor do tipo double, teremos um valor com duas casas decimais, caso contrário, o valor será tratado como sendo uma string. E sendo este o caso, o texto apresentado será integral, da mesma forma como foi montado pelo chamador.
Basicamente não existe nenhum tipo de complicação, ou dificuldade aqui. Não para quem já esteja acostumado a programar em MQL5. Já que tudo que está sendo feito, é de amplo conhecimento de todos, até mesmo de quem tem pouca experiência em MQL5, e no trato de objetos.
Sendo assim, podemos passar para a próxima função: RestoreState, que se encontra declarada na linha 175 e implementada até a linha 210. Este procedimento não trabalha sem ajuda. Ele precisa de outro procedimento, SaveState que se encontra presente na linha 244. Mas tanto um quanto o outro, fogem completamente as regras. Isto por que ambos trabalham em conjunto e tem como finalidade, armazenar de forma temporária, informações básicas. Tais informações são referentes, a última posição conhecida do Chart Trade. Para ser mais correto, a informação, na verdade se refere ao local, onde o objeto OBJ_CHAT, se encontrava pela última vez. Isto antes do gráfico ser atualizado.
Para armazenar tais informações recorremos as variáveis globais de terminal. Agora repare que usamos apenas uma única variável global de terminal para armazenar os valores. Porém quero que você preste atenção a um outro fato, que também é importante. Observe que na linha 187, estamos novamente usando a classe C_AdjustTemplate. Mas por que? Será que vamos mudar algo no template aqui e agora? A resposta para isto é: NÃO. Agora faremos um outro uso do template.
Lembra que durante a criação dele, lá no procedimento AdjustTemplate, presente na linha 72. Eu disse que podemos colocar coisas e tirar coisas de dentro do template? Pois bem, é o que faremos aqui. Usaremos os valores que se encontram no template, já modificado, para repor os dados no Chart Trade. E por que motivo precisamos repor estes dados? O objeto OBJ_CHAT não irá de fato receber o template para criar o Chart Trade? Sim. Mas precisamos reaver os dados, por conta de acontecer alguma interação do usuário com os objetos clicáveis. Em especial o botão de compra e venda a mercado. Isto por conta que tais botões geram eventos que serão vistos e explicados depois. Assim para evitar, seja um delay exagerado do sistema, para buscar as informações, ou para evitar que não tenhamos tais informações na hora que elas forem necessárias. Restauramos elas assim que for pedido o reinicio do Chart Trade.
Então para restaurar, corretamente as informações, que estão dentro do template. Primeiro, precisamos abrir ele, e isto é feito na linha 187. Se tivermos sucesso, o teste na linha 188 permitirá que as linhas 190 a 194 sejam executadas. Isto adicionará, tanto os nomes, quanto onde estará o valor a ser buscado. Depois disto, na linha 195, tentamos executar a conversão. Mas como não estamos, de fato adicionando nada ao template, e tão pouco modificando. A execução da linha 195 irá de fato capturar os dados que pedimos nas linhas 190 a linha 194. Com isto se a execução for bem-sucedida, poderemos entre as linhas 197 e 201, restaurar as variáveis privativas da classe C_ChartFloatingRAD. Não precisamos restaurar todas. Apenas as principais, que serão necessárias para que quando formos fazer uso dos eventos, tais valores estejam em mãos. No final podemos fechar o template e isto é feito na linha 204. E finalmente na linha 207 remover as variáveis globais de terminal, criadas de forma temporária.
Você tem que entender, que estas variáveis terão um tempo de vida muito curto. Este tempo de vida, é na ordem de menos de um segundo. Sendo apenas utilizadas, para guardar a posição em temos de coordenadas gráficas, de onde o objeto OBJ_CHAT se encontrava. Isto antes da mudança de tempo gráfico.
Muito bem, este artigo, já está com bastante informação para você apreciar e entender. Mas antes de terminar podemos falar e explicar rapidamente mais três procedimentos. Isto por que, os mesmos são bem simples e bastante rápidos de serem compreendidos.
O procedimento da linha 214, é o constructor desta classe. Praticamente ele se auto explica, isto devido ao fato de que ele faz uso do que foi explicado neste artigo. Então na linha 218, temos uma marcação, que informa se salvaremos ou não o status atual. Por padrão, não salvaremos nada. A linha 219, tenta criar o indicador, se não for possível, retornaremos ao chamador. Que no caso fará o indicador, ser encerrado. Na linha 220, tentamos restaurar o status anterior. Se ele falhar, usamos os dados que o usuário informou. Na linha 230, criamos o objeto OBJ_CHAT e na linha 231 ajustamos as coisas.
Já o procedimento na linha 234, é o destructor da classe. Aqui temos algo ainda mais simples. Na linha 237 removemos todo e qualquer objeto que esteja relacionado ao objeto OBJ_CHAT. É importante fazer isto, para evitar resíduos de objetos não necessários no gráfico. Agora na linha 238, testamos se iremos ou não salvar o estado atual do template. Se a indicação é de não salvar, a linha 239 removerá o arquivo de template do disco. Com isto não poderemos fazer uso da função RestoreState que está implementada da linha 175 a linha 210. Isto por que o teste da linha 188 irá de fato falhar, fazendo com que os valores sejam os indicados pelo usuário, durante o último carregamento do indicador.
Já na linha 244, temos a função SaveState. Esta fará uso de uma macro interna, que é definida na linha 246 e destruída na linha 257. Está macro, praticamente é desnecessária. Mas já que o nome da variável global de terminal, é usada por duas vezes. Uma para criar a mesma de forma temporária e a outra para armazenar o valor. Acho mais simples usar fazer uso da macro. Mas a questão importante aqui, é a linha 255. Esta linha garantirá que o teste na linha 238 falhe, mantendo assim o arquivo de template intacto.
Considerações finais
Apesar de ter ficado faltando explicar o procedimento DispatchMessage, que se encontra declarada na linha 260 e é implementada até a linha 386. Não irei de fato fazer isto neste artigo. O motivo é que este procedimento é bastante complicado, para ser explicado assim, em um curto espaço. E o mesmo é bem melhor compreendido quando visto em funcionamento, junto com um outro programa. Isto por que, é neste procedimento que são criados os eventos que permitem ao usuário usar o Chat Trade a fim de abrir ou fechar posições a mercado.
Tal tipo de coisa, merece uma explicação bem mais detalhada e aprofundada. Por conta disto, e para evitar que você, aspirante a programador, venha a não se interessar em ler o próximo artigo. Não mostrei o conteúdo interno deste procedimento. Tal conteúdo de fato será visto no próximo artigo em detalhes. Então guarde este código da classe C_ChartFloatingRAD em um arquivo. Estude o mesmo em detalhes, pois ele já é funcional e aguarde o próximo artigo, onde mostrarei o código que estará entre as linhas 260 e 386.
Então nos vemos no próximo artigo. E na sequência, segue as referências sobre programação RAD em MQL5. São artigos onde expliquei no passado, os conceitos usados para que este Chart Trade pudesse ser construído. Isto da forma como você pode perceber neste artigo. Não temos nenhum tipo de objeto, e mesmo assim, conseguimos interagir e apresentar objetos no gráfico. Mas ao fazer uso da janela Objects, via atalho CTRL + B, você irá de fato ver apenas um único objeto.
No anexo você terá tudo que precisa para ver o indicador funcionando e interagindo com ele. Assim como é visto o vídeo logo abaixo:
Referencias de artigos sobre RAD em MQL5





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso