Crie seu próprio Market Watch usando as classes da biblioteca padrão

Dmitriy Skub | 6 fevereiro, 2014

Introdução

O principal objetivo da tarefa era desenvolver uma ferramenta extensível e fácil de usar para a saída da informação textual arbitrária no gráfico do terminal do cliente MetaTrader 5. Por exemplo, os ajustes atuais do Expert Advisor, ou os resultados de seus trabalhos durante um intervalo especifico, apresentados como uma tabela, os valores dos preços ou uma tabela de preços, usados pelos comerciantes, ou um registro do comércio Expert Advisor. Todas essas informações podem ser exibidas dinamicamente no gráfico durante o trabalho do EA ou indicador; que utiliza esta biblioteca.

Como base para o desenvolvimento da biblioteca, uma coleção de classes da biblioteca padrão do terminal do cliente MetaTrader 5 foi usada. Primeiro, vamos considerar essas classes e, em seguida, estendê-las a cumprir a nossa tarefa.


Classes padrão para Objetos Gráficos

O conjunto de classes, em que estamos interessados, estão localizadas nas pastas Include e Include\ChartObjects.

Estes são os seguintes arquivos:

Vamos considerar essas classes com mais detalhes.


CObject: A classe base

A descrição da classe é curta, então vamos mostrá-la aqui:

class CObject
{
protected:
   CObject          *m_prev;
   CObject          *m_next;

public:
                     CObject();

   CObject          *Prev()                { return(m_prev); }
   void              Prev(CObject *node)   { m_prev=node;    }
   CObject          *Next()                { return(m_next); }
   void              Next(CObject *node)   { m_next=node;    }

   virtual bool      Save(int file_handle) { return(true);   }
   virtual bool      Load(int file_handle) { return(true);   }

   virtual int       Type() const          { return(0);      }

protected:
   virtual int       Compare(const CObject *node,int mode=0) const { return(0); }
};

//+------------------------------------------------------------------+
void CObject::CObject()
{
   m_prev=NULL;
   m_next=NULL;
}
    

Como você pode ver, esta classe contém apenas os dados de propósito geral e métodos, eles não estão relacionados diretamente com a produção no gráfico.

No entanto, ele tem uma propriedade muito importante - ele pode ser usado para criar as listas simplesmente ligadas e duplamente ligadas. Estas características fornecidas pelo campo de dados CObject::m_prev e CObject::m_next do tipo CObject* e métodos de suas leituras/escritas. O campo CObject::m_prev refere-se ao elemento da lista anterior, enquanto CObject::m_next - refere-se ao próximo. Mais detalhes sobre a construção das listas serão fornecidos mais adiante.

Além disso, existe um método para comparar dois objetos do tipo CObject* - o método CObject::Compare, que pode ser usado ao classificar os elementos da lista. Existem mais dois métodos úteis, que permitem que você salve/conte os campos de dados nos arquivos - estes são os métodos CObject::Save e CObject::Load. Para obter a desejada funcionalidade estes métodos devem ser sobrecarregados nas classes descendentes

O CObject::Type é o método de identificação do tipo de objeto. Este método é útil quando manipular uma lista, que contém objetos de tipos diferentes.

A classe CObject (e suas instâncias) possui as seguintes características:

A maioria dos métodos descritos acima, são virtuais e não implementado na classe base. A classe base não tem quaisquer propriedades reais com significado físico. Como é usual em OOP, a funcionalidade deve ser implementada nas classes descendentes.


CChartObject: a classe base para objetos gráficos

O CChartObject é um descendente da classe CObject.

Em seu nome, pode-se ver que esta é uma classe para descrever algum objeto gráfico abstrato. No entanto, este objeto abstrato já contém algumas propriedades físicas e métodos de trabalho com essas propriedades. Estas propriedades são comuns a todos os objetos gráficos em MetaTrader 5, então é lógico colocá-los nesta classe.

Vamos considerá-los em mais detalhes. Usaremos os seguintes dados para anexar o objeto gráfico para a janela do gráfico:

protected:
  long       m_chart_id;    // identifier of the chart, which contains 
                               // specified graphic object (0 - current chart)
  int        m_window;      // number of chart sub-window (0 - main window)
  string     m_name;        // unique name of the object on the chart
  int        m_num_points;  // number of points for anchoring the object

Antes de especificar ou ler as propriedades do objeto gráfico real, ele deve ser anexado com o objeto (instância de classe). Isto é feito pelo método CChartObject::Attach. Em classes descendentes, é chamado imediatamente após a criação do objeto gráfico no gráfico.

bool CChartObject::Attach(long chart_id,string name,int window,int points)
{
  if(ObjectFind(chart_id,name)<0)
  {
    return(false);
  }

  if(chart_id==0) chart_id=ChartID();

  m_chart_id  =chart_id;
  m_window    =window;
  m_name      =name;
  m_num_points=points;

  return(true);
}
    

Em primeiro lugar, verificamos a existência de um objeto gráfico real. Se existir, as suas propriedades são armazenados nos campos internos do objeto de classe CChartObject. Depois disso, podemos ler e modificar as propriedades de objetos gráficos (cor, localização, etc.)

Os métodos de salvar/ler as propriedades de objetos gráficos já estão implementados nos métodos CChartObject::Save e CChartObject::Load. O método titular de salvar/ler deve ser chamado primeiramente na classe descendente antes de seu próprio método.

A classe CChartObject (e os seus exemplos) tem as seguintes novas propriedades em comparação com os de base:


CChartObjectText: uma classe de objetos de texto gráfico

Voltemo-nos agora para o arquivo ChartObjectsTxtControls.mqh. Aqui, vamos encontrar a descrição de classes desenvolvidas para a saída de vários objetos gráficos, contendo texto, para o gráfico. Vamos considerar seus recursos básicos.

A classe básica para eles é a classe CChartObjectText. Ela encapsula as propriedades e métodos associados com a produção de texto no gráfico.

Aqui está a descrição da classe:

class CChartObjectText : public CChartObject
{
public:
   double            Angle() const;
   bool              Angle(double angle);
   string            Font() const;
   bool              Font(string font);
   int               FontSize() const;
   bool              FontSize(int size);
   ENUM_ANCHOR_POINT  Anchor() const;
   bool              Anchor(ENUM_ANCHOR_POINT anchor);

   bool              Create(long chart_id,string name,int window,datetime time,double price);

   virtual int       Type() const { return(OBJ_TEXT); }

   virtual bool      Save(int file_handle);
   virtual bool      Load(int file_handle);
};
    

Comparada com o CChartObject, ela contém métodos para ler e modificar as propriedades dos objetos gráficos textuais - o ângulo de orientação do texto no gráfico, o nome da fonte do texto, o tamanho da fonte, e as coordenadas do objeto gráfico. Um novo método apareceu CChartObjectText:: Create nos permite criar um objeto gráfico real do tipo OBJ_TEXT no gráfico.

A sua implementação:

bool CChartObjectText::Create(long chart_id,string name,int window,datetime time,double price)
{
  bool result = ObjectCreate( chart_id, name, OBJ_TEXT, window, time, price );
  if(result)
  {
    result &= Attach(chart_id, name, window, 1 );
  }

  return(result);
}
    

No caso da criação bem sucedida do objeto gráfico (o método ObjectCreate retornou verdadeiro), o CChartObject:: O método Attach é chamado, o qual nós consideramos mais cedo.

Assim, em comparação com a classe principal, o CChartObjectText inclui novas funcionalidades:


CChartObjectLabel: uma classe para a "rotulagem de texto" de objetos gráficos

A próxima classe na hierarquia das classes padrão é a classe CChartObjectLabel CChartObjectLabel. Ele permite que você crie objetos gráficos do tipo OBJ_LABEL (rótulo de texto) no gráfico.

Aqui está uma descrição desta classe:

class CChartObjectLabel : public CChartObjectText
{
public:
   int               X_Distance() const;
   bool              X_Distance(int X);
   int               Y_Distance() const;
   bool              Y_Distance(int Y);
   int               X_Size() const;
   int               Y_Size() const;
   ENUM_BASE_CORNER  Corner() const;
   bool              Corner(ENUM_BASE_CORNER corner);

   bool              Time(datetime time) { return(false);  }
   bool              Price(double price) { return(false);  }

   bool              Create(long chart_id,string name,int window,int X,int Y);

   virtual int       Type() const        { return(OBJ_LABEL); }

   virtual bool      Save(int file_handle);
   virtual bool      Load(int file_handle);
};
    

Aqui devemos notar a diferença entre o objeto gráfico do tipo OBJ_TEXT e o objeto do tipo OBJ_LABEL.

O primeiro está ligado ao gráfico de preço (coordenadas tempo-preço) ou no gráfico na sub-janela. O segundo está ligado às coordenadas de gráfico da janela ou sub-janela (pexels) do gráfico.

Portanto, os objetos do tipo OBJ_TEXT são movidos juntamente com o gráfico quando rolando a página, enquanto os objetos do tipo OBJ_LABEL permanecem fixo ao rolar. Portanto, dependendo das tarefas, devemos escolher um determinado tipo de objeto gráfico textual.

Em comparação com a classe principal, a classe CChartObjectLabel inclui as seguintes características distintivas:


CChartObjectEdit: uma classe para "campo de introdução" de objetos gráficos

A próxima classe na hierarquia é a classe CChartObjectEdit. Esta é uma classe para criar um objeto gráfico do tipo OBJ_EDIT (campo de entrada).

O objeto deste tipo é ligado da mesma forma que o objeto do tipo OBJ_LABEL utilizando as coordenadas do gráfico (pixels), lógicamente ele deriva da classe CChartObjectLabel, da mesma forma que as classes padrão:

class CChartObjectEdit : public CChartObjectLabel
{
public:
   bool              X_Size(int X);
   bool              Y_Size(int Y);
   color             BackColor() const;
   bool              BackColor(color new_color);
   bool              ReadOnly() const;
   bool              ReadOnly(bool flag);

   bool              Angle(double angle) { return(false);    }

   bool              Create(long chart_id,string name,int window,int X,int Y,int sizeX,int sizeY);

   virtual int       Type() const        { return(OBJ_EDIT); }

   virtual bool      Save(int file_handle);
   virtual bool      Load(int file_handle);
};
    

A diferença entre os campos de entrada do tipo OBJ_EDIT do rótulo de texto é o seguinte:


CChartObjectButton: uma classe para objeto gráfico "Button"

Outra classe na hierarquia de objetos gráficos textuais é a classe CChartObjectButton. Este objeto é chamado de botão, que é desenvolvido para criar um elemento de controle no gráfico, sob a forma de um botão pressionado para baixo. Esta classe é um descendente da classe CChartObjectEdit, e herda a sua funcionalidade:

class CChartObjectButton : public CChartObjectEdit
{
public:
  bool             State() const;
  bool             State(bool state);

  virtual int       Type() const { return(OBJ_BUTTON); }

  virtual bool      Save(int file_handle);
  virtual bool      Load(int file_handle);
};
    

A diferença do botão do tipo OBJ_BUTTON do campo de entrada é a seguinte:


A estrutura geral das classes padrão para objetos textuais gráficos

A estrutura (hierarquia) das classes da biblioteca padrão, podem ser resumidas como se segue:

A estrutura geral das classes padrão

Figura 1. A estrutura geral das classes padrão

A classe CObject é uma classe base para outras classes padrão, por exemplo, a classe CList, que opera a lista, bem como os outros.


Estender a funcionalidade das classes da biblioteca padrão

Nós discutimos brevemente a hierarquia das classes padrão, que são desenvolvidos para gerar objetos gráficos textuais no gráfico. Agora vamos estender essa hierarquia com novas classes. Primeiro de tudo, temos de decidir sobre a funcionalidade que é necessária para a implementação. Vamos formular os requisitos. Uma vez que estamos lidando com a saída de informações textuais, é lógico fornecer essas informações na forma estruturada seguinte:

TíTULO TEXTO DE INFORMAçãO


Esta estrutura da representação de informação textual é adequado para a maioria dos casos mais simples.

Por exemplo, o indicador de parâmetros de símbolo pode ter esta aparência:

Um exemplo de uma mostra estruturada de informações textuais

Figura 2. Um exemplo de uma mostra estruturada de informações textuais

Ele usa seis campos de informação da estrutura proposta acima. Alguns elementos da estrutura podem estar ausentes. Por exemplo, na figura 2, a telha do campo superior não é mostrada. Os outros campos contém o título e o texto. Este indicador pode ser encontrado no arquivo PricelInfo.mq5, anexado a este artigo.


Posicionamento dos objetos gráficos

O segundo ponto que precisamos considerar é a maneira de posicionar os objetos textuais gráficos no gráfico. O método adotado de especificar as coordenadas em pixels da tela permite o posicionamento do objeto em um local arbitrário do gráfico.

é inconveniente na prática, quando você precisa acomodar vários objetos textuais em diferentes lugares na tabela, uma vez que é necessário calcular todas as coordenadas da tela. Além disso, se você alterar o tamanho do gráfico, todas as coordenadas de pixel precisam ser recalculadas para ter certeza de que a posição relativa dos objetos na tela não foi alterada.

Se traçarmos a janela do gráfico em retângulos (campos) do mesmo tamanho, e atribuir cada um desses retângulos uma coordenada horizontal e vertical, obteremos um sistema de posicionamento universal, que é independente da resolução da tela.

Ao criar o objeto de texto gráfico, o usuário pode definir o número máximo de campos nas direções vertical e horizontal, e as coordenadas do objeto em campos como os parâmetros. A funcionalidade, incorporada na classe apropriada, irá automaticamente ajustar as coordenadas dos objetos gráficos quando você mudar a resolução da tela. Desta forma, as coordenadas são especificadas uma vez e não requerem qualquer ajustamento.


Geração automática de nomes de objetos únicos

A próxima questão que deve ser abordada é a geração automática do nome do objeto de texto gráfico. O principal requisito para o método de geração é a obtenção de um nome único dentro da janela dada. Isso permitirá localizar na tela um número suficiente de objetos, sem se preocupar com a necessidade de inventar nomes não-duplicados.

Propomos o seguinte método para gerar um nome (uma cadeia, que consiste de campos):

Data hora
Número de milissegundos


Para obter a parte da cadeia, contendo a data e hora, use a seguinte chamada:

TimeToString(TimeGMT(), TIME_DATE|TIME_MINUTES|TIME_SECONDS);

Para obter o número de milissegundos, use a seguinte chamada:

DoubleToString(GetTickCount(), 0);

Mas mesmo que meçamos o tempo dentro de milissegundos, é bem possível que quando consecutivamente chamarmos a função GetTickCount(), duas ou mais vezes, obteremos o mesmo valor. Isto é devido à restrição da discrição dos cronômetros internos do sistema operacional e processador. Assim, é necessário tomar medidas adicionais para detectar tal situação.

O método proposto é implementado nas seguintes funções:

string GetUniqName()
{
  static uint prev_count = 0;

  uint count = GetTickCount();
  while(1)
  {
    if(prev_count == UINT_MAX)
    {
      prev_count = 0;
    }
    if(count <= prev_count)
    {
      prev_count++;
      count = prev_count;
    }
    else
    {
      prev_count = count;
    }

//  Verify that there is no object already existing with such a name:
    string name = TimeToString(TimeGMT(), TIME_DATE|TIME_MINUTES|TIME_SECONDS)+" "+DoubleToString(count, 0);
    if(ObjectFind(0, name) < 0)
    {
      return(name);
    }
  }

  return(NULL);
}

A limitação deste método: a geração de não mais de 4294967295 (UINT_MAX) nomes únicos por segundo. Aparentemente, isso deveria ser suficiente em prática. Só no caso, existe uma verificação adicional da existência de um objeto gráfico com o mesmo nome.


A exibição do título da estrutura informacional - classe TTitleDisplay

A classe para exibir o título na tela do terminal é demonstrada abaixo:

class TTitleDisplay : public CChartObjectLabel
{
protected:
  long    chart_id;
  int     sub_window;
  long    chart_width;       // width of the chart in pixels
  long    chart_height;      // height of the chart graph in pixels
  long    chart_width_step;  // step of the coordinates grid in the horizontal direction
  long    chart_height_step; // step of the coordinates grid in the vertical direction
  int     columns_number;    // number of columns
  int     lines_number;      // number of lines
  int     curr_column;
  int     curr_row;

protected:
  void    SetParams(long chart_id, int window, int cols, int lines);// specify the object's parameters

protected:
  string  GetUniqName();    // get a unique name
  bool    Create(long chart_id, int window, int cols, int lines, int col, int row);
  void    RecalcAndRedraw();// recount the coordinates and re-draw

        
public:
  void    TTitleDisplay();  // constructor
  void    ~TTitleDisplay(); // destructor
};

O método básico que cria um objeto textual gráfico:

bool Create(long chart_id, int window, int _cols, int _lines, int _col, int _row);

Atribuição dos parâmetros de entrada é como segue:

O método TTitleDisplay:: SetParams calcula os parâmetros do objeto, associado com o posicionamento na tela.

A implementação é como segue:

void TTitleDisplay::SetParams(long _chart_id, int _window, int _cols, int _lines)
{
  this.chart_id = _chart_id;
  this.sub_window = _window;
  this.columns_number = _cols;
  this.lines_number = _lines;

//  Specify the size of the window in pixels:
  this.chart_width = GetSystemMetrics(SM_CXFULLSCREEN);
  this.chart_height = GetSystemMetrics(SM_CYFULLSCREEN);

//  Calculate the step of the coordinates grid:
  this.chart_width_step = this.chart_width/_cols;
  this.chart_height_step = this.chart_height/_lines;
}

Aqui usamos a chamada de função GetSystemMetrics WinAPI para obter as configurações de exibições atuais. Esta função é importada da biblioteca do sistema Windows user32.dll.

Uma classe para criar o texto informativo TFieldDisplay é construída de forma semelhante. Os detalhes podem ser encontrados na biblioteca TextDisplay.mqh, anexada a este artigo.


Classe CList: Manipulação de objetos na lista

Agora vamos considerar uma outra classe padrão, que vamos precisar para a realização de nosso plano. Esta classe permite agrupar objetos em listas. Está localizada no arquivo Include\Arrays\List.mqh. Este arquivo fornece a descrição e implementação de uma classe CList padrão, que é descendente da classe base CObject, considerada no início deste artigo. Ele contém um conjunto de métodos para a manipulação de objetos na lista (adicionar à lista, retirar da lista, acessar um elemento arbitrário da lista, e limpar a lista).

Vamos considerar os métodos básicos:

   int Add(CObject *new_node);
   int Insert(CObject *new_node,int index);

Estes são dois métodos para adicionar um novo item à lista. O primeiro CList::Add, permite que você adicione um novo elemento new_node ao final da lista. O segundo CList::Insert, permite que você insira um novo elemento new_node a um lugar arbitrário (especificado pelo índice) na lista.

   bool  Delete(int index);

O método CList::Delete permite que você remova um elemento com um índice especificado na lista. Enquanto isso, além de remover o item da lista, a memória ocupada pelo elemento do tipo CObject é liberada, a qual foi ocupada pelo elemento do tipo CObject. Em outras palavras, o objeto será apagado "fisicamente".

   int       IndexOf(CObject* node);
   CObject*  GetNodeAtIndex(int index);
   CObject*  GetFirstNode();
   CObject*  GetPrevNode();
   CObject*  GetNextNode();
   CObject*  GetLastNode();

CList:: O método IndexOf retorna o índice de um elemento específico na lista. A numeração dos índices começa do zero: o primeiro elemento tem um índice de zero. Este método executa a operação inversa, ele devolve o índice de ponteiro do elemento. Se o elemento não está na lista, ele retorna -1.

Mais quatro métodos para navegação através da lista CList:: GetFirstNode retorna o elemento anterior, o CList:: GetNextNode retorna o próximo, o CList:: GetLastNode retorna o último elemento na lista.

   void  Clear();

O método CList::Clear permite que você remova todos os elementos da lista, e também libera a memória ocupada pelos objetos.

Estes são os métodos básicos da classe CList, o restante é descrito na Referência MQL5.


Classe TableDisplay: Criação de uma tabela para mostragem do texto no gráfico

Então, nós temos tudo o que precisamos para a realização do plano. Aqui está uma classe simples que permite você organizar os objetos gráficos textuais em uma tabela de um tamanho arbitrário:

class TableDisplay : public CList
{
protected:
  long  chart_id;
  int   sub_window;

public:
  void  SetParams(long _chart_id, int _window, ENUM_BASE_CORNER _corner = CORNER_LEFT_UPPER);
  int   AddTitleObject(int _cols, int _lines, int _col, int _row, 
                      string _title, color _color, string _fontname = "Arial", int _fontsize = 8);
  int   AddFieldObject(int _cols, int _lines, int _col, int _row, 
                          color _color, string _fontname = "Arial", int _fontsize = 8);
  bool  SetColor(int _index, color _color);
  bool  SetFont(int _index, string _fontname, int _fontsize);
  bool  SetText(int _index, string _text);

public:
  void  TableDisplay();
  void  ~TableDisplay();
};

Antes de adicionar os objetos gráficos na tabela, você deve definir os parâmetros: o identificador do gráfico, o índice da sub-janela e o ponto de ancoragem. Isso é feito chamando o TableDisplay:: Método SetParams. Após isso, você pode definir qualquer número de títulos e campos de texto à tabela.

O texto completo da biblioteca, que nós desenvolvemos, pode ser encontrado no arquivo TextDisplay.mqh, anexado a este artigo.


3. Um exemplo de criação do Market Watch

Considere o exemplo de criação de uma tabela para apresentar os valores de vários símbolos, sob a forma de um indicador.

Ela deve se parecer mais ou menos assim:

Um exemplo de uma tabela de tela

Рисунок 3. Um exemplo de uma tabela de tela

#include  <TextDisplay.mqh>
#define  NUMBER  8
//---------------------------------------------------------------------
string  names[NUMBER]   = {"EURUSD", "GBPUSD", "AUDUSD", "NZDUSD", "USDCHF", "USDCAD", "USDJPY", "EURJPY"};
int     coord_y[NUMBER] = {2,        3,        4,        5,        6,      7,        8,       9};
Coordenadas são ordenadas a partir de zero.
TableDisplay  Table1;
int OnInit()
{
//  Creating a table
  Table1.SetParams(0, 0);

  for(int i=0; i<NUMBER; i++)
  {
    Table1.AddFieldObject(40, 40, 3, coord_y[i], Yellow);
  }

  for(int i=0; i<NUMBER; i++)
  {
    Table1.AddTitleObject(40, 40, 1, coord_y[i], names[i]+":", White);
  }

  ChartRedraw(0);
  EventSetTimer(1);

  return(0);
}

é ideal fazê-lo no manipulador de eventos OnInit. Primeiro, adicione os campos de informação, utilizando o TableDisplay:: Método AddFieldObject. Em seguida, adicione-os títulos, utilizando o TableDisplay:: Método AddTitleObject.

A adição é executada em ciclos separados por duas razões: em primeiro lugar, o número de títulos, em geral, pode não coincidir com o número de campos de informação e, por outro, o acesso aos campos de informações atualizadas é mais fácil de organizar quando eles são indexados em uma linha (neste caso, a partir de zero ao NúMERO de valor - 1).

Neste caso, a atualização de informações dinâmica é organizada pelo manipulador de eventos Timer. O manipulador OnTimer para este evento deve receber os valores de preços para os instrumentos indicados e exibir esses valores no gráfico.

O texto deste é mostrado abaixo:

//---------------------------------------------------------------------
double    rates[NUMBER];
datetime  times[NUMBER];
MqlTick   tick;
//---------------------------------------------------------------------
// OnTimer event handler
//---------------------------------------------------------------------
void OnTimer()
{
  for(int i=0; i<NUMBER; i++)
  {
//  Obtain the price values:
    ResetLastError();
    if(SymbolInfoTick(names[i], tick) != true)
    {
      Table1.SetText(i,"Err "+DoubleToString(GetLastError(),0));
      Table1.SetColor(i,Yellow);
      continue;
    }

    if(tick.time>times[i])
    {
       Table1.SetText(i, DoubleToString(tick.bid, (int)(SymbolInfoInteger(names[i], SYMBOL_DIGITS))));

       if(tick.bid>rates[i])
       {
         Table1.SetColor(i, Lime);
       }
       else if(tick.bid<rates[i])
       {
         Table1.SetColor(i, Red);
       }
       else
       {
         Table1.SetColor(i, Yellow);
       }
       rates[i] = tick.bid;
       times[i] = tick.time;
    }
  }

  ChartRedraw(0);
}

No início do ciclo, os dados de escala para o instrumento especificado são lidos, depois, a relevância dos dados é verificada - se o tempo da escala mudou desde a anterior, considera-se os dados irrelevantes. Além disso, analisamos o valor da cotação em relação a escala anterior.

Se o preço atual é maior do que o anterior, então vamos especificar uma cor verde para o campo da informação. Se ela for menor, uma cor vermelha e, se eles forem iguais - uma cor amarela. No final do ciclo, o valor atual do preço e o tempo de escala são armazenados para análise no chamado de manipulador de eventos OnTimer.

Em geral, o código para a atualização da informação dinâmica é dependente da tarefa. Basicamente, o usuário só precisa executar esta parte do código. Suponha decidimos adicionar um diferencial È direita do preço na figura 2. Vamos ver como isso pode ser feito.

Tudo que é necessário, é adicionar campos de dados adicionais à tabela:

  for(int i=0; i<NUMBER; i++)
  {
    Table1.AddFieldObject(40, 40, 5, coord_y[i], Yellow);
  }

e incluir o código, que atualiza o valor do crescimento, no manipulador de eventos OnTimer:

  Table1.SetText(i+NUMBER, DoubleToString((tick.ask-tick.bid)/SymbolInfoDouble(names[i], SYMBOL_POINT), 0));

Como resultado, obtemos a imagem seguinte:

Preços com um crescimento

Figura 4. Preços com um crescimento

Observe que os campos de índice para o crescimento, começa a partir do valor de NúMERO (se i é igual a zero).

void OnDeinit(const int _reason)
{
  EventKillTimer();

//  Removing the elements of display:
  Table1.Clear();
}

Aqui o temporizador e a tabela são apagados. Enquanto isso, todos os objetos também são liberados da memória.

O texto completo deste indicador pode ser encontrado no arquivo PriceList.mq5, anexado a este artigo. O anexo contém uma versão "melhorada" do indicador, que mostra a propagação. Tem uma série de parâmetros externos para a especificação da cor do título e a posição de uma tabela no gráfico.


Conclusão

O MarketWatch.mq5 anexado (e o MarketWatch.mqh incluído) contém o indicador para exibir os parâmetros básicos de instrumentos de negociação, na forma de uma tabela de resumo. Para cada símbolo, a informação semelhante a figura 2 é mostrada.

Além disso, ele mostra a porcentagem de variação de preço para os intervalos de tempo especificados. O conjunto de símbolos (não mais de 16) e os intervalos de tempo são especificados como uma cadeia com elementos separados por um ponto e vírgula. Os resultados do trabalho deste indicador são mostrados na figura 5:

Indicador da análise de mercado

Figura 5. Indicador do Market Watch

Nós consideramos uma maneira de visualizar informações de texto no gráfico do terminal do cliente MetaTrader 5.

Usando as classes da biblioteca padrão, fornecidas com o terminal do cliente, fomos capazes de desenvolver facilmente e rapidamente a nova funcionalidade para a representação de informações textuais na forma de uma tabela bidimensional. A aproximação de objetos orientados da linguagem MQL5 é muito poderosa.