Summary: 本文提供完整的基于双均线交叉策略的MQL4 EA源码,包含交易过滤、移动止损、风险管理以及详细的参数解释,适合初学者学习EA编程。




均线交叉是最经典且广泛使用的交易策略之一。此MQL4 EA源码实现了一个完整功能的外汇机器人:当快均线上穿慢均线时开多单,下穿时开空单。内置资金管理、时间过滤和移动止损,该EA可直接用于实盘交易或历史回测。

策略逻辑


  • 做多信号:快均线(如10)上穿慢均线(如30)

  • 做空信号:快均线下穿慢均线

  • 出场方式:反向交叉信号或移动止损


  • 完整MQL4源码


    ```cpp
    //+------------------------------------------------------------------+
    //| MovingAverage_Crossover_EA.mq4 |
    //| Generated by AutoCompile AI |
    //| |
    //+------------------------------------------------------------------+
    #property copyright "AutoCompile AI"
    #property link ""
    #property version "1.00"
    #property strict

    //--- 输入参数:移动平均线
    input int FastMAPeriod = 10; // 快均线周期
    input int SlowMAPeriod = 30; // 慢均线周期
    input int MAShift = 0; // 均线偏移
    input ENUM_MA_METHOD MAMethod = MODE_SMA; // 均线类型: SMA, EMA等
    input ENUM_APPLIED_PRICE MAPrice = PRICE_CLOSE; // 应用价格

    //--- 输入参数:资金管理
    input double FixedLotSize = 0.1; // 固定手数(UseMoneyManagement=false时生效)
    input bool UseMoneyManagement = true; // 使用自动手数(基于风险百分比)
    input double RiskPercent = 2.0; // 每笔交易风险占账户百分比
    input int StopLossPips = 50; // 止损点数
    input int TakeProfitPips = 150; // 止盈点数

    //--- 输入参数:交易过滤
    input bool UseTimeFilter = false; // 仅在特定时段交易
    input int StartHour = 8; // 交易开始小时(服务器时间)
    input int EndHour = 17; // 交易结束小时
    input int MaxSpread = 30; // 允许最大点差(点数)
    input int Slippage = 20; // 下单滑点

    //--- 输入参数:移动止损
    input bool UseTrailingStop = true; // 启用移动止损
    input int TrailStartPips = 20; // 盈利达到此点数后启动移动止损
    input int TrailStepPips = 10; // 移动止损距离(点数)

    //--- 全局变量
    double fastMA[], slowMA[];
    int magicNumber = 202510;
    string comment = "MA_Crossover";

    //+------------------------------------------------------------------+
    //| EA初始化函数 |
    //+------------------------------------------------------------------+
    int OnInit()
    {
    if(FastMAPeriod >= SlowMAPeriod)
    {
    Print("错误: 快均线周期必须小于慢均线周期");
    return(INIT_FAILED);
    }
    Print("均线交叉EA初始化成功");
    return(INIT_SUCCEEDED);
    }

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

    //+------------------------------------------------------------------+
    //| EA tick函数 |
    //+------------------------------------------------------------------+
    void OnTick()
    {
    //--- 检查市场是否可交易及点差条件
    if(!IsTradeAllowed()) return;
    if(MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread * Point) return;

    //--- 时间过滤
    if(UseTimeFilter)
    {
    datetime now = TimeCurrent();
    int currentHour = TimeHour(now);
    if(currentHour < StartHour || currentHour >= EndHour) return;
    }

    //--- 获取均线值
    int barsToCopy = SlowMAPeriod + 5;
    ArraySetAsSeries(fastMA, true);
    ArraySetAsSeries(slowMA, true);

    if(CopyBuffer(iMA(Symbol(), 0, FastMAPeriod, MAShift, MAMethod, MAPrice), 0, 0, barsToCopy, fastMA) < barsToCopy) return;
    if(CopyBuffer(iMA(Symbol(), 0, SlowMAPeriod, MAShift, MAMethod, MAPrice), 0, 0, barsToCopy, slowMA) < barsToCopy) return;

    //--- 检查现有持仓数量
    int buyCount = 0, sellCount = 0;
    for(int i = 0; i < OrdersTotal(); i++)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber)
    {
    if(OrderType() == OP_BUY) buyCount++;
    if(OrderType() == OP_SELL) sellCount++;
    }
    }
    }

    //--- 交叉检测
    bool fastAboveSlow = (fastMA[1] > slowMA[1]);
    bool fastBelowSlow = (fastMA[1] < slowMA[1]);
    bool prevFastAboveSlow = (fastMA[2] > slowMA[2]);
    bool prevFastBelowSlow = (fastMA[2] < slowMA[2]);

    bool buySignal = (prevFastBelowSlow && fastAboveSlow);
    bool sellSignal = (prevFastAboveSlow && fastBelowSlow);

    //--- 计算手数
    double lot = FixedLotSize;
    if(UseMoneyManagement)
    {
    double riskMoney = AccountBalance() * RiskPercent / 100.0;
    double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
    double stopLossPoints = StopLossPips * 10;
    lot = riskMoney / (stopLossPoints * tickValue);
    lot = NormalizeDouble(lot, 2);
    double minLot = MarketInfo(Symbol(), MODE_MINLOT);
    double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
    if(lot < minLot) lot = minLot;
    if(lot > maxLot) lot = maxLot;
    }

    //--- 开仓逻辑
    if(buySignal && buyCount == 0)
    {
    double entryPrice = Ask;
    double sl = entryPrice - StopLossPips * 10 * Point;
    double tp = entryPrice + TakeProfitPips * 10 * Point;
    int ticket = OrderSend(Symbol(), OP_BUY, lot, entryPrice, Slippage, sl, tp, comment, magicNumber, 0, clrGreen);
    if(ticket > 0)
    Print("买单开仓成功。订单号: ", ticket);
    else
    Print("买单开仓失败。错误码: ", GetLastError());
    }
    else if(sellSignal && sellCount == 0)
    {
    double entryPrice = Bid;
    double sl = entryPrice + StopLossPips * 10 * Point;
    double tp = entryPrice - TakeProfitPips * 10 * Point;
    int ticket = OrderSend(Symbol(), OP_SELL, lot, entryPrice, Slippage, sl, tp, comment, magicNumber, 0, clrRed);
    if(ticket > 0)
    Print("卖单开仓成功。订单号: ", ticket);
    else
    Print("卖单开仓失败。错误码: ", GetLastError());
    }

    //--- 移动止损管理
    if(UseTrailingStop)
    {
    for(int i = 0; i < OrdersTotal(); i++)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber)
    {
    if(OrderType() == OP_BUY)
    {
    double profitPips = (Bid - OrderOpenPrice()) / Point;
    if(profitPips > TrailStartPips * 10)
    {
    double newSL = Bid - TrailStepPips * 10 * Point;
    if(newSL > OrderStopLoss())
    OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrBlue);
    }
    }
    else if(OrderType() == OP_SELL)
    {
    double profitPips = (OrderOpenPrice() - Ask) / Point;
    if(profitPips > TrailStartPips * 10)
    {
    double newSL = Ask + TrailStepPips * 10 * Point;
    if(newSL < OrderStopLoss() || OrderStopLoss() == 0)
    OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrBlue);
    }
    }
    }
    }
    }
    }
    }
    //+------------------------------------------------------------------+
    ```

    如何编译与测试


    1. 保存为 `MovingAverage_Crossover_EA.mq4` 放入 `Experts` 文件夹。
    2. 在MetaEditor中按F7编译,应无报错。
    3. 在策略测试器(Ctrl+R)中对EURUSD、H1周期进行回测。
    4. 针对不同品种优化均线周期和风险设置。

    参数说明


    | 参数 | 说明 |
    |------|------|
    | FastMAPeriod / SlowMAPeriod | 交叉速度。典型值:10和30、5和20、20和50 |
    | UseMoneyManagement / RiskPercent | 基于账户百分比风险自动计算手数 |
    | StopLossPips / TakeProfitPips | 固定止损/止盈点数 |
    | UseTrailingStop / TrailStartPips | 盈利达到设定点数后启动移动止损 |
    | MaxSpread | 高波动时避免交易 |
    | UseTimeFilter | 限制交易时段(服务器时间) |

    回测建议


  • 最佳周期:H1或H4(减少假信号)

  • 推荐品种:EURUSD、GBPUSD、AUDUSD(趋势性品种)

  • 最小测试周期:6个月


  • 免费EA下载EA编程入门的优秀起点。修改MQL4代码可添加RSI过滤器、新闻过滤器或多周期确认。如需包含AI优化的完整自动化交易套件,请关注我们的高级版外汇AI EA——订阅获取每周高级策略更新。

    参考来源:AutoCompile AI - 基于经典交叉策略的原创MQL4 EA实现,2025年。
    ```