English Русский Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
利用标准库类创建您自己的“市场报价”

利用标准库类创建您自己的“市场报价”

MetaTrader 5示例 | 12 十二月 2013, 09:23
2 565 0
Dmitriy Skub
Dmitriy Skub

简介

我们任务的主要目标在于:开发一款用于 MetaTrader 5 客户端的图表任意文本信息输出的用户友好且可扩展的工具。比如说,“EA 交易”的当前设置,或是指定时间间隔内其运行结果(作为一个表呈现),交易者使用的价格值或指标值表,或是“EA 交易”的交易日志。在 EA 或使用此库的指标运行期间,所有此类信息都可以动态显示于图表上方。

作为开发此库的基础,有一系列的 MetaTrader 5 客户端标准库类被采用。我们首先要研究这些类,并对其实施相应的扩展,以完成我们的任务。

图形对象标准类

我们感兴趣的这组类,位于 IncludeInclude\ChartObjects 文件夹中。

文件如下:

  • Object.mqh - 包含可供创建所有其它类的 CObject 基类,与图形对象相关。
  • ChartObject.mqh - 还包含 CChartObject 类 - 衍生自 CObject,扩展图形对象一般数据与方法的功能性和封装性。
  • ChartObjectsTxtControls.mqh - 包含大量的类,旨在显示图表上的各类图形对象(包括文本)。(CChartObjectText 基类及其后代:CChartObjectLabelCChartObjectEditCChartObjectButton

我们更仔细地讲讲这些类。

CObject:基类

类描述很短,所以贴出来看看:

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;
}

您也看到了,此类中只包含一般用途的数据和方法,它们并不与图表的输出直接相关。

但是,它仍具备一个非常重要的属性 - 可用于创建单链和双链表。这些功能由 CObject::m_prevCObject* 类型的 CObject::m_next 数据字段及其读/写方法提供。CObject::m_prev 字段引用的是前一个列表元素,而 CObject::m_next 则是引用下一个。有关列表构造的更多详情,我们稍候再谈。

此外,还有一种对比 CObject* 类型两种对象的方法 - CObject::Compare 方法,可在对列表元素排序时使用。想要实现文件中数据字段的保存/计数,还有两种更有用的方法 - 那就是 CObject::SaveCObject::Load 方法。想要获取想要的功能,就要在后代类中重载这些方法。

CObject::Type 是对象类型识别方法。此方法在处理包含不同类型对象的列表时很有用。

CObject 类(及其实例)拥有下述功能:

  • 识别自己相对于列表中邻近元素的位置。
  • 对象类型识别。
  • 对象数据保存与加载的方法。
  • 与指定对象对比的方法。

如上所述的大多数方法都是虚拟的,并未于基类中实施。基类并没有任何带有实体意义的实际属性。作为 OOP 中的惯例,功能要在后代类中实施。

CChartObject: 图形对象的基类

CChartObjectCObject 类的一个后代。

通过其名称,您就可以看出这是一个描述某些抽象图形对象的类。不过,这个抽象对象已经包含了一些实体属性和使用这些属性的方法。此类属性对 MetaTrader 5 中的所有图形对象通用,所以将其置入此类也符合逻辑。

我们更仔细地讲讲它们。我们会利用下述数据,将图形对象附至图表窗口:

protected:
  long       m_chart_id;    // 包含指定图形对象的 
                               // 图表编号 (0 - 当前图表)
  int        m_window;      // 图表子窗口编号 (0 - 主窗口)
  string     m_name;        // 图表上对象的唯一名称
  int        m_num_points;  // 绑定对象的点数

在我们指定或读取真实图形对象的属性之前,必须将其与对象相连(类实例)。这一动作通过 CChartObject::Attach 方法来完成。在后代类中,它会在图表上创建图形对象后立即被调用。

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);
}

首先,我们验证真实图形对象是否存在。如果存在,则将其属性存储至 CChartObject 类对象的内部字段。之后,我们可以读取或修改图形对象的属性(颜色、位置等)。

图形对象属性的保存/读取方法,已于 CChartObject::SaveCChartObject::Load 方法中实施。在后代类中,要先调用保存/读取的父方法,再调用自己的方法。

与基类相比,CChartObject 类(及其实例)拥有下述新属性:

  • 带有类实例的图表上的真实图形对象的附加。
  • 所有图形对象通用属性的读取与修改。
  • 由图表删除图形对象。
  • 图表上图形对象的移动。


CChartObjectText:文本 - 图形对象的类

现在,我们把注意力转向 ChartObjectsTxtControls.mqh 文件。我们会在这里找到专为各种图形对象输出而开发的类的描述,其中包含图表上方的文本。我们来研究研究它们的基本功能。

它们的基类是 CChartObjectText 类。它封装了与图表上文本输出关联的属性和方法。

该类的描述如下:

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);
};

CChartObject 相比,它包含文本图形对象属性的读取与修改方法 - 图表上文本方向的角度、文本的字体名称、字号以及图形对象的坐标。有一种新方法出现 CChartObjectText::Create 允许我们在图表上创建一个 OBJ_TEXT 类型的真实图表对象。

其实施:

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);
}

如果图形对象已成功创建(ObjectCreate 方法返回 true),则 CChartObject::Attach 方法即被调用(我们之前讲过的方法)。

由此,对比父类,CChartObjectText 的新功能包括:

  • 文本图形对象属性的读取与修改。
  • 于图表上创建一个 OBJ_TEXT 类型的真实图形对象。

CChartObjectLabel: “文本标签”图形对象的一个类

标准类层级中的下一个类,就是 CChartObjectLabel 类。它允许您在图表上创建 OBJ_LABEL 类型(文本标签)的图形对象。

此为该类描述:

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);
};

这里,我们必须注意 OBJ_TEXT 类型图形对象与 OBJ_LABEL 类型对象两者间的区别。

前一种绑定价格图表(价格时间坐标)或子窗口的图表。后一种则绑定窗口的图表坐标,或是图表的子窗口(像素)。

因此,OBJ_TEXT 类型的对象会在滚动时随图表一同移动,而 OBJ_LABEL 类型的对象则会在滚动时保持不动。因此,我们必须根据任务,选择特定的图形文本对象类型。

对比父类,CChartObjectLabel 类包含的特色功能如下:

  • 定位图形对象时用到的图表坐标。
  • 它允许您读取和修改固定的角。实际上,这是在将坐标的开头分配给图表窗口四个角中的一个。
  • 于客户端图表上创建一个 OBJ_LABEL 类型的真实图形对象。

CChartObjectEdit:“输入字段”图形对象的一个类

层级中的下一个类是 CChartObjectEdit 类。这是一个用于创建 OBJ_EDIT 类型(输入字段)图形对象的类。

该类型的对象也和 OBJ_LABEL 类型的对象一样,利用图表坐标(像素)绑定,所以,像标准类一样由 CChartObjectLabel 类衍生出它来也合乎逻辑:

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);
};

OBJ_EDIT 类型输入字段与文本标签两者的区别如下:

  • 输入字段拥有宽度与高度属性(按屏幕像素指定),可限制图表上图形对象的尺寸。文本标签的尺寸会自动调整,以求整个文本都能被看到。
  • 启用/禁用文本修改也有相应的方法 - CChartObjectEdit::ReadOnly
  • 还添加了一种更改图形对象占据区域的背景颜色的方法。
  • 对象显示的角度,则不可能更改。输入字段只能以水平方向显示。
  • 它允许于图表上创建一个 OBJ_EDIT 类型的真实图形对象。

CChartObjectButton:“按钮”图形对象的类

CChartObjectButton 是文本图形对象层级中的又一个类。该对象被称为按钮,开发目的就是在图表上创建一个按下式按钮形式的控件元素。该类是 CChartObjectEdit 类的一个后代,且继承其功能性:

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);
};

源自输入字段的 OBJ_BUTTON 类型的按钮差别如下:

  • 它看起来像是一个按下式按钮,与 Windows 对话框中使用的那些类似。
  • 它拥有读取/修改按钮状态(按下/未按下)的新方法 - CChartObjectButton::State
  • 它允许于图表上创建一个 OBJ_BUTTON 类型的真实图形对象。

图形文本对象标准类的整体结构

标准库类的结构(层级)可总结如下:

标准类的总体结构

图 1. 标准类的总体结构

CObject 类是其它标准类的基类,比如操作列表以及其它的 CList 类。


标准库类的功能扩展

我们简要地探讨过旨在于图表上生成文本图形对象的标准类的层级。现在,我们利用新的类来扩展此层级。首先,我们必须决定实施所需的功能性。介绍一下要求。因为我们要处理文本信息的输出,所以按下述结构化形式提供此信息是合乎逻辑的:

标题 信息文本

文本信息的这种呈现结构,适用于大多数的简单情况。

比如说,交易品种参数的指标可能如下所示:

文本信息结构化显示示例

图 2. 文本信息结构化显示示例

它采用了上面提到结构的六个信息字段。可能会缺少结构中的某些元素。比如说图 2 中顶部字段的平铺就没有显示。其它字段包含标题与文本。该指标可在本文随附的 PricelInfo.mq5 文件中找到。

图形对象的定位

我们需要研究的第二点,就是在图表上定位图形文本对象的方式。采用的按屏幕像素指定坐标的方法,允许对图表中任意位置对象的定位。

如果您要在图表的不同位置上放置多个文本对象,在实际应用中会很不方便,因为所有的屏幕坐标都需要计算。此外,如果您更改了图表尺寸,则所有的像素坐标都需要重新计算,以确保对象在屏幕上的相对位置不被改变。

如果我们将图表窗口描画成同样大小的矩形(字段),并为每个矩形分配一个水平与垂直坐标,我们就会得到一个独立于屏幕分辨率之外的通用定位系统。

创建图形文本对象时,用户可以设置垂直与水平方向字段的最大数量,以及此类字段中作为参数的对象坐标。而内嵌于相应类中的功能,则会在您更改屏幕分辨率时自动调整图形对象的坐标。如此一来,坐标仅需指定一次,无需任何进一步的调整。


独特对象名称的自动生成

下一个必须处理的问题,就是图形文本对象名称的自动生成。对于生成方法的主要要求,就是在给定的窗口内获取一个独特的名称。如此则允许定位屏幕上的大量对象,且无需费心绞尽脑汁地自创不重复的名称。

我们建议采用下述方法生成名称(由字段构成的字符串):

日期时间
毫秒数

要获取字符串中包含日期与时间的部分,请使用下述调用:

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

要获取毫秒数,请使用下述调用:

DoubleToString(GetTickCount(), 0);

但是,即便我们测量时间到了毫秒,在连续调用 GetTickCount () 函数两次或更多次时,也极有可能会取得相同的值。这是由于操作系统与处理器内计时器不连续的限制。因此,有必要采取额外措施来检测此类情况。

建议方法利用下述函数实施:

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;
    }

//  确认没有同样名称的对象:
    string name = TimeToString(TimeGMT(), TIME_DATE|TIME_MINUTES|TIME_SECONDS)+" "+DoubleToString(count, 0);
    if(ObjectFind(0, name) < 0)
    {
      return(name);
    }
  }

  return(NULL);
}

此方法的局限:每秒钟生成的独特名称超不过 4294967295 (UINT_MAX) 个。很明显,这在实际应用中足够了。为防万一,还有一个是否存在同名图形对象的附加验证。


信息结构标题的显示 - TTitleDisplay 类

在终端屏幕上显示标题的类,如下所示:

class TTitleDisplay : public CChartObjectLabel
{
protected:
  long    chart_id;
  int     sub_window;
  long    chart_width;       // 图表的像素点数宽度
  long    chart_height;      // 图表的像素点数高度
  long    chart_width_step;  // 水平方向上网格坐标距离
  long    chart_height_step; // 垂直方向上网格坐标距离
  int     columns_number;    // 列数
  int     lines_number;      // 行数
  int     curr_column;
  int     curr_row;

protected:
  void    SetParams(long chart_id, int window, int cols, int lines);// 指定对象参数

protected:
  string  GetUniqName();    // 设置一个唯一名称
  bool    Create(long chart_id, int window, int cols, int lines, int col, int row);
  void    RecalcAndRedraw();// 重新计算坐标并重绘

        
public:
  void    TTitleDisplay();  // 构造函数
  void    ~TTitleDisplay(); // 析构函数
};

创建图形文本对象的基本方法:

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

输入参数的赋值如下:

  • chart_id - 窗口标识符(0 - 主窗口);
  • window - 子窗口编号(0 - 主);
  • cols - 水平方向图形文本对象最大数量(列数);
  • lines - 垂直方向图形文本对象最大数量(行数);
  • col - 图形对象的水平坐标(从零到 cols - 1 之间变化);
  • row - 图形对象的垂直坐标(从零到 lines - 1 之间变化);

TTitleDisplay::SetParams 方法会计算对象与屏幕上位置关联的参数。

实施如下:

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;

//  指定窗口的像素尺寸:
  this.chart_width = GetSystemMetrics(SM_CXFULLSCREEN);
  this.chart_height = GetSystemMetrics(SM_CYFULLSCREEN);

//  计算坐标网格的距离
  this.chart_width_step = this.chart_width/_cols;
  this.chart_height_step = this.chart_height/_lines;
}

这里,我们采用 GetSystemMetrics WinAPI 函数调用来获取当前显示设置。此函数由 user32.dll Windows 系统库导入。

创建信息文本的 TFieldDisplay 类也用类似方法构建。详情请见本文随附的 TextDisplay.mqh 库。

CList 类:列表中对象的处理

现在来研究另一个标准类,我们会在实现计划时用到它。此类允许您将对象组至列表。它位于 Include\Arrays\List.mqh 文件中。此文件会提供某标准 CList 类的描述与实施 - 该类为 CObject 基类的后代,前文我们讲过。它包含一系列处理列表中对象的方法(添加到列表、由列表中移除、访问列表任意元素以及清空列表)。

我们来看基本方法:

  • 添加到列表:
   int Add(CObject *new_node);
   int Insert(CObject *new_node,int index);

向列表中添加新项目有两种方法。第一种 CList::Add 方法允许您将新元素 new_node 添加到列表末尾。第二种 CList::Insert 方法则能让您将新元素 new_node 插入到列表中任意位置(由 索引指定)。

  • 由列表中移除:
   bool  Delete(int index);

CList::Delete 方法允许您将带有指定索引的某个元素由列表中移除。同时,除了由列表中移除该项以外,由 CObject 类型元素占用的内存也会被释放。换句话说,对象会被“物理”删除。

  • 访问列表中任意元素:
   int       IndexOf(CObject* node);
   CObject*  GetNodeAtIndex(int index);
   CObject*  GetFirstNode();
   CObject*  GetPrevNode();
   CObject*  GetNextNode();
   CObject*  GetLastNode();

CList::IndexOf 方法会返回列表中某特定元素的索引。索引的编号从零开始:第一个元素的索引为零。此方法会执行反运算,并按元素指针返回索引。如果元素未在列表中,则返回 -1。

巡览 CList::GetFirstNode 列表的另四种方法会返回前一元素,而 CList::GetNextNode 则会返回下一元素,CList::GetLastNode 会返回列表中最后一个元素。

  • 清空列表:
   void  Clear();

CList::Clear 方法允许您移除列表中所有元素,同时释放被对象占用的内存。

这些都是 CList 类的基本方法,其余方法的描述请见《MQL5 参考》


TableDisplay 类:创建一个在图表上显示文本的表

那么,我们已经得到了实现计划所需的一切。这里是一个简单的类,允许您在一个任意大小的表内组织文本图形对象:

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();
};

向此表添加图形对象之前,您必须先设置参数:图表标识符、子窗口索引以及固定点。可以通过调用 TableDisplay::SetParams 方法来实现。此后,您可以向此表添加任何数量的标题和文本字段。

我们开发的完整库文本,均见本文随附的 TextDisplay.mqh 文件。


3. 创建“市场报价”示例

考虑以指标的形式创建多交易品种值显示表的示例。

大体如下所示:

屏幕表格示例

图 3. 屏幕表格示例

  • 步骤 1 - 包含库(在指标的源代码中):
#include  <TextDisplay.mqh>
  • 步骤 2 - 创建带有标题名称和坐标的数组:
#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};
坐标从零开始排序。
  • 步骤 3 - 创建一个 TableDisplay 类型的表对象,以存储显示的所有文本对象:
TableDisplay  Table1;
  • 步骤 4 - 将对象标题和对象信息字段添加到表中:
int OnInit()
{
//  创建一个表格
  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);
}

最好是在 OnInit 事件处理程序中完成。首先,利用 TableDisplay::AddFieldObject 方法添加信息字段。然后,再利用 TableDisplay::AddTitleObject 方法向其添加标题。

出于两种原因,上述添加要在单独的周期内实施:首先,标题的数量一般都不会与信息字段的数量相符;第二,如果更新的信息字段于一行中索引,则更易于组织访问(本例是从零到值 NUMBER - 1)。

  • 步骤 5 - 添加代码以更新动态信息:

本例中,通过计时器事件处理程序组织动态信息的更新。该事件的 OnTimer 处理程序应接收给定工具的价格值,并于图表上显示。

文本如下所示:

//---------------------------------------------------------------------
double    rates[NUMBER];
datetime  times[NUMBER];
MqlTick   tick;
//---------------------------------------------------------------------
// OnTimer 事件处理函数
//---------------------------------------------------------------------
void OnTimer()
{
  for(int i=0; i<NUMBER; i++)
  {
//  获得价格数值:
    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);
}

周期开始时,读取指定工具的价格跳动数据,然后,再验证数据的相关性 - 如果价格跳动时间与之前不同,我们则认定数据不相关。此后,我们再分析之前一跳动相关的报价值。

如果当前价格高于前一价格,则我们将该信息字段指定为绿色。如果当前价格小于前一价格,则指定为红色;如果相等,则指定为黄色。周期结束时,存储价格的当前值和价格跳动时间,以供 OnTimer 事件处理程序被调用时进行分析。

一般来讲,更新动态信息的代码要取决于任务。基本上,用户只需要实施这部分代码。假设我们决定向图 2 中价格的右侧添加一个点差,我们来看看如何实现。

需要做的,只是将附加数据字段添加到此表:

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

再把会更新点差值的代码,添加到 OnTimer 事件处理程序中:

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

如此一来,我们就能看到下图:

带点差的价格

图 4. 带点差的价格

注意:点差索引字段从 NUMBER 值开始(如果等于零)。

  • 步骤 6 - 移除已创建的对象:
void OnDeinit(const int _reason)
{
  EventKillTimer();

//  删除显示的元素:
  Table1.Clear();
}

这里是要把计时器和表清空。同时,这些对象占用的内存也都会被释放。

该指标的完整文本,请见本文随附的 PriceList.mq5 文件。附件中包含该指标的一个“改进”版本 - 点差显示。它拥有大量用于图表内标题颜色指定及表格定位的外部参数。

总结

随附的 MarketWatch.mq5 (及内含的 MarketWatch.mqh)中,包含一个一览表形式的、显示交易工具基本参数的指标。每个交易品种的信息,皆如图 2 所示。

此外,它还会显示指定时间间隔内的价格变动百分比。一组的交易品种(不超过 16 种)和时间间隔,被指定为带元素的字符串,且由分号隔开。此指标的运行结果如图 5 所示:

市场回顾指标

图 5. 市场回顾指标

我们讲到了在 MetaTrader 5 客户端图表上显示文本信息的一种方式。

利用客户端提供的标准库类,我们就能相当轻松快速地开发出新的、以二维表形式呈现文本信息的功能。MQL5 语言的面向对象方法非常强大。

本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/179

附加的文件 |
marketwatch_doc.zip (379.28 KB)
marketwatch.mq5 (22.08 KB)
marketwatch.mqh (18.14 KB)
priceinfo.mq5 (16.95 KB)
pricelist.mq5 (14.11 KB)
textdisplay.mqh (29.4 KB)
建立一个频谱分析程序 建立一个频谱分析程序
本文旨在让读者熟悉使用 MQL5 语言图形对象的一种可能变量。它会对一个利用图形对象管理简单频谱分析程序的面板的实施指标进行分析。本文专为熟悉 MQL5 基础的读者编写。
MQL5 向导:无需编程即可创建 EA 交易程序 MQL5 向导:无需编程即可创建 EA 交易程序
您想试试不用浪费时间来编程的交易策略吗?利用 MQL5 向导,您只需要选择交易信号的类型,添加追踪仓位和资金管理模块,您的工作就完成了!创建自己的模块实现,或是通过“任务”服务订购 - 再将您的新模块合并到现有模块。
将指标从 MQL4 迁移到 MQL5 将指标从 MQL4 迁移到 MQL5
本文旨在说明将用 MQL4 编写的价格构建迁移到 MQL5。为了让将指标计算从 MQL4 迁移到 MQL5 的过程更加容易,建议使用 mql4_2_mql5.mqh 函数库。依据 MACD、随机动量指标和 RSI 指标说明其用途。
生长型神经气:MQL5 中的实施 生长型神经气:MQL5 中的实施
本文会举例说明如何开发一个可以实施名为“生长型神经气” (GNG) 自适应聚类算法的 MQL5 程序。本文针对已研究过语言文档、且已具备一定编程能力和神经信息学基础知识的用户。