//+------------------------------------------------------------------+
//|                                                 volumes-alert.mq5 |
//|  Plots tick volume as a histogram in a separate window and alerts |
//|  when the current bar's volume spikes above a multiple of its own |
//|  recent average.                                                  |
//|  Source: web-forex (educational, free to use and modify)          |
//+------------------------------------------------------------------+
#property copyright "web-forex"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrDodgerBlue
#property indicator_label1  "Volume"

input ENUM_APPLIED_VOLUME AppliedVolume  = VOLUME_TICK;
input int                 AveragePeriod  = 20;
input double               SpikeMultiplier = 2.0;
input bool                EnableAlert    = true;
input bool                EnablePush     = false;

double VolumeBuffer[];

int volumeHandle = INVALID_HANDLE;
int lastSignal = 0; // 0 = none, 1 = spike alerted on this bar

int OnInit()
{
   SetIndexBuffer(0, VolumeBuffer, INDICATOR_DATA);
   ArraySetAsSeries(VolumeBuffer, true);

   volumeHandle = iVolumes(_Symbol, _Period, AppliedVolume);

   IndicatorSetString(INDICATOR_SHORTNAME, "Volumes Alert");
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
   IndicatorRelease(volumeHandle);
}

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 (BarsCalculated(volumeHandle) < rates_total)
      return(0);

   CopyBuffer(volumeHandle, 0, 0, rates_total, VolumeBuffer);

   CheckSpikeSignal();
   return(rates_total);
}

double CalcVolumeSma(int startShift, int period)
{
   double arr[];
   ArraySetAsSeries(arr, true);
   if (CopyBuffer(volumeHandle, 0, startShift, period, arr) < period)
      return(0);

   double sum = 0;
   for (int i = 0; i < period; i++)
      sum += arr[i];
   return(sum / period);
}

void CheckSpikeSignal()
{
   if (!EnableAlert && !EnablePush)
      return;

   double volArr[];
   ArraySetAsSeries(volArr, true);
   if (CopyBuffer(volumeHandle, 0, 1, 1, volArr) < 1) return;

   double volLast = volArr[0];
   double avgVol   = CalcVolumeSma(2, AveragePeriod);

   int signal = (avgVol > 0 && volLast > avgVol * SpikeMultiplier) ? 1 : 0;

   if (signal == 1 && lastSignal != 1)
   {
      string msg = _Symbol + " " + EnumToString((ENUM_TIMEFRAMES)_Period) +
                   ": Volume spike, " + DoubleToString(volLast / avgVol, 1) + "x average";
      if (EnableAlert)
         Alert(msg);
      if (EnablePush)
         SendNotification(msg);
   }
   lastSignal = signal;
}
