一张图表上的多个指标(第 06 部分):将 MetaTrader 5 转变为 RAD 系统(II)·综合运用
(3/3)·从只读编辑框到累计盈亏着色,把上两篇的图表 IDE 真正跑通
从成交历史里扒出某品种累计盈亏
想在 MT5 面板实时显示某个符号的累计平仓盈亏,核心是先拉历史成交再按品种过滤累加。下面这段函数用 HistorySelect 框定从当天零点到当前的时间窗,遍历所有成交单,只把 DEAL_SYMBOL 匹配的 DEAL_PROFIT 加进 Accumulated,最后返回总和。 HistorySelect(macroGetDate(TimeLocal()), TimeLocal()); max = HistoryDealsTotal(); for (int c0 = 0; c0 < max; c0++) if ((ticket = HistoryDealGetTicket(c0)) > 0) if (HistoryDealGetString(ticket, DEAL_SYMBOL) == szSymbol) Accumulated += HistoryDealGetDouble(ticket, DEAL_PROFIT); return Accumulated; 逐行看:第一行 HistorySelect 取本地当天 0 点至现在的范围;第二行拿总数;for 循环里先取第 c0 笔成交的 ticket,大于 0 才有效;内层判断符号一致后,把该笔利润累加。回测时注意,若跨天不重选范围,零点后 Accumulated 会漏掉昨单。 外汇和贵金属杠杆高,历史利润只是已平仓结果,不代表后续概率,用它做面板参考就好,别当成仓位依据。
HistorySelect(macroGetDate(TimeLocal()), TimeLocal()); max = HistoryDealsTotal(); for (class="type">int c0 = class="num">0; c0 < max; c0++) if ((ticket = HistoryDealGetTicket(c0)) > class="num">0) if (HistoryDealGetString(ticket, DEAL_SYMBOL) == szSymbol) Accumulated += HistoryDealGetDouble(ticket, DEAL_PROFIT); class="kw">return Accumulated;
◍ 用静态变量累计Roof净值并刷新标签
这段逻辑的核心是把当前品种的已平盈利滚动累加进一个叫 Accumulated 的静态变量,再叠加 dValue 算出 d0,最后写进图表对象的文本与背景色。d0 为正时标签底色取 ForestGreen,为负则取 FireBrick,视觉上能直接区分当天Roof是盈余还是回吐。 UpdateRoof() 里用 memMax 缓存上一次 HistoryDealsTotal() 返回的交割单数。若 memMax == max 直接 return Accumulated,避免每帧重算;只有新成交出现才进循环把 DEAL_PROFIT 累加进 Accumulated。实测在普通外汇品种上,这种静态缓存能把每 tick 的对象刷新开销压到几乎可忽略。 OnTrade() 里调 SubWin.DispatchMessage 把 CHARTEVENT_CHART_CHANGE 和 NanoEA.UpdateRoof() 的返回值推给子窗口,等于每次成交事件触发一次Roof重算与标签更新。想验证就开 MT5 挂上这类 EA,连做几笔 XAUUSD 微单,看子窗口数字是否随平仓实时跳动——外汇与贵金属杠杆高,标签只是辅助,不代表方向判断。
d0 = AccumulatedRoof + dValue; ObjectSetString(Terminal.Get_ID(), m_ArrObject[eROOF_DIARY].szName, OBJPROP_TEXT, DoubleToString(MathAbs(d0), class="num">2)); ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eROOF_DIARY].szName, OBJPROP_BGCOLOR, (d0 >= class="num">0 ? clrForestGreen : clrFireBrick)); }else if (szArg == szMsgIDE[eLABEL_SYMBOL]) { ObjectSetString(Terminal.Get_ID(), m_ArrObject[eLABEL_SYMBOL].szName, OBJPROP_TEXT, Terminal.GetSymbol()); ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eLABEL_SYMBOL].szName, OBJPROP_ALIGN, ALIGN_CENTER); } class="kw">break; case CHARTEVENT_OBJECT_CLICK: class=class="str">"cmt">// .... The rest of the code.... } } class="type">void OnTrade() { SubWin.DispatchMessage(CHARTEVENT_CHART_CHANGE, C_Chart_IDE::szMsgIDE[C_Chart_IDE::eROOF_DIARY], NanoEA.UpdateRoof()); NanoEA.UpdatePosition(); } class="type">class="kw">double UpdateRoof(class="type">void) { class="type">class="kw">ulong ticket; class="type">class="kw">string szSymbol = Terminal.GetSymbol(); class="type">int max; class="kw">static class="type">int memMax = class="num">0; class="kw">static class="type">class="kw">double Accumulated = class="num">0; HistorySelect(macroGetDate(TimeLocal()), TimeLocal()); max = HistoryDealsTotal(); if (memMax == max) class="kw">return Accumulated; else memMax = max; for (class="type">int c0 = class="num">0; c0 < max; c0++) if ((ticket = HistoryDealGetTicket(c0)) > class="num">0) if (HistoryDealGetString(ticket, DEAL_SYMBOL) == szSymbol) Accumulated += HistoryDealGetDouble(ticket, DEAL_PROFIT);
「累计求和的返回收口」
上面这段 MQL5 片段是某个指标或 EA 里累加逻辑的收尾:用 return Accumulated; 把循环里攒下的总和交回调用方。
在 MT5 里直接新建一个脚本,把这段塞进自定义函数末尾,打印返回值,能验证累加是否按预期中断或跑满。外汇与贵金属杠杆高,验证时先用模拟盘,避免实盘误触。
class="kw">return Accumulated;
}别急着下结论
把 RAD 思路落进 MQL5 之后,你能搭出的不再只是脚本,而是一套带 IDE 交互的半自动框架。前文那套函数库已经把界面构建和控件错误率压了下来,EA_1.05.zip(约 3274.9 KB)里就是可跑的参考实现,开 MT5 直接加载就能看事件响应链路。 真正卡住多数人的不是语法,而是把外部库思路接进 MQL5 时的对象生命周期管理——这部分原文没给现成封装,得自己补。外汇与贵金属杠杆高,这类自建界面再顺手也改变不了品种本身的风险敞口,先在模拟盘验证交互逻辑再谈实盘。 剩下的空间交给你的具体策略:同样的控件骨架,接均线过滤还是接订单流,出来的系统完全两样。