使用 CGraphic 开发库实现一个剥头皮市场深度(基础篇)
「用 CGraphic 画出剥头皮用的市场深度」
想在 MT5 里做高频剥头皮,盘口厚度比一根均线有用得多。原生的市场深度窗口不够灵活,自己用标准库里的 CGraphic 把买一卖一挂单量画成实时柱状图,能直接看出流动性真空带。 CGraphic 在 Include/Graphics/Graphic.mqh 里,挂到独立子窗口即可。下面这段是最小可跑骨架:把 Depth of Market 的累计挂单量按价格档位映射成宽度,剥头皮者重点看价差两侧 3~5 档的陡降位置。 外汇与贵金属剥头皮属高风险行为,盘口可能在毫秒级抽空,任何图形信号都只是概率倾向,不能当作成交保证。
class="macro">#include <Graphics\Graphic.mqh> CGraphic graphic; class="type">int OnInit() { graphic.Create(class="num">0, "DOM_Scalp", class="num">0, class="num">0, class="num">0, class="num">300, class="num">200); graphic.Attach(class="num">0, class="num">1); class="kw">return(INIT_SUCCEEDED); } class="type">void OnTick() { graphic.Clear(); graphic.Histogram(m_symbol.Bid(), m_symbol.Ask()); graphic.Update(); }
◍ 这份资料覆盖了哪些模块
原文给出的目录显示,本系列第 1 篇将沿几条主线展开:先是简介与上个版本发布以来的修改,让读者知道基线在哪;随后进入 CPanel 图形开发库概览,并专门讨论与订单簿同步的分时数据流。 后半部分落到工程实现:CGraphic 基础、使用 CPanel 开发库做 CGraphic 的整合,以及安装与动力学性能市场深度特性的特点比较,最后以结论收口。 对 MT5 交易者而言,这套结构意味着你能在同一篇里拿到「图形库怎么搭」和「盘口深度数据怎么接」两条可验证线索,开 MT5 对照标准库例子即可逐步复现。
从旧深度库到 CGraphic 的现代化跳板
两年前那套围绕市场深度写的开发库,逻辑基础是仓位访问分时历史尚未原生支持。如今 MQL5 已能直接拉到仓位分时历史,MetaQuotes 也放出了 CGraphic 开发库,可以把自定义数据画成复杂统计图形,定位接近 R 语言里的 plot 函数,用法在另一篇专文里拆过。 这些新能力让原来的市场深度方案能大幅翻新。新版本里除了订单簿,还直接带上了最近交易的分时图表,旧版的两个核心模块——管深度的 CMarketBook 类、做渲染的图形面板——代码已被大量重写,修掉不少 bug,图形部分独立成了轻量级的 CPanel 库。 CGraphic 能在独立窗口画线图,表面看只服务统计,实际做剥头皮用的市场深度时一样能派上用场。开 MT5 把 CGraphic 接进深度面板,先验证它画分时图的延迟是否可接受,再决定要不要替掉旧渲染层。
「CMarketBook 实盘踩坑后的几处修正」
文章发出后我在 MT5 实盘里高频调用 CMarketBook,很快撞上几类崩溃:数组越界、订单簿空白或部分填充、切换品种时除零。这些都不是演示环境能暴露的,只有真把盘口类挂到图表上跑才显形。 原版订单簿单元是用几个基础元件类画的,后来给这些类补了功能,顺手抽成独立的 CPanel 开发库,丢在 Include 文件夹。轻量、好复用,做别的面板也能直接抄。 界面上也动了刀:原来开/关深度窗口的小三角换成了大号方块按钮;元件层级重绘逻辑改了,避免重开表格时盖在旧元件上。还加了 X/Y 轴人工偏移设置——标准品种名叠加交易面板时,原按钮常遮住图表活动元件,现在能自己挪位。 CMarketBook 已独立成模块,路径 MQL5\Include\Trade,上面三类报错全部修掉,指标整体稳定性有提升。接下来就基于这版改成一个偏剥头皮用的深度工具。
◍ 用 CPanel 把按钮当标签使
MQL5 里图形元件本质是几个基础图形元素的封装:文本标签、按钮、输入框、长方形标签、位图标签。它们共享大量属性,长方形标签、按钮和输入框配置后视觉上几乎无法区分,所以同一个类能基于不同元素造出外观一致的控件。比如输入框能显示成按钮样子,用户点上去以为按了键,实际触发的是输入框逻辑。 这种替代初看别扭,但每个基础元素仍有独有属性:输入框不能透明,长方形标签可以。CPanel 开发库就利用这点,让高级元件类(都派生自只存元素类型的 CNode)在创建时指定底层图形元素类型,从而用同一套接口产出不同观感的部件。 文本标签没有 frame 属性,想加边框就直接换成按钮类元素——图2无边框表单用标签,图3有边框表单用按钮,视觉效果补上了。实际写 GUI 时用户需求不可预知,最好别锁死某个基础元素,把选择权留出来。 市场深度图形化就是这样搭的:订单簿由多个基于 CElChart 的 CBookCell 组成,CElChart 自身派生于 CNode,提供长高、XY 坐标、宽高、背景边框色、边框类型、文字字体对齐等设置方法,但是否生效由底层元素决定。下面代码在 OnInit 里给两个 CElChart 实例(一个 OBJ_RECTANGLE_LABEL 背景、一个 OBJ_BUTTON 文字)设属性并显示,跑起来你就看到白底黑边面板。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//| MarketBookArticlePanel.mq5 | class=class="str">"cmt">//| Copyright class="num">2017, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2017, MetaQuotes Software Corp." class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class="macro">#include <Panel\ElChart.mqh> CElChart Fon(OBJ_RECTANGLE_LABEL); CElChart Label(OBJ_BUTTON); class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| EA交易初始化函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- Fon.Height(class="num">100); class=class="str">"cmt">// 设背景元件高100像素 Fon.Width(class="num">250); class=class="str">"cmt">// 设背景元件宽250像素 Fon.YCoord(class="num">200); class=class="str">"cmt">// 背景元件图表Y坐标200 Fon.XCoord(class="num">200); class=class="str">"cmt">// 背景元件图表X坐标200 Fon.BackgroundColor(clrWhite); class=class="str">"cmt">// 背景填白色 Fon.BorderType(BORDER_FLAT); class=class="str">"cmt">// 边框平直样式 Fon.BorderColor(clrBlack); class=class="str">"cmt">// 边框黑色 Fon.Show(); class=class="str">"cmt">// 显示背景元件 Label.Text("Meta Quotes 语言"); class=class="str">"cmt">// 按钮元件内写文字 Label.BorderType(BORDER_FLAT); class=class="str">"cmt">// 按钮边框平直 Label.BorderColor(clrBlack); class=class="str">"cmt">// 按钮边框黑色
把按钮挂进矩形面板才显示得出来
上面那段初始化里有个坑:单独建的 Label 如果直接 Label.Show() 但没挂到父容器,图表上大概率看不到它。正确做法是先 Fon.AddElement(Label) 把按钮加进矩形面板对象,再统一 Fon.Show() 一次,整块 UI 才会随父层渲染。 对比两组坐标能看清层级关系:Fon 矩形左上角在 X200/Y200,宽 250 高 100;Label 按钮宽 150,放在 X250/Y240。也就是说按钮左上角相对图表偏移了 50 像素横、40 像素纵,落进白底黑边矩形内部偏右下。 OnTick 和 OnChartEvent 这里都是空壳,说明这个面板只是静态展示「Meta Quotes 语言」字样,不参与报价刷新。要在外汇或贵金属图表上复用,记得 MT5 图形对象受图表重绘节奏影响,挂真信号时得在 tick 或事件里主动 ChartRedraw(),否则可能延迟显示。
CElChart Fon(OBJ_RECTANGLE_LABEL); CElChart *Label; class="type">int OnInit() { Fon.Height(class="num">100); Fon.Width(class="num">250); Fon.YCoord(class="num">200); Fon.XCoord(class="num">200); Fon.BackgroundColor(clrWhite); Fon.BorderType(BORDER_FLAT); Fon.BorderColor(clrBlack); Label = new CElChart(OBJ_BUTTON); Label.Text("Meta Quotes 语言"); Label.BorderType(BORDER_FLAT); Label.BorderColor(clrBlack); Label.Width(class="num">150); Label.YCoord(class="num">240); Label.XCoord(class="num">250); class=class="str">"cmt">//Label.Show(); Fon.AddElement(Label); Fon.Show(); ChartRedraw(); class="kw">return(INIT_SUCCEEDED); } class="type">void OnTick() { } class="type">void OnChartEvent(class="kw">const class="type">int id, class="kw">const class="type">long& lparam, class="kw">const class="type">class="kw">double& dparam)