//+------------------------------------------------------------------+
//|                                    XU_v48_RSIOMA_Fixed.mq5       |
//|                         Translated and Fixed to MQL5             |
//+------------------------------------------------------------------+
#property copyright "Your Name"
#property link      "https://www.mql5.com"
#property version   "1.22"
#property indicator_separate_window
#property indicator_minimum 0
#property indicator_maximum 100

// Buffers and Plots
#property indicator_buffers 6
#property indicator_plots   4

// --- RSI Levels ---
#property indicator_level1    30
#property indicator_level2    50
#property indicator_level3    70
#property indicator_levelcolor clrDimGray
#property indicator_levelstyle STYLE_DOT

// 1. RSI on MA (Color 0: Up Slope, Color 1: Down Slope, Color 2: Flat)
#property indicator_label1    "RSI on MA"
#property indicator_type1     DRAW_COLOR_LINE
#property indicator_color1    clrDeepSkyBlue, clrHotPink, clrGray
#property indicator_style1    STYLE_SOLID
#property indicator_width1    2

// 2. Marsioma
#property indicator_label2    "Marsioma"
#property indicator_type2     DRAW_LINE
#property indicator_color2    clrSnow
#property indicator_width2    2

// 3. Signal Up (Histogram)
#property indicator_label3    "Signal Up"
#property indicator_type3     DRAW_HISTOGRAM
#property indicator_color3    clrAqua
#property indicator_width3    2

// 4. Signal Down (Histogram)
#property indicator_label4    "Signal Down"
#property indicator_type4     DRAW_HISTOGRAM
#property indicator_color4    clrFuchsia
#property indicator_width4    2

//+------------------------------------------------------------------+
//| Input Parameters                                                 |
//+------------------------------------------------------------------+
input ENUM_TIMEFRAMES inpTimeframe = PERIOD_CURRENT; // Timeframe
input bool   inpShowHeader         = true;           // Show Dashboard Header
input bool   inpShowBgColor        = true;           // Show Dual Background Color
input int    inpRSIOMA             = 10;             // RSIOMA Period
input int    inpMa_RSIOMA          = 7;              // Ma_RSIOMA Period
input int    inpSlopeSmoothing     = 2;              // Slope Smoothing Period (Lookback Bars)
input bool   inpShowArrows         = true;           // Draw Arrows on Main Chart
input int    inpMaxBarsHistory     = 2000;           // Max Bars to Process (Speed Optimizer)

// --- Alert Inputs ---
input group "=== Alert Settings ==="
input bool   inpEnableAlerts       = true;           // Enable Alerts
input bool   inpAlertOnLevel50     = true;           // Alert on Level 50 Cross
input bool   inpAlertOnSlopeChange = true;           // Alert on RSI Slope Color Change
input bool   inpAlertPopup         = true;           // Alert Popup Window
input bool   inpAlertPush          = false;          // Alert Push Notifications
input bool   inpAlertEmail         = false;          // Alert Email

//+------------------------------------------------------------------+
//| Buffers                                                          |
//+------------------------------------------------------------------+
double RsiOnMaBuffer[];
double RsiColorBuffer[];
double MarsiomaBuffer[];
double SignalUpBuffer[];
double SignalDnBuffer[];
double TrendBuffer[];

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
int handle_ema, handle_rsi, handle_marsi;
string bgUpName  = "XU_RSIOMA_RECT_UP"; 
string bgDnName  = "XU_RSIOMA_RECT_DN"; 
string labelName = "XU_RSIOMA_Label";
string shortName = "XU_RSIOMA_v48";
string arrowPrefix = "XU_RSIOMA_Arrow_";

datetime lastBarAlertTime = 0; // Tracks the last bar time an alert was successfully fired

//+------------------------------------------------------------------+
//| OnInit                                                           |
//+------------------------------------------------------------------+
int OnInit()
{
    IndicatorSetString(INDICATOR_SHORTNAME, shortName);

    SetIndexBuffer(0, RsiOnMaBuffer, INDICATOR_DATA);
    SetIndexBuffer(1, RsiColorBuffer, INDICATOR_COLOR_INDEX);
    SetIndexBuffer(2, MarsiomaBuffer, INDICATOR_DATA);
    SetIndexBuffer(3, SignalUpBuffer, INDICATOR_DATA);
    SetIndexBuffer(4, SignalDnBuffer, INDICATOR_DATA);
    SetIndexBuffer(5, TrendBuffer, INDICATOR_CALCULATIONS);
    
    PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
    PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE);

    handle_ema = iMA(Symbol(), inpTimeframe, inpRSIOMA, 0, MODE_EMA, PRICE_CLOSE);
    handle_rsi = iRSI(Symbol(), inpTimeframe, inpRSIOMA, handle_ema);
    handle_marsi = iMA(Symbol(), inpTimeframe, inpMa_RSIOMA, 0, MODE_EMA, handle_rsi);

    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| OnDeinit                                                         |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    ObjectsDeleteAll(0, "XU_RSIOMA_");
}

//+------------------------------------------------------------------+
//| Trigger Notification Function                                    |
//+------------------------------------------------------------------+
void TriggerAlert(string message, datetime barTime)
{
    if(!inpEnableAlerts) return;
    
    // Ensure only one alert fires per unique bar timeframe
    if(lastBarAlertTime == barTime) return;
    lastBarAlertTime = barTime;

    if(inpAlertPopup)
        Alert(message);
    if(inpAlertPush)
        SendNotification(message);
    if(inpAlertEmail)
        SendMail("RSIOMA Alert - " + Symbol(), message);
}

//+------------------------------------------------------------------+
//| OnCalculate                                                      |
//+------------------------------------------------------------------+
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[])
{
    int min_bars = inpRSIOMA + inpMa_RSIOMA + inpSlopeSmoothing;
    if(rates_total < min_bars) return 0;

    int start_calc = rates_total - 1;
    if(inpMaxBarsHistory > 0 && start_calc > inpMaxBarsHistory)
        start_calc = inpMaxBarsHistory;

    int limit = prev_calculated - 1;
    if(limit < 0) 
        limit = rates_total - start_calc;
    if(limit < 0) 
        limit = 0;

    int to_copy = rates_total - limit;
    if(to_copy <= 0) return rates_total;

    double tempRsi[];
    double tempMarsi[];

    ArraySetAsSeries(tempRsi, true);
    ArraySetAsSeries(tempMarsi, true);

    if(CopyBuffer(handle_rsi, 0, 0, to_copy, tempRsi) <= 0) return 0;
    if(CopyBuffer(handle_marsi, 0, 0, to_copy, tempMarsi) <= 0) return 0;

    int smooth_period = (inpSlopeSmoothing < 1) ? 1 : inpSlopeSmoothing;

    for(int i = to_copy - 1; i >= 0; i--)
    {
        int bar_index = rates_total - 1 - i;
        if(bar_index < 0 || bar_index >= rates_total) continue;

        RsiOnMaBuffer[bar_index] = tempRsi[i];
        MarsiomaBuffer[bar_index] = tempMarsi[i];
        SignalUpBuffer[bar_index] = EMPTY_VALUE;
        SignalDnBuffer[bar_index] = EMPTY_VALUE;

        if(bar_index > 0)
            TrendBuffer[bar_index] = TrendBuffer[bar_index-1];
        else
            TrendBuffer[bar_index] = 0;

        // --- Adjustable Smoothed Slope Color Logic ---
        double previousColor = (bar_index > 0) ? RsiColorBuffer[bar_index - 1] : 2;

        if(bar_index >= smooth_period)
        {
            double diff = RsiOnMaBuffer[bar_index] - RsiOnMaBuffer[bar_index - smooth_period];

            if(diff > 0.0)
                RsiColorBuffer[bar_index] = 0; // Rising
            else if(diff < 0.0)
                RsiColorBuffer[bar_index] = 1; // Falling
            else
                RsiColorBuffer[bar_index] = previousColor; // Unchanged
        }
        else
        {
            RsiColorBuffer[bar_index] = 2; // Default neutral color
        }

        // Level 50 Crossover Signals & Main Chart Arrows
        if(bar_index > 0)
        {
            bool level50UpCross = (RsiOnMaBuffer[bar_index-1] <= 50 && RsiOnMaBuffer[bar_index] > 50);
            bool level50DnCross = (RsiOnMaBuffer[bar_index-1] >= 50 && RsiOnMaBuffer[bar_index] < 50);

            if(level50UpCross)
            {
                SignalUpBuffer[bar_index] = 100;
                TrendBuffer[bar_index] = 1; 
                
                if(inpShowArrows && (rates_total - bar_index <= inpMaxBarsHistory))
                    DrawChartArrow(time[bar_index], low[bar_index], true, bar_index);

                // Live Bar Level 50 Alert Check
                if(bar_index == rates_total - 1 && inpAlertOnLevel50)
                {
                    TriggerAlert(Symbol() + " (" + EnumToString(inpTimeframe) + "): RSI crossed ABOVE Level 50!", time[bar_index]);
                }
            }
            else if(level50DnCross)
            {
                SignalDnBuffer[bar_index] = 100;
                TrendBuffer[bar_index] = -1; 
                
                if(inpShowArrows && (rates_total - bar_index <= inpMaxBarsHistory))
                    DrawChartArrow(time[bar_index], high[bar_index], false, bar_index);

                // Live Bar Level 50 Alert Check
                if(bar_index == rates_total - 1 && inpAlertOnLevel50)
                {
                    TriggerAlert(Symbol() + " (" + EnumToString(inpTimeframe) + "): RSI crossed BELOW Level 50!", time[bar_index]);
                }
            }
            else if(inpShowArrows)
            {
               string name = arrowPrefix + IntegerToString(bar_index);
               if(ObjectFind(0, name) >= 0)
                  ObjectDelete(0, name);
            }

            // Live Bar Slope Color Change Alert Check
            if(bar_index == rates_total - 1 && inpAlertOnSlopeChange)
            {
                if(RsiColorBuffer[bar_index] != previousColor)
                {
                    if(RsiColorBuffer[bar_index] == 0)
                        TriggerAlert(Symbol() + " (" + EnumToString(inpTimeframe) + "): RSI Slope changed to UP (Rising)", time[bar_index]);
                    else if(RsiColorBuffer[bar_index] == 1)
                        TriggerAlert(Symbol() + " (" + EnumToString(inpTimeframe) + "): RSI Slope changed to DOWN (Falling)", time[bar_index]);
                }
            }
        }
    }

    if(rates_total > 0)
    {
        if(inpShowHeader)  
            UpdateDashboard(RsiOnMaBuffer[rates_total - 1], (int)TrendBuffer[rates_total - 1]);
        
        if(inpShowBgColor) 
            CreateCoordinateBackground(time[0], time[rates_total-1]);
    }

    return(rates_total);
}

// --- Draw Chart Arrows ---
void DrawChartArrow(datetime time, double price, bool isBuy, int index)
{
    string name = arrowPrefix + IntegerToString(index);
    ENUM_OBJECT arrowType = isBuy ? OBJ_ARROW_BUY : OBJ_ARROW_SELL;
    color arrowColor = isBuy ? clrAqua : clrFuchsia;

    if(ObjectFind(0, name) < 0)
    {
        if(!ObjectCreate(0, name, arrowType, 0, time, price))
            return;
        ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
        ObjectSetInteger(0, name, OBJPROP_BACK, false);
        ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
    }
    
    ObjectSetInteger(0, name, OBJPROP_TIME, time);
    ObjectSetDouble(0, name, OBJPROP_PRICE, price);
    ObjectSetInteger(0, name, OBJPROP_COLOR, arrowColor);
}

// --- Dashboard ---
void UpdateDashboard(double rsi_val, int trend_state)
{
    int subWindow = ChartWindowFind(0, shortName);
    if(subWindow < 0) return; 

    color textColor = (trend_state == 1) ? clrDeepSkyBlue : (trend_state == -1 ? clrHotPink : clrGray);

    if(ObjectFind(0, labelName) < 0)
    {
        if(ObjectCreate(0, labelName, OBJ_LABEL, subWindow, 0, 0))
        {
            ObjectSetInteger(0, labelName, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
            ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, 100);
            ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, 15);
            ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 12);
            ObjectSetString(0, labelName, OBJPROP_FONT, "Arial Bold");
            ObjectSetInteger(0, labelName, OBJPROP_ZORDER, 10);
        }
    }
    
    ObjectSetString(0, labelName, OBJPROP_TEXT, "RSI: " + DoubleToString(rsi_val, 2));
    ObjectSetInteger(0, labelName, OBJPROP_COLOR, textColor);
}

// --- Background ---
void CreateCoordinateBackground(datetime startTime, datetime endTime)
{
    int subWindow = ChartWindowFind(0, shortName);
    if(subWindow < 0) return;

    color colorUp = C'15,25,45'; 
    color colorDn = C'45,15,25'; 

    if(ObjectFind(0, bgUpName) < 0)
    {
        if(ObjectCreate(0, bgUpName, OBJ_RECTANGLE, subWindow, startTime, 100, endTime, 50))
        {
            ObjectSetInteger(0, bgUpName, OBJPROP_FILL, true);
            ObjectSetInteger(0, bgUpName, OBJPROP_BACK, true);
            ObjectSetInteger(0, bgUpName, OBJPROP_SELECTABLE, false);
        }
    }
    ObjectSetInteger(0, bgUpName, OBJPROP_TIME, 0, startTime);
    ObjectSetDouble(0, bgUpName, OBJPROP_PRICE, 0, 100);
    ObjectSetInteger(0, bgUpName, OBJPROP_TIME, 1, endTime + PeriodSeconds() * 100);
    ObjectSetDouble(0, bgUpName, OBJPROP_PRICE, 1, 50);
    ObjectSetInteger(0, bgUpName, OBJPROP_BGCOLOR, colorUp);
    ObjectSetInteger(0, bgUpName, OBJPROP_COLOR, colorUp);

    if(ObjectFind(0, bgDnName) < 0)
    {
        if(ObjectCreate(0, bgDnName, OBJ_RECTANGLE, subWindow, startTime, 50, endTime, 0))
        {
            ObjectSetInteger(0, bgDnName, OBJPROP_FILL, true);
            ObjectSetInteger(0, bgDnName, OBJPROP_BACK, true);
            ObjectSetInteger(0, bgDnName, OBJPROP_SELECTABLE, false);
        }
    }
    ObjectSetInteger(0, bgDnName, OBJPROP_TIME, 0, startTime);
    ObjectSetDouble(0, bgDnName, OBJPROP_PRICE, 0, 50);
    ObjectSetInteger(0, bgDnName, OBJPROP_TIME, 1, endTime + PeriodSeconds() * 100);
    ObjectSetDouble(0, bgDnName, OBJPROP_PRICE, 1, 0);
    ObjectSetInteger(0, bgDnName, OBJPROP_BGCOLOR, colorDn);
    ObjectSetInteger(0, bgDnName, OBJPROP_COLOR, colorDn);
}