//+------------------------------------------------------------------+
//|                                       MACD_Candles_Strength.mq4  |
//|  Candles colored by MACD (ATR-normalized) + crossover of two     |
//|  EMAs. Separates STRONG candles from FLAT ones.                  |
//+------------------------------------------------------------------+
#property copyright "Free indicator"
#property version   "1.10"
#property strict
#property description "Colored candles: MACD + crossover of 2 EMAs."
#property description "Strong = strong MACD AND aligned EMAs. Flat = no momentum / EMAs squeezed together."

#property indicator_chart_window
#property indicator_buffers 4
#property indicator_color1  clrDodgerBlue   // fast EMA
#property indicator_color2  clrOrange       // slow EMA
#property indicator_color3  clrLime         // bullish crossover arrow
#property indicator_color4  clrRed          // bearish crossover arrow

//--- MACD parameters
input int    InpFastEMA         = 12;    // MACD fast EMA
input int    InpSlowEMA         = 26;    // MACD slow EMA
input int    InpSignalSMA       = 9;     // MACD signal
//--- crossover EMA parameters
input int    InpEMAFast         = 14;    // Fast EMA (crossover)
input int    InpEMASlow         = 20;    // Slow EMA (crossover)
input bool   InpShowEMAs        = true;  // Show EMA lines
input bool   InpShowArrows      = true;  // Show crossover arrows
//--- classification
input int    InpATRPeriod       = 14;    // ATR period (normalization)
input double InpFlatThreshold   = 0.10;  // |Histogram|/ATR below this = FLAT
input double InpStrongThreshold = 0.30;  // |Histogram|/ATR above this = STRONG
input bool   InpUseEMAFilter    = true;  // Use EMAs in the classification
input double InpEMAFlatDist     = 0.05;  // |FastEMA-SlowEMA|/ATR below this = FLAT
input bool   InpHideChartCandles = true; // Hide the original chart candles
//--- drawing
input int    InpMaxBars         = 1000;  // Number of recent bars calculated and drawn
input string InpPrefix          = "MCS_"; // Prefix of the candle objects

//--- buffers (EMA lines and arrows)
double BufEmaF[], BufEmaS[], BufBuy[], BufSell[];

//--- candle colors: 0=Strong up, 1=Weak up, 2=Flat, 3=Weak down, 4=Strong down
color g_colors[5] = {clrLime, clrForestGreen, clrGray, clrFireBrick, clrRed};

//--- saved original chart colors
color g_bull, g_bear, g_chartUp, g_chartDown;
bool  g_colorsSaved = false;

//+------------------------------------------------------------------+
int OnInit()
{
   if(InpFastEMA < 1 || InpSlowEMA <= InpFastEMA || InpSignalSMA < 1 || InpATRPeriod < 1)
   {
      Print("Invalid parameters: the MACD slow EMA must be greater than the fast EMA.");
      return INIT_PARAMETERS_INCORRECT;
   }
   if(InpEMAFast < 1 || InpEMASlow <= InpEMAFast)
   {
      Print("Invalid parameters: the crossover slow EMA must be greater than the fast EMA.");
      return INIT_PARAMETERS_INCORRECT;
   }
   if(InpFlatThreshold < 0 || InpStrongThreshold < InpFlatThreshold || InpEMAFlatDist < 0)
   {
      Print("Invalid parameters: Strong must be >= Flat and distances must be >= 0.");
      return INIT_PARAMETERS_INCORRECT;
   }
   if(InpMaxBars < 50)
   {
      Print("Invalid parameters: InpMaxBars must be at least 50.");
      return INIT_PARAMETERS_INCORRECT;
   }

   IndicatorBuffers(4);
   SetIndexBuffer(0, BufEmaF);
   SetIndexBuffer(1, BufEmaS);
   SetIndexBuffer(2, BufBuy);
   SetIndexBuffer(3, BufSell);

   SetIndexStyle(0, InpShowEMAs ? DRAW_LINE : DRAW_NONE, STYLE_SOLID, 1, clrDodgerBlue);
   SetIndexStyle(1, InpShowEMAs ? DRAW_LINE : DRAW_NONE, STYLE_SOLID, 1, clrOrange);
   SetIndexStyle(2, InpShowArrows ? DRAW_ARROW : DRAW_NONE, STYLE_SOLID, 2, clrLime);
   SetIndexStyle(3, InpShowArrows ? DRAW_ARROW : DRAW_NONE, STYLE_SOLID, 2, clrRed);

   // arrows: 233 = up arrow, 234 = down arrow
   SetIndexArrow(2, 233);
   SetIndexArrow(3, 234);

   SetIndexLabel(0, "Fast EMA");
   SetIndexLabel(1, "Slow EMA");
   SetIndexLabel(2, "Bullish crossover");
   SetIndexLabel(3, "Bearish crossover");

   for(int p = 0; p < 4; p++)
      SetIndexEmptyValue(p, EMPTY_VALUE);

   SetIndexDrawBegin(0, InpEMAFast);
   SetIndexDrawBegin(1, InpEMASlow);

   if(InpHideChartCandles)
   {
      g_bull      = (color)ChartGetInteger(0, CHART_COLOR_CANDLE_BULL);
      g_bear      = (color)ChartGetInteger(0, CHART_COLOR_CANDLE_BEAR);
      g_chartUp   = (color)ChartGetInteger(0, CHART_COLOR_CHART_UP);
      g_chartDown = (color)ChartGetInteger(0, CHART_COLOR_CHART_DOWN);
      g_colorsSaved = true;
      ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, clrNONE);
      ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrNONE);
      ChartSetInteger(0, CHART_COLOR_CHART_UP,    clrNONE);
      ChartSetInteger(0, CHART_COLOR_CHART_DOWN,  clrNONE);
   }

   IndicatorShortName("MACD Candles Strength + EMAs");
   return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, InpPrefix);

   // restore the original chart colors
   if(g_colorsSaved)
   {
      ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, g_bull);
      ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, g_bear);
      ChartSetInteger(0, CHART_COLOR_CHART_UP,    g_chartUp);
      ChartSetInteger(0, CHART_COLOR_CHART_DOWN,  g_chartDown);
   }
   ChartRedraw();
}

//+------------------------------------------------------------------+
//| Draws (or updates) one candle with chart objects:                |
//| a trend line for the wick and a filled rectangle for the body.   |
//+------------------------------------------------------------------+
void DrawCandle(const int i, const int colIdx)
{
   color    clr  = g_colors[colIdx];
   datetime t    = Time[i];
   int      off  = (int)(PeriodSeconds() * 0.35);
   datetime t1   = t - off;
   datetime t2   = t + off;
   double   o    = Open[i];
   double   c    = Close[i];
   if(MathAbs(o - c) < Point)
      c = o + Point;                       // keep dojis visible

   string nameW = InpPrefix + "W" + IntegerToString((long)t);
   string nameB = InpPrefix + "B" + IntegerToString((long)t);

   //--- wick
   if(ObjectFind(0, nameW) < 0)
   {
      ObjectCreate(0, nameW, OBJ_TREND, 0, t, Low[i], t, High[i]);
      ObjectSetInteger(0, nameW, OBJPROP_RAY_RIGHT, false);
      ObjectSetInteger(0, nameW, OBJPROP_WIDTH, 1);
      ObjectSetInteger(0, nameW, OBJPROP_BACK, true);
      ObjectSetInteger(0, nameW, OBJPROP_SELECTABLE, false);
      ObjectSetInteger(0, nameW, OBJPROP_HIDDEN, true);
   }
   else
   {
      ObjectSetDouble(0, nameW, OBJPROP_PRICE1, Low[i]);
      ObjectSetDouble(0, nameW, OBJPROP_PRICE2, High[i]);
   }
   ObjectSetInteger(0, nameW, OBJPROP_COLOR, clr);

   //--- body
   if(ObjectFind(0, nameB) < 0)
   {
      ObjectCreate(0, nameB, OBJ_RECTANGLE, 0, t1, o, t2, c);
      ObjectSetInteger(0, nameB, OBJPROP_BACK, true);
      ObjectSetInteger(0, nameB, OBJPROP_FILL, true);
      ObjectSetInteger(0, nameB, OBJPROP_SELECTABLE, false);
      ObjectSetInteger(0, nameB, OBJPROP_HIDDEN, true);
   }
   else
   {
      ObjectSetDouble(0, nameB, OBJPROP_PRICE1, o);
      ObjectSetDouble(0, nameB, OBJPROP_PRICE2, c);
   }
   ObjectSetInteger(0, nameB, OBJPROP_COLOR, clr);
}

//+------------------------------------------------------------------+
int start()
{
   int minBars = MathMax(InpSlowEMA + InpSignalSMA, InpEMASlow) + InpATRPeriod + 2;
   if(Bars < minBars)
      return 0;

   int counted = IndicatorCounted();
   if(counted > 0) counted--;
   int limit = Bars - counted - 1;
   if(limit > InpMaxBars) limit = InpMaxBars;
   if(limit > Bars - 2)   limit = Bars - 2;   // we need bar i+1 as the previous one

   for(int i = limit; i >= 0; i--)
   {
      BufBuy[i]  = EMPTY_VALUE;
      BufSell[i] = EMPTY_VALUE;

      double hist     = iMACD(NULL, 0, InpFastEMA, InpSlowEMA, InpSignalSMA, PRICE_CLOSE, MODE_MAIN, i)
                      - iMACD(NULL, 0, InpFastEMA, InpSlowEMA, InpSignalSMA, PRICE_CLOSE, MODE_SIGNAL, i);
      double histPrev = iMACD(NULL, 0, InpFastEMA, InpSlowEMA, InpSignalSMA, PRICE_CLOSE, MODE_MAIN, i + 1)
                      - iMACD(NULL, 0, InpFastEMA, InpSlowEMA, InpSignalSMA, PRICE_CLOSE, MODE_SIGNAL, i + 1);
      double atr      = iATR(NULL, 0, InpATRPeriod, i);
      double emaF     = iMA(NULL, 0, InpEMAFast, 0, MODE_EMA, PRICE_CLOSE, i);
      double emaS     = iMA(NULL, 0, InpEMASlow, 0, MODE_EMA, PRICE_CLOSE, i);
      double emaFp    = iMA(NULL, 0, InpEMAFast, 0, MODE_EMA, PRICE_CLOSE, i + 1);
      double emaSp    = iMA(NULL, 0, InpEMASlow, 0, MODE_EMA, PRICE_CLOSE, i + 1);

      BufEmaF[i] = emaF;
      BufEmaS[i] = emaS;

      if(atr <= 0.0 || !MathIsValidNumber(hist) || !MathIsValidNumber(histPrev) ||
         !MathIsValidNumber(emaF) || !MathIsValidNumber(emaS))
      {
         DrawCandle(i, 2);
         continue;
      }

      //--- EMA crossovers
      bool crossUp   = (emaF > emaS && emaFp <= emaSp);
      bool crossDown = (emaF < emaS && emaFp >= emaSp);
      if(crossUp)   BufBuy[i]  = Low[i]  - atr * 0.5;
      if(crossDown) BufSell[i] = High[i] + atr * 0.5;

      //--- MACD strength and EMA distance (both normalized by ATR)
      double strength = MathAbs(hist) / atr;
      double emaDist  = MathAbs(emaF - emaS) / atr;
      bool   emaBull  = (emaF > emaS);
      bool   emaBear  = (emaF < emaS);

      //--- FLAT: no momentum, or EMAs squeezed together (if the filter is on)
      bool flat = (strength < InpFlatThreshold);
      if(InpUseEMAFilter && emaDist < InpEMAFlatDist && strength < InpStrongThreshold)
         flat = true;

      int col;
      if(flat)
      {
         col = 2;                                           // FLAT
      }
      else if(hist > 0.0)
      {
         bool strong = (strength >= InpStrongThreshold && hist >= histPrev);
         if(InpUseEMAFilter && !emaBull) strong = false;    // EMAs must confirm
         col = strong ? 0 : 1;                              // strong up / weak up
      }
      else
      {
         bool strong = (strength >= InpStrongThreshold && hist <= histPrev);
         if(InpUseEMAFilter && !emaBear) strong = false;    // EMAs must confirm
         col = strong ? 4 : 3;                              // strong down / weak down
      }
      DrawCandle(i, col);
   }

   return 0;
}
//+------------------------------------------------------------------+
