含 GUI 的 EA 面板开发:从零搭出可交互交易界面(基础篇)(基础篇)
(1/3)· 很多交易者想自动化重复操作却卡在界面开发,本文用标准指标信号 EA 演示如何低成本拼出 GUI 面板
「在 MT5 里给 EA 搭一个可交互面板」
想在 MT5 上做带图形界面的 EA,第一步不是写交易逻辑,而是先把面板画出来。多数新手直接堆按钮和输入框,结果坐标错位、事件漏接,最后界面比命令行还难用。
Anatoli Kazharski 在 2018 年 8 月 6 日发布的示例里,这套带 GUI 的 EA 教程累计被查看 8611 次、收到 15 条讨论,说明手动在图表上点单的需求一直真实存在。外汇与贵金属杠杆高、滑点频繁,界面响应慢半秒都可能错价成交。
核心思路是用 MQL5 的 CAppDialog 派生自己的面板类,把控件当作对象管理,而不是在 OnChartEvent 里写一堆 id==0 的硬编码判断。这样后面加按钮、加 Tab 页都只是扩类,不改主框架。
这套 GUI 到底由哪些零件构成
想在 MT5 里自己搭一套可视化面板,先得弄清底层元件清单。原文给出的目录把整套 GUI 拆成了十几个基础件:从表单、状态条、页面组,到输入栏位、按钮、带下拉的组合框、复选框、表格、标准图表和进度条,基本覆盖了手动交易与监控面板常用的交互控件。 这些元件不是孤立存在的。比如「用于控件的表单」是容器,「页面组」负责切换视图,「状态条」常挂在底部反馈运行状态,而「输入栏位 + 按钮 + 组合框」三者组合就能完成参数录入与触发。 另外目录里单列了 EasyAndFast 开发库的更新项,说明这套元件体系依赖该库迭代。交易者若要在实盘外汇或贵金属 EA 里复用,建议直接对照该库当前版本核对控件接口,避免老代码在 MT5 新 build 下编译失败。外汇与贵金属杠杆高,任何面板逻辑错误都可能放大下单风险,验证前务必在策略测试器跑通。
◍ 为什么给手工交易加一层信号面板
算法交易再热闹,仍有大量交易者坚持手动下单,但重复拉品种、切周期、盯指标这类机械活儿,人工做既费神又容易漏信号。 本文以终端自带的随机振荡指标(Stochastic)为例,演示如何写一个多品种信号 EA,并带图形界面(GUI)。你拿这套代码改一改,就能塞进任意指标,或按自己的计算逻辑触发交易决策。 这个面板顺手解决了几个手工交易的痛点:按属性筛出品种列表、不重新初始化 EA 就能切品种和周期、在界面里直接管图表属性、多品种用颜色块推送指标信号、还能操作已开仓位。 原文分两篇发,本篇只搭面板骨架,下一篇才填功能逻辑。想验证的话,开 MT5 建个 EA 把 Stochastic 信号接到界面上,先跑通多品种颜色提示就够了。
「EA 交互界面的元件分层」
做带 GUI 的 EA,核心价值是让使用者和程序直接对话,并把行情、仓位数据可视化。标准库能画控件,但用 EasyAndFast 这类开发库更省事——你只需盯逻辑,图形渲染交给底层。 先把界面拆成层级:最外层是窗口,底下挂状态栏和页面组。本例规划了两个页,「交易」页放品种过滤输入框、请求构建按钮、买卖按钮、交易量栏、信号水平输入框和品种表格;「仓位」页放持仓表与重放帧指示。 控件数量一多就容易乱,用分级表单列出来最直观:表单管总控,状态栏显概况,页面组分交易与仓位,图表属性再单独用组合框、复选框和输入框管时段、伸缩、缩进和指标开关。 主类 CProgram 里按上面清单声明各元件实例,创建代码拆到独立文件,用 MQL 程序类包含进来。下面这段是类声明的骨架,能直接看出整个 GUI 由哪些对象拼成。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 应用程序开发类 | class=class="str">"cmt">//+------------------------------------------------------------------+ class CProgram : class="kw">public CWndEvents { class="kw">private: class=class="str">"cmt">//--- 窗口 CWindow m_window1; class=class="str">"cmt">//--- 状态条 CStatusBar m_status_bar; class=class="str">"cmt">//--- 页面 CTabs m_tabs1; class=class="str">"cmt">//--- 输入栏位 CTextEdit m_symb_filter; CTextEdit m_lot; CTextEdit m_up_level; CTextEdit m_down_level; CTextEdit m_chart_scale; class=class="str">"cmt">//--- 按钮 CButton m_request; CButton m_chart_shift; CButton m_buy; CButton m_sell; CButton m_close_all; class=class="str">"cmt">//--- 组合框 CComboBox m_timeframes; class=class="str">"cmt">//--- 复选框 CCheckBox m_date_scale; CCheckBox m_price_scale; CCheckBox m_show_indicator; class=class="str">"cmt">//--- 表格 CTable m_table_positions; CTable m_table_symb; class=class="str">"cmt">//--- 标准图表 CStandardChart m_sub_chart1; class=class="str">"cmt">//--- 进度条 CProgressBar m_progress_bar; class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- 创建 GUI class="type">bool CreateGUI(class="type">void); class=class="str">"cmt">//--- class="kw">private: class=class="str">"cmt">//--- 表单 class="type">bool CreateWindow(class="kw">const class="type">class="kw">string text); class=class="str">"cmt">//--- 状态条 class="type">bool CreateStatusBar(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap); class=class="str">"cmt">//--- 页面 class="type">bool CreateTabs1(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap); class=class="str">"cmt">//--- 输入栏位 class="type">bool CreateSymbFilter(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class="type">bool CreateLot(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text);
面板控件的声明接口长这样
在 MT5 自定义面板里,每一类图形元素都对应一个返回 bool 的创建函数,入参统一用 x_gap、y_gap 控制相对锚点的像素偏移,text 传标签文案。 从源码声明看,水平线类有 CreateUpLevel、CreateDownLevel 和 CreateChartScale,按钮类覆盖 CreateRequest、CreateChartShift、CreateBuy、CreateSell、CreateCloseAll,组合框只有 CreateComboBoxTF 一个时段切换器。 复选框组负责坐标显示开关:CreateDateScale、CreatePriceScale、CreateShowIndicator;表格类用 CreatePositionsTable 和 CreateSymbolsTable 把持仓与品种拉成二维网格;子图与进度条则留给 CreateSubChart1 等后续扩展。 把这些函数直接贴进 EA 的 C++ 风格面板类,编译后若返回 false,说明对应控件 ID 冲突或坐标越界,开 MT5 跑一遍就能定位是哪一行的 x_gap 超了图表右边界。
class="type">bool CreateUpLevel(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class="type">bool CreateDownLevel(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class="type">bool CreateChartScale(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class=class="str">"cmt">//--- 按钮 class="type">bool CreateRequest(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class="type">bool CreateChartShift(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class="type">bool CreateBuy(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class="type">bool CreateSell(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class="type">bool CreateCloseAll(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class=class="str">"cmt">//--- 组合框 class="type">bool CreateComboBoxTF(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class=class="str">"cmt">//--- 复选框 class="type">bool CreateDateScale(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class="type">bool CreatePriceScale(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class="type">bool CreateShowIndicator(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); class=class="str">"cmt">//--- 表格 class="type">bool CreatePositionsTable(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap); class="type">bool CreateSymbolsTable(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap); class=class="str">"cmt">//--- 标准图表 class="type">bool CreateSubChart1(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap); class=class="str">"cmt">//--- 进度条
◍ 把进度条封装进可复用头文件
在 MT5 里反复手搓 GUI 控件会很拖累开发节奏,把创建逻辑收进一个独立的 mqh 头文件是更稳的做法。上面这段声明把一个进度条生成函数抽离出来,调用方只需传坐标偏移和文本就能拿到控件对象。 实际落地时,用 #include "CreateGUI.mqh" 把封装好的界面代码挂到主程序,编译后 EA 或脚本就能直接调 CreateProgressBar。外汇与贵金属品种波动大、点差跳变频繁,这类界面只做状态展示,不替代风控逻辑,实盘前务必在策略测试器里跑一遍验证坐标不溢出。 x_gap 和 y_gap 以像素为单位,文本参数决定进度条左侧说明文字;若你的图表缩放比例非 100%,建议先打印实际锚点再固化数值。
class="type">bool CreateProgressBar(class="kw">const class="type">int x_gap,class="kw">const class="type">int y_gap,class="kw">const class="type">class="kw">string text); }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 用于创建控件的代码 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "CreateGUI.mqh" class=class="str">"cmt">//+------------------------------------------------------------------+