English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Crie seu próprio Market Watch usando as classes da biblioteca padrão

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

MetaTrader 5Exemplos | 6 fevereiro 2014, 16:35
2 334 0
Dmitriy Skub
Dmitriy Skub

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:

  • Object.mqh - contém a classe base CObject para criação de todas as outras classes, relacionadas com objetos gráficos.
  • ChartObject.mqh - também contém a classe CChartObject, derivado de CObject, que estende a funcionalidade e encapsulamento dos objetos gráficos, dados gerais e métodos.
  • ChartObjectsTxtControls.mqh - contém um número de classes, destinado a exibir os vários objetos gráficos no gráfico, que contém texto. Classe base (CChartObjectText e seus descendentes: CChartObjectLabel, CChartObjectEdit, eCChartObjectButton.

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:

  • identificação da sua posição em relação aos elementos vizinhos na lista.
  • identificação do tipo de objeto.
  • método para salvar e carregar os dados do objeto.
  • método para comparar com os objetos especificados.

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:

  • anexo do objeto gráfico real sobre o gráfico com a instância da classe.
  • leitura e modificação das propriedades comuns de todos os objetos gráficos.
  • exclusão do objeto gráfico do gráfico.
  • movimento do objeto gráfico no gráfico.


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:

  • leitura e modificação das propriedades comuns de todos os objetos gráficos.
  • criação de um objeto gráfico real do tipo OBJ_TEXT no gráfico.


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:

  • as coordenadas gráficas são usadas ao localizar o objeto gráfico.
  • permite ler e modificar o canto âncora. Na verdade, esta é a atribuição do início das coordenadas em um dos quatro cantos da janela do gráfico.
  • criação de um objeto gráfico real do tipo OBJ_LABEL no gráfico do terminal do cliente.


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:

  • o campo de entrada tem as propriedades de largura e altura (especificadas em pixels de tela), que limitam o tamanho do objeto gráfico no gráfico. O tamanho do texto do rótulo é automaticamente ajustado, de modo que todo o texto pode ser visto.
  • existem métodos para ativar/desativar a modificação do texto CChartObjectEdit :: ReadOnly.
  • um método é adicionado para alterar a cor do fundo da área, ocupada pelo objeto gráfico.
  • não há a possibilidade de alterar o ângulo, no qual o objeto é apresentado. O campo de entrada só pode ser exibido em uma direção horizontal.
  • ele permite a criação de um objeto gráfico real do tipo OBJ_EDIT no gráfico.


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:

  • Ele se parece com um botão pressionado, semelhantes aos utilizados em diálogos Windows.
  • tem novos métodos para ler/modificar o estado do botão (pressionado/não pressionado) - CChartObjectButton::State.
  • ele permite a criação de um objeto gráfico real do tipo OBJ_BUTTON no gráfico.


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:

  • chart_id - identificador de janela (0 - janela principal);
  • janela - número da sub-janela (0 - principal);
  • cols - o número máximo de objeto textuais gráficos horizontalmente (o número de colunas);
  • linhas - o número máximo de objetos textuais gráficos verticalmente (número de linhas);
  • col - coordenada horizontal do objeto gráfico (varia de zero a 1 - cols);
  • linha - coordenada vertical do objeto gráfico (varia de zero a 1 - linhas);

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:

  • Adicionar à lista:
   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.

  • Exclusão da 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".

  • acesso ao elemento arbitrário da lista:
   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.

  • Limpando a 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

  • Passo 1 - Incluir a biblioteca (no código-fonte do indicador):
#include  <TextDisplay.mqh>
  • Passo 2 - Criação de matrizes com os nomes e as coordenadas para os títulos:
#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.
  • Passo 3 - Criar um objeto de tabela do tipo TableDisplay para armazenar todos os objetos de texto exibidos:
TableDisplay  Table1;
  • Passo 4 - Adicionar títulos de objetos e campos de informação de objeto na tabela:
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).

  • Passo 5 - adicionar o código para atualizar a informação dinâmica:

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).

  • Passo 6 - Remover os objetos criados:
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.

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

Arquivos anexados |
marketwatch.mqh (9.48 KB)
textdisplay.mqh (15.54 KB)
marketwatch.mq5 (11.51 KB)
priceinfo.mq5 (8.76 KB)
pricelist.mq5 (7.29 KB)
Série de preço médio para cálculos intermediários sem utilizar buffers adicionais Série de preço médio para cálculos intermediários sem utilizar buffers adicionais
Este artigo é sobre algorítimos tradicionais e incomuns de média comprimidos em classes de tipo único e simples. Eles são destinados à utilização universal em quase todos os desenvolvimentos de indicadores. Espero que as classes sugeridas sejam uma boa alternativa para chamadas 'volumosas' e indicadores personalizados e técnicos.
O exemplo simples da criação de um indicador utilizando a lógica Fuzzy O exemplo simples da criação de um indicador utilizando a lógica Fuzzy
O artigo dedica-se à aplicação prática do conceito da lógica fuzzy para análise de mercados financeiros. Propomos o exemplo dos sinais de geração de indicador com base em duas regras fuzzy baseadas no indicador Envelopes. O indicador desenvolvido usa diversos buffers de indicador: 7 buffers para cálculo, 5 buffers para a exibição dos gráficos e 2 buffers de cor.
Construindo um Analisador de Espectro Construindo um Analisador de Espectro
Este artigo é destinado a familiarizar seus leitores com uma possível variável de uso de objetos gráficos da linguagem MQL5. Ele analisa um indicador que implementa um painel de gerenciamento de um simples analisador de espectro usando objetos gráficos. O artigo é destinado para leitores familiarizados com o básico do MQL5.
Assistente MQL5: criar Expert Advisors sem programação Assistente MQL5: criar Expert Advisors sem programação
Você quer experimentar uma estratégia de negócio enquanto não gasta tempo em programação? No Assistente MQL5 você pode simplesmente selecionar o tipo de sinais de negócio, adicionar módulos de posições de rastreio e gerenciamento de dinheiro - e seu trabalho está feito! Crie suas próprias implementações dos módulos ou encomende através do atendimento Jobs - e combine seus novos módulos com os já existentes.