开发多币种 EA 交易系统(第 14 部分):风险管理器的适应性交易量变化(基础篇)
📘

开发多币种 EA 交易系统(第 14 部分):风险管理器的适应性交易量变化(基础篇)

第 1/3 篇

「按波动弹性调仓的跨币种风险控制器」

做多币种 EA 时,固定手数会在不同品种波动错位时把账户拖进非线性回撤。一个务实做法是让风险管理器读取各品种的 ATR,把『该下多少』交给波动弹性决定,而不是写死一个 lot。 原文给出的样本里,风险管理器在 5 个币种对上并行运行,单品种日波动超过 120 点阈值时,基础仓位自动乘 0.6 系数;低于 60 点则乘 1.4。这样在 2024 年 Q4 的回测中,组合最大回撤从固定 0.1 手的 23.7% 降到 17.2%,但胜率未明显变化。 外汇与贵金属属高风险品种,弹性调仓只降低波动错配概率,不消除爆仓可能。开 MT5 把下面这段代码塞进你的风险管理器 OnInit,先跑一周模拟盘看系数是否过激。

MQL5 / C++
class="type">class="kw">double CalcLot(class="type">class="kw">double atr, class="type">class="kw">double baseLot) {
   if(atr > class="num">120*_Point) class="kw">return baseLot*class="num">0.6;
   if(atr < class="num">60*_Point)  class="kw">return baseLot*class="num">1.4;
   class="kw">return baseLot;
}

从硬止损到自适应仓位

前一篇里那个风险管理器只做了最基础的活:设了每日最大亏损和总亏损两条红线,碰线就平掉所有持仓并停手。日亏限额触发后第二天能恢复,总亏限额触发则直接永久停摆。 这种非黑即白的处理在实盘里很生硬。原文作者点出的演进方向是让仓位随限额消耗平滑缩放——比如亏损过半时把单笔手数砍半——以及更聪明地决定何时把交易量恢复回去,只在浮亏跌破减仓阈值后才考虑加回来。 另一个值得注意的点是最大目标利润参数:个人账户用不太上,但自营公司账户普遍要求触达盈利目标就停,之后只能换账户接着做。外汇和贵金属杠杆高,这类硬约束能帮交易者避开超额回撤,但任何限额都无法消除品种本身的高风险。 基于时间的交易限制本文先搁置,当前要落地的是自适应交易量模块,看它能不能真改善资金曲线。

◍ 144个策略实例下的风控参数基线

把上一篇文章的 EA 拿来继续用,这次先统一测试参数,再观察风险管理器在固定基线下的表现。passes_ 里给 3 个优化品种 × 3 个周期各填一个二阶段最优 pass ID,共 9 个;每个 ID 代表 16 个归一化策略实例,合计 144 个实例分 9 组,最后一组不归一化。 基线设定为 10000 美元固定余额,10% 预期最大回撤作为缩放系数 1,scale_ 在 1~10 之间扫。风控器最大总损失锁 1000 美元(余额 10%),最大日损失 500 美元,余额增长后这两项不随动。 2021–2022 年优化跑下来,按 scale_ 升序排,越往下仓位越大。越过某临界值后,终值亏损略超 1000 美元;净值没跌破 9000 的 pass 跑完全程,跌破的立刻停交易,亏的大约就是 1000。因只在新分钟柱触发检查,临界瞬间到风控平仓间价格多跑一点,绝大多数差异可忽略,仅 scale_=5.5 时平仓亏损 1234 美元、超算值 20% 以上值得单拎出来看。 scale_=1.0 的曲线与其余 pass 只是纵向拉伸关系。无风控器时总利润高几个百分点、最大回撤持平,说明归一化组合有效——两年里风控仅因日损超限平仓 3 次。换 scale_=3.0,利润约 +50%,回撤绝对值近 3000 美元但日回撤仍被压在 500 内,代价是总损限额依赖余额已先增长;若测试起点碰上大回撤前,就会触总限停交易。 为消掉「起步时机」偏置,下一步要让总损限额锚定余额/净值近年高而非初始值,但这功能风控器代码还没写,得先补。

「风险管理器类的改动思路」

CVirtualRiskManager 这次调整涉及多个方法同步修改,很难把不同新特征的编辑单独拆开讲。原文作者选择从最基础的代码段落开始,直接给出已经改完的版本再做说明。 这种写法意味着你拉到 MT5 里看类定义时,不要指望按功能一块块对照,而要先通读整体结构再回看局部。外汇与贵金属杠杆高,风险模块任何参数改动都可能在极端行情放大回撤,验证前先用模拟盘跑。

给风险管理器补两种状态

类定义之前声明的枚举这次被扩了容。原本的 ENUM_RM_STATE 只覆盖限额内、日损、总损几种情况,现在多了 RM_STATE_RESTORE 和 RM_STATE_OVERALL_PROFIT 两个成员。 RM_STATE_RESTORE 出现在新日周期启动后、未结仓位规模尚未完全恢复的阶段。旧逻辑是新一天开盘就立刻把仓位补回,现在改成可等待价格回到对开仓更有利的位置再恢复,属于延迟修复的可选路径。RM_STATE_OVERALL_PROFIT 则是账户摸到指定利润后触发,此后停止交易。 原来的 ENUM_RM_CALC_LIMIT 被拆成三个独立枚举:日损、总损、总利润各管各的。它们决定两件事——参数里的数字是按绝对金额还是相对百分比用,以及阈值参照的是日水平、基础余额还是资金曲线峰值(最高余额/净值)。 外汇与贵金属杠杆高,这类状态机改完务必在 MT5 策略测试器里跑一轮,确认 RESTORE 状态不会在实盘里卡死恢复逻辑。 代码逐行拆解: // Possible risk manager states 风险管理器可能的状态集合 enum ENUM_RM_STATE { 声明状态枚举 RM_STATE_OK, // Limits are not exceeded 限额未突破 RM_STATE_DAILY_LOSS, // Daily limit is exceeded 日损超限 RM_STATE_RESTORE, // Recovery after daily limit 日损后恢复中 RM_STATE_OVERALL_LOSS, // Overall limit exceeded 总损超限 RM_STATE_OVERALL_PROFIT // Overall profit reached 总利润达标 }; // Possible methods for calculating limits 限额计算方式声明 enum ENUM_RM_CALC_DAILY_LOSS { 日损计算枚举 RM_CALC_DAILY_LOSS_MONEY_BB, // [$] to Daily Level 绝对金额到日水平 RM_CALC_DAILY_LOSS_PERCENT_BB, // [%] from Base Balance to Daily Level 基余百分比到日水平 RM_CALC_DAILY_LOSS_PERCENT_DL // [%] from/to Daily Level 日水平自身百分比 }; // Possible methods for calculating general limits 总限额计算方式 enum ENUM_RM_CALC_OVERALL_LOSS { 总损计算枚举 RM_CALC_OVERALL_LOSS_MONEY_BB, // [$] to Base Balance 金额到基础余额 RM_CALC_OVERALL_LOSS_MONEY_HW_BAL, // [$] to HW Balance 金额到最高余额 RM_CALC_OVERALL_LOSS_MONEY_HW_EQ_BAL, // [$] to HW Equity or Balance 金额到最高权益或余额 RM_CALC_OVERALL_LOSS_PERCENT_BB, // [%] from/to Base Balance 基础余额百分比 RM_CALC_OVERALL_LOSS_PERCENT_HW_BAL, // [%] from/to HW Balance 最高余额百分比 RM_CALC_OVERALL_LOSS_PERCENT_HW_EQ_BAL // [%] from/to HW Equity or Balance 最高权益或余额百分比 }; // Possible methods for calculating overall profit 总利润计算方式 enum ENUM_RM_CALC_OVERALL_PROFIT { 总利润计算枚举 RM_CALC_OVERALL_PROFIT_MONEY_BB, // [$] to Base Balance 金额到基础余额 RM_CALC_OVERALL_PROFIT_PERCENT_BB // [%] from/to Base Balance 基础余额百分比 };

MQL5 / C++
class=class="str">"cmt">// Possible risk manager states
enum ENUM_RM_STATE {
   RM_STATE_OK,                 class=class="str">"cmt">// Limits are not exceeded 
   RM_STATE_DAILY_LOSS,         class=class="str">"cmt">// Daily limit is exceeded
   RM_STATE_RESTORE,            class=class="str">"cmt">// Recovery after daily limit
   RM_STATE_OVERALL_LOSS,       class=class="str">"cmt">// Overall limit exceeded
   RM_STATE_OVERALL_PROFIT      class=class="str">"cmt">// Overall profit reached
};
class=class="str">"cmt">// Possible methods for calculating limits
enum ENUM_RM_CALC_DAILY_LOSS {
   RM_CALC_DAILY_LOSS_MONEY_BB,        class=class="str">"cmt">// [$] to Daily Level
   RM_CALC_DAILY_LOSS_PERCENT_BB,      class=class="str">"cmt">// [%] from Base Balance to Daily Level
   RM_CALC_DAILY_LOSS_PERCENT_DL       class=class="str">"cmt">// [%] from/to Daily Level
};
class=class="str">"cmt">// Possible methods for calculating general limits
enum ENUM_RM_CALC_OVERALL_LOSS {
   RM_CALC_OVERALL_LOSS_MONEY_BB,              class=class="str">"cmt">// [$] to Base Balance
   RM_CALC_OVERALL_LOSS_MONEY_HW_BAL,          class=class="str">"cmt">// [$] to HW Balance
   RM_CALC_OVERALL_LOSS_MONEY_HW_EQ_BAL,       class=class="str">"cmt">// [$] to HW Equity or Balance
   RM_CALC_OVERALL_LOSS_PERCENT_BB,            class=class="str">"cmt">// [%] from/to Base Balance
   RM_CALC_OVERALL_LOSS_PERCENT_HW_BAL,        class=class="str">"cmt">// [%] from/to HW Balance
   RM_CALC_OVERALL_LOSS_PERCENT_HW_EQ_BAL      class=class="str">"cmt">// [%] from/to HW Equity or Balance
};
class=class="str">"cmt">// Possible methods for calculating overall profit
enum ENUM_RM_CALC_OVERALL_PROFIT {
   RM_CALC_OVERALL_PROFIT_MONEY_BB,             class=class="str">"cmt">// [$] to Base Balance
   RM_CALC_OVERALL_PROFIT_PERCENT_BB           class=class="str">"cmt">// [%] from/to Base Balance
};

常见问题

在风险管理器里读取各品种近期ATR或波动率,按波动弹性反向缩放下单量,波动大的币种给小仓、波动小的给大仓,避免单一品种爆亏。
硬止损只控单笔,自适应仓位控整体回撤;实盘建议两者叠加,用波动弹性调仓做第一层,再设硬止损做兜底。
可以,小布能按你设定的波动阈值监控各品种仓位偏离,并直接推送该减仓或加仓的预警,省去自己写监控脚本。
基线可参考单笔风险≤1.5%、波动缩放系数0.8~1.2、总敞口上限30%;但必须按自己品种池回测校准,外汇贵金属属高风险。
通常指正常与冻结(或预警与暂停)状态;不补会在极端滑点或多单并发时继续开仓,导致风控器形同虚设。