//+------------------------------------------------------------------+ 
//|          PTR777 Wavelet Bands with MTF                           |
//+------------------------------------------------------------------+
#property version   "1.0"
#property strict

#property indicator_chart_window
#property indicator_buffers 5
#property indicator_color1 Lime          // Trend Up
#property indicator_color2 Red           // Trend Down
#property indicator_color3 DodgerBlue    // Upper Band
#property indicator_color4 DarkOrange    // Lower Band
#property indicator_color5 clrNONE
#property indicator_width1 2
#property indicator_width2 2
#property indicator_width3 1
#property indicator_width4 1

//--- inputs
input int FastMAPeriod = 13;
input int SlowMAPeriod = 34;
input double BandMultiplier = 2.0;
input ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT;  // MTF setting
input bool ShowOuterBands = false;                  // Show upper/lower bands

//--- buffers
double TrendUp[];
double TrendDown[];
double UpperBand[];
double LowerBand[];
double TrendRaw[]; // used for logic only

//+------------------------------------------------------------------+
//| Initialization                                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   IndicatorShortName("Wavelet Bands MTF (" + string(TimeFrame) + ")");

   //--- buffers
   SetIndexBuffer(0, TrendUp);
   SetIndexStyle(0, DRAW_LINE);
   SetIndexLabel(0, "Trend Up");

   SetIndexBuffer(1, TrendDown);
   SetIndexStyle(1, DRAW_LINE);
   SetIndexLabel(1, "Trend Down");

   SetIndexBuffer(2, UpperBand);
   SetIndexStyle(2, DRAW_LINE);
   SetIndexLabel(2, "Upper Band");

   SetIndexBuffer(3, LowerBand);
   SetIndexStyle(3, DRAW_LINE);
   SetIndexLabel(3, "Lower Band");

   SetIndexBuffer(4, TrendRaw); // invisible buffer

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom MTF functions                                             |
//+------------------------------------------------------------------+
double iMAOnArray(double &array[], int total, int ma_period, int ma_shift, int ma_method, int shift)
{
   double buf[], arr[];
   if(total == 0) total = ArraySize(array);
   if(total > 0 && total <= ma_period) return(0);
   
   if(ArrayResize(buf, total) < 0) return(0);
   
   for(int i = 0; i < total; i++)
      arr[i] = array[total-1-i];
   
   return(iMAOnArray(arr, 0, ma_period, ma_shift, ma_method, shift));
}

//+------------------------------------------------------------------+
//| Main Calculation 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(TimeFrame == PERIOD_CURRENT)
   {
      return CalculateCurrentTimeframe(rates_total, prev_calculated, close);
   }
   else
   {
      return CalculateMultiTimeframe(rates_total, prev_calculated, time, close);
   }
}

//+------------------------------------------------------------------+
//| Calculation for current timeframe                                |
//+------------------------------------------------------------------+
int CalculateCurrentTimeframe(const int rates_total,
                             const int prev_calculated,
                             const double &close[])
{
   int limit = rates_total - prev_calculated;
   if(prev_calculated > 0) limit++;

   for(int i = limit - 1; i >= 0; i--)
   {
      double fastMA = iMA(NULL, 0, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE, i);
      double slowMA = iMA(NULL, 0, SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE, i);

      double waveletDetail = fastMA - slowMA;
      double trend = slowMA;

      TrendRaw[i] = trend;

      if (ShowOuterBands)
      {
         UpperBand[i] = trend + BandMultiplier * MathAbs(waveletDetail);
         LowerBand[i] = trend - BandMultiplier * MathAbs(waveletDetail);
      }
      else
      {
         UpperBand[i] = EMPTY_VALUE;
         LowerBand[i] = EMPTY_VALUE;
      }

      // Trend direction check
      if(i < rates_total - 1)
      {
         if(TrendRaw[i] > TrendRaw[i + 1])
         {
            TrendUp[i] = trend;
            TrendDown[i] = EMPTY_VALUE;
         }
         else if(TrendRaw[i] < TrendRaw[i + 1])
         {
            TrendUp[i] = EMPTY_VALUE;
            TrendDown[i] = trend;
         }
         else
         {
            TrendUp[i] = TrendUp[i + 1];
            TrendDown[i] = TrendDown[i + 1];
         }
      }
      else
      {
         TrendUp[i] = trend;
         TrendDown[i] = EMPTY_VALUE;
      }
   }

   return(rates_total);
}

//+------------------------------------------------------------------+
//| Calculation for multi-timeframe                                  |
//+------------------------------------------------------------------+
int CalculateMultiTimeframe(const int rates_total,
                           const int prev_calculated,
                           const datetime &time[],
                           const double &close[])
{
   datetime timeArray[];
   double closeArray[];
   
   ArraySetAsSeries(timeArray, true);
   ArraySetAsSeries(closeArray, true);
   
   int copied = CopyClose(NULL, TimeFrame, 0, rates_total, closeArray);
   if(copied <= 0) return(prev_calculated);
   
   copied = CopyTime(NULL, TimeFrame, 0, rates_total, timeArray);
   if(copied <= 0) return(prev_calculated);
   
   double htTrendRaw[], htUpperBand[], htLowerBand[];
   ArrayResize(htTrendRaw, copied);
   ArrayResize(htUpperBand, copied);
   ArrayResize(htLowerBand, copied);
   
   for(int i = 0; i < copied; i++)
   {
      double fastMA = iMA(NULL, TimeFrame, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE, i);
      double slowMA = iMA(NULL, TimeFrame, SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE, i);
      
      double waveletDetail = fastMA - slowMA;
      htTrendRaw[i] = slowMA;
      htUpperBand[i] = htTrendRaw[i] + BandMultiplier * MathAbs(waveletDetail);
      htLowerBand[i] = htTrendRaw[i] - BandMultiplier * MathAbs(waveletDetail);
   }
   
   for(int i = 0; i < rates_total && !IsStopped(); i++)
   {
      int htIndex = iBarShift(NULL, TimeFrame, time[i]);
      if(htIndex >= 0 && htIndex < copied)
      {
         TrendRaw[i] = htTrendRaw[htIndex];

         if (ShowOuterBands)
         {
            UpperBand[i] = htUpperBand[htIndex];
            LowerBand[i] = htLowerBand[htIndex];
         }
         else
         {
            UpperBand[i] = EMPTY_VALUE;
            LowerBand[i] = EMPTY_VALUE;
         }

         if(i > 0 && htIndex < copied - 1)
         {
            if(htTrendRaw[htIndex] > htTrendRaw[htIndex + 1])
            {
               TrendUp[i] = htTrendRaw[htIndex];
               TrendDown[i] = EMPTY_VALUE;
            }
            else if(htTrendRaw[htIndex] < htTrendRaw[htIndex + 1])
            {
               TrendUp[i] = EMPTY_VALUE;
               TrendDown[i] = htTrendRaw[htIndex];
            }
            else
            {
               TrendUp[i] = TrendUp[i - 1];
               TrendDown[i] = TrendDown[i - 1];
            }
         }
         else
         {
            TrendUp[i] = htTrendRaw[htIndex];
            TrendDown[i] = EMPTY_VALUE;
         }
      }
      else
      {
         TrendRaw[i] = EMPTY_VALUE;
         UpperBand[i] = EMPTY_VALUE;
         LowerBand[i] = EMPTY_VALUE;
         TrendUp[i] = EMPTY_VALUE;
         TrendDown[i] = EMPTY_VALUE;
      }
   }

   return(rates_total);
}
