Vix is a single number. You can measure absolute maximum distance from a moving average, but how useful is that?
Sophistication starts when you go with a sample size and measure maximum stretch on the upside and on the downside. 2 volatility reads, yes. It makes possibble to see a lot of the underlying changes.

Of course, Counterforce was meant to do this. But so does Vax, only with lines instead of histograms, no limiting and no negative numbers.

#property copyright "Copyright © 2024, Macdulio"
#property link "https://forexfore.blog"
#property description "V1.0"
#property description "Vax"
#property strict
//--- indicator settings
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1 clrRed
#property indicator_color2 clrGreen
#property indicator_color3 clrPurple
#property indicator_color4 clrBlue
#property indicator_color5 clrRed
#property indicator_color6 clrDarkKhaki
#property indicator_color7 clrWhite
#property indicator_level1 0
#property indicator_level2 41
#property indicator_level3 62
#property indicator_level4 93
#property indicator_levelcolor clrBlue
#property indicator_levelstyle STYLE_DOT
extern double valuetomonitor = 5.5;
extern int lookback = 100;
extern int indicator_window = 3;
extern int sample = 200;
extern double FSize=32;
double upper[], middle[], lower[];
double avg;
double FMax = FSize*6/5;
double iHi4[];
double iLo4[];
string symbol = Symbol();
double ExtATRBuffer[],ExtATRBuffer2[],ExtATRBuffer3[],ExtATRBuffer4[],ExtATRBuffer5[],stoch60[];
double corr[],corr2[], RSI2[], squeeze[];
int init(){
SetIndexBuffer(0,ExtATRBuffer);
SetIndexStyle(0,DRAW_LINE,STYLE_SOLID,4,indicator_color1);
SetIndexBuffer(1,ExtATRBuffer2);
SetIndexStyle(1,DRAW_LINE,STYLE_SOLID,4,indicator_color2);
return(0);
}
//+------------------------------------------------------------------+
//| Average True Range |
//+------------------------------------------------------------------+
int start(){
ArrayResize(ExtATRBuffer, Bars);
ArrayInitialize(ExtATRBuffer, EMPTY_VALUE);
ArrayResize(ExtATRBuffer2, Bars);
ArrayInitialize(ExtATRBuffer2, EMPTY_VALUE);
ArrayResize(ExtATRBuffer3, Bars);
ArrayInitialize(ExtATRBuffer3, EMPTY_VALUE);
ArrayResize(ExtATRBuffer4, Bars);
ArrayInitialize(ExtATRBuffer4, EMPTY_VALUE);
ArrayResize(ExtATRBuffer5, Bars);
ArrayInitialize(ExtATRBuffer5, EMPTY_VALUE);
ArrayResize(iHi4, Bars);
ArrayInitialize(iHi4, EMPTY_VALUE);
ArrayResize(iLo4, Bars);
ArrayInitialize(iLo4, EMPTY_VALUE);
ArrayResize(stoch60, Bars);
ArrayInitialize(stoch60, EMPTY_VALUE);
ArrayResize(RSI2, Bars);
ArrayInitialize(RSI2, EMPTY_VALUE);
ArrayResize(corr, Bars);
ArrayInitialize(corr, EMPTY_VALUE);
ArrayResize(corr2, Bars);
ArrayInitialize(corr2, EMPTY_VALUE);
ArrayResize(middle, Bars);
ArrayInitialize(middle, EMPTY_VALUE);
ArrayResize(squeeze, Bars);
ArrayInitialize(squeeze, 0);
ArrayResize(upper, Bars);
ArrayInitialize(upper, EMPTY_VALUE);
ArrayResize(lower, Bars);
ArrayInitialize(lower, EMPTY_VALUE);
int i,j,k;
for(i=Bars-100; i>=0; i--){
if (Period()==240) iHi4[i]=iMA(NULL,0,52,0,MODE_EMA, PRICE_HIGH,i);
else if (Period()==30) iHi4[i]=iMA(NULL,0,414,0,MODE_EMA, PRICE_HIGH,i);
else if (Period()==60) iHi4[i]=iMA(NULL,0,207,0,MODE_EMA, PRICE_HIGH,i);
if (Period()==240) iLo4[i]=iMA(NULL,0,52,0,MODE_EMA, PRICE_LOW,i);
else if (Period()==30) iLo4[i]=iMA(NULL,0,414,0,MODE_EMA, PRICE_LOW,i);
else if (Period()==60) iLo4[i]=iMA(NULL,0,207,0,MODE_EMA, PRICE_LOW,i);
stoch60[i]=iStochastic(symbol,60,60,3,3,MODE_SMA,0,MODE_SIGNAL,i);
RSI2[i]=iRSI(symbol,0,2,PRICE_MEDIAN,i);
}
deletetxt1("Pepper");
deletetxt1("Panace");
deletetxt1("PLOT");
for(i=lookback; i>=0; i--){
middle[i] = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_TYPICAL, i);
avg = findAvg(20, i);
upper[i] = middle[i] + avg;
lower[i] = middle[i] - avg;
ExtATRBuffer[i]= -1*(iHigh(symbol,0,iHighest(symbol,0,MODE_HIGH,sample-1,i+1))-Low[i])*-10000;
ExtATRBuffer2[i]=(High[i]-iLow(symbol,0,iLowest(symbol,0,MODE_LOW,sample-1,i+1)))*10000;
if (Period()==60){
corr[i]=corr[i+1];
corr2[i]=corr2[i+1];
if (ExtATRBuffer4[i+6]!=EMPTY_VALUE) {corr[i]=iHigh(symbol,0,iHighest(symbol,0,MODE_HIGH,60,i))-1360*Point; corr2[i]=iHigh(symbol,0,iHighest(symbol,0,MODE_HIGH,60,i))-2100*Point;}
if (ExtATRBuffer5[i+6]!=EMPTY_VALUE) {corr[i]=iLow(symbol,0,iLowest(symbol,0,MODE_LOW,60,i))+1360*Point; corr2[i]=iLow(symbol,0,iLowest(symbol,0,MODE_LOW,60,i))+2100*Point;}
}
}
deletetxt1("AverD");
int twodigits = NormalizeDouble(ExtATRBuffer2[0],0);
if (MathAbs(ExtATRBuffer[0])>ExtATRBuffer2[0]) twodigits = NormalizeDouble(MathAbs(ExtATRBuffer[0]),0);
//string tds = IntegerToString(twodigits);
int tens = round(twodigits/10);
int ones = twodigits-tens*10;
string stens, sones;
//Print("tens=",tens);
//Print("ones=",ones);
switch(tens)
{
case 1: stens=CharToStr(140);
break;
case 2: stens=CharToStr(141);
break;
case 3: stens=CharToStr(142);
break;
case 4: stens=CharToStr(143);
break;
case 5: stens=CharToStr(144);
break;
case 6: stens=CharToStr(145);
break;
case 7: stens=CharToStr(146);
break;
case 8: stens=CharToStr(147);
break;
case 9: stens=CharToStr(148);
break;
default: stens=CharToStr(139);
break;
}
//deletetxt1("AverD");
switch(ones)
{
case 1: sones=CharToStr(140);
break;
case 2: sones=CharToStr(141);
break;
case 3: sones=CharToStr(142);
break;
case 4: sones=CharToStr(143);
break;
case 5: sones=CharToStr(144);
break;
case 6: sones=CharToStr(145);
break;
case 7: sones=CharToStr(146);
break;
case 8: sones=CharToStr(147);
break;
case 9: sones=CharToStr(148);
break;
default: sones=CharToStr(139);
break;
}
string jointstring=stens+sones;
ObjectCreate("AverD",OBJ_LABEL,indicator_window, 0,0);
ObjectSet("AverD",OBJPROP_CORNER,3);
ObjectSet("AverD",OBJPROP_XDISTANCE,20);
ObjectSet("AverD",OBJPROP_YDISTANCE,27);
ObjectSetText("AverD",jointstring,40,"Wingdings",DimGray);
if (twodigits>30) ObjectSetText("AverD",jointstring,40,"Wingdings",Yellow);
if (twodigits>58) ObjectSetText("AverD",jointstring,40,"Wingdings",DeepPink);
deletetxt1("Crush");
deletetxt1("Leap");
deletetxt1("Frog");
deletetxt1("Countess");
deletetxt1("Missing");
deletetxt1("KAROLY");
int counter = 9;
for(i=lookback; i>=0; i--){
if (Close[i]<iLo4[i] ) {ObjectSetText("Crushi"+i, "Vol Crush > ", 21, "Impact", clrWhite); ObjectSetText("Crush"+i, "Vol Crush -> ", 19, "Impact", clrNavy); ObjectSetText("Crushy"+i,DoubleToStr(NormalizeDouble(iHi4[i],4),4), 21, "Impact", clrWhite); ObjectSetText("Crushd"+i, DoubleToStr(NormalizeDouble(iHi4[i],4),4), 19, "Impact", clrNavy); }
else if (Close[i]>iHi4[i] ) { ObjectSetText("Crushi"+i, "Vol Crush > ", 21, "Impact", clrWhite); ObjectSetText("Crush"+i, "Vol Crush -> ", 19, "Impact", clrNavy); ObjectSetText("Crushy"+i, DoubleToStr(NormalizeDouble(iLo4[i],4),4), 21, "Impact", clrWhite); ObjectSetText("Crushd"+i, DoubleToStr(NormalizeDouble(iLo4[i],4),4), 19, "Impact", clrNavy); }
}
double rou=0;
double rod=0;
if (Period()==30){
deletetxt1("Libec");
i=0;
while(i<10){
if (High[i]-iMA(NULL,0,17,0,MODE_EMA, PRICE_MEDIAN,i)>rou) rou=High[i]-iMA(NULL,0,17,0,MODE_EMA, PRICE_MEDIAN,i);
if (iMA(NULL,0,17,0,MODE_EMA, PRICE_MEDIAN,i)-Low[i]>rod) rod=iMA(NULL,0,17,0,MODE_EMA, PRICE_MEDIAN,i)-Low[i];
i++;
}
ObjectCreate("Libec"+4,OBJ_LABEL,indicator_window, 0,0);
ObjectSetText("Libec"+4, DoubleToStr(rou*10000,2)+" ("+DoubleToStr(iMA(NULL,0,17,0,MODE_EMA, PRICE_MEDIAN,0)+rou,4)+")", 11, "Arial Black", DarkViolet);
ObjectSet("Libec"+4,OBJPROP_CORNER,2);
ObjectSet("Libec"+4,OBJPROP_XDISTANCE,20);
ObjectSet("Libec"+4,OBJPROP_YDISTANCE,67);
if (rou>rod) ObjectSet("Libec"+4,OBJPROP_COLOR,clrDarkGreen);
else if (rou<.0010) ObjectSet("Libec"+4,OBJPROP_COLOR,clrGray);
else ObjectSet("Libec"+4,OBJPROP_COLOR,clrBlack);
ObjectCreate("Libec"+5,OBJ_LABEL,indicator_window, 0,0);
ObjectSetText("Libec"+5,DoubleToStr(rod*10000,2)+" ("+DoubleToStr(iMA(NULL,0,17,0,MODE_EMA, PRICE_MEDIAN,0)-rod,4)+")", 11, "Arial Black", DarkViolet);
ObjectSet("Libec"+5,OBJPROP_CORNER,2);
ObjectSet("Libec"+5,OBJPROP_XDISTANCE,20);
ObjectSet("Libec"+5,OBJPROP_YDISTANCE,47);
if (rod>rou) ObjectSet("Libec"+5,OBJPROP_COLOR,clrCrimson);
else if (rod<.0010) ObjectSet("Libec"+5,OBJPROP_COLOR,clrGray);
else ObjectSet("Libec"+5,OBJPROP_COLOR,clrBlack);
}
return(0);
}
//+------------------------------------------------------------------+
void deletetxt1(string text){
for(int iObj=ObjectsTotal()-1; iObj >= 0; iObj--){
string on = ObjectName(iObj);
if(StringFind(on, text) == 0) ObjectDelete(on);
} }
double findAvg(int period, int shift) {
double sum=0;
for (int x=shift;x<(shift+period);x++) {
sum += High[x]-Low[x];
}
sum = sum/period;
return (sum);
}
Based on the need for \ volatility divergence, there should be a higher high print with the red line not making it down to 25.

