Summary: 完整的双均线交叉EA源码,包含快慢均线(可调周期)、ATR波动率过滤器(避免震荡市)、移动止损功能。附带详细参数说明、安装步骤和品种优化建议。




双均线交叉EA:完整MQL4源码(含ATR过滤器)

策略原理

本EA实现经典的双均线交叉策略,并增加ATR波动率过滤器,有效规避震荡行情。核心逻辑:

· 快均线:周期5-20,捕捉短期动能
· 慢均线:周期50-200,定义主要趋势方向
· ATR过滤器:仅当波动率超过阈值时才交易,避开震荡盘整

当快均线上穿慢均线且波动率足够时,开BUY多单;当快均线下穿慢均线且波动率足够时,开SELL空单。

完整源码

```cpp
//+------------------------------------------------------------------+
//| DualMACrossover.mq4 |
//| EA代码库 |
//+------------------------------------------------------------------+
#property copyright "EA Code Library"
#property version "1.00"
#property strict

//+------------------------------------------------------------------+
//| 输入参数 |
//+------------------------------------------------------------------+
input double LotSize = 0.01; // 手数 (0.01 至 1.0)
input int FastMAPeriod = 10; // 快均线周期 (5-30)
input int SlowMAPeriod = 30; // 慢均线周期 (20-100)
input int ATRPeriod = 14; // ATR周期 (10-21)
input double ATRMultiplier = 1.5; // ATR倍数过滤器 (1.0-3.0)
input int StopLoss = 300; // 止损点数 (200-500)
input int TakeProfit = 600; // 止盈点数 (400-1000)
input int MagicNumber = 20240601; // EA魔术号
input bool UseTrailingStop = true; // 启用移动止损
input int TrailingStart = 200; // 移动止损启动点数
input int TrailingStep = 50; // 移动止损步长
input int Slippage = 3; // 滑点点数

//+------------------------------------------------------------------+
//| 全局变量 |
//+------------------------------------------------------------------+
double lastFastMA = 0, lastSlowMA = 0;
double currentFastMA = 0, currentSlowMA = 0;
datetime lastBarTime = 0;

//+------------------------------------------------------------------+
//| 初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
// 参数验证
if(FastMAPeriod >= SlowMAPeriod)
{
Print("错误:快均线周期必须小于慢均线周期");
return INIT_PARAMETERS_INCORRECT;
}
if(ATRMultiplier <= 0)
{
Print("错误:ATR倍数必须为正数");
return INIT_PARAMETERS_INCORRECT;
}
if(LotSize < MarketInfo(Symbol(), MODE_MINLOT))
{
Print("警告:手数已调整为最小值 ", MarketInfo(Symbol(), MODE_MINLOT));
LotSize = MarketInfo(Symbol(), MODE_MINLOT);
}

Print("双均线EA初始化完成,魔术号:", MagicNumber);
return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| 反初始化函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Print("双均线EA已卸载,原因码:", reason);
}

//+------------------------------------------------------------------+
//| Tick函数 - 核心逻辑 |
//+------------------------------------------------------------------+
void OnTick()
{
// 新K线检测(只在K线收盘时交易,减少噪音)
if(Time[0] == lastBarTime) return;
lastBarTime = Time[0];

// 计算均线值(使用前一根K线确认信号)
currentFastMA = iMA(Symbol(), 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
currentSlowMA = iMA(Symbol(), 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
lastFastMA = iMA(Symbol(), 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
lastSlowMA = iMA(Symbol(), 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);

// 计算ATR波动率过滤器
double currentATR = iATR(Symbol(), 0, ATRPeriod, 1);
double atrThreshold = ATRMultiplier * currentATR;
double currentRange = High[1] - Low[1];
bool sufficientVolatility = (currentRange > atrThreshold);

// 检测交叉信号
bool fastCrossAboveSlow = (lastFastMA <= lastSlowMA && currentFastMA > currentSlowMA);
bool fastCrossBelowSlow = (lastFastMA >= lastSlowMA && currentFastMA < currentSlowMA);

// 统计现有持仓
int buyCount = 0, sellCount = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
{
if(OrderType() == OP_BUY) buyCount++;
if(OrderType() == OP_SELL) sellCount++;
}
}
}

// 入场逻辑
if(fastCrossAboveSlow && sufficientVolatility && buyCount == 0)
{
CloseAllPositions(); // 先平反向仓位
OpenBuy();
Print("买入信号:快均线上穿慢均线,波动率 ", currentRange, " > 阈值 ", atrThreshold);
}
else if(fastCrossBelowSlow && sufficientVolatility && sellCount == 0)
{
CloseAllPositions();
OpenSell();
Print("卖出信号:快均线下穿慢均线,波动率 ", currentRange, " > 阈值 ", atrThreshold);
}

// 移动止损管理
if(UseTrailingStop)
{
TrailingStop();
}
}

//+------------------------------------------------------------------+
//| 开多单函数 |
//+------------------------------------------------------------------+
void OpenBuy()
{
double ask = Ask;
double sl = 0, tp = 0;

if(StopLoss > 0) sl = ask - StopLoss * Point;
if(TakeProfit > 0) tp = ask + TakeProfit * Point;

int ticket = OrderSend(Symbol(), OP_BUY, LotSize, ask, Slippage, sl, tp,
"Dual MA Crossover", MagicNumber, 0, clrGreen);

if(ticket > 0)
{
Print("买入订单成功,票据号:", ticket, " 价格:", ask);
}
else
{
Print("买入订单失败,错误码:", GetLastError());
}
}

//+------------------------------------------------------------------+
//| 开空单函数 |
//+------------------------------------------------------------------+
void OpenSell()
{
double bid = Bid;
double sl = 0, tp = 0;

if(StopLoss > 0) sl = bid + StopLoss * Point;
if(TakeProfit > 0) tp = bid - TakeProfit * Point;

int ticket = OrderSend(Symbol(), OP_SELL, LotSize, bid, Slippage, sl, tp,
"Dual MA Crossover", MagicNumber, 0, clrRed);

if(ticket > 0)
{
Print("卖出订单成功,票据号:", ticket, " 价格:", bid);
}
else
{
Print("卖出订单失败,错误码:", GetLastError());
}
}

//+------------------------------------------------------------------+
//| 平仓所有持仓函数 |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
{
bool closeResult = false;
if(OrderType() == OP_BUY)
closeResult = OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clrWhite);
else if(OrderType() == OP_SELL)
closeResult = OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clrWhite);

if(closeResult)
Print("已平仓,票据号:", OrderTicket());
else
Print("平仓失败,票据号:", OrderTicket(), " 错误码:", GetLastError());
}
}
}
}

//+------------------------------------------------------------------+
//| 移动止损函数 |
//+------------------------------------------------------------------+
void TrailingStop()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
{
if(OrderType() == OP_BUY)
{
double currentProfit = Bid - OrderOpenPrice();
if(currentProfit > TrailingStart * Point)
{
double newStop = Bid - TrailingStep * Point;
if(newStop > OrderStopLoss())
{
bool modify = OrderModify(OrderTicket(), OrderOpenPrice(), newStop, OrderTakeProfit(), 0, clrWhite);
if(modify) Print("多单移动止损更新:", newStop);
}
}
}
else if(OrderType() == OP_SELL)
{
double currentProfit = OrderOpenPrice() - Ask;
if(currentProfit > TrailingStart * Point)
{
double newStop = Ask + TrailingStep * Point;
if(newStop < OrderStopLoss() || OrderStopLoss() == 0)
{
bool modify = OrderModify(OrderTicket(), OrderOpenPrice(), newStop, OrderTakeProfit(), 0, clrWhite);
if(modify) Print("空单移动止损更新:", newStop);
}
}
}
}
}
}
}
```

参数详解

参数 范围 默认值 说明
LotSize 0.01-1.0 0.01 固定交易手数
FastMAPeriod 5-30 10 快均线周期,越小越敏感
SlowMAPeriod 20-100 30 慢均线周期,越大越平滑
ATRPeriod 10-21 14 ATR计算周期
ATRMultiplier 1.0-3.0 1.5 越大要求波动越高
StopLoss 200-500 300 止损点数(300=30点)
TakeProfit 400-1000 600 止盈点数(600=60点)
MagicNumber 任意 20240601 区分不同EA的订单标识
UseTrailingStop true/false true 是否启用移动止损
TrailingStart 100-300 200 盈利多少点后启动移动止损
TrailingStep 25-100 50 止损线与当前价的距离
Slippage 1-10 3 允许的最大滑点

安装与使用步骤

1. 保存源码为 DualMACrossover.mq4 到 MQL4/Experts/ 文件夹
2. 编译:在MetaEditor中按F7编译
3. 加载到图表:拖拽EA到任意货币对图表
4. 设置参数:在输入参数标签页调整
5. 开启自动交易:点击工具栏绿色播放按钮

推荐测试: 在EURUSD或GBPUSD上运行,M15或H1周期,至少2年回测数据。

品种优化建议

针对不同品种的参数推荐:

品种 快均线 慢均线 ATR倍数 止损点数
EURUSD(欧美) 10 30 1.5 300
GBPUSD(镑美) 8 25 1.8 400
USDJPY(美日) 12 40 1.3 250
XAUUSD(黄金) 14 50 2.0 800

源码学习要点

本代码涵盖了EA编程的核心知识点:

· iMA() – 移动平均线指标调用
· iATR() – ATR波动率指标
· OrdersTotal()循环 – 持仓管理
· OrderSend() – 开仓
· OrderClose() – 平仓
· OrderModify() – 修改止损止盈(移动止损)
· 新K线检测 – 避免同一K线重复触发信号

想要更多高级EA?

本双均线EA是基础的入门策略。我们还有专业级EA(多周期确认、新闻过滤器、网格恢复、AI参数优化),欢迎订阅获取更多EA源码和交易策略。

参考来源: 自主编译,基于经典双均线交叉交易策略

```