利用标准库类创建您自己的市场报价(基础篇)
📘

利用标准库类创建您自己的市场报价(基础篇)

第 1/3 篇

「用标准库类搭一个自定义行情面板」

MT5 标准库里已经封装好 CMarketDepth、CSymbolInfo 这类现成类,不想从零写 WinAPI 也能快速拼出一个属于自己视角的“市场报价”窗口。思路是直接借标准库的行情订阅与字段读取能力,把默认报价页替换成按你自己优先级排序的品种列表。 实际工程里,先 #include <Trade\SymbolInfo.mqh> 拿到 CSymbolInfo 实例,再对需要的品种逐个调用 Refresh() 拉最新 tick。官方示例在 2013-12-12 发布,至今累计查看 3218 次、评论 20 条,说明这套标准库用法在老脚本里仍跑得通。 外汇与贵金属杠杆高、滑点随机,自定义面板只是看盘辅助,不预示任何方向;用它发现价差异常也仅代表当时流动性状态,后续走法仍是概率事件。

MQL5 / C++
class="macro">#include <Trade\SymbolInfo.mqh>
CSymbolInfo info;
info.Name("XAUUSD");
info.Refresh();
class="type">class="kw">double bid = info.Bid();
class="type">class="kw">double ask = info.Ask();

◍ 把EA状态直接画到图表上

做这套库的核心诉求很直接:在 MT5 图表上动态输出任意文本信息,而且得友好、能扩展。典型场景包括把 EA 的当前参数、某段时间内的运行结果以表格呈现,或者把交易者关注的价格位、指标数值、甚至 EA 的交易日志实时挂在图表上方。 这类信息不是静态贴一次就完事,而是在 EA 或调用该库的指标运行期间持续刷新。也就是说你盯盘时不用切到日志标签页,抬头就能看到关键上下文。 底层不是从零造轮子,而是基于 MetaTrader 5 标准库里现成的一组类来做。我们的工作是对这些类做针对性扩展,让它们能承担‘图表文字层’这个任务。外汇与贵金属品种波动剧烈,这类叠加信息仅作辅助观察,实盘决策仍需自行判断风险。

图形对象类的继承骨架

MQL5 把图表上的图形对象封装成了一套类体系,源码在 Include 和 Include\ChartObjects 两个目录下,直接翻 MT5 安装目录就能看到。 Object.mqh 里定义了 CObject 基类,它是所有图形对象类的老祖宗,只管最通用的对象生命周期和引用。 ChartObject.mqh 里的 CChartObject 从 CObject 派生,把坐标、颜色、可见性这些图形对象共有属性与方法包了进去,后续具体对象类都挂在它下面。 ChartObjectsTxtControls.mqh 则专门装文本类控件:CChartObjectText 打底,往下有 CChartObjectLabel、CChartObjectEdit、CChartObjectButton 三个后代,分别对应标签、可编辑框和按钮。 开 MT5 按 F4 进编辑器,搜这几个 mqh 文件名,就能逐文件看清继承链,比看文档直观。

「CObject 怎么撑起链表和类型识别」

MQL5 标准库里所有可视与不可视对象都从 CObject 派生,但它本身不画一根线、不输出一个像素。基类只放通用字段和方法,真正干活留给子类重写。 它有两个指针字段 m_prev 和 m_next,类型都是 CObject*,用来把对象串成单链或双链表。Prev()/Next() 的读写方法就围着这两个字段转,列表的前后游走全靠它们。 Compare 方法对比两个 CObject* 对象,排序列表时用得上;Save 和 Load 留了文件句柄参数,想把对象数据落盘或回读,就在子类里重载。Type 返回整数类型标识,一份列表混了多种对象时靠它分辨。 下面这段是基类原貌,多数方法标了 virtual 却只返默认值,印证了“基类不实施、子类才落地”的惯例。

MQL5 / C++
class CObject
{
class="kw">protected:
   CObject             *m_prev;
   CObject             *m_next;
class="kw">public:
                     CObject();
   CObject            *Prev()                { class="kw">return(m_prev); }
   class="type">void               Prev(CObject *node)   { m_prev=node;    }
   CObject            *Next()                { class="kw">return(m_next); }
   class="type">void               Next(CObject *node)   { m_next=node;    }
   class="kw">virtual class="type">bool       Save(class="type">int file_handle) { class="kw">return(true);   }
   class="kw">virtual class="type">bool       Load(class="type">int file_handle) { class="kw">return(true);   }
   class="kw">virtual class="type">int        Type() class="kw">const          { class="kw">return(class="num">0);      }
class="kw">protected:
   class="kw">virtual class="type">int        Compare(class="kw">const CObject *node,class="type">int mode=class="num">0) class="kw">const { class="kw">return(class="num">0); }
};
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CObject::CObject()
{
   m_prev=NULL;
   m_next=NULL;
}

◍ 图形对象基类怎么把实例挂到图表

CChartObject 继承自 CObject,是所有 MT5 图形对象的公共基类。它不画具体形状,但把颜色、位置、所属窗口这类通用属性与方法收拢到一起,后代类直接复用即可。 在读写某个真实图形对象之前,必须先调用 Attach 把它和类实例绑定。该方法会先用 ObjectFind 验证对象是否存在,不存在就返回 false;存在则把图表 ID、子窗口号、对象名、锚点数写进内部字段。 基类里已经实现了 Save 和 Load,负责通用属性的存读。后代类重写时务必先调父方法,再处理自己的字段,否则容易丢属性。 下面这段是 Attach 的核心声明与实现,注意 chart_id 传 0 时会被替换成 ChartID(),也就是当前图表。 图表对象的高频增删改都建立在这个绑定动作上,外汇和贵金属行情跳空多,对象锚点失效后要重新 Attach 才能稳定读写,这类操作本身不预示涨跌,只是降低脚本报错概率。

MQL5 / C++
class="kw">protected:
  class="type">long      m_chart_id;    class=class="str">"cmt">// 包含指定图形对象的 
                               class=class="str">"cmt">// 图表编号 (class="num">0 - 当前图表)
  class="type">int       m_window;      class=class="str">"cmt">// 图表子窗口编号 (class="num">0 - 主窗口)
  class="type">class="kw">string    m_name;        class=class="str">"cmt">// 图表上对象的唯一名称
  class="type">int       m_num_points;  class=class="str">"cmt">// 绑定对象的点数
class="type">bool CChartObject::Attach(class="type">long chart_id,class="type">class="kw">string name,class="type">int window,class="type">int points)
{
  if(ObjectFind(chart_id,name)<class="num">0)
  {
    class="kw">return(class="kw">false);
  }
  if(chart_id==class="num">0) chart_id=ChartID();
  m_chart_id  =chart_id;
  m_window    =window;
  m_name      =name;
  m_num_points=points;
  class="kw">return(true);
}

CChartObjectText 怎么管图表上的文字

在 ChartObjectsTxtControls.mqh 里,所有图表文字控件的老祖宗是 CChartObjectText。它挂在 CChartObject 之下,把文本对象特有的角度、字体、字号、锚点这些属性封装成了可读写的接口,而不用每次去调 ObjectSetInteger 那类底层函数。 比起父类,它多出来的硬能力就两条:一是改文本对象的外观参数,二是用 Create 在图上真正生成一个 OBJ_TEXT 对象。Create 内部先跑 ObjectCreate,返回 true 才接 Attach 把句柄绑进类实例,这套顺序错了对象就绑不上。 下面这段代码就是类声明和 Create 实现的原貌,逐行看一下方法签名就能知道能调什么: 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); // 反序列化读取 }; 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 ); // 建OBJ_TEXT if(result) { result &= Attach(chart_id, name, window, 1 ); // 绑定到类实例 } return(result); // 返回最终成败 } 开 MT5 随便建个 EA,include 这个头文件,用 Create 传 chart_id=0、name="test"、window=0、time=TimeCurrent()、price=Bid,就能在图表上看到一行默认文字。外汇和贵金属图表加载自定义对象有运行时报错风险,先在模拟盘验证再上实盘。

MQL5 / C++
class CChartObjectText : class="kw">public CChartObject
{
class="kw">public:
  class="type">class="kw">double            Angle() class="kw">const;
  class="type">bool              Angle(class="type">class="kw">double angle);
  class="type">class="kw">string            Font() class="kw">const;
  class="type">bool              Font(class="type">class="kw">string font);
  class="type">int               FontSize() class="kw">const;
  class="type">bool              FontSize(class="type">int size);
  ENUM_ANCHOR_POINT Anchor() class="kw">const;
  class="type">bool              Anchor(ENUM_ANCHOR_POINT anchor);
  class="type">bool              Create(class="type">long chart_id,class="type">class="kw">string name,class="type">int window,class="type">class="kw">datetime time,class="type">class="kw">double price);
  class="kw">virtual class="type">int       Type() class="kw">const { class="kw">return(OBJ_TEXT); }
  class="kw">virtual class="type">bool      Save(class="type">int file_handle);
  class="kw">virtual class="type">bool      Load(class="type">int file_handle);
};
class="type">bool CChartObjectText::Create(class="type">long chart_id,class="type">class="kw">string name,class="type">int window,class="type">class="kw">datetime time,class="type">class="kw">double price)
{
  class="type">bool result = ObjectCreate( chart_id, name, OBJ_TEXT, window, time, price );
  if(result)
  {
    result &= Attach(chart_id, name, window, class="num">1 );
  }
  class="kw">return(result);
}

常见问题

先用标准库里的图形对象基类把行情文字画到图表上,再套一个链表管理多个品种,比从零写窗口省事很多。
用图表文字对象类在指定坐标写文本即可,把状态字符串实时更新进去,肉眼盯图就能看到EA在干什么。
小布可基于你的品种清单自动生成轻量行情卡片并提示异动,你只需在品种页开启对应开关,不必自己写面板。
基类里留了类型识别的虚方法,子类重写后链表遍历时调一下就能知道具体类型,不用外部记标签。
在对象创建时绑定图表ID并设好持久化参数,EA重跑时先查是否存在再决定是否新建,就不会闪没。