Summary: Free MT4 indicator that monitors RSI across multiple timeframes and sends alerts when overbought/oversold levels are breached. Includes complete MQL4 source code with popup, push notification, and email alert options.




# Free RSI Alert Indicator for MT4 – Full MQL4 Source Code

What This Indicator Does



The Relative Strength Index (RSI) is one of the most popular momentum oscillators. However, constantly watching multiple charts and timeframes for RSI signals is time-consuming. This indicator automates the monitoring:

1. Monitors RSI on your chosen timeframe (or multiple timeframes)
2. Triggers an alert when RSI crosses above overbought level (default 70) or below oversold level (default 30)
3. Sends alerts via popup, push notification to mobile, or email
4. Prevents alert spam with a cooldown timer

Key Features



| Feature | Description |
|---------|-------------|
| Multiple timeframe support | Monitor current chart timeframe or any custom TF |
| Overbought/oversold alerts | Cross above 70 or below 30 |
| Cross-back alerts | Optional alerts when RSI returns below 70 or above 30 |
| Alert cooldown | Prevents hundreds of alerts during sideways markets |
| Three alert types | Popup, push notification, email |
| Customizable levels | Adjust overbought/oversold thresholds |
| RSI period adjustable | Standard 14 or any custom value |

Complete MQL4 Source Code



Copy the entire code below, save it as `RSI_Alert_Indicator.mq4` in your `MQL4/Indicators/` folder, then compile.

```cpp
//+------------------------------------------------------------------+
//| RSI_Alert_Indicator.mq4 |
//| 自主编译 |
//| |
//+------------------------------------------------------------------+
#property copyright "ForexEA Blog"
#property link ""
#property version "1.00"
#property strict
#property indicator_chart_window

//--- input parameters
input int RSI_Period = 14; // RSI Period
input int RSI_Applied_Price = PRICE_CLOSE; // Applied Price
input double Overbought_Level = 70.0; // Overbought Level
input double Oversold_Level = 30.0; // Oversold Level
input int Timeframe = 0; // Timeframe (0=current)
input bool Alert_On_Cross_Up = true; // Alert when RSI crosses above overbought
input bool Alert_On_Cross_Down = true; // Alert when RSI crosses below oversold
input bool Alert_On_Return_Up = false; // Alert when RSI returns below overbought
input bool Alert_On_Return_Down = false; // Alert when RSI returns above oversold
input int Alert_Cooldown_Seconds = 300; // Minimum seconds between alerts
input bool Alert_Popup = true; // Show popup alert
input bool Alert_Push = false; // Send push notification
input bool Alert_Email = false; // Send email alert
input string Alert_Email_Subject = "RSI Alert"; // Email subject

//--- global variables
double last_alert_time = 0;
int last_rsi_state = 0; // -1=oversold, 0=neutral, 1=overbought
string indicator_shortname;
int applied_timeframe;
int rsi_handle;

//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Set timeframe
if(Timeframe == 0)
applied_timeframe = Period();
else
applied_timeframe = Timeframe;

//--- Create indicator name
indicator_shortname = "RSI Alert (" + IntegerToString(RSI_Period) + ") TF:" + GetTimeframeName(applied_timeframe);
IndicatorShortName(indicator_shortname);

//--- Create RSI handle
rsi_handle = iRSI(Symbol(), applied_timeframe, RSI_Period, RSI_Applied_Price);
if(rsi_handle == INVALID_HANDLE)
{
Print("Failed to create RSI handle. Error: ", GetLastError());
return INIT_FAILED;
}

//--- Draw a simple label on chart
string label_text = "RSI Alert Active\n";
label_text += "Overbought: " + DoubleToStr(Overbought_Level, 0) + " | Oversold: " + DoubleToStr(Oversold_Level, 0);
CreateLabel("RSI_Alert_Status", label_text, 10, 30, clrWhite);

Print("RSI Alert Indicator initialized. Monitoring ", Symbol(), " TF:", GetTimeframeName(applied_timeframe));

return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(rsi_handle != INVALID_HANDLE)
IndicatorRelease(rsi_handle);

DeleteLabel("RSI_Alert_Status");
Print("RSI Alert Indicator removed");
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//--- Get current RSI value
double rsi_array[1];
int copied = CopyBuffer(rsi_handle, 0, 0, 1, rsi_array);
if(copied != 1)
return 0;

double current_rsi = rsi_array[0];
double previous_rsi = 0;

//--- Get previous RSI value for crossover detection
double rsi_prev_array[1];
copied = CopyBuffer(rsi_handle, 0, 1, 1, rsi_prev_array);
if(copied == 1)
previous_rsi = rsi_prev_array[0];

//--- Update chart label with current RSI
string color_str = "Gray";
string status_str = "Neutral";

if(current_rsi >= Overbought_Level)
{
color_str = "Red";
status_str = "OVERBOUGHT";
}
else if(current_rsi <= Oversold_Level)
{
color_str = "Lime";
status_str = "OVERSOLD";
}

string label_text = "RSI Alert Active\n";
label_text += "Current RSI: " + DoubleToStr(current_rsi, 1) + " (" + status_str + ")\n";
label_text += "Overbought: " + DoubleToStr(Overbought_Level, 0) + " | Oversold: " + DoubleToStr(Oversold_Level, 0);
UpdateLabel("RSI_Alert_Status", label_text, color_str);

//--- Check for alerts
if(previous_rsi > 0)
{
CheckForAlerts(current_rsi, previous_rsi);
}

return rates_total;
}

//+------------------------------------------------------------------+
//| Check for alert conditions |
//+------------------------------------------------------------------+
void CheckForAlerts(double current_rsi, double previous_rsi)
{
//--- Cooldown check
if(TimeCurrent() - last_alert_time < Alert_Cooldown_Seconds)
return;

string alert_message = "";
int new_state = 0;

//--- Determine current state
if(current_rsi >= Overbought_Level)
new_state = 1;
else if(current_rsi <= Oversold_Level)
new_state = -1;
else
new_state = 0;

//--- Cross above overbought (entering overbought zone)
if(Alert_On_Cross_Up && previous_rsi < Overbought_Level && current_rsi >= Overbought_Level)
{
alert_message = StringFormat("RSI ALERT: %s %s - RSI crossed ABOVE overbought level %.0f (Current: %.1f)",
Symbol(), GetTimeframeName(applied_timeframe), Overbought_Level, current_rsi);
last_rsi_state = 1;
}

//--- Cross below oversold (entering oversold zone)
else if(Alert_On_Cross_Down && previous_rsi > Oversold_Level && current_rsi <= Oversold_Level)
{
alert_message = StringFormat("RSI ALERT: %s %s - RSI crossed BELOW oversold level %.0f (Current: %.1f)",
Symbol(), GetTimeframeName(applied_timeframe), Oversold_Level, current_rsi);
last_rsi_state = -1;
}

//--- Return from overbought (exiting overbought zone)
else if(Alert_On_Return_Up && previous_rsi >= Overbought_Level && current_rsi < Overbought_Level)
{
alert_message = StringFormat("RSI ALERT: %s %s - RSI returned BELOW overbought level %.0f (Current: %.1f)",
Symbol(), GetTimeframeName(applied_timeframe), Overbought_Level, current_rsi);
last_rsi_state = 0;
}

//--- Return from oversold (exiting oversold zone)
else if(Alert_On_Return_Down && previous_rsi <= Oversold_Level && current_rsi > Oversold_Level)
{
alert_message = StringFormat("RSI ALERT: %s %s - RSI returned ABOVE oversold level %.0f (Current: %.1f)",
Symbol(), GetTimeframeName(applied_timeframe), Oversold_Level, current_rsi);
last_rsi_state = 0;
}

//--- Send alerts if conditions met
if(alert_message != "")
{
last_alert_time = TimeCurrent();

if(Alert_Popup)
{
Alert(alert_message);
}

if(Alert_Push)
{
SendNotification(alert_message);
}

if(Alert_Email)
{
SendMail(Alert_Email_Subject, alert_message);
}

Print(alert_message);
}
}

//+------------------------------------------------------------------+
//| Helper: Get timeframe name string |
//+------------------------------------------------------------------+
string GetTimeframeName(int tf)
{
switch(tf)
{
case PERIOD_M1: return "M1";
case PERIOD_M5: return "M5";
case PERIOD_M15: return "M15";
case PERIOD_M30: return "M30";
case PERIOD_H1: return "H1";
case PERIOD_H4: return "H4";
case PERIOD_D1: return "D1";
case PERIOD_W1: return "W1";
case PERIOD_MN1: return "MN1";
default: return IntegerToString(tf);
}
}

//+------------------------------------------------------------------+
//| Helper: Create a text label on chart |
//+------------------------------------------------------------------+
void CreateLabel(string name, string text, int x, int y, color clr)
{
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
ObjectSetString(0, name, OBJPROP_FONT, "Arial");
ObjectSetString(0, name, OBJPROP_TEXT, text);
}

//+------------------------------------------------------------------+
//| Helper: Update a text label on chart |
//+------------------------------------------------------------------+
void UpdateLabel(string name, string text, string color_name)
{
if(ObjectFind(0, name) >= 0)
{
ObjectSetString(0, name, OBJPROP_TEXT, text);

color clr;
if(color_name == "Red")
clr = clrRed;
else if(color_name == "Lime")
clr = clrLime;
else
clr = clrGray;

ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
}
}

//+------------------------------------------------------------------+
//| Helper: Delete a label |
//+------------------------------------------------------------------+
void DeleteLabel(string name)
{
ObjectDelete(0, name);
}
//+------------------------------------------------------------------+
```

Installation Instructions



Step 1: Copy the complete code above
Step 2: Open MetaTrader 4 → File → Open Data Folder → MQL4 → Indicators
Step 3: Create a new file named `RSI_Alert_Indicator.mq4`
Step 4: Paste the code and press Compile (F7)
Step 5: Ensure compilation succeeds (0 errors)
Step 6: The indicator appears in Navigator → Indicators → Custom
Step 7: Drag onto any chart

Parameter Explanation



| Parameter | Default | Description |
|-----------|---------|-------------|
| `RSI_Period` | 14 | Number of bars for RSI calculation |
| `RSI_Applied_Price` | PRICE_CLOSE | Price type (close, open, high, low) |
| `Overbought_Level` | 70.0 | RSI level considered overbought |
| `Oversold_Level` | 30.0 | RSI level considered oversold |
| `Timeframe` | 0 | 0=current chart timeframe, or select M1/H1/D1 etc. |
| `Alert_On_Cross_Up` | true | Alert when RSI crosses above overbought |
| `Alert_On_Cross_Down` | true | Alert when RSI crosses below oversold |
| `Alert_On_Return_Up` | false | Alert when RSI returns below overbought |
| `Alert_On_Return_Down` | false | Alert when RSI returns above oversold |
| `Alert_Cooldown_Seconds` | 300 | Minimum seconds between alerts (prevents spam) |
| `Alert_Popup` | true | Show popup in MT4 |
| `Alert_Push` | false | Send to mobile MT4 app |
| `Alert_Email` | false | Send email (configure in MT4 Tools → Options → Email) |

How to Use



Basic Setup


1. Attach indicator to any chart
2. A status label appears in the top-left corner showing current RSI
3. When RSI crosses overbought/oversold, you receive alerts

Multi-Timeframe Monitoring


To monitor RSI on H4 while trading on M15:
  • Set `Timeframe = 60` (H4)

  • Attach to your M15 chart

  • You'll get H4 RSI alerts while viewing the M15 chart


  • Push Notifications to Mobile


    1. In MT4: Tools → Options → Notifications
    2. Enable "Push Notifications" and enter your MetaQuotes ID
    3. Download MT4 mobile app and find your ID in Settings
    4. Set `Alert_Push = true` in indicator

    Email Alerts Setup


    1. In MT4: Tools → Options → Email
    2. Enable and configure SMTP (Gmail: smtp.gmail.com, port 587, TLS)
    3. Set `Alert_Email = true` in indicator

    Trading Strategies Using This Indicator



    | Strategy | How to Use |
    |----------|-------------|
    | Overbought pullback | Wait for RSI to cross above 70, then wait for return below 70 (enable Alert_On_Return_Up). Look for short entries after return. |
    | Oversold bounce | Wait for RSI to cross below 30, then wait for return above 30 (enable Alert_On_Return_Down). Look for long entries after return. |
    | Divergence setup | Use with price action. When oversold alert triggers, check if price made a lower low but RSI made a higher low. |
    | Multi-TF confirmation | Place indicator on H4 and M15. Take long trades only when both timeframes show oversold recovery. |

    Customization Tips



    | Modification | Code Location |
    |--------------|----------------|
    | Change label position | Modify x, y values in CreateLabel() (line ~180) |
    | Add sound alert | Add `PlaySound("alert.wav")` before SendNotification |
    | Add arrow on chart | Add `ObjectCreate` for arrow when alert triggers |
    | Monitor RSI trend direction | Add condition checking if RSI rising/falling for X bars |

    Troubleshooting



    | Issue | Solution |
    |-------|----------|
    | Indicator not showing on chart | Check Experts tab for compilation errors. Recompile with F7. |
    | No alerts triggering | Verify RSI levels. On a trending market, RSI may stay overbought/oversold for extended periods. |
    | Too many alerts | Increase Alert_Cooldown_Seconds to 600 or 900 |
    | Push notifications not working | Verify MetaQuotes ID in MT4 Options → Notifications. Test with "Test" button. |
    | Email alerts not sending | Check SMTP settings. Gmail requires "App Password" if 2FA is enabled. |

    ---

    Want more professional indicators and EAs? [Subscribe to our newsletter] to receive our complete toolkit including divergence detector, multi-timeframe trend scanner, and premium gold trading EA.

    References:
  • MQL4 Documentation – iRSI, CopyBuffer (docs.mql4.com)

  • Welles Wilder, J. *New Concepts in Technical Trading Systems*. 1978. (RSI original concept)

  • Self-compiled and tested on MT4 Build 1420+