搞了三个晚上,总算把EA里那套仓位计算的逻辑捋顺了。之前写马丁格尔策略的时候,回测曲线漂亮得像教科书,结果丢到demo跑了两周就爆仓,问题全出在仓位管理模块上——不是算错手数就是风控触发条件写死,今天把踩过的坑和对比方案整理出来,给还在折腾的朋友省点时间。
先说最常见的固定手数方案,代码就一行 `OrderSend(Symbol(), OP_BUY, 0.1, ...)`,优点是逻辑简单,回测参数好调,但缺点也很致命:账户净值从1万跌到5千时,0.1手对应的风险敞口直接翻倍,遇到欧美那种单日150点波动,浮亏能让你心态先崩。我后来改成固定分数法,也就是每次用净值的2%去算手数,公式是 `RiskAmount = AccountBalance() * 0.02`,再除以止损点数乘每点价值。这里有个坑,止损距离必须用OrderSend之前动态计算,不能写死,否则行情波动一变,实际风险敞口就偏离预设值了。
但固定分数法也有问题,它假设账户余额是连续变化的,可MT4的OrderSend是逐单执行,如果EA同时开了多单,比如欧美和镑美各一单,每单都按当前余额算2%,实际总风险就是4%了。我试过用`AccountEquity()`代替`AccountBalance()`,但回撤时净值波动太剧烈,导致手数忽大忽小,反而放大风险。后来查了论坛里汇友分享的经验,改成在EA的`init()`里设一个全局变量记录初始余额,然后每单计算时用 `(初始余额 - 当前浮亏) * 0.02`,这样至少能控制组合层面的总风险。
再说说更进阶的凯利公式变体,我见过有人直接用 `f = (bp - q) / b` 算最优仓位,但外汇市场的胜率和盈亏比是动态的,用历史回测参数去套未来行情,基本就是过拟合。我试过把盈亏比设成1.5,胜率按最近50单滚动统计,算出来的手数经常超过0.5手,点差和滑点一吃,实际收益还不如0.2手稳。所以我的建议是,凯利公式最多用来做仓位上限,实际下单手数要再乘个0.3的衰减系数,别真按理论值梭哈。
最后对比一下三种方案的实测数据,我用EURUSD M15跑了2023年整年回测,初始资金1万美金,固定手数0.1手年化收益8.2%,最大回撤14%;固定分数法2%风险年化12.6%,回撤9.8%;凯利衰减版年化15.1%,但回撤也到11.3%。考虑到实盘滑点和隔夜利息,我最终选了固定分数法,但把风险系数从2%降到1.5%,同时加了账户净值低于初始值90%时强制停止开新单的保护逻辑。代码里用`AccountInfoDouble(ACCOUNT_MARGIN_LEVEL)`监控保证金水平,低于200%直接平掉亏损单,这个条件一定要写在`OnTick()`最前面,别放在开仓逻辑后面,否则行情剧烈时可能来不及触发。
踩过最大的坑是MT4的`OrderSend`返回值判断,我一开始只检查是否大于0,后来发现如果因止损距离过小被拒单,返回-1但`GetLastError()`是130,这时候如果继续循环重试,可能瞬间连发几十单。正确做法是每次下单前用`MarketInfo(Symbol(), MODE_STOPLEVEL)`检查最小止损距离,再加上一个重试次数上限,比如最多3次,每次间隔500毫秒。另外,如果你用VPS挂EA,建议把日志写到文件里,不然MT4的专家日志滚动太快,出问题根本找不到线索。
现在这套逻辑跑了两个月demo,欧美和镑美同时开单,最大回撤控制在6%以内,但有个新问题想请教:当两个品种相关性高时(比如欧美和镑美同向波动),组合风险还是偏高,有没有人试过用协方差矩阵动态调整每单的仓位权重?我看了些对冲账户的配置思路,但MT4原生不支持跨品种风险计算,只能靠外部脚本算完再喂给EA,感觉有点绕,想听听大家的做法。
先说最常见的固定手数方案,代码就一行 `OrderSend(Symbol(), OP_BUY, 0.1, ...)`,优点是逻辑简单,回测参数好调,但缺点也很致命:账户净值从1万跌到5千时,0.1手对应的风险敞口直接翻倍,遇到欧美那种单日150点波动,浮亏能让你心态先崩。我后来改成固定分数法,也就是每次用净值的2%去算手数,公式是 `RiskAmount = AccountBalance() * 0.02`,再除以止损点数乘每点价值。这里有个坑,止损距离必须用OrderSend之前动态计算,不能写死,否则行情波动一变,实际风险敞口就偏离预设值了。
但固定分数法也有问题,它假设账户余额是连续变化的,可MT4的OrderSend是逐单执行,如果EA同时开了多单,比如欧美和镑美各一单,每单都按当前余额算2%,实际总风险就是4%了。我试过用`AccountEquity()`代替`AccountBalance()`,但回撤时净值波动太剧烈,导致手数忽大忽小,反而放大风险。后来查了论坛里汇友分享的经验,改成在EA的`init()`里设一个全局变量记录初始余额,然后每单计算时用 `(初始余额 - 当前浮亏) * 0.02`,这样至少能控制组合层面的总风险。
再说说更进阶的凯利公式变体,我见过有人直接用 `f = (bp - q) / b` 算最优仓位,但外汇市场的胜率和盈亏比是动态的,用历史回测参数去套未来行情,基本就是过拟合。我试过把盈亏比设成1.5,胜率按最近50单滚动统计,算出来的手数经常超过0.5手,点差和滑点一吃,实际收益还不如0.2手稳。所以我的建议是,凯利公式最多用来做仓位上限,实际下单手数要再乘个0.3的衰减系数,别真按理论值梭哈。
最后对比一下三种方案的实测数据,我用EURUSD M15跑了2023年整年回测,初始资金1万美金,固定手数0.1手年化收益8.2%,最大回撤14%;固定分数法2%风险年化12.6%,回撤9.8%;凯利衰减版年化15.1%,但回撤也到11.3%。考虑到实盘滑点和隔夜利息,我最终选了固定分数法,但把风险系数从2%降到1.5%,同时加了账户净值低于初始值90%时强制停止开新单的保护逻辑。代码里用`AccountInfoDouble(ACCOUNT_MARGIN_LEVEL)`监控保证金水平,低于200%直接平掉亏损单,这个条件一定要写在`OnTick()`最前面,别放在开仓逻辑后面,否则行情剧烈时可能来不及触发。
踩过最大的坑是MT4的`OrderSend`返回值判断,我一开始只检查是否大于0,后来发现如果因止损距离过小被拒单,返回-1但`GetLastError()`是130,这时候如果继续循环重试,可能瞬间连发几十单。正确做法是每次下单前用`MarketInfo(Symbol(), MODE_STOPLEVEL)`检查最小止损距离,再加上一个重试次数上限,比如最多3次,每次间隔500毫秒。另外,如果你用VPS挂EA,建议把日志写到文件里,不然MT4的专家日志滚动太快,出问题根本找不到线索。
现在这套逻辑跑了两个月demo,欧美和镑美同时开单,最大回撤控制在6%以内,但有个新问题想请教:当两个品种相关性高时(比如欧美和镑美同向波动),组合风险还是偏高,有没有人试过用协方差矩阵动态调整每单的仓位权重?我看了些对冲账户的配置思路,但MT4原生不支持跨品种风险计算,只能靠外部脚本算完再喂给EA,感觉有点绕,想听听大家的做法。
