Interfaces gráficas XI: Integração da Biblioteca Gráfica Padrão (build 16)

30 outubro 2017, 08:31
Anatoli Kazharski
0
810

Conteúdo


Introdução

O primeiro artigo Interfaces gráficas I: Preparação da Estrutura da Biblioteca (Capítulo 1) considera em detalhes a finalidade desta biblioteca. Você encontrará uma lista de artigos com os links no final de cada capítulo. Lá, você também pode encontrar e baixar a versão completa da biblioteca, no estágio de desenvolvimento atual. Os arquivos devem estar localizados nas mesmas pastas que o arquivo baixado.

O segundo capítulo da nona parte da série, Interfaces gráficas IX: Os controles Barra de Progresso e Gráfico de Linha (Capítulo 2), demonstrou um exemplo de como uma classe para criar gráficos de linha pode ser integrada na biblioteca. Essa foi uma solução temporária, já que as capacidades desta parte da biblioteca eram extremamente insuficientes. Uma nova versão da biblioteca gráfica para a criação de gráficos científicos (a classe CGraphic) foi apresentada recentemente. A descrição de algumas funções desta classe foi apresentada em Visualize isso! Biblioteca Gráfica em Linguagem MQL5 como Equivalente a Plot de R. Esta atualização da biblioteca desenvolvida para criar interfaces gráficas irá introduzir uma versão com um novo controle para a criação de gráficos. Agora está ainda mais fácil de visualizar os dados de diferentes tipos.


Alterações no esquema da biblioteca

Anteriormente, a biblioteca desenvolvida usou uma cópia da classe CCanvas projetada para desenho. Devido à recente refatoração global do código da biblioteca, esta cópia não é mais necessária e pode ser removida substituindo-a pela versão original da biblioteca padrão. Isso reduziu o volume da biblioteca por aproximadamente 10% e quase por 40% em relação à versão apresentada antes da refatoração nos artigos Interfaces gráficas XI: Refatoração do código da biblioteca (build 14.1) e Interfaces gráficas XI: Controles renderizados (build 14.2).

A classe CGraphic agora será usada para criar gráficos, portanto, inclua o arquivo Graphic.mqh no arquivo Objects.mqh. Já que o arquivo com a classe CCanvas já está incluída em um dos arquivos de inclusão no arquivo Graphic.mqh, ele também ficará disponível para toda a biblioteca.

//+------------------------------------------------------------------+
//|                                                      Objects.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "Enums.mqh"
#include "Defines.mqh"
#include "Fonts.mqh"
#include "Colors.mqh"
#include <Graphics\Graphic.mqh>
#include <ChartObjects\ChartObjectSubChart.mqh>
...

A classe CLineChart foi renomeada para CGraph. Seu conteúdo interno também foi alterado. Agora, esta classe contém apenas os métodos para gerenciar as propriedades gerais e os estados do controle. 

class CGraph : public CElement
  {
public:
   //--- Manipulador de eventos do gráfico
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- Mover o controle
   virtual void      Moving(const bool only_visible=true);
   //--- Gerenciamento
   virtual void      Show(void);
   virtual void      Hide(void);
   virtual void      Reset(void);
   virtual void      Delete(void);
   //--- Aplica as últimas alterações
   virtual void      Update(const bool redraw=false);
   //---
private:
   //--- Redimensionamento
   void              Resize(const int width,const int height);
   //--- Altera a largura da margem direita da janela
   virtual void      ChangeWidthByRightWindowSide(void);
   //--- Altera a altura na borda inferior da janela
   virtual void      ChangeHeightByBottomWindowSide(void);
  };

As propriedades do gráfico podem ser controladas usando o método CGraphic::GetGraphicPointer() para obter o ponteiro para uma instância da classe CGraphic:

class CGraph : public CElement
  {
private:
   //--- Objetos para criação do controle
   CGraphic          m_graph;
   //---
public:
   //--- Retorna o ponteiro para o gráfico
   CGraphic         *GetGraphicPointer(void) { return(::GetPointer(m_graph)); }
  };


Classes adicionais foram incluídas na classe CGraphic para gerenciar as propriedades dos eixos (CAxis) e curvas (CCurve) do gráfico. A classe CColorGenerator foi projetada para gerar as cores da curva. Todas essas classes estão contidas em arquivos separados, que estão incluídos no arquivo Graphic.mqh:

//+------------------------------------------------------------------+
//|                                                      Graphic.mqh |
//|                   Copyright 2016-2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
#include "Curve.mqh"
#include "Axis.mqh"
#include "ColorGenerator.mqh"
...

O arquivo com a classe CCanvas está incluída no arquivo Curve.mqh, e daqui estará disponível para toda a biblioteca.

//+------------------------------------------------------------------+
//|                                                        Curve.mqh |
//|                   Copyright 2016-2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Object.mqh>
#include <Canvas\Canvas.mqh>
...

Todas as interconexões acima entre os arquivos e as classes são mostradas na figura abaixo:

 Fig. 1. Interconexões entre as classes das bibliotecas padrão e desenvolvidas.

Fig. 1. Interconexões entre as classes das bibliotecas padrão e desenvolvidas.


Assim, as classes da biblioteca padrão para se trabalhar com arrays e arquivos se tornam automaticamente disponíveis para a biblioteca e para os arquivos da aplicação em que ele é utilizado. Vários aplicativos MQL de teste serão demonstrados mais adiante no artigo para ajudar a entender quais novos recursos estão disponíveis agora.


Aplicação para testar as propriedades do gráfico

O primeiro aplicativo MQL de teste implementará uma interface gráfica com controles para gerenciar certas propriedades de um tipo gráfico da CGraphic. Um controle do tipo CTabs está localizado na parte superior do formulário. Neste caso, é um grupo de quatro guias. Um gráfico com duas curvas com valores gerados aleatoriamente estará localizado abaixo da área de trabalho das guias.

A primeira guia (Background) terá os controles para gerenciar as seguintes propriedades do gráfico:

  • Cor de fundo.
  • O texto principal do gráfico (exibido na parte superior).
  • Texto auxiliar do gráfico (exibido na parte inferior).
  • Cor do texto principal.
  • Cor do texto auxiliar.
  • Tamanho da fonte do texto principal.
  • Tamanho da fonte do texto auxiliar.

Para definir e obter essas propriedades, a classe CGraphic fornece os métodos públicos correspondentes:

//+------------------------------------------------------------------+
//| Estrutura CBackground                                            |
//| Uso: plano de fundo em gráficos bidimensionais                   |
//+------------------------------------------------------------------+
struct CBackground
  {
   uint              clr;
   uint              clr_main;
   uint              clr_sub;
   string            main;
   string            sub;
   int               size_main;
   int               size_sub;
  };
//+------------------------------------------------------------------+
//| Classe CGraphic                                                  |
//| Uso: classe para desenhar gráficos bidimensionais                |
//+------------------------------------------------------------------+
class CGraphic
  {
protected:
   //--- elemento do gráfico
   CBackground       m_background;           // fundo de tela
   //---
public:
   //--- obtém as propriedades do fundo
   uint              BackgroundColor(void)       const { return(m_background.clr);       }
   uint              BackgroundMainColor(void)   const { return(m_background.clr_main);  }
   uint              BackgroundSubColor(void)    const { return(m_background.clr_sub);   }
   string            BackgroundMain(void)        const { return(m_background.main);      }
   string            BackgroundSub(void)         const { return(m_background.sub);       }
   int               BackgroundMainSize(void)    const { return(m_background.size_main); }
   int               BackgroundSubSize(void)     const { return(m_background.size_sub);  }
   //--- define as propriedades do fundo
   void              BackgroundColor(const uint clr)      { m_background.clr=clr;        }
   void              BackgroundMainColor(const uint clr)  { m_background.clr_main=clr;   }
   void              BackgroundSubColor(const uint clr)   { m_background.clr_sub=clr;    }
   void              BackgroundMain(const string main)    { m_background.main=main;      }
   void              BackgroundSub(const string sub)      { m_background.sub=sub;        }
   void              BackgroundMainSize(const int size)   { m_background.size_main=size; }
   void              BackgroundSubSize(const int size)    { m_background.size_sub=size;  }
  };

É assim que ele se parece:

 Fig. 2. Controles da primeira guia (Background) do aplicativo MQL de teste.

Fig. 2. Controles da primeira guia (Background) do aplicativo MQL de teste.


A segunda guia (Indents & history) conterá os controles para configurar as seguintes propriedades:

  • Indentação (esquerda, direita, superior, inferior).
  • Largura da legenda.
  • Tamanho da fonte da legenda.
  • Tamanho dos marcadores da legenda.
  • Indentações comuns para todos os elementos do gráfico.
  • Tamanho das marcas das escalas do eixo do gráfico. 

Os métodos da CGraphic mostrado na lista abaixo pode ser usado para obter e definir essas propriedades:

//+------------------------------------------------------------------+
//| Estrutura CCurveHistory                                          |
//| Uso: histórico de curvas em gráficos bidimensionais              |
//+------------------------------------------------------------------+
struct CCurveHistory
  {
   int               name_width;
   int               name_size;
   int               symbol_size;
   int               count_total;
   int               count_points;
   int               count_lines;
   int               count_histogram;
   int               count_custom;
  };
//+------------------------------------------------------------------+
//| Classe CGraphic                                                  |
//| Uso: classe para desenhar gráficos bidimensionais                |
//+------------------------------------------------------------------+
class CGraphic
  {
protected:
   //--- elemento do gráfico
   CCurveHistory     m_history;              // histórico
   //---
public:
   //--- obtém ou define as indentações
   int               IndentUp(void)               const { return(m_up0);     }
   void              IndentUp(const int up)             { m_up0=up;          }
   int               IndentDown(void)             const { return(m_down0);   }
   void              IndentDown(const int down)         { m_down0=down;      }
   int               IndentLeft(void)             const { return(m_left0);   }
   void              IndentLeft(const int left)         { m_left0=left;      }
   int               IndentRight(void)            const { return(m_right0);  }
   void              IndentRight(const int right)       { m_right0=right;    }
   //--- gets or sets gap 
   int               GapSize(void)           const { return(m_gap); }
   void              GapSize(const int size)       { m_gap=size;    }
   //--- obtém ou define o tamanho de marca principal
   int               MajorMarkSize(void)           const { return(m_mark_size); }
   void              MajorMarkSize(const int size)       { m_mark_size=size;    }
   //--- obtém as propriedades do histórico da curva
   int               HistoryNameWidth(void)            const { return(m_history.name_width);  }
   int               HistoryNameSize(void)             const { return(m_history.name_size);   }
   int               HistorySymbolSize(void)           const { return(m_history.symbol_size); }
   //--- define as propriedades do histórico da curva
   void              HistoryNameWidth(const int width) { m_history.name_width=width; }
   void              HistoryNameSize(const int size)   { m_history.name_size=size;   }
   void              HistorySymbolSize(const int size) { m_history.symbol_size=size; }
  };

Abaixo encontramos o aspecto da interface gráfica do aplicativo MQL de teste:

 Fig. 3. Controles da segunda guia (Indents & history) do aplicativo MQL de teste.

Fig. 3. Controles da segunda guia (Indents & history) do aplicativo MQL de teste.


A terceira guia (Grid) contém os controles para definir as propriedades de grade listadas abaixo:

  • Cor das linhas da grade.
  • Cor da linha do eixo zero.
  • Cor de fundo da grade.
  • Desenho de pontos nos nós da grade.
  • Raio de pontos.
  • Cor dos pontos.

Os métodos apropriados estão presentes na classe CGraphic para obter e definir essas propriedades (veja a lista de códigos abaixo):

//+------------------------------------------------------------------+
//| Estrutura CGrid                                                  |
//| Uso: grade em gráficos bidimensionais                            |
//+------------------------------------------------------------------+
struct CGrid
  {
   uint              clr_line;
   uint              clr_background;
   uint              clr_circle;
   uint              clr_axis_line;
   uint              clr_frame;
   int               r_circle;
   bool              has_circle;
  };
//+------------------------------------------------------------------+
//| Classe CGraphic                                                  |
//| Uso: classe para desenhar gráficos bidimensionais                |
//+------------------------------------------------------------------+
class CGraphic
  {
protected:
   //--- elemento do gráfico
   CGrid             m_grid;                 // grid
   //---
public:
   //--- obtém as propriedades da grade
   uint              GridLineColor(void)        const { return(m_grid.clr_line);       }
   uint              GridAxisLineColor(void)    const { return(m_grid.clr_axis_line);  }
   uint              GridBackgroundColor(void)  const { return(m_grid.clr_background); }
   int               GridCircleRadius(void)     const { return(m_grid.r_circle);       }
   uint              GridCircleColor(void)      const { return(m_grid.clr_circle);     }
   bool              GridHasCircle(void)        const { return(m_grid.has_circle);     }
   //--- define as propriedades da grade
   void              GridLineColor(const uint clr)        { m_grid.clr_line=clr;       }
   void              GridAxisLineColor(const uint clr)    { m_grid.clr_axis_line=clr;  }
   void              GridBackgroundColor(const uint clr)  { m_grid.clr_background=clr; }
   void              GridCircleRadius(const int r)        { m_grid.r_circle=r;         }
   void              GridCircleColor(const uint clr)      { m_grid.clr_circle=clr;     }
   void              GridHasCircle(const bool has)        { m_grid.has_circle=has;     }
  };

Abaixo é o que veremos no final:

 Fig. 4. Controles da terceira guia (Grid) do aplicativo MQL de teste.

Fig. 4. Controles da terceira guia (Grid) do aplicativo MQL de teste.


Os controles para gerenciar as propriedades dos eixos do gráfico serão colocados na quarta guia (Axes). Os botões de radio na parte esquerda da área de trabalho das guias permitem alternar entre a configuração de um determinado eixo. Estes botões estão separados dos outros controles da guia Axes por uma linha de separação.

Aqui estão as propriedades que estarão disponíveis para modificação:

  • Escala automática.
  • Valor mínimo do eixo.
  • Valor máximo do eixo.
  • Valor de tolerância para a mínima do eixo.
  • Valor de tolerância para a máxima do eixo.
  • Tamanho dos números do eixo.
  • O comprimento máximo de exibição dos números dos eixos.
  • Tamanho da fonte para o nome do eixo.
  • Valor do passo inicial para o eixo.
  • Quantidade máxima de números no eixo.
  • Nome do eixo.
  • Cor do texto do nome do eixo.

A lista abaixo mostra os nomes dos métodos da classe CAxis para obter e definir as propriedades acima:

//+------------------------------------------------------------------+
//| Classe CAxis                                                     |
//| Uso: classe para criar os eixos em gráficos bidimensionais       |
//+------------------------------------------------------------------+
class CAxis
  {
private:
   double            m_min;
   double            m_max;
   uint              m_clr;
   string            m_name;
   int               m_name_size;
   int               m_values_size;
   int               m_values_width;
   bool              m_auto_scale;
   double            m_default_step;   // tamanho do passo padrão
   double            m_max_labels;     // o número máixmo de marcações
   double            m_min_grace;      // valor "grace" aplicado ao intervalo mínimo de dados
   double            m_max_grace;      // valor "grace" aplicado ao intervalo máximo de dados
   //---
public:
                     CAxis(void);
                    ~CAxis(void);
   //--- propriedades
   double            Min(void)                  const { return(m_min);  }
   void              Min(const double min)            { m_min=min;      }
   double            Max(void)                  const { return(m_max);  }
   void              Max(const double max)            { m_max=max;      }
   string            Name(void)                 const { return(m_name); }
   void              Name(const string name)          { m_name=name;    }
   //--- propriedades padrão 
   uint              Color(void)                        const { return(m_clr);            }
   void              Color(const uint clr)                    { m_clr=clr;                }
   bool              AutoScale(void)                    const { return(m_auto_scale);     }
   void              AutoScale(const bool auto)               { m_auto_scale=auto;        }
   int               ValuesSize(void)                   const { return(m_values_size);    }
   void              ValuesSize(const int size)               { m_values_size=size;       }
   int               ValuesWidth(void)                  const { return(m_values_width);   }
   void              ValuesWidth(const int width)             { m_values_width=width;     }
   int               NameSize(void)                     const { return(m_name_size);      }
   void              NameSize(const int size)                 { m_name_size=size;         }
   double            DefaultStep(void)                  const { return(m_default_step);   }
   void              DefaultStep(const double value)          { m_default_step=value;     }
   double            MaxLabels(void)                    const { return(m_max_labels);     }
   void              MaxLabels(const double value)            { m_max_labels=value;       }
   double            MinGrace(void)                     const { return(m_min_grace);      }
   void              MinGrace(const double value)             { m_min_grace=value;        }
   double            MaxGrace(void)                     const { return(m_max_grace);      }
   void              MaxGrace(const double value)             { m_max_grace=value;        }
  };

O resultado é mostrado abaixo:

 Fig. 5. Controles da quarta guia (Axes) da aplicação MQL de teste.

Fig. 5. Controles da quarta guia (Axes) da aplicação MQL de teste.


O aplicativo de teste apresentado no artigo pode ser baixado usando o link abaixo para um estudo mais detalhado.


Aplicação para testar as propriedades das curvas do gráfico

Um aplicativo MQL separado foi escrito para testar certas propriedades das curvas em um gráfico com o tipo CGraphic. Os controles para gerenciar as propriedades das curvas do gráfico estarão localizados no topo do formulário dessa aplicação, com dois gráficos do tipo CGraphic (o controle CGraph) logo abaixo deles. O primeiro gráfico exibirá uma sériee de dados aleatórios, e o segundo irá traçar seus derivativos, que são calculados com base na fórmula do indicador Momentum, como exemplo.

Aqui estão os controles para gerenciar as propriedades das curvas do gráfico:

  • Caixa de seleção Animate - inicia a entrada automática de dados no gráfico.
  • Caixa de edição spin Array size - o número atual de elementos no array de dados que são exibidos no gráfico.
  • Botão Random - gera sequências de dados aleatórias em série no gráfico.
  • Caixa de edição spin Period - valor da variável para calcular o indicador Momentum.
  • Caixa combinada Curve type – tipo de curvas no gráfico.
  • Caixa combinada Point type - tipo de dados em pontos que são usados ​​para traçar as curvas no gráfico.

A classe personalizada da aplicação (CProgram) implementa os métodos que são relacionados aos controles listados acima e executa as seguintes tarefas:

  • Configuração do tamanho dos arrays de dados para exibição no gráfico.
  • Inicialização os arrays com dados.
  • Atualização dos gráficos para refletir as mudanças recentes.
  • Adição de um elemento ao final dos arrays.
  • Exclusão de um elemento no final dos arrays.
  • Atualização dos gráficos pelo timer.
  • Animação dos gráficos com entrada automática de novos dados.

Abaixo está a listagem de códigos para todos os métodos que implementam essas funções. Baixe os arquivos no final do artigo para encontrar mais detalhes sobre o código desses métodos.

class CProgram : public CWndEvents
  {
protected:
   //--- Arrays de dados para a saída no gráfico
   double            data1[];
   double            data2[];
   //---
   double            data3[];
   double            data4[];
   //---
private:
   //--- Redimensiona os arrays
   void              ResizeGraph1Arrays(void);
   void              ResizeGraph2Arrays(void);
   void              ResizeGraph1Arrays(const int new_size);
   void              ResizeGraph2Arrays(const int new_size);
   //--- Inicialização dos arrays
   void              InitGraph1Arrays(void);
   void              InitGraph2Arrays(void);
   //--- Zera os arrays
   void              ZeroGraph1Arrays(void);
   void              ZeroGraph2Arrays(void);
   //--- Define o valor aleatório no índice especificado
   void              SetGraph1Value(const int index);
   void              SetGraph2Value(const int index);
   //--- Atualiza as séries no gráfico
   void              UpdateGraph(void);
   void              UpdateGraph1(void);
   void              UpdateGraph2(void);
   
   //--- Recalcula a série no gráfico
   void              RecalculatingSeries(void);
   //--- Adiciona um valor a mais ao final dos arrays
   void              AddValue(void);
   //--- Remove um valor no final dos arrays
   void              DeleteValue(void);

   //--- Atualiza o gráfico pelo timer
   void              UpdateGraphByTimer(void);
   //--- Anima a série do gráfico
   void              AnimateGraphSeries(void);
  };

É assim que ele se parece:

 Fig. 6. Interface gráfica do aplicativo para testar as propriedades das curvas do gráfico.

Fig. 6. Interface gráfica do aplicativo para testar as propriedades das curvas do gráfico.


O aplicativo de teste apresentado no artigo pode ser baixado usando o link abaixo para um estudo mais detalhado.


Aplicação com um gráfico de hipocicloide animado

Em um de seus livros sobre programação em VBA no Microsoft Excel, John Walkenbach fornece aos leitores um CD com arquivos de teste. Um dos arquivos implementa um diagrama, onde um número infinito de hipocicloides é gerado. 

Para referência: A Wikipedia dá a seguinte definição:

Um hipocicloide (do grego ὑπό — embaixo, abaixo e κύκλος — círculo, circunferência) é uma curva de plano especial gerada pelo traço de um ponto fixo em um pequeno círculo que rola dentro de um círculo maior.

Definição de John Walkenbach dada em seu livro:

hipocicloide - o caminho formado por um ponto em um círculo que rola dentro de outro círculo.

Vamos implementar uma aplicação semelhante no MQL e adicionar uma interface gráfica para gerenciar os parâmetros. Vamos ver como funciona em detalhes.

Três parâmetros são usados ​​para gerar um novo hipocicloide, que é usado para inicializar as sequências numéricas com o passo especificado. Em seguida, os cálculos são realizados com base nos valores nessas sequências para obter as coordenadas de pontos no gráfico. Depois disso, os resultados obtidos são normalizados.

Na classe personalizada, nós declaramos vários arrays para calcular as sequências e os campos para calcular a média e desvio padrão.

//+------------------------------------------------------------------+
//|                                                      Program.mqh |
//|                        Copyright 2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Math\Stat\Stat.mqh>
#include <EasyAndFastGUI\WndEvents.mqh>
#include <EasyAndFastGUI\TimeCounter.mqh>
//+------------------------------------------------------------------+
//| Classe para a criação de uma aplicação                           |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
protected:
...
   //--- Arrays de dados para cálculos
   double            a_inc[];
   double            b_inc[];
   double            t_inc[];
   double            x_source[];
   double            y_source[];
   //--- Arrays de dados para a saída no gráfico
   double            x_norm[];
   double            y_norm[];
   //--- Para calcular a média e o desvio padrão
   double            x_mean;
   double            y_mean;
   double            x_sdev;
   double            y_sdev;
...
  };
//+------------------------------------------------------------------+
//| Construtor                                                       |
//+------------------------------------------------------------------+
CProgram::CProgram(void) : x_mean(0),
                           y_mean(0),
                           x_sdev(0),
                           y_sdev(0)
  {
...
  }

Os valores serão calculados no método CProgram::InitArrays(). Aqui, o primeiro ciclo calcula os dados iniciais. Em seguida, o desvio padrão e a média são obtidos, e o segundo ciclo normaliza os dados. Os tamanhos dos arrays são definidos usando o método CProgram::ResizeArrays(). Os valores para os tamanhos do array são retirados do controle da Caixa de texto (CTextEdit) da interface gráfica da aplicação.

class CProgram : public CWndEvents
  {
private:
   //--- Redimensiona os arrays
   void              ResizeArrays(void);
   //--- Inicialização dos arrays auxiliares para cálculos
   void              InitArrays(void);
  };
//+------------------------------------------------------------------+
//| Redimensiona os arrays                                           |
//+------------------------------------------------------------------+
void CProgram::ResizeArrays(void)
  {
   int array_size =::ArraySize(x_norm);
   int new_size   =(int)m_array_size.GetValue();
//--- Retorna, se o tamanho não mudou
   if(array_size==new_size)
      return;
//--- Define o novo tamanho
   ::ArrayResize(a_inc,new_size);
   ::ArrayResize(b_inc,new_size);
   ::ArrayResize(t_inc,new_size);
   ::ArrayResize(x_source,new_size);
   ::ArrayResize(y_source,new_size);
   ::ArrayResize(x_norm,new_size);
   ::ArrayResize(y_norm,new_size);
  }
//+------------------------------------------------------------------+
//| Inicialização dos arrays                                         |
//+------------------------------------------------------------------+
void CProgram::InitArrays(void)
  {
//--- Redimensiona os arrays
   ResizeArrays();
//--- Calcula os valores usando fórmulas
   int total=(int)m_array_size.GetValue();
   for(int i=0; i<total; i++)
     {
      if(i<1)
        {
         a_inc[i] =1+(double)m_animate.GetValue();
         b_inc[i] =1+(double)m_animate.GetValue();
         t_inc[i] =1+(double)m_animate.GetValue();
        }
      else
        {
         a_inc[i] =a_inc[i-1]+(double)m_a_inc.GetValue();
         b_inc[i] =b_inc[i-1]+(double)m_b_inc.GetValue();
         t_inc[i] =t_inc[i-1]+(double)m_t_inc.GetValue();
        }
      //---
      double a=a_inc[i];
      double b=b_inc[i];
      double t=t_inc[i];
      //---
      x_source[i] =(a-b)*cos(t)+b*cos((a/b-1)*t);
      y_source[i] =(a-b)*sin(t)+b*sin((a/b-1)*t);
     }
//--- Calcule a média
   x_mean=MathMean(x_source);
   y_mean=MathMean(y_source);
//--- Calcula o desvio padrão
   x_sdev=MathStandardDeviation(x_source);
   y_sdev=MathStandardDeviation(y_source);
//--- Ajuste para evitar a divisão por zero
   x_sdev =(x_sdev==0)? 1 : x_sdev;
   y_sdev =(y_sdev==0)? 1 : y_sdev;
//--- Normaliza os dados
   for(int i=0; i<total; i++)
     {
      x_norm[i] =(x_source[i]-x_mean)/x_sdev;
      y_norm[i] =(y_source[i]-y_mean)/y_sdev;
     }
  }

A classe CGraphic contém os métodos que permitem a adição de cortes, linhas e texto adicionais às escalas de eixos dentro da área de trabalho do gráfico criado.

Em nosso caso, o método CProgram::TextAdd() será usado para produzir os valores da média e o desvio padrão para as sequências X e Y no canto superior esquerdo do diagrama. O métodos CGraphic::ScaleX() e CGraphic::ScaleY() são usados ​​para obter as coordenadas do ponto extremo (canto superior esquerdo) do diagrama. Eles são projetados para dimensionar os valores reais do gráfico em coordenadas de pixels. Aqui a mínima ao longo do eixo X e a máxima ao longo do eixo Y são alimentados como valores reais. 

class CProgram : public CWndEvents
  {
private:
   //--- Adiciona o texto ao gráfico
   void              TextAdd(void);
  };
//+------------------------------------------------------------------+
//| Adiciona o texto ao gráfico                                      |
//+------------------------------------------------------------------+
void CProgram::TextAdd(void)
  {
//--- Obtém o ponteiro para o gráfico
   CGraphic *graph=m_graph1.GetGraphicPointer();
//---  
   int  x     =graph.ScaleX(graph.XAxis().Min())+50;
   int  y     =graph.ScaleY(graph.YAxis().Max())+10;
   int  y2    =y+20;
   uint clr   =::ColorToARGB(clrBlack);
   uint align =TA_RIGHT;
//---
   string str[8];
   str[0] ="x mean:";
   str[1] ="y mean:";
   str[2] =::DoubleToString(x_mean,2);
   str[3] =::DoubleToString(y_mean,2);
   str[4] ="x sdev:";
   str[5] ="y sdev:";
   str[6] =::DoubleToString(x_sdev,2);
   str[7] =::DoubleToString(y_sdev,2);
//--- Calcula as coordenadas e publica o texto no gráfico
   int l_x=0,l_y=0;
   for(int i=0; i<8; i++)
     {
      if(i<2)
         l_x=x;
      else if(i<6)
         l_x=(i%2==0)? l_x+50 : l_x;
      else
         l_x=(i%2==0)? l_x+60 : l_x;
      //---
      l_y=(i%2==0)? y : y2;
      //---
      graph.TextAdd(l_x,l_y,str[i],clr,align);
     }
  }

Após todos os dados necessários serem definidos no gráfico, é necessário redesenhá-lo para refletir as mudanças mais recentes. Isso é feito pelo método CProgram::UpdateSeries(). Aqui, ele verifica primeiro se há alguma série no gráfico. Se houver, então ele define os últimos dados calculados. Além disso, as propriedades da curva são definidas usando os controles da interface gráfica. Aqui, são (1) a suavização da linha, (2) o tipo de pontos e (3) o tipo da curva. Deve-se notar que o texto deve ser aplicado ao gráfico após todas as outras propriedades e dados forem definidas e renderizadas. No final, é necessário atualizar o gráfico para ver o resultado.

class CProgram : public CWndEvents
  {
private:
   //--- Define e atualiza as séries no gráfico
   void              UpdateSeries(void);
  };
//+------------------------------------------------------------------+
//| Define e atualiza as séries no gráfico                           |
//+------------------------------------------------------------------+
void CProgram::UpdateSeries(void)
  {
//--- Obtém o ponteiro para o gráfico
   CGraphic *graph=m_graph1.GetGraphicPointer();
//--- Atualiza todas as séries do gráfico
   int total=graph.CurvesTotal();
   if(total>0)
     {
      //--- Obtém o ponteiro da curva
      CCurve *curve=graph.CurveGetByIndex(0);
      //--- Define os arrays de dados
      curve.Update(x_norm,y_norm);
      //--- Obtém os valores das propriedades da curva
      ENUM_CURVE_TYPE curve_type =(ENUM_CURVE_TYPE)m_curve_type.GetListViewPointer().SelectedItemIndex();
      ENUM_POINT_TYPE point_type =(ENUM_POINT_TYPE)m_point_type.GetListViewPointer().SelectedItemIndex();
      //--- Define as propriedades
      curve.LinesSmooth(m_line_smooth.IsPressed());
      curve.PointsType(point_type);
      curve.Type(curve_type);
     }
//--- Aplicar 
   graph.Redraw(true);
//--- Saída do texto
   TextAdd();
//--- Atualiza o gráfico
   graph.Update();
  }

O método CProgram::RecalculatingSeries() é usado para calcular e aplicar os resultados obtidos em uma única chamada:

class CProgram : public CWndEvents
  {
private:
   //--- Recalcula a série no gráfico
   void              RecalculatingSeries(void);
  };
//+------------------------------------------------------------------+
//| Recalcula as séries no gráfico                                   |
//+------------------------------------------------------------------+
void CProgram::RecalculatingSeries(void)
  {
//--- Calcula os valores e inicializa os arrays
   InitArrays();
//--- Atualiza a série
   UpdateSeries();
  }

O diagrama plotado com base nessas fórmulas ficará mais interessante se ele se tornar animado. Para definir as sequências calculadas em movimento, é necessário alterar o valor inicial dessas sequências. Isso pode ser alcançado inserindo os valores através da caixa de edição spin ou executando o processo no modo automático. No modo automático, o valor nesta caixa de edição é incrementado ou diminuído pelo método CProgram::AnimateGraphSeries(). Este método é chamado no método CProgram::UpdateGraphByTimer(), que por sua vez é invocado no timer da aplicação.

class CProgram : public CWndEvents
  {
private:
   //--- Atualiza o gráfico pelo timer
   void              UpdateGraphByTimer(void);
   //--- Anima a série do gráfico
   void              AnimateGraphSeries(void);
  };
//+------------------------------------------------------------------+
//| Timer                                                            |
//+------------------------------------------------------------------+
void CProgram::OnTimerEvent(void)
  {
   CWndEvents::OnTimerEvent();
//--- Atualiza o gráfico pelo timer
   if(m_counter1.CheckTimeCounter())
     {
      UpdateGraphByTimer();
     }
...
  }
//+------------------------------------------------------------------+
//| Atualiza o gráfico pelo timer                                    |
//+------------------------------------------------------------------+
void CProgram::UpdateGraphByTimer(void)
  {
//--- Retorna, se (1) o formulário for minimizado ou (2) a animação estiver desativada
   if(m_window.IsMinimized() || !m_animate.IsPressed())
      return;
//--- Anima a série do gráfico
   AnimateGraphSeries();
//--- Atualiza os arrays e séries no gráfico
   RecalculatingSeries();
  }
//+------------------------------------------------------------------+
//| Anima a série do gráfico                                         |
//+------------------------------------------------------------------+
void CProgram::AnimateGraphSeries(void)
  {
//--- Para especificar a direção para redimensionar os arrays
   static bool counter_direction=false;
//--- Muda a direção se o mínima for atingida
   if((double)m_animate.GetValue()<=(double)m_animate.MinValue())
      counter_direction=false;
//--- Muda a direção se a máxima for alcançada
   if((double)m_animate.GetValue()>=(double)m_animate.MaxValue())
      counter_direction=true;
//--- Redimensiona o array na direção especificada
   string value="";
   if(!counter_direction)
      value=string((double)m_animate.GetValue()+m_animate.StepValue());
   else
      value=string((double)m_animate.GetValue()-m_animate.StepValue());
//--- Define o novo valor e atualiza a caixa de texto
   m_animate.SetValue(value,false);
   m_animate.GetTextBoxPointer().Update(true);
  }

O resultado obtido é exibido abaixo:

 Fig. 7. Demonstração de um hipocicloide animado.

Fig. 7. Demonstração de um hipocicloide animado.


O aplicativo de teste apresentado no artigo pode ser baixado usando o link abaixo para um estudo mais detalhado.


Nova versão da aplicação de teste das atualizações anteriores

A aplicação de teste demonstrada no artigo Interfaces Gráficas IX: Os Controles Barra de Progresso e Gráfico de Linha (Capítulo 2) foi atualizado de acordo com as alterações nesta atualização.

A nova versão deste aplicativo MQL com a interface gráfica atualizada é exibida abaixo:

 Fig. 8. Nova versão do aplicativo de teste das atualizações anteriores.

Fig. 8. Nova versão do aplicativo de teste das atualizações anteriores.


O aplicativo de teste apresentado no artigo pode ser baixado usando o link abaixo para um estudo mais detalhado.


Conclusão

Neste artigo, foi integrado uma parte da biblioteca padrão para traçar gráficos científicos com a biblioteca desenvolvida para a criação de interfaces gráficas. Todos os exemplos demonstrados podem ser baixados dos arquivos anexados a este artigo para estudar o código fonte em mais detalhes.

A biblioteca no estágio atual de desenvolvimento se parece com o esquema abaixo:

 Fig. 9. Estrutura da biblioteca, no atual estágio de desenvolvimento

Fig. 9. Estrutura da biblioteca, no atual estágio de desenvolvimento


O código da biblioteca apresentado é gratuito. Você pode usá-lo em seus projetos, inclusive comercialmente, escrever artigos e cumprir ordens.

Se você tiver dúvidas sobre como usar o material do artigo, você pode perguntar nos comentários.

Traduzido do russo pela MetaQuotes Software Corp.
Artigo original: https://www.mql5.com/ru/articles/3527

Arquivos anexados |
TradeObjects: Automação de negociação com base em objetos gráficos na MetaTrader TradeObjects: Automação de negociação com base em objetos gráficos na MetaTrader

Este artigo lida com uma abordagem simples para a criação de um sistema de negociação automatizado com base no desenho de uma linha ao gráfico e oferece um Expert Advisor pronto, usando as propriedades padrão dos objetos da MetaTrader 4 e 5, suportando as principais operações de negociação.

Escrevendo um livro de ofertas de scalping com base na biblioteca gráfica CGraphic Escrevendo um livro de ofertas de scalping com base na biblioteca gráfica CGraphic

O artigo apresenta a criação de um livro de ofertas de scalping com funcionalidade básica. Desenvolve-e um gráfico de ticks com base na biblioteca gráfica CGraphic e se integra na tabela de pedidos. Pode-se criar um poderoso auxiliar para negociação no curto prazo utilizando o livro de ofertas descrito.

Avaliação de risco numa sequência de operações com um ativo Avaliação de risco numa sequência de operações com um ativo

Este artigo descreve como usar os métodos da teoria da probabilidade e estatística matemática na análise de sistemas de negociação.

Busca automática de divergências e convergência Busca automática de divergências e convergência

O artigo examina todos os tipos de divergência: oculta, estendida, tripla, convergência, de classes A, B e C, etc. É criado um indicador universal para elas serem buscadas e exibidas num gráfico.