//+------------------------------------------------------------------+
//|                                                    WeisWave3.mq4 |
//|         This code comes as is and carries NO WARRANTY whatsoever |
//|                                            Use at your own risk! |
//+------------------------------------------------------------------+
#property strict
#property indicator_separate_window
#property indicator_minimum 0
#property indicator_buffers 2
#property indicator_plots   2
//--- plot upVolume
#property indicator_label1  "upVolume"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrDarkGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2
//--- plot dnVolume
#property indicator_label2  "dnVolume"
#property indicator_type2   DRAW_HISTOGRAM
#property indicator_color2  clrFireBrick
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2
//--- input parameters
input int      Difference = 300;
input int      LabelShift = 250;

//--- indicator buffers
double         upVolumeBuffer[];
double         dnVolumeBuffer[];
double         barDirection[];
double         trendDirection[];
double         waveDirection[];
long           volumeTracker = 0;

double         trendDifference = EMPTY_VALUE;
double         waveDifference = EMPTY_VALUE;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   IndicatorBuffers(5);

   SetIndexBuffer(0, upVolumeBuffer);
   SetIndexBuffer(1, dnVolumeBuffer);
   SetIndexBuffer(2, barDirection);
   SetIndexBuffer(3, trendDirection);
   SetIndexBuffer(4, waveDirection);
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
   for(int i = ObjectsTotal() - 1; i >= 0; i--)
     {
      string Label = ObjectName(i);
      ObjectDelete(Label);
     }

   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration 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[])
  {
//---
   // Only compute bars on new bar
   if (rates_total == prev_calculated) return(rates_total);

   int limit = rates_total - 1;

   int  waveChangeBar = limit - 1;
   bool needWaveStart = true;

   // Initialise values
   if (trendDifference == EMPTY_VALUE) trendDifference =0;
   if (waveDifference == EMPTY_VALUE) waveDifference = 0;

   string waveID = TimeToString(time[waveChangeBar], TIME_DATE|TIME_MINUTES) + "-TL";
   ObjectCreate(0, waveID, OBJ_TREND, 0, time[waveChangeBar], close[waveChangeBar], time[waveChangeBar], close[waveChangeBar]);
   ObjectSet(waveID, OBJPROP_RAY, false);
   ObjectSet(waveID, OBJPROP_WIDTH, 2);
   double shift = LabelShift / MathPow(10, Digits);
printf(shift);
   for(int i=limit-1; i>=0; i--) {
      // Determine this bar's direction
      if (close[i] - close[i+1] >  0) barDirection[i] =  1;    // current close higher
      if (close[i] - close[i+1] == 0) barDirection[i] =  0;    // current close equal
      if (close[i] - close[i+1] <  0) barDirection[i] = -1;    // current close lower

      if (barDirection[limit]   == EMPTY_VALUE) barDirection[limit]   = barDirection[i];
      if (trendDirection[limit] == EMPTY_VALUE) trendDirection[limit] = barDirection[i];
      if (waveDirection[limit]  == EMPTY_VALUE) waveDirection[limit]  = barDirection[i];

      // Determine if this bar has started a new trend
      if ((barDirection[i] != 0) && (barDirection[i] != barDirection[i+1]))
            trendDirection[i] = barDirection[i];
      else  trendDirection[i] = trendDirection[i+1];

      double barDifference = (close[i] - close[i+1]) * MathPow(10, Digits);
      trendDifference += barDifference;
      if (waveDirection[i+1] == 1) {
         if (trendDifference > waveDifference) {
            waveDifference += barDifference;
            needWaveStart = true;
         }
         else {
            if(needWaveStart) {
               waveChangeBar = i+1;
               needWaveStart = false;
            }
         }
      }
      else {
         if (trendDifference < waveDifference) {
            waveDifference += barDifference;
            needWaveStart = true;
         }
         else {
            if(needWaveStart) {
               waveChangeBar = i+1;
               needWaveStart = false;
            }
         }
      }

      // Determine if we have started a new wave
      double trendWaveDiff = MathAbs(trendDifference - waveDifference);
      if ((trendDifference != waveDifference) && (trendWaveDiff >= Difference)) {
         waveDirection[i] = trendDirection[i];
         if (waveDirection[i] == 1) {
            trendDifference = trendWaveDiff;
            waveDifference = trendWaveDiff;
         }
         else {
            trendDifference = -trendWaveDiff;
            waveDifference = -trendWaveDiff;
         }

         ObjectSet(waveID, OBJPROP_PRICE2, close[waveChangeBar]);
         ObjectSet(waveID, OBJPROP_TIME2, time[waveChangeBar]);
         waveID = TimeToString(time[waveChangeBar], TIME_DATE|TIME_MINUTES) + "-TL";
         ObjectCreate(0, waveID, OBJ_TREND, 0, time[waveChangeBar], close[waveChangeBar], time[i], close[i]);
         ObjectSet(waveID, OBJPROP_RAY, false);
         ObjectSet(waveID, OBJPROP_WIDTH, 2);

         string volLabel = TimeToString(time[waveChangeBar], TIME_DATE|TIME_MINUTES) + "-VOL";
         if (waveDirection[i] == 1) {
            ObjectCreate(0, volLabel, OBJ_TEXT, 0, time[waveChangeBar], low[waveChangeBar]-shift);
            ObjectSet(volLabel, OBJPROP_ANGLE, -90);
            ObjectSet(volLabel, OBJPROP_ANCHOR, ANCHOR_LEFT);
            ObjectSetText(volLabel, DoubleToString(dnVolumeBuffer[waveChangeBar], 0), 8, NULL, clrFireBrick);
         }
         else{
            ObjectCreate(0, volLabel, OBJ_TEXT, 0, time[waveChangeBar], high[waveChangeBar]+shift);
            ObjectSet(volLabel, OBJPROP_ANGLE, 90);
            ObjectSet(volLabel, OBJPROP_ANCHOR, ANCHOR_LEFT);
            ObjectSetText(volLabel, DoubleToString(upVolumeBuffer[waveChangeBar], 0), 8, NULL, clrDarkGreen);
         }

         needWaveStart = true;
      }
      else {
         waveDirection[i] = waveDirection[i+1];
         if (trendDirection[i] == waveDirection[i]) {
            trendDifference = waveDifference;
         }
      }

      // Add the volume of this bar to the wave, or start again
      if (waveDirection[i] == waveDirection[i+1]) {
         volumeTracker += tick_volume[i];
      }
      else {
         volumeTracker = 0;
         for (int k=waveChangeBar-1; k>=i; k--) {
            volumeTracker += tick_volume[k];
            if (waveDirection[i] ==  1) {
               upVolumeBuffer[k] = volumeTracker;
               dnVolumeBuffer[k] = 0;
            }
            if (waveDirection[i] == -1) {
               upVolumeBuffer[k] = 0;
               dnVolumeBuffer[k] = volumeTracker;
            }
         }
      }

      // Set the indicators
      if (waveDirection[i] ==  1) {
         upVolumeBuffer[i] = volumeTracker;
         dnVolumeBuffer[i] = 0;
      }
      if (waveDirection[i] == -1) {
         upVolumeBuffer[i] = 0;
         dnVolumeBuffer[i] = volumeTracker;
      }
   }

   ObjectSet(waveID, OBJPROP_PRICE2, close[0]);
   ObjectSet(waveID, OBJPROP_TIME2, time[0]);

//--- return value of prev_calculated for next call
   return(rates_total);
  }

string StringPadLeft (string inStr, ushort padStr, int totalStrLen) {
   string result;
   StringInit(result, totalStrLen, padStr);
   result = StringConcatenate(result, inStr);
   
   int pos = StringLen(inStr);
   
   return StringSubstr(result, pos, totalStrLen);
}
//+------------------------------------------------------------------+
