//+------------------------------------------------------------------+
//|                                             MACD tape on chart.mq5 |
//|                                                 Copyright mladen |
//|                                               mladenfx@gmail.com |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"
#property version   "1.00"

#property indicator_chart_window
#property indicator_buffers 9
#property indicator_plots   4

// Plot 1: MACD tape (Ribbon Filling)
#property indicator_label1  "MACD tape"
#property indicator_type1   DRAW_FILLING
#property indicator_color1  Green,Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

// Plot 2: Fast EMA
#property indicator_label2  "Fast EMA"
#property indicator_type2   DRAW_LINE
#property indicator_color2  DarkCyan
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

// Plot 3: Signal
#property indicator_label3  "Signal"
#property indicator_type3   DRAW_LINE
#property indicator_color3  Magenta
#property indicator_style3  STYLE_DOT
#property indicator_width3  1

// Plot 4: Slow EMA
#property indicator_label4  "Slow EMA"
#property indicator_type4   DRAW_LINE
#property indicator_color4  Orange
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1

// Inputs
input ENUM_TIMEFRAMES    Timeframe = PERIOD_CURRENT; // Timeframe
input int                FastEMA   = 12;             // MACD fast EMA period
input int                SlowEMA   = 26;             // MACD slow EMA period
input int                SignalEMA =  9;             // Signal EMA period
input ENUM_APPLIED_PRICE Price     = PRICE_CLOSE;    // Applied price

// Buffers
double fastMABuf[];        // Plot 1 element 1
double signalMABuf[];      // Plot 1 element 2
double fastMABufLine[];    // Plot 2
double signalMABufLine[];  // Plot 3
double slowMABufLine[];    // Plot 4
double fastMAcalc[];       // Calculation Buffer
double slowMAcalc[];       // Calculation Buffer
double macd[];             // Calculation Buffer
double signal[];           // Calculation Buffer

int FastMaHandle;
int SlowMaHandle;
ENUM_TIMEFRAMES TF; // resolved timeframe (never PERIOD_CURRENT)

//+------------------------------------------------------------------+
//| OnInit                                                           |
//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0,fastMABuf      ,INDICATOR_DATA);         ArraySetAsSeries(fastMABuf      ,true);
   SetIndexBuffer(1,signalMABuf    ,INDICATOR_DATA);         ArraySetAsSeries(signalMABuf    ,true);
   SetIndexBuffer(2,fastMABufLine  ,INDICATOR_DATA);         ArraySetAsSeries(fastMABufLine  ,true);
   SetIndexBuffer(3,signalMABufLine,INDICATOR_DATA);         ArraySetAsSeries(signalMABufLine,true);
   SetIndexBuffer(4,slowMABufLine  ,INDICATOR_DATA);         ArraySetAsSeries(slowMABufLine  ,true);
   SetIndexBuffer(5,fastMAcalc     ,INDICATOR_CALCULATIONS); ArraySetAsSeries(fastMAcalc     ,true);
   SetIndexBuffer(6,slowMAcalc     ,INDICATOR_CALCULATIONS); ArraySetAsSeries(slowMAcalc     ,true);
   SetIndexBuffer(7,macd           ,INDICATOR_CALCULATIONS); ArraySetAsSeries(macd           ,true);
   SetIndexBuffer(8,signal         ,INDICATOR_CALCULATIONS); ArraySetAsSeries(signal         ,true);

   // Resolve PERIOD_CURRENT so iBarShift works correctly in MTF mode
   TF = (Timeframe == PERIOD_CURRENT) ? (ENUM_TIMEFRAMES)Period() : Timeframe;

   string tfName = EnumToString(TF);
   IndicatorSetString(INDICATOR_SHORTNAME,"MACD tape on chart ("+(string)FastEMA+","+(string)SlowEMA+","+(string)SignalEMA+") ["+tfName+"]");
   
   FastMaHandle=iMA(NULL,TF,FastEMA,0,MODE_EMA,Price);
   SlowMaHandle=iMA(NULL,TF,SlowEMA,0,MODE_EMA,Price);
   
   if(FastMaHandle == INVALID_HANDLE || SlowMaHandle == INVALID_HANDLE)
   {
      Print("Error creating indicator handles");
      return(INIT_FAILED);
   }
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| OnDeinit                                                         |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   IndicatorRelease(FastMaHandle);
   IndicatorRelease(SlowMaHandle);
}

//+------------------------------------------------------------------+
//| OnCalculate                                                      |
//+------------------------------------------------------------------+
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 < SlowEMA) return(0);

   // --- Step 1: Get the number of bars calculated on the HTF ---
   int htfBars = BarsCalculated(FastMaHandle);
   if (htfBars <= SlowEMA)
   {
      Print("HTF fast MA not ready yet (",htfBars," bars)");
      return(0);
   }
   htfBars = MathMin(htfBars, BarsCalculated(SlowMaHandle));
   if (htfBars <= SlowEMA)
   {
      Print("HTF slow MA not ready yet (",htfBars," bars)");
      return(0);
   }

   // --- Step 2: Copy ALL available HTF MA values ---
   if (CopyBuffer(FastMaHandle, 0, 0, htfBars, fastMAcalc) <= 0)
   {
      Print("CopyBuffer fast MA failed. Error ", GetLastError());
      return(0);
   }
   if (CopyBuffer(SlowMaHandle, 0, 0, htfBars, slowMAcalc) <= 0)
   {
      Print("CopyBuffer slow MA failed. Error ", GetLastError());
      return(0);
   }

   // --- Step 3: Compute MACD and Signal over all HTF bars ---
   //   fastMAcalc / slowMAcalc are indexed as series (newest = index 0)
   //   We need a persistent signal array sized to HTF bars.
   //   Re-use the signal[] calc buffer but work over htfBars.
   double alpha = 2.0 / (1.0 + SignalEMA);

   // Seed oldest signal value
   int htfLimit = htfBars - 1;
   signal[htfLimit] = fastMAcalc[htfLimit] - slowMAcalc[htfLimit]; // seed = first macd
   for (int i = htfLimit - 1; i >= 0; i--)
   {
      macd[i]   = fastMAcalc[i] - slowMAcalc[i];
      signal[i] = signal[i+1] + alpha * (macd[i] - signal[i+1]);
   }

   // --- Step 4: Map HTF values onto every chart bar via iBarShift ---
   //   For each chart bar find which HTF bar it belongs to,
   //   then stamp that HTF bar's fast/slow/signal value.
   int limit = (prev_calculated > 0) ? rates_total - prev_calculated + 1 : rates_total;

   for (int i = limit - 1; i >= 0; i--)
   {
      // Get the open time of this chart bar
      datetime barTime = time[rates_total - 1 - i]; // time[] is NOT set as series

      // Find corresponding HTF bar (exact=false => use nearest)
      int htfIdx = iBarShift(NULL, TF, barTime, false);
      if (htfIdx < 0 || htfIdx >= htfBars) continue;

      double fastVal = fastMAcalc[htfIdx];
      double slowVal = slowMAcalc[htfIdx];
      double sigVal  = signal[htfIdx];

      // Plot buffers (as-series: index 0 = newest chart bar)
      fastMABuf[i]       = fastVal;
      signalMABuf[i]     = slowVal + sigVal;
      fastMABufLine[i]   = fastVal;
      signalMABufLine[i] = slowVal + sigVal;
      slowMABufLine[i]   = slowVal;
   }

   return(rates_total);
}

//+------------------------------------------------------------------+
//| checkCalculated  (kept for potential reuse)                      |
//+------------------------------------------------------------------+
bool checkCalculated(int bufferHandle, int minBars, string checkDescription)
{
   int calculated = BarsCalculated(bufferHandle);
   if (calculated < minBars)
   {
      Print("Not enough data for "+checkDescription+" (",calculated," bars). Error ",GetLastError());
      return(false);
   }
   return(true);
}

//+------------------------------------------------------------------+
//| doCopy  (kept for potential reuse)                               |
//+------------------------------------------------------------------+
bool doCopy(int bufferHandle, double& buffer[], const int buffNum, const int copyCount, string copyDescription)
{
   if(CopyBuffer(bufferHandle,buffNum,0,copyCount,buffer)<=0)
   {
      Print("Getting "+copyDescription+" failed! Error",GetLastError());
      return(false);
   }
   return(true);
}
