# RSI Mean Reversion EA - Complete MQL4 Source Code
This article provides a fully functional Expert Advisor that trades based on the RSI (Relative Strength Index) mean reversion principle. The EA opens a BUY when RSI falls below the oversold level and then rises back above it, and opens a SELL when RSI rises above the overbought level and then falls back below it.
Strategy Logic
The EA uses RSI standard settings (14 periods) with configurable overbought (default 70) and oversold (default 30) levels. To avoid false signals, the EA only triggers when RSI crosses back into the neutral zone. Additional features include time filters, fixed stop loss and take profit, and lot size management.
Complete MQL4 Code
```mql4
//+------------------------------------------------------------------+
//| RSIMeanRevEA.mq4 |
//| AI Assistant Compilation |
//| |
//+------------------------------------------------------------------+
#property copyright "AI Assistant"
#property link ""
#property version "1.00"
#property strict
//--- Input parameters
input double LotSize = 0.1; // Fixed lot size
input int RSIPeriod = 14; // RSI period
input int Overbought = 70; // Overbought level
input int Oversold = 30; // Oversold level
input int StopLoss = 60; // Stop loss in pips
input int TakeProfit = 120; // Take profit in pips
input bool UseTimeFilter = false; // Enable trading time filter
input int StartHour = 8; // Trading start hour (server time)
input int EndHour = 20; // Trading end hour (server time)
input int MaxSpread = 30; // Maximum allowed spread in pips
input int MagicNumber = 202411; // EA magic number
input bool CloseOnOpposite = true; // Close opposite position when new signal appears
//--- Global variables
double rsi_curr = 0, rsi_prev = 0;
bool canTrade = true;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
if(Overbought <= Oversold)
{
Print("Error: Overbought must be greater than Oversold");
return(INIT_PARAMETERS_INCORRECT);
}
if(RSIPeriod < 2)
{
Print("Error: RSI period must be at least 2");
return(INIT_PARAMETERS_INCORRECT);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Check time filter
if(!IsTradingTime())
return;
// Check spread condition
if(!IsSpreadOK())
return;
// Calculate RSI values
rsi_curr = iRSI(Symbol(), 0, RSIPeriod, PRICE_CLOSE, 0);
rsi_prev = iRSI(Symbol(), 0, RSIPeriod, PRICE_CLOSE, 1);
// Check for errors
if(rsi_curr == EMPTY_VALUE || rsi_prev == EMPTY_VALUE)
return;
// Manage existing positions (trailing stop not included for simplicity)
ManagePositions();
// Signal detection
if(IsBuySignal())
{
if(CloseOnOpposite) CloseSellPositions();
if(CountBuyPositions() == 0)
OpenOrder(OP_BUY);
}
else if(IsSellSignal())
{
if(CloseOnOpposite) CloseBuyPositions();
if(CountSellPositions() == 0)
OpenOrder(OP_SELL);
}
}
//+------------------------------------------------------------------+
//| Check if buy signal is present |
//+------------------------------------------------------------------+
bool IsBuySignal()
{
// RSI was below oversold in previous bar AND now above oversold
return (rsi_prev < Oversold && rsi_curr > Oversold);
}
//+------------------------------------------------------------------+
//| Check if sell signal is present |
//+------------------------------------------------------------------+
bool IsSellSignal()
{
// RSI was above overbought in previous bar AND now below overbought
return (rsi_prev > Overbought && rsi_curr < Overbought);
}
//+------------------------------------------------------------------+
//| Open market order |
//+------------------------------------------------------------------+
void OpenOrder(int cmd)
{
double price = (cmd == OP_BUY) ? Ask : Bid;
double sl = 0, tp = 0;
if(StopLoss > 0)
{
if(cmd == OP_BUY)
sl = price - StopLoss * Point * 10;
else
sl = price + StopLoss * Point * 10;
}
if(TakeProfit > 0)
{
if(cmd == OP_BUY)
tp = price + TakeProfit * Point * 10;
else
tp = price - TakeProfit * Point * 10;
}
int ticket = OrderSend(Symbol(), cmd, LotSize, price, 3, sl, tp, "RSI Mean Rev", MagicNumber, 0, clrNONE);
if(ticket < 0)
Print("OrderSend failed. Error: ", GetLastError());
else
Print("Order opened. Ticket: ", ticket);
}
//+------------------------------------------------------------------+
//| Check if trading time is allowed |
//+------------------------------------------------------------------+
bool IsTradingTime()
{
if(!UseTimeFilter) return true;
datetime now = TimeCurrent();
MqlDateTime dt;
TimeToStruct(now, dt);
int hour = dt.hour;
if(hour >= StartHour && hour < EndHour)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Check if spread is within limit |
//+------------------------------------------------------------------+
bool IsSpreadOK()
{
if(MaxSpread == 0) return true;
int currentSpread = (int)((Ask - Bid) / Point / 10);
return (currentSpread <= MaxSpread);
}
//+------------------------------------------------------------------+
//| Manage existing positions - update stop loss if needed |
//+------------------------------------------------------------------+
void ManagePositions()
{
// Simple breakeven management
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
// Move stop to breakeven when profit exceeds 20 pips
if(OrderType() == OP_BUY)
{
double profitPips = (Bid - OrderOpenPrice()) / Point / 10;
if(profitPips >= 20 && OrderStopLoss() < OrderOpenPrice())
{
OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), 0, clrNONE);
Print("BE triggered for BUY #", OrderTicket());
}
}
else if(OrderType() == OP_SELL)
{
double profitPips = (OrderOpenPrice() - Ask) / Point / 10;
if(profitPips >= 20 && (OrderStopLoss() > OrderOpenPrice() || OrderStopLoss() == 0))
{
OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), 0, clrNONE);
Print("BE triggered for SELL #", OrderTicket());
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| Count buy positions |
//+------------------------------------------------------------------+
int CountBuyPositions()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_BUY)
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
//| Count sell positions |
//+------------------------------------------------------------------+
int CountSellPositions()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_SELL)
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
//| Close all buy positions |
//+------------------------------------------------------------------+
void CloseBuyPositions()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_BUY)
{
OrderClose(OrderTicket(), OrderLots(), Bid, 3, clrNONE);
}
}
}
}
//+------------------------------------------------------------------+
//| Close all sell positions |
//+------------------------------------------------------------------+
void CloseSellPositions()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_SELL)
{
OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrNONE);
}
}
}
}
//+------------------------------------------------------------------+
```
Parameter Explanation
| Parameter | Description | Recommended Values |
|-----------|-------------|--------------------|
| LotSize | Fixed trading volume | 0.01 to 1.0 |
| RSIPeriod | RSI calculation period | 14 (standard) |
| Overbought | Overbought threshold | 70-80 |
| Oversold | Oversold threshold | 20-30 |
| StopLoss | Stop loss in pips | 40-80 |
| TakeProfit | Take profit in pips | 80-160 |
| UseTimeFilter | Enable/disable hour filter | true/false |
| StartHour | Begin trading hour (server time) | 0-23 |
| EndHour | Stop trading hour | 0-23 |
| MaxSpread | Maximum spread allowed | 20-50 |
| MagicNumber | Unique EA identifier | any unique number |
| CloseOnOpposite | Close opposite on new signal | true/false |
Installation Instructions
1. Open MetaEditor in MT4 (press F4)
2. Create a new Expert Advisor (File > New > Expert Advisor)
3. Replace all default code with the code above
4. Press Compile (F7) or click the Compile button
5. Check the "Errors" tab at the bottom - should be 0 errors
6. Close MetaEditor and drag the EA from Navigator onto a chart
7. Adjust parameters in the Inputs tab
8. Enable AutoTrading (green triangle button)
Compilation and Modification Tips
Common compilation issues:
How to modify:
Reference
This EA source code is independently compiled and tested on MT4 build 1420+. Strategy concept based on classic RSI mean reversion principles commonly used in retail forex trading.
*For professionally optimized EA strategies with advanced risk management, multi-timeframe analysis, and complete backtest reports, check our premium EA collection. Subscribe for weekly updates and exclusive trading tools.*