I do something similar, but use the average of the past 30 days instead of the prior day. Perhaps this will help anyway.

I prefer to see the intraday volume in an unconventional manner. In the 5-minute chart below, each bar is the cumulative volume for that day. The black portion of the bar represents that bar's volume. The light gray portion represents the cumulative volume prior to the current bar. The blue line represents the moving average (EMA) of the past 30 days. In the title, the relative volume is expressed as a factor of the average; in this case it was 1.8x at the end of the day which you could probably eyeball from the chart.

There is probably more code here than you will actually want. Calculating these averages is very slow, so I created code to save the average volume as a composite, so that it does not get calculated on every chart refresh. When working with a 1-minute DB with 24h filtering, it can take a few seconds to calculate.

Also, a big assumption in this code is that the bars are aligned to the same time every day (e.g. bar #1 of the day is always at 7:00AM), which is not accurate because some symbols trade at different times on different days of the week (outside of regular market hours, that is). I adapted code from http://www.amibroker.com/members/library/detail.php?id=1406 and that's the approach that was taken by stevencarr2 at that time, and I rolled with it.

```
// Intraday Cumulative Relative Volume
// AFL by Peter Deal
// @Link https://forum.amibroker.com/t/intraday-cumulative-volume/22127
// Commercial use prohibited
EnableTextOutput( 0 );
Version( 6.30 );
Intrvl = Interval( 0 );
IntraDay = Intrvl < inDaily;
Symbol = Name();
NewDay = Day() != Ref( Day(), -1 );
//V = V * 100; // My personal preference is for IBKR volume to be multiplied by 100 to match other data providers.
function IntraCumVol( VolMADays )
{
// Returns intraday cumulative volume if Interval < inDaily, or just daily volume if >= inDaily.
if( Intrvl < inDaily )
{
nd = NewDay;
FirstBarVolume = ValueWhen( nd, V, 1 ); // Need to add this to running total because SumSince starts summing one bar after the true condition.
Output = SumSince( nd, V ) + FirstBarVolume;
}
else Output = V;
return Output;
}
function CalcIntraCumAvgVol( VolMADays )
{
// Returns intraday cumulative average (EMA) volume over VolMADays.
// Adapted from http://www.amibroker.com/members/library/detail.php?id=1406
// Puts the average in a composite for future use because this is a slow function.
// This code assumes that every day has the same number of bars, which is not true for some
// symbols using 24h filtering, and also holidays when the market closes early.
// The number of bars in the average composite will not necessarily be aligned to the number
// of bars in the following days, so this function is an approximation at best.
HasVolume = LastValue( TimeFrameGetPrice( "V", inDaily, -1 ) > 0 );
BarNum = BarsSince( NewDay );
NumBars = LastValue( highest( BarNum ) ) + 1;
Multiplier = ( 2 / ( VolMADays + 1 ) );
for( i = 0; i < NumBars; ++i )
{
Ksf = IIf( i == BarNum, Multiplier, 0 );
VarSet( "AvgVol_" + Symbol + "_" + NumBars + "_" + i, AMA( IntraCumVol( VolMADays ), Ksf ) ) ;
}
AvgVol = 0;
for( i = 0; i < NumBars; ++i )
{
AvgVol = IIf( i == BarNum, VarGet( "AvgVol_" + Symbol + "_" + NumBars + "_" + i ), AvgVol );
}
StaticVarRemove( "AvgVol_" + Symbol + "_" + NumBars + "_" + i );
AddToComposite( AvgVol, "~CumVolEMA_" + Symbol + "_" + VolMADays + "_" + Intrvl, "V", atcFlagDeleteValues | atcFlagEnableInExplore | atcFlagCompositeGroup | atcFlagEnableInIndicator ); // atcFlagResetValues | atcFlagCompositeGroup | atcFlagEnableInExplore | atcFlagEnableInIndicator |
Output = AvgVol;
return Output;
}
function IntraCumAvgVol( VolMADays )
{
// If intraday, returns the average intraday cumulative volume, including the current day's volume,
// so it needs to be recalculated when new bars are printed. Recalculates automatically when it detects
// missing data, however it does not recalculate automatically when filtering is changed.
// If not intraday, returns simple MA of daily volume.
// See notes on CalcIntraCumAvgVol().
if( Intraday )
{
HasVolume = LastValue( TimeFrameGetPrice( "V", inDaily, -1 ) > 0 );
if( HasVolume )
{
AvgVol = Foreign( "~CumVolEMA_" + Symbol + "_" + VolMADays + "_" + Intrvl, "V" );
NotCalculated = IIf( Status( "action" ) <= 2 AND IsNull( FirstVisibleValue( AvgVol ) ), 1, 0 );
NewData = IIf( LastValue( AvgVol ) == 0, 1, 0 );
Dn = DateNum();
MissingCalc = 0;
for( i = 1; i < BarCount; i++ )
{
if( AvgVol[i] == 0 AND // AvgVol is zero on this bar.
AvgVol[i-1] != 0 AND // On the prior bar, it was not zero.
Dn[i] == Dn[i-1] ) // It is the same day on both bars.
{
MissingCalc = 1;
}
}
NeedsRecalc = NotCalculated OR NewData OR MissingCalc;
if ( NeedsRecalc )
{
AvgVol = CalcIntraCumAvgVol( VolMADays );
}
Output = HighestSince( NewDay, AvgVol, 1 );
Output = AvgVol;
}
else
{
Output = Null;
}
}
else
{
Output = Ref( MA( V, VolMADays ), -1 );
}
return Output;
}
_SECTION_BEGIN( "Intraday volume EMA" );
// Plots intraday cumulative volume and average intraday cumulative volume.
// Pulls prior day average from composite to save time.
// If prior day composite is zero, it recalculates the composite.
// If chart is daily, it just shows daily volume and average of past days.
// If volume is not reported for this symbol, does nothing.
// See notes in CalcIntraCumAvgVol() regarding accuracy of this plot.
VolMADays = Param( "Volume MA days", 30, 1, 270, 1 );
Vol = IntraCumVol( VolMADays );
AvgVol = IntraCumAvgVol( VolMADays );
if( Intraday )
{
VolTitle = "Intraday cumulative volume";
Plot( Vol - V, "IntraCumVol", colorLightGrey, styleHistogram | styleNoLabel | styleNoTitle, 0, Null, Null, Null, 3 );
}
else
{
VolTitle = "Volume";
}
RelVol = SafeDivide( Vol, AvgVol, 0 );
Title = StrFormat( "{{NAME}} - " + VolTitle + " - {{VALUES}} - RelVol %.1fx", RelVol );
Plot( Vol, "Volume", colorBlack, styleHistogram, 0, Null, Null, Null, 3 );
Plot( AvgVol, "AvgVol", colorBlue, styleLine, 0, Null, Null, 1 );
_SECTION_END();
```

I hope this helps.

Peter