//+------------------------------------------------------------------+
//|                                      UltimateMACD_MultiMA.mq4    |
//|                     Advanced MACD with 35+ Moving Average Types  |
//|                                    Version 1.0 - Production Ready |
//+------------------------------------------------------------------+
#property copyright "2025 - Advanced Trading Systems"
#property version   "1.00"
#property strict
#property indicator_separate_window
#property indicator_buffers 14
#property indicator_color1 clrGainsboro     // MACD line neutral
#property indicator_color2 clrCrimson       // MACD line above bands
#property indicator_color3 clrMediumBlue    // MACD line below bands
#property indicator_color4 clrOrange        // Signal line
#property indicator_color5 clrLime          // Histogram positive
#property indicator_color6 clrRed           // Histogram negative
#property indicator_color7 clrYellow        // Upper StdDev band
#property indicator_color8 clrYellow        // Lower StdDev band
#property indicator_color9 clrAqua          // Squeeze dots
#property indicator_color10 clrMagenta      // Divergence markers
#property indicator_color11 clrDimGray      // BB Upper
#property indicator_color12 clrDimGray      // BB Middle
#property indicator_color13 clrDimGray      // BB Lower
#property indicator_color14 clrNONE         // Hidden buffer for calculations

#define pi 3.14159265358979323846

//+------------------------------------------------------------------+
//| Enumerations for MA Methods                                      |
//+------------------------------------------------------------------+
enum ENUM_MA_MODE
{
   SMA,                 // Simple Moving Average
   EMA,                 // Exponential Moving Average
   Wilder,              // Wilder Exponential Moving Average
   LWMA,                // Linear Weighted Moving Average
   SineWMA,             // Sine Weighted Moving Average
   TriMA,               // Triangular Moving Average
   LSMA,                // Least Square Moving Average (Linear Regression)
   SMMA,                // Smoothed Moving Average
   HMA,                 // Hull Moving Average
   ZeroLagEMA,          // Zero-Lag Exponential Moving Average
   DEMA,                // Double Exponential Moving Average
   T3_basic,            // T3 by T.Tillson (original)
   ITrend,              // Instantaneous Trendline
   Median,              // Moving Median
   GeoMean,             // Geometric Mean
   REMA,                // Regularized EMA
   ILRS,                // Integral of Linear Regression Slope
   IE_2,                // Combination of LSMA and ILRS
   TriMAgen,            // Triangular Moving Average generalized
   VWMA,                // Volume Weighted Moving Average
   JSmooth,             // M.Jurik's Smoothing
   SMA_eq,              // Simplified SMA
   ALMA,                // Arnaud Legoux Moving Average
   TEMA,                // Triple Exponential Moving Average
   T3,                  // T3 by T.Tillson (corrected)
   Laguerre,            // Laguerre filter
   MD,                  // McGinley Dynamic
   BF2P,                // Two-pole Butterworth filter
   BF3P,                // Three-pole Butterworth filter
   SuperSmu,            // SuperSmoother
   Decycler,            // Simple Decycler
   eVWMA,               // Elastic Volume Weighted MA
   EWMA,                // Exponential Weighted Moving Average
   DsEMA,               // Double Smoothed EMA
   TsEMA,               // Triple Smoothed EMA
   VEMA                 // Volume-weighted Exponential Moving Average
};

enum ENUM_PRICE
{
   close,               // Close
   open,                // Open
   high,                // High
   low,                 // Low
   median,              // Median
   typical,             // Typical
   weightedClose,       // Weighted Close
   medianBody,          // Median Body (Open+Close)/2
   average,             // Average (High+Low+Open+Close)/4
   trendBiased,         // Trend Biased
   trendBiasedExt       // Trend Biased (extreme)
};

//+------------------------------------------------------------------+
//| Input Parameters                                                 |
//+------------------------------------------------------------------+
input string   sep1           = "═══ MACD MA Selection ═══";     // ───────────────────
input ENUM_MA_MODE FastMAMethod = EMA;                           // Fast MA Method
input int      FastMAPeriod   = 12;                              // Fast MA Period
input ENUM_MA_MODE SlowMAMethod = EMA;                           // Slow MA Method
input int      SlowMAPeriod   = 71;                              // Slow MA Period
input ENUM_MA_MODE SignalMAMethod = SMA;                         // Signal MA Method
input int      SignalMAPeriod = 9;                               // Signal MA Period

input string   sep2           = "═══ Price Settings ═══";        // ───────────────────
input ENUM_PRICE ApplyToPrice = close;                           // Price to use

input string   sep3           = "═══ Band Settings ═══";         // ───────────────────
input int      StdDevPeriod   = 20;                              // StdDev calculation period
input double   StdDevMultiplier = 2.0;                           // StdDev band multiplier
input int      BBPeriod       = 200;                             // Bollinger Band period
input double   BBDeviation    = 0.90;                             // Bollinger Band deviation
input bool     ShowBollingerBands = true;                        // Show Bollinger Bands

input string   sep4           = "═══ Color Change Settings ═══"; // ───────────────────
input bool     ColorOnSignalCross = true;                        // TRUE: Color on Signal cross | FALSE: Color on BB touch
input bool     RequireBothConditions = true;                     // Require BOTH BB position AND Signal cross

input string   sep5           = "═══ Signal Settings ═══";       // ───────────────────
input bool     ShowChartSignals = false;                          // Show signals on main chart
input bool     ShowBullishSignals = false;                        // Show bullish arrows
input bool     ShowBearishSignals = false;                        // Show bearish arrows
input bool     ShowVerticalLines = false;                        // Show vertical lines at signals
input bool     ShowInfoBox = false;                               // Show info box with signal details
input bool     ShowPriceMarkers = false;                          // Show circle markers at price

input string   sep6           = "═══ Display Settings ═══";      // ───────────────────
input bool     UseAdaptive    = false;                           // Adaptive parameters based on volatility
input bool     ShowSqueeze    = false;                           // Show volatility squeeze
input bool     ShowDivergence = false;                           // Show divergence signals
input bool     ShowHistogram  = false;                            // Show MACD histogram
input bool     AlertsEnabled  = false;                            // Enable all alerts

//+------------------------------------------------------------------+
//| Global Variables and Buffers                                     |
//+------------------------------------------------------------------+
// Indicator buffers
double MACDNeutral[];
double MACDAbove[];
double MACDBelow[];
double SignalLine[];
double HistogramPos[];
double HistogramNeg[];
double UpperBand[];
double LowerBand[];
double SqueezeDots[];
double DivergenceMarkers[];
double BBUpper[];
double BBMiddle[];
double BBLower[];
double MACDValues[];

// Working arrays for MA calculations
double tmp[][3][2];  // Temporary storage for complex MAs
double ma[3][4];     // MA storage
datetime prevtime[3];
double FastMABuffer[];
double SlowMABuffer[];
double MACDLine[];
double PriceBuffer[];
int ColorState[];

// Global variables
datetime lastAlertTime = 0;
int alertCooldown = 300;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
    // Validate input parameters
    if(FastMAPeriod <= 0 || SlowMAPeriod <= 0 || SignalMAPeriod <= 0)
    {
        Alert("Invalid MA period settings!");
        return(INIT_FAILED);
    }
    
    // Set indicator properties
    string fastName = EnumToString(FastMAMethod);
    string slowName = EnumToString(SlowMAMethod);
    string signalName = EnumToString(SignalMAMethod);
    
    IndicatorShortName("MACD-MultiMA [" + fastName + "(" + IntegerToString(FastMAPeriod) + 
                       ") - " + slowName + "(" + IntegerToString(SlowMAPeriod) + 
                       ") | Signal: " + signalName + "(" + IntegerToString(SignalMAPeriod) + ")]");
    IndicatorDigits(5);
    
    // Map buffers
    SetIndexBuffer(0, MACDNeutral);
    SetIndexBuffer(1, MACDAbove);
    SetIndexBuffer(2, MACDBelow);
    SetIndexBuffer(3, SignalLine);
    SetIndexBuffer(4, HistogramPos);
    SetIndexBuffer(5, HistogramNeg);
    SetIndexBuffer(6, UpperBand);
    SetIndexBuffer(7, LowerBand);
    SetIndexBuffer(8, SqueezeDots);
    SetIndexBuffer(9, DivergenceMarkers);
    SetIndexBuffer(10, BBUpper);
    SetIndexBuffer(11, BBMiddle);
    SetIndexBuffer(12, BBLower);
    SetIndexBuffer(13, MACDValues);
    
    // Set styles
    SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2);
    SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, 2);
    SetIndexStyle(2, DRAW_LINE, STYLE_SOLID, 2);
    SetIndexStyle(3, DRAW_LINE, STYLE_SOLID, 1);
    SetIndexStyle(4, DRAW_HISTOGRAM, STYLE_SOLID, 2);
    SetIndexStyle(5, DRAW_HISTOGRAM, STYLE_SOLID, 2);
    SetIndexStyle(6, DRAW_LINE, STYLE_DOT, 1);
    SetIndexStyle(7, DRAW_LINE, STYLE_DOT, 1);
    SetIndexStyle(8, DRAW_ARROW, STYLE_SOLID, 2);
    SetIndexStyle(9, DRAW_ARROW, STYLE_SOLID, 3);
    SetIndexStyle(10, DRAW_LINE, STYLE_SOLID, 1);
    SetIndexStyle(11, DRAW_LINE, STYLE_DASH, 1);
    SetIndexStyle(12, DRAW_LINE, STYLE_SOLID, 1);
    SetIndexStyle(13, DRAW_NONE);
    
    // Set arrow codes
    SetIndexArrow(8, 108); // Small circle for squeeze
    SetIndexArrow(9, 251); // Square for divergence
    
    // Set empty values
    SetIndexEmptyValue(0, EMPTY_VALUE);
    SetIndexEmptyValue(1, EMPTY_VALUE);
    SetIndexEmptyValue(2, EMPTY_VALUE);
    SetIndexEmptyValue(4, EMPTY_VALUE);
    SetIndexEmptyValue(5, EMPTY_VALUE);
    SetIndexEmptyValue(8, EMPTY_VALUE);
    SetIndexEmptyValue(9, EMPTY_VALUE);
    
    // Initialize working arrays
    int arraySize = MathMax(Bars, 5000);
    if(arraySize == 0) arraySize = 1000;
    
    // Calculate maximum size needed for complex MAs
    int maxTmpSize = averageSize(MathMax(FastMAMethod, MathMax(SlowMAMethod, SignalMAMethod)));
    if(maxTmpSize > 0) ArrayResize(tmp, maxTmpSize);
    
    ArraySetAsSeries(FastMABuffer, true);
    ArraySetAsSeries(SlowMABuffer, true);
    ArraySetAsSeries(MACDLine, true);
    ArraySetAsSeries(PriceBuffer, true);
    ArraySetAsSeries(ColorState, true);
    
    ArrayResize(FastMABuffer, arraySize);
    ArrayResize(SlowMABuffer, arraySize);
    ArrayResize(MACDLine, arraySize);
    ArrayResize(PriceBuffer, arraySize);
    ArrayResize(ColorState, arraySize);
    
    ArrayInitialize(FastMABuffer, 0);
    ArrayInitialize(SlowMABuffer, 0);
    ArrayInitialize(MACDLine, 0);
    ArrayInitialize(PriceBuffer, 0);
    ArrayInitialize(ColorState, 0);
    
    Print("UltimateMACD MultiMA initialized successfully");
    Print("Fast MA: ", fastName, "(", FastMAPeriod, ")");
    Print("Slow MA: ", slowName, "(", SlowMAPeriod, ")");
    Print("Signal: ", signalName, "(", SignalMAPeriod, ")");
    
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // Clean up all chart objects
    int deleted = 0;
    for(int i = ObjectsTotal() - 1; i >= 0; i--) 
    {
        string name = ObjectName(i);
        if(StringFind(name, "UMACD_") == 0) 
        {
            ObjectDelete(0, name);
            deleted++;
        }
    }
    
    Comment("");
    Print("UltimateMACD MultiMA deinitialized. Removed ", deleted, " chart objects");
}

//+------------------------------------------------------------------+
//| Get array size needed for specific MA method                     |
//+------------------------------------------------------------------+
int averageSize(int mode)
{   
   int arraysize;
   
   switch(mode)
   {
   case DEMA     : arraysize = 2; break;
   case T3_basic : arraysize = 6; break;
   case JSmooth  : arraysize = 5; break;
   case TEMA     : arraysize = 4; break;
   case T3       : arraysize = 6; break;
   case Laguerre : arraysize = 4; break;
   case DsEMA    : arraysize = 2; break;
   case TsEMA    : arraysize = 3; break;
   case VEMA     : arraysize = 2; break;
   default       : arraysize = 0; break;
   }
   
   return(arraysize);
}

//+------------------------------------------------------------------+
//| Get price value based on price type                              |
//+------------------------------------------------------------------+
double getPrice(int priceType, int bar)
{
   double close_price = Close[bar];
   double open_price  = Open[bar];
   double high_price  = High[bar];
   double low_price   = Low[bar];
   
   switch(priceType)
   {   
   case 0: return(close_price); break;
   case 1: return(open_price); break;
   case 2: return(high_price); break;
   case 3: return(low_price); break;
   case 4: return((high_price + low_price)/2); break;
   case 5: return((high_price + low_price + close_price)/3); break;
   case 6: return((high_price + low_price + 2*close_price)/4); break;
   case 7: return((close_price + open_price)/2); break;
   case 8: return((high_price + low_price + close_price + open_price)/4); break;
   case 9: if(close_price > open_price) return((high_price + close_price)/2); else return((low_price + close_price)/2); break;
   case 10: if(close_price > open_price) return(high_price); else return(low_price); break;
   default: return(close_price); break;
   }
}

//+------------------------------------------------------------------+
//| Master function for all MA calculations                          |
//+------------------------------------------------------------------+
double allAveragesOnArray(int index, double& price[], int period, int mode, int arraysize, int cbars, int bar)
{
   int i;
   double MA[4];  
        
   switch(mode) 
   {
   case EMA: case Wilder: case SMMA: case ZeroLagEMA: case DEMA: case T3_basic: 
   case ITrend: case REMA: case JSmooth: case SMA_eq: case TEMA: case T3: 
   case Laguerre: case MD: case BF2P: case BF3P: case SuperSmu: case Decycler: 
   case eVWMA: case DsEMA: case TsEMA: case VEMA:
      
      if(prevtime[index] != Time[bar])
      {
         ma[index][3] = ma[index][2]; 
         ma[index][2] = ma[index][1]; 
         ma[index][1] = ma[index][0]; 
   
         if(arraysize > 0) 
            for(i=0; i<arraysize; i++) 
               tmp[i][index][1] = tmp[i][index][0];
    
         prevtime[index] = Time[bar]; 
      }
   
      if(mode == ITrend || mode == REMA || mode == SMA_eq || (mode >= BF2P && mode < eVWMA)) 
         for(i=0; i<4; i++) 
            MA[i] = ma[index][i]; 
   }
      
   switch(mode)
   {
   case SMA       : ma[index][0] = SMAOnArray(price, period, bar); break;
   case EMA       : ma[index][0] = EMAOnArray(price[bar], ma[index][1], period, cbars, bar); break;
   case Wilder    : ma[index][0] = WilderOnArray(price[bar], ma[index][1], period, cbars, bar); break;  
   case LWMA      : ma[index][0] = LWMAOnArray(price, period, bar); break;
   case SineWMA   : ma[index][0] = SineWMAOnArray(price, period, bar); break;
   case TriMA     : ma[index][0] = TriMAOnArray(price, period, bar); break;
   case LSMA      : ma[index][0] = LSMAOnArray(price, period, bar); break;
   case SMMA      : ma[index][0] = SMMAOnArray(price, ma[index][1], period, cbars, bar); break;
   case HMA       : ma[index][0] = HMAOnArray(price, period, cbars, bar); break;
   case ZeroLagEMA: ma[index][0] = ZeroLagEMAOnArray(price, ma[index][1], period, cbars, bar); break;
   case DEMA      : ma[index][0] = DEMAOnArray(index, 0, price[bar], period, 1, cbars, bar); break;
   case T3_basic  : ma[index][0] = T3_basicOnArray(index, 0, price[bar], period, 0.7, cbars, bar); break;
   case ITrend    : ma[index][0] = ITrendOnArray(price, MA, period, cbars, bar); break;
   case Median    : ma[index][0] = MedianOnArray(price, period, cbars, bar); break;
   case GeoMean   : ma[index][0] = GeoMeanOnArray(price, period, cbars, bar); break;
   case REMA      : ma[index][0] = REMAOnArray(price[bar], MA, period, 0.5, cbars, bar); break;
   case ILRS      : ma[index][0] = ILRSOnArray(price, period, cbars, bar); break;
   case IE_2      : ma[index][0] = IE2OnArray(price, period, cbars, bar); break;
   case TriMAgen  : ma[index][0] = TriMA_genOnArray(price, period, cbars, bar); break;
   case VWMA      : ma[index][0] = VWMAOnArray(price, period, bar); break;
   case JSmooth   : ma[index][0] = JSmoothOnArray(index, 0, price[bar], period, 1, cbars, bar); break;
   case SMA_eq    : ma[index][0] = SMA_eqOnArray(price, MA, period, cbars, bar); break;
   case ALMA      : ma[index][0] = ALMAOnArray(price, period, 0.85, 8, bar); break;
   case TEMA      : ma[index][0] = TEMAOnArray(index, price[bar], period, 1, cbars, bar); break;
   case T3        : ma[index][0] = T3OnArray(index, 0, price[bar], period, 0.7, cbars, bar); break;
   case Laguerre  : ma[index][0] = LaguerreOnArray(index, price[bar], period, 4, cbars, bar); break;
   case MD        : ma[index][0] = McGinleyOnArray(price[bar], ma[index][1], period, cbars, bar); break;
   case BF2P      : ma[index][0] = BF2POnArray(price, MA, period, cbars, bar); break;
   case BF3P      : ma[index][0] = BF3POnArray(price, MA, period, cbars, bar); break;
   case SuperSmu  : ma[index][0] = SuperSmuOnArray(price, MA, period, cbars, bar); break;
   case Decycler  : ma[index][0] = DecyclerOnArray(price, MA, period, cbars, bar); return(price[bar] - ma[index][0]); 
   case eVWMA     : ma[index][0] = eVWMAOnArray(price[bar], ma[index][1], period, cbars, bar); break;
   case EWMA      : ma[index][0] = EWMAOnArray(price, period, bar); break;
   case DsEMA     : ma[index][0] = DsEMAOnArray(index, price[bar], period, cbars, bar); break;
   case TsEMA     : ma[index][0] = TsEMAOnArray(index, price[bar], period, cbars, bar); break;
   case VEMA      : ma[index][0] = VEMAOnArray(index, price[bar], period, cbars, bar); break;
   default        : ma[index][0] = SMAOnArray(price, period, bar); break;
   }
   
   return(ma[index][0]);
}

//+------------------------------------------------------------------+
//| Individual MA Calculation Functions                              |
//+------------------------------------------------------------------+

// Simple Moving Average
double SMAOnArray(double& array[], int per, int bar)
{
   double sum = 0;
   for(int i=0; i<per && bar+i<ArraySize(array); i++) 
      sum += array[bar+i];
   
   return(sum/per);
}

// Exponential Moving Average
double EMAOnArray(double price, double prev, int per, int cbars, int bar)
{
   if(bar >= cbars) return price;
   else return(prev + 2.0/(1 + per)*(price - prev));
}

// Wilder Exponential Moving Average
double WilderOnArray(double price, double prev, int per, int cbars, int bar)
{
   if(bar >= cbars) return price;
   else return(prev + (price - prev)/per);
}

// Linear Weighted Moving Average
double LWMAOnArray(double& array[], int per, int bar)
{
   double sum = 0, weight = 0;
   
   for(int i=0; i<per && bar+i<ArraySize(array); i++)
   { 
      weight += (per - i);
      sum += array[bar+i]*(per - i);
   }
   
   if(weight > 0) return(sum/weight); 
   else return(0); 
}

// Sine Weighted Moving Average
double SineWMAOnArray(double& array[], int per, int bar)
{
   double sum = 0, weight = 0;
  
   for(int i=0; i<per && bar+i<ArraySize(array); i++)
   { 
      weight += MathSin(pi*(i + 1)/(per + 1));
      sum += array[bar+i]*MathSin(pi*(i + 1)/(per + 1)); 
   }
   
   if(weight > 0) return(sum/weight); 
   else return(0); 
}

// Triangular Moving Average
double TriMAOnArray(double& array[], int per, int bar)
{
   int len = (int)MathCeil((per + 1)*0.5);
   double sum = 0;
   
   for(int i=0; i<len && bar+i<ArraySize(array); i++) 
      sum += SMAOnArray(array, len, bar+i);
         
   return(sum/len);
}

// Least Square Moving Average (Linear Regression)
double LSMAOnArray(double& array[], int per, int bar)
{   
   double sum = 0;
   
   for(int i=per; i>=1; i--) 
      if(bar+per-i < ArraySize(array))
         sum += (i - (per + 1)/3.0)*array[bar+per-i];
   
   return(sum*6/(per*(per + 1)));
}

// Smoothed Moving Average
double SMMAOnArray(double& array[], double prev, int per, int cbars, int bar)
{
   if(bar == cbars) 
      return SMAOnArray(array, per, bar);
   else if(bar < cbars)
   {
      double sum = 0;
      for(int i=0; i<per && bar+i+1<ArraySize(array); i++) 
         sum += array[bar+i+1];
      return (sum - prev + array[bar])/per;
   }
   
   return 0;
}

// Hull Moving Average
double HMAOnArray(double& array[], int per, int cbars, int bar)
{
   double _tmp[];
   int len = (int)MathSqrt(per);
   
   ArrayResize(_tmp, len);
   
   if(bar == cbars) 
      return array[bar]; 
   else if(bar < cbars)
   {
      for(int i=0; i<len; i++) 
         _tmp[i] = 2*LWMAOnArray(array, per/2, bar+i) - LWMAOnArray(array, per, bar+i);  
      return LWMAOnArray(_tmp, len, 0); 
   }  

   return 0;
}

// Zero-Lag Exponential Moving Average
double ZeroLagEMAOnArray(double& price[], double prev, int per, int cbars, int bar)
{
   int lag = (int)(0.5*(per - 1)); 
   double alpha = 2.0/(1 + (double)per); 
      
   if(bar >= cbars) 
      return price[bar];
   else 
      return alpha*(2*price[bar] - price[MathMin(bar+lag, ArraySize(price)-1)]) + (1 - alpha)*prev;
}

// Double Exponential Moving Average
double DEMAOnArray(int index, int num, double price, double per, double v, int cbars, int bar)
{
   double alpha = 2.0/(1 + per);
   
   if(bar == cbars) 
   {
      tmp[num][index][0] = price; 
      tmp[num+1][index][0] = price;
      return price;
   }
   else if(bar < cbars) 
   {
      tmp[num][index][0] = tmp[num][index][1] + alpha*(price - tmp[num][index][1]); 
      tmp[num+1][index][0] = tmp[num+1][index][1] + alpha*(tmp[num][index][0] - tmp[num+1][index][1]); 
      return tmp[num][index][0]*(1+v) - tmp[num+1][index][0]*v;
   }
   
   return 0;
}

// T3 Basic
double T3_basicOnArray(int index, int num, double price, int per, double v, int cbars, int bar)
{
   if(bar == cbars) 
   {
      for(int k=0; k<6; k++) 
         tmp[num+k][index][0] = price;
      return price;
   }
   else if(bar < cbars) 
   {
      double dema1 = DEMAOnArray(index, num, price, per, v, cbars, bar); 
      double dema2 = DEMAOnArray(index, num+2, dema1, per, v, cbars, bar); 
      return DEMAOnArray(index, num+4, dema2, per, v, cbars, bar);
   }
   
   return 0;
}

// Instantaneous Trendline
double ITrendOnArray(double& price[], double& array[], int per, int cbars, int bar)
{
   double alpha = 2.0/(per + 1);
   
   if(bar < cbars && array[1] > 0 && array[2] > 0) 
      return (alpha - 0.25*alpha*alpha)*price[bar] + 0.5*alpha*alpha*price[MathMin(bar+1, ArraySize(price)-1)] 
             -(alpha - 0.75*alpha*alpha)*price[MathMin(bar+2, ArraySize(price)-1)] + 2*(1 - alpha)*array[1] 
             -(1 - alpha)*(1 - alpha)*array[2];
   else 
      return (price[bar] + 2*price[MathMin(bar+1, ArraySize(price)-1)] + price[MathMin(bar+2, ArraySize(price)-1)])/4;
}

// Moving Median
double MedianOnArray(double& price[], int per, int cbars, int bar)
{
   double array[];
   ArrayResize(array, per);
   
   if(bar <= cbars)
   {
      for(int i=0; i<per && bar+i<ArraySize(price); i++) 
         array[i] = price[bar+i];
      ArraySort(array, WHOLE_ARRAY, 0, MODE_DESCEND);
      
      int num = (int)MathRound((per - 1)*0.5); 
      if(MathMod(per, 2) > 0) 
         return array[num]; 
      else 
         return 0.5*(array[num] + array[num+1]);
   }
    
   return 0; 
}

// Geometric Mean
double GeoMeanOnArray(double& price[], int per, int cbars, int bar)
{
   if(bar < cbars)
   { 
      double gmean = MathPow(MathAbs(price[bar]), 1.0/per); 
      for(int i=1; i<per && bar+i<ArraySize(price); i++) 
         gmean *= MathPow(MathAbs(price[bar+i]), 1.0/per); 
      return gmean;
   }
   else if(bar == cbars) 
      return SMAOnArray(price, per, bar);
   
   return 0;
}

// Regularized EMA
double REMAOnArray(double price, double& array[], int per, double lambda, int cbars, int bar)
{
   double alpha = 2.0/(per + 1);
   
   if(bar < cbars && array[1] > 0 && array[2] > 0) 
      return (array[1]*(1 + 2*lambda) + alpha*(price - array[1]) - lambda*array[2])/(1 + lambda); 
   else 
      return price;
}

// Integral of Linear Regression Slope
double ILRSOnArray(double& price[], int per, int cbars, int bar)
{
   double sum = per*(per - 1)*0.5;
   double sum2 = (per - 1)*per*(2*per - 1)/6.0;
   
   if(bar < cbars)
   {  
      double sum1 = 0;
      double sumy = 0;
      for(int i=0; i<per && bar+i<ArraySize(price); i++)
      { 
         sum1 += i*price[bar+i];
         sumy += price[bar+i];
      }
      double num1 = per*sum1 - sum*sumy;
      double num2 = sum*sum - per*sum2;
      
      double slope = (num2 != 0) ? num1/num2 : 0;
      return slope + SMAOnArray(price, per, bar);
   }
   
   return 0;
}

// IE/2 - Combination of LSMA and ILRS
double IE2OnArray(double& price[], int per, int cbars, int bar)
{
   if(bar < cbars) 
      return 0.5*(ILRSOnArray(price, per, cbars, bar) + LSMAOnArray(price, per, bar));
      
   return 0; 
}

// Triangular Moving Average Generalized
double TriMA_genOnArray(double& array[], int per, int cbars, int bar)
{
   int len1 = (int)MathFloor((per + 1)*0.5);
   int len2 = (int)MathCeil((per + 1)*0.5);
   double sum = 0;
   
   if(bar < cbars)
      for(int i = 0; i < len2 && bar+i<ArraySize(array); i++) 
         sum += SMAOnArray(array, len1, bar+i);
   
   return(sum/len2);
}

// Volume Weighted Moving Average
double VWMAOnArray(double& array[], int per, int bar)
{
   double sum = 0, weight = 0;
   
   for(int i=0; i<per && bar+i<Bars; i++)
   { 
      weight += (double)Volume[bar+i];
      sum += array[bar+i]*Volume[bar+i];
   }
     
   if(weight > 0) return(sum/weight); 
   else return(0); 
}

// JSmooth - Jurik Smoothing
double JSmoothOnArray(int index, int num, double price, int per, double power, int cbars, int bar)
{
   double beta = 0.45*(per - 1)/(0.45*(per - 1) + 2);
   double alpha = MathPow(beta, power);
   
   if(bar == cbars) 
   {
      tmp[num+4][index][0] = price; 
      tmp[num+0][index][0] = price; 
      tmp[num+2][index][0] = price;
      return price;
   }
   else if(bar < cbars) 
   {
      tmp[num+0][index][0] = (1 - alpha)*price + alpha*tmp[num+0][index][1];
      tmp[num+1][index][0] = (price - tmp[num+0][index][0])*(1-beta) + beta*tmp[num+1][index][1];
      tmp[num+2][index][0] = tmp[num+0][index][0] + tmp[num+1][index][0];
      tmp[num+3][index][0] = (tmp[num+2][index][0] - tmp[num+4][index][1])*MathPow((1-alpha), 2) + MathPow(alpha, 2)*tmp[num+3][index][1];
      tmp[num+4][index][0] = tmp[num+4][index][1] + tmp[num+3][index][0]; 
   }
   return(tmp[num+4][index][0]);
}

// Simplified SMA
double SMA_eqOnArray(double& price[], double& array[], int per, int cbars, int bar)
{
   if(bar == cbars) 
      return SMAOnArray(price, per, bar);
   else if(bar < cbars && bar+per < ArraySize(price)) 
      return (price[bar] - price[bar+per])/per + array[1];
   
   return 0;
}

// ALMA - Arnaud Legoux Moving Average
double ALMAOnArray(double& price[], int per, double offset, double sigma, int bar)
{
   double m = MathFloor(offset*(per - 1));
   double s = per/sigma;
   double w, sum = 0, wsum = 0;
   
   for(int i=0; i<per && bar+(per-1-i)<ArraySize(price); i++) 
   {
      w = MathExp(-((i - m)*(i - m))/(2*s*s));
      wsum += w;
      sum += price[bar+(per-1-i)]*w; 
   }
   
   if(wsum != 0) return(sum/wsum); 
   else return(0);
}

// Triple Exponential Moving Average
double TEMAOnArray(int index, double price, int per, double v, int cbars, int bar)
{
   double alpha = 2.0/(per+1);
   
   if(bar == cbars) 
   {
      tmp[0][index][0] = price; 
      tmp[1][index][0] = price; 
      tmp[2][index][0] = price;
      return price;
   }
   else if(bar < cbars) 
   {
      tmp[0][index][0] = tmp[0][index][1] + alpha*(price - tmp[0][index][1]);
      tmp[1][index][0] = tmp[1][index][1] + alpha*(tmp[0][index][0] - tmp[1][index][1]);
      tmp[2][index][0] = tmp[2][index][1] + alpha*(tmp[1][index][0] - tmp[2][index][1]);
      tmp[3][index][0] = tmp[0][index][0] + v*(tmp[0][index][0] + v*(tmp[0][index][0]-tmp[1][index][0]) - tmp[1][index][0] - v*(tmp[1][index][0] - tmp[2][index][0])); 
      return tmp[3][index][0];
   }
   
   return 0;
}

// T3 Corrected
double T3OnArray(int index, int num, double price, int per, double v, int cbars, int bar)
{
   double len = MathMax((per + 5.0)/3.0 - 1, 1);
   
   if(bar == cbars) 
   {
      for(int k=0; k<6; k++) 
         tmp[num+k][index][0] = price;
      return price;
   }
   else if(bar < cbars) 
   {
      double dema1 = DEMAOnArray(index, num, price, len, v, cbars, bar); 
      double dema2 = DEMAOnArray(index, num+2, dema1, len, v, cbars, bar); 
      return DEMAOnArray(index, num+4, dema2, len, v, cbars, bar);
   }
      
   return 0;
}

// Laguerre Filter
double LaguerreOnArray(int index, double price, int per, int order, int cbars, int bar)
{
   double gamma = 1 - 10.0/(per + 9);
   double aPrice[];
   
   ArrayResize(aPrice, order);
   
   for(int i=0; i<order; i++)
   {
      if(bar >= cbars) 
         tmp[i][index][0] = price;
      else
      {
         if(i == 0) 
            tmp[i][index][0] = (1 - gamma)*price + gamma*tmp[i][index][1];
         else
            tmp[i][index][0] = -gamma * tmp[i-1][index][0] + tmp[i-1][index][1] + gamma * tmp[i][index][1];
      
         aPrice[i] = tmp[i][index][0];
      }
   }
   
   return TriMA_genOnArray(aPrice, order, cbars, 0);
}

// McGinley Dynamic
double McGinleyOnArray(double price, double prev, int per, int cbars, int bar)
{
   if(bar == cbars) 
      return price;
   else if(bar < cbars) 
   {
      if(prev != 0) 
         return prev + (price - prev)/(per*MathPow(price/prev, 4)/2);
      else 
         return price;
   }

   return 0;
}

// Two-pole Butterworth Filter
double BF2POnArray(double& price[], double& array[], int per, int cbars, int bar)
{
   double a = MathExp(-1.414*pi/per);
   double b = 2*a*MathCos(1.414*1.25*pi/per);
   double c2 = b;
   double c3 = -a*a;
   double c1 = 1 - c2 - c3;
   
   if(bar < cbars && array[1] > 0 && array[2] > 0 && bar+2 < ArraySize(price)) 
      return c1*(price[bar] + 2*price[bar+1] + price[bar+2])/4 + c2*array[1] + c3*array[2];
   else if(bar+2 < ArraySize(price))
      return (price[bar] + 2*price[bar+1] + price[bar+2])/4;
   
   return 0;
}

// Three-pole Butterworth Filter
double BF3POnArray(double& price[], double& array[], int per, int cbars, int bar)
{
   double a = MathExp(-pi/per);
   double b = 2*a*MathCos(1.738*pi/per);
   double c = a*a;
   double d2 = b + c;
   double d3 = -(c + b*c);
   double d4 = c*c;
   double d1 = 1 - d2 - d3 - d4;
   
   if(bar < cbars && array[1] > 0 && array[2] > 0 && array[3] > 0 && bar+3 < ArraySize(price)) 
      return d1*(price[bar] + 3*price[bar+1] + 3*price[bar+2] + price[bar+3])/8 + d2*array[1] + d3*array[2] + d4*array[3];
   else if(bar+3 < ArraySize(price))
      return (price[bar] + 3*price[bar+1] + 3*price[bar+2] + price[bar+3])/8;
   
   return 0;
}

// SuperSmoother
double SuperSmuOnArray(double& price[], double& array[], int per, int cbars, int bar)
{
   double a = MathExp(-1.414*pi/per);
   double b = 2*a*MathCos(1.414*pi/per);
   double c2 = b;
   double c3 = -a*a;
   double c1 = 1 - c2 - c3;
   
   if(bar < cbars && array[1] > 0 && array[2] > 0 && bar+1 < ArraySize(price)) 
      return c1*(price[bar] + price[bar+1])/2 + c2*array[1] + c3*array[2];
   else if(bar+1 < ArraySize(price))
      return (price[bar] + price[bar+1])/2;
   
   return 0;
}

// Decycler
double DecyclerOnArray(double& price[], double& hp[], int per, int cbars, int bar)
{
   double alpha1 = (MathCos(1.414*pi/per) + MathSin(1.414*pi/per) - 1)/MathCos(1.414*pi/per);
  
   if(bar > cbars - 4 || bar+2 >= ArraySize(price)) 
      return(0);
   
   hp[0] = (1 - alpha1/2)*(1 - alpha1/2)*(price[bar] - 2*price[bar+1] + price[bar+2]) + 
           2*(1 - alpha1)*hp[1] - (1 - alpha1)*(1 - alpha1)*hp[2];
       
   return(hp[0]);
}

// Elastic Volume Weighted Moving Average
double eVWMAOnArray(double price, double prev, int per, int cbars, int bar)
{
   if(bar < cbars && prev > 0 && bar < Bars)
   {
      double max = 0;
      for(int i=0; i<per && bar+i<Bars; i++) 
         max = MathMax(max, Volume[bar+i]);
      
      double diff = 3*max - Volume[bar];
          
      if(diff < 0) 
         return prev;
      else 
         return (diff*prev + Volume[bar]*price)/(3*max);
   }
   else 
      return price;
}

// Exponential Weighted Moving Average
double EWMAOnArray(double& array[], int per, int bar)
{
   double sum = 0, weight = 0, alpha = 2.0/(1 + per);
   
   for(int i=0; i<per && bar+i<ArraySize(array); i++)
   { 
      weight += alpha*MathPow(1-alpha, i);
      sum += array[bar+i]*alpha*MathPow(1-alpha, i);
   }
   
   if(weight > 0) return(sum/weight); 
   else return(0); 
}

// Double Smoothed EMA
double DsEMAOnArray(int index, double price, int per, int cbars, int bar)
{
   double alpha = 4.0/(per + 3);
   
   if(bar == cbars) 
   {
      for(int k=0; k<2; k++) 
         tmp[k][index][0] = price;
      return(price);
   }
   else if(bar < cbars) 
   {
      tmp[0][index][0] = tmp[0][index][1] + alpha*(price - tmp[0][index][1]);
      tmp[1][index][0] = tmp[1][index][1] + alpha*(tmp[0][index][0] - tmp[1][index][1]);
   }
      
   return(tmp[1][index][0]);
}

// Triple Smoothed EMA
double TsEMAOnArray(int index, double price, int per, int cbars, int bar)
{
   double alpha = 6.0/(per + 5);
   
   if(bar == cbars) 
   {
      for(int k=0; k<3; k++) 
         tmp[k][index][0] = price;
      return(price);
   }
   else if(bar < cbars) 
   {
      tmp[0][index][0] = tmp[0][index][1] + alpha*(price - tmp[0][index][1]);
      tmp[1][index][0] = tmp[1][index][1] + alpha*(tmp[0][index][0] - tmp[1][index][1]);
      tmp[2][index][0] = tmp[2][index][1] + alpha*(tmp[1][index][0] - tmp[2][index][1]);
   }
      
   return(tmp[2][index][0]);
}

// Volume-weighted Exponential Moving Average
double VEMAOnArray(int index, double price, int per, int cbars, int bar)
{
   double vema = price, alpha = 2.0/(per + 1);
   
   if(bar == cbars && bar < Bars) 
   {
      tmp[0][index][0] = (1 - alpha)*price*Volume[bar];
      tmp[1][index][0] = (1 - alpha)*Volume[bar];
   }
   else if(bar < cbars && bar < Bars) 
   {
      tmp[0][index][0] = tmp[0][index][1] + alpha*(price*Volume[bar] - tmp[0][index][1]);
      tmp[1][index][0] = tmp[1][index][1] + alpha*(Volume[bar] - tmp[1][index][1]);
   }
  
   if(tmp[1][index][0] > 0) 
      vema = tmp[0][index][0]/tmp[1][index][0];
   
   return(vema);
}

//+------------------------------------------------------------------+
//| 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[])
{
    // Check minimum bars
    int minBars = MathMax(MathMax(SlowMAPeriod, BBPeriod), StdDevPeriod) + 10;
    if(rates_total < minBars) return(0);
    
    // Resize arrays if needed
    if(ArraySize(MACDLine) < rates_total) 
    {
        ArrayResize(FastMABuffer, rates_total + 100);
        ArrayResize(SlowMABuffer, rates_total + 100);
        ArrayResize(MACDLine, rates_total + 100);
        ArrayResize(PriceBuffer, rates_total + 100);
        ArrayResize(ColorState, rates_total + 100);
    }
    
    // Calculate limit
    int limit = rates_total - prev_calculated;
    if(prev_calculated > 0) limit++;
    limit = MathMin(limit, rates_total - minBars);
    
    // Main calculation loop
    for(int i = limit; i >= 0; i--)
    {
        // Clear all line buffers first
        MACDNeutral[i] = EMPTY_VALUE;
        MACDAbove[i] = EMPTY_VALUE;
        MACDBelow[i] = EMPTY_VALUE;
        HistogramPos[i] = EMPTY_VALUE;
        HistogramNeg[i] = EMPTY_VALUE;
        SqueezeDots[i] = EMPTY_VALUE;
        DivergenceMarkers[i] = EMPTY_VALUE;
        
        // Get price value
        PriceBuffer[i] = getPrice(ApplyToPrice, i);
        
        // Calculate Fast MA using selected method
        int fastSize = averageSize(FastMAMethod);
        FastMABuffer[i] = allAveragesOnArray(0, PriceBuffer, FastMAPeriod, 
                                             FastMAMethod, fastSize, 
                                             rates_total - minBars, i);
        
        // Calculate Slow MA using selected method
        int slowSize = averageSize(SlowMAMethod);
        SlowMABuffer[i] = allAveragesOnArray(1, PriceBuffer, SlowMAPeriod, 
                                             SlowMAMethod, slowSize, 
                                             rates_total - minBars, i);
        
        // Calculate MACD line
        MACDLine[i] = FastMABuffer[i] - SlowMABuffer[i];
        MACDValues[i] = MACDLine[i]; // Store in hidden buffer
        
        // Calculate Signal line using selected method
        int signalSize = averageSize(SignalMAMethod);
        SignalLine[i] = allAveragesOnArray(2, MACDLine, SignalMAPeriod, 
                                           SignalMAMethod, signalSize, 
                                           rates_total - minBars, i);
        
        // Calculate histogram
        double histogram = MACDLine[i] - SignalLine[i];
        if(ShowHistogram) 
        {
            if(histogram > 0)
                HistogramPos[i] = histogram;
            else
                HistogramNeg[i] = histogram;
        }
        
        // Calculate StdDev bands
        double macdSum = 0, macdSumSq = 0;
        int stdCount = 0;
        for(int j = 0; j < StdDevPeriod && i + j < rates_total; j++) 
        {
            if(i + j < ArraySize(MACDLine)) 
            {
                macdSum += MACDLine[i + j];
                macdSumSq += MACDLine[i + j] * MACDLine[i + j];
                stdCount++;
            }
        }
        
        double macdStdDev = 0;
        if(stdCount > 1) 
        {
            double mean = macdSum / stdCount;
            double variance = (macdSumSq / stdCount) - (mean * mean);
            macdStdDev = MathSqrt(MathMax(variance, 0));
        }
        
        UpperBand[i] = macdStdDev * StdDevMultiplier;
        LowerBand[i] = -macdStdDev * StdDevMultiplier;
        
        // Calculate Bollinger Bands on MACD
        if(ShowBollingerBands) 
        {
            double bbSum = 0;
            int bbCount = 0;
            for(int j = 0; j < BBPeriod && i + j < rates_total; j++) 
            {
                if(i + j < ArraySize(MACDLine)) 
                {
                    bbSum += MACDLine[i + j];
                    bbCount++;
                }
            }
            BBMiddle[i] = bbCount > 0 ? bbSum / bbCount : 0;
            
            // Calculate BB standard deviation
            double bbSumSq = 0;
            for(int j = 0; j < BBPeriod && i + j < rates_total; j++) 
            {
                if(i + j < ArraySize(MACDLine)) 
                {
                    double diff = MACDLine[i + j] - BBMiddle[i];
                    bbSumSq += diff * diff;
                }
            }
            
            double bbStdDev = bbCount > 1 ? MathSqrt(bbSumSq / bbCount) : 0;
            BBUpper[i] = BBMiddle[i] + (bbStdDev * BBDeviation);
            BBLower[i] = BBMiddle[i] - (bbStdDev * BBDeviation);
        }
        
        // Determine color based on settings with state persistence
        bool shouldColorRed = false;
        bool shouldColorBlue = false;
        
        // Get previous state (if exists)
        int prevState = (i < rates_total - 1 && i + 1 < ArraySize(ColorState)) ? ColorState[i + 1] : 0;
        
        if(ColorOnSignalCross) 
        {
            if(RequireBothConditions) 
            {
                // Check for signal line crosses
                bool signalCrossUp = false;
                bool signalCrossDown = false;
                if(i < rates_total - 1) 
                {
                    signalCrossUp = (MACDLine[i] > SignalLine[i]) && (MACDLine[i + 1] <= SignalLine[i + 1]);
                    signalCrossDown = (MACDLine[i] < SignalLine[i]) && (MACDLine[i + 1] >= SignalLine[i + 1]);
                }
                
                // State machine for reversal zones
                if(prevState == 0) 
                {
                    // Currently NEUTRAL (gray)
                    
                    // Check for BEARISH REVERSAL (sell setup)
                    if(signalCrossDown && MACDLine[i] > BBUpper[i]) 
                    {
                        ColorState[i] = 1;  // Turn CRIMSON
                        if(i == 0) 
                        {
                            Print("BEARISH REVERSAL: Signal crossed DOWN above BB Upper - CRIMSON (SELL)");
                            if(AlertsEnabled) Alert(Symbol() + " SELL SIGNAL: MACD reversal at extreme high!");
                        }
                    }
                    // Check for BULLISH REVERSAL (buy setup)
                    else if(signalCrossUp && MACDLine[i] < BBLower[i]) 
                    {
                        ColorState[i] = -1; // Turn MEDIUMBLUE
                        if(i == 0) 
                        {
                            Print("BULLISH REVERSAL: Signal crossed UP below BB Lower - MEDIUMBLUE (BUY)");
                            if(AlertsEnabled) Alert(Symbol() + " BUY SIGNAL: MACD reversal at extreme low!");
                        }
                    }
                    else 
                    {
                        ColorState[i] = 0;  // Stay gray
                    }
                }
                else if(prevState == 1) 
                {
                    // Currently CRIMSON (in sell zone)
                    if(MACDLine[i] < BBUpper[i]) 
                    {
                        ColorState[i] = 0;
                        if(i == 0) Print("MACD dropped below BB Upper - Resetting to GRAY");
                        
                        // Check if we should immediately go to blue
                        if(signalCrossUp && MACDLine[i] < BBLower[i]) 
                        {
                            ColorState[i] = -1;
                            if(i == 0) Print("Immediate switch to MEDIUMBLUE - new BUY signal");
                        }
                    }
                    else 
                    {
                        ColorState[i] = 1;
                    }
                }
                else if(prevState == -1) 
                {
                    // Currently MEDIUMBLUE (in buy zone)
                    if(MACDLine[i] > BBLower[i]) 
                    {
                        ColorState[i] = 0;
                        if(i == 0) Print("MACD rose above BB Lower - Resetting to GRAY");
                        
                        // Check if we should immediately go to crimson
                        if(signalCrossDown && MACDLine[i] > BBUpper[i]) 
                        {
                            ColorState[i] = 1;
                            if(i == 0) Print("Immediate switch to CRIMSON - new SELL signal");
                        }
                    }
                    else 
                    {
                        ColorState[i] = -1;
                    }
                }
                
                // Apply the state to color
                shouldColorRed = (ColorState[i] == 1);
                shouldColorBlue = (ColorState[i] == -1);
            }
            else 
            {
                // Simple signal cross mode (no BB involvement)
                shouldColorRed = (MACDLine[i] > SignalLine[i]);
                shouldColorBlue = (MACDLine[i] < SignalLine[i]);
                ColorState[i] = shouldColorRed ? 1 : (shouldColorBlue ? -1 : 0);
            }
        }
        else 
        {
            // Original BB touch mode (no signal line involvement)
            shouldColorRed = (MACDLine[i] > BBUpper[i]);
            shouldColorBlue = (MACDLine[i] < BBLower[i]);
            ColorState[i] = shouldColorRed ? 1 : (shouldColorBlue ? -1 : 0);
        }
        
        // Apply color to appropriate buffer
        if(shouldColorRed) 
        {
            MACDAbove[i] = MACDLine[i];
            // Connect from previous bar for smooth line
            if(i < rates_total - 1 && MACDAbove[i + 1] == EMPTY_VALUE) 
            {
                if(MACDNeutral[i + 1] != EMPTY_VALUE)
                    MACDAbove[i + 1] = MACDNeutral[i + 1];
                else if(MACDBelow[i + 1] != EMPTY_VALUE)
                    MACDAbove[i + 1] = MACDBelow[i + 1];
            }
        }
        else if(shouldColorBlue) 
        {
            MACDBelow[i] = MACDLine[i];
            // Connect from previous bar for smooth line
            if(i < rates_total - 1 && MACDBelow[i + 1] == EMPTY_VALUE) 
            {
                if(MACDNeutral[i + 1] != EMPTY_VALUE)
                    MACDBelow[i + 1] = MACDNeutral[i + 1];
                else if(MACDAbove[i + 1] != EMPTY_VALUE)
                    MACDBelow[i + 1] = MACDAbove[i + 1];
            }
        }
        else 
        {
            MACDNeutral[i] = MACDLine[i];
            // Connect from previous bar for smooth line
            if(i < rates_total - 1 && MACDNeutral[i + 1] == EMPTY_VALUE) 
            {
                if(MACDAbove[i + 1] != EMPTY_VALUE)
                    MACDNeutral[i + 1] = MACDAbove[i + 1];
                else if(MACDBelow[i + 1] != EMPTY_VALUE)
                    MACDNeutral[i + 1] = MACDBelow[i + 1];
            }
        }
        
        // Detect squeeze
        if(ShowSqueeze) 
        {
            bool isSqueeze = MathAbs(MACDLine[i]) < macdStdDev * 0.5;
            if(isSqueeze) 
            {
                SqueezeDots[i] = 0; // Plot at zero line
            }
        }
        
        // Check for chart signals - both current and historical
        if(ShowChartSignals) 
        {
            // Check if this is a new signal
            bool isNewBullSignal = false;
            bool isNewBearSignal = false;
            
            // Check for color state changes
            if(i < rates_total - 1) 
            {
                // SELL Signal - CRIMSON state (bearish reversal)
                if(ColorState[i] == 1 && ColorState[i + 1] != 1) 
                {
                    isNewBearSignal = true;
                }
                // BUY Signal - MEDIUMBLUE state (bullish reversal)
                else if(ColorState[i] == -1 && ColorState[i + 1] != -1) 
                {
                    isNewBullSignal = true;
                }
            }
            
            // Place signals on chart
            if(isNewBearSignal) 
            {
                PlaceChartSignal(time[i], high[i], low[i], false, true, i);
                if(i == 0) 
                {
                    string maMethod = "Fast: " + EnumToString(FastMAMethod) + "(" + IntegerToString(FastMAPeriod) + ") " +
                                     "Slow: " + EnumToString(SlowMAMethod) + "(" + IntegerToString(SlowMAPeriod) + ")";
                    Print("SELL signal generated using ", maMethod);
                    if(AlertsEnabled) 
                    {
                        Alert(Symbol() + " SELL SIGNAL at ", DoubleToString(Close[i], Digits));
                        PlaySound("alert.wav");
                    }
                }
            }
            else if(isNewBullSignal) 
            {
                PlaceChartSignal(time[i], high[i], low[i], true, false, i);
                if(i == 0) 
                {
                    string maMethod = "Fast: " + EnumToString(FastMAMethod) + "(" + IntegerToString(FastMAPeriod) + ") " +
                                     "Slow: " + EnumToString(SlowMAMethod) + "(" + IntegerToString(SlowMAPeriod) + ")";
                    Print("BUY signal generated using ", maMethod);
                    if(AlertsEnabled) 
                    {
                        Alert(Symbol() + " BUY SIGNAL at ", DoubleToString(Close[i], Digits));
                        PlaySound("alert.wav");
                    }
                }
            }
        }
    }
    
    // Update comment
    UpdateComment();
    
    return(rates_total);
}

//+------------------------------------------------------------------+
//| Place chart signals                                              |
//+------------------------------------------------------------------+
void PlaceChartSignal(datetime barTime, double high, double low, 
                     bool bullish, bool bearish, int barIndex)
{
    // Create unique names for signals
    string prefix = "UMACD_MA_";
    string objName = "";
    
    // Get price values for this bar
    double closePrice = iClose(NULL, 0, barIndex);
    
    // Place bullish signal (BUY)
    if(bullish && ShowBullishSignals) 
    {
        // Diamond marker at the low
        objName = prefix + "BuyDiamond_" + TimeToString(barTime);
        if(ObjectFind(0, objName) < 0) 
        {
            if(ObjectCreate(0, objName, OBJ_ARROW, 0, barTime, low - (10 * Point))) 
            {
                ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, 119); // Diamond
                ObjectSetInteger(0, objName, OBJPROP_COLOR, clrAqua);
                ObjectSetInteger(0, objName, OBJPROP_WIDTH, 3);
                ObjectSetInteger(0, objName, OBJPROP_BACK, false);
                ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, true);
                
                string tooltip = "BUY Signal\n";
                tooltip += "Time: " + TimeToString(barTime) + "\n";
                tooltip += "Price: " + DoubleToString(closePrice, Digits) + "\n";
                tooltip += "Fast MA: " + EnumToString(FastMAMethod) + "(" + IntegerToString(FastMAPeriod) + ")\n";
                tooltip += "Slow MA: " + EnumToString(SlowMAMethod) + "(" + IntegerToString(SlowMAPeriod) + ")\n";
                tooltip += "Signal: " + EnumToString(SignalMAMethod) + "(" + IntegerToString(SignalMAPeriod) + ")";
                
                ObjectSetString(0, objName, OBJPROP_TOOLTIP, tooltip);
            }
        }
        
        // Small up arrow
        objName = prefix + "BuyArrow_" + TimeToString(barTime);
        if(ObjectFind(0, objName) < 0) 
        {
            if(ObjectCreate(0, objName, OBJ_ARROW, 0, barTime, low - (25 * Point))) 
            {
                ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, 233); // Up arrow
                ObjectSetInteger(0, objName, OBJPROP_COLOR, clrLime);
                ObjectSetInteger(0, objName, OBJPROP_WIDTH, 2);
                ObjectSetInteger(0, objName, OBJPROP_BACK, false);
            }
        }
        
        // Optional: Add vertical line
        if(ShowVerticalLines) 
        {
            objName = prefix + "BuyLine_" + TimeToString(barTime);
            if(ObjectFind(0, objName) < 0) 
            {
                if(ObjectCreate(0, objName, OBJ_VLINE, 0, barTime, 0)) 
                {
                    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrLime);
                    ObjectSetInteger(0, objName, OBJPROP_STYLE, STYLE_DOT);
                    ObjectSetInteger(0, objName, OBJPROP_WIDTH, 1);
                    ObjectSetInteger(0, objName, OBJPROP_BACK, true);
                }
            }
        }
        
        // Optional: Add price marker
        if(ShowPriceMarkers) 
        {
            objName = prefix + "BuyDot_" + TimeToString(barTime);
            if(ObjectFind(0, objName) < 0) 
            {
                if(ObjectCreate(0, objName, OBJ_ARROW, 0, barTime, closePrice)) 
                {
                    ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, 159); // Small circle
                    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrLime);
                    ObjectSetInteger(0, objName, OBJPROP_WIDTH, 1);
                    ObjectSetInteger(0, objName, OBJPROP_BACK, true);
                }
            }
        }
    }
    
    // Place bearish signal (SELL)
    if(bearish && ShowBearishSignals) 
    {
        // Diamond marker above the high
        objName = prefix + "SellDiamond_" + TimeToString(barTime);
        if(ObjectFind(0, objName) < 0) 
        {
            if(ObjectCreate(0, objName, OBJ_ARROW, 0, barTime, high + (10 * Point))) 
            {
                ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, 119); // Diamond
                ObjectSetInteger(0, objName, OBJPROP_COLOR, clrMagenta);
                ObjectSetInteger(0, objName, OBJPROP_WIDTH, 3);
                ObjectSetInteger(0, objName, OBJPROP_BACK, false);
                ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, true);
                
                string tooltip = "SELL Signal\n";
                tooltip += "Time: " + TimeToString(barTime) + "\n";
                tooltip += "Price: " + DoubleToString(closePrice, Digits) + "\n";
                tooltip += "Fast MA: " + EnumToString(FastMAMethod) + "(" + IntegerToString(FastMAPeriod) + ")\n";
                tooltip += "Slow MA: " + EnumToString(SlowMAMethod) + "(" + IntegerToString(SlowMAPeriod) + ")\n";
                tooltip += "Signal: " + EnumToString(SignalMAMethod) + "(" + IntegerToString(SignalMAPeriod) + ")";
                
                ObjectSetString(0, objName, OBJPROP_TOOLTIP, tooltip);
            }
        }
        
        // Small down arrow
        objName = prefix + "SellArrow_" + TimeToString(barTime);
        if(ObjectFind(0, objName) < 0) 
        {
            if(ObjectCreate(0, objName, OBJ_ARROW, 0, barTime, high + (25 * Point))) 
            {
                ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, 234); // Down arrow
                ObjectSetInteger(0, objName, OBJPROP_COLOR, clrRed);
                ObjectSetInteger(0, objName, OBJPROP_WIDTH, 2);
                ObjectSetInteger(0, objName, OBJPROP_BACK, false);
            }
        }
        
        // Optional: Add vertical line
        if(ShowVerticalLines) 
        {
            objName = prefix + "SellLine_" + TimeToString(barTime);
            if(ObjectFind(0, objName) < 0) 
            {
                if(ObjectCreate(0, objName, OBJ_VLINE, 0, barTime, 0)) 
                {
                    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrRed);
                    ObjectSetInteger(0, objName, OBJPROP_STYLE, STYLE_DOT);
                    ObjectSetInteger(0, objName, OBJPROP_WIDTH, 1);
                    ObjectSetInteger(0, objName, OBJPROP_BACK, true);
                }
            }
        }
        
        // Optional: Add price marker
        if(ShowPriceMarkers) 
        {
            objName = prefix + "SellDot_" + TimeToString(barTime);
            if(ObjectFind(0, objName) < 0) 
            {
                if(ObjectCreate(0, objName, OBJ_ARROW, 0, barTime, closePrice)) 
                {
                    ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, 159); // Small circle
                    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrRed);
                    ObjectSetInteger(0, objName, OBJPROP_WIDTH, 1);
                    ObjectSetInteger(0, objName, OBJPROP_BACK, true);
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| Update comment with current status                               |
//+------------------------------------------------------------------+
void UpdateComment()
{
    if(!ShowInfoBox) 
    {
        Comment("");
        return;
    }
    
    string comment = "\n╔════════════════════════════════════╗";
    comment += "\n║   ULTIMATE MACD MULTI-MA           ║";
    comment += "\n╠════════════════════════════════════╣";
    
    // MA Methods being used
    comment += "\n║ Fast MA: " + EnumToString(FastMAMethod) + "(" + IntegerToString(FastMAPeriod) + ")";
    comment += "\n║ Slow MA: " + EnumToString(SlowMAMethod) + "(" + IntegerToString(SlowMAPeriod) + ")";
    comment += "\n║ Signal: " + EnumToString(SignalMAMethod) + "(" + IntegerToString(SignalMAPeriod) + ")";
    comment += "\n╠════════════════════════════════════╣";
    
    double macd = MACDValues[0];
    double signal = SignalLine[0];
    double histogram = macd - signal;
    
    // Current state
    string stateStr = "";
    string tradeStr = "";
    color stateColor = clrGray;
    
    if(ColorState[0] == 1) 
    {
        stateStr = "CRIMSON (Extreme High)";
        tradeStr = "SELL ZONE";
        stateColor = clrCrimson;
    }
    else if(ColorState[0] == -1) 
    {
        stateStr = "MEDIUMBLUE (Extreme Low)";
        tradeStr = "BUY ZONE";
        stateColor = clrMediumBlue;
    }
    else 
    {
        stateStr = "GRAY (Neutral)";
        tradeStr = "NO TRADE";
        stateColor = clrGray;
    }
    
    comment += "\n║ State: " + stateStr;
    comment += "\n║ Trade: " + tradeStr;
    comment += "\n╠════════════════════════════════════╣";
    comment += "\n║ MACD: " + DoubleToString(macd, 5);
    comment += "\n║ Signal: " + DoubleToString(signal, 5);
    comment += "\n║ Histogram: " + DoubleToString(histogram, 5);
    comment += "\n╠════════════════════════════════════╣";
    
    // Position relative to bands
    string position = "";
    if(macd > BBUpper[0])
        position = "Above BB Upper";
    else if(macd < BBLower[0])
        position = "Below BB Lower";
    else
        position = "Inside Bands";
    
    comment += "\n║ BB Position: " + position;
    comment += "\n║ BB Upper: " + DoubleToString(BBUpper[0], 5);
    comment += "\n║ BB Lower: " + DoubleToString(BBLower[0], 5);
    
    // Add current MA values
    comment += "\n╠════════════════════════════════════╣";
    comment += "\n║ Fast MA Value: " + DoubleToString(FastMABuffer[0], Digits);
    comment += "\n║ Slow MA Value: " + DoubleToString(SlowMABuffer[0], Digits);
    comment += "\n╚════════════════════════════════════╝";
    
    Comment(comment);
}

//+------------------------------------------------------------------+