//+------------------------------------------------------------------+
//|                                         GCM_Chimera_Candles.mq5 |
//|                     Combined GCM HARSI Visuals + Chimera Logic   |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "2.06"
#property indicator_separate_window
#property indicator_buffers 43  // Adjusted for Manual Buffers
#property indicator_plots   6

//--- Plot 1: Chimera HARSI Candles
#property indicator_label1  "Chimera Open;Chimera High;Chimera Low;Chimera Close"
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- Plot 2: Consensus Line
#property indicator_label2  "Consensus Sentiment"
#property indicator_type2   DRAW_COLOR_LINE
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- Plot 3-6: Signals
#property indicator_label3  "Main Buy Label"
#property indicator_type3   DRAW_ARROW
#property indicator_color3  clrLime
#property indicator_width3  1

#property indicator_label4  "Main Sell Label"
#property indicator_type4   DRAW_ARROW
#property indicator_color4  clrRed
#property indicator_width4  1

#property indicator_label5  "Fast Buy Alert"
#property indicator_type5   DRAW_ARROW
#property indicator_color5  clrLime
#property indicator_width5  1

#property indicator_label6  "Fast Sell Alert"
#property indicator_type6   DRAW_ARROW
#property indicator_color6  clrRed
#property indicator_width6  1

// --- CONSTANTS ---
#define ARROW_BUY_MAIN  233
#define ARROW_SELL_MAIN 234
#define PALETTE_SIZE 44 // 0-19 Bear, 20-39 Bull, 40 White, 41 Gray, 42 Lime, 43 Red

// --- INPUTS ---
input group "Visual Colors"
input color InpGreedColor = clrAqua;          // Bullish (Greed) Base Color
input color InpFearColor  = clrMaroon;        // Bearish (Fear) Base Color
input color InpNeutralColor = clrYellow;      // Neutral Base Color
input color InpConsolColor  = clrWhite;       // Consolidation Color
input color InpLineBull   = clrLime;          // Line Bullish Color
input color InpLineBear   = clrRed;           // Line Bearish Color
input bool  InpPaintConsolidation = true;     // Paint Main Chart Bars (White)?
input bool  InpGrayOnConflict     = false;    // Paint Gray on Indicator Conflict?

input group "GCM HARSI Visuals"
input int              inp_smoothing  = 1;    // Candle Open Smoothing (1 = No Lag)

input group "Chimera Core Logic"
input int InpLookbackPeriod = 252;            // Lookback Period (normalization)
input int InpShortSmoothing = 1;              // Short Smoothing Period
input int InpLongSmoothing = 12;              // Long Smoothing Period
input double InpStDevValue = 1.8;             // Standard Deviation Multiplier

input group "Component Settings"
input int InpRSILength = 14;                  // RSI Length
input int InpMACDFast = 12;                   // MACD Fast Length
input int InpMACDSlow = 26;                   // MACD Slow Length
input int InpMACDSignal = 9;                  // MACD Signal Length
input int InpBBLength = 20;                   // Bollinger Bands Length
input double InpBBMult = 2.0;                 // Bollinger Bands Mult
input int InpStochKPeriod = 14;               // Stochastic %K Period
input int InpStochSmooth = 3;                 // Stochastic %K Smooth
input int InpStochDPeriod = 3;                // Stochastic %D Period
input int InpATRLength = 14;                  // ATR Length
input int InpADXLength = 14;                  // ADX Length

input group "Signal Config"
input bool             inp_showMainSig = true;    // Show HARSI Reversal Labels?
input bool             inp_showFastSig = true;    // Show Momentum Alerts?
input bool             inp_filterExtreme = true;  // Filter Signals by OB/OS?
input int              inp_upper      = 20;       // Overbought Level (+20)
input int              inp_lower      = -20;      // Oversold Level (-20)

input group "Alert Config"
input bool             inp_alert_popup = true;    // Popup Alert
input bool             inp_alert_push  = false;   // Push Notification
input bool             inp_alert_sound = false;   // Sound Alert
input string           inp_sound_file  = "alert.wav"; // Sound File

// --- BUFFERS ---
// 1. Drawing Buffers
double ExtOpenBuffer[];
double ExtHighBuffer[];
double ExtLowBuffer[];
double ExtCloseBuffer[];
double ExtColorBuffer[];     // Candle Color Index
double ExtConsensusBuffer[]; // Line Data
double ExtLineColorBuffer[]; // Line Color Index (Buffer 6)

double ExtBuyLabelBuffer[];
double ExtSellLabelBuffer[];
double ExtBuyFastBuffer[];
double ExtSellFastBuffer[];

// 2. Calculation Buffers (start from 11)
double RSI_Normalized[];
double MACD_Normalized[];
double BB_Normalized[];
double Stoch_Normalized[];
double ATR_Normalized[];

double SentimentRaw[];
double SentimentShort[];
double SentimentLong[];
double AvgSentiment[];

// ADX Helpers
double SmoothTRBuffer[];
double SmoothPlusDMBuffer[];
double SmoothMinusDMBuffer[];
double ADXBuffer[];
double DIPlusBuffer[];
double DIMinusBuffer[];
double DirVolBuffer[];

// Bands Helpers
double MidLineBuffer[]; // Double smoothed AvgSentiment
double StDevBuffer[];

// Manual Calc Buffers
double PercentBBuffer[]; // Stores raw %B values
double RSIRawBuffer[];   // Raw RSI values (0-100)
double RSI_AvgU[];       // RSI Smoothing Up
double RSI_AvgD[];       // RSI Smoothing Dn

double MACD_FastBuffer[]; // Fast EMA
double MACD_SlowBuffer[]; // Slow EMA
double MACD_MainBuffer[]; // MACD Line
double MACD_SignalBuffer[]; // Signal Line
double MACD_HistBuffer[]; // Histogram (to be normalized)

double ATRBuffer[];      // Manual ATR Buffer

// --- HANDLES ---
// ALL HANDLES REMOVED - FULL MANUAL CALCULATION

// --- GLOBALS ---
uint g_palette[PALETTE_SIZE];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   // Map Buffers
   SetIndexBuffer(0, ExtOpenBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, ExtHighBuffer, INDICATOR_DATA);
   SetIndexBuffer(2, ExtLowBuffer, INDICATOR_DATA);
   SetIndexBuffer(3, ExtCloseBuffer, INDICATOR_DATA);
   SetIndexBuffer(4, ExtColorBuffer, INDICATOR_COLOR_INDEX);
   
   SetIndexBuffer(5, ExtConsensusBuffer, INDICATOR_DATA);
   SetIndexBuffer(6, ExtLineColorBuffer, INDICATOR_COLOR_INDEX); // Line Color
   
   SetIndexBuffer(7, ExtBuyLabelBuffer, INDICATOR_DATA);
   SetIndexBuffer(8, ExtSellLabelBuffer, INDICATOR_DATA);
   SetIndexBuffer(9, ExtBuyFastBuffer, INDICATOR_DATA);
   SetIndexBuffer(10, ExtSellFastBuffer, INDICATOR_DATA);
   
   SetIndexBuffer(11, RSI_Normalized, INDICATOR_CALCULATIONS);
   SetIndexBuffer(12, MACD_Normalized, INDICATOR_CALCULATIONS);
   SetIndexBuffer(13, BB_Normalized, INDICATOR_CALCULATIONS);
   SetIndexBuffer(14, Stoch_Normalized, INDICATOR_CALCULATIONS);
   SetIndexBuffer(15, ATR_Normalized, INDICATOR_CALCULATIONS);
   SetIndexBuffer(16, SentimentRaw, INDICATOR_CALCULATIONS);
   SetIndexBuffer(17, SentimentShort, INDICATOR_CALCULATIONS);
   SetIndexBuffer(18, SentimentLong, INDICATOR_CALCULATIONS);
   SetIndexBuffer(19, AvgSentiment, INDICATOR_CALCULATIONS);
   
   SetIndexBuffer(20, SmoothTRBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(21, SmoothPlusDMBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(22, SmoothMinusDMBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(23, ADXBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(24, DIPlusBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(25, DIMinusBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(26, DirVolBuffer, INDICATOR_CALCULATIONS);
   
   SetIndexBuffer(27, MidLineBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(28, StDevBuffer, INDICATOR_CALCULATIONS);
   
   SetIndexBuffer(29, PercentBBuffer, INDICATOR_CALCULATIONS);
   
   SetIndexBuffer(30, RSIRawBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(31, RSI_AvgU, INDICATOR_CALCULATIONS);
   SetIndexBuffer(32, RSI_AvgD, INDICATOR_CALCULATIONS);
   
   SetIndexBuffer(33, MACD_FastBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(34, MACD_SlowBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(35, MACD_MainBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(36, MACD_SignalBuffer, INDICATOR_CALCULATIONS);
   SetIndexBuffer(37, MACD_HistBuffer, INDICATOR_CALCULATIONS);

   SetIndexBuffer(38, ATRBuffer, INDICATOR_CALCULATIONS);

   ArrayInitialize(ExtOpenBuffer, EMPTY_VALUE);
   ArrayInitialize(ExtCloseBuffer, EMPTY_VALUE);
   ArrayInitialize(ExtHighBuffer, EMPTY_VALUE);
   ArrayInitialize(ExtLowBuffer, EMPTY_VALUE);
   ArrayInitialize(ExtConsensusBuffer, EMPTY_VALUE);
   ArrayInitialize(ExtColorBuffer, 0.0);
   ArrayInitialize(ExtLineColorBuffer, 41.0); // Default Gray
   
   // --- PALETTE GENERATION ---
   // 0-19: Bearish (Neutral -> Fear)
   // 20-39: Bullish (Neutral -> Greed)
   // 40: Consolidation (White)
   // 41: Default/Gray
   // 42: Line Bullish (Lime)
   // 43: Line Bearish (Red)
   
   // Bearish: Yellow (Neutral) to Maroon (Fear)
   for(int i=0; i<20; i++) {
       double f = (double)i / 19.0; // 0 to 1
       g_palette[i] = GradientColor(InpNeutralColor, InpFearColor, f);
   }
   
   // Bullish: Yellow (Neutral) to Aqua (Greed)
   for(int i=0; i<20; i++) {
       double f = (double)i / 19.0;
       g_palette[20+i] = GradientColor(InpNeutralColor, InpGreedColor, f);
   }
   
   g_palette[40] = InpConsolColor;
   g_palette[41] = clrGray;
   g_palette[42] = InpLineBull; // Lime
   g_palette[43] = InpLineBear; // Red

   // Assign Palette to Plot 0 (Candles) AND Plot 1 (Line)
   
   PlotIndexSetInteger(0, PLOT_COLOR_INDEXES, PALETTE_SIZE);
   for(int i=0; i<PALETTE_SIZE; i++) {
       PlotIndexSetInteger(0, PLOT_LINE_COLOR, i, g_palette[i]);
   }
   
   PlotIndexSetInteger(1, PLOT_COLOR_INDEXES, PALETTE_SIZE); // Plot 1 is Line
   for(int i=0; i<PALETTE_SIZE; i++) {
       PlotIndexSetInteger(1, PLOT_LINE_COLOR, i, g_palette[i]);
   }

   IndicatorSetInteger(INDICATOR_LEVELS, 3);
   IndicatorSetDouble(INDICATOR_LEVELVALUE, 0, 0.0);
   IndicatorSetDouble(INDICATOR_LEVELVALUE, 1, 20);
   IndicatorSetDouble(INDICATOR_LEVELVALUE, 2, -20);
   IndicatorSetString(INDICATOR_SHORTNAME, "GCM Chimera Candles");
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, "GCM_White_");
}

//+------------------------------------------------------------------+
//| Helper Prototypes                                                |
//+------------------------------------------------------------------+
color GradientColor(color start, color end, double factor);
double CalculateStochastic(const double &high[], const double &low[], const double &close[], int index, int k_per, int d_per);
double NormalizeArray(const double &arr[], int index, int lookback);
double GetSMA(const double &arr[], int index, int period);
double GetStDev(const double &arr[], int index, int period);
double GetSMA_ATR_Buffer(int index, int period, const double &close[], const double &atr_buf[]); // Helper for Volume Factor
void DrawOverlayCandle(datetime t, double o, double h, double l, double c);
void DeleteOverlayCandle(datetime t);


//+------------------------------------------------------------------+
//| 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[])
{
   if (rates_total < InpLookbackPeriod + InpLongSmoothing * 2) return 0;
   
   // Set Series
   ArraySetAsSeries(open, true);
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low, true);
   ArraySetAsSeries(close, true);
   ArraySetAsSeries(time, true);
   
   // Map Buffers to Series
   ArraySetAsSeries(ExtOpenBuffer, true);
   ArraySetAsSeries(ExtHighBuffer, true);
   ArraySetAsSeries(ExtLowBuffer, true);
   ArraySetAsSeries(ExtCloseBuffer, true);
   ArraySetAsSeries(ExtColorBuffer, true);
   
   ArraySetAsSeries(ExtConsensusBuffer, true);
   ArraySetAsSeries(ExtLineColorBuffer, true);
   
   ArraySetAsSeries(ExtBuyLabelBuffer, true);
   ArraySetAsSeries(ExtSellLabelBuffer, true);
   ArraySetAsSeries(ExtBuyFastBuffer, true);
   ArraySetAsSeries(ExtSellFastBuffer, true);
   
   ArraySetAsSeries(RSI_Normalized, true);
   ArraySetAsSeries(MACD_Normalized, true);
   ArraySetAsSeries(BB_Normalized, true);
   ArraySetAsSeries(Stoch_Normalized, true);
   ArraySetAsSeries(ATR_Normalized, true);
   ArraySetAsSeries(SentimentRaw, true);
   ArraySetAsSeries(SentimentShort, true);
   ArraySetAsSeries(SentimentLong, true);
   ArraySetAsSeries(AvgSentiment, true);
   
   ArraySetAsSeries(SmoothTRBuffer, true);
   ArraySetAsSeries(SmoothPlusDMBuffer, true);
   ArraySetAsSeries(SmoothMinusDMBuffer, true);
   ArraySetAsSeries(ADXBuffer, true);
   ArraySetAsSeries(DIPlusBuffer, true);
   ArraySetAsSeries(DIMinusBuffer, true);
   ArraySetAsSeries(DirVolBuffer, true);
   
   ArraySetAsSeries(MidLineBuffer, true);
   ArraySetAsSeries(StDevBuffer, true);
   
   ArraySetAsSeries(PercentBBuffer, true);
   ArraySetAsSeries(RSIRawBuffer, true);
   ArraySetAsSeries(RSI_AvgU, true);
   ArraySetAsSeries(RSI_AvgD, true);
   
   ArraySetAsSeries(MACD_FastBuffer, true);
   ArraySetAsSeries(MACD_SlowBuffer, true);
   ArraySetAsSeries(MACD_MainBuffer, true);
   ArraySetAsSeries(MACD_SignalBuffer, true);
   ArraySetAsSeries(MACD_HistBuffer, true);
   
   ArraySetAsSeries(ATRBuffer, true);

   // =========================================================================
   // LOOP 1: RECURSIVE & RAW COMPONENTS (Entire Valid History)
   // =========================================================================
   // Calculate as far back as possible to ensure history buffers are populated.
   int limit_hist;
   if(prev_calculated == 0 || rates_total > prev_calculated + 1)
       limit_hist = rates_total - 2;
   else
       limit_hist = rates_total - prev_calculated + 1;
       
   if(limit_hist > rates_total - 2) limit_hist = rates_total - 2;

   for(int i = limit_hist; i >= 0; i--)
   {
      double h = high[i];
      double l = low[i];
      double c1 = close[i+1]; 
      
      double tr = MathMax(h-l, MathMax(MathAbs(h-c1), MathAbs(l-c1)));
      double up = h - high[i+1];
      double dn = low[i+1] - l;
      double pdm = (up > dn && up > 0) ? up : 0;
      double ndm = (dn > up && dn > 0) ? dn : 0;
      
      bool seed = (i >= rates_total - MathMax(InpADXLength, InpATRLength) * 2) || (prev_calculated == 0 && i == limit_hist); 
      if(i >= rates_total - 2) seed = true; 
      
      // --- ADX ---
      if(seed) {
          SmoothTRBuffer[i] = tr;
          SmoothPlusDMBuffer[i] = pdm;
          SmoothMinusDMBuffer[i] = ndm;
      } else {
          SmoothTRBuffer[i] = SmoothTRBuffer[i+1] - (SmoothTRBuffer[i+1]/InpADXLength) + tr;
          SmoothPlusDMBuffer[i] = SmoothPlusDMBuffer[i+1] - (SmoothPlusDMBuffer[i+1]/InpADXLength) + pdm;
          SmoothMinusDMBuffer[i] = SmoothMinusDMBuffer[i+1] - (SmoothMinusDMBuffer[i+1]/InpADXLength) + ndm;
      }
      
      double tr_s = SmoothTRBuffer[i];
      if(tr_s > 0) {
         DIPlusBuffer[i] = 100 * SmoothPlusDMBuffer[i] / tr_s;
         DIMinusBuffer[i] = 100 * SmoothMinusDMBuffer[i] / tr_s;
      } else {
         DIPlusBuffer[i] = 0; DIMinusBuffer[i] = 0;
      }
      
      double sum = DIPlusBuffer[i] + DIMinusBuffer[i];
      double dx = (sum > 0) ? 100 * MathAbs(DIPlusBuffer[i] - DIMinusBuffer[i]) / sum : 0;
      
      if(seed) ADXBuffer[i] = dx;
      else ADXBuffer[i] = (ADXBuffer[i+1] * (InpADXLength-1) + dx) / InpADXLength;
      
      // --- ATR (Manual) --- 
      if(seed) ATRBuffer[i] = tr; 
      else ATRBuffer[i] = (ATRBuffer[i+1] * (InpATRLength - 1) + tr) / InpATRLength;
      
      // --- RSI (Manual) ---
      double diff = close[i] - close[i+1];
      double u = (diff > 0) ? diff : 0;
      double d = (diff < 0) ? -diff : 0;
      
      if(seed) {
          RSI_AvgU[i] = u;
          RSI_AvgD[i] = d;
      } else {
          RSI_AvgU[i] = (RSI_AvgU[i+1] * (InpRSILength - 1) + u) / InpRSILength;
          RSI_AvgD[i] = (RSI_AvgD[i+1] * (InpRSILength - 1) + d) / InpRSILength;
      }
      
      double ars = (RSI_AvgD[i] == 0) ? 0 : RSI_AvgU[i] / RSI_AvgD[i];
      RSIRawBuffer[i] = (RSI_AvgD[i] == 0) ? 100 : 100.0 - (100.0 / (1.0 + ars));
      
      // --- MACD (Manual) ---
      double price = close[i];
      double alphaFast = 2.0 / (InpMACDFast + 1.0);
      double alphaSlow = 2.0 / (InpMACDSlow + 1.0);
      double alphaSig  = 2.0 / (InpMACDSignal + 1.0);
      
      if(seed) {
          MACD_FastBuffer[i] = price;
          MACD_SlowBuffer[i] = price;
          MACD_MainBuffer[i] = 0;
          MACD_SignalBuffer[i] = 0;
      } else {
          MACD_FastBuffer[i] = price * alphaFast + MACD_FastBuffer[i+1] * (1.0 - alphaFast);
          MACD_SlowBuffer[i] = price * alphaSlow + MACD_SlowBuffer[i+1] * (1.0 - alphaSlow);
          MACD_MainBuffer[i] = MACD_FastBuffer[i] - MACD_SlowBuffer[i];
          MACD_SignalBuffer[i] = MACD_MainBuffer[i] * alphaSig + MACD_SignalBuffer[i+1] * (1.0 - alphaSig);
      }
      MACD_HistBuffer[i] = MACD_MainBuffer[i] - MACD_SignalBuffer[i];
      
      // --- LOOP 2 INLINE Optimization: Calculate Raw Derived Components (PercentB, DirVol) ---
      // We calculate these HERE for ALL i to ensure history is available later.
      
      // PercentB
      double bb_raw_sma = GetSMA(close, i, InpBBLength);
      double bb_raw_std = GetStDev(close, i, InpBBLength);
      double bb_upper = bb_raw_sma + InpBBMult * bb_raw_std;
      double bb_lower = bb_raw_sma - InpBBMult * bb_raw_std;
      double bb_bandwidth = bb_upper - bb_lower;
      PercentBBuffer[i] = (bb_bandwidth == 0) ? 50 : 100.0 * (close[i] - bb_lower) / bb_bandwidth;
      
      // DirVol
      double di_diff = DIPlusBuffer[i] - DIMinusBuffer[i];
      double atr_val = ATRBuffer[i];
      double atr_pct = (close[i] == 0) ? 0 : (atr_val / close[i]) * 100;
      double atr_avg = GetSMA_ATR_Buffer(i, InpLookbackPeriod, close, ATRBuffer); 
      double vol_factor = (atr_avg <= 0) ? 1.0 : atr_pct / atr_avg;
      DirVolBuffer[i] = di_diff * vol_factor;
   }
   
   // =========================================================================
   // LOOP 3: NORMALIZATION & VISUALIZATION (Requires Valid Lookback)
   // =========================================================================
   // UNIFIED LIMIT: Run visualizing loop for same history range as calculation loops.
   // NormalizeArray handles "not enough history" by returning 50, so it's safe.
   // This ensures bars are drawn immediately upon load (even if flat/neutral initially).
   
   int limit = limit_hist; // Use same limit as Loop 1
   
   for(int i = limit; i >= 0; i--)
   {
      // --- NORMALIZE MANUALLY CALCULATED BUFFERS ---
      
      RSI_Normalized[i]   = NormalizeArray(RSIRawBuffer, i, InpLookbackPeriod);
      MACD_Normalized[i]  = NormalizeArray(MACD_HistBuffer, i, InpLookbackPeriod);
      Stoch_Normalized[i] = CalculateStochastic(high, low, close, i, InpStochKPeriod, InpStochDPeriod); // Stoch has internal loop, robust.
      BB_Normalized[i]    = NormalizeArray(PercentBBuffer, i, InpLookbackPeriod);
      ATR_Normalized[i]   = NormalizeArray(DirVolBuffer, i, InpLookbackPeriod);
      
      // Sentiment
      SentimentRaw[i] = (RSI_Normalized[i] + MACD_Normalized[i] + BB_Normalized[i] + Stoch_Normalized[i] + ATR_Normalized[i]) / 5.0;
      SentimentShort[i] = GetSMA(SentimentRaw, i, InpShortSmoothing);
      SentimentLong[i] = GetSMA(SentimentRaw, i, InpLongSmoothing);
      
      AvgSentiment[i] = (SentimentShort[i] + SentimentLong[i]) / 2.0;
      
      // --- BANDS LOGIC ---
      MidLineBuffer[i] = GetSMA(AvgSentiment, i, InpLookbackPeriod); 
      
      double stdev = GetStDev(AvgSentiment, i, InpLookbackPeriod*2);
      
      double mid = MidLineBuffer[i];
      double top = mid + InpStDevValue * stdev;
      double bot = mid - InpStDevValue * stdev;
      
      // --- GCM HARSI VISUALIZATION ---
      double source = AvgSentiment[i] - 50.0;
      ExtConsensusBuffer[i] = source;
      
      // Line Color Logic
      bool bullish = SentimentShort[i] > SentimentLong[i];
      ExtLineColorBuffer[i] = bullish ? 42 : 43; // Lime or Red
      
      double haOpen, haHigh, haLow, haClose;
      
      bool hasHistory = (i < rates_total - 1) && (ExtOpenBuffer[i+1] != EMPTY_VALUE);
      
      if(!hasHistory) { 
           haOpen = source; haClose = source; haHigh = source; haLow = source;
      } else {
           double prevOpen = ExtOpenBuffer[i+1];
           double prevClose = ExtCloseBuffer[i+1];
           haOpen = (inp_smoothing > 1) ? ((prevOpen * inp_smoothing) + prevClose) / (inp_smoothing + 1.0) : (prevOpen + prevClose) / 2.0;
           
           double open_src = (ExtConsensusBuffer[i+1] != EMPTY_VALUE) ? ExtConsensusBuffer[i+1] : source;
           double close_src = source;
           
           double h_src = MathMax(open_src, close_src); 
           double l_src = MathMin(open_src, close_src); 
           
           haClose = (open_src + h_src + l_src + close_src) / 4.0;
           haHigh = MathMax(h_src, MathMax(haOpen, haClose));
           haLow = MathMin(l_src, MathMin(haOpen, haClose));
      }
       
       ExtOpenBuffer[i] = haOpen;
       ExtHighBuffer[i] = haHigh;
       ExtLowBuffer[i] = haLow;
       ExtCloseBuffer[i] = haClose;
       
       // --- COLOR LOGIC (Pine Matching) ---
       double adx = ADXBuffer[i];
       double dip = DIPlusBuffer[i];
       double dim = DIMinusBuffer[i];
       bool is_cons = (adx < 14) && (MathAbs(dip - dim) < 5) && (dip < 25) && (dim < 25);
       
       // Overlay (Main Chart) Logic
       if(InpPaintConsolidation) {
           if(is_cons) {
               DrawOverlayCandle(time[i], open[i], high[i], low[i], close[i]);
           } else {
               DeleteOverlayCandle(time[i]);
           }
       }
       
       if(is_cons) {
           ExtColorBuffer[i] = 40; // White
       } else {
           // 2. Conflict Check (Gray)
           bool conflict = false;
           if(InpGrayOnConflict) {
               int bulls = 0; int bears = 0;
               if(RSI_Normalized[i] > 50) bulls++; else bears++;
               if(MACD_Normalized[i] > 50) bulls++; else bears++;
               if(BB_Normalized[i] > 50) bulls++; else bears++;
               if(Stoch_Normalized[i] > 50) bulls++; else bears++;
               if(ATR_Normalized[i] > 50) bulls++; else bears++;
               
               if(bulls != 5 && bears != 5) conflict = true;
           }
           
           if(conflict) {
               ExtColorBuffer[i] = 41; // Gray
           } else {
               // 3. Trend Color (Gradient)
               double avg = AvgSentiment[i];
               
               // Calculate Distance for gradient
               double dist = MathAbs(avg - mid);
               double max_dist = MathMax(top - mid, mid - bot);
               if(max_dist == 0) max_dist = 1;
               
               double factor = dist / max_dist;
               if(factor > 1.0) factor = 1.0;
               
               int idx = (int)(factor * 19.99);
               if(idx < 0) idx = 0; if(idx > 19) idx = 19;
               
               if(bullish) { 
                   ExtColorBuffer[i] = 20 + idx; // Bullish Palette (Yellow -> Aqua)
               } else {
                   ExtColorBuffer[i] = idx;      // Bearish Palette (Yellow -> Maroon)
               }
           }
       }
       
       // Signals
       bool isGreen = haClose > haOpen;
       bool prevGreen = (i < rates_total-1) ? (ExtCloseBuffer[i+1] > ExtOpenBuffer[i+1]) : isGreen;
       bool sBuy = isGreen && !prevGreen;
       bool sSell = !isGreen && prevGreen;
       
       if(inp_filterExtreme) {
           if(source > inp_upper) sBuy = false;
           if(source < inp_lower) sSell = false;
       }
       
       ExtBuyLabelBuffer[i] = sBuy ? haLow - 5 : EMPTY_VALUE;
       ExtSellLabelBuffer[i] = sSell ? haHigh + 5 : EMPTY_VALUE;
   }
   
   ChartRedraw();
   return(rates_total);
}

//+------------------------------------------------------------------+
//| HELPERS                                                          |
//+------------------------------------------------------------------+
void DrawOverlayCandle(datetime t, double o, double h, double l, double c)
{
    string nameW = "GCM_White_W_" + (string)t;
    string nameB = "GCM_White_B_" + (string)t;
    
    // Check if objects exist
    if(ObjectFind(0, nameW) < 0) {
        ObjectCreate(0, nameW, OBJ_TREND, 0, t, h, t, l);
        ObjectSetInteger(0, nameW, OBJPROP_COLOR, clrWhite);
        ObjectSetInteger(0, nameW, OBJPROP_WIDTH, 1);
        ObjectSetInteger(0, nameW, OBJPROP_RAY_RIGHT, false);
        ObjectSetInteger(0, nameW, OBJPROP_SELECTABLE, false);
        ObjectSetInteger(0, nameW, OBJPROP_BACK, false);
    } else {
        ObjectMove(0, nameW, 0, t, h);
        ObjectMove(0, nameW, 1, t, l);
    }
    
    if(ObjectFind(0, nameB) < 0) {
        ObjectCreate(0, nameB, OBJ_TREND, 0, t, o, t, c);
        ObjectSetInteger(0, nameB, OBJPROP_COLOR, clrWhite);
        ObjectSetInteger(0, nameB, OBJPROP_WIDTH, 3);
        ObjectSetInteger(0, nameB, OBJPROP_RAY_RIGHT, false);
        ObjectSetInteger(0, nameB, OBJPROP_SELECTABLE, false);
        ObjectSetInteger(0, nameB, OBJPROP_BACK, false);
    } else {
        ObjectMove(0, nameB, 0, t, o);
        ObjectMove(0, nameB, 1, t, c);
    }
}

void DeleteOverlayCandle(datetime t)
{
    string nameW = "GCM_White_W_" + (string)t;
    string nameB = "GCM_White_B_" + (string)t;
    ObjectDelete(0, nameW);
    ObjectDelete(0, nameB);
}

color GradientColor(color start, color end, double factor)
{
   int r1 = (start >> 16) & 0xFF;
   int g1 = (start >> 8) & 0xFF;
   int b1 = start & 0xFF;
   
   int r2 = (end >> 16) & 0xFF;
   int g2 = (end >> 8) & 0xFF;
   int b2 = end & 0xFF;
   
   int r = r1 + (int)((r2 - r1) * factor);
   int g = g1 + (int)((g2 - g1) * factor);
   int b = b1 + (int)((b2 - b1) * factor);
   
   return (color)((r << 16) | (g << 8) | b);
}

double CalculateStochastic(const double &high[], const double &low[], const double &close[], int index, int k_per, int d_per)
{
   double sum_k = 0;
   for(int d=0; d<d_per; d++) {
       int idx = index + d; 
       if(idx >= ArraySize(high) - k_per) return 50; 
       double h_max = -99999, l_min = 99999;
       for(int k=0; k<k_per; k++) {
           h_max = MathMax(h_max, high[idx+k]);
           l_min = MathMin(l_min, low[idx+k]);
       }
       double k_val = 50;
       if(h_max - l_min != 0) k_val = 100.0 * (close[idx] - l_min) / (h_max - l_min);
       sum_k += k_val;
   }
   return sum_k / d_per;
}

double NormalizeArray(const double &arr[], int index, int lookback)
{
    double mean=0; int count=0;
    for(int k=0; k<lookback; k++) {
        if(index+k < ArraySize(arr)) { mean += arr[index+k]; count++; }
    }
    if(count==0) return 50;
    mean /= count;
    double sum=0;
    for(int k=0; k<count; k++) sum += MathPow(arr[index+k]-mean, 2);
    double stdev = MathSqrt(sum/count);
    if(stdev==0) return 50;
    double z = (arr[index]-mean)/stdev;
    return MathMin(100.0, MathMax(0.0, 50.0 + z*15.0));
}

double GetSMA(const double &arr[], int index, int period) {
    double s=0; int c=0;
    for(int k=0; k<period; k++) {
        if(index+k < ArraySize(arr)) { s += arr[index+k]; c++; }
    }
    return c>0 ? s/c : 0;
}

double GetStDev(const double &arr[], int index, int period) {
    double mean = GetSMA(arr, index, period);
    double sum = 0; int c=0;
    for(int k=0; k<period; k++) {
        if(index+k < ArraySize(arr)) { sum += MathPow(arr[index+k]-mean, 2); c++; }
    }
    return c>0 ? MathSqrt(sum/c) : 0;
}

double GetSMA_ATR_Buffer(int index, int period, const double &close[], const double &atr_buf[]) {
    double s=0; 
    for(int k=0; k<period; k++) {
        if(index+k < ArraySize(close) && index+k < ArraySize(atr_buf)) {
             double c = close[index+k];
             if(c!=0) s += (atr_buf[index+k]/c)*100.0; 
        }
    }
    return s/period;
}
