
Desenvolvendo um sistema de Replay (Parte 76): Um novo Chart Trade (III)
Introdução
No artigo anterior Desenvolvendo um sistema de Replay (Parte 75): Um novo Chart Trade (II), explique diversas coisas sobre a classe C_ChartFloatingRAD. No entanto, devido a questão do material ser bastante denso, e a explicação foi feita de maneira que fosse a mais detalhada quando possível. Ficou faltando um procedimento a ser visto. Porém, mesmo que eu o tivesse deixado no código do arquivo de cabeçalho C_ChartFloatingRAD.mqh, e tentasse explicar o mesmo, no artigo anterior. Isto não seria feito de forma adequada. Visto que para compreender o funcionamento do procedimento DispatchMessage, é necessário explicar uma outra coisa junto.
Mas neste artigo, que se inicia agora. Poderei me aprofundar bastante, na questão da explicação, de como o procedimento DispatchMessage, realmente trabalha. Visto que ele é o procedimento, mais importante da classe C_ChartFloatingRAD. Sendo o responsável por gerar e responder aos eventos que o MetaTrader 5, informará ao Chart Trade.
Então, o conteúdo que será visto neste artigo, deverá ser complementado com o que foi visto no artigo anterior. Não tente entender este artigo, sem antes compreender profundamente o que foi explicado no artigo anterior. Os dois últimos artigos, junto com este representam exatamente todo o conceito por detrás do indicador Chart Trade. Assim sendo, entender o que estou explicando, em cada um destes artigos, é extremamente importante para entender o que será feito no futuro.
Assim sem mais delongas, vamos para a explicação do procedimento DispatchMessage. Esta será vista no tópico a seguir.
Entendendo como DispatchMessage funciona
Se você ainda espera, ver diversos objetos, sendo programados aqui no Chart Trade. Você ainda, de fato, não compreendeu como as coisas aqui, funcionam. Então antes de prosseguirmos, sugiro que você estude o artigo anterior. Pois agora veremos algo, que torna o Chart Trade funcional. Mas faremos isto apenas respondendo e gerando eventos. Não criaremos nenhum objeto. Apenas iremos de fato, tornar os eventos informados pelo MetaTrader 5 em algo funcional.
No artigo passado, ao olhar o código do arquivo de cabeçalho, C_ChartFloatingRAD.mqh, você pode ter notado, que existe uma região, onde falta o código. O código faltante naquela mesma região, pode ser visto logo abaixo. No fragmento em destaque.
259. //+------------------------------------------------------------------+ 260. void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) 261. { 262. #define macro_AdjustMinX(A, B) { \ 263. B = (A + m_Info.Regions[MSG_TITLE_IDE].w) > x; \ 264. mx = x - m_Info.Regions[MSG_TITLE_IDE].w; \ 265. A = (B ? (mx > 0 ? mx : 0) : A); \ 266. } 267. #define macro_AdjustMinY(A, B) { \ 268. B = (A + m_Info.Regions[MSG_TITLE_IDE].h) > y; \ 269. my = y - m_Info.Regions[MSG_TITLE_IDE].h; \ 270. A = (B ? (my > 0 ? my : 0) : A); \ 271. } 272. 273. static short sx = -1, sy = -1, sz = -1; 274. static eObjectsIDE obj = MSG_NULL; 275. short x, y, mx, my; 276. double dvalue; 277. bool b1, b2, b3, b4; 278. ushort ev = evChartTradeCloseAll; 279. 280. switch (id) 281. { 282. case CHARTEVENT_CHART_CHANGE: 283. x = (short)ChartGetInteger(GetInfoTerminal().ID, CHART_WIDTH_IN_PIXELS); 284. y = (short)ChartGetInteger(GetInfoTerminal().ID, CHART_HEIGHT_IN_PIXELS); 285. macro_AdjustMinX(m_Info.x, b1); 286. macro_AdjustMinY(m_Info.y, b2); 287. macro_AdjustMinX(m_Info.minx, b3); 288. macro_AdjustMinY(m_Info.miny, b4); 289. if (b1 || b2 || b3 || b4) AdjustTemplate(); 290. break; 291. case CHARTEVENT_MOUSE_MOVE: 292. if ((*m_Mouse).CheckClick(C_Mouse::eClickLeft)) switch (CheckMousePosition(x = (short)lparam, y = (short)dparam)) 293. { 294. case MSG_TITLE_IDE: 295. if (sx < 0) 296. { 297. DeleteObjectEdit(); 298. ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false); 299. sx = x - (m_Info.IsMaximized ? m_Info.x : m_Info.minx); 300. sy = y - (m_Info.IsMaximized ? m_Info.y : m_Info.miny); 301. } 302. if ((mx = x - sx) > 0) ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_XDISTANCE, mx); 303. if ((my = y - sy) > 0) ObjectSetInteger(GetInfoTerminal().ID, m_Info.szObj_Chart, OBJPROP_YDISTANCE, my); 304. if (m_Info.IsMaximized) 305. { 306. m_Info.x = (mx > 0 ? mx : m_Info.x); 307. m_Info.y = (my > 0 ? my : m_Info.y); 308. }else 309. { 310. m_Info.minx = (mx > 0 ? mx : m_Info.minx); 311. m_Info.miny = (my > 0 ? my : m_Info.miny); 312. } 313. break; 314. case MSG_BUY_MARKET: 315. ev = evChartTradeBuy; 316. case MSG_SELL_MARKET: 317. ev = (ev != evChartTradeBuy ? evChartTradeSell : ev); 318. case MSG_CLOSE_POSITION: 319. if ((m_Info.IsMaximized) && (sz < 0)) 320. { 321. string szTmp = StringFormat("%d?%s?%c?%d?%.2f?%.2f", ev, _Symbol, (m_Info.IsDayTrade ? 'D' : 'S'), m_Info.Leverage, 322. FinanceToPoints(m_Info.FinanceTake, m_Info.Leverage), FinanceToPoints(m_Info.FinanceStop, m_Info.Leverage)); 323. PrintFormat("Send %s - Args ( %s )", EnumToString((EnumEvents) ev), szTmp); 324. sz = x; 325. EventChartCustom(GetInfoTerminal().ID, ev, 0, 0, szTmp); 326. DeleteObjectEdit(); 327. } 328. break; 329. }else 330. { 331. sz = -1; 332. if (sx > 0) 333. { 334. ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, true); 335. sx = sy = -1; 336. } 337. } 338. break; 339. case CHARTEVENT_OBJECT_ENDEDIT: 340. switch (obj) 341. { 342. case MSG_LEVERAGE_VALUE: 343. case MSG_TAKE_VALUE: 344. case MSG_STOP_VALUE: 345. dvalue = StringToDouble(ObjectGetString(GetInfoTerminal().ID, m_Info.szObj_Editable, OBJPROP_TEXT)); 346. if (obj == MSG_TAKE_VALUE) 347. m_Info.FinanceTake = (dvalue <= 0 ? m_Info.FinanceTake : dvalue); 348. else if (obj == MSG_STOP_VALUE) 349. m_Info.FinanceStop = (dvalue <= 0 ? m_Info.FinanceStop : dvalue); 350. else 351. m_Info.Leverage = (dvalue <= 0 ? m_Info.Leverage : (short)MathFloor(dvalue)); 352. AdjustTemplate(); 353. obj = MSG_NULL; 354. ObjectDelete(GetInfoTerminal().ID, m_Info.szObj_Editable); 355. break; 356. } 357. break; 358. case CHARTEVENT_OBJECT_CLICK: 359. if (sparam == m_Info.szObj_Chart) if ((*m_Mouse).CheckClick(C_Mouse::eClickLeft)) switch (obj = CheckMousePosition(x = (short)lparam, y = (short)dparam)) 360. { 361. case MSG_DAY_TRADE: 362. m_Info.IsDayTrade = (m_Info.IsDayTrade ? false : true); 363. DeleteObjectEdit(); 364. break; 365. case MSG_MAX_MIN: 366. m_Info.IsMaximized = (m_Info.IsMaximized ? false : true); 367. DeleteObjectEdit(); 368. break; 369. case MSG_LEVERAGE_VALUE: 370. CreateObjectEditable(obj, m_Info.Leverage); 371. break; 372. case MSG_TAKE_VALUE: 373. CreateObjectEditable(obj, m_Info.FinanceTake); 374. break; 375. case MSG_STOP_VALUE: 376. CreateObjectEditable(obj, m_Info.FinanceStop); 377. break; 378. } 379. if (obj != MSG_NULL) AdjustTemplate(); 380. break; 381. case CHARTEVENT_OBJECT_DELETE: 382. if (sparam == m_Info.szObj_Chart) macro_CloseIndicator(C_Terminal::ERR_Unknown); 383. break; 384. } 385. ChartRedraw(); 386. } 387. //+------------------------------------------------------------------+ 388. }; 389. //+------------------------------------------------------------------+
Fragmento faltante do código C_ChartFloatingRAD.mqh
Note que o fragmento acima, se encaixa perfeitamente na região de código faltante. Que foi visto no artigo passado. Então para completar o código da classe C_ChartFloatingRAD, este fragmento deverá ser colocado, exatamente naquela região. Seguindo a enumeração das linhas indicadas. Acredito que você, não terá de fato, nenhuma dificuldade em fazer isto. Mas então vamos entender como este fragmento funciona.
A primeira coisa que você pode notar aqui, neste fragmento, é que não existe nenhuma chamada a fim de criar, qualquer objeto. Como eu disse, não iremos realmente ficar programado objetos. O Chart Trade, é criado e salvo como sendo um template. Isto é feito inteiramente dentro do MetaTrader 5. No artigo anterior, deixei algumas referências no final do mesmo, para que você possa compreender o conceito.
Este tipo de programação, não tem sido muito usada, por grande parte dos programadores. Isto pelo que consegui notar. Mas ela é de fato, muito mais prática e simples de ser feita. Isto por que você não precisa programar cada um dos objetos. Ter todo um trabalho para posicionar e ajustar os mesmos. Quando necessário, você simplesmente faz algum tipo de menção do objeto. Isto dentro do template. E na parte da programação, você cria o objeto correto. Mas só e somente, se não for possível, configurar ele diretamente pelo MetaTrader 5. Desenhando as coisas e salvando como um template. Este tipo de coisa, como falei no artigo passado é algo bastante raro de ser feito. Na verdade, o único objeto com o qual não consegui lidar adequadamente, foi o objeto OBJ_EDIT. Isto por que, é muito mais trabalhoso, criar toda a lógica de inserir e manipular um texto, do que simplesmente criar o OBJ_EDIT. Por conta disto, ele é o único objeto que realmente será criado.
Mas voltemos a olhar o fragmento. Você consegue perceber que neste fragmento estamos apenas tratando de alguns eventos? Mas se é isto que está acontecendo. Por que conseguimos fazer as coisas, como foi mostrado no vídeo presente no artigo anterior? E mesmo que o vídeo não estivesse ali presente. Você tem acesso aos executáveis no anexo. E mesmo assim, pode ter ficado bastante confuso, tentando entender como aquele código, que não tem diversos objetos presentes nele, consegue funcionar daquela maneira. Muito provavelmente deve ter imaginado, que no procedimento DispatchMessage, outros objetos poderiam parecer. Mas olhando o fragmento acima, pode notar que não. NÃO EXISTEM OUTROS OBJETO. Tudo que estamos fazendo, é tratamento dos eventos, que o MetaTrader 5 está nos fornecendo. Mas como então isto funciona?
Para facilitar o entendimento e a explicação, vamos por partes. Aqui estamos tratando de cinco tipos de eventos, que o MetaTrader 5 nos envia. Mas antes de ver os eventos que estamos e como estamos lidando com eles. Você pode notar que entre as linhas 273 e 278, declaramos algumas variáveis. As que estão sendo declaradas como estáticas, são variáveis que poderiam estar em âmbito global, dentro da classe. Porém pelo motivo de que elas somente são usadas aqui, neste procedimento, e que precisamos manter o valor entre chamadas. As definimos como estáticas. Mas se você olhar com calma, irá de fato notar, que a variável declarada na linha 278, não é estática. Mesmo assim ela está sendo inicializada no momento de sua declaração. Isto faz com que não venhamos a nos preocupar, com algumas questões relacionadas ao uso errado desta variável. Observe que o valor que está sendo colocado nela, é o de um evento declarado no arquivo Defines.mqh.
Então vamos começar vendo o primeiro evento tratado. Este é o CHARTEVENT_CHART_CHANGE, que se inicia na linha 282 e vai até a linha 290. Este evento é gerado sempre que o gráfico sofre alguma mudança. Este não é um procedimento crítico. Sendo apenas composto de cálculos. Estes tem como objetivo, de colocar e manter, o objeto OBJ_CHART, em uma posição adequada dentro da janela gráfica.
O próximo evento é o CHARTEVENT_MOUSE_MOVE. Este se inicia na linha 291 e vai até a linha 338, sendo assim o tratador mais longo dentro do procedimento DispatchMessage. Este evento é disparado pelo MetaTrader 5, sempre que o mouse se mover, ou que os botões do mouse venham a ser pressionados. Porém, por padrão, o MetaTrader 5, não dispara este evento. Precisamos dizer para o MetaTrader 5, disparar ele para nos. Esta tarefa, de dizer ao MetaTrader 5, que desejamos receber eventos de mouse, é feito pelo indicador de mouse. Veja os artigos anteriores nesta sequência, para entender como o indicador de mouse funciona. Entender o funcionamento, em detalhe do indicador de mouse, é bastante importante para nos. Já que ele é o indicador que irá de fato, permitir que o usuário consiga interagir com os elementos que estamos criado e implementando.
Mas veja, que não estamos lidando diretamente com os eventos de mouse. Observe na linha 292 que a primeira coisa que de fato fazemos, é testar se está ocorrendo um clique com o botão esquerdo. Mas para que este clique seja de fato válido, pedimos ao indicador de mouse a confirmação de que o clique é válido. Mas por que estamos fazendo isto? Por que simplesmente não testamos aqui, dentro do tratador, se o clique é ou não válido? Por que ter o trabalho de perguntar isto ao indicador de mouse?
Bem, o motivo para perguntar ao indicador de mouse, se o clique é ou não válido, é devido ao fato de que o indicador de mouse, é também usado para gerar estudos. Quando o indicador de mouse estiver executando um estudo, a pedido do usuário, nenhum clique é válido. Não temos como realmente saber, quando e por quanto tempo o indicador de mouse, estará no modo estudo. Sendo assim, a maneira mais eficaz e segura de verificar isto, é justamente perguntando ao indicador de mouse. Então se o indicador de mouse, informar que o clique é valido, iremos de fato converter as posições que estão sendo informadas pelo MetaTrader 5, e checar em qual objeto o clique foi dado. Isto é feito pela chamada CheckMousePosition. Poderíamos usar, as coordenadas que o indicador de mouse, indicaria. No entanto, se fossemos fazer isto, precisaríamos ler o buffer do indicador. E como os valores seriam os mesmos que o MetaTrader 5 nos informa, não faz sentido ler o buffer para obter estes valores.
Mas antes de ver como um clique válido, será tratado. Vamos para a linha 329, onde teremos o tratamento, caso o evento CHARTEVENT_MOUSE_MOVE, não tenha recebido um clique válido. Ou ele tenha sido disparado, por conta de algum movimento, executado pelo usuário ao interagir com o mouse. Neste caso na linha 331, revertemos o valor da variável sz, para um valor negativo. Logo em seguida, na linha 332, testamos se a variável sx, tem algum valor positivo. Caso isto se confirme, indica que estávamos tratando de algum evento do mouse. E agora não vamos mais tratar tal evento. Assim sendo, na linha 334, dizemos ao Metatrader 5, que o mouse, poderá mover o gráfico. Logo depois na linha 335, colocamos sx e sy com um valor negativo. Isto fará com que o teste da linha 332, falhe. Evitando assim que venhamos a ficar executado, sem necessidade a linha 334.
Você deve ter em mente, que depois do evento OnTick, que é tratado no Expert Advisor, o evento CHARTEVENT_MOUSE_MOVE é um dos que mais será disparado. Em alguns casos, este evento CHARTEVENT_MOUSE_MOVE, supera e muito o evento OnTick. E se não tomarmos alguns cuidados, podemos deixar a plataforma MetaTrader 5, bastante lenta e sobrecarregada, apenas por conta de tratar eventos CHARTEVENT_MOUSE_MOVE. Então tome sempre bastante cuidado com estes eventos vindos do mouse. E não é a toa, que o MetaTrader 5, vem com este evento desativado por padrão.
Muito bem. Agora podemos voltar, e ver o que acontece entre as linhas 293 e 328. Pois é nesta região do código, em que iremos de fato interagir com alguns dos elementos do Chart Trade. Quando CheckMousePosition retorna, ela poderá indicar um dos objetos que vemos nesta região do código. Entre eles: A barra de título e os botões de compra a mercado, venda a mercado ou fechar posições. Outros elementos são tratados em outro lugar. Depois irei de fato explicar o motivo disto. Mas cada um destes quatro elementos citados, precisa ser tratado de uma maneira diferente. Então vamos começar com o mais complicado deles. A barra de título.
Quando o clique acontece na barra de título, pode ser que o usuário, queira movimentar o Chart Trade. Então entre as linhas 295 e 313, temos toda a lógica necessária para que isto ocorra. Não vou entrar em detalhes assim, já que todo este processo, foi explicado em um outro artigo nesta mesma sequência. Onde construímos as primeiras versões do Chart Trade. Se tiver alguma dúvida, leia os artigos anteriores, pois eles também são importantes para o que estamos fazendo aqui. Você deve ter em mente que um código, não nasce assim do nada. Ele vai sendo construído e implementado aos pouco, até tomar a forma que você está vendo neste momento.
Agora a parte, onde realmente nos interessa, se encontra entre as linhas 314 e 328. Neste ponto do código, você deve prestar atenção, ao valor que foi definido na linha 278. Isto por que aqui, testaremos duas, de três condições. Apesar de usar três. A primeira condição que testamos é o fato de ter ocorrido um clique válido, no botão de compra a mercado. Caso isto tenha ocorrido, o valor da variável ev, será definido para destacar o evento de compra a mercado. Isto é feito na linha 315.
Agora atenção: Como a linha 316, temos de fato, a condição de que o clique foi dado no botão de venda a mercado. Precisaremos testar, se o clique foi no botão compra a mercado. Isto para definir corretamente o valor da variável ev. Mas por que precisamos deste teste? Não estamos tratando de um outro evento? Sim. Estamos realmente tratando de um outro evento.
Mas já que todos os três eventos: Compra a mercado; Venda a mercado e Fechamento de posição, executa o mesmo tipo de coisa. Não damos uma pausa entre os eventos. Colocamos eles em cadeia. Por conta justamente disto, de termos colocado eles em cadeia, precisamos testar, na linha 317, se o evento anterior, modificou ou não o valor da variável ev. Se o evento anterior, mudou o valor, não podemos fazer isto no próximo evento na cadeia. Caso contrário, apenas o último evento de fato seria disparado. Os eventos que o antecedem, jamais seriam de fato tratados.
De qualquer maneira, no final iremos sempre cair na linha 318, onde está o evento para fechar a posição. Neste e apenas neste evento, faremos de fato os testes necessários para que um evento customizado, seja disparado pelo MetaTrader 5. Então vamos entender, como chegaremos neste ponto, a fim de evitar falhas.
Na linha 319, testamos se o Chart Trade, está ou não maximizado. Este teste é importante, pois a função CheckMousePosition, ignora o fato de que a janela esteja ou não maximizada. Preste atenção a isto. Pois se este teste não for feito, e você clicar na posição, onde um dos botões estaria, o evento customizado seria disparado. Para evitar isto, e somente disparar o evento, quando de fato os objetos estiverem no gráfico, verificamos a condição de janela maximizada ou não.
Aqui mora um fato importante: A janela precisa estar maximizada no gráfico, ou seja, os botões precisam estar visíveis. Mas, porém, toda via e entre tanto, existe uma pequena falha neste processo de testagem. Quem está fazendo o teste é o nosso código, ou seja, o Chart Trade. O teste não está sendo feito pelo MetaTrader 5. E por que este fato é importante? O problema, é que se tiver um outro objeto, sobre os botões, ou seja, se você colocar algo que cubra os botões, mas o Chart Trade estiver maximizado. Quando clicar na região, onde um dos botões esteja, o código e não o MetaTrader 5, irá de fato disparar o evento customizado. Esta é uma falha, da qual futuramente pretendo corrigir. Porém como não é algo assim tão grave, neste momento, ainda podemos conviver com ela. No entanto, você deve se lembrar deste problema, quando for usar o Chart Trade em uma conta real. NÃO COLOQUE NADA NA FRENTE DELE, QUANDO ELE ESTIVER MAXIMIZADO.
Existe um outro teste, nesta mesma linha 319. Este teste visa, verificar e evitar que um clique válido, seguido de um movimento do mouse, faça com que diversos eventos sejam disparados. É um simples teste, onde o valor sz, deverá ser negativo. Caso ele seja positivo, significa que um evento já foi disparado, e que o botão do mouse continua pressionado. No momento em que ele for liberado e ocorrer um movimento do mouse, a linha 331, garantirá que poderemos disparar um novo evento customizado. Este tipo de teste, apesar de ser bastante simples, evita muitas dores de cabeça.
Toda a mágica em si, acontece na linha 321. Mas é claro, para evitar termos uma linha imensa, ela foi dividida em duas partes. Assim sendo, a linha 322, também deverá ser considerada como sendo a 321. Mas antes de explicar esta linha 321, vamos ver o que as quatro próximas linhas estão fazendo. Começamos na linha 323. Esta linha imprimirá na caixa de ferramentas, o pedido que foi enviado via evento customizado. Pode parecer bobagem fazer isto, mas acredite, isto evita muitas dores de cabeça. Pois se você estiver observando a caixa de mensagem, e notar uma mensagem como será impressa ao enviar um evento customizado. Terá sua atenção sendo chamada para verificar o que pode ter ocorrido. Então nunca ignore, as mensagens postadas na caixa de mensagem do MetaTrader 5. Muitas delas são de suma importância.
Já a linha 324, simplesmente fará o bloqueio, de forma a evitar a condição explicada assim. Já que a variável sz, é usada no teste da linha 319. O evento customizado, é de fato disparado na linha 325. Note que, diferente do que foi feito no indicador de controle. Aqui os dados são enviados na região da string. Caso isto não fosse possível, teríamos problemas em enviar muitas informações entre aplicações.
Agora vem um detalhe. As strings, aqui no MQL5, seguem o mesmo princípio de strings em C/C++. Ou seja, elas terminam em um carácter NULL. E por que estou dizendo este tipo de coisa? O motivo disto, é para que você entenda por que temos que usar a função StringFormat aqui. Se você achar desnecessário, imprimir o que está sendo enviado, via evento customizado. Pode simplesmente pegar o conteúdo da linha 321 e colocar aqui, na linha 325. Trocando para isto a variável szTmp, pela função StringFormat, e usando exatamente o que está sendo usado na linha 321.
Mas voltando a questão da string. O problema é que teremos de passar valores numéricos dentro da string. Neste momento você pode estar se perguntando: Mas por que não usar os campos lparam e dparam da mensagem? Por que temos que usar o campo sparam? O motivo é justamente o tamanho da informação que teremos de passar. Se fossemos passar poucos parâmetros, poderíamos até fazer uso dos campos lparam e dparam. Mas como a quantidade de informação é grande, temos que de fato usar o campo sparam. E é neste ponto, que muitos cometem erros, principalmente iniciantes, ou aspirantes a programador.
Quando você observa um número, vamos supor o valor 65. Para uma aplicação este valor irá de fato representar o número 65. Mas para outra aplicação este mesmo valor representará a letra A. Agora muitos podem ter ficado confusos com isto. Mas o problema é que você está olhando o número 65 de forma literal. Sendo que o correto seria olhar ele de forma binária. Neste caso ele seria representado da seguinte forma, em 8 bits: 0100 0001. Esta seria a forma correta de olhar as coisas, quando estamos lidando com programação. Então vamos passar a olhar as coisas de forma correta. Quando você olhar uma string, não deve pensar nela como caracteres imprimíveis ou que pode ser compreendido pelo ser humano. Pense na string como um número gigante, mas bastante grande mesmo. Compostos não de 1 byte ou 256 bytes, ou seja, lá a quantidade de bytes que você queira, mas sim por uma quantidade enorme de bytes.
Pensando desta forma, fica mais simples de entender uma outra coisa. Como você faz para dizer que um determinado byte, corresponde ao final de uma string? Algumas linguagens de programação, fazem uso de um valor logo no início da string. O que seria um valor morto, que indicaria a quantidade de caracteres, ou bytes que a string conterá. Um exemplo de linguagem que faz uso desta técnica é o Basic. Outra seria o antigo Pascal. Nesta o comprimento da string se encontra no começo da string.
Então dentro da string em sim, que na verdade deveria, nestes casos ser pensada como um array, podemos ter qualquer valor, em termos de byte. Isto é poderíamos ter valores entre 0 e 255. Porém, este tipo de coisa, apesar de ser adequada em muitas situações, é péssima em outras. Já que o uso de um array de tamanho fixo, faz com que a memória seja mal utilizada. O motivo é que talvez você precise de 3 bytes. Mas por conta do fato de que o compilador perceba que na mesma string, ou melhor array, precisaremos hora de 50 bytes, hora de 20 bytes. O compilador irá de fato alocar, a maior área necessária para o array, ou seja, 50 bytes. Mesmo que em alguns momentos precisemos apenas de 3 bytes.
Por conta desta questão, outras linguagens não fazem uso desta configuração de strings. Então como saber quando uma string termina? A forma de fazer isto, é definindo um código, ou valor, que indicará o final da string. No caso mais comum, fazemos uso no carácter NULL, ou 0000 0000 em binário. O motivo deste carácter ser usado, está ligado com as escolhas feitas no momento da implementação do compilador. Qualquer carácter poderia ser usado. Mas o que nos interessa aqui não é isto. E sim, no que isto influenciará na nossa mensagem que terá que ser passada com uma string.
Vamos voltar novamente, no caso dos valores numéricos. O nosso Chart Trade deverá transferir basicamente dois tipos de valores: short e double. Bem, o valor short utiliza 16 bits ou 2 bytes. Não vou nem entrar na questão do valor double. Irei de fato matar a coisa no short mesmo. Quem dentro do Chart Trade, usa um valor short? O nível de alavancagem. Ok. Qual o menor valor que a alavancagem pode ter? O menor valor é UM. E como este valor é representado em binário? O mesmo é representado da seguinte forma: 0000 0000 0000 0001. Aqui estou escrevendo ele de maneira que ele fique em 16 bits.
Porém, apesar do tipo short usar 2 bytes, a string, é na verdade, composta por 1 byte. Então o primeiro byte, do valor 1 dentro da string, representa o carácter NULL. Puxa vida, então antes de qualquer informação puder vim a ser lida, a string já terá sido finalizada? Sim. Por este motivo, temos que converter os valores em caracteres imprimíveis. Ou seja, não importa o valor binário da coisa, o valor será convertido em uma forma compreensível, ou seja, imprimível. Transmitida e depois convertida novamente em seu correspondente binário. Por isto precisamos da função StringFormat aqui.
Considerações finais
Apesar deste artigo, parecer terminar de forma abruta. Não me sinto confortável em explicar, em pouco tempo e espaço, a segunda coisa da qual precisamos fazer. Esta coisa é o protocolo de comunicação entre as aplicações. Apesar de você achar que esta questão sobre o protocolo, venha a ser algo simples. Ela na verdade é algo bastante complicado de ser explicado de forma rápida. Eu simplesmente poderia lhe dizer que a linha 321 cria um protocolo e que este será o protocolo que teremos de usar.
No entanto, simplesmente fazer isto. Além de deixar completamente vago toda a questão envolvendo a comunicação entre programas. Não iria lhe ajudar em nada. Caso você esteja vendo estas coisas sendo criadas, e imaginando como poderia usar isto em seus próprios programas. Digo isto, pois apesar do MetaTrader 5, já está a um bom tempo no mercado. E ter diversos programadores interessados em criar coisas para ele. Não vejo ninguém, ou nenhum código usando o que estou mostrando aqui. Sempre que as pessoas querem fazer algo, criam tudo do zero, ou criam programas enormes. Estes em sua grande maioria, são extremamente complicados de serem mantidos, corrigidos ou melhorados. Porém usando este conhecimento, que estou disposto a repassar, você poderá criar programas menores, consideravelmente mais simples e fáceis de serem corrigidos e mantidos.
Por isto, quero aproveitar a oportunidade que o Chart Trade está nos dando, para explicar em detalhes, como o processo de mensagens funciona. Assim quem sabe, você como aspirante, ou estudante de programação, veja que podemos fazer muito mais do que você normalmente vê, a grande maioria fazendo.
Com relação aos demais eventos, que são eles: CHARTEVENT_OBJECT_ENDEDIT; CHARTEVENT_OBJECT_CLICK e CHARTEVENT_OBJECT_DELETE. Tenho total certeza que se você se esforçar um pouco, irá de fato conseguir entender perfeitamente o que cada um deles está fazendo. Já que o código dos mesmos é consideravelmente muito mais simples, do que o código em passamos a maior parte do artigo.
Então no próximo artigo, irei de fato, explicar, por que a linha 321 tem aquele formato. E o que isto irá de fato implicar no código do Expert Advisor que for receber os eventos do Chart Trade. Isto para que ele possa executar as ordens disparadas, pela interação do usuário, com os botões presentes no Chart Trade.





- 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