作 者:老余捞鱼
原创不易,转载请标明出处及原作者。

文中示例仅用于技术讨论,不构成任何操作建议。
量化策略开发应以学习和技术交流为目的。
本号不荐股、不卖课、不承诺收益。
市场有风险,请合法合规投资。
本文约 2900 字 | 预计阅读 5-8 分钟,后有代码下载,建议先收藏。
· · ·
做过突破交易的人都懂这个画面:布林带的上下轨越收越窄,波动率被压到一个极低的水平,然后某一根K线突然拉出去。赚到的会喊”抓住了”,错过的人会啐一口说”假突破”。
这个模式本身已经被人写了无数遍。问题从来不是怎么发现收缩:随便扫一眼布林带宽度就知道了。问题是这三个:
这根K线是真突破还是噪音?多还是空?仓位放多大?
今天我就用布林带宽度、一目均衡云层、随机指标三个东西,一次性回答这三个问题。MQL5代码全开源,会在文章末尾提供下载地址。
整体的流程和输出大概是下面这样。

▲ EA信号流程:布林宽度确认扩张 → 云层定方向 → 随机指标滤噪音 → ATR算仓位和止损
一、别等”收缩”,等”扩张确认”
大多数布林带突破策略的写法是:带宽低于某个阈值就触发入场。这个逻辑有个明显的问题:收缩可以持续几十根K线。你在里面开单,跟抛硬币差不多。
今天这个 EA 换了个思路。它不关心收缩到多窄,它关心的是:收缩结束之后,带宽有没有”真的张开”。
具体实现分两步。第一步,在最近 N 根 K 线里找到带宽的最低点。第二步,当前带宽必须比那个最低点大了至少 20%(默认参数 InpExpansionFactor = 1.20),EA 才认为扩张发生了。
这个 20% 不是拍脑袋拍出来的。如果只比较相邻两根 K 线的带宽,涨 2% 是扩张,涨 5% 也是扩张:但前者可能只是噪音,后者才是真正的波动率回归。用 20% 这个阈值,本质上是在等波动率”足够大”的变化,而不是盯着每一根 K 线的小幅跳动。
代码逻辑值得看一下:
// 窗口内的最低带宽
double minRecentWidth = DBL_MAX;
for(int i = 1; i <= InpBreakoutLookback; i++) {
double w = (upper[i] - lower[i]) / MathMax(middle[i], 1e-10);
if(w < minRecentWidth) minRecentWidth = w;
}
// 当前带宽比最低点扩张了20%?触发
bool isExpanding = curWidth > minRecentWidth * InpExpansionFactor;这个设计的实际效果是:它不会在市场缩量横盘了三个月、带宽一直趴在地上的时候反复开单。它等的是”压到极致之后真的开始动了”的那一刻。
二、方向交给一目均衡云,不做猜测
扩张确认了,方向怎么办?
这个 EA 用的是一目均衡的云层(Kumo)。规则很直白:价格在云层上方 → 只做多。价格在云层下方 → 只做空。价格在云层内部 → 不开单,等着。
为什么不用均线交叉或者蜡烛颜色?因为云层本身是一个”共识区域”:只有当价格已经站在云的一侧,才能说明多空哪一方占据了上风。云内部的行情本质上方向不明确,强行开单就是在赌。
double cloudTop = MathMax(spanA[1], spanB[1]);
double cloudBottom = MathMin(spanA[1], spanB[1]);
bool wantBuy = (price > cloudTop);
bool wantSell = (price < cloudBottom);有了这个约束,EA 不会在方向不明的窄幅震荡里浪费子弹。扩张确认告诉你”波动率回来了”,云层方向告诉你”你要跟哪边”。两个条件同时满足,信号才成立。
三、再加一道过滤:随机指标
方向是对的,但突破仍然可能是假动作。EA 的第三层保护是随机指标的 %K/%D 交叉。
逻辑跟云层一致:只取同方向的交叉。做多信号必须等 %K 从下方向上穿过 %D,做空信号必须等 %K 从上方向下跌破 %D。如果方向对,但随机指标没交叉?不开单。
bool bullishCross = (kPrev <= dPrev) && (kNow > dNow);
bool bearishCross = (kPrev >= dPrev) && (kNow < dNow);
if(wantBuy && !bullishCross) wantBuy = false;
if(wantSell && !bearishCross) wantSell = false;而且这个过滤是可选的(InpRequireStochCross),关掉之后就能 A/B 测试:开和不开,哪个效果好。这一点在 EA 设计里很重要:你的规则能不能关掉回测,决定了你是在用一条规则还是在赌一个故事。
四、仓位按”你想赚多少钱”反推
做过多品种 EA 的人都知道:0.1 手 EURUSD 和 0.1 手 XAUUSD 是一回事吗?
当然不是。一个波动 10 个点,一个波动 100 个点,同样的手数意味着完全不同的风险暴露。
本EA 的仓位逻辑倒过来算:你先定”这笔交易止盈了要赚多少钱”(比如 50 欧元),然后 EA 根据当前品种的 tick value 和 ATR 算出的止盈距离,反推需要开多少手。
double CalcLotForTargetProfit(string symbol, double tpDistance, double targetProfit) {
double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
double valuePerLot = (tpDistance / tickSize) * tickValue;
double lot = targetProfit / valuePerLot;
// ... 对齐到品种的最小手数步长
}这个设计的好处是:你不是在管理手数,你是在管理”每笔交易想冒多少、赚多少”:这比盯着手数看要诚实得多。
止损和止盈的距离本身也用了 ATR 的倍数:止损 1.5×ATR,止盈固定 3.0×ATR。ATR 动,止损止盈跟着动。品种波动大就自动放宽止损,产品量小就自动收紧。不会出现”固定 20 点止损在黄金上等于没设”的情况。
五、浮盈跑起来了,trailing stop 跟上
突破交易有一个很恶心的体验:方向对了,跑了 3%,没止盈,然后一个回踩扫掉止损,变成亏损。
本EA 加了一个 trailing stop,但它不是一开仓就跟着跑。它等浮盈超过一定距离(InpTrailingStartATRMult,默认 1×ATR)之后才启动,而且只往有利方向移动,不往后退。
double trailDist = atrValue * InpTrailingATRMult; // 比如 0.5×ATR,跟得很紧
double profitDist = tick.bid - openPrice;
if(profitDist < startDist) return; // 不够远,不跟
double newSL = tick.bid - trailDist;
if(newSL > currentSL) trade.PositionModify(...);0.5×ATR 的跟紧距离,加上 1×ATR 的启动门槛,意味着 EA 只有在盈利足够多的时候才开始锁定利润,而不是刚开单就急着上移止损。
六、按品种×时间框架独立统计
多数 EA 跑完之后,你只知道总盈亏。赚了 500 块,不错。但你知道这 500 块是 H4 赚的 800 扣掉 M15 亏的 300 吗?
我们 EA 内部维护了一个 context 数组,每一个 context 对应一个「品种 + 时间框架」的组合。M15 的 EURUSD、H4 的 EURUSD、D1 的 GBPUSD……每一个组合有自己的指标句柄、magic number 和独立的交易统计。每次有仓位关闭仓位,OnTradeTransaction 会把盈亏归到对应的 context 上。
日志打出来长这样:
EURUSD H4 | trades=12 wins=7 losses=5 winRate=58.3% profitTotal=145.30
EURUSD D1 | trades=4 wins=3 losses=1 winRate=75.0% profitTotal=89.10
GBPUSD M30 | trades=31 wins=14 losses=17 winRate=45.2% profitTotal=-38.50一眼就能看出来:D1 胜率 75% 但交易太少,M30 交易多但亏钱,H4 才是主要贡献者。这个级别的透明度在免费 EA 里不多见。你可以直接用这些数据决定关掉哪些时间框架、调哪个品种的参数,不用靠猜。
七、需要注意的几点
参数不是通用的。 布林带的回溯窗口、扩张因子、ATR 倍数:这些东西对 EURUSD H4 好用的,不一定会对 XAUUSD M10 好用。必须分品种分时间框架测,别偷懒。
相关性风险。 在 EURUSD 和 GBPUSD 上同时跑同一个逻辑,行情来了两边都开单。你以为你在分散风险,实际上你在加倍暴露于同一个方向。
没有总敞口上限。 按目标盈利金额反推手数,这个设计解决了单品种的问题。但如果 9 个时间框架同时在某个品种上开了单,你的总仓位可能是单笔的 9 倍。作者自己也说了,这个 EA 缺一个账户级别的总风险上限:”这也是一个值得单独加的控制项”。
提示:我这个EA就是个模板,不是成品。Squeeze-breakout 策略本身就是假信号高发的类型。参数需要在你自己的品种和时间框架上跑实证,不是复制粘贴就能上实盘的。
代码和下载
完整源代码可以从这里直接下载:
🔗https://www.laoyulaoyu.com/code/BollingerSEA.zip
三个指标的串联逻辑:布林宽度确认扩张、一目均衡定方向、随机指标过滤假信号:加上 ATR 止损止盈、trailing stop、多上下文并行跑,这套东西就算不直接用,框架思路也值得参考。
Be First to Comment