开发多币种 EA 交易(第 12 部分):开发自营交易级别风险管理器·综合运用
🛡️

开发多币种 EA 交易(第 12 部分):开发自营交易级别风险管理器·综合运用

(3/3)·从基础余额到每日水平,手把手把自营公司风控模型写进EA最后一块拼图

含代码示例偏理论 第 3/3 篇
回测里压到10%回撤的策略,实盘一启动就可能突破阈值——历史归一化给不了前向保证。把自营公司的每日止损与总止损逻辑固化进EA,才能在未知行情里留条退路。

「策略主循环里的五个关键调用」

在 EA 的 OnTick 收尾阶段,有一串固定顺序的方法调用决定了策略能否正常运转。看懂这段,你就能定位为什么自己的面板不刷新、虚拟仓位不更新。 CAdvisor::Tick() 负责策略信号计算,必须最先跑;随后 m_riskManager.Tick() 处理虚拟持仓的风控逻辑,背景高亮那段就是它。顺序反了,风控可能读到上一根 K 的旧信号。 m_receiver.Correct() 做市场成交量修正,Save() 落盘状态,m_interface.Redraw() 重绘界面。外汇与贵金属波动剧烈,若 Redraw 被跳过,你看到的可能是几分钟前的假报价,实盘高风险。 把这五个调用直接抄进你的 OnTick 末尾做验证,缺哪个 MT5 日志里都不会报错,但功能就是残的。

MQL5 / C++
class=class="str">"cmt">// Start handling in strategies
  CAdvisor::Tick();
class=class="str">"cmt">// Risk manager handles class="kw">virtual positions
  m_riskManager.Tick();
class=class="str">"cmt">// Adjusting market volumes
  m_receiver.Correct();
class=class="str">"cmt">// Save status
  Save();
class=class="str">"cmt">// Render the interface
  m_interface.Redraw();
}

把风控六参数拆进独立EA

验证风险管理器不用改写整套逻辑,只要在 EA 输入区把它的六个参数露出来,再在 OnInit() 里拼好初始化串即可。下面这段代码把日亏上限、总亏上限等都做成了 input,默认日亏上限 200、总亏上限 500,基准余额 10000。 OnInit() 里先调 CMoney 设好固定余额和仓位占比 1.0,随后用 StringFormat 分别生成策略实例串、单策略组串、风控器串。把策略参数单独存进 strategyParams 变量,组串里只嵌这个变量和 scale_,结构比原先揉在一起清晰,改参数时不易误伤别的逻辑。 把文件存为 SimpleVolumesExpertSingle.mq5 后,MT5 里直接挂测就能看风控是否按 200/500 的阈值拦截订单。外汇与贵金属波动剧烈,这类硬阈值只降低极端回撤概率,不保证规避所有穿仓风险。

MQL5 / C++
input group "===  Risk management"
input class="type">bool        rmIsActive_         = true;
input class="type">class="kw">double      rmStartBaseBalance_     = class="num">10000;
input ENUM_RM_CALC_LIMIT
                  rmCalcDailyLossLimit_   = RM_CALC_LIMIT_FIXED;
input class="type">class="kw">double      rmMaxDailyLossLimit_    = class="num">200;
input ENUM_RM_CALC_LIMIT
                  rmCalcOverallLossLimit_ = RM_CALC_LIMIT_FIXED;
input class="type">class="kw">double      rmMaxOverallLossLimit_  = class="num">500;
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                   |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit() {
   CMoney::FixedBalance(fixedBalance_);
   CMoney::DepoPart(class="num">1.0);
class=class="str">"cmt">// Prepare the initialization class="type">class="kw">string for a single strategy instance
   class="type">class="kw">string strategyParams = StringFormat(
                              "class CSimpleVolumesStrategy(\"%s\",%d,%d,%.2f,%.2f,%d,%.2f,%.2f,%d,%d)",
                              Symbol(), Period(),
                              signalPeriod_, signalDeviation_, signaAddlDeviation_,
                              openDistance_, stopLevel_, takeLevel_, ordersExpiration_,
                          maxCountOfOrders_
                          );
class=class="str">"cmt">// Prepare the initialization class="type">class="kw">string for a group with one strategy instance
   class="type">class="kw">string groupParams = StringFormat(
                           "class CVirtualStrategyGroup(\n"
                           "       [\n"
                           "        %s\n"
                           "       ],%f\n"
                           "    )",
                           strategyParams, scale_
                        );
class=class="str">"cmt">// Prepare the initialization class="type">class="kw">string for the risk manager
   class="type">class="kw">string riskManagerParams = StringFormat(
                                 "class CVirtualRiskManager(\n"

◍ 把风控参数拼进虚拟顾问初始化串

这段 MQL5 片段做的是把已构造好的策略组参数与风险管理器参数,拼成一个 CVirtualAdvisor 类的初始化字符串,再据此 NEW 出处理虚拟持仓的 EA 实例。 StringFormat 里第一组 %s 填 groupParams,第二组 %s 填 riskManagerParams,后面 %d,%s,%d 依次对应 magic_(整型魔数)、策略名字符串 "SimpleVolumesSingle"、以及布尔值 true(代表启用单策略组模式)。 前面风控管理器那段格式化串 " %d,%.2f,%d,%.2f,%d,%.2f" 实际塞了 6 个量:rmIsActive_(是否激活)、rmStartBaseBalance_(起始基线余额)、rmCalcDailyLossLimit_ 与 rmMaxDailyLossLimit_(当日亏损计算限与硬上限,均保留两位小数)、rmCalcOverallLossLimit_ 与 rmMaxOverallLossLimit_(总亏损计算限与硬上限)。 PrintFormat 会把最终 expertParams 原样打印到日志,开 MT5 跑一下就能在专家日志里看到完整嵌套文本,用来核对参数有没有串位。外汇与贵金属品种波动大,虚拟风控的限值若设错,实盘切换后可能放大回撤风险。

MQL5 / C++
              "               %d,%.2f,%d,%.2f,%d,%.2f"
              "          )",
              rmIsActive_, rmStartBaseBalance_,
              rmCalcDailyLossLimit_, rmMaxDailyLossLimit_,
              rmCalcOverallLossLimit_, rmMaxOverallLossLimit_
             );
class=class="str">"cmt">// Prepare the initialization class="type">class="kw">string for an EA with a group of a single strategy and the risk manager
   class="type">class="kw">string expertParams = StringFormat(
               "class CVirtualAdvisor(\n"
               "      %s,\n"
               "      %s,\n"
               "      %d,%s,%d\n"
               ")",
               groupParams,
               riskManagerParams,
               magic_, "SimpleVolumesSingle", true
              );
   PrintFormat(__FUNCTION__" | Expert Params:\n%s", expertParams);
class=class="str">"cmt">// Create an EA handling class="kw">virtual positions
   expert = NEW(expertParams);
   if(!expert) class="kw">return INIT_FAILED;
   class="kw">return(INIT_SUCCEEDED);
}

「用模型策略实跑验证风控开关」

拿前几轮优化出来的模型策略参数直接跑单趟测试,先在 2021–2022 年关掉风险管理器。结果资金曲线出现多次明显回撤,最大的是 2021 年 10 月底约 380 美元、2022 年 6 月约 840 美元。 打开风险管理器,设每日最大亏损 150 美元、总亏损 450 美元。2021 年 10 月它两次平掉亏损市价仓,但虚拟仓没平,第二天市价仓重开在不利价位,总回撤反而略高于不用风控时的净值回撤,且没吃到原该有的微利反而亏了。2022 年 6 月触发七次日亏限额,同样低价重开造成连锁损失。 不过这里有个细节:总亏损按基础余额算,基准 10000 减 450 即 9550 美元才触发。因前期利润垫着,资金没破 9550,EA 继续开仓。把 scale_ 提到 50 后,2022 年 6 月资金跌破 9550,交易直接停摆,之后不再开仓——两个限制工具都按设计工作了。 把风控接到自营规则外也成立。优化时把总损设为日亏的 10%,一年标准化利润从 1560 美元增至 2276 美元,接近一倍半。最佳通行里 scale_=88、限额 7.6% 与 10%,全程未触总损,EA 持续交易。单实例看意义不大,但多实例 EA 逻辑一致,风控模块倾向确有实用价值。外汇与贵金属品种波动剧烈,回测结论仅代表历史样本,实盘仍属高风险。

管理器能落地但别急着上实盘

这套基础交易风险管理器已经能守住两个硬指标:每日最大亏损与总亏损上限。核心判定就一行——当 m_dailyProfit 低于负的 DailyLoss() 且当前仓位占用保证金大于 0 时,禁止继续开仓。 它目前有个致命短板:EA 重启后状态不保留,所以千万别直接丢进真实账户。外汇和贵金属杠杆高、跳空频繁,重启丢状态可能让限额形同虚设。 后续可补的料不少:按交易时段禁开(比如重要数据发布前后)、亏损过半时仓位砍半、只在回撤破线后才恢复手数。这些改起来都不算难,作者说留到后面篇章。 代码层看,m_dailyProfit 每个 tick 用净值减日初基准重算,逻辑透明。想验证就开 MT5 把 VirtualRiskManager.mqh 挂上,跑模拟盘看每日熔断是否准时触发。

MQL5 / C++
if(m_dailyProfit < -DailyLoss() && CMoney::DepoPart() > class="num">0) { ... }
m_dailyProfit = m_equity - m_baseDailyLevel;
让小布替你跑这套诊断
这些自营级风控阈值与小布盯盘的AIGC已内置,打开对应品种页即可看到实时回撤与暂停交易提示,把重复劳动交给小布,你专注决策。

常见问题

基础余额用固定初始值如10000,每日基础资金在D1新柱触发时读取账户余额与资金最大值并缓存,两者不可混用。
自营交易公司通用模型仅要求日损与总损,为避免首次实现过度复杂化暂略,后续可按同思路扩展。
小布已内置类似自营级回撤监控,可对照本文参数在品种页设置日损百分比与总损上限,无需自写EA也能收到暂停提醒。
账户规模固定时前者直观,资金增长后后者能随基础余额动态缩放,实盘倾向用百分比以降低人工调整频率。
首版采用简单模型直接市价全平,进阶可改为梯度减仓,但需额外处理滑点与订单拒绝,外汇贵金属高风险下先保不破线。