//+------------------------------------------------------------------+
//|                                     MACD_Gradient_Histogram.mq5  |
//|  Sub-window part: MACD histogram + MACD line + Signal line,      |
//|  20-step gradient driven by the MACD / Signal crossover.         |
//|  Pair with "MACD_Gradient_Candles" for the main-chart candles.   |
//+------------------------------------------------------------------+
#property description "MACD 20-step gradient histogram (sub-window)"
#property indicator_separate_window

#property indicator_buffers 10
#property indicator_plots   3

// Plot 1: Histogram
#property indicator_type1   DRAW_COLOR_HISTOGRAM
#property indicator_color1  0x0000FF,0x001AFF,0x0035FF,0x004FFF,0x006AFF,0x0084FF,0x009FFF,0x00B9FF,0x00D4FF,0x00EEFF,0x00FFF6,0x00FFDC,0x00FFC1,0x00FFA6,0x00FF8C,0x00FF71,0x00FF57,0x00FF3C,0x00FF21,0x00FF00
#property indicator_width1  2
#property indicator_label1  "MACD Histogram"

// Plot 2: MACD Line
#property indicator_type2   DRAW_COLOR_LINE
#property indicator_color2  0x0000FF,0x001AFF,0x0035FF,0x004FFF,0x006AFF,0x0084FF,0x009FFF,0x00B9FF,0x00D4FF,0x00EEFF,0x00FFF6,0x00FFDC,0x00FFC1,0x00FFA6,0x00FF8C,0x00FF71,0x00FF57,0x00FF3C,0x00FF21,0x00FF00
#property indicator_width2  2
#property indicator_label2  "MACD Line"

// Plot 3: Signal Line
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrGold
#property indicator_width3  1
#property indicator_label3  "Signal"

enum enPrices
{
   pr_close,      // Close
   pr_open,       // Open
   pr_high,       // High
   pr_low,        // Low
   pr_median,     // Median
   pr_typical,    // Typical
   pr_weighted,   // Weighted
   pr_average,    // Average (high+low+open+close)/4
   pr_medianb,    // Average median body (open+close)/2
   pr_tbiased,    // Trend biased price
   pr_haclose,    // Heiken ashi close
   pr_haopen ,    // Heiken ashi open
   pr_hahigh,     // Heiken ashi high
   pr_halow,      // Heiken ashi low
   pr_hamedian,   // Heiken ashi median
   pr_hatypical,  // Heiken ashi typical
   pr_haweighted, // Heiken ashi weighted
   pr_haaverage,  // Heiken ashi average
   pr_hamedianb,  // Heiken ashi median body
   pr_hatbiased   // Heiken ashi trend biased price
};

input int      InpFastEMA        = 12;             // Macd fast period
input int      InpSlowEMA        = 26;             // Macd slow period
input int      InpSignalEMA      = 9;              // Signal period
input enPrices InpAppliedPrice   = pr_close;       // Price to use
input int      InpGradientPeriod = 100;            // Gradient Lookback Period (spread strength)

// Gradient colors - switch at the MACD / Signal crossover
input color    InpBearColor      = clrRed;         // MACD below Signal: strongest color
input color    InpBullColor      = clrLime;        // MACD above Signal: strongest color
input color    InpNeutralColor   = clrDimGray;     // Color right at the crossover (spread ~ 0)

// Plot buffers
double ExtHistPlot[];
double ExtHistColor[];
double ExtMacdLinePlot[];
double ExtMacdLineColor[];
double ExtSignalPlot[];

// Calculation buffers
double ExtFastEma[];
double ExtSlowEma[];
double ExtMacdCalc[];
double ExtSignalCalc[];
double ExtSpreadAbs[];

//------------------------------------------------------------------
int OnInit()
{
   if(InpFastEMA < 1 || InpSlowEMA < 1 || InpSignalEMA < 1 || InpGradientPeriod < 1)
   {
      Print("All periods must be >= 1");
      return(INIT_PARAMETERS_INCORRECT);
   }

   SetIndexBuffer(0, ExtHistPlot,       INDICATOR_DATA);
   SetIndexBuffer(1, ExtHistColor,      INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2, ExtMacdLinePlot,   INDICATOR_DATA);
   SetIndexBuffer(3, ExtMacdLineColor,  INDICATOR_COLOR_INDEX);
   SetIndexBuffer(4, ExtSignalPlot,     INDICATOR_DATA);
   SetIndexBuffer(5, ExtFastEma,        INDICATOR_CALCULATIONS);
   SetIndexBuffer(6, ExtSlowEma,        INDICATOR_CALCULATIONS);
   SetIndexBuffer(7, ExtMacdCalc,       INDICATOR_CALCULATIONS);
   SetIndexBuffer(8, ExtSignalCalc,     INDICATOR_CALCULATIONS);
   SetIndexBuffer(9, ExtSpreadAbs,      INDICATOR_CALCULATIONS);

   ArraySetAsSeries(ExtHistPlot,      false);
   ArraySetAsSeries(ExtHistColor,     false);
   ArraySetAsSeries(ExtMacdLinePlot,  false);
   ArraySetAsSeries(ExtMacdLineColor, false);
   ArraySetAsSeries(ExtSignalPlot,    false);
   ArraySetAsSeries(ExtFastEma,       false);
   ArraySetAsSeries(ExtSlowEma,       false);
   ArraySetAsSeries(ExtMacdCalc,      false);
   ArraySetAsSeries(ExtSignalCalc,    false);
   ArraySetAsSeries(ExtSpreadAbs,     false);

   PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, InpSignalEMA - 1);
   IndicatorSetString(INDICATOR_SHORTNAME, "MACD Gradient Histogram(" + string(InpFastEMA) + "," + string(InpSlowEMA) + "," + string(InpSignalEMA) + ")");
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits + 1);

   // --- Crossover-based gradient palette (20 colors) ---
   // Index  0..9  : MACD below Signal  (0 = strongest bear ... 9 = nearly neutral)
   // Index 10..19 : MACD above Signal  (10 = nearly neutral ... 19 = strongest bull)
   int rn = InpNeutralColor & 0xFF, gn = (InpNeutralColor >> 8) & 0xFF, bn = (InpNeutralColor >> 16) & 0xFF;
   int rb = InpBearColor    & 0xFF, gb = (InpBearColor    >> 8) & 0xFF, bb = (InpBearColor    >> 16) & 0xFF;
   int ru = InpBullColor    & 0xFF, gu = (InpBullColor    >> 8) & 0xFF, bu = (InpBullColor    >> 16) & 0xFF;

   for(int k = 0; k < 10; k++)
   {
      double s = (k + 1) / 10.0;
      color bearCol = (color)(((int)(bn + s*(bb-bn)) << 16) | ((int)(gn + s*(gb-gn)) << 8) | (int)(rn + s*(rb-rn)));
      color bullCol = (color)(((int)(bn + s*(bu-bn)) << 16) | ((int)(gn + s*(gu-gn)) << 8) | (int)(rn + s*(ru-rn)));

      int bearIdx = 9 - k;
      int bullIdx = 10 + k;

      PlotIndexSetInteger(0, PLOT_LINE_COLOR, bearIdx, bearCol);
      PlotIndexSetInteger(1, PLOT_LINE_COLOR, bearIdx, bearCol);
      PlotIndexSetInteger(0, PLOT_LINE_COLOR, bullIdx, bullCol);
      PlotIndexSetInteger(1, PLOT_LINE_COLOR, bullIdx, bullCol);
   }
   return(INIT_SUCCEEDED);
}

//------------------------------------------------------------------
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 &TickVolume[],
                const long &Volume[],
                const int &Spread[])
{
   if(rates_total < 2) return(0);

   int first = (prev_calculated > 0) ? prev_calculated - 1 : 0;

   double aFast = 2.0 / (1.0 + InpFastEMA);
   double aSlow = 2.0 / (1.0 + InpSlowEMA);
   double aSig  = 2.0 / (1.0 + InpSignalEMA);

   // Pass 1: MACD, Signal, |MACD - Signal|
   for(int i = first; i < rates_total; i++)
   {
      double price = getPrice(InpAppliedPrice, Open, Close, High, Low, rates_total, i);
      if(i == 0)
      {
         ExtFastEma[i]    = price;
         ExtSlowEma[i]    = price;
         ExtMacdCalc[i]   = 0.0;
         ExtSignalCalc[i] = 0.0;
      }
      else
      {
         ExtFastEma[i]    = ExtFastEma[i-1] + aFast * (price - ExtFastEma[i-1]);
         ExtSlowEma[i]    = ExtSlowEma[i-1] + aSlow * (price - ExtSlowEma[i-1]);
         ExtMacdCalc[i]   = ExtFastEma[i] - ExtSlowEma[i];
         ExtSignalCalc[i] = ExtSignalCalc[i-1] + aSig * (ExtMacdCalc[i] - ExtSignalCalc[i-1]);
      }
      ExtSpreadAbs[i] = MathAbs(ExtMacdCalc[i] - ExtSignalCalc[i]);
   }

   // Pass 2: gradient colors + plot data
   for(int i = first; i < rates_total; i++)
   {
      double spread = ExtMacdCalc[i] - ExtSignalCalc[i];

      int start  = (int)MathMax(0, i - InpGradientPeriod + 1);
      int count  = i - start + 1;
      double maxSp = ExtSpreadAbs[ArrayMaximum(ExtSpreadAbs, start, count)];

      int k = 0;
      if(maxSp > 0.0)
      {
         k = (int)MathFloor(9.99 * MathAbs(spread) / maxSp);
         if(k < 0) k = 0;
         if(k > 9) k = 9;
      }
      int colorIndex = (spread >= 0.0) ? 10 + k : 9 - k;

      ExtHistPlot[i]      = ExtMacdCalc[i];
      ExtHistColor[i]     = colorIndex;
      ExtMacdLinePlot[i]  = ExtMacdCalc[i];
      ExtMacdLineColor[i] = colorIndex;
      ExtSignalPlot[i]    = ExtSignalCalc[i];
   }
   return(rates_total);
}

//------------------------------------------------------------------
double workHa[][4];
double getPrice(int price, const double &open[], const double &close[], const double &high[], const double &low[], int bars, int i, int instanceNo = 0)
{
   if(price >= pr_haclose)
   {
      if(ArrayRange(workHa, 0) != bars) ArrayResize(workHa, bars);

      double haOpen;
      if(i > 0)
           haOpen = (workHa[i-1][instanceNo+2] + workHa[i-1][instanceNo+3]) / 2.0;
      else haOpen = (open[i] + close[i]) / 2;
      double haClose = (open[i] + high[i] + low[i] + close[i]) / 4.0;
      double haHigh  = MathMax(high[i], MathMax(haOpen, haClose));
      double haLow   = MathMin(low[i],  MathMin(haOpen, haClose));

      if(haOpen < haClose) { workHa[i][instanceNo+0] = haLow;  workHa[i][instanceNo+1] = haHigh; }
      else                 { workHa[i][instanceNo+0] = haHigh; workHa[i][instanceNo+1] = haLow;  }
      workHa[i][instanceNo+2] = haOpen;
      workHa[i][instanceNo+3] = haClose;

      switch(price)
      {
         case pr_haclose:    return(haClose);
         case pr_haopen:     return(haOpen);
         case pr_hahigh:     return(haHigh);
         case pr_halow:      return(haLow);
         case pr_hamedian:   return((haHigh + haLow) / 2.0);
         case pr_hamedianb:  return((haOpen + haClose) / 2.0);
         case pr_hatypical:  return((haHigh + haLow + haClose) / 3.0);
         case pr_haweighted: return((haHigh + haLow + haClose + haClose) / 4.0);
         case pr_haaverage:  return((haHigh + haLow + haClose + haOpen) / 4.0);
         case pr_hatbiased:
            if(haClose > haOpen) return((haHigh + haClose) / 2.0);
            else                 return((haLow + haClose) / 2.0);
      }
   }

   switch(price)
   {
      case pr_close:    return(close[i]);
      case pr_open:     return(open[i]);
      case pr_high:     return(high[i]);
      case pr_low:      return(low[i]);
      case pr_median:   return((high[i] + low[i]) / 2.0);
      case pr_medianb:  return((open[i] + close[i]) / 2.0);
      case pr_typical:  return((high[i] + low[i] + close[i]) / 3.0);
      case pr_weighted: return((high[i] + low[i] + close[i] + close[i]) / 4.0);
      case pr_average:  return((high[i] + low[i] + close[i] + open[i]) / 4.0);
      case pr_tbiased:
         if(close[i] > open[i]) return((high[i] + close[i]) / 2.0);
         else                   return((low[i] + close[i]) / 2.0);
   }
   return(0);
}
//+------------------------------------------------------------------+
