Calculating Relative Volume (RVOL)

Hi,

I am relatively new to Amibroker.

Can anyone please help me with this code? Much appreciated.

I've had a look at related post and found the below code that partially works but not what i want. It only compares the First bar volume with avg of last 10 days volume

What i want is to be able to run the scan on real time data and find stocks that are trading higher relative volume than avg of previous X No of days.

For example - If the scan ran at 11 am, then it should look for all stocks that are trading 2x the average volume at 11 am compared to average volume of last 5 days but only till 11 am (not entire days). So it should be like for comparison for time interval.

The scan should automatically find the current day bars, sum all of those intraday bar volume and then compare with corresponding bars of previous days.

I mostly run the scan with 5 min or 1 min candles.

Thanks in advance.

/// @link https://forum.amibroker.com/t/afl-for-relative-volume-scanner/6686/10
/// INTRA-DAY code!
//if( Interval() != in15Minute )
//	Error( "Set to 15-Minute Interval as that one is what you asked for!" );
dn = DateNum();
newday = dn != Ref( dn, -1);
avgvol = SparseExpand(newday, Ref(MA(SparseCompress(newday, V),10),-1));
first_bar_vol = IIf(newday, V, Null);
RVOL = (first_bar_vol / avgvol);
//
Filter = first_bar_vol > 2*avgvol;

AddColumn(RVOL, "RVOL");

Try this code

PBT   = Period_Beginning_Time	  = ParamTime("Period Beginning Time","10:30:00",0);
PET   = Period_Ending_Time	      = ParamTime("Period Ending Time","11:30:00",0);
NLBD  = Number_of_Look_Back_Days  = Param("Look Back Days",5,0,100);
Ratio = Current_To_Average Volume = Param("Ratio Between Current and Average Volume of Past Period",2,0,5,0.1);


NTS = New_Trading_Session		= Ref(Day(),0) != Ref(Day(),-1);
C1  = Condition_No_One			= Cum(NTS) >= LastValue(Cum(NTS))-NLBD AND TimeNum() >= PBT AND TimeNum() <= PET;
GV  = Gross_Volume				= SumSince(!C1,V);
C2  = Condition_No_Two			= Ref(GV,1) < Ref(GV,0) AND LastValue(Cum(C1)) != Cum(C1);
GV  = Gross_Volume				= Cum(IIf(C2,GV,0));
AV  = Average_Volume			= LastValue(GV)/NLBD;
CV  = Current_Volume			= Cum(ValueWhen(C1 AND Cum(Ref(C2,-1)) >= NLBD,V));

Buy_Condition = CV >= AV*Ratio;



3 Likes

Hi Sebastian,

Thanks for responding.

Do i have to keep updating the end time in live market conditions?

Is there a way for the code to automatically detect completed bars in current live trading day and then look for avg of corresponding bars for previous days?

Thanks
Sam

Another variant can be done like this.

tn = TimeNum();
tm = LastValue(tn);	//tm = 120000;

tv = IIf( tn <= tm, V, 0 );

dv = TimeFrameCompress( tv, inDaily, compressVolume);

av3 = MA( dv, 3); // Your X, 3 in this example

Filter = LastValue( dv ) > ( 2 * Ref( av3, -1));
// 2Y Vol than the 3MA till that time, 2Y as an example

You can even add a start time by modifying the condition in IIF()

A cumulative of V till the present in bar in current day compared Y times to an X running Average.

Hi Travick,

Thanks for helping.

I did a test run and realized that your code is not doing like for like comparison of the time intervals.

For example, let's say the market is open from 9am to 3pm, In real time, if i'm running the scan at 1 pm, its comparing today's volume from 9am to 1pm with volume of previous days from 9 am to 3 pm.

It should only compare 9 am to 1 pm for previous days as well, otherwise the indicator would not give us an accurate picture of what stocks are seeing unusual volumes.

Please help.

Thanks
Sam

Kindly post your live market runs and explain in detail how you are running it.
The whole point of using LastValue() of TimeNum() is to get the latest bar time.

If you want intraday volume, you need to run the afl code in intraday data not Daily

Just a necessary small fix for variable Current_Volume, i shall to use iif()
instead of Valuewhen() , as the latter would keep the last value even if the condition was false , so here's a correction for that

// This line should be
CV  = Current_Volume = Cum(ValueWhen(C1 AND Cum(Ref(C2,-1)) >= NLBD,V));

// Replaced by this one 
CV  = Current_Volume = Cum(IIf(C1 AND Cum(Ref(C2,-1)) >= NLBD,V,0));

Thanks everyone for the help.

Hello @Sebastian,
I have created "new formular" and copy all your code to it. but then when i insert that formular to chart, it not work (instead, it shows the code text)
Please help me through this!
this is the code screen:
image

this is what i get on the chart when "insert"
image
Thank you very much!!

Put an underscore "_" before Volume in line 5.

yes, the error's gone.
but i got a blank chart (the one at the bottom). something goes wrong somewhere?

image

Plot variables CV and AV.

Plot(CV,"",colorblack,styleline);
Plot(AV,"",colorred,styleline);

Hi C_M,
there's a black line, but it seem not correct. please take a look

image

After hours of research, I finally came accross a RVOL code at an old Amibroker forum archive. I saved the link in the code. This code also include Stdev line for Volume.
Here is the nugget:

//RVOL: RELATIVE VOLUME WITH STANDARD DEVIATION BAND
//link: https://www.mail-archive.com/amibroker@yahoogroups.com/msg39758.html
//Note for Vietnamese market: 4 hour of trading total, each hour is 3600s

H1=V; //Use volume to calculate
dn = DateNum();
Avgvol=0;
sqsum=0;
relsd=0;

d=Param("d",20,2,50); //Select the number of period to do averaging

if (Interval()<inDaily) 
{
n = round(3600*4/Interval());  //number of bars in the day
barnum = BarsSince(dn!=Ref(dn,-1)); //bar number from start of the day
	for (i=0; i<n; i++) 
		{
			VarSet("vol"+i,IIf(i==barnum,H1,0));
			VarSet("vols"+i,IIf(i==barnum,H1*H1,0));
		}
	for (i=0; i<n; i++) 
	{ 
		Avgvol=IIf(barnum==i,Sum(VarGet("vol"+i),n*d)/d,Avgvol);
		sqsum=IIf(barnum==i,Sum(VarGet("vols"+i),n*d)/d,sqsum);
	}
relsd=sqrt(sqsum-(Avgvol*Avgvol));
}

// Z-Score
z=100*((H1-Avgvol)/relsd);

Plot(V,"Volume",colorGreen,styleHistogram);
Plot(Avgvol-relsd,"Lower",colorDarkRed,styleline|styleThick);
Plot(Avgvol,"Avg Vol",colorRed,styleHistogram|styleThick);
Plot(Avgvol+relsd,"Upper",colorPink,styleline|styleThick);
Plot(0,"ZeroLine",colorwhite,styleNoTitle|styleNoLabel);
1 Like

hi, I am working on similar code at the moment. So I am using IQFeed futures data and want to compare the true volume with the average volume of the past ndays.

I made some code that works but there are some issues:

  1. futures trading in the US starts on Sunday evening 6PM
  2. on holidays (like MLK day yesterday) the number of bars in that day is less than normal and also the volume is meaningless.

so I just put the code here. Maybe someone has a good idea how to avoid errors caused by point 1 & 2

//SetBarsRequired( sbrAll, sbrAll );
bi = BarIndex();
ndays = Param( "Number of Days", 10, 1, 10, 1 );
disp = ParamToggle( "Display Stats", "Off|On", 1 );

separator = Day() != Ref( Day(), -1 ) AND DayOfWeek() != 0;// remove Sunday
//separator = Day() != Ref( Day(), -1 ); // include Sunday
maxdays = LastValue( Cum( separator ) ) - 1; // check if ndays are available in database
ndays = Min( ndays, maxdays );

Plot( V, "True Volume", colorYellow, styleStaircase, Null, Null, 0, 0, 2 );
Plot( IIf( separator, 1, Null ), "", ColorRGB( 0, 255, 255 ), styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -1, 1 );

average_volume_array = 0;

for( i = 1; i <= ndays; i++ )
{
    delta_index_of_separator = ValueWhen( separator, bi, 1 ) - ValueWhen( separator, bi, ( i + 1 ) );
    average_volume_array = average_volume_array + Ref( V, -delta_index_of_separator );
}

Plot( SafeDivide( average_volume_array, ndays ), "Average Volume over the previous " + ndays + " days", colorRed, styleStaircase, Null, Null, 0, 1, 2 );

if( disp )
{
    ymin = Status( "axisminy" );
    ymax = Status( "axismaxy" );
    dy = ymax - ymin;
    fvb = FirstVisibleValue( bi );
    lvb = LastVisibleValue( bi );
    delta_index_of_separator = ValueWhen( separator, bi, 1 ) - ValueWhen( separator, bi, 2 );
    dd = Day();
    mm = Month();
    yy = Year();
    dow = DayOfWeek();

    for( i = lvb; i > fvb; i-- )
    {
        if( separator[i] )
        {
            if( dow[i] == 0 )
                dowstr = "Sunday";

            if( dow[i] == 1 )
                dowstr = "Monday";

            if( dow[i] == 2 )
                dowstr = "Tuesday";

            if( dow[i] == 3 )
                dowstr = "Wednesday";

            if( dow[i] == 4 )
                dowstr = "Thursday";

            if( dow[i] == 5 )
                dowstr = "Friday";

            if( dow[i] == 6 )
                dowstr = "Saturday";

            PlotTextSetFont( "" + delta_index_of_separator[i] + " delta bars", "Helvetica", 10, i + 4, ymax - dy / 4, colorAqua, colorDefault, 0 );
            PlotTextSetFont( dowstr + ", " + mm[i] + "/" + dd[i] + "/" + yy[i], "Helvetica", 10, i + 4, ymax - dy / 3, colorYellow, colorDefault, 0 );
        }
    }
}

this is how it looks like (bottom chart). Yellow is the true volume. Red is the average over the pas ndays (in this case 10 days).
es

1 Like

I solved it. The problem to solve is to calculate the average volume of the past "ndays" and display this volume on the current day (using intraday data).

The "holidays" are found when the number of bars in that day deviates (or is less than) the number of bars in a regular trading day with a percentage more than some cutoff percentage. I use 8% as a cutoff.

These days are then removed using sparseCompress. And the resulting volume array is now free from low volume days and can be used to calculate the average.

When the average is calculated the average volume array array is expanded.

It does not seem to matter where the separator is placed. Included in the code are 3 ways to calculate the separator between days.

SetBarsRequired( sbrAll, sbrAll );
bi = BarIndex();
ndays = Param( "Number of Days", 10, 1, 20, 1 );
disp = ParamToggle( "Display Stats", "Off|On", 1 );
selsep = ParamList( "Select Separator", "Time|Day|expandPoint", 1 );
cutoff = Param( "Cutoff Percentage", 8, 1, 20, 0.1 );

// various ways to calculate the separator between trading days
if( selsep == "Time" )
{
    separator = TimeNum() >= 165900;
    separator = separator - Ref( separator, -1 );
    separator = IIf( Day() != Ref( Day(), -1 ) AND !( DayOfWeek() == 0 ), 0, separator );
    separator_day = Day() != Ref( Day(), -1 );
}
else
    if( selsep == "Day" )
    {
        separator = Day() != Ref( Day(), -1 ) AND DayOfWeek() != 0;// remove Sunday
        separator_day = Day() != Ref( Day(), -1 );
    }
    else
        if( selsep == "expandPoint" )
        {
            // version of Jorgen W., uses database time settings.
            // For CME use
            // Day 09:30 - 17:29, Night 17:30 - 09:29
            // compression Day/Night checked
            // First day of Week: Sunday
            separator = Ref( Nz( TimeFrameExpand( 1, inDaily, expandPoint ) ), -1 );
            separator_day = Day() != Ref( Day(), -1 );
        }

// find the length of a regular trading day
delta_index_of_separator = ValueWhen( separator, bi, 1 ) - ValueWhen( separator, bi, 2 );
ss = Sort( delta_index_of_separator, 0, -1, 0 );
ss = ss[BarCount - 1];

// correct number of days used if not available in database
maxdays = LastValue( Cum( separator ) ) - 1; // check if ndays are available in database
ndays = Min( ndays, maxdays );

// find the index of days that are holidays / half trading days based on the number of bars in that day using a "cutoff" percentage
average_volume_array = 0;
average_volume_countdays_array = 0;
holiday_index = IIf( ( ss - abs( ValueWhen( separator, bi, 1 ) - ValueWhen( separator, bi, 0 ) ) ) / ss * 100 > cutoff, 1, 0 );
holiday_index = IIf( bi >= LastValue( ValueWhen( separator, bi ) ), 0, holiday_index );

// exclude bars at the holiday_index using SparseCompress
volume_SparseCompress = SparseCompress( !holiday_index, V );
separator_SparseCompress = SparseCompress( !holiday_index, separator );

for( i = 1; i <= ndays; i++ )
{
    // use regular BarIndex() bi
    delta_index_of_separator = ValueWhen( separator_SparseCompress, bi, 1 ) - ValueWhen( separator_SparseCompress, bi, ( i + 1 ) );
    average_volume_array = average_volume_array + Ref( volume_SparseCompress, -delta_index_of_separator ); // numerator
}

// calculate the average
average_volume_array = SafeDivide( average_volume_array, ndays );

// expand the average
average_volume_array_SparseExpand = SparseExpand( !holiday_index, average_volume_array );

Plot( V, "True Volume", IIf( C > O, ParamColor( "Up Color", colorBlue ), ParamColor( "Down Color", colorRed ) ), styleHistogram, Null, Null, 0, 0, 3 );
Plot( IIf( separator, 1, Null ), "", ColorRGB( 0, 255, 255 ), styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -1, 1 );
Plot( average_volume_array_SparseExpand, "Average Volume over the previous " + ndays + " days", colorGold, styleStaircase | styleNoLabel, Null, Null, 0, 1, 1 );

if( selsep != "Day" )
{
    Plot( IIf( separator_day, 1, Null ), "", ColorRGB( 100, 100, 100 ), styleDashed | styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -1, 1 );
}

if( disp )
{
    lastsep = LastValue( ValueWhen( separator, bi ) );
    ymin = Status( "axisminy" );
    ymax = Status( "axismaxy" );
    dy = ymax - ymin;
    fvb = FirstVisibleValue( bi );
    lvb = LastVisibleValue( bi );
    delta_index_of_separator = ValueWhen( separator, bi, 1 ) - ValueWhen( separator, bi, 2 );
    dd = Day();
    mm = Month();
    yy = Year();
    dow = DayOfWeek();

    for( i = lvb; i > fvb; i-- )
    {
        if( ( separator[i] AND selsep == "Day" ) OR( separator_day[i] AND selsep != "Day" ) )
        {
            if( dow[i] == 0 )
                dowstr = "Sunday";

            if( dow[i] == 1 )
                dowstr = "Monday";

            if( dow[i] == 2 )
                dowstr = "Tuesday";

            if( dow[i] == 3 )
                dowstr = "Wednesday";

            if( dow[i] == 4 )
                dowstr = "Thursday";

            if( dow[i] == 5 )
                dowstr = "Friday";

            if( dow[i] == 6 )
                dowstr = "Saturday";

            holiday_status = "";

            if( holiday_index[i] AND bi[i] != lastsep )
            {
                holiday_status = "+++ Holiday +++";
                PlotTextSetFont( holiday_status, "Helvetica", 10, i + 4, ymax - dy / 3, colorGold, colorDefault, 0 );
            }
            else
                if( bi[i] != lastsep )
                {
                    holiday_status = "Regular Trading";
                }
                else
                    if( bi[i] == lastsep )
                    {
                        holiday_status = "Last Day";
                    }

            PlotTextSetFont( "" + delta_index_of_separator[i] + " bars", "Helvetica", 12, i - delta_index_of_separator[i] / 1.75, ymax - dy / 4, colorAqua, colorDefault, 0 );
            PlotTextSetFont( dowstr + ", " + mm[i] + "/" + dd[i] + "/" + yy[i], "Helvetica", 10, i + 4, ymax - dy / 4, colorGold, colorDefault, 0 );
        }
    }
}

es

5 Likes

Hi @empottasch,
I was about to post my version, but yours is great.
Compared to yours, there's no time management, and a 'holi'day is discarded based on its volume, not the number of bars. I've added two other views of relative volume and simplified a few lines at the end too, not much.

_SECTION_BEGIN("Empottasch Relative Volume");
//SetBarsRequired( sbrAll, sbrAll );
bi = BarIndex();
ndays = Param( "Number of Days", 10, 2, 21, 1 );
disp = ParamToggle( "Display Stats", "Off|On", 1 );
cumview = ParamList( "Viewpoint", "Classic|Cumulative|Delta", 0);
remove_sunday = ParamToggle("Remove Sunday", "No|Yes", 1);
remove_lowvol = ParamToggle("Remove Low-Volume Days", "No|Yes", 1);
minvollevel = Param("Low Volume Cutoff (%)", 50, 0, 100, 5)*0.01;

D = Day();
separator = D != Ref( D, -1 ); 			// include Sunday
	
maxdays = LastValue( Cum( separator ) ) - 1; 			// check if ndays are available in database
ndays = Min( ndays, maxdays );

if (remove_lowvol) {
	TimeFrameSet(inDaily);
	adv = AMA(V, 1/(ndays+1));							// average daily volume
	Tmp = Cum(1); LastDay = LastValue(Tmp) == Tmp;
	regular_day = (V >= minvollevel*adv) OR LastDay;		// criterium for low vol: 25% of average
	if (remove_sunday) regular_day = regular_day AND DayOfWeek() != 0;
	TimeFrameRestore();
	regular_day = TimeFrameExpand(regular_day, inDaily, expandFirst);
	V = V * regular_day;
} else regular_day = 1;

if (cumview != "Classic") {
	Vol = Sum(V, BarsSince(separator)+1);
} else {
	Vol = V;
}

CVol = SparseCompress(regular_day, Vol);
Cseparator = SparseCompress(regular_day, separator); 

average_volume_array = 0;
for( i = 1; i <= ndays; i++ )
{
	delta_index_of_separator = ValueWhen( Cseparator, bi, 1 ) - ValueWhen( Cseparator, bi, ( i + 1 ) );
	average_volume_array += Ref( CVol, -delta_index_of_separator );
}
// average_volume_array = average_volume_array + Ref( volume_SparseCompress, -delta_index_of_separator ); // numerator
Caverage_volume = SafeDivide( average_volume_array, ndays );
average_volume = SparseExpand(regular_day, Caverage_volume);

if (cumview == "Delta") {
	Delta = 100*SafeDivide((Vol - average_volume), average_volume);
	color = IIf(Delta < 0, colorRed, IIf(Delta > 0, colorGreen, colorgrey40));
	Plot(Delta, "% Average Volume Difference over the previous " + ndays + " days", color, styleStaircase, Null, Null, 0, 1, 2 );
	PlotGrid(0, colorGrey40, 2);
	Plot(200, "", colorDefault, styleNoDraw);
} else {
	Plot( Vol, "True Volume", colorYellow, styleStaircase, Null, Null, 0, 0, 2 );
	Plot( IIf( separator, 1, Null ), "", ColorRGB( 0, 255, 255 ), styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -1, 1 );
	Plot( average_volume, "Average Volume over the previous " + ndays + " days", colorRed, styleStaircase, Null, Null, 0, 1, 2 );
}

if( disp )
{
    ymin = Status( "axisminy" );
    ymax = Status( "axismaxy" );
    dy = ymax - ymin;
    fvb = FirstVisibleValue( bi );
    lvb = LastVisibleValue( bi );
    delta_index_of_separator = ValueWhen( separator, bi, 1 ) - ValueWhen( separator, bi, 2 );
    dt = DateTime();
    lastbar = bi == LastValue(bi);
    next_delta = ValueWhen(separator OR lastbar, bi, 0);
	delta_index_of_separator[BarCount-1] = LastValue(BarsSince(separator));
	
    for( i = lvb; i > fvb; i-- )
    {
        if( separator[i] ) 
        { 
            daydate = DateTimeFormat("%A, %x", dt[i]);

            PlotTextSetFont( "" + delta_index_of_separator[next_delta[i]] + " bars", "Helvetica", 10, i + 14, ymax - dy / 4, colorAqua, colorDefault, 0 );
            PlotTextSetFont( daydate, "Helvetica", 10, i + 14, ymax - dy / 3, colorYellow, colorDefault, 0 );
            if ( !regular_day[i] ) PlotTextSetFont( "Low Volume\nDiscarded", "Helvetica", 10, i + 14, ymax - dy / 2, colorOrange, colorDefault, 0 );
		}
    }
}
_SECTION_END();

One last thing, there could be a problem when computing average in low volume products if some bars are 'missing' as the number of bars could change from day to day.
Cheers.

3 Likes

thank you. I will check out your code tomorrow. Indeed best comment out setbarsrequired.

and yes the search for a "holiday" day is a bit simplistic and sometimes gives a problem. So I will look at your code and get back to you tomorrow

hi, yes the volume is a good idea. I added it to my code. You are right that for certain futures the length of the days in bars are not always the same and therefor I use a percentage. If the number of bars is less than 8% of a regular day then I assume it is a "holiday" day.

The way I find the length of a regular day is maybe not very accurate. I did it this way because the code is intended for use in a tick database that has limited data. But I will think about a better way.

For the rest our results are sometimes the same and sometimes there is a difference. I think mine is correct because I calculated some number manually. I am not sure exactly why there is a difference but I think is is due to how you handled the separator. How you remove the Sunday does not seem correct, maybe you can have a look at that. See chart below I calculate it for ndays = 3 1/10/22 @ES# at 3:55PM. The average volume 90562, which I manually verified:

>>> (87302 + 83659 + 100617 )/ 3
90526.0

in your chart it is off. It is due to the handling of Sundays imo.

es

my updated code adding your volume solution:

//SetBarsRequired( sbrAll );
bi = BarIndex();
ndays = Param( "Number of Days", 10, 1, 20, 1 );
disp = ParamToggle( "Display Stats", "Off|On", 1 );
selectseparator = ParamList( "Select Separator", "Time|Day|expandPoint", 1 );
findholidays = ParamList( "Find Holdidays", "Use Bars|Use Volume", 0 );
cutoff = Param( "Bars Cutoff Percentage", 8, 1, 20, 0.1 ); // a holiday (low vol day) has at least the cutoff% less bars than regular a day.
minvollevel = Param( "Low Volume Cutoff (%)", 50, 0, 100, 5 ) * 0.01; // a holiday (low vol day) has at least the minvollevel% less volume than a regular day.

// various ways to calculate the separator between trading days
if( selectseparator == "Time" )
{
    separator = TimeNum() >= 165900;
    separator = separator - Ref( separator, -1 );
    separator = IIf( Day() != Ref( Day(), -1 ) AND !( DayOfWeek() == 0 ), 0, separator );
    separator_day = Day() != Ref( Day(), -1 );
}
else
    if( selectseparator == "Day" )
    {
        separator = Day() != Ref( Day(), -1 ) AND DayOfWeek() != 0;// remove Sunday
        separator_day = Day() != Ref( Day(), -1 );
    }
    else
        if( selectseparator == "expandPoint" )
        {
            // version of Jorgen W., uses database time settings.
            // For CME use
            // Day 09:30 - 17:29, Night 17:30 - 09:29
            // compression Day/Night checked
            // First day of Week: Sunday
            separator = Ref( Nz( TimeFrameExpand( 1, inDaily, expandPoint ) ), -1 );
            separator_day = Day() != Ref( Day(), -1 );
        }

// correct number of days used if not available in database
maxdays = LastValue( Cum( separator ) ) - 1; // check if ndays are available in database
ndays = Min( ndays, maxdays );

// find the index of days that are holidays / half trading days based on the number of bars OR the volume
if( findHolidays == "Use Bars" )
{
	// find the length of a regular trading day
    delta_index_of_separator = ValueWhen( separator, bi, 1 ) - ValueWhen( separator, bi, 2 );
    ss = Sort( delta_index_of_separator, 0, -1, 0 );
    ss = ss[BarCount - 1]; // length regular trading days stored in ss
    holiday_index = IIf( ( ss - abs( ValueWhen( separator, bi, 1 ) - ValueWhen( separator, bi, 0 ) ) ) / ss * 100 > cutoff, 1, 0 );
    holiday_index = IIf( bi >= LastValue( ValueWhen( separator, bi ) ), 0, holiday_index ); // last day is not complete keep this day
}
else
    if( findholidays == "Use Volume" )
    {
        // code from alligator
        TimeFrameSet( inDaily );
        adv = AMA( V, 1 / ( ndays + 1 ) ); // average daily volume
        Tmp = Cum( 1 );
        LastDay = LastValue( Tmp ) == Tmp;
        regular_day = ( V >= minvollevel * adv ) OR LastDay; // criterium for low vol: minvollevel% of average
        TimeFrameRestore();
        holiday_index = !TimeFrameExpand( regular_day, inDaily, expandFirst );
    }

// exclude bars at the holiday_index using SparseCompress
volume_SparseCompress = SparseCompress( !holiday_index, V );
separator_SparseCompress = SparseCompress( !holiday_index, separator );

// add the volumes, creating the numerator
average_volume_array = 0;

for( i = 1; i <= ndays; i++ )
{
    // use regular BarIndex() bi
    delta_index_of_separator = ValueWhen( separator_SparseCompress, bi, 1 ) - ValueWhen( separator_SparseCompress, bi, ( i + 1 ) );
    average_volume_array = average_volume_array + Ref( volume_SparseCompress, -delta_index_of_separator ); // numerator
}

// calculate the average, dividing it by ndays
average_volume_array = SafeDivide( average_volume_array, ndays );

// expand the average
average_volume_array_SparseExpand = SparseExpand( !holiday_index, average_volume_array );

Plot( V, "True Volume", IIf( C > O, ParamColor( "Up Color", colorBlue ), ParamColor( "Down Color", colorRed ) ), styleHistogram, Null, Null, 0, 0, 3 );
Plot( IIf( separator, 1, Null ), "", ColorRGB( 0, 255, 255 ), styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -1, 1 );
Plot( average_volume_array_SparseExpand, "Average Volume over the previous " + ndays + " days", colorGold, styleStaircase | styleNoLabel, Null, Null, 0, 1, 1 );

if( selectseparator != "Day" )
{
    Plot( IIf( separator_day, 1, Null ), "", ColorRGB( 100, 100, 100 ), styleDashed | styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -1, 1 );
}

if( disp )
{
    lastsep = LastValue( ValueWhen( separator, bi ) );
    ymin = Status( "axisminy" );
    ymax = Status( "axismaxy" );
    dy = ymax - ymin;
    fvb = FirstVisibleValue( bi );
    lvb = LastVisibleValue( bi );
    delta_index_of_separator = ValueWhen( separator, bi, 1 ) - ValueWhen( separator, bi, 2 );
    dd = Day();
    mm = Month();
    yy = Year();
    dow = DayOfWeek();

    for( i = lvb; i > fvb; i-- )
    {
        if( ( separator[i] AND selectseparator == "Day" ) OR( separator_day[i] AND selectseparator != "Day" ) )
        {
            if( dow[i] == 0 )
                dowstr = "Sunday";

            if( dow[i] == 1 )
                dowstr = "Monday";

            if( dow[i] == 2 )
                dowstr = "Tuesday";

            if( dow[i] == 3 )
                dowstr = "Wednesday";

            if( dow[i] == 4 )
                dowstr = "Thursday";

            if( dow[i] == 5 )
                dowstr = "Friday";

            if( dow[i] == 6 )
                dowstr = "Saturday";

            holiday_status = "";

            if( holiday_index[i] AND bi[i] != lastsep )
            {
                holiday_status = "+++ Holiday +++";
                PlotTextSetFont( holiday_status, "Helvetica", 10, i + 4, ymax - dy / 3, colorGold, colorDefault, 0 );
            }
            else
                if( bi[i] != lastsep )
                {
                    holiday_status = "Regular Trading";
                }
                else
                    if( bi[i] == lastsep )
                    {
                        holiday_status = "Last Day";
                    }

            PlotTextSetFont( "" + delta_index_of_separator[i] + " bars", "Helvetica", 12, i - delta_index_of_separator[i] / 1.75, ymax - dy / 4, colorAqua, colorDefault, 0 );
            PlotTextSetFont( dowstr + ", " + mm[i] + "/" + dd[i] + "/" + yy[i], "Helvetica", 10, i + 4, ymax - dy / 4, colorGold, colorDefault, 0 );
        }
    }
}

3 Likes