#property copyright "Darwinex & Trade Like A Machine Ltd"
#property link      "http://www.darwinex.com"
#property strict

//Indicator settings
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_HISTOGRAM
#property indicator_color1  clrGreen, clrOrange, clrRed
#property indicator_style1  0
#property indicator_width1  3

//Level of above average (1.25) and below average (0.8) volume (for time of day) - (ratio of 1.0 indicates current volume is the same as average)
#property indicator_level1 1.25 //Above Average Volume Level
#property indicator_level2 0.8  //Below Average Volume Level

//Input Parmans
input int                 InpAveragingDays  =  5;               //Number of Days for Comparison 
input ENUM_APPLIED_VOLUME InpVolumeType     =  VOLUME_TICK;     //Volume Type

//Indicator Buffers
double ExtRelVolumesBuffer[];
double ExtColorsBuffer[];
int    BarsIn24Hours = 0;
int    AveragingDays;

void OnInit()
{
   //Set Buffers
   SetIndexBuffer(0,ExtRelVolumesBuffer, INDICATOR_DATA);
   SetIndexBuffer(1,ExtColorsBuffer, INDICATOR_COLOR_INDEX);
   
   //Define how many bars required to begin drawing 
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 100);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, 100);

   //Set indicator digits
   IndicatorSetInteger(INDICATOR_DIGITS, 2);
   
   //Ensure valid InpAveragingDays
   if(InpAveragingDays >= 1)
      AveragingDays = InpAveragingDays;
   else 
      AveragingDays = 5;
      
   //Set name of indicator
   string short_name = StringFormat("RVOL (Relative Volume) (%d)", AveragingDays);
   IndicatorSetString(INDICATOR_SHORTNAME, short_name);
   
   //Mean Level
   IndicatorSetInteger(INDICATOR_LEVELCOLOR, 0, clrWhite);
   IndicatorSetString(INDICATOR_LEVELTEXT, 0, "Above Average Volume");   
   IndicatorSetInteger(INDICATOR_LEVELCOLOR, 1, clrWhite);
   IndicatorSetString(INDICATOR_LEVELTEXT, 1, "Below Average Volume");   
}

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[])
{
   //rates_total is the number of bars available for calculations
   if(rates_total < 1)
      return(0);
   
   if(BarsIn24Hours == 0) //Set to 0 by default above
   {
      SetBarsIn24Hours();
      if(BarsIn24Hours == 0) //Bars not yet available in chart for calculation to succeed
         return(0);
   }
   //Set starting point for the processing
   int startBar = prev_calculated - 1;

   //Adjust Start position
   if(startBar < 1)
   {
      ExtRelVolumesBuffer[0] = 0;
      startBar = 1;
   }
     
   //Main cycle
   if(InpVolumeType==VOLUME_TICK)
      CalculateRelVolume(startBar, rates_total, tick_volume);
   else
      CalculateRelVolume(startBar, rates_total, volume);

   //OnCalculate done. Return new prev_calculated.
   return(rates_total);
}

void CalculateRelVolume(const int startBar, const int rates_total, const long& volume[])
{
   ExtRelVolumesBuffer[0] = (double)volume[0];
   ExtColorsBuffer[0] = 0.0;
   
   for(int i = startBar; i < rates_total && !IsStopped(); i++)
   {
      if(i > AveragingDays * BarsIn24Hours)
      {
         double curr_volume = (double)volume[i];
         
         double mean_volume = 0.0;
         
         for(int j = 1; j <= AveragingDays; j++)
            mean_volume += (double)volume[i - (j * BarsIn24Hours)];  
            
         mean_volume /= (double)AveragingDays;
         
         ExtRelVolumesBuffer[i] = curr_volume / mean_volume;   //N.B. Value of 1.0 represents current vol is equal to average volume, 0.0-1.0 is below average, >1.0 is above average
         
         if(ExtRelVolumesBuffer[i] > indicator_level1)         //If current vol higher than average     
            ExtColorsBuffer[i] = 0.0;
         else if (ExtRelVolumesBuffer[i] > indicator_level2)   //If current vol lower than average     
            ExtColorsBuffer[i] = 1.0;
         else 
            ExtColorsBuffer[i] = 2.0;
      }
      else
      {
         ExtRelVolumesBuffer[i] = 0.0;
         ExtColorsBuffer[i] = 0.0;
      }
   }
}

int SetBarsIn24Hours()
{
   datetime prevDateTime = iTime(NULL, PERIOD_CURRENT, 0) - (86400 * 7); //Need to base calculation on 7 days so that weekends don't interfere 
   
   int numBarsIn7Days = iBarShift(NULL, PERIOD_CURRENT, prevDateTime, false);
   
   //Num bars in 7 days actually represents 5 trading days. N.B. This Indicator only works for assets that trade 5 days per week. It will not work with 24x7 Crypto for example
   BarsIn24Hours = numBarsIn7Days / 5; 
      
   return BarsIn24Hours;
}