Summary: 完整的布林带均值回归MT4 EA源码,价格触及上下轨时开仓,结合ATR波动率过滤确认。含保本止损、点差控制和时间过滤,直接编译可用。




# 布林带均值回归EA - 完整MQL4源码

本文提供一个完整的布林带均值回归自动交易EA,配有ATR波动率确认过滤。当价格触及或突破布林带上轨时开空单,触及或突破下轨时开多单,利用价格回归中轨的均值回归特性获利。

策略逻辑



该策略基于均值回归原理运作——当价格显著偏离其移动平均线(布林带中轨)时,倾向于回归。布林带使用标准差来衡量这种偏离程度。EA包含ATR波动率过滤,避免在低波动环境下交易(此时均值回归可能无法提供足够的盈利空间)。附加功能包括保本止损管理、点差控制和交易时间过滤。

核心特性



  • 布林带信号:上下轨触及时进场

  • ATR波动率过滤:避免低波动时交易

  • 保本止损管理:盈利达到设定值后移动止损至开仓价

  • 点差保护:点差过大时暂停交易

  • 时间过滤:限制在指定时段交易

  • 单方向单持仓:避免过度暴露风险


  • 完整MQL4代码



    ```mql4
    //+------------------------------------------------------------------+
    //| BB_MeanReversionEA.mq4 |
    //| AI助手独立自主编译 |
    //| |
    //+------------------------------------------------------------------+
    #property copyright "AI助手"
    #property link ""
    #property version "1.00"
    #property strict

    //--- 输入参数
    input double LotSize = 0.1; // 固定手数
    input int BandsPeriod = 20; // 布林带周期
    input double BandsDeviation = 2.0; // 标准差倍数
    input int ATRPeriod = 14; // ATR过滤周期
    input double MinATR = 10; // 最小ATR值(点数)- 低波动过滤
    input int StopLoss = 60; // 止损点数
    input int TakeProfit = 120; // 止盈点数
    input bool UseBreakEven = true; // 启用保本止损
    input int BreakEvenPips = 25; // 触发保本所需盈利点数
    input int MaxSpread = 30; // 最大允许点差(点数)
    input bool UseTimeFilter = false; // 启用交易时间过滤
    input int StartHour = 8; // 开始交易小时(服务器时间)
    input int EndHour = 20; // 结束交易小时
    input int MagicNumber = 202412; // EA魔术号
    input bool CloseOpposite = true; // 反向信号时平仓反向单

    //--- 全局变量
    double upperBand = 0, lowerBand = 0, middleBand = 0;
    double atrValue = 0;
    int pointMultiplier = 10; // 5位报价平台乘数

    //+------------------------------------------------------------------+
    //| EA初始化函数 |
    //+------------------------------------------------------------------+
    int OnInit()
    {
    // 检测4位报价平台
    if(Digits == 4 || Digits == 3)
    pointMultiplier = 1;
    else if(Digits == 5 || Digits == 2)
    pointMultiplier = 10;

    if(BandsPeriod < 2)
    {
    Print("错误: 布林带周期至少为2");
    return(INIT_PARAMETERS_INCORRECT);
    }

    if(ATRPeriod < 2)
    {
    Print("错误: ATR周期至少为2");
    return(INIT_PARAMETERS_INCORRECT);
    }

    Print("EA初始化成功,品种: ", Symbol());
    Print("点数乘数: ", pointMultiplier);
    return(INIT_SUCCEEDED);
    }

    //+------------------------------------------------------------------+
    //| EA反初始化函数 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
    {
    Print("EA已移除,原因代码: ", reason);
    }

    //+------------------------------------------------------------------+
    //| EA报价处理函数 |
    //+------------------------------------------------------------------+
    void OnTick()
    {
    // 检查时间过滤
    if(!IsTradingTime())
    return;

    // 检查点差条件
    if(!IsSpreadOK())
    return;

    // 获取布林带数值
    upperBand = iBands(Symbol(), 0, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_UPPER, 0);
    lowerBand = iBands(Symbol(), 0, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_LOWER, 0);
    middleBand = iBands(Symbol(), 0, BandsPeriod, BandsDeviation, 0, PRICE_CLOSE, MODE_MAIN, 0);

    // 获取ATR波动率值
    atrValue = iATR(Symbol(), 0, ATRPeriod, 0);

    // 验证数据有效性
    if(upperBand == EMPTY_VALUE || lowerBand == EMPTY_VALUE || atrValue == EMPTY_VALUE)
    return;

    // 转换为点数进行比较
    double atrPoints = atrValue / Point / pointMultiplier;

    // 低波动过滤 - 跳过交易
    if(atrPoints < MinATR)
    return;

    // 管理现有持仓的保本止损
    ManageBreakEven();

    // 信号检测
    if(IsSellSignal())
    {
    if(CloseOpposite) CloseBuyPositions();
    if(CountSellPositions() == 0)
    OpenOrder(OP_SELL);
    }
    else if(IsBuySignal())
    {
    if(CloseOpposite) CloseSellPositions();
    if(CountBuyPositions() == 0)
    OpenOrder(OP_BUY);
    }
    }

    //+------------------------------------------------------------------+
    //| 检查买入信号 - 价格触及或跌破下轨 |
    //+------------------------------------------------------------------+
    bool IsBuySignal()
    {
    // 使用最低价确认,避免重绘
    double lowPrice = Low[0];
    return (lowPrice <= lowerBand);
    }

    //+------------------------------------------------------------------+
    //| 检查卖出信号 - 价格触及或突破上轨 |
    //+------------------------------------------------------------------+
    bool IsSellSignal()
    {
    // 使用最高价确认,避免重绘
    double highPrice = High[0];
    return (highPrice >= upperBand);
    }

    //+------------------------------------------------------------------+
    //| 开仓函数 |
    //+------------------------------------------------------------------+
    void OpenOrder(int cmd)
    {
    double price = (cmd == OP_BUY) ? Ask : Bid;
    double sl = 0, tp = 0;
    double slPoints = StopLoss * pointMultiplier * Point;
    double tpPoints = TakeProfit * pointMultiplier * Point;

    if(StopLoss > 0)
    {
    if(cmd == OP_BUY)
    sl = price - slPoints;
    else
    sl = price + slPoints;
    }

    if(TakeProfit > 0)
    {
    if(cmd == OP_BUY)
    tp = price + tpPoints;
    else
    tp = price - tpPoints;
    }

    // 发送订单前检查保证金
    double marginRequired = MarketInfo(Symbol(), MODE_MARGINREQUIRED);
    double freeMargin = AccountFreeMargin();

    if(freeMargin < marginRequired * LotSize * 1.5)
    {
    Print("保证金不足。需要: ", marginRequired * LotSize, " 可用: ", freeMargin);
    return;
    }

    int ticket = OrderSend(Symbol(), cmd, LotSize, price, 3, sl, tp, "BB MeanRev", MagicNumber, 0, clrNONE);

    if(ticket < 0)
    Print("开仓失败,错误码: ", GetLastError());
    else
    Print("开仓成功,订单号: ", ticket, " 类型: ", (cmd == OP_BUY ? "买入" : "卖出"));
    }

    //+------------------------------------------------------------------+
    //| 检查当前是否在允许交易时间内 |
    //+------------------------------------------------------------------+
    bool IsTradingTime()
    {
    if(!UseTimeFilter) return true;

    datetime now = TimeCurrent();
    MqlDateTime dt;
    TimeToStruct(now, dt);

    int hour = dt.hour;

    if(hour >= StartHour && hour < EndHour)
    return true;

    return false;
    }

    //+------------------------------------------------------------------+
    //| 检查点差是否在限制范围内 |
    //+------------------------------------------------------------------+
    bool IsSpreadOK()
    {
    if(MaxSpread == 0) return true;

    int currentSpread = (int)((Ask - Bid) / Point / pointMultiplier);
    return (currentSpread <= MaxSpread);
    }

    //+------------------------------------------------------------------+
    //| 保本止损管理 - 盈利达标后将止损移至开仓价 |
    //+------------------------------------------------------------------+
    void ManageBreakEven()
    {
    if(!UseBreakEven) return;

    for(int i = 0; i < OrdersTotal(); i++)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
    {
    double breakEvenTrigger = BreakEvenPips * pointMultiplier * Point;
    double currentSL = OrderStopLoss();

    if(OrderType() == OP_BUY)
    {
    double profitPoints = (Bid - OrderOpenPrice()) / Point / pointMultiplier;
    if(profitPoints >= BreakEvenPips && (currentSL == 0 || currentSL < OrderOpenPrice()))
    {
    bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), 0, clrNONE);
    if(modified)
    Print("保本止损已设置 - 买单 #", OrderTicket());
    }
    }
    else if(OrderType() == OP_SELL)
    {
    double profitPoints = (OrderOpenPrice() - Ask) / Point / pointMultiplier;
    if(profitPoints >= BreakEvenPips && (currentSL == 0 || currentSL > OrderOpenPrice()))
    {
    bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), 0, clrNONE);
    if(modified)
    Print("保本止损已设置 - 卖单 #", OrderTicket());
    }
    }
    }
    }
    }
    }

    //+------------------------------------------------------------------+
    //| 统计买单数量 |
    //+------------------------------------------------------------------+
    int CountBuyPositions()
    {
    int count = 0;
    for(int i = 0; i < OrdersTotal(); i++)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_BUY)
    count++;
    }
    }
    return count;
    }

    //+------------------------------------------------------------------+
    //| 统计卖单数量 |
    //+------------------------------------------------------------------+
    int CountSellPositions()
    {
    int count = 0;
    for(int i = 0; i < OrdersTotal(); i++)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_SELL)
    count++;
    }
    }
    return count;
    }

    //+------------------------------------------------------------------+
    //| 平仓所有买单 |
    //+------------------------------------------------------------------+
    void CloseBuyPositions()
    {
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_BUY)
    {
    if(OrderClose(OrderTicket(), OrderLots(), Bid, 3, clrNONE))
    Print("已平仓买单 #", OrderTicket());
    else
    Print("平仓买单失败 #", OrderTicket(), " 错误码: ", GetLastError());
    }
    }
    }
    }

    //+------------------------------------------------------------------+
    //| 平仓所有卖单 |
    //+------------------------------------------------------------------+
    void CloseSellPositions()
    {
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_SELL)
    {
    if(OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrNONE))
    Print("已平仓卖单 #", OrderTicket());
    else
    Print("平仓卖单失败 #", OrderTicket(), " 错误码: ", GetLastError());
    }
    }
    }
    }
    //+------------------------------------------------------------------+
    ```

    参数详解



    | 参数 | 说明 | 推荐值 |
    |------|------|--------|
    | 固定手数 | 每笔交易手数 | 0.01 - 1.0 |
    | 布林带周期 | 布林带计算周期 | 20(标准) |
    | 标准差倍数 | 标准差倍数 | 2.0 - 2.5 |
    | ATR周期 | ATR过滤计算周期 | 14 |
    | 最小ATR | 最小ATR点数 - 过滤低波动 | 8-15 |
    | 止损点数 | 止损距离 | 50-80 |
    | 止盈点数 | 止盈距离 | 100-160 |
    | 启用保本止损 | 是否启用保本功能 | true |
    | 保本触发点数 | 触发保本所需盈利点数 | 20-30 |
    | 最大点差 | 允许的最大点差 | 20-50 |
    | 启用时间过滤 | 是否限制交易时段 | false |
    | 开始小时 | 开始交易时间 | 8 |
    | 结束小时 | 停止交易时间 | 20 |
    | 魔术号 | EA唯一标识码 | 任意不重复 |
    | 反向平仓 | 新信号是否平掉反向单 | true |

    安装步骤



    1. 在MT4中打开MetaEditor(按F4)
    2. 创建新的EA(文件 > 新建 > 智能交易系统)
    3. 删除所有默认代码,粘贴上方完整代码
    4. 按编译按钮(F7)- 检查底部错误选项卡应为0个错误
    5. 关闭MetaEditor,从导航器将EA拖拽到图表上
    6. 在输入参数选项卡中调整参数
    7. 启用自动交易(绿色三角形按钮)

    编译与修改技巧



    常见问题处理:
  • 对于4位报价平台,EA会自动检测并调整点数乘数

  • 确保MagicNumber不与其他EA冲突

  • 实盘前至少在模拟账户测试2周

  • 建议使用VPS保证全天候稳定运行


  • 参数优化建议:
  • 多数货币对使用BandsDeviation = 2.0效果最佳

  • MinATR应根据交易品种的平均波动率调整

  • 可开启UseTimeFilter避开低流动性时段


  • 参考来源



    本文EA源码为自主独立编译,基于均值回归策略原理和标准布林带方法论设计。

    *如需包含多周期确认、机器学习过滤和完整回测报告的高级EA策略,请查看我们的付费EA合集。订阅后可每周获取更新和专业交易工具。*