MT5指标编译通过 · EX5 32KB 自动发布 7 0

EMA三线+随机指标交叉EA

taiyu1983·1 天前发布

EMA49/89金叉死叉定方向,价格穿EMA20配合随机指标上涨下跌入场,可调止盈止损

EMA三线+随机指标交叉EA

MT5 真机运行截图 · 服务器把编译好的 EX5 挂到黄金 H1 图表上截的,你装上去看到的就是这个样子

挂到 MT5 上运行时终端报了错

编译通过了,但真挂到图表上时终端记录了下面的错误。指标一报错就会被终端停掉,图上可能只剩半截线甚至一片空白—— 这就是「装上去和预期不一样」的原因。把报错连同代码丢给 AI 工作台,让它改好重新发布,截图会自动更新。

指标没能挂到图表上(指标加载失败 错误 4802),截图里没有它
EMA_Stoch_CrossEA.mq5222 行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#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());
   }
}
MT5 运行截图 · 完整视图带价格轴和时间轴的整张图表(约 150 根 H1 K 线),上面的封面是它最近 80 根 K 线的放大视图
EMA三线+随机指标交叉EA 在 MT5 上的真实截图

作品说明

这是一个完整的自动交易EA,核心逻辑是:用EMA49/89金叉死叉判断大方向,用价格穿EMA20+随机指标确认进场,带可调止盈止损。

使用说明

  1. 安装方法:将代码保存为 .mq5 文件,放入 MT5 的 MQL5/Experts 目录,编译后拖到图表上,在"算法交易"按钮打开、允许自动交易的情况下运行。
  1. 策略逻辑:
  • 方向过滤:EMA49在EMA89上方时只做多,下方时只做空
  • 入场触发:价格收盘穿过EMA20(多单向上穿、空单向下穿)
  • 确认信号:随机指标必须和方向一致(做多时上涨、做空时下跌)
  1. 参数调整:
  • EMA周期:默认20/49/89,可改为13/34/89等其他组合
  • 随机指标:标准(9,5,3),反应更快可用(5,3,3)
  • 止损止盈:按点数设置,黄金500点约5美元,根据资金和周期调整;设为0则不带止损止盈
  1. 风险控制:
  • 默认每次只开一单,有持仓时不再加仓
  • 止损点数建议:M5周期300-500点,M15周期500-800点,H1周期800-1500点
  • 手数根据账户资金调整,建议每1000美元不超过0.01手
  1. 回测建议:
  • 先用历史数据测试至少3个月,观察胜率和最大回撤
  • 重点关注震荡行情表现,该策略在单边趋势中表现较好,震荡市可能频繁止损
  1. 注意事项:
  • 必须在允许自动交易的环境运行
  • 需保持MT5终端开启,或使用VPS挂机
  • 每次改参数后重新回测验证
  1. 优化方向:可增加时间过滤(避开重要数据公布时段)、加大止盈倍数(如止盈=止损×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.

评论

后可以留言,比如反馈用着怎么样、想加什么功能。

还没有人评论,来抢个沙发。