Uso dos recursos no MQL5

MetaQuotes | 10 janeiro, 2014

A importância da interface nos programas modernos

Muito tempo atrás, o principal propósito dos programas de computador era fazer cálculos matemáticos pesados e processar grandes quantidades de dados. Mas com o aumento da potência dos computadores, as prioridades mudaram. Agora, entre dois programas com funcionalidade idêntica, um usuário pode escolher aquele que seja mais fácil de se trabalhar.

Hoje em dia, não é suficiente escrever um programa de acordo com o algoritmo de cálculo necessário, mas você também deve fornecer uma interface gráfica amigável ao usuário. Mesmo análises técnicas surgiram do desejo dos negociantes terem uma representação visual do estado atual do mercado: linhas de tendência, níveis de suporte e resistência, vários canais e indicadores técnicos foram desenvolvidos para mostrar uma imagem objetiva do que está acontecendo.

A nova linguagem do MQL5 fornece ferramentas ainda mais poderosas para criar aplicações inteiramente funcionais que não requerem nada além do que o Terminal cliente MetaTrader 5. Neste artigo, mostraremos como usar os Recursos para criar um arquivo EX5 executável com uma interface amigável para o usuário, e este arquivo não precisará de nenhuma operação de rotina como instalação ou início.


As possibilidades do MQL5

Primeiro e acima de tudo, claro, a possibilidade de trabalhar com gráficos é muito importante. Podem ser encontrados exemplos em artigos, aqui estão alguns deles:

É o uso dos elementos do gráfico que torna um programa mais interessante e fácil de controlar a partir da perspectiva do usuário. Além das ferramentas clássicas para Análises Técnicas, o terminal MetaTrader 5 fornece uma vasta gama de objetos gráficos, que podem ser utilizados como tijolos para construir sua própria interface gráfica.


Utilização de arquivos de imagem para criação de interface

Para criar uma interface especial, geralmente, são usadas as imagens dos arquivos gráficos. Isso permite conseguir um design reconhecível exclusivo de vários elementos de controle. A linguagem do MQL5 oferece dois objetos gráficos que utilizam gráficos:

Estes dois objetos permitem que você crie uma grande variedade de controles e os compare com os handlers de Eventos com um "clique do mouse" (CHARTEVENT_OBJECT_CLICK). Para definir a imagem desejada para OBJ_BITMAP ou OBJ_BITMAP_LABEL, especifique o arquivo BMP desejado na propriedade OBJPROP_BMPFILE. Isso pode ser feito manualmente na guia "Parameters" (Parâmetros) do objeto gráfico.


A segunda e principal forma para um programador MQL5 é especificar um nome de arquivo para a propriedade OBJPROP_BMPFILE utilizando a função ObjectSetString(). Por exemplo:

   //--- Load an image for the "Pressed" button state
   bool set=ObjectSetString(0,object_name,OBJPROP_BMPFILE,0,bmp_file_name);

Um algoritmo padrão de uso do OBJ_BITMAP ou OBJ_BITMAP_LABEL:

  1. Crie um objeto utilizando a função ObjectCreate().
  2. Usando a função ObjectSetInteger() fixe o objeto ao canto do gráfico desejado, se necessário. As coordenadas X e Y do ponto de fixação em pixels serão definidas relativas a este canto.
  3. Em ObjectSetInteger(), defina os valores das coordenadas X e Y (OBJPROP_XDISTANCE e OBJPROP_YDISTANCE).
  4. Utilizando ObjectSetString(), defina o valor da propriedade OBJPROP_BMPFILE para o objeto gráfico (um para BITMAP ou dois para OBJ_BITMAP_LABEL).
  5. Para o objeto OBJ_BITMAP_LABEL, utilizando ObjectSetInteger(), você pode definir o estado atual do botão - pressionado ou não pressionado (OBJPROP_STATE é verdadeiro ou falso).

Após criar e configurar o objeto, durante a execução do programa MQL5, você pode mudar dinamicamente não apenas a posição e condição do objeto gráfico, mas também mudar o valor da propriedade OBJ_BITMAP_LABEL para exibir imagens. Assim, a interface pode ser muito flexível e reconfigurável.


Reproduzindo sons

Uma conveniência adicional necessária nos programas é a capacidade de perguntar ao usuário sobre uma ação no caso de uma determinada situação. Para implementar esta interação reversa, geralmente a reprodução de diferentes sons é utilizada, dependendo do evento. Isso aliviará o negociador de uma observação contínua de gráficos de preços, voltando sua atenção apenas em casos necessários. Para reproduzir arquivos de som, é utilizada a função PlaySound() no MQL5.

A função PlaySound() é muito fácil de usar e requer apenas a especificação de um caminho para um arquivo de som:

//--- The path to a sound file  
string wav_file_name="Ok.wav";
...
//--- Play a sound from the file terminal_directory\Sounds\Ok.wav
bool played=PlaySound(wav_file_name);
if(!played)
  //--- Failed to play the sound, notify of this
  {
   PrintFormat("Failed to play file %s. Error code=%d", wav_file_name, GetLastError());
  }


Onde localizar arquivos de som e imagem

As funções ObjectSetString() e PlaySound() requerem a especificação de um caminho para um arquivo. Por questões de segurança, todos os arquivos que são usados nos programas MQL5 estão localizados dentro do sandbox de arquivo. Isso significa os arquivos só podem ser armazenados em determinados diretórios, o trabalho com arquivos de outros diretórios não é permitido. Primeiro, você precisa saber quais diretórios estão disponíveis para as funções e operações de arquivo e como são nomeados.

Existem três diretórios diferentes:

Para determinar o local destes diretórios, você pode usar o script WhereMyFolders.mq5:

//+------------------------------------------------------------------+
//|                                               WhereMyFolders.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- The folder from which the terminal is started - terminal_directory
   string terminal_path=TerminalInfoString(TERMINAL_PATH);
//--- The folder that stores the terminal data - terminal_data_directory
   string terminal_data_path=TerminalInfoString(TERMINAL_DATA_PATH);
//--- The shared folder of all client terminals - common_terminal_folder
   string common_data_path=TerminalInfoString(TERMINAL_COMMONDATA_PATH);   
   //--- Show all the paths 
   Print("TERMINAL_PATH(terminal_directory) = ",TerminalInfoString(TERMINAL_PATH));
   Print("TERMINAL_DATA_PATH(terminal_data_directory) = ",TerminalInfoString(TERMINAL_DATA_PATH));
   Print("TERMINAL_COMMONDATA_PATH(comon_terminal_folder) = ",TerminalInfoString(TERMINAL_COMMONDATA_PATH));   
  }

Importante: Em alguns casos, o local do terminal_directory e terminal_data_directory pode coincidir, mas é melhor nunca confiar nisso e, assim, não confundir estes conceitos.

Os arquivos de imagem e som são pesquisados pelo sistema runtime terminal na seguinte ordem:

Para a função PlaySound() há apenas mais uma coisa: se o arquivo não for localizado utilizando os dois métodos acima, este arquivo de som é buscado por relativo ao terminal_directory\Sounds\.


Exemplos para arquivos de Som:


Exemplos de arquivos de imagem:

Observe que a barra invertida dupla "\\" é usada como separador ao escrever o caminho.

Importante: Ao especificar o caminho, sempre use barras invertidas duplas como separador, porque uma barra invertida única é um caractere de controle para o compilador quando analisa as linhas constantes e constantes de caractere no código-fonte de um programa.


Novas possibilidades - Recursos

Para usar imagens e sons no seu programa MQL5, certifique-se que todos os arquivos de mídia estejam localizados nas pastas adequadas. Isso impõe uma desvantagem definitiva na transferência de arquivo EX5 compilado de um terminal para outro. Mas, é possível resolver este problema no estágio de escrita do código. Em tais casos, use os recursos.

Para utilizar um recurso em um programa, ele deve ser declarado usando a diretiva do compilador #resource.

 #resource path_to_resource_file

Agora, este recurso pode ser usado em vez de um caminho de arquivo. O comando #resource diz ao compilador que o recurso no caminho especificado path_to_resource_file deve ser incluso no arquivo EX5 executável. Assim, todas as imagens e sons necessários podem ser localizados diretamente em um arquivo EX5. Agora, para iniciar um programa MQL5 em outro terminal, você não precisará transmitir todos os arquivos o utilizando.

Qualquer arquivo EX5 pode conter recursos, e qualquer programa EX5 pode usar recursos de outro programa EX5. Ou seja, um Expert Advisor pode usar os recursos que estão localizados em um indicador ou biblioteca EX5. Esta é mais uma conveniência de uso de recursos.

O uso de recursos permite que você obtenha tudo em um só - o arquivo executável em si e todos os recursos que ele usa são compilados em um arquivo EX5 durante a compilação de um código-fonte.


Procura de recurso por um compilador

Um recurso é especificado utilizando a diretiva #resource "" (caminho para o arquivo de recurso).

 #resource ""
O comprimento da string constante > não deve exceder a 63 caracteres. O compilador procura por um recurso no caminho especificado na seguinte sequência:1

Importante: No caminho do recurso, é inaceitável usar substrings "..\\" e ":\\".

Exemplos de recurso incluindo os Recursos do tópico Ajuda:

//--- Correct specification of a resource
#resource "\\Images\\euro.bmp" // euro.bmp is located in terminal_data_directory\MQL5\Images\
#resource "picture.bmp"        // picture.bmp is locate in the same directory with the source file
#resource "Resource\\map.bmp"  // The resource is located in the folder source_file_directory\Resource\map.bmp
 
//--- incorrect specification of resources
#resource ":picture_2.bmp"     // Use of ":" is not allowed
#resource "..\\picture_3.bmp"  // Use of ".." is not allowed
#resource "\\Files\\Images\\Folder_First\\My_panel\\Labels\\too_long_path.bmp" //More than 63 characters


Nomes dos recursos

Após a declaração de um recurso utilizando a diretiva #resource, ele pode ser utilizado em qualquer parte de um programa. Para o nome do recurso, será utilizado seu caminho sem a barra no começo da string que define o caminho para o recurso.

Exemplos:

//---Examples of specifying resources and their names in the comments
#resource "\\Images\\cat.bmp"           // Resource name - Images\cat.bmp
#resource "dog.bmp"                     // Resource name - dog.bmp
#resource "Resource\\map.bmp"           // Resource name - Resource\map.bmp
#resource "\\Files\\Pictures\\bird.bmp" // Resource name - Files\Pictures\bird.bmp
#resource "\\Files\\good.wav"           // Resource name - Files\good.wav"
#resource "\\Sounds\\thrill.wav"        // Resource name - Sounds\thrill.wav"

Nomes de recursos independem da fonte - para o compilador, os nomes dog.bmp e DOG.bmp serão a mesma coisa.


Utilização de recursos próprios e de terceiros

Para utilizar um recurso, você deve especificar seu nome. O nome do recurso e seu caminho sem uma barra invertida no começo da linha. Quando você utiliza seu próprio recurso, o atributo especial "::" deve ser adicionado antes do nome do recurso.

//--- Use of resources
ObjectSetString(0,bitmap_name,OBJPROP_BMPFILE,0,"::Images\\cat.bmp");
...
ObjectSetString(0,my_bitmap,OBJPROP_BMPFILE,0,"::dog.bmp");
...
set=ObjectSetString(0,bitmap_label,OBJPROP_BMPFILE,1,"::Files\\Pictures\\bird.bmp");
...
PlaySound("::Files\\good.wav");
...
PlaySound("::Sounds\\thrill.wav");

Você pode usar não apenas seus próprios recursos (de seu arquivo EX5), mas também de qualquer um dos módulos e bibliotecas EX5. Desta forma, você pode criar um repositório de recursos e usá-los em muitos outros programas MQL5.

Para utilizar recursos de outro arquivo EX5, o nome do recurso deve ser especificado na forma :: (nome do recurso). Suponha que o script Draw_Triangles_Script.mq5 contenha um recurso para uma imagem no arquivo triangle.bmp:

 #resource "\\Files\\triangle.bmp"

Então, seu nome, para usar no script em si, ficará assim "Files\triangle.bmp", e para usá-lo, deve ser adicionado "::" no nome do recurso - "::Files\triangle.bmp". A fim de utilizar o mesmo recurso de outro programa, por exemplo, de um Expert Advisor, precisamos adicionar ao nome do recurso o caminho para o arquivo EX5 relativo à terminal_data_directory\MQL5\ e o nome do arquivo EX5 do script - Draw_Triangles_Script.ex5. Suponha que o script esteja localizado na pasta padrão terminal_data_directory\MQL5\Scripts\, então, a chamada deve ser escrita da seguinte forma:

//--- Use of a script resource in an Expert Advisor
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"\\Scripts\\Draw_Triangles_Script.ex5::Files\\triangle_1.bmp");

Se o caminho para o arquivo executável não estiver especificado ao chamar o recurso de outro EX5, o arquivo executável é procurado na mesma pasta que contém o programa que chama o recurso. Isso significa o seguinte: se um Expert Advisor estiver localizado em terminal_data_directory\MQL5\Experts\ e um recurso do arquivo Draw_Triangles_Script.ex5 for solicitado nele sem a especificação do caminho, então o arquivo será procurado em terminal_data_directory\MQL5\Experts\.

//--- Request for a resource from a script in an Expert Advisor without path specification
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"Draw_Triangles_Script.ex5::Files\\triangle_1.bmp");


Compressão de recursos nos arquivos EX5 - Como funciona

Arquivos em BMP e WAV são automaticamente comprimidos antes de serem inclusos em um arquivo EX5 executável. Isso significa que o uso de recursos não apenas permite que você crie programas MQL5 cheios de recursos, mas também reduz o tamanho geral dos arquivos necessários pelo terminal ao usar imagens e sons em comparação ao modo convencional de escrever programas MQL5.

O tamanho do arquivo de recurso não pode exceder 16 Mb.

Importante: A vantagem adicional em utilizar recursos é a compressão automática de arquivos WAV e BMP ao compilar em um arquivo EX5 executável. Isso reduz não apenas a quantidade, mas também o tamanho dos arquivos utilizados pelo programa.

Por exemplo, considere um pequeno programa Animals_EA.mq5. Um pequeno bloco do código para uso de recurso é dado abaixo:

//+------------------------------------------------------------------+
//|                                                   Animals_EA.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//--- Declare image resources
#resource "\\Images\\cat.bmp"
#resource "\\Images\\dog.bmp"
#resource "\\Images\\cow.bmp"
#resource "\\Images\\bird.bmp"
//--- Declare sound resources
#resource "\\Files\\MySounds\\cat.wav"
#resource "\\Files\\MySounds\\dog.wav"
#resource "\\Files\\MySounds\\cow.wav"
#resource "\\Files\\MySounds\\bird.wav"
//--- Object names
string cat_dog="cat_dog";
string cow_bird="cow_bird";
string canvas="canvas";
string text="text";
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Create a substrate
   CreateCanvas(canvas,50,50,500,500);
//--- Create buttons
   CreateObjectBITMAP_LABEL(cat_dog,110,120,"::Images\\cat.bmp","::Images\\dog.bmp");
   CreateObjectBITMAP_LABEL(cow_bird,110,330,"::Images\\cow.bmp","::Images\\bird.bmp");
   CreateText(text,"Click on any graphical object",200,90,clrTan);
//--- Give a command for an immediate refresh to see the object
   ChartRedraw();
//---
   return(0);
  }
//+------------------------------------------------------------------+
//|  Creating OBJ_BITMAP_LABEL with the specified images          |
//+------------------------------------------------------------------+
bool CreateObjectBITMAP_LABEL(string obj_name,int X,int Y,string res_name1,string res_name2)
  {
//--- If there is no such an object on the chart
   if(ObjectFind(0,obj_name)==-1)
     {
      //--- Create it
      bool res=ObjectCreate(0,obj_name,OBJ_BITMAP_LABEL,0,0,0);
      //--- Check the result
      if(!res)
        {
         PrintFormat("%s: Failed to create OBJ_BITMAP_LABEL with the name %s. Error code=%d",
                     __FUNCTION__,
                     GetLastError());
         return false;
        }
     }

//--- Set the coordinates
   ObjectSetInteger(0,obj_name,OBJPROP_XDISTANCE,X);
   ObjectSetInteger(0,obj_name,OBJPROP_YDISTANCE,Y);
//--- Disable display on the background
   ObjectSetInteger(0,obj_name,OBJPROP_BACK,false);
//--- Reset the error code
   ResetLastError();
//--- Set an image for the pressed condition
   bool res=ObjectSetString(0,obj_name,OBJPROP_BMPFILE,0,res_name1);
//--- Check the operation result
   if(!res)
     {
      PrintFormat("%s: Failed to upload an image from the resource %s. Error code=%d",
                  __FUNCTION__,
                  res_name1,
                  GetLastError());
      return false;
     }
//--- Set an image for the depressed state
   res=ObjectSetString(0,obj_name,OBJPROP_BMPFILE,1,res_name2);
//--- Check the operation result
   if(!res)
     {
      PrintFormat("%s: Failed to upload an image from the resource %s. Error code=%d",
                  __FUNCTION__,
                  res_name2,
                  GetLastError());
      return false;
     }
//--- Set the button pressed
   ObjectSetInteger(0,obj_name,OBJPROP_STATE,true);
   return true;
  }
//+------------------------------------------------------------------+

A tarefa do programa é desenhar um background azul (substrato), dois botões gráficos que mudam a aparência com o clique do mouse. Quando você clica no substrato, ele muda sua cor de azul para bege, e vice e versa. Em cada mudança, um som é executado, o evento do clique do mouse é manuseado pela função OnChartEvent(). Um gráfico imediatamente após o início do Adviser Animals_EA.mq5 é mostrado na figura.



Dê uma olhada nas propriedades do objeto OBJ_BITMAP_LABEL, por exemplo, cat_dog. Mudar as propriedades do Arquivo Bitmap (Ligado) e Arquivo Bitmap (Desligado) é possível agora através de uma caixa de diálogo, estes campos estão indisponíveis e estão escurecidos.


Importante: Nos objetos gráficos, imagens carregadas a partir de recursos podem ser modificadas apenas programaticamente. Alterar manualmente estas propriedades através da janela Propriedades do objeto se torna inacessível.

O volume total de imagens usado pelo Expert Advisor Animals_EA.mq5 é de 430 kb.


Mas o tamanho do arquivo executável resultante Animals_EA.ex5 que contém todas essas imagens é de 339 kb. Assim, em vez de 9 arquivos (um arquivo MQ5, quatro arquivos BMP e quatro arquivos WAV), temos agora um arquivo EX5 que contém todos os recursos necessários para o programa.

Apenas imagens em 24 ou 32 bits BMP podem ser usadas nos recursos. Imagens de 32-bit BMP podem conter composição alfa - nesse caso, elas serão aplicadas ao gráfico com transparência.

O arquivo do Expert Advisor Animals_EA.mq5, as imagens e os sons estão anexados ao artigo:

Se quiser testar este programa no seu terminal, basta baixar o Expert Advisor Animals_EA.ex5 compilado em anexo, ele contém todos os recursos necessários. Neste caso, você não precisa fazer o download e instalar os arquivos de imagem e som.


Salvando a memória do terminal

Cada recurso é carregado apenas uma vez na memória do terminal. Embora sob condição normal de uso, cada acesso ao arquivo cause um carregamento adicional do arquivo na memória. Por exemplo, suponha que temos 50 objetos OBJ_BITMAP, cada um deles contém a mesma imagem de tamanho 100 kb. Então, durante o uso normal, estes 50 objetos poderiam precisar de memória de 50*100kb=5Mb.

Se declararmos um recurso para a imagem subida, então esta imagem será carregada na memória apenas uma vez, independente do número de objetos nos quais use.

Importante: Os recursos são carregados na memória apenas uma vez e podem economizar memória se usados diversas vezes.


Conclusão

O uso de recursos facilita o uso e distribuição de programas MQL5. Criar ferramentas confortáveis e modernas para negociação que requer o uso de arquivos de imagem e som multimídia. O conceito de recurso no MQL5 é simples e fácil de entender, então teste e veja.

As imagens no formato 32-bit BMP podem conter composição alfa - neste caso elas serão aplicadas ao gráfico com transparência.

Os recursos fornecem as seguintes vantagens: