EMA 金叉死叉 ATR 追踪止损 EA
快慢 EMA 交叉开仓,ATR 动态追踪止损,固定风险回报比止盈
相对上一版改了:刚才这份代码用 MetaEditor 编译没通过,报了 25 个错误: 第 2 行第 1 列:'strategy' - unexpected token, probably type is missing? 出错的那行代码:strategy("EMA金叉死叉追踪止损策略", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=100, initial_capital=10000, commission_type=strategy.commission.percent, commission_v
效果示意图 · AI 根据源码绘制,仅示意画了哪些元素,细节以实际运行为准
//+------------------------------------------------------------------+
//| 基于 XAUOF 社区作品 #8《EMA 金叉 + ATR 追踪止损策略》 |
//| (作者 XAUOF 官方)二次创作 |
//| 改动:从 Pine Script 翻译成 MQL5 EA,保留所有核心逻辑 |
//+------------------------------------------------------------------+
#property copyright "XAUOF 指标工坊"
#property version "1.00"
#property strict
#include <Trade\Trade.mqh>
//--- 输入参数
input int EmaFastPeriod = 9; // 快速 EMA 周期(推荐 9)
input int EmaSlowPeriod = 21; // 慢速 EMA 周期(推荐 21)
input int AtrPeriod = 14; // ATR 周期(推荐 14)
input double AtrMultiplier = 2.0; // ATR 止损倍数(推荐 1.5-3.0)
input double RiskRewardRatio = 2.0; // 风险回报比(止盈是止损的倍数,推荐 2.0-3.0)
input bool LongOnly = false; // 仅做多(true=只做多单,false=多空都做)
input double RiskPercent = 1.0; // 每单风险百分比(推荐 1-2%)
input int MagicNumber = 20241201; // EA 魔术编号(用于识别自己的订单)
input string TradeComment = "EMA_ATR"; // 订单备注
//--- 全局变量
CTrade trade;
int handleEmaFast, handleEmaSlow, handleAtr;
double emaFast[], emaSlow[], atrBuffer[];
//--- 持仓跟踪
double entryPrice = 0; // 入场价
double stopLoss = 0; // 当前止损价
double takeProfit = 0; // 止盈价
int positionType = 0; // 1=多头, -1=空头, 0=无持仓
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
trade.SetExpertMagicNumber(MagicNumber);
// 创建指标句柄
handleEmaFast = iMA(_Symbol, PERIOD_CURRENT, EmaFastPeriod, 0, MODE_EMA, PRICE_CLOSE);
handleEmaSlow = iMA(_Symbol, PERIOD_CURRENT, EmaSlowPeriod, 0, MODE_EMA, PRICE_CLOSE);
handleAtr = iATR(_Symbol, PERIOD_CURRENT, AtrPeriod);
if(handleEmaFast == INVALID_HANDLE || handleEmaSlow == INVALID_HANDLE || handleAtr == INVALID_HANDLE)
{
Print("指标句柄创建失败");
return INIT_FAILED;
}
// 设置数组为时间序列(索引 0 = 当前 K 线)
ArraySetAsSeries(emaFast, true);
ArraySetAsSeries(emaSlow, true);
ArraySetAsSeries(atrBuffer, true);
Print("EMA 金叉死叉 ATR 追踪止损 EA 初始化成功");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
IndicatorRelease(handleEmaFast);
IndicatorRelease(handleEmaSlow);
IndicatorRelease(handleAtr);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 检查是否有新 K 线
static datetime lastBar = 0;
datetime currentBar = iTime(_Symbol, PERIOD_CURRENT, 0);
bool isNewBar = (currentBar != lastBar);
if(isNewBar) lastBar = currentBar;
// 复制指标数据
if(CopyBuffer(handleEmaFast, 0, 0, 3, emaFast) < 3) return;
if(CopyBuffer(handleEmaSlow, 0, 0, 3, emaSlow) < 3) return;
if(CopyBuffer(handleAtr, 0, 0, 2, atrBuffer) < 2) return;
// 当前持仓状态
bool inLong = false, inShort = false;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber)
{
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) inLong = true;
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) inShort = true;
}
}
bool inPosition = inLong || inShort;
// 金叉信号(快线上穿慢线)
bool longSignal = (emaFast[0] > emaSlow[0] && emaFast[1] <= emaSlow[1]);
// 死叉信号(快线下穿慢线)
bool shortSignal = (emaFast[0] < emaSlow[0] && emaFast[1] >= emaSlow[1]);
//========== 开仓逻辑 ==========
if(isNewBar && !inPosition)
{
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double atr = atrBuffer[0];
// 多头开仓
if(longSignal)
{
entryPrice = currentPrice;
stopLoss = entryPrice - atr * AtrMultiplier;
takeProfit = entryPrice + (entryPrice - stopLoss) * RiskRewardRatio;
// 计算手数
double lots = CalculateLots(entryPrice - stopLoss);
if(lots > 0)
{
if(trade.Buy(lots, _Symbol, 0, stopLoss, takeProfit, TradeComment))
{
positionType = 1;
Print("多单开仓成功:入场价=", entryPrice, " 止损=", stopLoss, " 止盈=", takeProfit);
}
}
}
// 空头开仓
if(shortSignal && !LongOnly)
{
entryPrice = currentPrice;
stopLoss = entryPrice + atr * AtrMultiplier;
takeProfit = entryPrice - (stopLoss - entryPrice) * RiskRewardRatio;
// 计算手数
double lots = CalculateLots(stopLoss - entryPrice);
if(lots > 0)
{
if(trade.Sell(lots, _Symbol, 0, stopLoss, takeProfit, TradeComment))
{
positionType = -1;
Print("空单开仓成功:入场价=", entryPrice, " 止损=", stopLoss, " 止盈=", takeProfit);
}
}
}
}
//========== 追踪止损逻辑 ==========
if(inPosition)
{
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double atr = atrBuffer[0];
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber)
{
ulong ticket = PositionGetInteger(POSITION_TICKET);
double currentSL = PositionGetDouble(POSITION_SL);
double currentTP = PositionGetDouble(POSITION_TP);
// 多头追踪止损(止损只能上移)
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
double newStopLoss = currentPrice - atr * AtrMultiplier;
if(newStopLoss > currentSL && newStopLoss < currentPrice)
{
if(trade.PositionModify(ticket, newStopLoss, currentTP))
{
Print("多单止损上移至:", newStopLoss);
}
}
}
// 空头追踪止损(止损只能下移)
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{
double newStopLoss = currentPrice + atr * AtrMultiplier;
if(newStopLoss < currentSL && newStopLoss > currentPrice)
{
if(trade.PositionModify(ticket, newStopLoss, currentTP))
{
Print("空单止损下移至:", newStopLoss);
}
}
}
}
}
}
// 平仓后重置状态
if(!inPosition && positionType != 0)
{
positionType = 0;
entryPrice = 0;
stopLoss = 0;
takeProfit = 0;
}
}
//+------------------------------------------------------------------+
//| 计算手数(基于固定风险百分比) |
//+------------------------------------------------------------------+
double CalculateLots(double riskDistance)
{
if(riskDistance <= 0) return 0;
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskAmount = balance * RiskPercent / 100.0;
// 每点价值
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
// 风险距离对应的点数
double points = riskDistance / _Point;
// 计算手数
double lots = riskAmount / (points * tickValue / tickSize);
// 规范化手数
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double stepLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
lots = MathFloor(lots / stepLot) * stepLot;
lots = MathMax(lots, minLot);
lots = MathMin(lots, maxLot);
return lots;
}
//+------------------------------------------------------------------+作品说明
明白了,原始代码是 Pine Script(TradingView 的语言),但你要在 MetaTrader 5 上编译,所以报错了。我现在把它翻译成 MQL5 版本的 EA,保留原作的 EMA 金叉死叉 + ATR 追踪止损逻辑,改成能在 MT5 上直接编译运行的自动交易程序。
相对原作改动:
- 从 Pine Script 语法翻译成 MQL5 语法
- 保留所有参数:快慢 EMA 周期、ATR 周期和倍数、风险回报比、仅做多开关、每单风险百分比
- 用 CTrade 类实现开仓、追踪止损、止盈逻辑
- 追踪止损机制:多头止损只能上移、空头止损只能下移
- 仓位计算:根据风险百分比和 ATR 止损距离动态计算手数
使用说明
安装步骤:
- 打开 MetaEditor,新建 Expert Advisor 文件
- 把代码复制进去,保存为
ema_crossover_atr_trailing_stop_ea.mq5 - 点击编译,确保 0 错误 0 警告
- 在 MT5 图表上右键 → EA 交易 → 选择这个 EA 拖到图表上
参数调整:
- 快慢 EMA 周期:默认 9/21,适合短周期趋势;长周期可用 20/50
- ATR 倍数:默认 2.0,越大止损越宽容,越小越紧
- 风险回报比:默认 2.0,即止盈距离是止损的 2 倍
- 每单风险:默认 1%,保守账户用 0.5%,激进可到 2%
- 仅做多:黄金牛市时可打开,只做多单
信号逻辑:
- 开仓:快线上穿慢线做多,下穿做空,每次只开一单
- 止损:入场时设置初始止损 = 当前价 ± ATR × 倍数
- 追踪:价格有利方向移动后,止损自动跟进(多头上移、空头下移)
- 止盈:固定止盈位 = 入场价 + 止损距离 × 风险回报比
注意事项:
- 回测时打开"每笔分时"模式,避免虚假信号
- 滑点大的品种(如黄金)建议手动设置滑点容忍度
- EA 只在新 K 线出现时检测信号,避免同一根 K 线反复开仓
- 实盘前先用模拟账户测试一周,确认逻辑符合预期
- 震荡行情会频繁止损,适合趋势明显的时段
AI 解读根据源码逐行分析写成,供参考,以实际运行为准
这是什么
这是一个基于均线交叉的趋势跟踪 EA,用快慢 EMA 的金叉死叉判断方向,入场后用 ATR(平均真实波幅)动态调整止损位,跟着价格走。它会自动算仓位大小,每单风险固定在账户余额的百分比,省去手动计算。适合想让程序代跑趋势策略的交易者。
逻辑原理
进场信号: 快速 EMA(默认 9 周期)上穿慢速 EMA(默认 21 周期)时做多,下穿时做空。EA 只在新 K 线出现时检测交叉,避免同一根 K 线反复开仓,同时只持有一单。
止损计算: 入场瞬间用当前 ATR(默认 14 周期)乘以倍数(默认 2.0)算出止损距离,多头止损设在入场价下方,空头止损设在上方。
追踪止损: 每个 Tick 检查一次,如果价格朝有利方向移动,止损就跟着走。多头的止损只能往上移(永远不回撤),空头的止损只能往下移。移动规则是:新止损 = 当前价 ± ATR × 倍数,前提是新止损比旧止损更优。
止盈位置: 固定不动,入场时就算好:止盈距离 = 止损距离 × 风险回报比(默认 2.0)。意思是如果你愿意亏 10 美元,就瞄准赚 20 美元。
仓位管理: 每次开仓前,用账户余额乘以风险百分比(默认 1%),除以止损距离对应的点数价值,算出这次该开多少手。止损越宽、手数越小,反之越大。
参数说明
- EmaFastPeriod(9): 快速 EMA 的周期。数字越小越灵敏,越大越平滑。短周期用 5-12,长周期用 12-20。
- EmaSlowPeriod(21): 慢速 EMA 的周期。常见组合有 9/21、12/26、20/50。快慢差距越大,信号越少但越可靠。
- AtrPeriod(14): 计算 ATR 的 K 线根数。14 是经典值,波动大的品种可以用 10,求稳用 20。
- AtrMultiplier(2.0): ATR 乘几倍当止损距离。1.5 倍止损紧,容易被扫;3.0 倍止损宽,能扛回调但盈亏比变差。
- RiskRewardRatio(2.0): 止盈是止损的几倍。2.0 就是盈亏比 1:2,激进可以用 1.5,保守用 3.0。
- LongOnly(false): 打开后只做多单,关闭则多空都做。牛市品种可以开启。
- RiskPercent(1.0): 每单愿意亏掉账户余额的百分比。1% 是标准风控,保守用 0.5%,激进最多 2%。
- MagicNumber(20241201): EA 识别自己订单的编号,同一账户跑多个 EA 时要改成不同值。
- TradeComment(EMA_ATR): 订单备注,在历史记录里能看到。
怎么用
把代码复制到 MetaEditor 里,另存为 .mq5 文件,点编译。编译成功后,在 MT5 的导航器窗口找到这个 EA,拖到任意图表上。弹出参数框时调整参数,勾选"允许自动交易",点确定。图表右上角出现笑脸表情说明 EA 在跑。
信号在图表上看不到,EA 是直接开仓的。开仓后能在"交易"选项卡看到持仓,止损和止盈线会显示在图表上。止损线会随 K 线更新慢慢移动。到止损或止盈就自动平仓,然后等下一个交叉信号。
适合挂在 H1(1 小时)或 H4(4 小时)周期,日内交易者可以试 M15 或 M30。品种选波动稳定、点差低的,黄金、欧美、镑美都行。
适用场景
适合: 趋势明显的单边行情,尤其是黄金、原油、主要外汇对的突破阶段。默认参数(9/21 EMA + 2 倍 ATR)在 H1 周期表现较稳,能吃到中级趋势的中段利润。长周期(H4、D1)可以用 20/50 EMA 组合,过滤掉更多噪音。
品种: 代码没有限制交易品种,但点差太大的(如某些小币种)会被滑点吃掉利润。波动太小的(如 USDCNY)ATR 会很窄,止损止盈都挤在一起。
不适合: 震荡盘整、窄幅波动、假突破多的行情。EMA 交叉是滞后信号,行情走出来才反应,震荡市里快慢线反复缠绕会不断开平仓。
风险提示
滞后性: EMA 是均线,价格拐头后要等几根 K 线才能交叉,入场点往往不是最优的起涨点。趋势走了一半才上车,回调时容易被追踪止损扫出来。
假信号: 震荡行情里 EMA 会频繁金叉死叉,每次信号都开仓就会连续止损。代码里没有 ADX 或波动率过滤,无法识别行情是否适合交易。
追踪止损风险: ATR 是平均波动,不代表瞬时回调幅度。消息行情或闪崩时,价格可能瞬间打穿追踪止损,实际成交价比设定价差很多。代码里没有设置滑点容忍度,MT5 默认会以任意滑点成交。
仓位计算依赖 ATR: 如果 ATR 突然暴涨(比如非农夜),算出的手数会变得很小,错过行情;ATR 很小时手数可能超出账户承受能力。
无时间过滤: 代码 24 小时运行,不管亚盘美盘。某些时段流动性差、点差变宽,不适合交易。
回测陷阱: 如果用"开盘价"模式回测,交叉信号会提前触发,实盘对不上。必须用"每笔分时"或"真实报价"模式。
常见问题
- 这个 EA 会重绘吗?
- 不会。EMA 和 ATR 都是确定性指标,历史数据不会变。EA 只在新 K 线收盘后检测交叉,信号是固定的。
- 默认参数适合什么周期?
- 9/21 周期的 EMA 组合适合 H1 和 H4 周期,偏短线。如果用 D1 日线建议改成 20/50,过滤掉日内噪音。
- 震荡行情会不会频繁止损?
- 会。EMA 交叉在盘整时会反复触发,每次都止损出场。代码里没有过滤震荡的逻辑,需要手动判断行情或加上 ADX 条件。
- 可以同时在多个品种上运行吗?
- 可以。每个图表拖一个 EA 实例,魔术编号用同一个也行,它按品种符号区分订单。但要注意总仓位,多品种同时跑会叠加风险。
- 止盈可以改成追踪止盈吗?
- 代码里是固定止盈,不会移动。如果想改成追踪止盈,需要修改 OnTick 里的止盈逻辑,参考追踪止损的写法。
EMA Crossover with ATR Trailing Stop EA for MT5
An automated trading system that enters on fast/slow EMA crossovers, sets initial stop-loss based on ATR multiples, and trails the stop dynamically as price moves favorably. Position size is calculated from account risk percentage.
Source code is shown above. Compiled EX5 files are available to VIP members.
评论
还没有人评论,来抢个沙发。