English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Guia prático do MQL5: Propriedades de posição no painel de informações personalizado

Guia prático do MQL5: Propriedades de posição no painel de informações personalizado

MetaTrader 5Exemplos | 20 março 2014, 13:52
3 901 1
Anatoli Kazharski
Anatoli Kazharski

Introdução

Agora criaremos um Consultor Especialista simples que obterá propriedades de posição no símbolo atual e as exibirá no painel personalizado de informações durante as negociações manuais. O painel de informações será criado usando objetos gráficos e a informação exibida será atualizada a cada ponto. Isto será muito mais conveniente do que ter que executar manualmente todas as vezes o script descrito no artigo anterior da série, chamado "Guia prático do MQL5: Obtendo as propriedades das posições".

 

Desenvolvendo um Consultor Especialista

Vamos começar com objetos gráficos. Para criar o painel de informações, precisamos de objetos para o plano de fundo, cabeçalho, nomes e propriedades de valores de posição. O plano de fundo e o cabeçalho requerem um retângulo que não se move com o preço. O retângulo pode ser criado usando um objeto gráfico como a Etiqueta Retângulo ou Editar, enquanto os nomes e valores das propriedades de objeto serão feitas usando as Etiquetas de Texto.

Antes de prosseguirmos com o código, primeiro prepararemos uma disposição para o painel de informações. Sua conveniência está no fato de que podemos rapidamente modificar qualquer propriedade na janela de configurações e personalizar o visual do painel de informações.

Todo objeto tem uma janela de configurações que pode ser aberta do menu de contextos de um objeto selecionado. A janela de configurações pode também ser aberta da Lista de Objeto (Ctrl+B) ao selecionar o objeto necessário clicando em Propriedades. A disposição do painel de informações é mostrada abaixo. Também pode ser usado para estimar tamanhos e coordenadas quando escrevendo um código. Quando o código para o painel de informações está pronto, você terá de deletar os objetos de disposição manualmente já que o Consultor Especialista não será capaz de 'vê-los' e, portanto, não irá removê-los do gráfico.

Fig. 1. Preparando a disposição para o painel de informações.

Fig. 1. Preparando a disposição para o painel de informações.

Agora precisamos criar um modelo para o Consultor Especialista. Isto pode ser feito rapidamente para o script. No Assistente do MQL5, a opção Consultor Especialista (modelo) é selecionada por padrão. Passaremos pelas próximas etapas sem fazer quaisquer mudanças para as opções já que elas não são necessárias agora. Clique em Terminar e você verá um modelo como abaixo:

//+------------------------------------------------------------------+
//|                                      PositionPropertiesPanel.mq5 |
//|                        Copyright 2012, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2012, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+

Você pode notar que o modelo de Consultor Especialista é diferente do modelo de script. Além das propriedades do programas (#property), há três funções principais: OnInit(), OnDeinit() e OnTick().

A função OnInit() é chamada quando carregando o programa, modificando parâmetros externos, compilando o programa, desde que o programa está naquele momento adicionado ao gráfico, e quando modificando o símbolo ou período. Caso necessário, você pode inicializar certas variáveis ou arranjos (arrays) nesta função para ser possível trabalhar com elas mais tarde.

A função OnDeinit() é chamada quando você exclui o programa do gráfico, muda a conta, símbolo ou período. Todos possíveis motivos de deinicialização são fornecidos na Referência MQL5. Este Consultor Especialista utilizará uma função definida pelo usuário, GetDeinitReasonText(), que converte o identificador do motivo de deinicialização (o parâmetro da função OnDeinit()) para texto.

E, finalmente, a função OnTick(). Ela é chamada toda vez em que há um novo ponto no símbolo cujo gráfico o Consultor Especialista está operando no momento.

Vamos agora preparar todas as constantes, variáveis e arranjos que usaremos em nosso Consultor Especialista. Iremos colocá-las no começo do programa. Primeiro, defina as variáveis cujos valores permanecem inalterados por todo o programa:

//---
#define INFOPANEL_SIZE 14 // Size of the array for info panel objects
#define EXPERT_NAME MQL5InfoString(MQL5_PROGRAM_NAME) // Name of the Expert Advisor
//---

Isto é seguido por variáveis globais para propriedades de posição:

//--- GLOBAL VARIABLES
bool                 pos_open=false;         // Flag of presence/absence of an open position
string               pos_symbol="";          // Symbol
long                 pos_magic=0;            // Magic number
string               pos_comment="";         // Comment
double               pos_swap=0.0;           // Swap
double               pos_commission=0.0;     // Commission
double               pos_price=0.0;          // Position price
double               pos_cprice=0.0;         // Current price of the position
double               pos_profit=0.0;         // Profit/Loss of the position
double               pos_volume=0.0;         // Position volume
double               pos_sl=0.0;             // Stop Loss of the position
double               pos_tp=0.0;             // Take Profit of the position
datetime             pos_time=NULL;          // Position opening time
long                 pos_id=0;               // Position identifier
ENUM_POSITION_TYPE   pos_type=WRONG_VALUE;   // Position type

Após as variáveis, declararemos arranjos de nomes de objetos gráficos. Estes objetos exibirão propriedades de posição e seus valores no gráfico. Para este propósito, criaremos dois arranjos de cadeias (strings) e imediatamente inicializaremos seus elementos para valores. Em colchetes, usamos o valor da constante INFOPANEL_SIZE declarado no início do programa. Isto é, haverá 14 elementos em cada arranjo.

// Array of names of objects that display names of position properties
string positionPropertyNames[INFOPANEL_SIZE]=
  {
   "name_pos_symbol",
   "name_pos_magic",
   "name_pos_comment",
   "name_pos_swap",
   "name_pos_commission",
   "name_pos_price",
   "name_pos_cprice",
   "name_pos_profit",
   "name_pos_volume",
   "name_pos_sl",
   "name_pos_tp",
   "name_pos_time",
   "name_pos_id",
   "name_pos_type"
  };
//---
// Array of names of objects that display values of position properties
string positionPropertyValues[INFOPANEL_SIZE]=
  {
   "value_pos_symbol",
   "value_pos_magic",
   "value_pos_comment",
   "value_pos_swap",
   "value_pos_commission",
   "value_pos_price",
   "value_pos_cprice",
   "value_pos_profit",
   "value_pos_volume",
   "value_pos_sl",
   "value_pos_tp",
   "value_pos_time",
   "value_pos_id",
   "value_pos_type"
  };
//---

Usando estes nomes, podemos programaticamente encontrar o objeto necessário no gráfico e definir ou modificar suas propriedades como texto exibido, cor, tamanho etc. Além disso, estes nomes serão exibidos na janela Lista de Objetos (Ctrl+B) após serem criados no gráfico. Mas agora você não será capaz de visualizá-los já que os objetos criados pelo programa MQL5 estão ocultos por padrão. Para fazê-los visíveis, você deve clicar em Listar Todos na janela Lista de Objetos. Esta característica ajuda a separar os objetos criados manualmente daqueles criados programaticamente o que é admitidamente bem conveniente.

Além disso, precisaremos de funções definidas pelo usuário as quais serão empregadas pelo Consultor Especialista para criar objetos gráficos. A função oferecida pelo MQL5 para criação de objetos gráficos é ObjectCreate(). Mas já que também precisamos definir propriedades de objeto, enquanto os próprios objetos podem precisar serem criados mais do que uma vez, será melhor pensar em um método mais conveniente e compacto que pode ser implementado em uma simples linha de código.

Para criar o plano de fundo e cabeçalho do painel de informação, usaremos o objeto gráfico Editar. Vamos agora escrever a função CreateEdit():

//+------------------------------------------------------------------+
//| CREATING THE EDIT OBJECT                                         |
//+------------------------------------------------------------------+
void CreateEdit(long             chart_id,         // chart id
                int              sub_window,       // (sub)window number
                string           name,             // object name
                string           text,             // displayed text
                ENUM_BASE_CORNER corner,           // chart corner
                string           font_name,        // font
                int              font_size,        // font size
                color            font_color,       // font color
                int              x_size,           // width
                int              y_size,           // height
                int              x_distance,       // X-coordinate
                int              y_distance,       // Y-coordinate
                long             z_order,          // Z-order
                color            background_color, // background color
                bool             read_only)        // Read Only flag
  {
// If the object has been created successfully,...
   if(ObjectCreate(chart_id,name,OBJ_EDIT,sub_window,0,0))
     {
      // ...set its properties
      ObjectSetString(chart_id,name,OBJPROP_TEXT,text);                 // displayed text
      ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner);            // set the chart corner
      ObjectSetString(chart_id,name,OBJPROP_FONT,font_name);            // set the font
      ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size);       // set the font size
      ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color);         // font color
      ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,background_color); // background color
      ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,x_size);             // width
      ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,y_size);             // height
      ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance);     // set the X coordinate
      ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance);     // set the Y coordinate
      ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false);         // cannot select the object if FALSE
      ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order);           // Z-order of the object
      ObjectSetInteger(chart_id,name,OBJPROP_READONLY,read_only);       // Read Only
      ObjectSetInteger(chart_id,name,OBJPROP_ALIGN,ALIGN_LEFT);         // align left
      ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n");              // no tooltip if "\n"
     }
  }

Agora o objeto gráfico Editar (OBJ_EDIT) pode ser criado usando uma simples linha de código. Ilustraremos isto com um exemplo quando criamos uma função que definirá o painel de informação no gráfico.

Vamos agora continuar para os objetos de Etiquetas de Texto os quais serão usados para exibir a lista das propriedades de posição e seus valores, e criar a função CreateLabel() de forma similar:

//+------------------------------------------------------------------+
//| CREATING THE LABEL OBJECT                                        |
//+------------------------------------------------------------------+
void CreateLabel(long               chart_id,   // chart id
                 int                sub_window, // (sub)window number
                 string             name,       // object name
                 string             text,       // displayed text
                 ENUM_ANCHOR_POINT  anchor,     // anchor point
                 ENUM_BASE_CORNER   corner,     // chart corner
                 string             font_name,  // font
                 int                font_size,  // font size
                 color              font_color, // font color
                 int                x_distance, // X-coordinate
                 int                y_distance, // Y-coordinate
                 long               z_order)    // Z-order
  {
// If the object has been created successfully,...
   if(ObjectCreate(chart_id,name,OBJ_LABEL,sub_window,0,0))
     {
      // ...set its properties
      ObjectSetString(chart_id,name,OBJPROP_TEXT,text);              // displayed text
      ObjectSetString(chart_id,name,OBJPROP_FONT,font_name);         // set the font
      ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color);      // set the font color
      ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,anchor);         // set the anchor point
      ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner);         // set the chart corner
      ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size);    // set the font size
      ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance);  // set the X-coordinate
      ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance);  // set the Y-coordinate
      ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false);      // cannot select the object if FALSE
      ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order);        // Z-order of the object
      ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n");           // no tooltip if "\n"
     }
  }

É também aconselhável dar uma olhada nas descrições de função na Referência do MQL5.

Quando for excluído do gráfico, o Consultor Especialista deve, por sua vez, excluir todos os objetos que foram previamente adicionados a tabela. Para fazer isto, você pode simplesmente passar o nome do objeto para a função DeleteObjectByName(). Ela então procurará pelo objeto pelo nome especificado e irá deletá-lo, se encontrado, usando a função embutida ObjectFind() que procura pelo objeto e a função ObjectDelete() que exclui o objeto.

//+------------------------------------------------------------------+
//| DELETING THE OBJECT BY NAME                                      |
//+------------------------------------------------------------------+
void DeleteObjectByname(string name)
  {
   int  sub_window=0;      // Returns the number of the subwindow where the object is located
   bool res       =false;  // Result following an attempt to delete the object
//--- Find the object by name
   sub_window=ObjectFind(ChartID(),name);
//---
   if(sub_window>=0) // If it has been found,..
     {
      res=ObjectDelete(ChartID(),name); // ...delete it
      //---
      // If an error occurred when deleting the object,..
      if(!res) // ...print the relevant message
        {
         Print("Error deleting the object: ("+IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));
        }
     }
  }

Além, na função DeleteObjectByName(), também implementamos uma verificação por erros quando deletando um objeto. Se um erro ocorrer, uma mensagem relevante aparecerá contendo o código de erro e a descrição. Como você pode ver no código acima, usamos uma função adicional definida pelo usuário que converte o código de erro para descrição textual - a função ErrorDescription(). Já que há muitos códigos de erros, exemplificarei o acima usando apenas uma parte desta função (veja o código abaixo). A versão completa do código pode ser encontrada no código fonte anexado a este artigo.

//+------------------------------------------------------------------+
//| RETURNING THE ERROR DESCRIPTION                                  |
//+------------------------------------------------------------------+
string ErrorDescription(int error_code)
  {
   string error_string="";
//---
   switch(error_code)
     {
      //--- Trade server return codes

      case 10004: error_string="Requote";                                                                break;
      case 10006: error_string="Request rejected";                                                       break;
      case 10007: error_string="Request canceled by trader";                                             break;
      case 10008: error_string="Order placed";                                                           break;
      case 10009: error_string="Request executed";                                                       break;
      case 10010: error_string="Request executed partially";                                             break;
      case 10011: error_string="Request processing error";                                               break;
      case 10012: error_string="Request timed out";                                                      break;
      case 10013: error_string="Invalid request";                                                        break;
      case 10014: error_string="Invalid request volume";                                                 break;
      case 10015: error_string="Invalid request price";                                                  break;
      case 10016: error_string="Invalid Stop orders in the request";                                     break;
      case 10017: error_string="Trading forbidden";                                                      break;
      case 10018: error_string="Market is closed";                                                       break;
      case 10019: error_string="Insufficient funds";                                                     break;
      case 10020: error_string="Prices changed";                                                         break;
      case 10021: error_string="No quotes to process the request";                                       break;
      case 10022: error_string="Invalid order expiration in the request";                                break;
      case 10023: error_string="Order status changed";                                                   break;
      case 10024: error_string="Too many requests";                                                      break;
      case 10025: error_string="No changes in the request";                                              break;
      case 10026: error_string="Automated trading is disabled by trader";                                break;
      case 10027: error_string="Automated trading is disabled by the client terminal";                   break;
      case 10028: error_string="Request blocked for processing";                                         break;
      case 10029: error_string="Order or position frozen";                                               break;
      case 10030: error_string="The specified type of order execution by balance is not supported";      break;
      case 10031: error_string="No connection with trade server";                                        break;
      case 10032: error_string="Transaction is allowed for live accounts only";                          break;
      case 10033: error_string="You have reached the maximum number of pending orders";                  break;
      case 10034: error_string="You have reached the maximum order and position volume for this symbol"; break;

      ...

     }
//---
   return(error_string);
  }

No artigo anterior lidamos com a função GetPositionProperties() que obtém propriedades de posição. Agora a estrutura da função será um pouco mais complexa. Verificaremos por uma posição que está atualmente aberta, com a bandeira de presença/ausência se uma posição aberta sendo armazenada na variável global pos_open. Esta informação pode ser necessária em outras funções, sem ter que chamar a função PositionSelect() a todo momento.

Então, quando uma posição aberta existir, obteremos suas propriedades, em outro caso todas as variáveis serão zeradas. Agora vamos escrever uma simples função ZeroPositionProperties():

//+------------------------------------------------------------------+
//| ZEROING OUT VARIABLES FOR POSITION PROPERTIES                    |
//+------------------------------------------------------------------+
void ZeroPositionProperties()
  {
   pos_symbol     ="";
   pos_comment    ="";
   pos_magic      =0;
   pos_price      =0.0;
   pos_cprice     =0.0;
   pos_sl         =0.0;
   pos_tp         =0.0;
   pos_type       =WRONG_VALUE;
   pos_volume     =0.0;
   pos_commission =0.0;
   pos_swap       =0.0;
   pos_profit     =0.0;
   pos_time       =NULL;
   pos_id         =0;
  }

Além disso, no final da função GetPositionProperties(), chamaremos uma função definida pelo usuário SetInfoPanel() que extrai/atualiza o painel de informação no gráfico.

//+------------------------------------------------------------------+
//| GETTING POSITION PROPERTIES                                      |
//+------------------------------------------------------------------+
void GetPositionProperties()
  {
// Check if there is an open position
   pos_open=PositionSelect(_Symbol);
//---
   if(pos_open) // If an open position exists, get its properties
     {
      pos_symbol     =PositionGetString(POSITION_SYMBOL);
      pos_comment    =PositionGetString(POSITION_COMMENT);
      pos_magic      =PositionGetInteger(POSITION_MAGIC);
      pos_price      =PositionGetDouble(POSITION_PRICE_OPEN);
      pos_cprice     =PositionGetDouble(POSITION_PRICE_CURRENT);
      pos_sl         =PositionGetDouble(POSITION_SL);
      pos_tp         =PositionGetDouble(POSITION_TP);
      pos_type       =(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
      pos_volume     =PositionGetDouble(POSITION_VOLUME);
      pos_commission =PositionGetDouble(POSITION_COMMISSION);
      pos_swap       =PositionGetDouble(POSITION_SWAP);
      pos_profit     =PositionGetDouble(POSITION_PROFIT);
      pos_time       =(datetime)PositionGetInteger(POSITION_TIME);
      pos_id         =PositionGetInteger(POSITION_IDENTIFIER);
     }
   else // If there is no open position, zero out variables for position properties
      ZeroPositionProperties();
//---
   SetInfoPanel(); // Set/update the info panel
  }

Vamos agora escrever a função SetInfoPanel(). Abaixo está o código da função com comentários detalhados:

//+------------------------------------------------------------------+
//| SETTING THE INFO PANEL                                           |
//|------------------------------------------------------------------+
void SetInfoPanel()
  {
   int               y_bg=18;             // Y-coordinate for the background and header
   int               y_property=32;       // Y-coordinate for the list of properties and their values
   int               line_height=12;      // Line height
//---
   int               font_size=8;         // Font size
   string            font_name="Calibri"; // Font
   color             font_color=clrWhite; // Font color
//---
   ENUM_ANCHOR_POINT anchor=ANCHOR_RIGHT_UPPER; // Anchor point in the top right corner
   ENUM_BASE_CORNER  corner=CORNER_RIGHT_UPPER; // Origin of coordinates in the top right corner of the chart
//--- X-coordinates
   int               x_first_column=120// First column (names of properties)
   int               x_second_column=10;  // Second column (values of properties)
//--- Array of Y-coordinates for the names of position properties and their values
   int               y_prop_array[INFOPANEL_SIZE]={0};
//--- Fill the array with coordinates for each line on the info panel
   y_prop_array[0]=y_property;
   y_prop_array[1]=y_property+line_height;
   y_prop_array[2]=y_property+line_height*2;
   y_prop_array[3]=y_property+line_height*3;
   y_prop_array[4]=y_property+line_height*4;
   y_prop_array[5]=y_property+line_height*5;
   y_prop_array[6]=y_property+line_height*6;
   y_prop_array[7]=y_property+line_height*7;
   y_prop_array[8]=y_property+line_height*8;
   y_prop_array[9]=y_property+line_height*9;
   y_prop_array[10]=y_property+line_height*10;
   y_prop_array[11]=y_property+line_height*11;
   y_prop_array[12]=y_property+line_height*12;
   y_prop_array[13]=y_property+line_height*13;
//--- Background of the info panel
   CreateEdit(0,0,"InfoPanelBackground","",corner,font_name,8,clrWhite,230,190,231,y_bg,0,C'15,15,15',true);
//--- Header of the info panel
   CreateEdit(0,0,"InfoPanelHeader","POSITION PROPERTIES",corner,font_name,8,clrWhite,230,14,231,y_bg,1,clrFireBrick,true);
//--- List of the names of position properties and their values
//    Property name
   CreateLabel(0,0,pos_prop_names[0],"Symbol :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[0],2);
//    Property value
   CreateLabel(0,0,pos_prop_values[0],GetValInfoPanel(0),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[0],2);
//---
   CreateLabel(0,0,pos_prop_names[1],"Magic Number :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[1],2);
   CreateLabel(0,0,pos_prop_values[1],GetValInfoPanel(1),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[1],2);
//---
   CreateLabel(0,0,pos_prop_names[2],"Comment :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[2],2);
   CreateLabel(0,0,pos_prop_values[2],GetValInfoPanel(2),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[2],2);
//---
   CreateLabel(0,0,pos_prop_names[3],"Swap :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[3],2);
   CreateLabel(0,0,pos_prop_values[3],GetValInfoPanel(3),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[3],2);
//---
   CreateLabel(0,0,pos_prop_names[4],"Commission :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[4],2);
   CreateLabel(0,0,pos_prop_values[4],GetValInfoPanel(4),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[4],2);
//---
   CreateLabel(0,0,pos_prop_names[5],"Open Price :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[5],2);
   CreateLabel(0,0,pos_prop_values[5],GetValInfoPanel(5),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[5],2);
//---
   CreateLabel(0,0,pos_prop_names[6],"Current Price :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[6],2);
   CreateLabel(0,0,pos_prop_values[6],GetValInfoPanel(6),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[6],2);
//---
   CreateLabel(0,0,pos_prop_names[7],"Profit :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[7],2);
   CreateLabel(0,0,pos_prop_values[7],GetValInfoPanel(7),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[7],2);
//---
   CreateLabel(0,0,pos_prop_names[8],"Volume :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[8],2);
   CreateLabel(0,0,pos_prop_values[8],GetValInfoPanel(8),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[8],2);
//---
   CreateLabel(0,0,pos_prop_names[9],"Stop Loss :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[9],2);
   CreateLabel(0,0,pos_prop_values[9],GetValInfoPanel(9),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[9],2);
//---
   CreateLabel(0,0,pos_prop_names[10],"Take Profit :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[10],2);
   CreateLabel(0,0,pos_prop_values[10],GetValInfoPanel(10),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[10],2);
//---
   CreateLabel(0,0,pos_prop_names[11],"Time :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[11],2);
   CreateLabel(0,0,pos_prop_values[11],GetValInfoPanel(11),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[11],2);
//---
   CreateLabel(0,0,pos_prop_names[12],"Identifier :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[12],2);
   CreateLabel(0,0,pos_prop_values[12],GetValInfoPanel(12),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[12],2);
//---
   CreateLabel(0,0,pos_prop_names[13],"Type :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[13],2);
   CreateLabel(0,0,pos_prop_values[13],GetValInfoPanel(13),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[13],2);
//---
   ChartRedraw(); // Redraw the chart
  }

Vamos olhar mais de perto a função SetInfoPanel(). Variáveis que tem a ver com as propriedades dos objetos gráficos (coordenadas, cor, fontes, texto exibido etc.) são declaradas no início da função. Preste atenção ao processo de preencher o arranjo de coordenadas Y para a lista de propriedades de posição no painel de informação. É implementado de uma forma que é clara para iniciantes. Mas pode ser reduzida para um punhado de linhas de código quando usando um ciclo (loop). Você pode escrever como se segue:

//--- Fill the array with coordinates for each line on the info panel
   for(int i=0; i<infopanel_size; i++)=""     ="" {=""       if(i==0) y_prop_array[i]=y_property;
      else     y_prop_array[i]=y_property+line_height*i;
     }

Então, todas as propriedades dos objetos que precisam ser exibidas no painel devem ser especificadas nos parâmetros das funções criadas anteriormente CreateLabel() e CreateEdit(), tomando um objeto por vez. A lista completa também pode ser implementada em algumas linhas de código usando um loop. Para fazer isto, precisamos criar outro arranjo para objetos que exibem o texto dos nomes de propriedades de posição no gráfico. Deixe isto como seu dever de casa.

A função GetPropertyValue() que recebe o número de objeto retorna o valor que é passado para a função CreateLabel() como o quarto parâmetro (texto exibido). Trata-se de todos os objetos que exibirão valores de propriedades de posição. O valor retornado pela função é um valor de string ajustado que será exibido por fim no painel. Abaixo está o código da função com comentários detalhados:

//+------------------------------------------------------------------+
//| RETURNING THE STRING WITH POSITION PROPERTY VALUE                |
//+------------------------------------------------------------------+
string GetPropertyValue(int number)
  {
//--- Sign indicating the lack of an open position or a certain property
//    E.g. the lack of a comment, Stop Loss or Take Profit
   string empty="-";
//--- If an open position exists, return the value of the requested property
   if(pos_open)
     {
      switch(number)
        {
         case 0  : return(pos_symbol);                                           break;
         case 1  : return(IntegerToString((int)pos_magic));                      break;
         //--- return the value of the comment, if any, otherwise return the sign indicating the lack of comment
         case 2  : return(pos_comment!="" ? pos_comment : empty);                break;
         case 3  : return(DoubleToString(pos_swap,2));                           break;
         case 4  : return(DoubleToString(pos_commission,2));                     break;
         case 5  : return(DoubleToString(pos_price,_Digits));                    break;
         case 6  : return(DoubleToString(pos_cprice,_Digits));                   break;
         case 7  : return(DoubleToString(pos_profit,2));                         break;
         case 8  : return(DoubleToString(pos_volume,2));                         break;
         case 9  : return(pos_sl!=0.0 ? DoubleToString(pos_sl,_Digits) : empty); break;
         case 10 : return(pos_tp!=0.0 ? DoubleToString(pos_tp,_Digits) : empty); break;
         case 11 : return(TimeToString(pos_time,TIME_DATE|TIME_MINUTES));        break;
         case 12 : return(IntegerToString((int)pos_id));                         break;
         case 13 : return(PositionTypeToString(pos_type));                       break;
         
         default : return(empty);
        }
     }
//---
// If there is no open position, return the sign indicating the lack of the open position "-"
   return(empty);
  }

O código acima sugere que um certo valor é preparado para cada número passado para a função, desde que haja uma posição aberta. Se não há posição aberta atualmente, a função retornará um traço (-) exibido para todos objetos que tem a ver com os valores da propriedade da posição.

No final da função SetInfoPanel(), chamamos a função ChartRedraw() designada para uma redefinição forçada do gráfico. A não ser que seja chamada, você não será capaz de visualizar as modificações realizadas.

Agora precisamos escrever uma função que excluirá todos os objetos gráficos criados pelo Consultor Especialista. Vamos chamá-la DeleteInfoPanel():

//+------------------------------------------------------------------+
//| DELETING THE INFO PANEL                                          |
//+------------------------------------------------------------------+
void DeleteInfoPanel()
  {
   DeleteObjectByName("InfoPanelBackground");   // Delete the panel background
   DeleteObjectByName("InfoPanelHeader");       // Delete the panel header
//--- Delete position properties and their values
   for(int i=0; i<infopanel_size; i++)=""     ="" {=""       deleteobjectbyname(pos_prop_names[i]);    // Delete the property
      DeleteObjectByName(pos_prop_values[i]);   // Delete the value
     }
//---
   ChartRedraw(); // Redraw the chart
  }

Agora apenas precisamos distribuir os métodos que criamos entre as funções principais do Consultor Especialista que estavam originalmente presentes no modelo após sua criação no Assistente do MQL5. Esta é a parte mais fácil:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Get the properties and set the panel
   GetPositionProperties();
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Print the deinitialization reason to the journal
   Print(GetDeinitReasonText(reason));
//--- When deleting from the chart
   if(reason==REASON_REMOVE)
      //--- Delete all objects relating to the info panel from the chart
      DeleteInfoPanel();

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Get the properties and update the values on the panel
   GetPositionProperties();

  }
//+------------------------------------------------------------------+

A única coisa que você pode esbarrar aqui é a função GetDeinitReasonText() que retorna uma descrição textual do código do motivo de deinicialização:

//+---------------------------------------------------------------------+
//| RETURNING A TEXTUAL DESCRIPTION OF THE DEINITIALIZATION REASON CODE |
//+---------------------------------------------------------------------+
string GetDeinitReasonText(int reason_code)
  {
   string text="";
//---
   switch(reason_code)
     {
      case REASON_PROGRAM :     // 0
         text="The Expert Advisor has stopped working calling the ExpertRemove() function.";   break;
      case REASON_REMOVE :      // 1
         text="The '"+EXPERT_NAME+"' program has been removed from the chart.";                break;
      case REASON_RECOMPILE :   // 2
         text="The '"+EXPERT_NAME+"' program has been recompiled.";                            break;
      case REASON_CHARTCHANGE : // 3
         text="Chart symbol or period has been changed.";                                      break;
      case REASON_CHARTCLOSE :  // 4
         text="The chart is closed.";                                                          break;
      case REASON_PARAMETERS :  // 5
         text="Input parameters have been changed by the user.";                               break;
      case REASON_ACCOUNT :     // 6
         text="A different account has been activated.";                                       break;
      case REASON_TEMPLATE :    // 7
         text="A different chart template has been applied.";                                  break;
      case REASON_INITFAILED :  // 8
         text="A flag specifying that the OnInit() handler returned zero value.";              break;
      case REASON_CLOSE :       // 9
         text="The terminal has been closed.";                                                 break;
      default : text="The reason is undefined.";
     }
//---
   return text;
  }

Se você tentar usar o Consultor Especialista no símbolo gráfico que atualmente não tem posição aberta, você verá traços ao invés dos valores de propriedade de posição no painel. O painel parecerá o mesmo após você fechar uma certa posição.

Fig. 2. Painel de informação na ausência de uma posição aberta.

Fig. 2. Painel de informação na ausência de uma posição aberta.

Se o Consultor Especialista é adicionado ao gráfico do símbolo que tem uma posição aberta ou se uma posição é aberta após adicionar o Consultor Especialista ao gráfico, todos os traços serão substituídos pelos valores de propriedade de posição apropriados:

Fig. 3. Painel de informação exibindo propriedades da posição aberta.

Fig. 3. Painel de informação exibindo propriedades da posição aberta.

Há uma pequena peculiaridade. Após fechar a posição, só no novo ponto que os valores no painel serão atualizados. Há uma maneira de fazer os valores serem atualizados imediatamente mas o que precisa ser feito para implementar isto será discutido no próximo artigo da série.

 

Conclusão

Algumas das funções introduzidas neste artigo também serão usadas nos artigos seguintes da série Guia prático do MQL5, enquanto outras serão modificadas e melhoradas dependendo da tarefa em mãos. É aconselhável ler os artigos em ordem, um após o outro já que cada novo artigo é uma continuação lógica do anterior. Certamente também depende do seu nível de competência e habilidades, portanto, pode ser mais racional e interessante começar com publicações mais recentes. 

O arquivo de código-fonte está anexado ao artigo.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/641

Arquivos anexados |
Últimos Comentários | Ir para discussão (1)
Leandro Santana
Leandro Santana | 1 ago 2016 em 19:46
Onde encontro esse código no formato mq4 ?
Guia prático do MQL5: Analisando propriedades de posição no testador de estratégias do MetaTrader 5 Guia prático do MQL5: Analisando propriedades de posição no testador de estratégias do MetaTrader 5
Apresentaremos uma versão modificada do Expert Advisor a partir fo artigo anterior "Guia prático do MQL5: Propriedades de posição no painel de informações personalizado". Alguns dos assuntos que abordaremos incluem a obtenção de dados das barras, verificação de eventos de uma nova barra no símbolo atual, inclusão de uma classe de negociação da Biblioteca padrão a um arquivo, criação de uma função para buscar por sinais de negociação e uma função para execução das operações de negócio, assim como determinar os eventos de negócio na função OnTrade().
Guia prático do MQL5: obter propriedades de posição Guia prático do MQL5: obter propriedades de posição
Neste artigo, criaremos um script que capta todas as propriedades de posição e as exibe para o usuário em uma caixa de diálogo. Com a execução do script, você será capaz de selecionar entre dois modos disponíveis na lista suspensa nos parâmetros externos: tanto visualizar as propriedades da posição apenas no símbolo atual ou visualizar as propriedades da posição em todos os símbolos.
Guia prático do MQL5: Como Evitar Erros Quando Configurando/Modificando Níveis de Negociação Guia prático do MQL5: Como Evitar Erros Quando Configurando/Modificando Níveis de Negociação
Em continuação do nosso trabalho no Consultor Especialista do artigo anterior da série chamado "Guia prático: Analisando propriedades de posição no testador de estratégias do MetaTrader 5", o melhoraremos com um punhado de funções úteis, assim como aprimorar e otimizar as já existentes. O Consultor Especialista terá neste momento parâmetros externos que podem ser otimizados no Testador de Estratégias MetaTrader 5 e, em algumas formas, se parecerá com um simples sistema de transações.
Guia prático do MQL5: utilização de diferentes modos de impressão Guia prático do MQL5: utilização de diferentes modos de impressão
Este é o primeiro artigo da série Livro de receitas MQL5. Vou iniciar com exemplos simples para permitir que aqueles que estejam dando os seus primeiros passos em programação se familiarizem gradativamente com a nova linguagem. Eu me lembro que as minhas primeiras tentativas de projetar e programar sistemas de negociação foram muito difíceis, visto que era a primeira linguagem de programação da minha vida. Entretanto, no fim das contas foi mais fácil do que eu pensava e apenas demorou alguns meses até que eu pudesse desenvolver um programa razoavelmente complexo.