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:

  • <strong>Monitors RSI on your chosen timeframe</strong> (or multiple timeframes)

  • <strong>Triggers an alert</strong> when RSI crosses above overbought level (default 70) or below oversold level (default 30)

  • <strong>Sends alerts</strong> via popup, push notification to mobile, or email

  • <strong>Prevents alert spam</strong> 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


  • Attach indicator to any chart

  • A status label appears in the top-left corner showing current RSI

  • 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


  • In MT4: Tools → Options → Notifications

  • Enable "Push Notifications" and enter your MetaQuotes ID

  • Download MT4 mobile app and find your ID in Settings

  • Set Alert_Push = true in indicator


  • Email Alerts Setup


  • In MT4: Tools → Options → Email

  • Enable and configure SMTP (Gmail: smtp.gmail.com, port 587, TLS)

  • 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+