EMA三线+随机指标交叉EA
EMA49/89金叉死叉定方向,价格穿EMA20配合随机指标上涨下跌入场,可调止盈止损
MT5 真机运行截图 · 服务器把编译好的 EX5 挂到黄金 H1 图表上截的,你装上去看到的就是这个样子
挂到 MT5 上运行时终端报了错
编译通过了,但真挂到图表上时终端记录了下面的错误。指标一报错就会被终端停掉,图上可能只剩半截线甚至一片空白—— 这就是「装上去和预期不一样」的原因。把报错连同代码丢给 AI 工作台,让它改好重新发布,截图会自动更新。
指标没能挂到图表上(指标加载失败 错误 4802),截图里没有它
#property copyright "XAUOF指标工坊"
#property version "1.00"
#include <Trade\Trade.mqh>
//--- 可调参数
input group "===== 均线参数 ====="
input int EMA20_Period = 20; // 快速EMA周期(入场触发线)
input int EMA49_Period = 49; // 中期EMA周期(金叉死叉快线)
input int EMA89_Period = 89; // 长期EMA周期(金叉死叉慢线)
input group "===== 随机指标参数 ====="
input int Stoch_K = 9; // 随机指标K周期
input int Stoch_D = 5; // 随机指标D周期
input int Stoch_Slowing = 3; // 随机指标慢化
input group "===== 交易设置 ====="
input double Lot_Size = 0.01; // 固定手数
input int Stop_Loss = 500; // 止损点数(0=不设止损)
input int Take_Profit = 1000; // 止盈点数(0=不设止盈)
input int Magic_Number = 202610; // EA魔术号
input string Trade_Comment = "EMA_Stoch"; // 订单注释
//--- 全局变量
CTrade trade;
int ema20_handle, ema49_handle, ema89_handle, stoch_handle;
double ema20[], ema49[], ema89[];
double stoch_main[], stoch_signal[];
datetime last_bar_time = 0; // 记录上一根K线时间,避免同一根K线重复开仓
//+------------------------------------------------------------------+
//| EA初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
// 设置交易对象属性
trade.SetExpertMagicNumber(Magic_Number);
trade.SetDeviationInPoints(30);
trade.SetTypeFilling(ORDER_FILLING_FOK);
// 创建三条EMA句柄
ema20_handle = iMA(_Symbol, PERIOD_CURRENT, EMA20_Period, 0, MODE_EMA, PRICE_CLOSE);
ema49_handle = iMA(_Symbol, PERIOD_CURRENT, EMA49_Period, 0, MODE_EMA, PRICE_CLOSE);
ema89_handle = iMA(_Symbol, PERIOD_CURRENT, EMA89_Period, 0, MODE_EMA, PRICE_CLOSE);
if(ema20_handle == INVALID_HANDLE || ema49_handle == INVALID_HANDLE || ema89_handle == INVALID_HANDLE)
{
Print("创建EMA句柄失败");
return INIT_FAILED;
}
// 创建随机指标句柄
stoch_handle = iStochastic(_Symbol, PERIOD_CURRENT, Stoch_K, Stoch_D, Stoch_Slowing, MODE_SMA, STO_LOWHIGH);
if(stoch_handle == INVALID_HANDLE)
{
Print("创建随机指标句柄失败");
return INIT_FAILED;
}
// 预分配数组
ArraySetAsSeries(ema20, true);
ArraySetAsSeries(ema49, true);
ArraySetAsSeries(ema89, true);
ArraySetAsSeries(stoch_main, true);
ArraySetAsSeries(stoch_signal, true);
Print("EA初始化成功:", _Symbol, " 手数=", Lot_Size, " 止损=", Stop_Loss, " 止盈=", Take_Profit);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| EA反初始化函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(ema20_handle != INVALID_HANDLE) IndicatorRelease(ema20_handle);
if(ema49_handle != INVALID_HANDLE) IndicatorRelease(ema49_handle);
if(ema89_handle != INVALID_HANDLE) IndicatorRelease(ema89_handle);
if(stoch_handle != INVALID_HANDLE) IndicatorRelease(stoch_handle);
Print("EA已停止");
}
//+------------------------------------------------------------------+
//| EA主循环函数 |
//+------------------------------------------------------------------+
void OnTick()
{
// 检查是否有新K线形成(避免同一根K线重复判断)
datetime current_bar_time = iTime(_Symbol, PERIOD_CURRENT, 0);
if(current_bar_time == last_bar_time)
return;
last_bar_time = current_bar_time;
// 等待指标数据准备好
if(BarsCalculated(ema20_handle) < 3 || BarsCalculated(ema49_handle) < 3 ||
BarsCalculated(ema89_handle) < 3 || BarsCalculated(stoch_handle) < 3)
return;
// 拷贝指标数据(最近3根K线:当前[0]、前一根[1]、前两根[2])
if(CopyBuffer(ema20_handle, 0, 0, 3, ema20) <= 0) return;
if(CopyBuffer(ema49_handle, 0, 0, 3, ema49) <= 0) return;
if(CopyBuffer(ema89_handle, 0, 0, 3, ema89) <= 0) return;
if(CopyBuffer(stoch_handle, 0, 0, 3, stoch_main) <= 0) return;
if(CopyBuffer(stoch_handle, 1, 0, 3, stoch_signal) <= 0) return;
// 获取当前K线和前一根K线的收盘价
double close_current = iClose(_Symbol, PERIOD_CURRENT, 1); // [1]是刚收盘的K线
double close_prev = iClose(_Symbol, PERIOD_CURRENT, 2); // [2]是它前面那根
// 判断当前是否已有持仓
if(HasPosition())
return; // 已有持仓就不再开新单
// ===== 判断大方向:EMA49和EMA89的金叉死叉 =====
bool is_golden_cross = (ema49[0] > ema89[0]); // EMA49在EMA89上方,金叉状态,只做多
bool is_death_cross = (ema49[0] < ema89[0]); // EMA49在EMA89下方,死叉状态,只做空
// ===== 判断随机指标方向 =====
// 上涨:快线在慢线上方,或者快线比前一根上升
bool stoch_rising = (stoch_main[0] > stoch_signal[0]) || (stoch_main[0] > stoch_main[1]);
// 下跌:快线在慢线下方,或者快线比前一根下降
bool stoch_falling = (stoch_main[0] < stoch_signal[0]) || (stoch_main[0] < stoch_main[1]);
// ===== 做多条件 =====
// 1. 金叉状态
// 2. K线收盘价从下方穿过EMA20(前一根在下方,当前在上方)
// 3. 随机指标在上涨
if(is_golden_cross)
{
bool price_cross_up = (close_prev <= ema20[1] && close_current > ema20[0]);
if(price_cross_up && stoch_rising)
{
OpenBuy();
return;
}
}
// ===== 做空条件 =====
// 1. 死叉状态
// 2. K线收盘价从上方穿过EMA20(前一根在上方,当前在下方)
// 3. 随机指标在下跌
if(is_death_cross)
{
bool price_cross_down = (close_prev >= ema20[1] && close_current < ema20[0]);
if(price_cross_down && stoch_falling)
{
OpenSell();
return;
}
}
}
//+------------------------------------------------------------------+
//| 检查是否已有持仓 |
//+------------------------------------------------------------------+
bool HasPosition()
{
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0)
{
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) == Magic_Number)
{
return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| 开多单 |
//+------------------------------------------------------------------+
void OpenBuy()
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = 0, tp = 0;
// 计算止损止盈价格
if(Stop_Loss > 0)
sl = NormalizeDouble(ask - Stop_Loss * _Point, _Digits);
if(Take_Profit > 0)
tp = NormalizeDouble(ask + Take_Profit * _Point, _Digits);
// 执行买入
if(trade.Buy(Lot_Size, _Symbol, ask, sl, tp, Trade_Comment))
{
Print("做多开仓成功:价格=", ask, " 止损=", sl, " 止盈=", tp);
}
else
{
Print("做多开仓失败,错误代码=", GetLastError());
}
}
//+------------------------------------------------------------------+
//| 开空单 |
//+------------------------------------------------------------------+
void OpenSell()
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = 0, tp = 0;
// 计算止损止盈价格
if(Stop_Loss > 0)
sl = NormalizeDouble(bid + Stop_Loss * _Point, _Digits);
if(Take_Profit > 0)
tp = NormalizeDouble(bid - Take_Profit * _Point, _Digits);
// 执行卖出
if(trade.Sell(Lot_Size, _Symbol, bid, sl, tp, Trade_Comment))
{
Print("做空开仓成功:价格=", bid, " 止损=", sl, " 止盈=", tp);
}
else
{
Print("做空开仓失败,错误代码=", GetLastError());
}
}作品说明
这是一个完整的自动交易EA,核心逻辑是:用EMA49/89金叉死叉判断大方向,用价格穿EMA20+随机指标确认进场,带可调止盈止损。
使用说明
- 安装方法:将代码保存为
.mq5文件,放入 MT5 的MQL5/Experts目录,编译后拖到图表上,在"算法交易"按钮打开、允许自动交易的情况下运行。
- 策略逻辑:
- 方向过滤:EMA49在EMA89上方时只做多,下方时只做空
- 入场触发:价格收盘穿过EMA20(多单向上穿、空单向下穿)
- 确认信号:随机指标必须和方向一致(做多时上涨、做空时下跌)
- 参数调整:
- EMA周期:默认20/49/89,可改为13/34/89等其他组合
- 随机指标:标准(9,5,3),反应更快可用(5,3,3)
- 止损止盈:按点数设置,黄金500点约5美元,根据资金和周期调整;设为0则不带止损止盈
- 风险控制:
- 默认每次只开一单,有持仓时不再加仓
- 止损点数建议:M5周期300-500点,M15周期500-800点,H1周期800-1500点
- 手数根据账户资金调整,建议每1000美元不超过0.01手
- 回测建议:
- 先用历史数据测试至少3个月,观察胜率和最大回撤
- 重点关注震荡行情表现,该策略在单边趋势中表现较好,震荡市可能频繁止损
- 注意事项:
- 必须在允许自动交易的环境运行
- 需保持MT5终端开启,或使用VPS挂机
- 每次改参数后重新回测验证
- 优化方向:可增加时间过滤(避开重要数据公布时段)、加大止盈倍数(如止盈=止损×2)提高盈亏比。
AI 解读根据源码逐行分析写成,供参考,以实际运行为准
这是什么
这是一个 MT5 自动交易 EA,核心思路是用三条 EMA 均线配合随机指标过滤进场。EMA49 和 EMA89 的金叉死叉决定做多还是做空,价格穿过 EMA20 时触发入场信号,随机指标的涨跌方向作为最后确认。每次只开一单,带固定点数的止损止盈,适合不想盯盘、希望跟趋势自动交易的场景。
逻辑原理
方向过滤:代码每根 K 线收盘后检查 EMA49 和 EMA89 的位置关系。EMA49 在 EMA89 上方时判定为金叉状态,只允许做多;EMA49 在 EMA89 下方时判定为死叉状态,只允许做空。
入场触发:用 EMA20 作为快速触发线。做多时,要求前一根 K 线收盘价在 EMA20 下方、当前 K 线收盘价穿到 EMA20 上方;做空时反过来,要求从上方穿到下方。
信号确认:随机指标(Stochastic)用来判断当前动能方向。做多时,要求随机指标的主线在信号线上方、或者主线比前一根上升;做空时,要求主线在信号线下方、或者主线比前一根下降。三个条件同时满足才下单。
止损止盈:开仓时按参数设置的点数计算固定止损和止盈价格。做多时止损在入场价下方、止盈在上方;做空时反过来。如果参数设为 0 就不带止损止盈,靠手动或其他逻辑平仓。
仓位控制:代码每次检查账户是否已有该 EA 开的持仓(通过魔术号识别),有持仓就不再开新单,避免加仓和重复信号。
参数说明
EMA20_Period(默认 20):快速 EMA 周期,价格穿过这条线时触发入场。周期越小反应越快,但假信号也多;周期大一些更稳但入场会晚。
EMA49_Period(默认 49)、EMA89_Period(默认 89):中长期 EMA,用来判断金叉死叉。经典组合是 50/100 或 49/89,也可以改成 34/89、55/144 等斐波那契数列组合。
Stoch_K(默认 9)、Stoch_D(默认 5)、Stoch_Slowing(默认 3):随机指标的三个周期参数,标准设置是 9/5/3。如果想更灵敏可以用 5/3/3,更平滑可以用 14/7/3。
Lot_Size(默认 0.01):每次开仓的固定手数。建议每 1000 美元本金不超过 0.01 手,根据账户资金和风险承受调整。
Stop_Loss(默认 500):止损点数,黄金 500 点约等于 5 美元。M5 周期建议 300-500 点,M15 周期 500-800 点,H1 周期 800-1500 点。设为 0 则不带止损。
Take_Profit(默认 1000):止盈点数,默认是止损的两倍,这样盈亏比是 1:2。可以根据回测结果调整,或者设为 0 不带止盈、靠均线反向穿越平仓。
Magic_Number(默认 202610):EA 的魔术号,用来区分不同 EA 开的单子。如果同一个账户跑多个 EA,每个 EA 要设不同的魔术号。
Trade_Comment(默认 "EMA_Stoch"):订单备注,方便在交易历史里识别这个 EA 开的单。
怎么用
把代码保存成 .mq5 文件,放到 MT5 数据文件夹的 MQL5/Experts 目录下,在 MT5 的 MetaEditor 里编译。编译成功后,从导航器窗口的"EA 交易"里把这个 EA 拖到图表上,弹出参数设置窗口,调整参数后点确定。图表右上角会出现 EA 的笑脸图标,确保"算法交易"按钮是打开的(工具栏上有个绿色的三角形按钮)。
EA 会在每根 K 线收盘时检查信号,满足条件就自动下单。开仓后可以在"交易"窗口看到持仓和止损止盈价格。EA 运行期间不要手动关掉自动交易按钮,也不要关闭 MT5 终端,否则 EA 会停止工作。如果需要 24 小时运行,建议用 VPS 挂机。
适用场景
这个 EA 的逻辑是跟趋势,适合有明显单边行情的品种和周期。黄金、原油、主要货币对(欧美、镑美)在 M15 到 H1 周期的趋势行情中表现较好。如果市场在震荡、EMA 频繁金叉死叉,或者价格在 EMA20 附近反复穿来穿去,EA 会连续开仓又止损,表现会很差。
不适合用在波动极小的品种(比如某些小币种交叉盘)或者超短周期(M1、M5 的噪音太多)。也不适合重大消息前后,因为价格可能瞬间穿过所有均线然后又反抽,触发信号后马上止损。
如果想在震荡行情里也能用,需要加时间过滤或者波动率过滤,只在趋势明确时开启 EA。
风险提示
滞后性:EMA 是滞后指标,尤其是 EMA89 这种长周期均线,金叉死叉的信号往往在趋势走了一段之后才出现。如果趋势很短,可能刚进场就反转。
假突破:价格穿 EMA20 后可能只是短暂的假突破,随机指标的方向判断也不能完全避免。震荡行情里会频繁触发信号又马上止损。
固定止损的局限:代码用的是固定点数止损,不会根据 ATR 或波动率调整。如果行情突然变得很猛,500 点的止损可能不够;如果行情变安静,500 点又太宽,会让盈亏比变差。
单一仓位:代码每次只开一单,不加仓也不网格,所以抓到大趋势时收益有限。如果想提高收益,要么加大手数(风险也加大),要么改代码加分批进场逻辑。
无时间和品种过滤:代码没有限制交易时间和品种,如果在低流动性时段(比如亚洲盘)或者点差很大的品种上跑,滑点和成本会吃掉很多利润。
回测时注意勾选"每个点位"模式,检查最大回撤和连续亏损次数。如果连续止损超过 5 次,说明参数不适合当前行情,需要暂停或调整。实盘前一定要先在模拟账户跑至少一周,确认 EA 没有逻辑错误和异常下单。
常见问题
- 这个 EA 会重绘或者未来函数吗
- 不会。代码用的是已经收盘的 K 线数据(iClose 的索引是 [1] 和 [2]),EMA 和随机指标也是用历史值计算,不会因为新 K 线改变之前的信号。回测结果和实盘逻辑一致。
- 可以用在黄金以外的品种吗
- 可以。代码没有限制品种,理论上任何 MT5 支持的交易品种都能用。但不同品种的波动特性不同,止损止盈的点数要根据品种调整。比如欧美货币对波动小,500 点止损可能太大;原油波动大,500 点可能不够。
- MT4 能用吗
- 不能直接用。这是 MQL5 代码,MT4 用的是 MQL4,语法和函数库不一样。如果要在 MT4 上用,需要把代码改写成 MQL4 版本,主要是指标句柄、订单函数、数组操作这些地方要改。
- 参数默认值适合什么周期
- 默认参数(EMA 20/49/89、随机指标 9/5/3、止损 500 点、止盈 1000 点)是按黄金 M15 到 H1 周期设计的。如果用在 M5 这种更短周期,止损止盈要缩小到 300/600 左右;如果用在 H4 或日线,要放大到 1500/3000 以上。具体数值要回测验证。
- 为什么有时候不开仓
- 可能是三个条件没同时满足。检查一下:1)EMA49 和 EMA89 是不是金叉或死叉状态;2)价格是不是刚穿过 EMA20(不是一直在上面或下面);3)随机指标的方向是不是和预期一致。另外如果账户已有持仓,EA 不会开新单。
EMA Triple Line + Stochastic Crossover EA for MT5
An automated trading EA that uses EMA49/89 crossover to determine trend direction, confirms entry with price crossing EMA20 and Stochastic momentum, includes adjustable stop-loss and take-profit, opens only one position at a time.
Source code is shown above. Compiled EX5 files are available to VIP members.
评论
还没有人评论,来抢个沙发。