Desenvolvendo um sistema de Replay (Parte 47): Projeto do Chart Trade (VI)
Introdução
No artigo anterior Desenvolvendo um sistema de Replay (Parte 46): Projeto do Chart Trade (V), mostrei como você pode fazer para adicionar dados ao executável, de forma a não precisar transporta-los de forma independente. Aquele conhecimento é muito importante para algo que será feito em breve. Mas por hora vamos continuar a desenvolver as coisas, que precisam ser implementadas antes.
Neste artigo iremos finalizar, o indicador Chart Trade, o tornando funcional a ponto de podermos usá-lo em conjunto com algum EA. O que iremos fazer, irá nos permitir, acessar e trabalhar com o indicador, como se ele estivesse de fato ligado ao EA. Mas vamos fazer isto de uma maneira, bem mais interessante do que foi feito lá atrás no artigo: Desenvolvendo um EA de negociação do zero (Parte 30): CHART TRADE agora como indicador ?!. Pois naquele artigo, usamos o Chart Trade como um indicador indireto. Aqui ele será um indicador puro.
Para isto iremos fazer com que ele trabalhe de uma forma bem especifica, da mesma forma como seria trabalhado com qualquer outro tipo de indicador. Ou seja vamos criar o buffer de dados para o mesmo. O que iremos fazer aqui, já foi explicado em outros artigos, para compreender, dê uma olhada nos seguintes artigos:
- Desenvolvendo um sistema de Replay (Parte 37): Pavimentando o Terreno (I)
- Desenvolvendo um sistema de Replay (Parte 38): Pavimentando o Terreno (II)
- Desenvolvendo um sistema de Replay(Parte 39): Pavimentando o Terreno (III)
Estes 3 artigos, contém a base do que iremos fazer de fato. Se você não os leu, aconselho fazer isto. Caso contrário, você irá ficar a ver navios neste artigo, já que o entendimento não será adequado, devido à falta de um conhecimento mais profundo das bases envolvidas aqui. Então leia os artigos que estão sendo informados, e compreenda bem o conteúdo presente lá.
Antes de fato começar a efetuar as mudanças, é preciso que façamos algumas pequenas modificações. Isto no código já existente da classe C_ChartFloatingRAD, a fim de nos proporcionar um fácil e adequado acesso aos dados que iremos precisar. Então vamos começar a última etapa do indicador Chart Trade, mas isto será visto no próximo tópico.
Pequenas mudanças. Grandes resultados
As mudanças que serão feitas, não são muitas, e tão pouco complicadas. Isto para quem está acompanhando, esta sequência de artigos. Como está sendo feito nesta segunda etapa de artigos sobre o sistema de replay / simulação. Logo abaixo, você tem acesso ao código, na integra do indicador Chart Trade. É importante vermos primeiro este código, para simplificar a explicação no código da classe.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Chart Trade base indicator." 04. #property description "This version communicates via buffer with the EA." 05. #property description "See the articles for more details." 06. #property version "1.47" 07. #property icon "/Images/Market Replay/Icons/Indicators.ico" 08. #property link "https://www.mql5.com/pt/articles/11760" 09. #property indicator_chart_window 10. #property indicator_plots 0 11. #property indicator_buffers 1 12. //+------------------------------------------------------------------+ 13. #include <Market Replay\Chart Trader\C_ChartFloatingRAD.mqh> 14. //+------------------------------------------------------------------+ 15. C_ChartFloatingRAD *chart = NULL; 16. //+------------------------------------------------------------------+ 17. input int user01 = 1; //Leverage 18. input double user02 = 100.1; //Finance Take 19. input double user03 = 75.4; //Finance Stop 20. //+------------------------------------------------------------------+ 21. double m_Buff[]; 22. //+------------------------------------------------------------------+ 23. int OnInit() 24. { 25. bool bErr; 26. 27. chart = new C_ChartFloatingRAD("Indicator Chart Trade", new C_Mouse("Indicator Mouse Study"), user01, user02, user03); 28. 29. if (bErr = (_LastError != ERR_SUCCESS)) Print(__FILE__, " - [Error]: ", _LastError); 30. 31. SetIndexBuffer(0, m_Buff, INDICATOR_DATA); 32. ArrayInitialize(m_Buff, EMPTY_VALUE); 33. 34. return (bErr ? INIT_FAILED : INIT_SUCCEEDED); 35. } 36. //+------------------------------------------------------------------+ 37. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 38. { 39. (*chart).MountBuffer(m_Buff, rates_total); 40. 41. return rates_total; 42. } 43. //+------------------------------------------------------------------+ 44. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 45. { 46. (*chart).DispatchMessage(id, lparam, dparam, sparam); 47. (*chart).MountBuffer(m_Buff); 48. 49. ChartRedraw(); 50. } 51. //+------------------------------------------------------------------+ 52. void OnDeinit(const int reason) 53. { 54. if (reason == REASON_CHARTCHANGE) (*chart).SaveState(); 55. 56. delete chart; 57. } 58. //+------------------------------------------------------------------+
Código fonte do Indicador Chart Trade
Notem que todo este código visto acima, contém tudo que precisamos para fazer o indicador Chart Trade funcionar. Mas por motivos de praticidade, grande parte do código, foi lançado para dentro da classe, que será vista logo mais. No entanto, você pode estar pensando: Como este código funciona ?!?! Como ele consegue nos permitir enviar pedidos para que o EA execute as operações ?!?! Calma. Vamos primeiro entender o que está acontecendo aqui. No código do indicador.
Na linha 11 temos a primeira das etapas que precisamos. Nesta linha definimos e informamos que iremos utilizar 1 buffer. Poderíamos utilizar mais buffer, mas usar 1 já será o suficiente.
O buffer que iremos utilizar é declarado na linha 21. Mas somente definimos a forma de usá-lo na linha 31. Já que não queremos "lixo" assim que o buffer for criado, iniciamos ele na linha 32, de forma que ele conterá apenas e somente valores zero.
Basicamente, como você pode ver, o código do indicador, não sofreu grandes mudanças, frente aquele que foi visto nos artigos anteriores. Mas apareceu duas novas linhas. A linha 39 e a linha 47. Ambas linhas, efetuam uma chamada a mesma rotina dentro da classe, que iremos ver logo depois. Mas você pode estar imaginando que, são funções diferentes, devido ao número e parâmetros serem diferentes. Mas logo você irá perceber que ambas são iguais. Mas para entender isto, será preciso ver o código da classe. E este pode ser visto logo abaixo, totalmente na integra.
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. public : 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 stData 015. { 016. int Leverage; 017. double PointsTake, 018. PointsStop; 019. bool IsDayTrade; 020. union u01 021. { 022. ulong TickCount; 023. double dValue; 024. }uCount; 025. eObjectsIDE Msg; 026. }; 027. private : 028. struct st00 029. { 030. int x, y, minx, miny; 031. string szObj_Chart, 032. szObj_Editable, 033. szFileNameTemplate; 034. long WinHandle; 035. double FinanceTake, 036. FinanceStop; 037. bool IsMaximized; 038. stData ConfigChartTrade; 039. struct st01 040. { 041. int x, y, w, h; 042. color bgcolor; 043. int FontSize; 044. string FontName; 045. }Regions[MSG_NULL]; 046. }m_Info; 047.//+------------------------------------------------------------------+ 048. C_Mouse *m_Mouse; 049. string m_szShortName; 050.//+------------------------------------------------------------------+ 051. void CreateWindowRAD(int w, int h) 052. { 053. m_Info.szObj_Chart = "Chart Trade IDE"; 054. m_Info.szObj_Editable = m_Info.szObj_Chart + " > Edit"; 055. ObjectCreate(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJ_CHART, 0, 0, 0); 056. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, m_Info.x); 057. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, m_Info.y); 058. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XSIZE, w); 059. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YSIZE, h); 060. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_DATE_SCALE, false); 061. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_PRICE_SCALE, false); 062. m_Info.WinHandle = ObjectGetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_CHART_ID); 063. }; 064.//+------------------------------------------------------------------+ 065. void AdjustEditabled(C_AdjustTemplate &Template, bool bArg) 066. { 067. for (eObjectsIDE c0 = 0; c0 <= MSG_STOP_VALUE; c0++) 068. if (bArg) 069. { 070. Template.Add(EnumToString(c0), "bgcolor", NULL); 071. Template.Add(EnumToString(c0), "fontsz", NULL); 072. Template.Add(EnumToString(c0), "fontnm", NULL); 073. } 074. else 075. { 076. m_Info.Regions[c0].bgcolor = (color) StringToInteger(Template.Get(EnumToString(c0), "bgcolor")); 077. m_Info.Regions[c0].FontSize = (int) StringToInteger(Template.Get(EnumToString(c0), "fontsz")); 078. m_Info.Regions[c0].FontName = Template.Get(EnumToString(c0), "fontnm"); 079. } 080. } 081.//+------------------------------------------------------------------+ 082.inline void AdjustTemplate(const bool bFirst = false) 083. { 084.#define macro_AddAdjust(A) { \ 085. (*Template).Add(A, "size_x", NULL); \ 086. (*Template).Add(A, "size_y", NULL); \ 087. (*Template).Add(A, "pos_x", NULL); \ 088. (*Template).Add(A, "pos_y", NULL); \ 089. } 090.#define macro_GetAdjust(A) { \ 091. m_Info.Regions[A].x = (int) StringToInteger((*Template).Get(EnumToString(A), "pos_x")); \ 092. m_Info.Regions[A].y = (int) StringToInteger((*Template).Get(EnumToString(A), "pos_y")); \ 093. m_Info.Regions[A].w = (int) StringToInteger((*Template).Get(EnumToString(A), "size_x")); \ 094. m_Info.Regions[A].h = (int) StringToInteger((*Template).Get(EnumToString(A), "size_y")); \ 095. } 096.#define macro_PointsToFinance(A) A * (GetInfoTerminal().VolumeMinimal + (GetInfoTerminal().VolumeMinimal * (m_Info.ConfigChartTrade.Leverage - 1))) * GetInfoTerminal().AdjustToTrade 097. 098. C_AdjustTemplate *Template; 099. 100. if (bFirst) 101. { 102. Template = new C_AdjustTemplate(m_Info.szFileNameTemplate = IntegerToString(GetInfoTerminal().ID) + ".tpl", true); 103. for (eObjectsIDE c0 = 0; c0 <= MSG_CLOSE_POSITION; c0++) macro_AddAdjust(EnumToString(c0)); 104. AdjustEditabled(Template, true); 105. }else Template = new C_AdjustTemplate(m_Info.szFileNameTemplate); 106. m_Info.ConfigChartTrade.Leverage = (m_Info.ConfigChartTrade.Leverage <= 0 ? 1 : m_Info.ConfigChartTrade.Leverage); 107. m_Info.FinanceTake = macro_PointsToFinance(FinanceToPoints(MathAbs(m_Info.FinanceTake), m_Info.ConfigChartTrade.Leverage)); 108. m_Info.FinanceStop = macro_PointsToFinance(FinanceToPoints(MathAbs(m_Info.FinanceStop), m_Info.ConfigChartTrade.Leverage)); 109. m_Info.ConfigChartTrade.PointsTake = FinanceToPoints(m_Info.FinanceTake, m_Info.ConfigChartTrade.Leverage); 110. m_Info.ConfigChartTrade.PointsStop = FinanceToPoints(m_Info.FinanceStop, m_Info.ConfigChartTrade.Leverage); 111. (*Template).Add("MSG_NAME_SYMBOL", "descr", GetInfoTerminal().szSymbol); 112. (*Template).Add("MSG_LEVERAGE_VALUE", "descr", IntegerToString(m_Info.ConfigChartTrade.Leverage)); 113. (*Template).Add("MSG_TAKE_VALUE", "descr", DoubleToString(m_Info.FinanceTake, 2)); 114. (*Template).Add("MSG_STOP_VALUE", "descr", DoubleToString(m_Info.FinanceStop, 2)); 115. (*Template).Add("MSG_DAY_TRADE", "state", (m_Info.ConfigChartTrade.IsDayTrade ? "1" : "0")); 116. (*Template).Add("MSG_MAX_MIN", "state", (m_Info.IsMaximized ? "1" : "0")); 117. (*Template).Execute(); 118. if (bFirst) 119. { 120. for (eObjectsIDE c0 = 0; c0 <= MSG_CLOSE_POSITION; c0++) macro_GetAdjust(c0); 121. m_Info.Regions[MSG_TITLE_IDE].w = m_Info.Regions[MSG_MAX_MIN].x; 122. AdjustEditabled(Template, false); 123. }; 124. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YSIZE, (m_Info.IsMaximized ? 210 : m_Info.Regions[MSG_TITLE_IDE].h + 6)); 125. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, (m_Info.IsMaximized ? m_Info.x : m_Info.minx)); 126. ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, (m_Info.IsMaximized ? m_Info.y : m_Info.miny)); 127. 128. delete Template; 129. 130. ChartApplyTemplate(m_Info.WinHandle, "/Files/" + m_Info.szFileNameTemplate); 131. ChartRedraw(m_Info.WinHandle); 132. 133.#undef macro_PointsToFinance 134.#undef macro_GetAdjust 135.#undef macro_AddAdjust 136. } 137.//+------------------------------------------------------------------+ 138. eObjectsIDE CheckMousePosition(const int x, const int y) 139. { 140. int xi, yi, xf, yf; 141. 142. for (eObjectsIDE c0 = 0; c0 <= MSG_CLOSE_POSITION; c0++) 143. { 144. xi = (m_Info.IsMaximized ? m_Info.x : m_Info.minx) + m_Info.Regions[c0].x; 145. yi = (m_Info.IsMaximized ? m_Info.y : m_Info.miny) + m_Info.Regions[c0].y; 146. xf = xi + m_Info.Regions[c0].w; 147. yf = yi + m_Info.Regions[c0].h; 148. if ((x > xi) && (y > yi) && (x < xf) && (y < yf)) return c0; 149. } 150. return MSG_NULL; 151. } 152.//+------------------------------------------------------------------+ 153.inline void DeleteObjectEdit(void) 154. { 155. ChartRedraw(); 156. ObjectsDeleteAll(GetInfoTerminal().ID, m_Info.szObj_Editable); 157. m_Info.ConfigChartTrade.Msg = MSG_NULL; 158. } 159.//+------------------------------------------------------------------+ 160. template <typename T > 161. void CreateObjectEditable(eObjectsIDE arg, T value) 162. { 163. long id = GetInfoTerminal().ID; 164. 165. DeleteObjectEdit(); 166. CreateObjectGraphics(m_Info.szObj_Editable, OBJ_EDIT, clrBlack, 0); 167. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_XDISTANCE, m_Info.Regions[arg].x + m_Info.x + 3); 168. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_YDISTANCE, m_Info.Regions[arg].y + m_Info.y + 3); 169. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_XSIZE, m_Info.Regions[arg].w); 170. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_YSIZE, m_Info.Regions[arg].h); 171. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_BGCOLOR, m_Info.Regions[arg].bgcolor); 172. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_ALIGN, ALIGN_CENTER); 173. ObjectSetInteger(id, m_Info.szObj_Editable, OBJPROP_FONTSIZE, m_Info.Regions[arg].FontSize - 1); 174. ObjectSetString(id, m_Info.szObj_Editable, OBJPROP_FONT, m_Info.Regions[arg].FontName); 175. ObjectSetString(id, m_Info.szObj_Editable, OBJPROP_TEXT, (typename(T) == "double" ? DoubleToString(value, 2) : (string) value)); 176. ChartRedraw(); 177. m_Info.ConfigChartTrade.Msg = MSG_NULL; 178. } 179.//+------------------------------------------------------------------+ 180. bool RestoreState(void) 181. { 182. uCast_Double info; 183. bool bRet; 184. 185. if (bRet = GlobalVariableGet(macro_NameGlobalVariable("P"), info.dValue)) 186. { 187. m_Info.x = info._int[0]; 188. m_Info.y = info._int[1]; 189. } 190. if (bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("M"), info.dValue) : bRet)) 191. { 192. m_Info.minx = info._int[0]; 193. m_Info.miny = info._int[1]; 194. } 195. if (bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("B"), info.dValue) : bRet)) 196. { 197. m_Info.ConfigChartTrade.IsDayTrade = info._char[0]; 198. m_Info.IsMaximized = info._char[1]; 199. m_Info.ConfigChartTrade.Msg = (eObjectsIDE)info._char[2]; 200. } 201. if (bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("L"), info.dValue) : bRet)) 202. m_Info.ConfigChartTrade.Leverage = info._int[0]; 203. bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("Y"), m_Info.ConfigChartTrade.uCount.dValue) : bRet); 204. bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("T"), m_Info.FinanceTake) : bRet); 205. bRet = (bRet ? GlobalVariableGet(macro_NameGlobalVariable("S"), m_Info.FinanceStop) : bRet); 206. 207. 208. GlobalVariablesDeleteAll(macro_NameGlobalVariable("")); 209. 210. return bRet; 211. } 212.//+------------------------------------------------------------------+ 213. public : 214.//+------------------------------------------------------------------+ 215. C_ChartFloatingRAD(const string szShortName) 216. :m_Mouse(NULL), 217. m_szShortName(szShortName) 218. { 219. } 220.//+------------------------------------------------------------------+ 221. C_ChartFloatingRAD(string szShortName, C_Mouse *MousePtr, const int Leverage, const double FinanceTake, const double FinanceStop) 222. :C_Terminal(), 223. m_szShortName(NULL) 224. { 225. if (!IndicatorCheckPass(szShortName)) SetUserError(C_Terminal::ERR_Unknown); 226. m_Mouse = MousePtr; 227. if (!RestoreState()) 228. { 229. m_Info.ConfigChartTrade.Leverage = Leverage; 230. m_Info.FinanceTake = FinanceTake; 231. m_Info.FinanceStop = FinanceStop; 232. m_Info.ConfigChartTrade.IsDayTrade = true; 233. m_Info.ConfigChartTrade.uCount.TickCount = 0; 234. m_Info.ConfigChartTrade.Msg = MSG_NULL; 235. m_Info.IsMaximized = true; 236. m_Info.minx = m_Info.x = 115; 237. m_Info.miny = m_Info.y = 64; 238. } 239. CreateWindowRAD(170, 210); 240. AdjustTemplate(true); 241. } 242.//+------------------------------------------------------------------+ 243. ~C_ChartFloatingRAD() 244. { 245. if (m_Mouse == NULL) return; 246. ChartRedraw(); 247. ObjectsDeleteAll(GetInfoTerminal().ID, m_Info.szObj_Chart); 248. FileDelete(m_Info.szFileNameTemplate); 249. 250. delete m_Mouse; 251. } 252.//+------------------------------------------------------------------+ 253. void SaveState(void) 254. { 255.#define macro_GlobalVariable(A, B) if (GlobalVariableTemp(A)) GlobalVariableSet(A, B); 256. 257. uCast_Double info; 258. 259. if (m_Mouse == NULL) return; 260. info._int[0] = m_Info.x; 261. info._int[1] = m_Info.y; 262. macro_GlobalVariable(macro_NameGlobalVariable("P"), info.dValue); 263. info._int[0] = m_Info.minx; 264. info._int[1] = m_Info.miny; 265. macro_GlobalVariable(macro_NameGlobalVariable("M"), info.dValue); 266. info._char[0] = m_Info.ConfigChartTrade.IsDayTrade; 267. info._char[1] = m_Info.IsMaximized; 268. info._char[2] = (char)m_Info.ConfigChartTrade.Msg; 269. macro_GlobalVariable(macro_NameGlobalVariable("B"), info.dValue); 270. info._int[0] = m_Info.ConfigChartTrade.Leverage; 271. macro_GlobalVariable(macro_NameGlobalVariable("L"), info.dValue); 272. macro_GlobalVariable(macro_NameGlobalVariable("T"), m_Info.FinanceTake); 273. macro_GlobalVariable(macro_NameGlobalVariable("S"), m_Info.FinanceStop); 274. macro_GlobalVariable(macro_NameGlobalVariable("Y"), m_Info.ConfigChartTrade.uCount.dValue); 275. 276.#undef macro_GlobalVariable 277. } 278.//+------------------------------------------------------------------+ 279.inline void MountBuffer(double &Buff[], const int iPos = -1) 280. { 281. static int posBuff = 0; 282. uCast_Double info; 283. 284. if ((m_szShortName != NULL) || (m_Info.ConfigChartTrade.Msg == MSG_NULL)) return; 285. posBuff = (iPos > 5 ? iPos - 5 : posBuff); 286. Buff[posBuff + 0] = m_Info.ConfigChartTrade.uCount.dValue; 287. info._char[0] = (char)m_Info.ConfigChartTrade.IsDayTrade; 288. info._char[1] = (char)m_Info.ConfigChartTrade.Msg; 289. Buff[posBuff + 1] = info.dValue; 290. info._int[0] = m_Info.ConfigChartTrade.Leverage; 291. Buff[posBuff + 2] = info.dValue; 292. Buff[posBuff + 3] = m_Info.ConfigChartTrade.PointsTake; 293. Buff[posBuff + 4] = m_Info.ConfigChartTrade.PointsStop; 294. } 295.//+------------------------------------------------------------------+ 296.inline const stData GetDataBuffer(void) 297. { 298. double Buff[]; 299. int handle; 300. uCast_Double info; 301. stData data; 302. 303. ZeroMemory(data); 304. if (m_szShortName == NULL) return data; 305. if ((handle = ChartIndicatorGet(ChartID(), 0, m_szShortName)) == INVALID_HANDLE) return data; 306. if (CopyBuffer(handle, 0, 0, 5, Buff) == 5) 307. { 308. data.uCount.dValue = Buff[0]; 309. info.dValue = Buff[1]; 310. data.IsDayTrade = (bool)info._char[0]; 311. data.Msg = (C_ChartFloatingRAD::eObjectsIDE) info._char[1]; 312. info.dValue = Buff[2]; 313. data.Leverage = info._int[0]; 314. data.PointsTake = Buff[3]; 315. data.PointsStop = Buff[4]; 316. } 317. if (handle != INVALID_HANDLE) IndicatorRelease(handle); 318. 319. return data; 320. }; 321.//+------------------------------------------------------------------+ 322. void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) 323. { 324.#define macro_AdjustMinX(A, B) { \ 325. B = (A + m_Info.Regions[MSG_TITLE_IDE].w) > x; \ 326. mx = x - m_Info.Regions[MSG_TITLE_IDE].w; \ 327. A = (B ? (mx > 0 ? mx : 0) : A); \ 328. } 329.#define macro_AdjustMinY(A, B) { \ 330. B = (A + m_Info.Regions[MSG_TITLE_IDE].h) > y; \ 331. my = y - m_Info.Regions[MSG_TITLE_IDE].h; \ 332. A = (B ? (my > 0 ? my : 0) : A); \ 333. } 334. 335. static int sx = -1, sy = -1; 336. int x, y, mx, my; 337. static eObjectsIDE obj = MSG_NULL; 338. double dvalue; 339. bool b1, b2, b3, b4; 340. eObjectsIDE tmp; 341. 342. if (m_szShortName == NULL) switch (id) 343. { 344. case CHARTEVENT_CHART_CHANGE: 345. x = (int)ChartGetInteger(GetInfoTerminal().ID, CHART_WIDTH_IN_PIXELS); 346. y = (int)ChartGetInteger(GetInfoTerminal().ID, CHART_HEIGHT_IN_PIXELS); 347. macro_AdjustMinX(m_Info.x, b1); 348. macro_AdjustMinY(m_Info.y, b2); 349. macro_AdjustMinX(m_Info.minx, b3); 350. macro_AdjustMinY(m_Info.miny, b4); 351. if (b1 || b2 || b3 || b4) AdjustTemplate(); 352. break; 353. case CHARTEVENT_MOUSE_MOVE: 354. if ((*m_Mouse).CheckClick(C_Mouse::eClickLeft)) switch (tmp = CheckMousePosition(x = (int)lparam, y = (int)dparam)) 355. { 356. case MSG_TITLE_IDE: 357. if (sx < 0) 358. { 359. DeleteObjectEdit(); 360. ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false); 361. sx = x - (m_Info.IsMaximized ? m_Info.x : m_Info.minx); 362. sy = y - (m_Info.IsMaximized ? m_Info.y : m_Info.miny); 363. } 364. if ((mx = x - sx) > 0) ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, mx); 365. if ((my = y - sy) > 0) ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, my); 366. if (m_Info.IsMaximized) 367. { 368. m_Info.x = (mx > 0 ? mx : m_Info.x); 369. m_Info.y = (my > 0 ? my : m_Info.y); 370. }else 371. { 372. m_Info.minx = (mx > 0 ? mx : m_Info.minx); 373. m_Info.miny = (my > 0 ? my : m_Info.miny); 374. } 375. break; 376. case MSG_BUY_MARKET: 377. case MSG_SELL_MARKET: 378. case MSG_CLOSE_POSITION: 379. DeleteObjectEdit(); 380. m_Info.ConfigChartTrade.Msg = tmp; 381. m_Info.ConfigChartTrade.uCount.TickCount = GetTickCount64(); 382. break; 383. }else if (sx > 0) 384. { 385. ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, true); 386. sx = sy = -1; 387. } 388. break; 389. case CHARTEVENT_OBJECT_ENDEDIT: 390. switch (obj) 391. { 392. case MSG_LEVERAGE_VALUE: 393. case MSG_TAKE_VALUE: 394. case MSG_STOP_VALUE: 395. dvalue = StringToDouble(ObjectGetString(GetInfoTerminal().ID, m_Info.szObj_Editable, OBJPROP_TEXT)); 396. if (obj == MSG_TAKE_VALUE) 397. m_Info.FinanceTake = (dvalue <= 0 ? m_Info.FinanceTake : dvalue); 398. else if (obj == MSG_STOP_VALUE) 399. m_Info.FinanceStop = (dvalue <= 0 ? m_Info.FinanceStop : dvalue); 400. else 401. m_Info.ConfigChartTrade.Leverage = (dvalue <= 0 ? m_Info.ConfigChartTrade.Leverage : (int)MathFloor(dvalue)); 402. AdjustTemplate(); 403. obj = MSG_NULL; 404. ObjectDelete(GetInfoTerminal().ID, m_Info.szObj_Editable); 405. break; 406. } 407. break; 408. case CHARTEVENT_OBJECT_CLICK: 409. if (sparam == m_Info.szObj_Chart) switch (obj = CheckMousePosition(x = (int)lparam, y = (int)dparam)) 410. { 411. case MSG_DAY_TRADE: 412. m_Info.ConfigChartTrade.IsDayTrade = (m_Info.ConfigChartTrade.IsDayTrade ? false : true); 413. DeleteObjectEdit(); 414. break; 415. case MSG_MAX_MIN: 416. m_Info.IsMaximized = (m_Info.IsMaximized ? false : true); 417. DeleteObjectEdit(); 418. break; 419. case MSG_LEVERAGE_VALUE: 420. CreateObjectEditable(obj, m_Info.ConfigChartTrade.Leverage); 421. break; 422. case MSG_TAKE_VALUE: 423. CreateObjectEditable(obj, m_Info.FinanceTake); 424. break; 425. case MSG_STOP_VALUE: 426. CreateObjectEditable(obj, m_Info.FinanceStop); 427. break; 428. } 429. if (obj != MSG_NULL) AdjustTemplate(); 430. break; 431. } 432. } 433.//+------------------------------------------------------------------+ 434.}; 435.//+------------------------------------------------------------------+ 436.#undef macro_NameGlobalVariable 437.//+------------------------------------------------------------------+
Código fonte da classe C_ChartFloatingRAD
Talvez você esteja pensando que estou de sacanagem, ao colocar o código fonte no artigo. Mas isto está longe de ser sacanagem, quero de fato explicar com o máximo de detalhes o que está acontecendo. Isto para que você, não use de fato este código, mas que consiga entender e criar algo MELHOR.
Então vamos entender o que está acontecendo aqui. Pois se você não conseguir entender o funcionamento desta classe, com toda a certeza não entenderá o que irá ser desenvolvido depois.
Logo no início temos, já algumas mudanças. Na linha 12 fazemos a declaração de uma clausura pública. De fato, esta clausula está aí por precisarmos de que os dados possam ser acessados fora da classe. Você pode até pensar que poderíamos colocar estes mesmos dados em outro local. Isto de maneira a manter apenas um tipo de clausula. Mas, aqui estou declarando apenas uma estrutura e uma enumeração. A enumeração já é conhecida de longa data. No entanto a estrutura é nova. Então entre as linhas 14 e 26 temos a declaração da estrutura que é usada para organizar os dados que precisamos.
Grande parte desta estrutura é bem simples de ser compreendida, sendo quase que uma auto explicativa. Porém, existem algumas coisas aqui que são bem estranhas. Como por que desta união, que se encontra presente entre as linhas 20 e 24 ?!?! E por que da linha 25 ?!?! Bem o fato é que a união, irá nos permitir transferir mais facilmente as coisas. E a linha 25 será usada em um momento bem especifico. Nós iremos chegar lá. Tenha calma.
Esta mesma estrutura é referenciada na linha 38. Mas lembre-se do seguinte: Os dados presentes na classe, não podem ser diretamente acessados fora da classe. Por conta disto, precisamos de algum meio de poder acessar eles. Na verdade, não iremos acessar eles de forma direta. Não no indicador, como você pode ver ao olhar o código fonte do indicador. Seguindo, temos a linha 49. Esta tem uma função interessante. Ela irá servir como um tipo de seletor. Mas isto será melhor compreendido mais à frente.
Na linha 106, montamos a adequamos, a primeira das variáveis, que foram declaradas na estrutura encontrada na linha 38. Notem que basicamente é a mesma coisa que antes fazíamos. Mas agora estamos lidando, com uma modelagem um pouco diferente.
Então na linha 109 temos uma das variáveis sendo ajustadas. Esta é a variável do número de pontos do valor de take. Atenção a isto, NÃO estou falando em termos de financeiro, estou falando em termos de PONTOS. Não confunda as duas coisas. Uma outra coisa, é que também não estou mencionando o número de pontos com base no preço atual negociado. Estou falando em termos de pontos gerais. Não interessa o preço, o que importa é quantos pontos de deslocamento estaremos tendo. É importante que você também note que este valor em pontos, já estará ajustado em termos financeiros. Isto por conta da linha 107, que faz o ajuste para nós.
Na linha 110, temos algo equivalente, só que desta vez estamos fazendo isto para o valor de stop. Da mesma forma como era feito na linha 107, para ajustar o financeiro, antes de assumirmos a pontuação na linha 109. Na linha 108 ajustamos o financeiro do stop, antes de assumir a pontuação do stop. É muito importante que você entenda o que está acontecendo neste ponto. Caso você não consiga compreender, irá ter dificuldades no entendimento do ajuste a ser feito depois. No momento que formos lançar as ordens no ativo.
Mas para facilitar um pouco a vida, no anexo, você terá acesso aos indicadores de Mouse e do Chart Trade, assim como também a um EA bastante simples, para que consiga entender o que está se passando. Por motivos de segurança, o EA presente no anexo, não irá lançar ordens. Ele apenas irá imprimir os valores que estão sendo lançado. Assim ficará mais claro, para que você consiga entender como o sistema de fato funciona.
Agora nas linhas 157 e 177, por motivos de praticidade, ajustamos o valor de uma outra variável. Até agora não foi feito nenhum tipo de acesso. Tudo que estamos fazendo é ajustando e configurando os valores das variáveis. Mas ao observar na linha 203, vemos algo que parece estranho. Por que estamos armazenando este valor em uma variável global de terminal ?!?! Será que de fato precisamos fazer isto ?!?! Ou seria pura perda de tempo ?!?! De fato, precisamos fazer isto. O motivo é que quando o indicador Chart Trade é removido e lançado novamente no gráfico, qualquer valor que estiver em memória irá ser perdido. E este valor que estamos armazenando é muito importante para nós.
No entanto, aqui estamos apenas recuperando os valores que foram armazenados. Então este mesmo valor que estamos recuperando na linha 203, foi na verdade armazenado usando a linha 274. Vocês devem ter notado que pulei algumas funções, nesta explicação. Mas agora vamos voltar a elas. Começaremos pelo constructor. Sim agora não temos apenas 1, mas 2 constructores para a classe. O motivo disto é o mesmo que foi feito no artigo sobre o indicador de mouse. Precisamos de um método para conseguir traduzir os dados do buffer.
Bem, lá no fundo, e bem no fundo. Não precisaríamos disto. Poderíamos fazer a tradução diretamente no EA, ou no indicador. Mas para facilitar a manutenção, prefiro colocar tudo juntinho. Assim se mais para frente for necessário fazer qualquer mudança. Tudo que precisarei fazer é trabalhar na classe C_ChartFloatingRAD. E não ter todo aquele trabalho para ajustar programa por programa, a fim de ter uma padronização dos módulos. Bem, mas voltando aos constructores, temos o antigo constructor, montado a partir da linha 221. Basicamente ele recebeu a linha 223, onde inicializamos o nome do indicador. Detalhe: Este nome não é o usado para gravar no buffer, e sim para ler o buffer. E temos também, as linhas entre 232 e 234, onde iniciamos as novas variáveis. Nem todas, pois as demais são ajustadas no procedimento de ajuste do template.
O segundo constructor é bastante simples. Sendo iniciado na linha 215. Ali basicamente damos os valores padrão para ser usados. Isto durante a fase de tradução. Igual aconteceu com o indicador de mouse, aqui temos também duas fases. Uma em que gravamos no buffer, e uma outra onde fazemos a leitura do buffer. Mas isto não é por que a programação está sendo mal conduzida. Se você está pensando isto, é por que ainda não entendeu o que estamos fazendo. O que de fato fazemos, ao usar o indicador, é gravar os dados em um buffer. Este é lido via CopyBuffer por algum outro programa, normalmente o EA. Por isto temos duas fases, e pelo mesmo motivo temos dois constructores.
Mas diferente dos constructores, no caso do destructor, podemos ter apenas um. Este tem seu código iniciado a partir da linha 243. Porém, observem que a única adição que foi feita, é justamente a linha 245. Então caso estejamos usando a classe em um indicador, quando o destructor for chamado, este teste da linha 245 irá passar, permitindo que os objetos criados sejam removidos. Porém se a classe está sendo usada para ler o buffer do indicador, ao fazer o teste da linha 245, este irá falhar, e evitará que qualquer objeto seja removido. Um mecanismo simples, porém, funcional.
Muito bem, esta foi a parte fácil. Agora chegamos à parte crítica da nossa explicação. Como a interação é feita, e como os dados são armazenados e lidos do buffer. Esta parte talvez seja um pouco confusa para muitos que estão começando. Por isto é tão importante compreender os conceitos vistos nos artigos anteriores, dos quais mencionei no início deste. Mas para facilitar um pouco, vamos dar uma olhada na figura 01.
Figura 01 - Esquema de comunicação.
Nesta figura 01, vemos como é o sistema de comunicação a fim de conseguir transferir informações do indicador para o Expert Advisor. Notem que o buffer não faz parte realmente do indicador. Apesar de ele, buffer, está sendo declarado no indicador, você não deve pensar nele como sendo parte da memória do mesmo. Ele é de fato mantido pelo MetaTrader 5. E quando removemos o indicador do gráfico, o MetaTrader 5 libera a memória que era usada pelo buffer. Mas, e aqui é que mora um dos perigos. Os dados não são de fato destruídos. Apenas a memória é liberada. Talvez você não consiga compreender o real perigo nisto. Mas tentarei explicar de forma simples.
Se o MetaTrader 5 libera a memória onde o buffer se encontrava, pelo fato de que o indicador foi removido do gráfico. Isto depois de ele, buffer, ter sido escrito. Se o indicador for recolocado no gráfico. Pode, não é que vá acontecer, pode ser que o buffer ainda contenha algum tipo de dado. Isto da última atualização. Então, quando o Expert Advisor, via CopyBuffer, ler estes dados, pode, e novamente, isto não indica que irá acontecer, pode ser que ele leia dados incorretos.
Esta questão é tão séria, que você deve tomar o máximo cuidado ao acessar o buffer. Para garantir que exista alguma sincronia entre a escrita e a leitura, foi preciso modificar o procedimento DispatchMessage, presente na classe C_ChartFloatingRAD. Esta sincronia entre a escrita do buffer e sua leitura é muito importante. Se ela não for feita de maneira correta, teremos um atraso entre o que o usuário mandou ser feito e o que de fato estará sendo feito. Ou seja, o usuário pode enviar um pedido de compra, e este não ser atendido. Porém ao enviar logo depois um pedido de venda, a compra irá ser executada. Este tipo de falha, não é de fato culpa da plataforma MetaTrader 5, mas sim do mal entendimento de como desenvolver o código, a fim de promover a correta sincronização entre os eventos.
Não existe de fato uma ligação, em termos de código, entre o Expert Advisor e o indicador Chart Trade. Esta ligação irá se dar pelo uso do buffer. Então o Expert Advisor não sabe o que o Chart Trade está fazendo, assim como o Chart Trade não sabe o que o Expert Advisor está de fato fazendo. Mas, no entanto, o MetaTrader 5 sabe, o que ambos estão fazendo. E como o ponto comum entre o Indicador e o Expert Advisor é justamente o MetaTrader 5, usamos ele de maneira a nos permitir fazer as coisas acontecerem. Mais ou menos como mágica, onde você, ou o usuário irá ter a impressão de que o Expert Advisor e o Indicador Chart Trade, são um único programa.
Mas aqui existe uma coisa igualmente importante. Você deve saber que sem o indicador de mouse, que já foi mostrado em artigos passados, o indicador Chart Trade, NÃO irá funcionar. É necessário que você tenha os 3 aplicativos no gráfico. O indicador de Mouse, o Indicador Chart Trade e o Expert Advisor, além de outras coisas que veremos no futuro. Sem isto todo o sistema não irá de fato fazer absolutamente nada.
E quem está garantindo isto ?!?! Quem de fato garante isto é justamente o evento CHARTEVENT_MOUSE_MOVE, que se encontra na linha 353 da classe C_ChartFloatingRAD. Caso o indicador de mouse, não esteja no gráfico. Você irá poder clicar, editar e modificar os valores do indicador Chart Trade. Isto por que, tais eventos não necessariamente estão ligados ao indicador de mouse. No entanto você não poderá enviar pedidos de compra, venda, ou fechamento, e em mover o indicador Chart Trade, sem que o indicador de mouse esteja no gráfico.
Mas então espere um pouco. Preciso que o indicador de mouse esteja no gráfico, assim consigo interagir com o Chart Trade ?!?! É isto ?!?! Sim. Você pode até retirar esta pendencia, mas isto irá trazer outros problemas a você depois. Caso queira usar os demais métodos que irei explicar. Este tipo de coisa, é um custo que você terá que pagar, caso queira trabalhar como da mesma maneira como faço. Por isto é importante, que você compreenda muito bem como o sistema funciona, caso contrário, irá ficar com um sistema que você não poderá de fato confiar.
Mas vamos voltar ao código, a fim de conseguir compreender, com foi que fiz para conseguir que o sistema fique sincronizado. Para uma compreensão completa é preciso que você entenda o que o código fonte do indicador faz, mas se você leu os artigos que indiquei no início deste daqui, não terá dificuldades em compreender tal funcionamento. Assim sendo, irei considerar que você já compreende como o código do indicador funciona. Podendo assim focar no código da classe.
Toda a vez que você clica, ou move o mouse, o MetaTrader 5 gera algum evento. Os eventos de clique em geral são tratados pelo CHARTEVENT_OBJECT_CLICK. Mas, porém, toda via e, entretanto, usar este tratador não nos permite manter a sincronização. O motivo é um tanto quanto complicado de explicar, mas tem a ver com a ordem de execução das coisas. Então para que de fato ao clicar em um dos 3 botões presentes no Chart Trade, ( botão de compra, botão de venda e botão de fechar posição ) tenhamos no mesmo instante um evento gerado no Expert Advisor, fazemos as coisas de uma forma um pouco diferente.
Por conta disto, se você comparar este código presente no procedimento DispatchMessage, com o mesmo código visto no artigo anterior, irá notar que eles são ligeiramente diferentes. A diferença em si, está onde tratamos o clique nos botões acima mencionados. Na versão anterior este clique era tratado na chamada CHARTEVENT_OBJECT_CLICK, agora iremos trata-lo na CHARTEVENT_MOUSE_MOVE. E por conta que o próprio código nos informa de qual foi o objeto clicado, criamos uma nova variável apenas para podermos trabalhar de maneira um pouco mais organizada. Esta variável está sendo declarada na linha 340. Tendo seu valor ajustado na linha 354.
Agora bastante atenção ao que explicarei. Entre as linhas 376 e 378, colocamos os códigos dos botões. Assim quando o indicador de mouse, enviar os dados para nós, poderemos enviar o pedido para o Expert Advisor executar. Mas aqui existe um pequeno detalhe. Como fazer o Expert Advisor saber, qual foi o botão pressionado ?!?! Simples. Enviamos o código do botão para o Expert Advisor. Isto é feito na linha 380. Agora na linha 381, capturamos o número de ticks de clock a fim de gerar um número exclusivo. Este será necessário para o Expert Advisor. Mas não se preocupe, logo você entenderá como isto funciona de fato.
Então a cada evento que for gerado, além desta chamada à função DispatchMessage, que irá preparar as coisas para lançamento no buffer. Teremos de fato uma outra chamada. Esta é que de fato irá colocar os dados no buffer. Você pode ver o seu código a partir da linha 279 na classe. Agora reparem, que na linha 281 temos uma variável estática. Esta irá armazenar o valor que é repassado pelo evento OnCalculate, ou seja, temos que armazenar o valor rates_total, o motivo disto já foi explicado antes. Leia os artigos indicados no início, para entender tal motivo. Assim quando a chamada efetuada pelo tratador OnChartEvent acontecer, saberemos onde colocar os dados no buffer.
Atenção ao fato de que na linha 284, efetuamos um teste a fim de garantir que apenas o indicador Chart Trade irá escrever na memória. Além disto, a escrita somente irá acontecer, quando um dos botões desejados for de fato clicado. Tudo muito lindo e muito bonito. Mas nada disto realmente de fato irá ter algum valor sem que o Expert Advisor consiga interpretar tais dados, que o indicador Chart Trade estará enviando. Para entender como o Expert Advisor irá conseguir interpretar as coisas, precisamos ver um código funcional, porém que seja o mais básico possível.
Usando um Expert Advisor de teste
Como tudo precisa ser testado, precisamos sempre que tais testes, sejam feitos de maneira a deixar claro, o que de fato está acontecendo. Para testar a interação entre o Indicador Chart Trade, Indicador de Mouse e o Expert Advisor. Precisamos fazer o uso de um sistema, que seja o mais simples, quanto for possível ser criado. Mas ao mesmo tempo precisamos que este mesmo sistema, além de simples, funcione com base em algo que iremos de fato fazer uso no futuro.
Com base neste critério vamos fazer uso do código que você pode ver logo abaixo:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Demo version between interaction of Chart Trade and EA" 04. #property version "1.47" 05. #property link "https://www.mql5.com/pt/articles/11760" 06. //+------------------------------------------------------------------+ 07. #include <Market Replay\Chart Trader\C_ChartFloatingRAD.mqh> 08. //+------------------------------------------------------------------+ 09. C_ChartFloatingRAD *chart = NULL; 10. //+------------------------------------------------------------------+ 11. int OnInit() 12. { 13. chart = new C_ChartFloatingRAD("Indicator Chart Trade"); 14. 15. return (CheckPointer(chart) != POINTER_INVALID ? INIT_SUCCEEDED : INIT_FAILED); 16. } 17. //+------------------------------------------------------------------+ 18. void OnDeinit(const int reason) 19. { 20. delete chart; 21. } 22. //+------------------------------------------------------------------+ 23. void OnTick() {} 24. //+------------------------------------------------------------------+ 25. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) 26. { 27. static ulong st_uTime = 0; 28. C_ChartFloatingRAD::stData info; 29. 30. switch (id) 31. { 32. case CHARTEVENT_OBJECT_CLICK: 33. info = (*chart).GetDataBuffer(); 34. if (st_uTime != info.uCount.TickCount) 35. { 36. st_uTime = info.uCount.TickCount; 37. PrintFormat("%u -- %s [%s] %d : %f <> %f", info.uCount.TickCount, info.IsDayTrade ? "DT" : "SW", EnumToString(info.Msg), info.Leverage, info.PointsTake, info.PointsStop); 38. }else Print("IGNORADO..."); 39. break; 40. } 41. } 42. //+------------------------------------------------------------------+
Código fonte do Expert Advisor de teste
Note que este código é extremamente simples e compacto. Sendo quase em sua totalidade auto explicativo. Mas apesar disto, pode ser que você, principalmente iniciantes não consiga de fato compreender o funcionamento do código. Não se sinta mal por isto. Todo iniciante tem o mesmo tipo de dificuldade. Mas se você se esforçar, estudando, dedicando, tendo disciplina e sempre tentando sempre se aprimorar. Em uma data futura, você acabará por se tornar um grande profissional. Mas desistir, não é uma opção, não pra quem deseja se profissionalizar.
Bem, mas vamos dar uma rápida passada pelo código, já que são poucas linhas será simples de entender.
Todo aquele código, visto no tópico anterior, presente na classe C_ChartFloatingRAD, é resumido quando passa a ser utilizado aqui, no Expert Advisor. Apesar de na linha 7 estamos incluindo a classe por inteiro, para o compilador não é bem assim. Então na linha 9 declaramos de maneira global um ponteiro. Este será usado para que possamos acessar a classe C_ChartFloatingRAD. Isto talvez lhe deixe um pouco confuso. Mas tal confusão se deve ao fato de você está imaginando que a classe irá ser acessada da mesma forma que é acessada no código do indicador.
De fato, você poderia até fazer isto. Mas não é nem um pouco adequado fazer isto. O motivo é que a classe não foi pensada para ser usada sem que seja em um indicador. Assim como a classe C_Mouse, que é utilizada no indicador mouse, não deve ser utilizada em um código que não seja um indicador. Sei que muitos podem ficar tentados em fazer isto. Mas isto NÃO deve ser feito. Pois toda a segurança, modelagem e desempenho esperado, não foi dirigida de forma a usar as classes em código que não são os originais das mesmas. Ou seja, se você colocar o mesmo modo de codificar o indicador, aqui no Expert Advisor, irá de fato conseguir fazer com que não precise usar o indicador Chart Trade. Isto é fato.
No entanto se você fizer isto, de transferir o código do Indicador para dentro do Expert Advisor. Irá e poderá ter problemas com a estabilidade e segurança de todo o sistema. Visto que ele não está sendo criado de forma a dar tal sustentabilidade. Então cada coisa em seu devido lugar. Assim sendo, quando na linha 13 estivermos criando o ponteiro, fazendo a chamada ao constructor, veja que estarei informando o mesmo nome que foi informado como sendo o do indicador Chart Trade. Assim o indicador irá fazer o seu trabalho, e o Expert Advisor irá fazer o seu. Cada um em seu canto. Se algo der errado em algum deles. Tudo que precisará ser feito, será lança-lo novamente no gráfico.
Agora observem que praticamente todo o código, se resume a apenas isto. Informar o nome do indicador, e logo depois no tratador de eventos OnChartEvent, capturar o evento CHARTEVENT_OBJECT_CLICK, e então analisar o que aconteceu. Aqui vale uma observação importante. Sempre que você clicar, irá ser gerado um evento de clique em objeto, mesmo que você imagine que não clicou em nada de importante. O motivo disto é que o indicador de mouse estará, e deverá estar no gráfico. E este indicador conta com uma linha horizontal, que é um objeto. Então sempre que você clicar, esta linha horizontal irá gerar um evento.
Mas então como o sistema consegue diferenciar entre um clique nesta linha e um clique em outro objeto ?!?! Isto é uma questão bastante interessante, que será vista em um outro artigo, em breve. Mas você precisa estar ciente disto quando for usar diversos objetos no gráfico. Principalmente por que iremos adicionar outros indicadores em breve. Mas isto fica para o futuro.
A questão é que na linha 33, o tal evento de clique em objetos, irá tentar ler o conteúdo do buffer do indicador Chart Trade. Se ele conseguir fazer isto, teremos os dados sendo retornados. E então na linha 34, iremos verificar se estamos tratando de um evento diferente, vindo do Chart Trade ou de outra coisa, que pode ser ignorada.
Se de fato o evento foi gerado no Chart Trade, e o motivo foi o fato de termos clicado em um dos botões de interação com o sistema de ordens, teremos a atualização do valor da variável estática, isto feito na linha 36, e logo depois iremos imprimir uma mensagem no terminal a fim de podermos analisar o que foi que aconteceu. Caso o evento deva ser ignorado por qualquer motivo, teremos a execução da linha 38.
Conclusão
No vídeo 01, você pode ver como o sistema funciona na prática. Mas independentemente disto, nada substitui o fato de você mesmo poder ver o sistema em funcionamento. Então no anexo você terá acesso ao sistema no seu atual estágio.
Vídeo 01 - Demonstração
- 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