MT4EA / 策略编译通过 · EX4 14KB 11 10

RSI 超卖回归 EA(MT4)

XAUOF 官方·1 小时前发布

RSI 超卖且价格在长期均线上方时做多,固定止损止盈,带每日单数限制

RSI 超卖回归 EA(MT4)
EMA_RSI_Reversal_EA.mq4325
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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
//+------------------------------------------------------------------+
//| EMA趋势过滤 + RSI反转EA                                              |
//| 只在新K线开盘时判断信号,支持4位/5位报价                                  |
//+------------------------------------------------------------------+

#property copyright "Kiro MQL4 EA Generator"
#property link      ""
#property version   "1.00"
#property strict

//--- 可调参数
input int      RSI_Period = 14;              // RSI周期
input double   RSI_Oversold = 30.0;          // RSI超卖阈值(做多信号)
input double   RSI_Overbought = 70.0;        // RSI超买阈值(做空信号)
input int      EMA_Period = 200;             // EMA周期(趋势过滤)
input double   LotSize = 0.1;                // 固定手数
input int      StopLossPips = 50;            // 止损点数(pips)
input double   TakeProfitMultiplier = 1.5;   // 止盈倍数(相对止损)
input int      MagicNumber = 20250106;       // 魔术号
input int      MaxPositions = 1;             // 同时最多持仓数
input int      MaxOrdersPerDay = 5;          // 每天最多下单数
input int      Slippage = 3;                 // 滑点(pips)

//--- 全局变量
datetime LastBarTime = 0;                    // 上一根K线的时间,用于判断新K线
int      OrderCountToday = 0;                // 今日已下单数
int      LastTradeDay = 0;                   // 上次交易日期(DayOfYear)

//+------------------------------------------------------------------+
//| EA初始化函数                                                        |
//+------------------------------------------------------------------+
int OnInit()
{
   // 参数合法性检查
   if(RSI_Period < 2 || RSI_Period > 100)
   {
      Alert("RSI周期必须在2到100之间");
      return(INIT_PARAMETERS_INCORRECT);
   }
   if(RSI_Oversold >= RSI_Overbought)
   {
      Alert("RSI超卖阈值必须小于超买阈值");
      return(INIT_PARAMETERS_INCORRECT);
   }
   if(EMA_Period < 2 || EMA_Period > 500)
   {
      Alert("EMA周期必须在2到500之间");
      return(INIT_PARAMETERS_INCORRECT);
   }
   if(LotSize <= 0)
   {
      Alert("手数必须大于0");
      return(INIT_PARAMETERS_INCORRECT);
   }
   if(StopLossPips <= 0)
   {
      Alert("止损点数必须大于0");
      return(INIT_PARAMETERS_INCORRECT);
   }
   if(TakeProfitMultiplier <= 0)
   {
      Alert("止盈倍数必须大于0");
      return(INIT_PARAMETERS_INCORRECT);
   }
   
   // 初始化上一根K线时间
   LastBarTime = Time[0];
   
   // 初始化今日交易计数
   LastTradeDay = DayOfYear();
   OrderCountToday = 0;
   
   Print("EA初始化成功 - ", Symbol(), " M", Period());
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| EA反初始化函数                                                      |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   Print("EA已停止,原因代码: ", reason);
}

//+------------------------------------------------------------------+
//| EA主函数                                                           |
//+------------------------------------------------------------------+
void OnTick()
{
   // 1. 检查是否是新K线
   if(Time[0] == LastBarTime)
      return;  // 不是新K线,直接返回
   
   LastBarTime = Time[0];  // 更新上一根K线时间
   
   // 2. 重置每日交易计数
   int currentDay = DayOfYear();
   if(currentDay != LastTradeDay)
   {
      OrderCountToday = 0;
      LastTradeDay = currentDay;
      Print("新交易日开始,重置今日下单计数");
   }
   
   // 3. 检查每日下单限制
   if(OrderCountToday >= MaxOrdersPerDay)
   {
      return;  // 今日已达到最大下单数
   }
   
   // 4. 检查当前持仓数
   int currentPositions = CountMyPositions();
   if(currentPositions >= MaxPositions)
   {
      return;  // 已达到最大持仓数
   }
   
   // 5. 计算指标值(需要足够的历史数据)
   if(Bars < EMA_Period + RSI_Period + 10)
   {
      Print("历史数据不足,等待更多K线");
      return;
   }
   
   // 当前K线(索引1,已完成的K线)的RSI和EMA
   double rsi_current = iRSI(Symbol(), 0, RSI_Period, PRICE_CLOSE, 1);
   double rsi_previous = iRSI(Symbol(), 0, RSI_Period, PRICE_CLOSE, 2);
   double ema_current = iMA(Symbol(), 0, EMA_Period, 0, MODE_EMA, PRICE_CLOSE, 1);
   double price_current = Close[1];
   
   // 6. 信号判断
   bool buySignal = false;
   bool sellSignal = false;
   
   // 做多信号:价格在EMA200上方 且 RSI从30以下回升到30以上
   if(price_current > ema_current)
   {
      if(rsi_previous < RSI_Oversold && rsi_current >= RSI_Oversold)
      {
         buySignal = true;
      }
   }
   
   // 做空信号:价格在EMA200下方 且 RSI从70以上回落到70以下
   if(price_current < ema_current)
   {
      if(rsi_previous > RSI_Overbought && rsi_current <= RSI_Overbought)
      {
         sellSignal = true;
      }
   }
   
   // 7. 执行交易
   if(buySignal)
   {
      OpenBuyOrder();
   }
   else if(sellSignal)
   {
      OpenSellOrder();
   }
}

//+------------------------------------------------------------------+
//| 统计当前持仓数(仅统计本EA的单子)                                      |
//+------------------------------------------------------------------+
int CountMyPositions()
{
   int count = 0;
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
         {
            count++;
         }
      }
   }
   return count;
}

//+------------------------------------------------------------------+
//| 开多单                                                             |
//+------------------------------------------------------------------+
void OpenBuyOrder()
{
   // 计算止损止盈价格
   double sl = 0, tp = 0;
   CalculateSLTP(OP_BUY, sl, tp);
   
   // 当前卖价(买入用Ask)
   double price = Ask;
   
   // 转换滑点(适配4位/5位报价)
   int slippage = NormalizeSlippage(Slippage);
   
   // 下单
   int ticket = OrderSend(Symbol(), OP_BUY, LotSize, price, slippage, sl, tp, 
                          "EMA_RSI_Buy", MagicNumber, 0, clrBlue);
   
   if(ticket > 0)
   {
      Print("多单开仓成功,订单号: ", ticket, " 价格: ", price, " SL: ", sl, " TP: ", tp);
      OrderCountToday++;
   }
   else
   {
      int error = GetLastError();
      Print("多单开仓失败,错误码: ", error, " ", ErrorDescription(error));
   }
}

//+------------------------------------------------------------------+
//| 开空单                                                             |
//+------------------------------------------------------------------+
void OpenSellOrder()
{
   // 计算止损止盈价格
   double sl = 0, tp = 0;
   CalculateSLTP(OP_SELL, sl, tp);
   
   // 当前买价(卖出用Bid)
   double price = Bid;
   
   // 转换滑点(适配4位/5位报价)
   int slippage = NormalizeSlippage(Slippage);
   
   // 下单
   int ticket = OrderSend(Symbol(), OP_SELL, LotSize, price, slippage, sl, tp, 
                          "EMA_RSI_Sell", MagicNumber, 0, clrRed);
   
   if(ticket > 0)
   {
      Print("空单开仓成功,订单号: ", ticket, " 价格: ", price, " SL: ", sl, " TP: ", tp);
      OrderCountToday++;
   }
   else
   {
      int error = GetLastError();
      Print("空单开仓失败,错误码: ", error, " ", ErrorDescription(error));
   }
}

//+------------------------------------------------------------------+
//| 计算止损止盈价格                                                    |
//+------------------------------------------------------------------+
void CalculateSLTP(int orderType, double &sl, double &tp)
{
   double point = Point;
   
   // 适配5位报价(JPY货币对除外)
   if(Digits == 5 || Digits == 3)
   {
      point = point * 10;
   }
   
   double slDistance = StopLossPips * point;
   double tpDistance = StopLossPips * TakeProfitMultiplier * point;
   
   if(orderType == OP_BUY)
   {
      sl = NormalizeDouble(Bid - slDistance, Digits);
      tp = NormalizeDouble(Bid + tpDistance, Digits);
   }
   else if(orderType == OP_SELL)
   {
      sl = NormalizeDouble(Ask + slDistance, Digits);
      tp = NormalizeDouble(Ask - tpDistance, Digits);
   }
}

//+------------------------------------------------------------------+
//| 适配滑点(4位/5位报价)                                              |
//+------------------------------------------------------------------+
int NormalizeSlippage(int slippagePips)
{
   if(Digits == 5 || Digits == 3)
   {
      return slippagePips * 10;
   }
   return slippagePips;
}

//+------------------------------------------------------------------+
//| 错误码描述(简化版)                                                 |
//+------------------------------------------------------------------+
string ErrorDescription(int errorCode)
{
   switch(errorCode)
   {
      case 0:    return "无错误";
      case 1:    return "无错误,但结果未知";
      case 2:    return "通用错误";
      case 3:    return "无效参数";
      case 4:    return "交易服务器繁忙";
      case 5:    return "旧版本客户端";
      case 6:    return "无法连接到交易服务器";
      case 7:    return "没有足够的权限";
      case 8:    return "请求太频繁";
      case 9:    return "不允许的操作扰乱了交易";
      case 64:   return "账户被禁用";
      case 65:   return "无效账户";
      case 128:  return "交易超时";
      case 129:  return "无效价格";
      case 130:  return "无效止损";
      case 131:  return "无效交易量";
      case 132:  return "市场关闭";
      case 133:  return "交易被禁止";
      case 134:  return "资金不足";
      case 135:  return "价格改变";
      case 136:  return "无报价";
      case 137:  return "经纪商繁忙";
      case 138:  return "重新报价";
      case 139:  return "订单被锁定";
      case 140:  return "只允许买入";
      case 141:  return "请求太多";
      case 145:  return "由于价格接近市场,修改被拒绝";
      case 146:  return "交易子系统繁忙";
      case 147:  return "使用过期价格";
      case 148:  return "订单价格与Bid/Ask相差太远";
      default:   return "未知错误";
   }
}
//+------------------------------------------------------------------+

作品说明

策略思路

本 EA 采用趋势+超跌超买反转的组合逻辑:用 EMA200 判断主趋势方向,用 RSI(14) 的回升/回落作为入场信号。价格在 EMA200 上方只做多,等待 RSI 从超卖区(<30)回升突破 30 时开多单;价格在 EMA200 下方只做空,等待 RSI 从超买区(>70)回落跌破 70 时开空单。止损止盈采用固定点数,支持 4/5 位报价自动适配。新 K 线开盘时才检测信号,避免同一根 K 线重复开仓。设置了每日最大下单数和最大持仓数限制,防止过度交易。

使用说明

  1. 安装方法
  • 将代码保存为 EMA_RSI_Reversal_EA.mq4
  • 放入 MT4 数据文件夹的 MQL4/Experts/ 目录
  • 在 MT4 中点击「编译」按钮,确保无错误
  • 拖动 EA 到图表上,勾选「允许自动交易」
  1. 参数调整建议
  • RSI_Period(14):标准周期,短周期(如 9)更敏感,长周期(如 21)更平滑
  • RSI_Oversold(30)/ RSI_Overbought(70):超卖超买阈值,可根据品种波动性调整(例如股指可用 20/80)
  • EMA_Period(200):趋势过滤周期,常用 100/150/200,周期越长趋势判断越稳定
  • StopLossPips(50):止损点数,需根据品种波动率调整(如 EURUSD 用 30-50,GBPJPY 用 80-150)
  • TakeProfitMultiplier(1.5):盈亏比,1.5 表示止盈是止损的 1.5 倍
  • MaxPositions(1):同时最多持仓数,设为 1 可避免同方向重复开仓
  • MaxOrdersPerDay(5):每天最多下单数,防止震荡行情频繁交易
  • Slippage(3):滑点容忍度(pips),流动性差的品种可适当放宽到 5-10
  1. 信号识别
  • 做多信号:价格在 EMA200 上方 + RSI 从 30 以下回升突破 30
  • 做空信号:价格在 EMA200 下方 + RSI 从 70 以上回落跌破 70
  • 只在新 K 线开盘时检测,避免同一根 K 线重复触发
  1. 注意事项
  • 回测建议:先在策略测试器中用历史数据测试,确认参数合理后再实盘
  • 品种适配:自动适配 4 位和 5 位报价(如 EURUSD 和 USDJPY)
  • 风险控制:固定手数交易,建议先用 0.01 手测试,确认稳定后再加仓
  • 日志监控:下单失败会打印错误码到「专家」日志,及时检查连接或账户状态
  • 趋势品种:本策略适合有明显趋势的品种(如主要货币对、贵金属),震荡市场建议降低 MaxOrdersPerDay 或暂停
  • 时间框架:建议用 H1 或 H4 周期,M15 以下信号过于频繁且噪音大

评论

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

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