Español
preview
Do básico ao intermediário: Array (IV)

Do básico ao intermediário: Array (IV)

MetaTrader 5Exemplos | 1 novembro 2024, 11:07
149 0
CODE X
CODE X

Introdução

O conteúdo exposto aqui, visa e tem como objetivo, pura e simplesmente a didática. De modo algum deve ser encarado como uma aplicação final, onde o objetivo não seja o estudo dos conceitos aqui mostrados.

No artigo anterior Do básico ao intermediário: Array (III), foi explicado como utilizar arrays para passar dados entre funções e procedimentos. Assim como também foi explicado alguns detalhes relacionados a questão de inicialização e cuidados básicos que devem ser tomados, para não se criar algo insustentável no longo prazo. Como acredito que muitos de vocês acham que tudo isto, que está sendo mostrado pode ter pouco valor, ou quase nunca será de fato aplicado na prática. Neste artigo iremos começar a brincar de verdade. Então é aqui que a diversão realmente irá começar pra valer. Isto por que, até este momento, apenas aplicamos certos conceitos e regras simples nos códigos que foram vistos até aqui. Mas está chegando a hora de começarmos a entrar no que de fato é o MetaTrader 5.

Porém antes de fazermos isto, na prática, precisamos ver e entender certas coisas, que muitos talvez não saibam. E outros com toda a certeza não fazem a mínima ideia de como funciona. Então como a coisa agora começa a ficar muito mais divertida, e ao mesmo tempo, mais elaborada. Peço que você tenha ainda mais calma com os assuntos que serão vistos, neste e nos próximos artigos. Isto porque, entender o que será visto aqui, irá lhe ajudar muito a entender outras coisas, que acontecem quando criamos aplicações reais para o MetaTrader 5 executar.

A primeira coisa que iremos fazer é entender como a memória pode ser melhor explorada, usando para isto arrays. Sim, o assunto sobre arrays ainda não terminou. E se você imaginava que era algo que em pouco tempo você iria ver tudo. Esqueça. Este assunto de fato é muito longo e extenso. Justamente por conta disto, é iremos ver o mesmo, de agora em diante, de forma mais espaçada. Em pequenos trechos e junto com outros assuntos que serão abordados no decorrer dos artigos. Assim a coisa toda não ficar cansativa e chata.

Ok, antes de começarmos, preciso lembrar que existe um pré-requisito para conseguir acompanhar o que será explicado neste artigo. Basicamente o pré-requisito é ter compreendido como os códigos do último tópico, visto no artigo anterior funciona. Ou seja, como trabalhar com arrays fora do local onde eles estão sendo declarados.


Operador sizeof

Vamos começar a nossa diversão fazendo uma pequena brincadeira. A mesma tem como objetivo, mostrar como a manipulação de dados, pode ocorrer dentro da memória. Ou seja, não iremos utilizar variáveis convencionais aqui. O objetivo é fazer tudo por meio de arrays. Desta forma iremos simular o que seria a criação, movimentação, leitura e escrita de variáveis na memória RAM do computador. Sei que isto parece ser algo completamente fora de questão. Mas fazer isto, além de um excelente exercício de lógica e programação. Irá lhe ajudar a pensar como um verdadeiro programador. Isto por que, será necessário executar diversas coisas que muitos programadores, se quer sabem como fazer.

Vamos começar nosso exercício com um pequeno vislumbre de algo que será muito maior. Se bem, que vou tentar deixar as coisas o mais simples possível, para que todos consigam acompanhar o raciocínio empregado. Para isto, a primeira coisa que precisamos fazer, é entender o que o operador sizeof realmente faz. E por que ele existe.

Pois bem, o operador sizeof, é encarregado de nos dizer, quantos bytes um determinado tipo ou variável está usando na memória. Parece ser algo místico. Mas é bem simples de entender. Em primeiro lugar, é preciso que você saiba, que número de elementos de um array, não significa memória alocada. Um array pode ter X elementos, e, no entanto, ocupar Y bytes. O número de elementos somente será igual ao número de bytes usados, ou alocados em memória, se e somente se, o tipo de dado utilizado for igual a 8 bits, ou 1 byte. No caso do MQL5, os tipos que cumprem este requisito são o tipo char e uchar. Todos os demais terão um número maior de bytes frente ao número de elementos presentes no array. Então não confunda operador sizeof, com uma operação ArraySize ou uma chamada Size. Cujo propósito é saber o número de elementos em um array.

Para deixar isto devidamente esclarecido e fácil de entender. Vamos ver o seguinte exemplo mostrado abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     const char  ROM_1[]  = {2, 3, 3, 5, 8};
07.     const short ROM_2[]  = {2, 3, 3, 5, 8};
08. 
09.     PrintFormat("ROM_1 contains %d elements and occupies %d bytes of memory", ROM_1.Size(), sizeof(ROM_1));
10.     PrintFormat("ROM_2 contains %d elements and occupies %d bytes of memory", ROM_2.Size(), sizeof(ROM_2));
11. }
12. //+------------------------------------------------------------------+

Código 01

Este código 01, quando executado produz o seguinte resultado visto logo abaixo.

Imagem 01

Agora vamos entender o que esta imagem 01 está nos dizendo. Apesar de ser algo que só olhando já conseguimos perceber. Observe que no código 01, temos dois arrays estáticos sendo criados. A única diferença entre eles é o fato de um ser do tipo char e o outro do tipo short. Fora isto são exatamente iguais. Contendo os mesmos cinco elementos. No entanto, a quantidade de bytes usado em cada um é diferente. Por que?

Bem, meu caro leitor, no artigo Do básico ao intermediário: Variáveis (II), existe uma tabela que informa a quantidade de bytes que cada tipo de dados básico ocupa na memória. Se você olhar aquela tabela irá notar que o tipo short, ocupa dois bytes. Como temos cinco elementos, ao multiplicar o número de elementos no array, pela quantidade de bytes que cada elemento ocupa, chegaremos ao número de dez bytes. De fato, é bem simples e direto o uso do operador sizeof, para que venhamos a saber a quantidade de espaço ocupado em memória.

E por que isto é importante para nós? Bem, esta informação, de quanta memória uma dada informação irá utilizar, é extremamente útil. Nos permitindo inclusive alocar mais memória, ou mesmo liberar uma certa quantidade de memória de um modo muito fácil e direto. Apesar de ainda não termos usado isto aqui. Iremos fazer muito este tipo de implementação ao logo do tempo. Mas para o nosso atual interesse. O que foi visto aqui, já é mais do que o suficiente. Assim podemos ir para a próxima etapa.


Enumeradores

Este tópico será voltado a explicar um conceito muito simples. Porém pode ser extremamente útil em uma infinidade de situações. Para explicar o que seria um enumerador, de uma forma muito simples, e fácil de compreender, vamos utilizar um código visto em um artigo anterior. O mesmo pode ser observado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. string ValueToString(ulong arg, char format)
05. {
06.     const string szChars = "0123456789ABCDEF";
07.     string  sz0 = "";
08. 
09.     while (arg)
10.         switch (format)
11.         {
12.             case 0:
13.                 sz0 = StringFormat("%c%s", szChars[(uchar)(arg % 10)], sz0);
14.                 arg /= 10;
15.                 break;
16.             case 1:
17.                 sz0 = StringFormat("%c%s", szChars[(uchar)(arg & 0x7)], sz0);
18.                 arg >>= 3;
19.                 break;
20.             case 2:
21.                 sz0 = StringFormat("%c%s", szChars[(uchar)(arg & 0xF)], sz0);
22.                 arg >>= 4;
23.                 break;
24.             case 3:
25.                 sz0 = StringFormat("%c%s", szChars[(uchar)(arg & 0x1)], sz0);
26.                 arg >>= 1;
27.                 break;
28.             default:
29.                 return "Format not implemented.";
30.         }
31. 
32.     return sz0;
33. }
34. //+------------------------------------------------------------------+

Código 02

Este código que é um arquivo de cabeçalho, que foi mostrado em um outro artigo. Mas que irá estar presente aqui novamente. Nos será de grande valia neste momento. Você pode notar que para usar um dos formados, precisamos utilizar um valor decimal qualquer. Porém quando usamos isto no código, fica bem difícil entender do que se trata, e qual o objetivo previsto. Isto por que, um código que usaria este tipo de abordagem mostrada no código 02, precisaria ser escrito como mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     ushort  value = 0xCADA;
09. 
10.     PrintFormat("Translation personal.\n" +
11.                 "Decimal: %s\n" + 
12.                 "Octal  : %s\n" +
13.                 "Hex    : %s\n" +
14.                 "Binary : %s",
15.                 ValueToString(value, 0),
16.                 ValueToString(value, 1),
17.                 ValueToString(value, 2),
18.                 ValueToString(value, 3)
19.                );
20. }
21. //+------------------------------------------------------------------+

Código 03

No caso o arquivo de cabeçalho indicado na linha quatro deste código 03, é exatamente o que é visto em código 02. Porém a questão aqui, é justamente os valores, que você pode observar entre as linhas 15 e 18. Olhando aqueles valores, você conseguiria dizer que tipo de tratamento seria feito, a fim de criar a string de saída? Definitivamente NÃO. Você precisaria recorrer ao arquivo de cabeçalho. Procurar a função ValueToString. Analisar como cada um dos valores trabalha. Para somente depois decidir qual seria o valor adequado a ser utilizado. Ou seja, muito trabalho, para pouca produção. Justamente devido a isto, se torna necessário um tipo de estrutura muito mais prática e eficaz. A mesma é conhecida como ENUMERADOR. Sendo que em um enumerador, você cria um tipo especial de dado, que seguirá uma contagem progressiva, a cada novo dado que você criar. Isto é bastante prático e muito fácil de ser utilizado.

Assim, atualizando o código 02, para um que utiliza enumeradores, podemos ver o código que surge na sequência, logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. enum eConvert {
05.     FORMAT_DECIMAL,
06.     FORMAT_OCTAL,
07.     FORMAT_HEX,
08.     FORMAT_BINARY
09. };
10. //+------------------------------------------------------------------+
11. string ValueToString(ulong arg, eConvert format)
12. {
13.     const string szChars = "0123456789ABCDEF";
14.     string  sz0 = "";
15. 
16.     while (arg)
17.         switch (format)
18.         {
19.             case FORMAT_DECIMAL:
20.                 sz0 = StringFormat("%c%s", szChars[(uchar)(arg % 10)], sz0);
21.                 arg /= 10;
22.                 break;
23.             case FORMAT_OCTAL:
24.                 sz0 = StringFormat("%c%s", szChars[(uchar)(arg & 0x7)], sz0);
25.                 arg >>= 3;
26.                 break;
27.             case FORMAT_HEX:
28.                 sz0 = StringFormat("%c%s", szChars[(uchar)(arg & 0xF)], sz0);
29.                 arg >>= 4;
30.                 break;
31.             case FORMAT_BINARY:
32.                 sz0 = StringFormat("%c%s", szChars[(uchar)(arg & 0x1)], sz0);
33.                 arg >>= 1;
34.                 break;
35.             default:
36.                 return "Format not implemented.";
37.         }
38. 
39.     return sz0;
40. }
41. //+------------------------------------------------------------------+

Código 04

Veja que é bem simples mesmo de fazer a coisa funcionar. Claro que aqui estamos vendo, um enumerador básico sendo criado. Mas acredito que você não terá dificuldades em entender o que está sendo feito na linha quatro. Uma vez definido este enumerador, podemos fazer as substituições como você pode observar no restante do código. Com isto, agora o antigo código 03, passará a ser como o código mostrado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     ushort  value = 0xCADA;
09. 
10.     PrintFormat("Translation personal.\n" +
11.                 "Decimal: %s\n" + 
12.                 "Octal  : %s\n" +
13.                 "Hex    : %s\n" +
14.                 "Binary : %s",
15.                 ValueToString(value, FORMAT_DECIMAL),
16.                 ValueToString(value, FORMAT_OCTAL),
17.                 ValueToString(value, FORMAT_HEX),
18.                 ValueToString(value, FORMAT_BINARY)
19.                );
20. }
21. //+------------------------------------------------------------------+

Código 05

Agora diga a verdade. Só de bater o olhe neste código 05, já é perfeitamente possível entender o que ele está fazendo não é mesmo? Pois bem, apesar desta pequena mudança, ainda assim o código 03 continuará funcionando, sem nenhuma mudança. Isto até que venhamos a mexer novamente no enumerador. Mas por hora, vamos deixar as coisas assim. Já que não faz sentido falarmos de certos detalhes mais avançados com relação aos enumeradores. Em um futuro breve, iremos voltar novamente a este tema. Mas com outros objetivos em mente.


Um número infinito de argumentos

Agora vamos a um tema, um pouco mais elaborado, para tornar este artigo mais interessante. Em um artigo anterior, onde mostrei como poderíamos criar uma representação de valores binários. Isto para que pudéssemos visualizar ele no terminal do MetaTrader 5. Mencionei o fato de que haveria uma certa dificuldade em se criar um procedimento em MQL5, a fim de ter um comportamento muito fácil de ser feito em C e C++. Na verdade, até onde sei, as únicas linguagens que nativamente permitem tal modelagem são, de fato C e C++. Além do Java que tem algo muito parecido sendo implementado também.

Onde podemos criar uma função ou procedimento, onde não haveria uma quantidade fixa de argumentos ou parâmetros. Mas haveria sim, um número mínimo de tais variáveis sendo declaradas. Isto no momento em que fosse feita a chamada de uma dada função ou procedimento. Sendo este valor mínimo de um argumento pelo menos.

Uma vez que isto tivesse sido feito, poderíamos passar, tantos, quanto forem os dados necessários, os argumentos para a função ou procedimento. E dentro da função ou procedimento, haveria três chamadas especiais que nos permitiria ler, um a um cada argumento extra. Para quem tiver interesse ou mesmo curiosidade, veja va_start, va_arg e va_end, pois estas são as três funções que o C e C++ utiliza. No caso do Java, o nome destas funções, é ligeiramente diferente. Mas o princípio de funcionamento é o mesmo. E sabendo o conceito aplicado em tais funções, podemos criar algo muito parecido aqui no MQL5.

Na verdade, muitos podem vir a considerar o que será mostrado como algo avançado. Porém ao meu ver isto é material básico. Que todo iniciante deveria saber como fazer. O que faremos basicamente é uma brincadeira a fim de manipular um array em MQL5. Mas para que o truque funcione, com o atual nível de informações já mostrada. Será necessário, fazer uma pequena artimanha. Esta artimanha que iremos utilizar envolve o uso do operador sizeof, junto com algumas pequenas manipulações simples que serão feitas em um array.

Agora vamos pensar o seguinte: Quando declaramos um array dinâmico, podemos a medida de nossa necessidade adicionar novos elementos a ele. E como o tipo mais simples é o tipo uchar, ou char dependendo do caso. Podemos usar ele como base para outros tipos. Mas apenas empilhar valores em um array, não nos ajudará a transmitir dados por ele. Precisamos de algo um pouco mais bem pensado.

Assim acabamos voltando nossa atenção ao tipo string. Isto por que o tipo string nos permite transferir valores. Pois sabemos como cada string termina. Ou seja, com um símbolo de nulo, ou zero.

Porém, e é aqui onde entra a nossa artimanha e a parte divertida. E se criássemos uma string do tipo usado em BASIC? Para quem não sabe, falei sobre isto em um artigo anterior. Quem sabe isto nos seria bem mais útil. E de fato é onde mora o pulo do gato. Já que utilizar um símbolo nulo, em valores binários não seria adequado.

No entanto, usar um elemento neutro dentro de um array, a ponto de criar um array com qualquer quantidade de elementos. Isto sim parece ser genial. Chega até parecer um pouco se maldade, dizer que isto deveria ser de conhecimento de qualquer programador iniciante. Mas sim. Com base no que vimos até este ponto. Podemos e iremos construir algo que consiga fazer isto. Usar um tipo de implementação que poucas linguagens conseguem fazer. No entanto, muito mais do que isto. Iremos criar algo aqui, que é básico. E muitos programadores que se dizem mais experientes não faziam, ou fazem ideia de que é possível ser feito no MQL5.

Para tornar as coisas o mais didáticas e simples de entender. Vamos começar fazendo o seguinte: Definindo algumas variáveis e constantes para serem usadas no nosso modelo de exemplo. Assim, surge o código que é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     const uint  ui = 0xCADA0169;
09.     ushort      us = 0x43BC;
10.     uchar       uc = B'01011101';
11. 
12.     uchar Infos[];
13. 
14.     PrintFormat("Translation personal.\n" +
15.                 "FUNCTION: [%s]\n" +
16.                 "ui => 0x%s\n" + 
17.                 "us => 0x%s\n" +
18.                 "uc => B'%s'",
19.                 __FUNCTION__,
20.                 ValueToString(ui, FORMAT_HEX),
21.                 ValueToString(us, FORMAT_HEX),
22.                 ValueToString(uc, FORMAT_BINARY)
23.                );
24.     
25.     ArrayFree(Infos);
26. }
27. //+------------------------------------------------------------------+

Código 06

Ok, quando você executar este código 06, irá ver no terminal algo parecido com o mostrado na imagem logo abaixo.

Imagem 02

Bem isto não é nada de extraordinário. Na verdade, já era até mesmo esperado. Mas agora vem a parte interessante. Veja, que neste código 06, na linha 12 já adicionei um array do qual iremos precisar. Eu pessoalmente prefiro o tipo sem sinal, por isto utilizo o tipo uchar. Mas outros podem preferir usar um tipo com sinal. Assim irão preferir usar o tipo char. De qualquer forma, não irá fazer diferença para o nosso propósito.

Porém quero lembrar, que a implementação que será vista aqui, tem como objetivo apenas a didática. Não é de maneira alguma a melhor maneira de implementar o mecanismo que será mostrado. Existem forma bem mais adequadas de se fazer isto. Porém exigem utilização de alguns métodos e conceitos que ainda não foram explicados. Mas como estes mesmos conceitos, dos quais ainda não foram explicados, surgiram devido justamente para facilitar o que será visto aqui. Acho perfeitamente válido e prático, mostrar primeiro o conceito, e depois os métodos criados para tornar mais simples a própria implementação. Já que uma coisa irá levar a outra de uma maneira muito natural. Desta forma, o código que iremos criar contém muitas partes inline. Mas isto é apenas por que seria difícil explicar como funciona o método, se a implementação fosse feita de outra maneira.

Então vamos ao ritual de transferir os valores declarados nas linhas oito, nove e dez, para dentro do array. Lembrando que precisamos fazer isto, de forma a depois reconstruir estes mesmos valores. Caso contrário a implementação seria completamente inútil.

Entendido este critério, vamos a primeira parte da implementação. E irei fazer isto aos poucos para que todos, mesmo aqueles que estão começando consigam entender o que está sendo criado. Esta primeira parte  pode ser observada logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     const uint  ui = 0xCADA0169;
09.     ushort      us = 0x43BC;
10.     uchar       uc = B'01011101';
11. 
12.     uchar Infos[];
13. 
14.     PrintFormat("Translation personal.\n" +
15.                 "FUNCTION: [%s]\n" +
16.                 "ui => 0x%s\n" + 
17.                 "us => 0x%s\n" +
18.                 "uc => B'%s'\n",
19.                 __FUNCTION__,
20.                 ValueToString(ui, FORMAT_HEX),
21.                 ValueToString(us, FORMAT_HEX),
22.                 ValueToString(uc, FORMAT_BINARY)
23.                );
24.     
25.     ArrayResize(Infos, Infos.Size() + sizeof(ui) + 1);
26.     ArrayResize(Infos, Infos.Size() + sizeof(us) + 1);
27.     ArrayResize(Infos, Infos.Size() + sizeof(uc) + 1);
28. 
29.     ZeroMemory(Infos);
30. 
31.     Print("******************");
32.     PrintFormat("The Infos block contains %d bytes.", Infos.Size());
33.     ArrayPrint(Infos);
34.     Print("******************");
35. 
36.     ArrayFree(Infos);
37. }
38. //+------------------------------------------------------------------+

Código 07

Quando executada, iremos ver no terminal o que é mostrado na imagem logo abaixo.

Imagem 03

Agora preste muita atenção meu caro leitor. Isto para não ficar perdido no meio da explicação. Este trecho que está sendo destacado na imagem 03. Nada mais é do que a execução das linhas 31 até a linha 34. No entanto, você pode notar que estamos mostrando tanto o conteúdo da memória como também a quantidade de memória alocada. É interessante notar que a memória está sendo alocada entre as linhas 25 e 27. Mas isto daqui é apenas o início do código. Já que iremos tornar as coisas um pouco mais agradáveis, devido ao fato de estamos fazendo a implementação em pequenos passos. De certa maneira o código da linha 29 é desnecessário. Definido justamente a forma como iremos trabalhar os valores.

Ok, acredito que o restante já esteja bem fixado em sua mente. Assim podemos partir para o que seria o segundo passo. Este é visto logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     const uint  ui = 0xCADA0169;
09.     ushort      us = 0x43BC;
10.     uchar       uc = B'01011101';
11. 
12.     uchar       Infos[],
13.                 counter = 0;
14.     uint        start,
15.                 number;
16. 
17.     PrintFormat("Translation personal.\n" +
18.                 "FUNCTION: [%s]\n" +
19.                 "ui => 0x%s\n" + 
20.                 "us => 0x%s\n" +
21.                 "uc => B'%s'\n",
22.                 __FUNCTION__,
23.                 ValueToString(ui, FORMAT_HEX),
24.                 ValueToString(us, FORMAT_HEX),
25.                 ValueToString(uc, FORMAT_BINARY)
26.                );
27.     
28.     number = sizeof(ui) + 1;
29.     start = Infos.Size();
30.     ArrayResize(Infos, start + number);
31.     ArrayFill(Infos, start, number, 0);
32.     Infos[counter++] = sizeof(ui);
33. 
34.     number = sizeof(us) + 1;
35.     start = Infos.Size();
36.     ArrayResize(Infos, start + number);
37.     ArrayFill(Infos, start, number, 0);
38.     Infos[counter++] = sizeof(us);
39. 
40.     number = sizeof(uc) + 1;
41.     start = Infos.Size();
42.     ArrayResize(Infos, start + number);
43.     ArrayFill(Infos, start, number, 0);
44.     Infos[counter++] = sizeof(uc);
45. 
46.     Print("******************");
47.     PrintFormat("The Infos block contains %d bytes.", Infos.Size());
48.     ArrayPrint(Infos);
49.     Print("******************");
50. 
51.     ArrayFree(Infos);
52. }
53. //+------------------------------------------------------------------+

Código 08

Agora quando usamos este código 08, o resultado já começa a ficar um tanto mais interessante. Isto pode ser visto na imagem logo abaixo.

Imagem 04

Observe que temos alguns valores agora no array, que está sendo criado. Estes valores estão sendo colocados ali, justamente por conta das linhas 32, 38 e 44. Sendo este o indicativo de quantos bytes teremos. Mas existe um pequeno problema aqui. Que será resolvido no próximo passo. Mas antes vamos entender o que mudou entre o código 07 e este código 08. Isto por que você pode observar que estamos criando pequenos blocos, que poderiam ser colocados em alguma função, ou mesmo algum procedimento externo. Isto claramente é observado entre as linhas 28 até a 32.

Logo depois temos algo muito parecido entre as linhas 34 e 38. E uma repetição muito semelhante entre as linhas 40 e 44. Mas como foi dito anteriormente. Não irei implementar isto em um procedimento ou função externa. Já que ao fazer isto, eu estaria infringindo uma regra da qual me impus para demonstrar este mecanismo que está sendo implementado. Que era o de não fazer nada que ainda não foi mostrado.

Assim sendo, se você já sabe como unir todos estes blocos em um único. Ótimo. Já que a única diferença entre eles é justamente a variável que cada um deles está usando para alocar memória suficiente para comportar o valor. E este é o próximo passo. Colocar o valor dentro do array. Isto é visto logo na sequência. E desta vez, você notará que o código mudou só um pouco mais.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     const uint  ui = 0xCADA0169;
09.     ushort      us = 0x43BC;
10.     uchar       uc = B'01011101';
11. 
12.     uchar       Infos[],
13.                 counter = 0;
14.     uint        start,
15.                 number;
16. 
17.     PrintFormat("Translation personal.\n" +
18.                 "FUNCTION: [%s]\n" +
19.                 "ui => 0x%s\n" + 
20.                 "us => 0x%s\n" +
21.                 "uc => B'%s'\n",
22.                 __FUNCTION__,
23.                 ValueToString(ui, FORMAT_HEX),
24.                 ValueToString(us, FORMAT_HEX),
25.                 ValueToString(uc, FORMAT_BINARY)
26.                );
27.     
28.     number = sizeof(ui) + 1;
29.     start = Infos.Size();
30.     ArrayResize(Infos, start + number);
31.     Infos[counter++] = sizeof(ui);
32.     Infos[counter++] = (uchar)(ui >> 24);
33.     Infos[counter++] = (uchar)(ui >> 16);
34.     Infos[counter++] = (uchar)(ui >> 8);
35.     Infos[counter++] = (uchar)(ui & 0xFF);
36. 
37.     number = sizeof(us) + 1;
38.     start = Infos.Size();
39.     ArrayResize(Infos, start + number);
40.     Infos[counter++] = sizeof(us);
41.     Infos[counter++] = (uchar)(us >> 8);
42.     Infos[counter++] = (uchar)(us & 0xFF);
43. 
44.     number = sizeof(uc) + 1;
45.     start = Infos.Size();
46.     ArrayResize(Infos, start + number);
47.     Infos[counter++] = sizeof(uc);
48.     Infos[counter++] = (uc);
49. 
50.     Print("******************");
51.     PrintFormat("The Infos block contains %d bytes.", Infos.Size());
52.     ArrayPrint(Infos);
53.     Print("******************");
54. 
55.     ArrayFree(Infos);
56. }
57. //+------------------------------------------------------------------+

Código 09

Estamos quase terminando. Falta só mais um passo para que tudo seja perfeitamente compreendido e implementado. No entanto, se você executar este código 09, irá notar que a saída ficou levemente diferente, como pode ser observado logo na imagem abaixo.

Imagem 05

Neste caso, foi feita a marcação dos valores que estavam originalmente posicionados na imagem 04. Sei que pode parecer um tanto quanto estranho estes valores que estão sendo mostrado nesta figura 05. Mas se você observar com atenção ao que está ocorrendo no código 09. Perceberá que este são os valores que de fato fazem parte dos dados contidos nas linhas oito, nove e dez. Talvez você não esteja acreditando nisto. Então vamos ao último passo. E este é implementado no código visto logo na sequência.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     const uint  ui = 0xCADA0169;
09.     ushort      us = 0x43BC;
10.     uchar       uc = B'01011101';
11. 
12.     uchar       Infos[],
13.                 counter = 0;
14.     uint        start,
15.                 number;
16. 
17.     PrintFormat("Translation personal.\n" +
18.                 "FUNCTION: [%s]\n" +
19.                 "ui => 0x%s\n" + 
20.                 "us => 0x%s\n" +
21.                 "uc => B'%s'\n",
22.                 __FUNCTION__,
23.                 ValueToString(ui, FORMAT_HEX),
24.                 ValueToString(us, FORMAT_HEX),
25.                 ValueToString(uc, FORMAT_BINARY)
26.                );
27.     
28.     number = sizeof(ui) + 1;
29.     start = Infos.Size();
30.     ArrayResize(Infos, start + number);
31.     Infos[counter++] = sizeof(ui);
32.     Infos[counter++] = (uchar)(ui >> 24);
33.     Infos[counter++] = (uchar)(ui >> 16);
34.     Infos[counter++] = (uchar)(ui >> 8);
35.     Infos[counter++] = (uchar)(ui & 0xFF);
36. 
37.     number = sizeof(us) + 1;
38.     start = Infos.Size();
39.     ArrayResize(Infos, start + number);
40.     Infos[counter++] = sizeof(us);
41.     Infos[counter++] = (uchar)(us >> 8);
42.     Infos[counter++] = (uchar)(us & 0xFF);
43. 
44.     number = sizeof(uc) + 1;
45.     start = Infos.Size();
46.     ArrayResize(Infos, start + number);
47.     Infos[counter++] = sizeof(uc);
48.     Infos[counter++] = (uc);
49. 
50.     Print("******************");
51.     PrintFormat("The Infos block contains %d bytes.", Infos.Size());
52.     ArrayPrint(Infos);
53.     Print("******************");
54. 
55.     Procedure(Infos);
56. 
57.     ArrayFree(Infos);
58. }
59. //+------------------------------------------------------------------+
60. void Procedure(const uchar &arg[])
61. {
62.     Print("Translation personal.\n" +
63.           "FUNCTION: ", __FUNCTION__);
64. 
65.     for (uchar c = 0; c < arg.Size(); ) switch(arg[c++])
66.     {
67.         case 4:
68.             {
69.                 uint value = 0;
70. 
71.                 for (uchar i = 0; (c < arg.Size()) && (i < (sizeof(value))); c++, i++)
72.                     value = (value << 8) | arg[c];
73.                 Print("0x", ValueToString(value, FORMAT_HEX));
74.             }
75.             break;
76.         case 2:
77.             {
78.                 ushort value = 0;
79. 
80.                 for (uchar i = 0; (c < arg.Size()) && (i < sizeof(value)); c++, i++)
81.                     value = (value << 8) | arg[c];
82.                 Print("0x", ValueToString(value, FORMAT_HEX));
83.             }
84.             break;
85.         case 1:
86.             {
87.                 uchar value = 0;
88. 
89.                 for (uchar i = 0; (c < arg.Size()) && (i < sizeof(value)); c++, i++)
90.                     value = (value << 8) | arg[c];
91.                 Print("B'", ValueToString(value, FORMAT_BINARY), "'");
92.             }
93.             break;
94.     }
95. 
96. }
97. //+------------------------------------------------------------------+

Código 10

E aí está meu caro leitor, um código criado por um iniciante em programação. Totalmente escrito em MQL5, e que tem a capacidade de transferir uma quantidade infinita de informações dentro de um único bloco de array. O resultado da execução deste código pode ser observado na imagem logo abaixo

Imagem 06

Aparentemente isto seria algo impossível de ser feito em MQL5. Ou seja, implementar um mecanismo, que existem em linguagens como C e C++. Capaz de enviar uma quantidade ilimitada de valores de uma função para outra. E dependendo da maneira como você agrega as coisas, até mesmo de uma aplicação para outra dentro do MetaTrader 5. Porém, fazer isto, já é um tópico um pouco mais avançado. Necessitando que você de fato venha a compreender diversos outros conceitos e coisas presentes no MQL5. Assim como também conseguir compreender de maneira adequada como o MetaTrader 5 funciona.

E quando digo funciona, não estou dizendo em termos de colocar coisas no gráfico. Isto é totalmente sem graça e chato. Não dá nenhum tipo de tesão ou emoção. Quando digo funciona, estou querendo dizer, que você precisa saber por que o MetaTrader 5 faz as coisas que ele FAZ. Mas principalmente como usar os mecanismos que ele utiliza, ou disponibiliza, para de fato conseguir executar coisas, como estas que estou mostrando neste momento. Coisas que ao meu ver são básicas e muito simples. Porém, que poucos realmente conseguem compreender e implementar.

Mas veja como tudo é lindo e maravilhoso. Quando conceitos básicos são colocados em prática. Aqui neste código 10, temos o seguinte trabalho sendo feito. Entre as linhas 28 e 48, criamos o array. E depois quando executamos a linha 55, enviamos este mesmo array, para dentro de um procedimento. Mas que poderia ser qualquer outra coisa. Ali, usando um mecanismo muito simples. Desmontamos o que foi montado entres as linhas informadas a pouco.

Sei que muitos podem estar dizendo: Cara, para que criar algo deste tipo? Complicar o código de maneira completamente desnecessária. Bem, sinto muito ter que repetir novamente o que foi dito no início deste tópico. Que era justamente o fato de que, o que seria implementado aqui, não era de forma alguma a melhor maneira de se fazer isto. Porém, como este conhecimento sendo devidamente assimilado e você, meu caro e estimado leitor, conseguindo compreender o que foi mostrado aqui. Podemos partir para algo que de outra forma seria muito mais complicado de explicar.

No entanto, devido ao fato de que o que será explicado nos próximos artigos, tem tudo a ver com este código 10. A criação do mesmo, me parece bastante interessante é plausível. Não sendo nenhuma complicação. Muito pelo contrário. Este passo a passo, que estará no anexo, da mesma maneira que foi mostrado aqui. Servirá muito bem, como ponte de apoio para aqueles que desejam de fato, explorar o MQL5 e o MetaTrader 5 de uma maneira muito mais avançada.

Então meu caro leitor, não perca tempo esperando respostas, as questões que vão surgindo em sua mente. Procure estudar cada detalhe visto, neste e nos demais artigos. E principalmente praticar o que vai sendo mostrado. Pois o conhecimento vai se acumulando de maneira muito rápida e sem retorno. Assim como as dúvidas que podem surgir devido a falta de prática.

E para fechar com chave de ouro este artigo. Vou mostrar como o mesmo código 10, poderia ser escrito. Isto para mostrar que podemos fazer as coisas de uma maneira mais compacta. E caso você venha a sentir mais confortável, analisando um código mais compacto e que faz, basicamente a mesma coisa. Tal código mais compacto pode ser observado logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #include "Tutorial\File 01.mqh"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     const uint  ui = 0xCADA5169;
09.     ushort      us = 0x43BC;
10.     uchar       uc = B'01011101';
11. 
12.     uchar       Infos[],
13.                 counter = 0;
14.     uint        start,
15.                 number;
16. 
17.     PrintFormat("Translation personal.\n" +
18.                 "FUNCTION: [%s]\n" +
19.                 "ui => 0x%s\n" + 
20.                 "us => 0x%s\n" +
21.                 "uc => B'%s'\n",
22.                 __FUNCTION__,
23.                 ValueToString(ui, FORMAT_HEX),
24.                 ValueToString(us, FORMAT_HEX),
25.                 ValueToString(uc, FORMAT_BINARY)
26.                );
27.     
28.     number = sizeof(ui) + 1;
29.     start = Infos.Size();
30.     ArrayResize(Infos, start + number);
31.     Infos[counter++] = sizeof(ui);
32.     Infos[counter++] = (uchar)(ui >> 24);
33.     Infos[counter++] = (uchar)(ui >> 16);
34.     Infos[counter++] = (uchar)(ui >> 8);
35.     Infos[counter++] = (uchar)(ui & 0xFF);
36. 
37.     number = sizeof(us) + 1;
38.     start = Infos.Size();
39.     ArrayResize(Infos, start + number);
40.     Infos[counter++] = sizeof(us);
41.     Infos[counter++] = (uchar)(us >> 8);
42.     Infos[counter++] = (uchar)(us & 0xFF);
43. 
44.     number = sizeof(uc) + 1;
45.     start = Infos.Size();
46.     ArrayResize(Infos, start + number);
47.     Infos[counter++] = sizeof(uc);
48.     Infos[counter++] = (uc);
49. 
50.     Print("******************");
51.     PrintFormat("The Infos block contains %d bytes.", Infos.Size());
52.     ArrayPrint(Infos);
53.     Print("******************");
54. 
55.     Procedure(Infos);
56. 
57.     ArrayFree(Infos);
58. }
59. //+------------------------------------------------------------------+
60. void Procedure(const uchar &arg[])
61. {
62.     Print("Translation personal.\n" +
63.           "FUNCTION: ", __FUNCTION__);
64. 
65.     ulong value;
66. 
67.     for (uchar c = 0; c < arg.Size(); )
68.     {
69.         value = 0;
70.         for (uchar j = arg[c++], i = 0; (c < arg.Size()) && (i < j); i++, c++)
71.             value = (value << 8) | arg[c];
72.         Print("0x", ValueToString(value, FORMAT_HEX), " B'", ValueToString(value, FORMAT_BINARY), "'");
73.     }
74. }
75. //+------------------------------------------------------------------+

Código 11

Ao executar este código 11, teremos um resultado que é mostrado na imagem logo na sequência.

Imagem 07

Note que temos uma informação levemente diferente nesta imagem 07, do que a vista na imagem 06. Isto é justamente devido ao fato, de que no momento em que estamos recriando os dados originais. Estamos fazendo isto dentro de um único laço. E este é o laço visto na linha 70. Este laço é relativamente simples. Porém é necessário que você o estude com calma meu caro leitor. Isto para que consiga entender como ele consegue recriar a informação que foi armazenada anteriormente.

Mas basicamente, ele estará sempre olhando para a posição onde dizemos qual é o número de bytes, ou elementos que fazem parte de um bloco da informação original. Justamente por conta disto, o laço externo, ou seja, o da linha 67, precisou sofrer uma pequena mudança na sua estrutura. Caso contrário, não iriamos de fato conseguir reaver as informações gravadas no array.


Considerações finais

Este artigo, tem como objetivo server de ponte entre o que estávamos vendo antes, e o que será visto no próximo artigo. Sei que muitos podem achar algo desnecessário e completamente maluco o que foi visto e implementado aqui. Porém, se você, meu caro e estimado leitor. De fato, conseguir captar o objetivo e propósito disto que foi apresentado neste artigo. Irá notar que existe, ou melhor dizendo, surge a necessidade de usarmos, ou desenvolvermos algo a mais na linguagem.

E de fato, tal coisa realmente se encontra implementada na linguagem MQL5. Tanto que está coisa será tema do próximo artigo. Mas se você ainda não conseguiu captar tal ideia. Pense no seguinte: O que seria preciso, para que não fosse necessário, implementar o código que se encontra entre as linhas 28 até 48. Isto sem perda de recursos. Permitindo assim que aquelas mesmas linhas, pudessem ser simplificadas em um código muito mais simples e prático? Pense nisto, e a resposta irá vir no próximo artigo. Até lá, estude e pratique com os códigos vistos neste artigo. Os mesmos estarão disponíveis no anexo.

Arquivos anexados |
Anexo.zip (5.5 KB)
Redes neurais de maneira fácil (Parte 94): Otimização da sequência de dados iniciais Redes neurais de maneira fácil (Parte 94): Otimização da sequência de dados iniciais
Ao trabalhar com séries temporais, geralmente usamos os dados na sequência histórica. Mas isso é realmente o mais eficiente? Há quem acredite que modificar a sequência dos dados iniciais pode aumentar a eficácia dos modelos de aprendizado. Neste artigo, vou apresentar um desses métodos.
Desenvolvendo um sistema de Replay (Parte 72): Uma comunicação inusitada (I) Desenvolvendo um sistema de Replay (Parte 72): Uma comunicação inusitada (I)
O que iremos construir será complexo de entender. Por isso, apresentarei apenas o início da construção neste artigo. Leia com calma, pois entender o conteúdo aqui é essencial para o próximo passo. O objetivo deste conteúdo é apenas didático, sem aplicação prática além do aprendizado e estudo dos conceitos apresentados.
Dominando a Dinâmica do Mercado: Criando um Expert Advisor (EA) para Estratégia de Suporte e Resistência Dominando a Dinâmica do Mercado: Criando um Expert Advisor (EA) para Estratégia de Suporte e Resistência
Um guia abrangente para desenvolver um algoritmo de negociação automatizado baseado na estratégia de Suporte e Resistência. Informações detalhadas sobre todos os aspectos da criação de um expert advisor em MQL5 e testá-lo no MetaTrader 5 – desde a análise dos comportamentos de faixa de preço até o gerenciamento de risco.
Como visualizar operações diretamente no gráfico sem se perder no histórico de negociações Como visualizar operações diretamente no gráfico sem se perder no histórico de negociações
Neste artigo, criaremos uma ferramenta simples para visualização prática de posições e operações diretamente no gráfico, com navegação por teclas. Isso permitirá que traders estudem visualmente operações individuais e obtenham todas as informações sobre os resultados das negociações diretamente no local.