请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  量化策略 帖子:3364748 新帖:12

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

K线达人发表于:4 月 17 日 16:17回复(1)

简介

我们任务的主要目标在于:开发一款用于 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 语言的面向对象方法非常强大。

全部回复

0/140

量化课程

    移动端课程