利用标准库类创建您自己的市场报价(基础篇)
「用标准库类搭一个自定义行情面板」
MT5 标准库里已经封装好 CMarketDepth、CSymbolInfo 这类现成类,不想从零写 WinAPI 也能快速拼出一个属于自己视角的“市场报价”窗口。思路是直接借标准库的行情订阅与字段读取能力,把默认报价页替换成按你自己优先级排序的品种列表。 实际工程里,先 #include <Trade\SymbolInfo.mqh> 拿到 CSymbolInfo 实例,再对需要的品种逐个调用 Refresh() 拉最新 tick。官方示例在 2013-12-12 发布,至今累计查看 3218 次、评论 20 条,说明这套标准库用法在老脚本里仍跑得通。 外汇与贵金属杠杆高、滑点随机,自定义面板只是看盘辅助,不预示任何方向;用它发现价差异常也仅代表当时流动性状态,后续走法仍是概率事件。
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 却只返默认值,印证了“基类不实施、子类才落地”的惯例。
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 才能稳定读写,这类操作本身不预示涨跌,只是降低脚本报错概率。
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,就能在图表上看到一行默认文字。外汇和贵金属图表加载自定义对象有运行时报错风险,先在模拟盘验证再上实盘。
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); }