根据品种和 EA 的 ORDER_MAGIC 分析余额/净值图形·综合运用
📊

根据品种和 EA 的 ORDER_MAGIC 分析余额/净值图形·综合运用

(3/3)· 一个账户跑多个EA却看不出谁在赚谁在亏?本篇用分策略余额/净值图与MFE-MAE分布收尾整套诊断

实战向进阶 第 3/3 篇
同一账户并行多个策略时,总净值在零轴附近晃并不代表每个EA都平庸——只是盈亏互相掩盖。按ORDER_MAGIC拆开画余额和净值曲线,才能看清哪个策略在拖后腿、哪个在悄悄复利。

◍ 用符号与魔术码过滤成交记录

在 MT5 的成交历史遍历里,先按交易品种和 EA 魔术码做双重过滤,能避免把别的品种或手动单误算进策略统计。上面这段代码就是典型的入口筛子:若指定了品种字符串且当前成交不属于该品种,直接 continue 跳过;若指定了非 ULONG_MAX 的魔术码且成交魔术码不匹配,也同样跳过。 这种写法在写持仓监控或盈亏汇总脚本时很实用。比如你只关心黄金 XAUUSD 上魔术码为 888 的网格单,把 sSymbol 设为 "XAUUSD"、uMagic 设为 888,循环里其余成交一律不处理,回测或实盘统计速度都会更干净。 外汇与贵金属杠杆高、滑点跳空频繁,过滤逻辑写错可能把跨品种亏损并进来误导判断,上线前建议在策略测试器用历史成交跑一遍确认条数。

MQL5 / C++
   if(sSymbol!="")
      if(deal_symbol!=sSymbol)
         class="kw">continue;
   if(uMagic!=ULONG_MAX)
      if(deal_magic!=uMagic)
         class="kw">continue;
   class=class="str">"cmt">//--- 仅买入或卖出

「把每笔持仓的极端浮动盈亏记进数组」

MFE(最大盈利)和 MAE(最大亏损)捕捉的是单笔订单从开仓到平仓期间出现过的最佳与最差浮动状态。把它们和该笔订单的最终财务结果放在一起,X 轴放盈亏点数、Y 轴放 MFE 或 MAE 点数,就能画出分布散点图,直观看策略是“拿不住利润”还是“扛不住回撤”。 记账靠两个全局数组:m_arr_pos_id 存持仓 ID,m_arr_mfe_mae 是二维数组,第二维三个槽分别是 [0] MFE、[1] 最终财务结果、[2] MAE。两个数组下标 i 严格一一对应,m_arr_pos_id[i] 永远指向 m_arr_mfe_mae[i] 的那一笔,尺寸在 GetHistory 里统一扩。 入场时新建元素,三个值先清零;持仓在列且浮亏 -20.2 时记浮亏、财务结果 0;浮盈 +5.81 时记浮盈、财务结果 0;浮盈 -3.06 同理。规则只有一条:只要还没平仓,总体财务结果就是 0,浮盈归到 MFE 或 MAE 里。 出场分四种 deal_entry:IN 建仓、OUT 平仓、INOUT 反转、OUT_BY 反向单抵销。OUT 和 OUT_BY 要按手数比对 ArrOpenPositions,量相同就删记录写 [0.0][财务结果],量不同就调剩余仓量;INOUT 反转直接改类型和量。每类收尾都把浮盈置 0、写入总体财务结果到 m_arr_mfe_mae。 对话框要加两块画布:余额/净值线图,以及 MFE、MAE 散点图。重算历史时若在 GetHistory 里刷浮盈,就写 [浮盈][财务结果 0.0] 进数组,别和已平仓的 [0.0][财务结果] 弄混。外汇与贵金属杠杆高,MFE/MAE 只揭示历史分布,不代表未来回撤可控。

MQL5 / C++
class="type">long  m_arr_pos_id[];
class="type">class="kw">double m_arr_mfe_mae[][class="num">3];  class=class="str">"cmt">// [][class="num">0] - mfe, [][class="num">1] - 最终财务结果,[][class="num">2] - mae

         if(deal_symbol=="")
            DebugBreak();
         ArrOpenPositions.Add(HistoryDeal);
         class=class="str">"cmt">//--- mfe, mae
         class="type">int size=ArraySize(m_arr_pos_id);
         ArrayResize(m_arr_pos_id,size+class="num">1,class="num">10);
         ArrayResize(m_arr_mfe_mae,size+class="num">1,class="num">10);
         m_arr_pos_id[size]=deal_position_ID;
         class=class="str">"cmt">// [][class="num">0] - mfe, [][class="num">1] - 最终财务结果,[][class="num">2] - mae
         m_arr_mfe_mae[size][class="num">0]=class="num">0.0;
         m_arr_mfe_mae[size][class="num">1]=class="num">0.0;
         m_arr_mfe_mae[size][class="num">2]=class="num">0.0;
         class="kw">continue;
         }
         class=class="str">"cmt">//--- 
         if(deal_entry==DEAL_ENTRY_OUT)
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 加入 Mfe Mae 结果                                                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void AddResultMfeMae(class="kw">const class="type">long pos_id,class="kw">const class="type">class="kw">double floating_profit,class="kw">const class="type">class="kw">double financial_result)
  {
class=class="str">"cmt">// [][class="num">0] - mfe(盈利), [][class="num">1] - 最终财务结果,[][class="num">2] - mae(亏损)
class=class="str">"cmt">//--- 搜索 pos_id
   class="type">int position=-class="num">1;
   class="type">int size=ArraySize(m_arr_pos_id);
   for(class="type">int i=class="num">0;i<size;i++)
      if(m_arr_pos_id[i]==pos_id)
         {
          position=i;
          class="kw">break;
         }
   if(position==-class="num">1)

用 MFE/MAE 数组抓取浮盈浮亏极值

这段代码负责在持仓生命周期内持续刷新最大有利变动(MFE)与最大不利变动(MAE)。逻辑很直接:浮亏为 0 时直接 return 不做记录;浮盈为正时,若当前 floating_profit 超过已存 MFE(数组索引 0)则更新;浮亏为负时,若比已存 MAE(数组索引 2)更小则更新,索引 1 始终存 financial_result。 下面三行调用给出了具体数值样本:AddResultMfeMae(pos_id,-20.2,0.0) 表示某笔持仓曾浮亏 20.2 点但平仓盈亏为 0;AddResultMfeMae(pos_id,5.81,0.0) 是浮盈 5.81 点未实现离场;AddResultMfeMae(pos_id,0.0,-3.06) 则是无浮盈、实亏 3.06。 在 MT5 里把这套数组接进你自己的持仓管理类,就能复盘每笔单子“曾经走到过哪里”。外汇与贵金属杠杆高,浮盈回吐和放大亏损都很快,MFE/MAE 统计只描述历史分布,不预示下一笔走向。

MQL5 / C++
  class="kw">return;
class=class="str">"cmt">//---
  if(floating_profit==class="num">0.0)
    class="kw">return;
  if(floating_profit>class="num">0.0) class=class="str">"cmt">// profit
    {
      if(m_arr_mfe_mae[position][class="num">0]<floating_profit)
        m_arr_mfe_mae[position][class="num">0]=floating_profit;
    }
  else class=class="str">"cmt">// loss
    {
      if(m_arr_mfe_mae[position][class="num">2]>floating_profit)
        m_arr_mfe_mae[position][class="num">2]=floating_profit;
    }
  m_arr_mfe_mae[position][class="num">1]=financial_result;
}
  AddResultMfeMae(pos_id,-class="num">20.2,class="num">0.0);
  AddResultMfeMae(pos_id,class="num">5.81,class="num">0.0);
  AddResultMfeMae(pos_id,class="num">0.0,-class="num">3.06);

◍ 最后一句大实话

把多个 EA 跑在同一个对冲账户里,靠 ORDER_MAGIC 拆开看每个策略的余额与净值曲线,这套思路在 MT5 上确实能落地。原文附的 Accounting_positions_on_history.mq5 主程序 81.59 KB,配套 HistoryDeal.mqh 仅 6.66 KB,读者可直接下载 MQL5.zip(26.34 KB)在 MT5 里加载验证。 但评论区 Sergei Lebedev 指出的坑得记牢:MT5 的 DEAL_PROFIT 默认不按 MAGIC 隔离,跨周期或多 EA 同品种平仓时,原文里 _balance=m_balance+deal_commission+deal_swap+deal_profit 的求和方式可能算错真实盈亏,尤其涉及非美元基准的跨市场品种。外汇与贵金属本身杠杆高、回撤快,这类拆分统计只帮你看清贡献度,不预示任何盈利。 真要拿去用,先开个模拟账户把默认起始日期改成开户日,避免 EgorKim 遇到的挂起吃 2GB 内存的问题,再逐 Magic 比对曲线。

交给小布盯盘分策略看盘
这些按魔幻数拆净值、算MFE/MAE分布的诊断,小布盯盘的AIGC已内置,打开对应品种页即可看到分EA的贡献拆解,你只管读图决策。

常见问题

库存费随品种多空方向和持仓过夜天数变化,多头与空头在某些品种上会被券商反向收取,所以历史成交里 SWAP 既有正也有负,汇总时直接相加即可。
可以。MFE 代表持仓期间出现过的最大浮盈,MAE 是最大浮盈回撤前的浮亏,把每笔按魔幻数归集后画分布,能看出某EA是否总在小幅盈利就被扫或扛到大亏才平,概率上倾向暴露出场逻辑问题。
能。小布盯盘的品种页支持按魔幻数过滤成交与持仓,自动绘制分策略余额/净值曲线与 MFE-MAE 散点,省去自己写面板联调。
段长越短浮盈采样越密、图形越平滑但计算量更大;实盘诊断中倾向取与策略平均持仓周期匹配的值,分钟级 scalper 用5分钟,日线波段用15分钟以上更省资源。
常见是面板只刷新了余额没重算持仓清单,或过滤条件没下传到 HistoryDeal 类。检查 3.3 的小调整是否把所选魔幻数传入持仓遍历,而非仅用于标题显示。