向指标或者EA中快速添加控制面板·综合运用
(3/3)· 从指标检测到图形面板联动,手把手把免重启调参真正跑通在实盘程序里
参数回读:对话框怎么把控件值吐给EA
在 MT5 的面板类里,Initialization 负责把外部传入的 Lots、TakeProfit、MACDOpenLevel 等 9 个参数写进成员变量;末尾三行 mMACDOpenLevel=MACDOpenLevel; mMACDCloseLevel=MACDCloseLevel; mMATrendPeriod=MATrendPeriod; 就是典型落库动作,return(true) 表示初始化成功。 真正让 EA 后续能读到用户改过的值,靠的是 GetValues 这套引用传参。它把 mMail、mLots、mMACDOpenLevel 等成员逐一赋给入参引用,调用方拿到的是实时内存值,不是初始化时的快照。 控件文本回写也有坑:m_edit1.Text("Edit1") 失败会直接中断流程;而手数显示用 DoubleToString(mLots,2) 固定保留两位小数,意味着 0.1 手会显示成 '0.10'。开 MT5 把这段塞进你的 CControlsDialog,改个 Lots 看编辑框是否同步,就能验证回读链路通没通。外汇贵金属面板参数误读可能引发异常下单,属高风险操作。
mMACDOpenLevel=MACDOpenLevel; mMACDCloseLevel=MACDCloseLevel; mMATrendPeriod=MATrendPeriod; class=class="str">"cmt">//--- class="kw">return(true); } class="type">int CControlsDialog::GetCheck(class="kw">const class="type">int idx) if(!m_edit1.Text("Edit1")) if(!m_edit1.Text(DoubleToString(mLots,class="num">2))) class="kw">virtual class="type">bool Initialization(class="kw">const class="type">bool Mail,class="kw">const class="type">bool Push,class="kw">const class="type">bool Alert_, class="kw">const class="type">class="kw">double Lots,class="kw">const class="type">int TakeProfit, class="kw">const class="type">int TrailingStop,class="kw">const class="type">int MACDOpenLevel, class="kw">const class="type">int MACDCloseLevel,class="kw">const class="type">int MATrendPeriod); class=class="str">"cmt">//--- 获取值 class="kw">virtual class="type">void GetValues(class="type">bool &Mail,class="type">bool &Push,class="type">bool &Alert_, class="type">class="kw">double &Lots,class="type">int &TakeProfit, class="type">int &TrailingStop,class="type">int &MACDOpenLevel, class="type">int &MACDCloseLevel,class="type">int &MATrendPeriod); class="kw">protected: class=class="str">"cmt">//--- 创建独立控件 class="type">bool CreateCheckGroup(class="type">void); class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 获取值 class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CControlsDialog::GetValues(class="type">bool &Mail,class="type">bool &Push,class="type">bool &Alert_, class="type">class="kw">double &Lots,class="type">int &TakeProfit, class="type">int &TrailingStop,class="type">int &MACDOpenLevel, class="type">int &MACDCloseLevel,class="type">int &MATrendPeriod) { Mail=mMail; Push=mPush; Alert_=mAlert_; Lots=mLots; TakeProfit=mTakeProfit; TrailingStop=mTrailingStop; MACDOpenLevel=mMACDOpenLevel; MACDCloseLevel=mMACDCloseLevel; MATrendPeriod=mMATrendPeriod; }
「把勾选状态变成邮件推送和弹窗」
在 MT5 的自定义面板类里,通知发送不是直接写死,而是靠复选框索引驱动。CControlsDialog::Notifications 这个函数就是入口:先拿 m_check_group.ControlsTotal() 得到组里控件数,再按索引 0、1、2 分别判断要不要发邮件、推手机通知、弹终端 Alert。
class="type">void CControlsDialog::Notifications(class="kw">const class="type">class="kw">string text) { class="type">int i=m_check_group.ControlsTotal(); if(GetCheck(class="num">0)) SendMail(" ",text); if(GetCheck(class="num">1)) SendNotification(text); if(GetCheck(class="num">2)) Alert(text); }
class="type">void CControlsDialog::Notifications(class="kw">const class="type">class="kw">string text) { class="type">int i=m_check_group.ControlsTotal(); if(GetCheck(class="num">0)) SendMail(" ",text); if(GetCheck(class="num">1)) SendNotification(text); if(GetCheck(class="num">2)) Alert(text); }
◍ 面板改动如何触发EA重算
这段逻辑来自一个 MACD 样条 EA 的参数面板响应函数。每当交易者在对话框里改了手数、止盈、追踪止损、MACD 开仓/平仓阈值或均线趋势周期,程序就把对应编辑框文本转成数值,并与内存里的旧值比对;不一致就覆盖变量并把 mModification 置真,后续 tick 才会按新参数重算信号。 具体看几个关键比对:m_edit1 控制 Lots,m_edit2 管 TakeProfit,m_edit3 管 TrailingStop,m_edit4/m_edit5 分别是 MACDOpenLevel 与 MACDCloseLevel,m_edit6 对应 MATrendPeriod。全部用 StringToInteger(StringToDouble(...)) 做强制转换,意味着编辑框里填 "1.2" 也会被截成整型 1,外汇与贵金属品种上设小数手数会直接失效,属于高风险下的隐性坑。 初始化阶段还有两个硬参数:ExtTimeOut=10 表示两次交易操作之间至少隔 10 秒;bool_tester 默认 false,若 MQLInfoInteger(MQL_TESTER) 返回假才走实盘分支,并创建 360x380 的 Notification 对话框。你在 MT5 里把这段挂上 EURUSD 回测,改面板数值后若信号没变,先查 mModification 有没有被置位。
if(StringToInteger(m_edit2.Text())!=mTakeProfit) { mTakeProfit=(class="type">int)StringToDouble(m_edit2.Text()); mModification=true; } if(StringToInteger(m_edit3.Text())!=mTrailingStop) { mTrailingStop=(class="type">int)StringToDouble(m_edit3.Text()); mModification=true; } if(StringToInteger(m_edit4.Text())!=mMACDOpenLevel) { mMACDOpenLevel=(class="type">int)StringToDouble(m_edit4.Text()); mModification=true; } if(StringToInteger(m_edit5.Text())!=mMACDCloseLevel) { mMACDCloseLevel=(class="type">int)StringToDouble(m_edit5.Text()); mModification=true; } if(StringToInteger(m_edit6.Text())!=mMATrendPeriod) { mMATrendPeriod=(class="type">int)StringToDouble(m_edit6.Text()); mModification=true; } class="type">int ExtTimeOut=class="num">10; class=class="str">"cmt">// 交易操作之间的间隔时间(秒) class="type">bool bool_tester=class="kw">false; class=class="str">"cmt">// true - 测试器模式 if(!MQLInfoInteger(MQL_TESTER)) { bool_tester=class="kw">false; ExtDialog.Initialization(ExtMail,ExtPush,ExtAlert, ExtLots,ExtTakeProfit,ExtTrailingStop, ExtMACDOpenLevel,ExtMACDCloseLevel,ExtMATrendPeriod); if(!ExtDialog.Create(class="num">0,"Notification",class="num">0,class="num">100,class="num">100,class="num">360,class="num">380)) class="kw">return(INIT_FAILED); }
面板改参后如何热重载EA逻辑
在MT5里给EA挂一个交互面板,最怕的是改了手数、止盈或MACD阈值后策略不生效,只能重启终端。上面的片段给出了一种不重启就能热重载的做法:图表事件触发后先问面板「参数变没变」,变了就拉新值并重新初始化。
核心判断在 ExtDialog.Modification()。它返回true代表用户在面板上动过输入项;此时用 GetValues() 把邮件开关、手数、止盈、 trailing stop、MACD开平电平、均线趋势周期一次性读回。随后调 ExtExpert.Init() 重建内部状态,成功才把 Modification 标记复位并打印新参数,失败则打印 Parameter change error。
实盘里这套机制的价值是:你可以在欧美盘切换时把 ExtLots 从0.1调到0.3、把 ExtMATrendPeriod 从12改成18,EA下一 tick 就按新参数跑,不用断开持仓。外汇与贵金属杠杆高,参数热改若没做 Init 校验,可能出现旧仓位和新逻辑错位,建议先在策略测试器里用历史数据验证 Modification 分支。
让小布替你跑这套
把上面代码段直接贴进你的EA的 OnChartEvent,配合一个 CDialog 派生面板,就能在MT5里手动拖参不重启。重点盯 Print 那行输出,确认 Lots 和 MATrendPeriod 真的随面板变动。
class=class="str">"cmt">//--- 运行程序 if(!ExtDialog.Run()) class="kw">return(INIT_FAILED); } else bool_tester=true; class=class="str">"cmt">//--- 成功 class="kw">return(INIT_SUCCEEDED); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| ChartEvent函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ 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, class="kw">const class="type">class="kw">string &sparam) { ExtDialog.ChartEvent(id,lparam,dparam,sparam); class=class="str">"cmt">// 查询面板中的bool变量,参数是否已经改变 class=class="str">"cmt">// 如果是,查询面板参数并调用 class=class="str">"cmt">// CSampleExpert::Init(class="type">void) if(ExtDialog.Modification()) { ExtDialog.GetValues(ExtMail,ExtPush,ExtAlert, ExtLots,ExtTakeProfit,ExtTrailingStop, ExtMACDOpenLevel,ExtMACDCloseLevel,ExtMATrendPeriod); if(ExtExpert.Init()) { ExtDialog.Modification(class="kw">false); Print("Parameters changed, ",ExtLots,", ",ExtTakeProfit,", ",ExtTrailingStop,", ", ExtMACDOpenLevel,", ",ExtMACDCloseLevel,", ",ExtMATrendPeriod); } else { ExtDialog.Modification(class="kw">false); Print("Parameter change error"); } } }
「记住这一条就够了」
把面板塞进指标只是体力活:面板类里把尺寸、坐标和事件响应都封装好,指标里挂一个 OnChartEvent() 就能跑。真正卡人的是 EA 与面板之间的通信——如果面板从第一行起就没预留集成接口,后期接 EA 基本要重写。 文末给的七个文件就是活样板:NewBarOriginal.mq5 到 NewBar.mq5 是指标改造对照,PanelDialog 系列是面板从裸写到可通信的演进,MACD Sample.mq5 则是接好面板后的 EA 成品。下载包里 newbar.mq5 占 3.24 KB、paneldialog2.mqh 有 28.48 KB,直接拖进 MT5 的 MQL5 目录就能编译验证。 下面这段改色代码演示了“先 undef 再 define 再 include”的顺序铁律——顺序错了标准库颜色就覆盖不上去。 外汇与贵金属挂 EA 面板属于高风险操作,回测通过不代表实盘不滑点爆仓,通信逻辑建议先在策略测试器跑满一周 tick 再上真仓。
class=class="str">"cmt">// BEFORE connecting Dialog.mqh! class="macro">#include <Controls\Defines.mqh> class=class="str">"cmt">//--- 忘记旧颜色 class="macro">#undef CONTROLS_DIALOG_COLOR_BORDER_LIGHT class="macro">#undef CONTROLS_DIALOG_COLOR_BORDER_DARK class="macro">#undef CONTROLS_DIALOG_COLOR_BG class="macro">#undef CONTROLS_DIALOG_COLOR_CAPTION_TEXT class="macro">#undef CONTROLS_DIALOG_COLOR_CLIENT_BG class="macro">#undef CONTROLS_DIALOG_COLOR_CLIENT_BORDER class=class="str">"cmt">//--- 设置新颜色 class="macro">#define CONTROLS_DIALOG_COLOR_BORDER_LIGHT clrWhite class=class="str">"cmt">// 对话框边框颜色(外部) class="macro">#define CONTROLS_DIALOG_COLOR_BORDER_DARK C&class="macro">#x27;0xB6,0xB6,0xB6&class="macro">#x27; class=class="str">"cmt">// 对话框边框颜色(内部) class="macro">#define CONTROLS_DIALOG_COLOR_BG clrLightGreen class=class="str">"cmt">// 对话框背景(标题下方和客户端区域周围) class="macro">#define CONTROLS_DIALOG_COLOR_CAPTION_TEXT C&class="macro">#x27;0x28,0x29,0x3B&class="macro">#x27; class=class="str">"cmt">// 对话框标题文字颜色 class="macro">#define CONTROLS_DIALOG_COLOR_CLIENT_BG clrAliceBlue class=class="str">"cmt">// 客户区域的背景颜色 class="macro">#define CONTROLS_DIALOG_COLOR_CLIENT_BORDER C&class="macro">#x27;0xC8,0xC8,0xC8&class="macro">#x27; class=class="str">"cmt">// 客户区域的颜色 class=class="str">"cmt">// 现在连接 class="macro">#include <Controls\Dialog.mqh>