//+------------------------------------------------------------------+
//|                                                  William VIX Fix |
//|                      Port from FxCodeBase LUA to MQL4 (classic)  |
//|                      MQL4 compatible (build 509+ / 600+)         |
//|                      Conversion by ChatGPT                       |
//+------------------------------------------------------------------+
#property indicator_separate_window
#property indicator_buffers 6
#property indicator_color1  Lime      // WVF Up
#property indicator_color2  Gray      // WVF Down
#property indicator_color3  Blue      // Upper Band
#property indicator_color4  Blue      // Lower Band
#property indicator_color5  Orange    // Range High
#property indicator_color6  Orange    // Range Low

//---- Inputs
extern int    Period = 22;      // Highest Close lookback (Period+1 bars)
extern int    bbl    = 20;      // Bollinger length (on WVF)
extern double mult   = 2.0;     // StdDev multiplier
extern int    lb     = 50;      // Lookback for Range High/Low
extern double ph     = 0.85;    // Percentile factor (High)
extern double pl     = 1.01;    // Percentile factor (Low)

// 0 = line, 1 = histogram
extern int    PlotType   = 1;
extern int    LineStyle  = 0;      // STYLE_SOLID=0, DASH=1, etc.
extern int    Width      = 2;      // Thickness of WVF histogram/line
extern bool   ShowBands  = true;
extern bool   ShowRange  = true;

//---- Buffers (plotted)
double WVF_Up[];
double WVF_Dn[];
double UpperBand[];
double LowerBand[];
double RangeHigh[];
double RangeLow[];

//---- internal working array
double WVF[];

//+------------------------------------------------------------------+
//| init() - classic MQL4 initialization                             |
//+------------------------------------------------------------------+
int init()
{
   IndicatorShortName("William VIX Fix (MT4)");

   //--- map buffers
   SetIndexBuffer(0, WVF_Up);   SetIndexLabel(0, "WVF Up");
   SetIndexBuffer(1, WVF_Dn);   SetIndexLabel(1, "WVF Down");
   SetIndexBuffer(2, UpperBand);SetIndexLabel(2, "Upper Band");
   SetIndexBuffer(3, LowerBand);SetIndexLabel(3, "Lower Band");
   SetIndexBuffer(4, RangeHigh);SetIndexLabel(4, "Range High");
   SetIndexBuffer(5, RangeLow); SetIndexLabel(5, "Range Low");

   //--- drawing styles
   int drawType = (PlotType==1 ? DRAW_HISTOGRAM : DRAW_LINE);
   SetIndexStyle(0, drawType, LineStyle, Width);
   SetIndexStyle(1, drawType, LineStyle, Width);

   if(ShowBands)
   {
      SetIndexStyle(2, DRAW_LINE, STYLE_SOLID, 1);
      SetIndexStyle(3, DRAW_LINE, STYLE_SOLID, 1);
   }
   else
   {
      SetIndexStyle(2, DRAW_NONE);
      SetIndexStyle(3, DRAW_NONE);
   }

   if(ShowRange)
   {
      SetIndexStyle(4, DRAW_LINE, STYLE_SOLID, 1);
      SetIndexStyle(5, DRAW_LINE, STYLE_SOLID, 1);
   }
   else
   {
      SetIndexStyle(4, DRAW_NONE);
      SetIndexStyle(5, DRAW_NONE);
   }

   //--- ensure series order
   ArraySetAsSeries(WVF_Up,   true);
   ArraySetAsSeries(WVF_Dn,   true);
   ArraySetAsSeries(UpperBand,true);
   ArraySetAsSeries(LowerBand,true);
   ArraySetAsSeries(RangeHigh,true);
   ArraySetAsSeries(RangeLow, true);
   ArraySetAsSeries(WVF,      true);

   return(0);
}

//+------------------------------------------------------------------+
//| start() - main calc                                              |
//+------------------------------------------------------------------+
int start()
{
   int bars = Bars;
   if(bars <= Period+1) return(0);

   //--- size working array and clear outputs
   ArrayResize(WVF, bars);
   ArrayInitialize(WVF_Up,    EMPTY_VALUE);
   ArrayInitialize(WVF_Dn,    EMPTY_VALUE);
   ArrayInitialize(UpperBand, EMPTY_VALUE);
   ArrayInitialize(LowerBand, EMPTY_VALUE);
   ArrayInitialize(RangeHigh, EMPTY_VALUE);
   ArrayInitialize(RangeLow,  EMPTY_VALUE);

   //--- indices where each component becomes valid
   int lastWVF   = bars - (Period+1);
   int lastBand  = (bbl>1 ? bars - (Period+1) - (bbl-1) : -1);
   int lastRange = (lb>0  ? bars - (Period+1) - (lb -1) : -1);

   int i;

   //=====================================================
   // 1) WVF core
   //=====================================================
   for(i=lastWVF; i>=0; i--)
   {
      int   idxMaxClose = iHighest(NULL, 0, MODE_CLOSE, Period+1, i);
      double maxClose   = Close[idxMaxClose];
      if(maxClose==0.0) { WVF[i]=0.0; continue; }
      WVF[i] = (maxClose - Low[i]) / maxClose * 100.0;
   }

   //=====================================================
   // 2) Bands on WVF
   //=====================================================
   if(ShowBands && bbl>1)
   {
      for(i=lastBand; i>=0; i--)
      {
         double mid  = iMAOnArray(WVF, 0, bbl, 0, MODE_SMA, i);
         double dev  = iStdDevOnArray(WVF, 0, bbl, 0, MODE_SMA, i);
         UpperBand[i] = mid + mult * dev;
         LowerBand[i] = mid - mult * dev;
      }
   }

   //=====================================================
   // 3) Range High/Low + coloring
   //=====================================================
   for(i=lastRange; i>=0; i--)
   {
      if(ShowRange)
      {
         int imax = ArrayMaximum(WVF, i, lb);
         int imin = ArrayMinimum(WVF, i, lb);
         RangeHigh[i] = WVF[imax] * ph;
         RangeLow[i]  = WVF[imin] * pl;
      }

      bool condUp=false;
      if(ShowBands && UpperBand[i]!=EMPTY_VALUE) condUp = condUp || (WVF[i] >= UpperBand[i]);
      if(ShowRange && RangeHigh[i]!=EMPTY_VALUE) condUp = condUp || (WVF[i] >= RangeHigh[i]);

      if(condUp) { WVF_Up[i] = WVF[i];  WVF_Dn[i] = EMPTY_VALUE; }
      else       { WVF_Dn[i] = WVF[i];  WVF_Up[i] = EMPTY_VALUE; }
   }

   return(0);
}
//+------------------------------------------------------------------+
