//+------------------------------------------------------------------+
//|                                                      RedK EVEREX |
//|           Converted from https://www.tradingview.com/v/I5qJDPxT/ |
//+------------------------------------------------------------------+
#property indicator_separate_window
#property indicator_buffers 7
#property strict

/*
User Notes:
--------------------------

RedK EVEREX is an experimental indicator that explores "Volume Price Analysis"
basic concepts and Wyckoff law "Effort versus Result" - by inspecting the
relative volume (effort) and the associated (relative) price action (result) for
each bar - showing the analysis as an easy to read "stacked bands" visual. From
that analysis, we calculate a "Relative Rate of Flow" (RROF) - an easy to use
+100/-100 oscilator that can be used to trigger a signal when a bullish or
bearish mode is detected for a certain user-selected length of bars.

What is RROF?
--------------------------

* Once we have the values of relative volume and relative price strength, it's
  easy from there to combine these values into a moving index that can be used
  to track overall strength and detect reversals in market direction - if you
  think about it this a very similar concept to a volume-weighted RSI. I call
  that index the "Relative Rate of Flow" - or RROF (cause we're not using the
  direct volume and price values in the calculation, but rather relative values
  that we calculated with the proprietary "Normalize" function in the script.

* You can show RROF as a single or longer double-period strength indicator by
  setting the "Show Bias" option to true) - and you can customize it in terms of
  smoothing, and signal line.

* Once you attach RROF to a chart, you will see how the RROF is able to detect
  change in market condition from Bearsh to Bullish - then from Bullish to
  Bearish with good accuracy.

* RROF is a "strength indicator" - it does not track price values (levels) or
  momentum - as you will see when you use it, the price can be moving up, while
  the RROF signal line starts moving down, reflecting decreasing strength (or
  otherwise, increasing bear strength) - So if you incorporate EVEREX in your
  trading you will need to use it alongside other momentum and price value
  indicators (like MACD, MA's, Trend Channels, Support & Resistance Lines, Fib /
  Donchian..etc) - to use for trade confirmation
 */

enum enBsFilter
{
   bf_slope,    //  Filter by Slope
   bf_zero,     //  Filter by Zero Level
   bf_both,     //  Filter by Both
};
//
//

extern int             MaxBars       = 0;             // Maximum Bars, 0=all bars, minimum=500
input int              length        = 10;            // RROF Length
input ENUM_MA_METHOD   MA_Type       = MODE_LWMA;     // RROF MA Type
input int              smooth        = 3;             // RROF Smooth
input int              sig_length    = 5;             // Signal Length
input ENUM_MA_METHOD   S_Type        = MODE_LWMA;     // Signal Type
input int              lookback      = 20;            // Lookback Length
extern bool            lkbk_Calc     = true;          // Lookback MA Type Simple? true=SMA, false=RROF MA Type
//+-----------------------------------------------------------------------------------------------------------+
input ENUM_LINE_STYLE  RROFStyle     = STYLE_SOLID;   // RROF Style
input int              RROFWidth     = 1;             // RROF Width
input color            RROFColor     = clrDodgerBlue; // RROF Color
//+-----------------------------------------------------------------------------------------------------------+
input ENUM_LINE_STYLE  SignalStyle   = STYLE_SOLID;   // Signal Style
input int              SignalWidth   = 1;             // Signal Width
input color            SignalColor   = clrRed;        // Signal Color
//+-----------------------------------------------------------------------------------------------------------+
input bool             showBias      = true;          // Show Bias?
input int              B_Length      = 30;            // Bias Length
input ENUM_MA_METHOD   B_Type        = MODE_LWMA;     // Bias MA Type
input ENUM_LINE_STYLE  BiasStyle     = STYLE_DOT;     // Bias Style
input int              BiasWidth     = 1;             // Bias Width
input color            BiasColor     = clrBeige;      // Bias Color
input bool             UseBiasFilter = true;          // Use Bias Filter?
extern enBsFilter      BsFilterType  = 0;             // Bias Filter Type
//+-----------------------------------------------------------------------------------------------------------+
input bool             showEVEREX    = false;         // Show EVEREX
input int              bandscale     = 100;           // Note: Band scale options ["100", "200", "400"] not directly available in MQL4
//+-----------------------------------------------------------------------------------------------------------+
input bool             ShowVolume    = false;         // Show Volume?
input ENUM_LINE_STYLE  VolumeStyle   = STYLE_DOT;     // Volume Style
input int              VolumeWidth   = 1;             // Volume Width
input color            VolumeColor   = clrMagenta;    // Volume Color
//+-----------------------------------------------------------------------------------------------------------+
input bool             ShowPrice     = false;         // Show Price?
input ENUM_LINE_STYLE  PriceStyle    = STYLE_DOT;     // Price Style
input int              PriceWidth    = 1;             // Price Width
input color            PriceColor    = clrDimGray;    // Price Color
//+-----------------------------------------------------------------------------------------------------------+
input double           Level         = 40.0;          // Level
input ENUM_LINE_STYLE  LevelsStyle   = STYLE_DOT;     // Levels Style
input color            LevelsColor   = clrDimGray;    // Levels Color
//+-----------------------------------------------------------------------------------------------------------+

int lookbackMA;
int maxPeriod;

// double RROFBuffer[];
double RROF_s[];
double SignalBuffer[];
double RROF_b[];
double VolaBuffer[];
double PriceaBuffer[];
double Trend[];
double Bias[];
double Bv[];
double BarSpread_abs[];
double SrcShift_abs[];
double bulls[];
double bears[];
double RROF[];
double RROF_bs[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int init()
{
   IndicatorBuffers(14);
   SetIndexBuffer(0, RROF_s);        SetIndexLabel(0,"RROF Smooth");       SetIndexStyle(0,DRAW_LINE,RROFStyle,RROFWidth,RROFColor);
   SetIndexBuffer(1, SignalBuffer);  SetIndexLabel(1,"Signal Line");       SetIndexStyle(1,DRAW_LINE,SignalStyle,SignalWidth,SignalColor);
   SetIndexBuffer(2, RROF_bs);       SetIndexLabel(2,"RROF Bias");         SetIndexStyle(2,showBias ? DRAW_LINE : DRAW_NONE,BiasStyle,BiasWidth,BiasColor);
   SetIndexBuffer(3, VolaBuffer);    SetIndexLabel(3,"Volume Normalized"); SetIndexStyle(3,ShowVolume ? DRAW_LINE : DRAW_NONE,VolumeStyle,VolumeWidth,VolumeColor);
   SetIndexBuffer(4, PriceaBuffer);  SetIndexLabel(4,"Price Normalized");  SetIndexStyle(4,ShowPrice ? DRAW_LINE : DRAW_NONE,PriceStyle,PriceWidth,PriceColor);
   SetIndexBuffer(5, Trend);         SetIndexLabel(5,"Trend");             SetIndexStyle(5,DRAW_NONE);
   SetIndexBuffer(6, Bias);          SetIndexLabel(6,"Bias");              SetIndexStyle(6,DRAW_NONE);
   SetIndexBuffer(7, Bv);            SetIndexLabel(7,"Bv");                SetIndexStyle(7,DRAW_NONE);
   SetIndexBuffer(8, BarSpread_abs); SetIndexLabel(8,"BarSpread");         SetIndexStyle(8,DRAW_NONE);
   SetIndexBuffer(9, SrcShift_abs);  SetIndexLabel(9,"SrcShift");          SetIndexStyle(9,DRAW_NONE);
   SetIndexBuffer(10, bulls);        SetIndexLabel(10,"bulls");            SetIndexStyle(10,DRAW_NONE);
   SetIndexBuffer(11,bears);         SetIndexLabel(11,"bears");            SetIndexStyle(11,DRAW_NONE);
   SetIndexBuffer(12,RROF);          SetIndexLabel(12,"RROF");             SetIndexStyle(12,DRAW_NONE);
   SetIndexBuffer(13,RROF_b);        SetIndexLabel(13,"RROF_b");           SetIndexStyle(13,DRAW_NONE);

   IndicatorSetInteger(INDICATOR_LEVELS,3);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,LevelsColor);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,LevelsStyle);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,0,0);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,1,Level);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,2,-Level);

   if(lkbk_Calc==true) { lookbackMA=MODE_SMA; }
   else { lookbackMA=MA_Type; }

   maxPeriod=MathMax(length,smooth);
   maxPeriod=MathMax(maxPeriod,sig_length);
   maxPeriod=MathMax(maxPeriod,lookback);
   maxPeriod=MathMax(maxPeriod,B_Length);

   if(MaxBars>0 && MaxBars<500) MaxBars=500;

   IndicatorShortName("RedK EVEREX");
   return(0);
} 
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int start()
{
   int i,counted_bars=IndicatorCounted();
   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
   int limit=fmin(Bars-counted_bars,Bars-maxPeriod);
   if(MaxBars>0 && limit>MaxBars) limit=MaxBars;

   double Vola,Vola_n_pre,Vola_n;

   // Volume "effort" Calculation
   for(i=limit;i>=0;i--) { Bv[i]=(double)Volume[i]; }
   for(i=limit;i>=0;i--)
   {
      Vola=iMAOnArray(Bv,0,length,0,MA_Type,i);

      Vola_n_pre = Normalize(Bv[i], Vola) * 100;
      Vola_n = Vola_n_pre; // Handle case of no volume data

      // Price "result" calculation
      double BarSpread = Close[i] - Open[i];
      double BarRange = High[i] - Low[i];
      double R2 = High[i+1] - Low[i+1];
      double SrcShift = Close[i] - Close[i+1];

      //double sign_shift = MathSign(SrcShift);
      double sign_shift; if(SrcShift<0){sign_shift=-1;}else{sign_shift=1;}      
      
      //double sign_spread = MathSign(BarSpread);
      double sign_spread; if(BarSpread<0){sign_spread=-1;}else{sign_spread=1;}

      double barclosing = 2 * DivZero((Close[i] - Low[i]),BarRange) * 100 - 100;
      double s2r = DivZero(BarSpread,BarRange) * 100;
            BarSpread_abs[i] = MathAbs(BarSpread);
      
      double BarSpread_avg = iMAOnArray(BarSpread_abs, 0, lookback, 0, lookbackMA, i);
      double BarSpread_ratio_n = Normalize(BarSpread_abs[i], BarSpread_avg) * 100 * sign_spread;

      double barclosing_2 = 2 * DivZero((Close[i] - Low[i+1]),R2) * 100 - 100;
      double Shift2Bar_toR2 = DivZero(SrcShift,R2) * 100;
            SrcShift_abs[i] = MathAbs(SrcShift);
      double srcshift_avg = iMAOnArray(SrcShift_abs, 0, lookback, 0, lookbackMA, i);
      double srcshift_ratio_n = Normalize(SrcShift_abs[i], srcshift_avg) * 100 * sign_shift;

      double Pricea_n = (barclosing + s2r + BarSpread_ratio_n + barclosing_2 + Shift2Bar_toR2 + srcshift_ratio_n) / 6;

      double bar_flow = Pricea_n * Vola_n / 100;

      // Bulls and Bears calculation
            bulls[i] = MathMax(bar_flow, 0);
            bears[i] = -1 * MathMin(bar_flow, 0);
      double bulls_avg = iMAOnArray(bulls, 0, length, 0, MA_Type, i);
      double bears_avg = iMAOnArray(bears, 0, length, 0, MA_Type, i);
      double dx = DivZero(bulls_avg,bears_avg);
            RROF[i] = 2 * (100 - 100 / (1 + dx)) - 100;
            RROF_s[i] = iMAOnArray(RROF, 0, smooth, 0, MODE_SMA, i);

      // Signal line calculation
      // double Signal = iMAOnArray(RROF_s, 0, sig_length, 0, S_Type, i);
      SignalBuffer[i] = iMAOnArray(RROF_s, 0, sig_length, 0, S_Type, i);

      // Calculate Bias / sentiment on longer length
      double bulls_avg_B = iMAOnArray(bulls, 0, B_Length, 0, B_Type, i);
      double bears_avg_B = iMAOnArray(bears, 0, B_Length, 0, B_Type, i);
      double dx_b = DivZero(bulls_avg_B,bears_avg_B);  
            RROF_b[i] = 2 * (100 - 100 / (1 + dx_b)) - 100;
            RROF_bs[i] = iMAOnArray(RROF_b, 0, smooth, 0, MODE_SMA, i);

      // Storing values in buffers
      VolaBuffer[i] = Vola_n;
      PriceaBuffer[i] = Pricea_n;

      if(UseBiasFilter)
      {
         if(BsFilterType==bf_slope)
         {
            if(RROF_bs[i]>RROF_bs[i+1]) { Trend[i] =  1; }
            else if(RROF_bs[i]<RROF_bs[i+1]) { Trend[i] = -1; }
            else Trend[i] = Trend[i+1];
         }
         else if(BsFilterType==bf_zero)
         {
            if(RROF_bs[i]>0) { Trend[i] =  1; }
            else if(RROF_bs[i]<0) { Trend[i] = -1; }
            else Trend[i] = Trend[i+1];
         }
         else if(BsFilterType==bf_both)
         {
            if(RROF_bs[i]>RROF_bs[i+1] && RROF_bs[i]>0) { Trend[i] =  1; }
            else if(RROF_bs[i]<RROF_bs[i+1] && RROF_bs[i]<0) { Trend[i] = -1; }
            else Trend[i] = Trend[i+1];
         }
         else Trend[i] = 0;
      }
      else Trend[i] = 0;

      if(RROF_s[i]>SignalBuffer[i] && ((UseBiasFilter && Trend[i]>0) || !UseBiasFilter))
      {
         if(RROF_s[i]>Level) Bias[i] = 4;
         else if(RROF_s[i]>0) Bias[i] = 3;
         else if(RROF_s[i]>-Level) Bias[i] = 2;
         else if(RROF_s[i]<-Level) Bias[i] = 1;
         else Bias[i] = 0;
      }
      else if(RROF_s[i]<SignalBuffer[i] && ((UseBiasFilter && Trend[i]<0) || !UseBiasFilter))
      {
         if(RROF_s[i]<-Level) Bias[i] = -4;
         else if(RROF_s[i]>-Level) Bias[i] = -3;
         else if(RROF_s[i]>0) Bias[i] = -2;
         else if(RROF_s[i]>Level) Bias[i] = -1;
         else Bias[i] = 0;
      }
      else Bias[i] = 0;

   }
   return(0);
}

double Normalize(double Value, double Avg) {
   double X = DivZero(Value,Avg);
   double Nor = 0.1; // Default value
   if (X > 1.50) Nor = 1.00;
   else if (X > 1.20) Nor = 0.90;
   else if (X > 1.00) Nor = 0.80;
   else if (X > 0.80) Nor = 0.70;
   else if (X > 0.60) Nor = 0.60;
   else if (X > 0.40) Nor = 0.50;
   else if (X > 0.20) Nor = 0.25;
   return (Nor);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double DivZero(double n,double d)
{
//+------------------------------------------------------------------+
// Divides N by D, and returns 0 if the denominator (D) = 0
// Usage:   double x = DivZero(y,z)  sets x = y/z
// Use DivZero(y,z) instead of y/z to eliminate division by zero errors
   if(d == 0) return(0);  else return(1.0*n/d);
}
//+------------------------------------------------------------------+

//+--------------------------- END ----------------------------------+
