//+------------------------------------------------------------------+
//|                                                    XU-MA v3.mq5  |
//|                                      Converted from MQL4 to MQL5 |
//+------------------------------------------------------------------+
#property copyright "XARD UNIVERSE"
#property link      "https://forex-station.com"
#property version   "3.00"
#property description "[XU-MA v3]"
#property description "THIS IS A FREE INDICATOR"
#property description "Welcome to XARD UNIVERSE"

#property indicator_chart_window
#property indicator_buffers 21
#property indicator_plots   11

//--- Inputs
input string          Indicator                  = "[XU-MA v3]";
//--- [01] Candle Settings
input string          STR01                      = "<<<==== [01] Candle Settings ====>>>";
input bool            showCANDLES                = true;
input int             cWick                      = 1;
input color           CandleUp                   = C'96,170,204';
input color           CandleWt                   = C'34,34,34';
input color           CandleDn                   = C'255,140,255';
input bool            EnableGradient             = true; // Enable 20-Step Gradient Coloring
//--- [02] Openline Settings
input string          STR02                      = "<<<==== [02] Openline Settings ====>>>";
input bool            showDOP                    = true;
input int             DOPwidth                   = 5;
input int             DOPtf                      = 1440;
input color           DOPclr                     = C'60,60,60';
//--- [03] TREND Settings
input string          STR03                      = "<<<==== [03] TREND Settings ====>>>";
input bool            showTREND                  = true;
input color           TRENDupclr                 = clrBlue;
input color           TRENDdnclr                 = clrCrimson;
input color           Tbgdclr                    = C'100,130,160';
input int             TRENDper                   = 36;
input int             TRENDtf                    = 0;
input int             TRENDshft                  = 0;
input ENUM_MA_METHOD  TRENDmode                  = MODE_EMA;
input ENUM_APPLIED_PRICE TRENDtype               = PRICE_MEDIAN;
input int             TRENDwidth                 = 7;
//--- [04] SIGNAL Settings
input string          STR04                      = "<<<==== [04] SIGNAL Settings ====>>>";
input bool            showSIGNAL                 = true;
input color           SIGNALupclr                = clrBlue;
input color           SIGNALdnclr                = clrCrimson;
input color           Sbgdclr                    = C'100,130,160';
input int             SIGNALper                  = 9;
input int             SIGNALtf                   = 0;
input int             SIGNALshft                 = 0;
input ENUM_MA_METHOD  SIGNALmode                 = MODE_EMA;
input ENUM_APPLIED_PRICE SIGNALtype              = PRICE_MEDIAN;
input int             SIGNALwidth                = 4;
//--- [05] BGDzones Settings
input string          STR05                      = "<<<==== [05] BGDzones Settings ====>>>";
input bool            showBGDzones               = true;
input ENUM_APPLIED_PRICE CCIPrice                = PRICE_TYPICAL;
input color           ColorUp                    = C'53,72,110';
input color           ColorDown                  = C'120,63,82';
input color           ColorWait                  = C'91,103,112';
//--- [06] BOXtxt Settings
input string          STR06                      = "<<<==== [06] BOXtxt Settings ====>>>";
input bool            showBOXtxt                 = true;
input bool            showSig                    = true;
input int             moveTxtLR                  = 0;
input int             moveTxtUD                  = 0;
input int             FontSize                   = 15;
//--- [07] Alert Settings
input string          STR07                      = "<<<==== [07] Alert Settings ====>>>";
input bool            AlertsOn                   = true;
input bool            AlertsOnCurrent            = true;
input bool            AlertsMessage              = true;
input bool            AlertsSound                = false;
input bool            alertsNotify               = true;
input bool            AlertsEmail                = false;
input string          soundfile                  = "alert1.wav";
//--- [08] Dashboard Settings
input string          STR08                      = "<<<==== [08] Dashboard Settings ====>>>";
input bool            showDashboard              = true;
input int             dashX                      = 20;
input int             dashY                      = 80;
input ENUM_BASE_CORNER dashCorner                = CORNER_LEFT_UPPER;

//--- Buffers
double candle0[], candle1[], candle2[], candle3[], candle4[], candle5[], candle6[], candle7[];
double DOP[];
double Tbgd[], TREND[], TRENDdna[], TRENDdnb[], trend[];
double Sbgd[], SIGNAL[], SIGNALdna[], SIGNALdnb[], signal_buf[];
double colors[], xtrend[];

//--- Global variables
ENUM_TIMEFRAMES timeFrame;
string ID = "b";
datetime lastDummyTime = 0;

//--- Indicator handles
int h_TREND_high = INVALID_HANDLE;
int h_TREND_low  = INVALID_HANDLE;
int h_TREND_med  = INVALID_HANDLE;
int h_SIGNAL_high = INVALID_HANDLE;
int h_SIGNAL_low  = INVALID_HANDLE;
int h_SIGNAL_med  = INVALID_HANDLE;

//--- Dashboard Data Struct
struct DashTFData {
   ENUM_TIMEFRAMES tf;
   string name;
   int h_t_h, h_t_l;
   int h_s_h, h_s_l;
};

DashTFData dashData[8];

//+------------------------------------------------------------------+
//| Helper to map integer timeframe to ENUM_TIMEFRAMES               |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES IntegerToTFEnum(int minutes)
{
   if(minutes <= 0) return PERIOD_CURRENT;
   switch(minutes)
   {
      case 1:    return PERIOD_M1;
      case 2:    return PERIOD_M2;
      case 3:    return PERIOD_M3;
      case 4:    return PERIOD_M4;
      case 5:    return PERIOD_M5;
      case 6:    return PERIOD_M6;
      case 10:   return PERIOD_M10;
      case 12:   return PERIOD_M12;
      case 15:   return PERIOD_M15;
      case 20:   return PERIOD_M20;
      case 30:   return PERIOD_M30;
      case 60:   return PERIOD_H1;
      case 120:  return PERIOD_H2;
      case 180:  return PERIOD_H3;
      case 240:  return PERIOD_H4;
      case 360:  return PERIOD_H6;
      case 480:  return PERIOD_H8;
      case 720:  return PERIOD_H12;
      case 1440: return PERIOD_D1;
      case 10080:return PERIOD_W1;
      case 43200:return PERIOD_MN1;
      default:   return PERIOD_CURRENT;
   }
}

//+------------------------------------------------------------------+
//| Helper forward declarations                                      |
//+------------------------------------------------------------------+
void candle(int direction, int i, const double &open[], const double &close[], const double &high[], const double &low[]);
void candle_gradient(int color_idx, int i, const double &open[], const double &close[], const double &high[], const double &low[]);
color GetGradientColor(color clrFrom, color clrTo, int step, int total_steps);
void UpdatePanelAndLabels();
void UpdateDashboard();
color GetDashboardColor(ENUM_TIMEFRAMES tf, int tf_idx);
color GetContrastColor(color bg);
void manageAlerts(const datetime &time[]);
void doAlert(string direction);
void CleanUpOnIsle1();
double GetHTFPrice(string symbol, ENUM_TIMEFRAMES tf, int price_type, int shift);
double GetHTFMAValMQ5(string symbol, ENUM_TIMEFRAMES tf, int period, int shift_ma, int ma_method, int price_type, int ltf_bar_i,
                      const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[],
                      const double &htf_ma_buffer[]);

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
   IndicatorSetString(INDICATOR_SHORTNAME, ID);
   
   //--- Candle Buffers (Plots 0 and 1)
   SetIndexBuffer(0, candle0, INDICATOR_DATA);
   SetIndexBuffer(1, candle1, INDICATOR_DATA);
   SetIndexBuffer(2, candle2, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(3, candle3, INDICATOR_DATA);
   SetIndexBuffer(4, candle4, INDICATOR_DATA);
   SetIndexBuffer(5, candle5, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(6, candle6, INDICATOR_CALCULATIONS);
   SetIndexBuffer(7, candle7, INDICATOR_CALCULATIONS);
   
   // Plot 0: Wicks
   PlotIndexSetInteger(0, PLOT_DRAW_TYPE, showCANDLES ? DRAW_COLOR_HISTOGRAM2 : DRAW_NONE);
   PlotIndexSetInteger(0, PLOT_LINE_WIDTH, cWick);
   if(EnableGradient && showCANDLES)
   {
      PlotIndexSetInteger(0, PLOT_COLOR_INDEXES, 41);
      PlotIndexSetInteger(0, PLOT_LINE_COLOR, 0, CandleWt);
      for(int s = 1; s <= 20; s++) PlotIndexSetInteger(0, PLOT_LINE_COLOR, s, GetGradientColor(CandleWt, CandleUp, s - 1, 20));
      for(int s = 1; s <= 20; s++) PlotIndexSetInteger(0, PLOT_LINE_COLOR, 20 + s, GetGradientColor(CandleWt, CandleDn, s - 1, 20));
   }
   else
   {
      PlotIndexSetInteger(0, PLOT_COLOR_INDEXES, 3);
      PlotIndexSetInteger(0, PLOT_LINE_COLOR, 0, CandleUp);
      PlotIndexSetInteger(0, PLOT_LINE_COLOR, 1, CandleWt);
      PlotIndexSetInteger(0, PLOT_LINE_COLOR, 2, CandleDn);
   }
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetString(0, PLOT_LABEL, "Wicks");
   
   // Plot 1: Bodies
   PlotIndexSetInteger(1, PLOT_DRAW_TYPE, showCANDLES ? DRAW_COLOR_HISTOGRAM2 : DRAW_NONE);
   PlotIndexSetInteger(1, PLOT_LINE_WIDTH, cWick + 4);
   if(EnableGradient && showCANDLES)
   {
      PlotIndexSetInteger(1, PLOT_COLOR_INDEXES, 41);
      PlotIndexSetInteger(1, PLOT_LINE_COLOR, 0, CandleWt);
      for(int s = 1; s <= 20; s++) PlotIndexSetInteger(1, PLOT_LINE_COLOR, s, GetGradientColor(CandleWt, CandleUp, s - 1, 20));
      for(int s = 1; s <= 20; s++) PlotIndexSetInteger(1, PLOT_LINE_COLOR, 20 + s, GetGradientColor(CandleWt, CandleDn, s - 1, 20));
   }
   else
   {
      PlotIndexSetInteger(1, PLOT_COLOR_INDEXES, 3);
      PlotIndexSetInteger(1, PLOT_LINE_COLOR, 0, CandleUp);
      PlotIndexSetInteger(1, PLOT_LINE_COLOR, 1, CandleWt);
      PlotIndexSetInteger(1, PLOT_LINE_COLOR, 2, CandleDn);
   }
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetString(1, PLOT_LABEL, "Bodies");
   
   //--- DOP Buffer (Plot 2)
   SetIndexBuffer(8, DOP, INDICATOR_DATA);
   PlotIndexSetDouble(8, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   if(showDOP && PeriodSeconds() <= PeriodSeconds(PERIOD_H1))
   {
      PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_LINE);
      PlotIndexSetInteger(2, PLOT_LINE_WIDTH, DOPwidth);
      PlotIndexSetInteger(2, PLOT_LINE_COLOR, DOPclr);
      PlotIndexSetString(2, PLOT_LABEL, "DOP");
   }
   else
   {
      PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_NONE);
   }

   //--- TREND Buffers (Plot 3, 4, 5, 6)
   SetIndexBuffer(9,  Tbgd,    INDICATOR_DATA);
   SetIndexBuffer(10, TREND,   INDICATOR_DATA);
   SetIndexBuffer(11, TRENDdna,INDICATOR_DATA);
   SetIndexBuffer(12, TRENDdnb,INDICATOR_DATA);
   SetIndexBuffer(13, trend,   INDICATOR_CALCULATIONS);
   if(showTREND)
   {
      PlotIndexSetInteger(3, PLOT_DRAW_TYPE, DRAW_LINE);
      PlotIndexSetInteger(3, PLOT_LINE_WIDTH, TRENDwidth + 4);
      PlotIndexSetInteger(3, PLOT_LINE_COLOR, Tbgdclr);
      PlotIndexSetString(3, PLOT_LABEL, "Tbgd");

      PlotIndexSetInteger(4, PLOT_DRAW_TYPE, DRAW_LINE);
      PlotIndexSetInteger(4, PLOT_LINE_WIDTH, TRENDwidth);
      PlotIndexSetInteger(4, PLOT_LINE_COLOR, TRENDupclr);
      PlotIndexSetString(4, PLOT_LABEL, "TREND");

      PlotIndexSetInteger(5, PLOT_DRAW_TYPE, DRAW_LINE);
      PlotIndexSetInteger(5, PLOT_LINE_WIDTH, TRENDwidth);
      PlotIndexSetInteger(5, PLOT_LINE_COLOR, TRENDdnclr);
      PlotIndexSetString(5, PLOT_LABEL, "TRENDdna");

      PlotIndexSetInteger(6, PLOT_DRAW_TYPE, DRAW_LINE);
      PlotIndexSetInteger(6, PLOT_LINE_WIDTH, TRENDwidth);
      PlotIndexSetInteger(6, PLOT_LINE_COLOR, TRENDdnclr);
      PlotIndexSetString(6, PLOT_LABEL, "TRENDdnb");
   }
   else
   {
      for(int i = 3; i <= 6; i++) PlotIndexSetInteger(i, PLOT_DRAW_TYPE, DRAW_NONE);
   }

   //--- SIGNAL Buffers (Plot 7, 8, 9, 10)
   SetIndexBuffer(14, Sbgd,     INDICATOR_DATA);
   SetIndexBuffer(15, SIGNAL,   INDICATOR_DATA);
   SetIndexBuffer(16, SIGNALdna,INDICATOR_DATA);
   SetIndexBuffer(17, SIGNALdnb,INDICATOR_DATA);
   SetIndexBuffer(18, signal_buf, INDICATOR_CALCULATIONS);
   if(showSIGNAL)
   {
      PlotIndexSetInteger(7, PLOT_DRAW_TYPE, DRAW_LINE);
      PlotIndexSetInteger(7, PLOT_LINE_WIDTH, SIGNALwidth + 4);
      PlotIndexSetInteger(7, PLOT_LINE_COLOR, Sbgdclr);
      PlotIndexSetString(7, PLOT_LABEL, "Sbgd");

      PlotIndexSetInteger(8, PLOT_DRAW_TYPE, DRAW_LINE);
      PlotIndexSetInteger(8, PLOT_LINE_WIDTH, SIGNALwidth);
      PlotIndexSetInteger(8, PLOT_LINE_COLOR, SIGNALupclr);
      PlotIndexSetString(8, PLOT_LABEL, "SIGNAL");

      PlotIndexSetInteger(9, PLOT_DRAW_TYPE, DRAW_LINE);
      PlotIndexSetInteger(9, PLOT_LINE_WIDTH, SIGNALwidth);
      PlotIndexSetInteger(9, PLOT_LINE_COLOR, SIGNALdnclr);
      PlotIndexSetString(9, PLOT_LABEL, "SIGNALdna");

      PlotIndexSetInteger(10, PLOT_DRAW_TYPE, DRAW_LINE);
      PlotIndexSetInteger(10, PLOT_LINE_WIDTH, SIGNALwidth);
      PlotIndexSetInteger(10, PLOT_LINE_COLOR, SIGNALdnclr);
      PlotIndexSetString(10, PLOT_LABEL, "SIGNALdnb");
   }
   else
   {
      for(int i = 7; i <= 10; i++) PlotIndexSetInteger(i, PLOT_DRAW_TYPE, DRAW_NONE);
   }

   SetIndexBuffer(19, colors,  INDICATOR_CALCULATIONS);
   SetIndexBuffer(20, xtrend,  INDICATOR_CALCULATIONS);

   // Set Array Series mapping
   ArraySetAsSeries(candle0, true);
   ArraySetAsSeries(candle1, true);
   ArraySetAsSeries(candle2, true);
   ArraySetAsSeries(candle3, true);
   ArraySetAsSeries(candle4, true);
   ArraySetAsSeries(candle5, true);
   ArraySetAsSeries(candle6, true);
   ArraySetAsSeries(candle7, true);
   ArraySetAsSeries(DOP, true);
   ArraySetAsSeries(Tbgd, true);
   ArraySetAsSeries(TREND, true);
   ArraySetAsSeries(TRENDdna, true);
   ArraySetAsSeries(TRENDdnb, true);
   ArraySetAsSeries(trend, true);
   ArraySetAsSeries(Sbgd, true);
   ArraySetAsSeries(SIGNAL, true);
   ArraySetAsSeries(SIGNALdna, true);
   ArraySetAsSeries(SIGNALdnb, true);
   ArraySetAsSeries(signal_buf, true);
   ArraySetAsSeries(colors, true);
   ArraySetAsSeries(xtrend, true);
   
   timeFrame = (DOPtf > 0) ? IntegerToTFEnum(DOPtf) : Period();

   // Create MA handles
   ENUM_TIMEFRAMES trendTF = IntegerToTFEnum(TRENDtf);
   h_TREND_high = iMA(_Symbol, trendTF, TRENDper, TRENDshft, TRENDmode, PRICE_HIGH);
   h_TREND_low  = iMA(_Symbol, trendTF, TRENDper, TRENDshft, TRENDmode, PRICE_LOW);
   h_TREND_med  = iMA(_Symbol, trendTF, TRENDper, TRENDshft, TRENDmode, TRENDtype);

   ENUM_TIMEFRAMES signalTF = IntegerToTFEnum(SIGNALtf);
   h_SIGNAL_high = iMA(_Symbol, signalTF, SIGNALper, SIGNALshft, SIGNALmode, PRICE_HIGH);
   h_SIGNAL_low  = iMA(_Symbol, signalTF, SIGNALper, SIGNALshft, SIGNALmode, PRICE_LOW);
   h_SIGNAL_med  = iMA(_Symbol, signalTF, SIGNALper, SIGNALshft, SIGNALmode, SIGNALtype);

   if(h_TREND_high == INVALID_HANDLE || h_TREND_low == INVALID_HANDLE || h_TREND_med == INVALID_HANDLE ||
      h_SIGNAL_high == INVALID_HANDLE || h_SIGNAL_low == INVALID_HANDLE || h_SIGNAL_med == INVALID_HANDLE)
   {
      Print("Error creating indicator handles");
      return(INIT_FAILED);
   }

   // Initialize MTF Dashboard Handles
   if(showDashboard)
   {
      ENUM_TIMEFRAMES d_tfs[8] = {PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1};
      string d_names[8] = {"M1", "M5", "M15", "M30", "H1", "H4", "D1", "W1"};
      
      for(int i = 0; i < 8; i++)
      {
         dashData[i].tf = d_tfs[i];
         dashData[i].name = d_names[i];
         dashData[i].h_t_h = iMA(_Symbol, d_tfs[i], TRENDper, TRENDshft, TRENDmode, PRICE_HIGH);
         dashData[i].h_t_l = iMA(_Symbol, d_tfs[i], TRENDper, TRENDshft, TRENDmode, PRICE_LOW);
         dashData[i].h_s_h = iMA(_Symbol, d_tfs[i], SIGNALper, SIGNALshft, SIGNALmode, PRICE_HIGH);
         dashData[i].h_s_l = iMA(_Symbol, d_tfs[i], SIGNALper, SIGNALshft, SIGNALmode, PRICE_LOW);
      }
   }

   EventSetTimer(60);
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   CleanUpOnIsle1();
   EventKillTimer();

   // Release core handles
   IndicatorRelease(h_TREND_high);
   IndicatorRelease(h_TREND_low);
   IndicatorRelease(h_TREND_med);
   IndicatorRelease(h_SIGNAL_high);
   IndicatorRelease(h_SIGNAL_low);
   IndicatorRelease(h_SIGNAL_med);
   
   // Release dashboard handles
   if(showDashboard)
   {
      for(int i = 0; i < 8; i++)
      {
         if(dashData[i].h_t_h != INVALID_HANDLE) IndicatorRelease(dashData[i].h_t_h);
         if(dashData[i].h_t_l != INVALID_HANDLE) IndicatorRelease(dashData[i].h_t_l);
         if(dashData[i].h_s_h != INVALID_HANDLE) IndicatorRelease(dashData[i].h_s_h);
         if(dashData[i].h_s_l != INVALID_HANDLE) IndicatorRelease(dashData[i].h_s_l);
      }
   }
}

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
{
   ChartRedraw();
}

//+------------------------------------------------------------------+
//| Main calculation 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[])
{
   if(rates_total < 100) return(0);
   
   // Set array indexing style to series (index 0 is newest bar)
   ArraySetAsSeries(time, true);
   ArraySetAsSeries(open, true);
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low, true);
   ArraySetAsSeries(close, true);

   // Set up local arrays to copy MA values
   double trend_high_arr[], trend_low_arr[], trend_med_arr[];
   double sig_high_arr[], sig_low_arr[], sig_med_arr[];

   ArraySetAsSeries(trend_high_arr, true);
   ArraySetAsSeries(trend_low_arr, true);
   ArraySetAsSeries(trend_med_arr, true);
   ArraySetAsSeries(sig_high_arr, true);
   ArraySetAsSeries(sig_low_arr, true);
   ArraySetAsSeries(sig_med_arr, true);
   
   // Copy buffer data to local arrays
   if(CopyBuffer(h_TREND_high, 0, 0, rates_total, trend_high_arr) < 0) return(0);
   if(CopyBuffer(h_TREND_low,  0, 0, rates_total, trend_low_arr)  < 0) return(0);
   if(CopyBuffer(h_TREND_med,  0, 0, rates_total, trend_med_arr)  < 0) return(0);
   if(CopyBuffer(h_SIGNAL_high, 0, 0, rates_total, sig_high_arr) < 0) return(0);
   if(CopyBuffer(h_SIGNAL_low,  0, 0, rates_total, sig_low_arr)  < 0) return(0);
   if(CopyBuffer(h_SIGNAL_med,  0, 0, rates_total, sig_med_arr)  < 0) return(0);

   int limit = rates_total - prev_calculated;
   if(prev_calculated == 0) limit = rates_total - 1;
   
   //--- DOP Line
   if(showDOP)
   {
      for(int i = limit; i >= 0; i--)
      {
         double open_val[1];
         ENUM_TIMEFRAMES dopTF = IntegerToTFEnum(DOPtf);
         if(CopyOpen(_Symbol, dopTF, time[i], 1, open_val) > 0)
         {
            DOP[i] = open_val[0];
         }
         else
         {
            DOP[i] = (i < rates_total - 1) ? DOP[i+1] : EMPTY_VALUE;
         }
      }
   }

   //--- TREND Calculation
   if(showTREND)
   {
      for(int i = limit; i >= 0; i--)
      {
         double ma_high = GetHTFMAValMQ5(_Symbol, IntegerToTFEnum(TRENDtf), TRENDper, TRENDshft, TRENDmode, PRICE_HIGH, i, time, open, high, low, close, trend_high_arr);
         double ma_low  = GetHTFMAValMQ5(_Symbol, IntegerToTFEnum(TRENDtf), TRENDper, TRENDshft, TRENDmode, PRICE_LOW,  i, time, open, high, low, close, trend_low_arr);
         double ma_med  = GetHTFMAValMQ5(_Symbol, IntegerToTFEnum(TRENDtf), TRENDper, TRENDshft, TRENDmode, TRENDtype, i, time, open, high, low, close, trend_med_arr);
         
         if(close[i] > ma_high) trend[i] = 1;
         else if(close[i] < ma_low) trend[i] = -1;
         else trend[i] = (i < rates_total-1) ? trend[i+1] : 0;
         
         TREND[i] = ma_med;
         Tbgd[i] = ma_med;
         
         TRENDdna[i] = (trend[i] == -1) ? ma_med : EMPTY_VALUE;
         TRENDdnb[i] = (trend[i] == -1) ? ma_med : EMPTY_VALUE;
      }
   }

   //--- SIGNAL Calculation
   if(showSIGNAL)
   {
      for(int i = limit; i >= 0; i--)
      {
         double ma_high = GetHTFMAValMQ5(_Symbol, IntegerToTFEnum(SIGNALtf), SIGNALper, SIGNALshft, SIGNALmode, PRICE_HIGH, i, time, open, high, low, close, sig_high_arr);
         double ma_low  = GetHTFMAValMQ5(_Symbol, IntegerToTFEnum(SIGNALtf), SIGNALper, SIGNALshft, SIGNALmode, PRICE_LOW,  i, time, open, high, low, close, sig_low_arr);
         double ma_med  = GetHTFMAValMQ5(_Symbol, IntegerToTFEnum(SIGNALtf), SIGNALper, SIGNALshft, SIGNALmode, SIGNALtype, i, time, open, high, low, close, sig_med_arr);
         
         if(close[i] > ma_high) signal_buf[i] = 1;
         else if(close[i] < ma_low) signal_buf[i] = -1;
         else signal_buf[i] = (i < rates_total-1) ? signal_buf[i+1] : 0;
         
         SIGNAL[i] = ma_med;
         Sbgd[i] = ma_med;
         
         SIGNALdna[i] = (signal_buf[i] == -1) ? ma_med : EMPTY_VALUE;
         SIGNALdnb[i] = (signal_buf[i] == -1) ? ma_med : EMPTY_VALUE;
      }
   }

   //--- Direction & Candles
   for(int i = limit; i >= 0; i--)
   {
      if(trend[i] == 1 && signal_buf[i] == 1)
         xtrend[i] = 1;
      else if(trend[i] == -1 && signal_buf[i] == -1)
         xtrend[i] = -1;
      else
         xtrend[i] = 0;

      candle6[i] = 0.0;
      candle7[i] = 0.0;
      
      if(EnableGradient)
      {
         int color_idx = 0;
         if(xtrend[i] == 1)
         {
            int steps = 0;
            for(int j = 0; j < 20; j++)
            {
               if(i + j < rates_total && xtrend[i + j] == 1) steps++;
               else break;
            }
            if(steps < 1) steps = 1;
            if(steps > 20) steps = 20;
            color_idx = steps; // Indices 1 to 20: Up Trend
         }
         else if(xtrend[i] == -1)
         {
            int steps = 0;
            for(int j = 0; j < 20; j++)
            {
               if(i + j < rates_total && xtrend[i + j] == -1) steps++;
               else break;
            }
            if(steps < 1) steps = 1;
            if(steps > 20) steps = 20;
            color_idx = 20 + steps; // Indices 21 to 40: Down Trend
         }
         candle_gradient(color_idx, i, open, close, high, low);
      }
      else
      {
         if(xtrend[i] == 1)       candle(1, i, open, close, high, low);
         else if(xtrend[i] == -1) candle(3, i, open, close, high, low);
         else                     candle(2, i, open, close, high, low);
      }
   }

   //--- Background Zones
   if(showBGDzones)
   {
      for(int i = limit; i >= 0; i--)
      {
         colors[i] = (trend[i] == 1) ? 1 : (trend[i] == -1 ? -1 : 0);
      }
   }

   //--- Draw Objects (Panel & Labels)
   UpdatePanelAndLabels();
   UpdateDashboard();
   manageAlerts(time);

   return(rates_total);
}

//+------------------------------------------------------------------+
//| Candle Drawing Function (Standard Colors)                        |
//+------------------------------------------------------------------+
void candle(int direction, int i, const double &open[], const double &close[], const double &high[], const double &low[])
{
   double bodyHigh = MathMax(open[i], close[i]);
   double bodyLow  = MathMin(open[i], close[i]);
   
   if(!showCANDLES)
   {
      candle0[i] = EMPTY_VALUE;
      candle1[i] = EMPTY_VALUE;
      candle2[i] = EMPTY_VALUE;
      candle3[i] = EMPTY_VALUE;
      candle4[i] = EMPTY_VALUE;
      candle5[i] = EMPTY_VALUE;
      return;
   }

   candle0[i] = low[i];
   candle1[i] = high[i];
   candle3[i] = bodyLow;
   candle4[i] = bodyHigh;
   
   switch(direction)
   {
      case 1: // Up
         candle2[i] = 0.0; // Color index 0 (CandleUp)
         candle5[i] = 0.0; // Color index 0 (CandleUp)
         break;
      case 2: // Neutral
         candle2[i] = 1.0; // Color index 1 (CandleWt)
         candle5[i] = 1.0; // Color index 1 (CandleWt)
         break;
      case 3: // Down
         candle2[i] = 2.0; // Color index 2 (CandleDn)
         candle5[i] = 2.0; // Color index 2 (CandleDn)
         break;
      default:
         candle0[i] = EMPTY_VALUE;
         candle1[i] = EMPTY_VALUE;
         candle2[i] = EMPTY_VALUE;
         candle3[i] = EMPTY_VALUE;
         candle4[i] = EMPTY_VALUE;
         candle5[i] = EMPTY_VALUE;
         break;
   }
}

//+------------------------------------------------------------------+
//| Candle Drawing Function (Gradient Colors)                        |
//+------------------------------------------------------------------+
void candle_gradient(int color_idx, int i, const double &open[], const double &close[], const double &high[], const double &low[])
{
   double bodyHigh = MathMax(open[i], close[i]);
   double bodyLow  = MathMin(open[i], close[i]);
   
   if(!showCANDLES)
   {
      candle0[i] = EMPTY_VALUE;
      candle1[i] = EMPTY_VALUE;
      candle2[i] = EMPTY_VALUE;
      candle3[i] = EMPTY_VALUE;
      candle4[i] = EMPTY_VALUE;
      candle5[i] = EMPTY_VALUE;
      return;
   }

   candle0[i] = low[i];
   candle1[i] = high[i];
   candle3[i] = bodyLow;
   candle4[i] = bodyHigh;
   
   candle2[i] = (double)color_idx;
   candle5[i] = (double)color_idx;
}

//+------------------------------------------------------------------+
//| Helper to calculate linear color shifts                          |
//+------------------------------------------------------------------+
color GetGradientColor(color clrFrom, color clrTo, int step, int total_steps)
{
   if(total_steps <= 1) return clrTo;
   
   uchar r1 = (uchar)(clrFrom & 0xFF);
   uchar g1 = (uchar)((clrFrom >> 8) & 0xFF);
   uchar b1 = (uchar)((clrFrom >> 16) & 0xFF);
   
   uchar r2 = (uchar)(clrTo & 0xFF);
   uchar g2 = (uchar)((clrTo >> 8) & 0xFF);
   uchar b2 = (uchar)((clrTo >> 16) & 0xFF);
   
   double factor = (double)step / (double)(total_steps - 1);
   
   uchar r = (uchar)(r1 + factor * (r2 - r1));
   uchar g = (uchar)(g1 + factor * (g2 - g1));
   uchar b = (uchar)(b1 + factor * (b2 - b1));
   
   return (color)(r | (g << 8) | (b << 16));
}

//+------------------------------------------------------------------+
//| Determine best text color (White/Black) based on bg luminance    |
//+------------------------------------------------------------------+
color GetContrastColor(color bg)
{
   int r = (bg & 0xFF);
   int g = ((bg >> 8) & 0xFF);
   int b = ((bg >> 16) & 0xFF);
   double yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000.0;
   
   return (yiq >= 128) ? clrBlack : clrWhite;
}

//+------------------------------------------------------------------+
//| Update Panel and Labels                                          |
//+------------------------------------------------------------------+
void UpdatePanelAndLabels()
{
   if(!showBOXtxt) return;

   string stateText  = "WAIT";
   color  stateColor = ColorWait;
   
   if(xtrend[0] == 1.0)       { stateText = "BUY";  stateColor = TRENDupclr; }
   else if(xtrend[0] == -1.0) { stateText = "SELL"; stateColor = TRENDdnclr; }

   string panelName = ID + "_panel";
   if(ObjectFind(0, panelName) < 0)
   {
      ObjectCreate(0, panelName, OBJ_RECTANGLE_LABEL, 0, 0, 0);
      ObjectSetInteger(0, panelName, OBJPROP_CORNER,    CORNER_LEFT_UPPER);
      ObjectSetInteger(0, panelName, OBJPROP_XDISTANCE, 10 + moveTxtLR);
      ObjectSetInteger(0, panelName, OBJPROP_YDISTANCE, 20 + moveTxtUD);
      ObjectSetInteger(0, panelName, OBJPROP_XSIZE,     120);
      ObjectSetInteger(0, panelName, OBJPROP_YSIZE,     40);
      ObjectSetInteger(0, panelName, OBJPROP_BGCOLOR,   C'20,20,20');
      ObjectSetInteger(0, panelName, OBJPROP_BORDER_TYPE, BORDER_FLAT);
      ObjectSetInteger(0, panelName, OBJPROP_COLOR,     C'60,60,60');
      ObjectSetInteger(0, panelName, OBJPROP_BACK,      true);
      ObjectSetInteger(0, panelName, OBJPROP_SELECTABLE, false);
   }
   else
   {
      ObjectSetInteger(0, panelName, OBJPROP_XDISTANCE, 10 + moveTxtLR);
      ObjectSetInteger(0, panelName, OBJPROP_YDISTANCE, 20 + moveTxtUD);
   }

   if(showSig)
   {
      string lblName = ID + "_label";
      if(ObjectFind(0, lblName) < 0)
      {
         ObjectCreate(0, lblName, OBJ_LABEL, 0, 0, 0);
         ObjectSetInteger(0, lblName, OBJPROP_CORNER,    CORNER_LEFT_UPPER);
         ObjectSetInteger(0, lblName, OBJPROP_SELECTABLE, false);
      }
      ObjectSetInteger(0, lblName, OBJPROP_XDISTANCE, 18 + moveTxtLR);
      ObjectSetInteger(0, lblName, OBJPROP_YDISTANCE, 25 + moveTxtUD);
      ObjectSetString (0, lblName, OBJPROP_TEXT,      stateText);
      ObjectSetInteger(0, lblName, OBJPROP_COLOR,     stateColor);
      ObjectSetInteger(0, lblName, OBJPROP_FONTSIZE,  FontSize);
      ObjectSetString (0, lblName, OBJPROP_FONT,      "Arial Bold");
   }

   ChartRedraw(0);
}

//+------------------------------------------------------------------+
//| Get Dashboard Background Color representing the current TF       |
//+------------------------------------------------------------------+
color GetDashboardColor(ENUM_TIMEFRAMES tf, int tf_idx)
{
   double th[], tl[], sh[], sl[], c[];
   int max_count = 300; 
   
   int c_c = CopyClose(_Symbol, tf, 0, max_count, c);
   if(c_c < 21) return clrNONE; // Need at least 21 bars for safe 20-step gradient calc
   
   int c_th = CopyBuffer(dashData[tf_idx].h_t_h, 0, 0, c_c, th);
   int c_tl = CopyBuffer(dashData[tf_idx].h_t_l, 0, 0, c_c, tl);
   int c_sh = CopyBuffer(dashData[tf_idx].h_s_h, 0, 0, c_c, sh);
   int c_sl = CopyBuffer(dashData[tf_idx].h_s_l, 0, 0, c_c, sl);

   // Establish true count available across all requested buffers to avoid out of bounds
   int count = MathMin(c_c, MathMin(c_th, MathMin(c_tl, MathMin(c_sh, c_sl))));
   if(count < 21) return clrNONE;

   ArraySetAsSeries(th, true);
   ArraySetAsSeries(tl, true);
   ArraySetAsSeries(sh, true);
   ArraySetAsSeries(sl, true);
   ArraySetAsSeries(c, true);
   
   double t[], s[], xt[];
   ArrayResize(t, count);
   ArrayResize(s, count);
   ArrayResize(xt, count);

   int last = count - 1;
   t[last]  = (c[last] > th[last]) ? 1 : ((c[last] < tl[last]) ? -1 : 0);
   s[last]  = (c[last] > sh[last]) ? 1 : ((c[last] < sl[last]) ? -1 : 0);
   xt[last] = (t[last] == 1 && s[last] == 1) ? 1 : ((t[last] == -1 && s[last] == -1) ? -1 : 0);
   
   for(int i = last - 1; i >= 0; i--)
   {
       t[i]  = (c[i] > th[i]) ? 1 : ((c[i] < tl[i]) ? -1 : t[i+1]);
       s[i]  = (c[i] > sh[i]) ? 1 : ((c[i] < sl[i]) ? -1 : s[i+1]);
       xt[i] = (t[i] == 1 && s[i] == 1) ? 1 : ((t[i] == -1 && s[i] == -1) ? -1 : 0);
   }

   int color_idx = 0;
   if(EnableGradient)
   {
       if(xt[0] == 1)
       {
           int steps = 0;
           for(int j = 0; j < 20; j++) {
               if(j < count && xt[j] == 1) steps++;
               else break;
           }
           if(steps < 1) steps = 1;
           if(steps > 20) steps = 20;
           color_idx = steps; 
       }
       else if(xt[0] == -1)
       {
           int steps = 0;
           for(int j = 0; j < 20; j++) {
               if(j < count && xt[j] == -1) steps++;
               else break;
           }
           if(steps < 1) steps = 1;
           if(steps > 20) steps = 20;
           color_idx = 20 + steps;
       }

       if(color_idx == 0) return CandleWt;
       if(color_idx >= 1 && color_idx <= 20) return GetGradientColor(CandleWt, CandleUp, color_idx - 1, 20);
       if(color_idx >= 21 && color_idx <= 40) return GetGradientColor(CandleWt, CandleDn, (color_idx - 20) - 1, 20);
   }
   else
   {
       if(xt[0] == 1) return CandleUp;
       if(xt[0] == -1) return CandleDn;
       return CandleWt;
   }

   return CandleWt;
}

//+------------------------------------------------------------------+
//| Update MTF Dashboard Visuals                                     |
//+------------------------------------------------------------------+
void UpdateDashboard()
{
   if(!showDashboard) return;

   int startX = dashX;
   int startY = dashY;

   string panelName = ID + "_dash_bg";
   if(ObjectFind(0, panelName) < 0)
   {
      ObjectCreate(0, panelName, OBJ_RECTANGLE_LABEL, 0, 0, 0);
      ObjectSetInteger(0, panelName, OBJPROP_CORNER, dashCorner);
      ObjectSetInteger(0, panelName, OBJPROP_XDISTANCE, startX - 5);
      ObjectSetInteger(0, panelName, OBJPROP_YDISTANCE, startY - 5);
      ObjectSetInteger(0, panelName, OBJPROP_XSIZE, 8 * 40 + 10);
      ObjectSetInteger(0, panelName, OBJPROP_YSIZE, 40);
      ObjectSetInteger(0, panelName, OBJPROP_BGCOLOR, C'20,20,20');
      ObjectSetInteger(0, panelName, OBJPROP_BORDER_TYPE, BORDER_FLAT);
      ObjectSetInteger(0, panelName, OBJPROP_COLOR, C'60,60,60');
      ObjectSetInteger(0, panelName, OBJPROP_BACK, true);
      ObjectSetInteger(0, panelName, OBJPROP_SELECTABLE, false);
   }
   else
   {
      ObjectSetInteger(0, panelName, OBJPROP_XDISTANCE, startX - 5);
      ObjectSetInteger(0, panelName, OBJPROP_YDISTANCE, startY - 5);
   }

   for(int i = 0; i < 8; i++)
   {
      color boxColor = GetDashboardColor(dashData[i].tf, i);
      
      string boxName = ID + "_dash_box_" + IntegerToString(i);
      if(ObjectFind(0, boxName) < 0)
      {
         ObjectCreate(0, boxName, OBJ_RECTANGLE_LABEL, 0, 0, 0);
         ObjectSetInteger(0, boxName, OBJPROP_CORNER, dashCorner);
         ObjectSetInteger(0, boxName, OBJPROP_XSIZE, 36);
         ObjectSetInteger(0, boxName, OBJPROP_YSIZE, 30);
         ObjectSetInteger(0, boxName, OBJPROP_BORDER_TYPE, BORDER_FLAT);
         ObjectSetInteger(0, boxName, OBJPROP_BACK, false);
         ObjectSetInteger(0, boxName, OBJPROP_SELECTABLE, false);
         ObjectSetInteger(0, boxName, OBJPROP_BGCOLOR, CandleWt); // Default initial color
         ObjectSetInteger(0, boxName, OBJPROP_COLOR, CandleWt);
      }
      ObjectSetInteger(0, boxName, OBJPROP_XDISTANCE, startX + i * 40);
      ObjectSetInteger(0, boxName, OBJPROP_YDISTANCE, startY);
      
      string lblName = ID + "_dash_lbl_" + IntegerToString(i);
      if(ObjectFind(0, lblName) < 0)
      {
         ObjectCreate(0, lblName, OBJ_LABEL, 0, 0, 0);
         ObjectSetInteger(0, lblName, OBJPROP_CORNER, dashCorner);
         ObjectSetInteger(0, lblName, OBJPROP_ANCHOR, ANCHOR_CENTER);
         ObjectSetInteger(0, lblName, OBJPROP_FONTSIZE, 8);
         ObjectSetString (0, lblName, OBJPROP_FONT, "Arial Bold");
         ObjectSetInteger(0, lblName, OBJPROP_SELECTABLE, false);
      }
      ObjectSetInteger(0, lblName, OBJPROP_XDISTANCE, startX + i * 40 + 18);
      ObjectSetInteger(0, lblName, OBJPROP_YDISTANCE, startY + 15);
      ObjectSetString (0, lblName, OBJPROP_TEXT, dashData[i].name);
      
      // Update color conditionally to avoid blinking grey on MTF data fetch failure
      if(boxColor != clrNONE) 
      {
         ObjectSetInteger(0, boxName, OBJPROP_BGCOLOR, boxColor);
         ObjectSetInteger(0, boxName, OBJPROP_COLOR, boxColor);
         ObjectSetInteger(0, lblName, OBJPROP_COLOR, GetContrastColor(boxColor));
      }
   }
   
   ChartRedraw(0); // Appended to ensure object property changes are visibly rendered without waiting for event timers
}

//+------------------------------------------------------------------+
//| Alert Management                                                 |
//+------------------------------------------------------------------+
void manageAlerts(const datetime &time[])
{
   if(!AlertsOn) return;
   
   static datetime lastAlertTime = 0;
   int shift = AlertsOnCurrent ? 0 : 1;
   
   if(xtrend[shift] != xtrend[shift+1] && time[shift] != lastAlertTime)
   {
      lastAlertTime = time[shift];
      string dir = (xtrend[shift] == 1.0) ? "UP" : "DOWN";
      doAlert(dir);
   }
}

void doAlert(string direction)
{
   string msg = _Symbol + " " + EnumToString(timeFrame) + " : Direction changed to " + direction;
   
   if(AlertsMessage) Alert(msg);
   if(AlertsSound) PlaySound(soundfile);
   if(alertsNotify) SendNotification(msg);
   if(AlertsEmail) SendMail("XU-MA Alert", msg);
}

//+------------------------------------------------------------------+
//| Clean all objects                                                |
//+------------------------------------------------------------------+
void CleanUpOnIsle1()
{
   for(int i = ObjectsTotal(0, -1, -1)-1; i >= 0; i--)
   {
      string name = ObjectName(0, i, -1, -1);
      if(StringFind(name, ID) == 0)
         ObjectDelete(0, name);
   }
}

//+------------------------------------------------------------------+
//| Get price of HTF bar at shift                                    |
//+------------------------------------------------------------------+
double GetHTFPrice(string symbol, ENUM_TIMEFRAMES tf, int price_type, int shift)
{
   double res[1];
   switch(price_type)
   {
      case PRICE_CLOSE:
         if(CopyClose(symbol, tf, shift, 1, res) > 0) return res[0];
         break;
      case PRICE_OPEN:
         if(CopyOpen(symbol, tf, shift, 1, res) > 0) return res[0];
         break;
      case PRICE_HIGH:
         if(CopyHigh(symbol, tf, shift, 1, res) > 0) return res[0];
         break;
      case PRICE_LOW:
         if(CopyLow(symbol, tf, shift, 1, res) > 0) return res[0];
         break;
      case PRICE_MEDIAN:
         {
            double h[1], l[1];
            if(CopyHigh(symbol, tf, shift, 1, h) > 0 && CopyLow(symbol, tf, shift, 1, l) > 0)
               return (h[0] + l[0]) / 2.0;
         }
         break;
      case PRICE_TYPICAL:
         {
            double h[1], l[1], c[1];
            if(CopyHigh(symbol, tf, shift, 1, h) > 0 && CopyLow(symbol, tf, shift, 1, l) > 0 && CopyClose(symbol, tf, shift, 1, c) > 0)
               return (h[0] + l[0] + c[0]) / 3.0;
         }
         break;
      case PRICE_WEIGHTED:
         {
            double h[1], l[1], c[1];
            if(CopyHigh(symbol, tf, shift, 1, h) > 0 && CopyLow(symbol, tf, shift, 1, l) > 0 && CopyClose(symbol, tf, shift, 1, c) > 0)
               return (h[0] + l[0] + 2.0 * c[0]) / 4.0;
         }
         break;
   }
   return 0;
}

//+------------------------------------------------------------------+
//| Calculate non-repainting HTF MA value for MQ5                    |
//+------------------------------------------------------------------+
double GetHTFMAValMQ5(string symbol, ENUM_TIMEFRAMES tf, int period, int shift_ma, int ma_method, int price_type, int ltf_bar_i,
                      const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[],
                      const double &htf_ma_buffer[])
{
   if(tf == PERIOD_CURRENT || tf == (ENUM_TIMEFRAMES)_Period)
   {
      return htf_ma_buffer[ltf_bar_i];
   }
   
   int htf_shift = iBarShift(symbol, tf, time[ltf_bar_i], false);
   htf_shift += shift_ma;
   
   // Calculate forming HTF bar prices at ltf_bar_i
   datetime htf_start_time = iTime(symbol, tf, htf_shift);
   int first_ltf_shift = iBarShift(symbol, (ENUM_TIMEFRAMES)_Period, htf_start_time, false);
   if(first_ltf_shift < ltf_bar_i) first_ltf_shift = ltf_bar_i;
   
   double temp_high = high[ltf_bar_i];
   double temp_low = low[ltf_bar_i];
   
   for(int k = ltf_bar_i + 1; k <= first_ltf_shift; k++)
   {
      if(high[k] > temp_high) temp_high = high[k];
      if(low[k] < temp_low) temp_low = low[k];
   }
   
   double temp_open = open[first_ltf_shift];
   double temp_close = close[ltf_bar_i];
   double temp_price = 0;
   
   switch(price_type)
   {
      case PRICE_CLOSE:     temp_price = temp_close; break;
      case PRICE_OPEN:      temp_price = temp_open; break;
      case PRICE_HIGH:      temp_price = temp_high; break;
      case PRICE_LOW:       temp_price = temp_low; break;
      case PRICE_MEDIAN:    temp_price = (temp_high + temp_low) / 2.0; break;
      case PRICE_TYPICAL:   temp_price = (temp_high + temp_low + temp_close) / 3.0; break;
      case PRICE_WEIGHTED:  temp_price = (temp_high + temp_low + 2.0 * temp_close) / 4.0; break;
      default:              temp_price = temp_close; break;
   }
   
   double prev_ma = htf_ma_buffer[htf_shift + 1];
   
   if(ma_method == MODE_EMA)
   {
      double alpha = 2.0 / (period + 1.0);
      return temp_price * alpha + prev_ma * (1.0 - alpha);
   }
   else if(ma_method == MODE_SMMA)
   {
      return (temp_price + prev_ma * (period - 1.0)) / period;
   }
   else if(ma_method == MODE_LWMA)
   {
      double sum = temp_price * period;
      double weight_sum = period;
      for(int k = 1; k < period; k++)
      {
         double p = GetHTFPrice(symbol, tf, price_type, htf_shift + k);
         sum += p * (period - k);
         weight_sum += (period - k);
      }
      return sum / weight_sum;
   }
   else // MODE_SMA
   {
      double sum = temp_price;
      for(int k = 1; k < period; k++)
      {
         sum += GetHTFPrice(symbol, tf, price_type, htf_shift + k);
      }
      return sum / period;
   }
}