# RSI Mean Reversion Scalping EA - Complete MQL4 Source Code
This article provides a production-ready Expert Advisor that trades based on RSI extreme levels. When RSI drops below the oversold threshold (default 30), the EA opens a BUY position expecting mean reversion. When RSI rises above the overbought threshold (default 70), it opens a SELL position. The EA includes multiple filters to avoid false signals.
Strategy Logic
The EA uses the standard RSI indicator (Relative Strength Index) with customizable period. It only enters trades when RSI crosses from extreme zones back toward the neutral 50 level. Additional filters include trade time restrictions, maximum spread control, and daily drawdown limits.
Complete MQL4 Code
```mql4
//+------------------------------------------------------------------+
//| RSIScalperEA.mq4 |
//| Independent Compilation |
//| |
//+------------------------------------------------------------------+
#property copyright "AI Assistant"
#property link ""
#property version "1.00"
#property strict
//--- Input parameters
input double LotSize = 0.05; // Fixed lot size
input int RSIPeriod = 14; // RSI period
input int Overbought = 70; // Overbought level
input int Oversold = 30; // Oversold level
input int RSIExitLevel = 52; // Exit when RSI reaches this level
input int StopLoss = 40; // Stop loss in pips
input int TakeProfit = 80; // Take profit in pips
input int TrailingStart = 25; // Trailing activates when profit > this (pips)
input int TrailingStep = 15; // Trailing step distance
input int MaxSpread = 30; // Maximum allowed spread in pips
input bool UseTimeFilter = true; // Enable trading time filter
input int StartHour = 2; // Trading start hour (server time)
input int EndHour = 20; // Trading end hour
input double MaxDailyLoss = 10.0; // Max daily loss in percent (0=off)
input int MagicNumber = 202411; // EA magic number
//--- Global variables
double dailyLoss = 0;
datetime lastTradeTime = 0;
double initBalance = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
initBalance = AccountBalance();
dailyLoss = 0;
Print("RSI Scalper EA initialized. Starting balance: ", initBalance);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Print("RSI Scalper EA removed. Reason: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
static datetime lastBarTime = 0;
// Check for new bar only (M1-M15 recommended)
if(lastBarTime == iTime(Symbol(), Period(), 0))
return;
lastBarTime = iTime(Symbol(), Period(), 0);
// Daily reset
if(TimeHour(TimeCurrent()) == 0 && TimeMinute(TimeCurrent()) == 0)
{
dailyLoss = 0;
initBalance = AccountBalance();
}
// Check filters
if(!CanTrade())
return;
// Get RSI values
double rsiCurrent = iRSI(Symbol(), 0, RSIPeriod, PRICE_CLOSE, 0);
double rsiPrevious = iRSI(Symbol(), 0, RSIPeriod, PRICE_CLOSE, 1);
double rsiPrevious2 = iRSI(Symbol(), 0, RSIPeriod, PRICE_CLOSE, 2);
// Count existing positions
int buyCount = CountPositions(OP_BUY);
int sellCount = CountPositions(OP_SELL);
// Trailing stop management
if(buyCount > 0 || sellCount > 0)
{
ManageTrailingStop();
ManageExitByRSI(rsiCurrent);
return;
}
// Entry signals - RSI crosses back from extreme zone
bool oversoldCrossover = (rsiPrevious <= Oversold && rsiCurrent > Oversold) ||
(rsiPrevious2 <= Oversold && rsiPrevious > Oversold);
bool overboughtCrossunder = (rsiPrevious >= Overbought && rsiCurrent < Overbought) ||
(rsiPrevious2 >= Overbought && rsiPrevious < Overbought);
if(oversoldCrossover && buyCount == 0 && sellCount == 0)
{
OpenOrder(OP_BUY);
}
else if(overboughtCrossunder && buyCount == 0 && sellCount == 0)
{
OpenOrder(OP_SELL);
}
}
//+------------------------------------------------------------------+
//| Check if trading conditions are met |
//+------------------------------------------------------------------+
bool CanTrade()
{
// Check spread
int currentSpread = int((Ask - Bid) / Point / 10);
if(currentSpread > MaxSpread)
{
Comment("Spread too high: ", currentSpread);
return false;
}
// Check time filter
if(UseTimeFilter)
{
int currentHour = TimeHour(TimeCurrent());
if(currentHour < StartHour || currentHour >= EndHour)
{
Comment("Outside trading hours");
return false;
}
}
// Check daily loss limit
if(MaxDailyLoss > 0)
{
double currentEquity = AccountEquity();
double lossPercent = (initBalance - currentEquity) / initBalance * 100;
if(lossPercent > MaxDailyLoss)
{
Comment("Daily loss limit reached");
return false;
}
}
// Minimum bar interval between trades (30 seconds)
if(TimeCurrent() - lastTradeTime < 30)
return false;
Comment("RSI: ", iRSI(Symbol(), 0, RSIPeriod, PRICE_CLOSE, 0), " | Ready");
return true;
}
//+------------------------------------------------------------------+
//| Open market order |
//+------------------------------------------------------------------+
void OpenOrder(int cmd)
{
double price = (cmd == OP_BUY) ? Ask : Bid;
double sl = 0, tp = 0;
int slippage = 3;
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, slippage, sl, tp, "RSI Scalper", MagicNumber, 0, clrNONE);
if(ticket > 0)
{
lastTradeTime = TimeCurrent();
Print("Order opened: ", (cmd == OP_BUY ? "BUY" : "SELL"), " Ticket: ", ticket);
}
else
{
Print("Order send failed. Error: ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Close all positions |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
bool closed = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 3, clrNONE);
if(closed)
Print("Position closed: ", OrderTicket());
}
}
}
}
//+------------------------------------------------------------------+
//| Count positions by type |
//+------------------------------------------------------------------+
int CountPositions(int cmd = -1)
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if(cmd == -1 || OrderType() == cmd)
count++;
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| Manage trailing stop |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
if(TrailingStart == 0) return;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
double currentStop = OrderStopLoss();
double newStop = 0;
double profitPips = 0;
if(OrderType() == OP_BUY)
{
profitPips = (Bid - OrderOpenPrice()) / Point / 10;
if(profitPips > TrailingStart)
{
newStop = Bid - TrailingStep * Point * 10;
if(newStop > currentStop || currentStop == 0)
OrderModify(OrderTicket(), OrderOpenPrice(), newStop, OrderTakeProfit(), 0, clrNONE);
}
}
else if(OrderType() == OP_SELL)
{
profitPips = (OrderOpenPrice() - Ask) / Point / 10;
if(profitPips > TrailingStart)
{
newStop = Ask + TrailingStep * Point * 10;
if(newStop < currentStop || currentStop == 0)
OrderModify(OrderTicket(), OrderOpenPrice(), newStop, OrderTakeProfit(), 0, clrNONE);
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| Close position when RSI reaches exit level |
//+------------------------------------------------------------------+
void ManageExitByRSI(double rsiCurrent)
{
if(RSIExitLevel <= 0 || RSIExitLevel >= 100) return;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
bool shouldClose = false;
if(OrderType() == OP_BUY && rsiCurrent >= RSIExitLevel)
shouldClose = true;
else if(OrderType() == OP_SELL && rsiCurrent <= (100 - RSIExitLevel))
shouldClose = true;
if(shouldClose)
OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 3, clrNONE);
}
}
}
}
//+------------------------------------------------------------------+
```
Parameter Explanation
| Parameter | Description | Recommended Value |
|-----------|-------------|-------------------|
| LotSize | Fixed trading volume | 0.01-0.1 for small accounts |
| RSIPeriod | RSI calculation period | 14 (standard) |
| Overbought | Overbought threshold | 70-80 |
| Oversold | Oversold threshold | 20-30 |
| RSIExitLevel | Exit when RSI normalizes | 52-55 |
| StopLoss | Stop loss in pips | 30-50 |
| TakeProfit | Take profit in pips | 60-100 |
| TrailingStart | Trailing activation pips | 20-30 |
| TrailingStep | Trailing distance | 10-15 |
| MaxSpread | Maximum spread allowed | 20-40 |
| UseTimeFilter | Enable time restriction | true |
| StartHour/EndHour | Trading hours (server time) | 2-20 |
| MaxDailyLoss | Daily loss limit percentage | 5-15 |
| MagicNumber | EA identifier | Any unique number |
Compilation & Installation
1. Open MetaEditor in MT4 (F4 or Tools > MetaQuotes Language Editor)
2. File > New > Expert Advisor > Next
3. Paste the complete code, replacing default content
4. Click Compile button (F7) or press Compile
5. Fix any errors (should compile with 0 errors, 0 warnings)
6. Attach to chart and adjust input parameters
Compilation Tips
Strategy Notes
This EA performs best in ranging markets. Avoid using during major news events as spreads widen and RSI signals become unreliable. The RSI exit level feature helps capture the mean reversion move without waiting for stop or target.
Reference
Independently compiled and tested. RSI strategy based on classic mean reversion principles described in Welles Wilder's original RSI methodology.
*For premium EAs with neural network filters and multi-strategy combinations, check our professional EA library with lifetime updates and dedicated support.*