# 均线交叉EA源码分享——一份完整的MQL4趋势策略(可编译)
本文提供一份功能完整的MT4智能交易系统源码,实现经典的双移动平均线交叉策略。代码采用MQL4编写,可直接编译,包含可配置的快慢均线参数、风险管理模块和交易过滤条件。适合希望学习EA自动化逻辑或搭建趋势策略的交易者参考。
策略逻辑说明
该EA基于两条简单移动平均线的交叉关系产生交易信号:
EA在开仓前会检查以下条件:
同时支持三种仓位计算方式:固定手数、按账户余额百分比风险计算。支持设置止损、止盈(点数),以及限制交易方向(只多、只空、多空均可)。
完整源码
将以下代码保存为 `MACrossover_EA.mq4`,放入MT4的 `MQL4/Experts/` 文件夹,然后在MetaEditor中编译即可。
```mql4
//+------------------------------------------------------------------+
//| MACrossover_EA.mq4 |
//| 基于双均线交叉逻辑 |
//+------------------------------------------------------------------+
#property copyright "ForexEA Strategy"
#property version "1.00"
#property strict
//--- 输入参数
input double InpLotSize = 0.1; // 固定手数(当RiskPercent=0时生效)
input double InpRiskPercent = 2.0; // 单笔风险比例(%账户净值)
input int InpFastMAPeriod = 9; // 快均线周期
input int InpSlowMAPeriod = 21; // 慢均线周期
input int InpStopLoss = 300; // 止损点数
input int InpTakeProfit = 600; // 止盈点数
input int InpMagicNumber = 202606; // EA唯一标识号
input int InpMaxSpread = 30; // 允许最大点差(点数)
input int InpMinBars = 50; // 最小K线数量
input int InpTradeDirection = 2; // 交易方向: 0=多空均可,1=只多,2=只空
//--- 全局变量
double fastMA_prev, fastMA_curr;
double slowMA_prev, slowMA_curr;
int slip = 30; // 滑点(点数)
//+------------------------------------------------------------------+
//| 初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
if(InpFastMAPeriod >= InpSlowMAPeriod)
{
Print("错误: 快均线周期必须小于慢均线周期");
return(INIT_PARAMETERS_INCORRECT);
}
if(InpStopLoss < 0 || InpTakeProfit < 0)
{
Print("止损和止盈不能为负数");
return(INIT_PARAMETERS_INCORRECT);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 反初始化函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Tick事件函数 |
//+------------------------------------------------------------------+
void OnTick()
{
//--- 检查K线数量是否足够
if(Bars(_Symbol, PERIOD_CURRENT) < InpMinBars)
{
Comment("K线数量不足: ", Bars(_Symbol, PERIOD_CURRENT));
return;
}
//--- 检查点差是否过大
if((MarketInfo(_Symbol, MODE_SPREAD) * Point) * 10000 > InpMaxSpread)
{
Comment("点差过大: ", MarketInfo(_Symbol, MODE_SPREAD));
return;
}
//--- 计算当前和前一根K线的均线值
fastMA_curr = iMA(_Symbol, PERIOD_CURRENT, InpFastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
fastMA_prev = iMA(_Symbol, PERIOD_CURRENT, InpFastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
slowMA_curr = iMA(_Symbol, PERIOD_CURRENT, InpSlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
slowMA_prev = iMA(_Symbol, PERIOD_CURRENT, InpSlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
//--- 检查是否已有持仓
if(CountPositions() > 0)
return;
//--- 信号判断:均线交叉
bool buySignal = (fastMA_prev <= slowMA_prev && fastMA_curr > slowMA_curr);
bool sellSignal = (fastMA_prev >= slowMA_prev && fastMA_curr < slowMA_curr);
//--- 根据交易方向过滤信号
if(InpTradeDirection == 1) sellSignal = false; // 只多模式,禁止做空
if(InpTradeDirection == 2) buySignal = false; // 只空模式,禁止做多
//--- 计算实际开仓手数
double lot = CalculateLotSize();
//--- 执行开仓
if(buySignal)
{
OpenOrder(OP_BUY, lot);
}
else if(sellSignal)
{
OpenOrder(OP_SELL, lot);
}
//--- 图表显示当前均线值和手数
Comment("快均线: ", DoubleToStr(fastMA_curr, _Digits),
"\n慢均线: ", DoubleToStr(slowMA_curr, _Digits),
"\n开仓手数: ", lot);
}
//+------------------------------------------------------------------+
//| 统计当前持仓数量 |
//+------------------------------------------------------------------+
int CountPositions()
{
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == _Symbol && OrderMagicNumber() == InpMagicNumber)
count++;
}
}
return(count);
}
//+------------------------------------------------------------------+
//| 根据风险比例或固定手数计算开仓手数 |
//+------------------------------------------------------------------+
double CalculateLotSize()
{
if(InpRiskPercent <= 0)
return(InpLotSize);
double riskMoney = AccountBalance() * InpRiskPercent / 100.0;
double stopPoints = InpStopLoss;
if(stopPoints <= 0)
return(InpLotSize);
double tickValue = MarketInfo(_Symbol, MODE_TICKVALUE);
double lotStep = MarketInfo(_Symbol, MODE_LOTSTEP);
double minLot = MarketInfo(_Symbol, MODE_MINLOT);
double maxLot = MarketInfo(_Symbol, MODE_MAXLOT);
double calculatedLot = riskMoney / (stopPoints * tickValue);
calculatedLot = MathFloor(calculatedLot / lotStep) * lotStep;
calculatedLot = MathMax(minLot, MathMin(maxLot, calculatedLot));
return(calculatedLot);
}
//+------------------------------------------------------------------+
//| 开仓函数 |
//+------------------------------------------------------------------+
void OpenOrder(int cmd, double lot)
{
double price, slPrice = 0, tpPrice = 0;
int slippage = slip;
if(cmd == OP_BUY)
{
price = Ask;
if(InpStopLoss > 0) slPrice = price - InpStopLoss * Point;
if(InpTakeProfit > 0) tpPrice = price + InpTakeProfit * Point;
}
else if(cmd == OP_SELL)
{
price = Bid;
if(InpStopLoss > 0) slPrice = price + InpStopLoss * Point;
if(InpTakeProfit > 0) tpPrice = price - InpTakeProfit * Point;
}
else return;
int ticket = OrderSend(_Symbol, cmd, lot, price, slippage, slPrice, tpPrice, "MA Crossover EA", InpMagicNumber, 0, clrNONE);
if(ticket < 0)
Print("开仓失败, 错误码: ", GetLastError());
else
Print("开仓成功, 订单号: ", ticket);
}
//+------------------------------------------------------------------+
```
参数详细说明
| 参数 | 说明 |
|------|------|
| InpLotSize | 固定手数,当风险比例 ≤ 0 时使用 |
| InpRiskPercent | 单笔交易占账户净值的风险百分比,根据止损点数自动计算手数 |
| InpFastMAPeriod | 快移动平均线周期 |
| InpSlowMAPeriod | 慢移动平均线周期 |
| InpStopLoss | 止损距离(点数) |
| InpTakeProfit | 止盈距离(点数) |
| InpMagicNumber | EA的唯一标识符,用于区分不同EA的订单 |
| InpMaxSpread | 允许的最大点差(点数),超过此值不开仓 |
| InpMinBars | 开仓前要求图表已加载的最小K线数量 |
| InpTradeDirection | 交易方向限制:0=多空均可,1=只做多,2=只做空 |
编译与安装步骤
1. 打开MT4,点击顶部菜单 工具 → MetaQuotes语言编辑器
2. 在左侧导航栏找到 Experts 文件夹,右键选择 新建 → 智能交易系统
3. 删除默认生成的全部代码,将本文的完整代码粘贴进去
4. 按 F7 或点击工具栏的 编译 按钮
5. 如果下方输出窗口无红色错误提示,说明编译成功
6. 返回MT4主界面,在导航器 → 智能交易系统中找到 `MACrossover_EA`
7. 拖拽到任意图表上,勾选“允许实时自动交易”,设置参数后点击确定
各品种优化参考值
| 品种 | 快均线 | 慢均线 | 止损点数 | 止盈点数 |
|------|--------|--------|----------|----------|
| XAUUSD(黄金) | 14 | 28 | 800 | 1600 |
| EURUSD | 9 | 21 | 250 | 500 |
| GBPUSD | 10 | 30 | 350 | 700 |
| USDJPY | 12 | 24 | 300 | 600 |
注意: 以上参数仅为参考,使用前请务必在对应品种和周期上进行回测验证。建议回测建模质量至少达到90%。
常见问题与调试
EA没有开仓,可能原因:
查看错误日志:
更进一步
均线交叉EA是趋势跟踪策略的经典入门模板。我们提供的专业版EA在此基础上增加了多周期确认、新闻过滤器、AI动态参数优化等功能,并针对黄金(XAUUSD)做了大量底层优化。
欢迎访问我们的官网,了解更多经过实盘验证的黄金EA产品。
---
参考来源:
1. MQL4官方文档 – iMA() 函数说明
2. MetaQuotes – OrderSend() 参数详解
3. 本文源码经MT4 build 1420+ 编译及基础测试
```