Volume Price Distribution

Hello All,
I am trying to display (and then manipulate the data) of the VAP every month, for a one year data history.
I used the code from the documentation and try to adapt it, but I am stuck with different kind of errors.

//Code adapted from http://www.amibroker.com/guide/afl/pricevoldistribution.html
segment = Month();
segment = segment != Ref(segment, -1);

for( i = 300; i < BarCount; i++ )
{
   if( segment[ i ] ==1)
		mx = PriceVolDistribution( H, L, V, 50, False, i-240, i );
		bins = MxGetSize( mx, 0 );
		for( k = 0; k < bins; k++ ) 
			 { 
				price = mx[ k ][ 0 ]; // price level 
				relvolume = mx[ k ][ 1 ]; // relative volume 0..1 
				relbar = relvolume * (20); 
				GfxMoveTo( i, price ); 
				GfxLineTo( i + relbar, price ); 
			 } 

}

For now, I have the error that mx has not been initialized. I also tried different approach where I didn't not have a display every month as I wanted (though I had something)

//Code adapted from http://www.amibroker.com/guide/afl/pricevoldistribution.html

for( j = 300; j < BarCount; j++ )
{

	if( segment[j] == 1 )
		{
			fvb = j-240; 
			lvb = j;

			mx = PriceVolDistribution( H, L, V, 100, False, fvb, lvb ); 

			GfxSetCoordsMode( 1 ); 

			GfxSelectPen( colorBlue ); 

			bins = MxGetSize( mx, 0 );
 
			for( i = 0; i < bins; i++ ) 
				 { 
				price = mx[ i ][ 0 ]; // price level 
				relvolume = mx[ i ][ 1 ]; // relative volume 0..1 
				relbar = relvolume * (lvb-fvb + 1); 
				GfxMoveTo( fvb, price ); 
				GfxLineTo( fvb + relbar, price ); 
				 } 		
		
		}

}

image

I do not get why last years of 2020 are not plotted, and how to improve the plotting. Any help would be appreciated.
Thanks,

If you want to look back 240 bars every start of month (see your if statement) then you do not need to iterate BarCount at all. You just need to iterate number of months.

The code of below picture is 60 times faster then your upper one despite of being more code.
Also it plots properly as you can see.

Hint: when you iterate number of months see ValueWhen function.
Number of months: Use Cum() function and count number of months of visible chart.

18

1 Like

Hi,
I wanted to edit my previous post instead of deleting it... I'm noob.
Thanks fxshrat for your input, much appreciated.

Here is an updated version of the code. Thanks to fxshrat hints and help from this post from fxshrat (again :slight_smile: ): How to make this code that counts the number of times a certain event happened in the past more elegant?, I ended up with this code.

Could you have a quick look to check for obvious errors?
I am using: LastVisibleValue(ValueWhen(event, BarIndex(), i)); It seems to work, but is quite weird, is there a better way?
Last but not least, if I want to get nice rectangles as you have, is GfxFillSolidRect the way to go?
Thanks a lot for your help

// VAP every month with 240 days historical data. Ref: https://forum.amibroker.com/t/volume-price-distribution/23199/2
// code based on http://www.amibroker.com/guide/afl/pricevoldistribution.html and https://forum.amibroker.com/t/how-to-make-this-code-that-counts-the-number-of-times-a-certain-event-happened-in-the-past-more-elegant/14385/3
// Many thanks for fxshrat for his input!

event = Month();
event = event != Ref(event, -1);

event_number = LastVisibleValue(Cum(event));
//_TRACEF( "event_month value is = %g", event_number);

bi = BarIndex();

for ( i = 1; i < event_number; i++ )
{
	event_index = LastVisibleValue(ValueWhen(event, BarIndex(), i));
	
	//Below Code from http://www.amibroker.com/guide/afl/pricevoldistribution.html
	mx = PriceVolDistribution( H, L, V, 100, False, event_index  - 240, event_index ); 
	GfxSetCoordsMode( 1 ); 
	GfxSelectPen( colorBlue ); 
	bins = MxGetSize( mx, 0 );
	
	for( j = 0; j < bins; j++ ) 
		 { 
		price = mx[ j ][ 0 ]; // price level 
		relvolume = mx[ j ][ 1 ]; // relative volume 0..1 
		relbar = relvolume *5; 
		GfxMoveTo( event_index, price ); 
		GfxLineTo( event_index + relbar, price ); 
		 } 	
}

EDIT: picture of the current results, with Amibroker built in VAP of the last month to check for consistency:

image

I retract my previous statement.
Using ValueWhen is not better.

// VAP every month with 240 days historical data. Ref: https://forum.amibroker.com/t/volume-price-distribution/23199/2
// code based on http://www.amibroker.com/guide/afl/pricevoldistribution.html and https://forum.amibroker.com/t/how-to-make-this-code-that-counts-the-number-of-times-a-certain-event-happened-in-the-past-more-elegant/14385/3
// Many thanks for fxshrat for his input!

event = Month();
event = event != Ref(event, -1);

Plot( C, "Price", colorDefault, styleBar );

bv = Status("barvisible");

GfxSetCoordsMode( 1 ); 
GfxSelectPen( colorBlue ); 
for ( i = 0; i < BarCount; i++ )
{
	if ( event[i] && bv[i] ) 
	{	
		//Below Code from http://www.amibroker.com/guide/afl/pricevoldistribution.html
		mx = PriceVolDistribution( H, L, V, 100, False, i  - 240, i ); 		
		bins = MxGetSize( mx, 0 );
		
		for( j = 0; j < bins; j++ ) 
			{ 
			price = mx[ j ][ 0 ]; // price level 
			relvolume = mx[ j ][ 1 ]; // relative volume 0..1 
			relbar = relvolume *5; 
			GfxMoveTo( i, price ); 
			GfxLineTo( i + relbar, price ); 
			} 	
	}
}
3 Likes

Thanks for the updated piece of code.
I will now plot the distribution with histograms (i guess with GfxFillSolidRect ) and try to get Peaks and Troughs from the distribution.

Hello,
Thanks for the code. Using this I managed to write an AFL for intra day and weekly. I admire your coding. Thanks once again.

hi,
I am trying to get on the same screen the VAP distrib for weekly and daily data.
So I took the daily timeframe, plot it with the above formula, everything works fine.

If I use this code to plot the weekly data, I end up with an error (PriceVolDistributions all price in range are the same or Null). If I switch the timeframe selector, the code works fine.
I guess the TimeFrameSet(inWeekly) is not working the way I thought it would work.

Should I use TimeFrameSet ?

// rectangle height
bins = Param("Bins", 500, 3, 1000, 1);
pRecHeight = Param("Rectangle Height", 0.75, 0.10, 1, 0.05);
//RecHeight = (HighestVisibleValue(H) - LowestVisibleValue(L))/bins * pRecHeight;


TimeFrameSet(inWeekly); 
event = Month() % 3 == 0;

priceH = IIf( H == L, H + 0.01, H);

max_value = 0;

for ( i = 0; i < BarCount; i++ )
{
	if ( event[i] && bv[i] ) 
	{	
		//Below Code from http://www.amibroker.com/guide/afl/pricevoldistribution.html
		mx = PriceVolDistribution( priceH, L, V, bins, False, i - 50, i ); 
		mx = MxSortRows(mx, False, 0);
		
		mat_sort = MxSortRows(mx, False, 1);
		max_value[i] = mat_sort[0][0];	
		bins = MxGetSize( mx, 0 );
		
		compteur = 0;
		for( j = 0; j < bins; j++ ) 
			{ 
			
			price = mx[ j ][ 0 ]; // price level 
			relvolume = mx[ j ][ 1 ]; // relative volume 0..1 
			relbar = relvolume *3; 
			
			RecHeight = (mx[ bins -1][ 0 ] - mx[ 0 ][ 0 ]) / (bins-1) * pRecHeight; 

			// upper left corner of the rectangle.	
			x1 = i;
			y1 = price + RecHeight;
			// lower right corner of the rectangle.	
			x2 = i + relbar;
			y2 = price - RecHeight; 
			color = colorLightGrey;
			
			if( j > 2 AND j < bins - 2 )
			{
				if( 
				//mx[ j - 2 ][ 1 ] >= mx[ j - 1 ][ 1 ] 
				//AND 
				mx[ j - 1 ][ 1 ] >= mx[ j  ][ 1 ] 
				AND mx[ j  ][ 1 ] <= mx[ j + 1 ][ 1 ]
				AND mx[j][0] < C[i]
				AND compteur < 3
				//AND  mx[ j + 1 ][ 1 ] <= mx[ j + 2 ][ 1 ] 
				)
					{
					  color = colorRed;
					  compteur +=1;
					}
				else
					{
					  color = colorLightGrey;
					}
			}




			GfxFillSolidRect( x1, y1, x2, y2, color );
			} 	
	}
}

max_value = ValueWhen( max_value != 0, max_value );

TimeFrameRestore(); 

max_value = TimeFrameExpand(max_value,inWeekly,expandlast); 


Plot(max_value, "max_value", colorRed, styleLine | styleThick);

You are operating on compressed array so elements at start of array are Null.

start = Min(NullCount(C)+50, Barcount-1);
for ( i = start; i < BarCount; i++ )

Ok, thanks for the clarification.
I edi

In my previous code, there is one modifiation to make to plot it every 3 months (in case anyone is interested):

event = Month() % 3 == 0 AND Month()!= Ref(Month(), -1);

instead of

event = Month() % 3 == 0;

I still do not understand one element. On the first code version, depending of the zoom level, I have different results for the VAP distribution.
For exemple,
image

If I zoom in a little:
image

Redline being the POC (maximum volume for each profile plotted).
The code is supposed to be totally independent of the any zoom value (not last visible bar or anything like this), then I don't get why zoom would impact the Max of the volume profile in any way...

// VAP every month with 240 days historical data. Ref: https://forum.amibroker.com/t/volume-price-distribution/23199/2
// code based on http://www.amibroker.com/guide/afl/pricevoldistribution.html and https://forum.amibroker.com/t/how-to-make-this-code-that-counts-the-number-of-times-a-certain-event-happened-in-the-past-more-elegant/14385/3
// Many thanks for fxshrat for his input!

event = Month();
event = event != Ref(event, -1);
bv = Status("barvisible");
GfxSetOverlayMode( 1 );
GfxSetCoordsMode( 1 ); 

// rectangle height
bins = Param("Bins", 500, 3, 1000, 1);
pRecHeight = Param("Rectangle Height", 0.75, 0.10, 1, 0.05);
//RecHeight = (HighestVisibleValue(H) - LowestVisibleValue(L))/bins * pRecHeight;

max_value = 0;

for ( i = 0; i < BarCount; i++ )
{
	if ( event[i] && bv[i] ) 
	{	
		//Below Code from http://www.amibroker.com/guide/afl/pricevoldistribution.html
		mx = PriceVolDistribution( H, L, V, bins, False, 0, i ); 
		mx = MxSortRows(mx, False, 0);
		
		mat_sort = MxSortRows(mx, False, 1);
		max_value[i] = mat_sort[0][0];	
		size = MxGetSize( mx, 0 );
		
		compteur = 0;
		for( j = 0; j < size; j++ ) 
			{ 
			
			price = mx[ j ][ 0 ]; // price level 
			relvolume = mx[ j ][ 1 ]; // relative volume 0..1 
			relbar = relvolume *20; 
			
			RecHeight = (mx[ size -1][ 0 ] - mx[ 0 ][ 0 ]) / (size-1) * pRecHeight; 

			// upper left corner of the rectangle.	
			x1 = i;
			y1 = price + RecHeight;
			// lower right corner of the rectangle.	
			x2 = i + relbar;
			y2 = price - RecHeight; 
			color = colorLightGrey;
			
			if( j > 2 AND j < size - 2 )
			{
				if( 
				//mx[ j - 2 ][ 1 ] >= mx[ j - 1 ][ 1 ] 
				//AND 
				mx[ j - 1 ][ 1 ] >= mx[ j  ][ 1 ] 
				AND mx[ j  ][ 1 ] <= mx[ j + 1 ][ 1 ]
				AND mx[j][0] < C[i]
				AND compteur < 3
				//AND  mx[ j + 1 ][ 1 ] <= mx[ j + 2 ][ 1 ] 
				)
					{
					  color = colorRed;
					  compteur +=1;
					}
				else
					{
					  color = colorLightGrey;
					}
			}




			GfxFillSolidRect( x1, y1, x2, y2, color );
			} 	
	}
}

max_value = ValueWhen( max_value != 0, max_value );

Plot(max_value, "max_value", colorRed, styleLine | styleThick);

Your startbar is zero.

mx = PriceVolDistribution( H, L, V, bins, False, 0, i ); 

So of course results will be different at different zoom levels since QuickAFL is applied.
Reading entire Knowledge base is mandatory advice.

Thanks. I read about quick AFL already, but didn't make the link (not skilled enough).
Really appreciate your help

Hi,

I am trying to plot volume at exact price, not distribution. I took inspiration from various codes mentioned in this post. The error I am getting is also mentioned below. My matrix variable is holding correct values as in quote editor. Please suggest me where is the mistake?.

SetBarsRequired(sbrAll,sbrAll);

bi=BarIndex();
styl=ParamStyle("Line Style",styleStaircase,maskAll);
Camarcol=ParamColor("Line Color",colorYellow);
Show=ParamToggle("Show Values","No|YES",0);


mode=0;H1=0;L1=0;

{
MB=Day()!=Ref(Day(),-1);
ME=Day()!=Ref(Day(),1);
H1=ValueWhen(MB,Ref(HighestSince(MB,C,0),-1));
L1=ValueWhen(MB,Ref(LowestSince(MB,C,0),-1));
Plot(IIf(ME,1,Null),"",colorYellow,styleHistogram|styleOwnScale|styleThick,0,1);
stbar=ValueWhen(mb,bi);
enbar=ValueWhen(me,bi);
nobars=BarsSince(mb);
event =Day();
event =Day()!=Ref(Day(),1);
Hv=ValueWhen(event,HighestSince(Day()!=Ref(Day(),-1),C,1));
Lv=ValueWhen(event,lowestSince(Day()!=Ref(Day(),-1),C,1));

}

Plot(H1,"H1",Camarcol,styl);
Plot((H1+L1)/2,"Mid",colorBlue,styl);
Plot(L1,"L1",Camarcol,styl);

GfxSetZOrder(-3);
GfxSetZOrder(zord);


// VAP every month with 240 days historical data. Ref: https://forum.amibroker.com/t/volume-price-distribution/23199/2
// code based on http://www.amibroker.com/guide/afl/pricevoldistribution.html and https://forum.amibroker.com/t/how-to-make-this-code-that-counts-the-number-of-times-a-certain-event-happened-in-the-past-more-elegant/14385/3
// Many thanks for fxshrat for his input!
mxvol[0]=0;maxvol[0]=0;Volpoc[0]=0;k=0;Volpocv[0]=0;VPP[0]=0;VPV[0]=0;fiba=0;enba=0;
cnt=0;
bv = Status("barvisible");
GfxSetCoordsMode( 1 ); 
GfxSelectPen( Volcol ); 

function DSVolPro(startbar,endbar)
	{

	nobs=endbar-startbar;//number of bars in a period
	dsmatrix=Matrix(nobs,2,Null);// close and volume
	for(n=startbar;n<endbar;n++)
		{
		//_TRACE("Counter = "+n);
		dsmatrix[n][0]=C[n];
		dsmatrix[n][1]=V[n];
		}
		
		totvol=0;
		for(n=startbar;n<endbar;n++)
		{
		totvol=totvol+dsmatrix[n][1];
		}
		for(n=startbar;n<endbar;n++)
		{
		dsmatrix[n][1]=(dsmatrix[n][1]/totvol)*100;
		}
		
	return dsmatrix;
	}	


for ( i = 0; i<BarCount; i++ )
{
	if(i==0 || stbar[i])
		{
		fiba[i]=bi[i];
		}
		else
		{
		fiba[i]=fiba[i-1];
		}
		if(i==BarCount-1 || enbar[i])
		{
		enba[i]=bi[i];
		}
		
	
	if ( (event[i] && bv[i])   ) 
	{	enba[i]=enbar[i];
		x=(hv[i]-lv[i]);
		//enbar[i]=cnt-1;

		maxivol=0;chkvol=0;totvol=0;
		
		
		mx=DSVolpro(i-(enba[i]-fiba[i]),i+1);
		grlen=(enba[i]=fiba[i])/3;
		bins = MxGetSize( mx, 0 );
		for(j=0;j<bins;j++)
		{
		totvol=totvol+mx[j][1];
		}
		for( j =0; j <bins; j++ ) 
			{ 
			
			price = mx[ j ][ 0 ]; // price level 
			relvolume = mx[ j ][ 1 ]; // relative volume 0..1 
			maxivol=Max(maxivol,relvolume);
			
			relbar = (relvolume) *grlen; 
			GfxMoveTo(i-(enbar[i]-stbar[i]), price ); 
			//GfxMoveTo(enba[i], price ); 
			GfxLineTo( i-(enbar[i]-stbar[i]) + relbar, price ); 
			//GfxLineTo( enba[i] + relbar, price ); 
			_TRACE("Event = "+price);	
			}
		
	}
	
	if ( i==BarCount-1  ) 
	{	
		

		maxivol=0;chkvol=0;totvol=0;
		enba[i]=bi[i];

		xx=NullCount(fiba,3);
		fiba[i]=IIf(NullCount(fiba,3)>=enba[i],0,fiba[i]);
		mx=DSVolpro(i-(i-fiba[i]),i+1);
		grlen=(enba[i]-fiba[i])/3;
		bins = MxGetSize( mx, 0 );
		_TRACE("matrix = "+MxToString(mx));	
		
		for( j =0; j <bins; j++ ) 
			{ 
			
			price = mx[ j ][ 0 ]; // price level 
			relvolume = mx[ j ][ 1 ]; // relative volume 0..1 
			maxivol=Max(maxivol,relvolume);
			
			relbar = (relvolume) *grlen; 
			//GfxMoveTo(i-(enbar[i]-stbar[i]), price ); 
			GfxMoveTo(i-(enba[i]-fiba[i]), price ); 
			//GfxMoveTo(enba[i], price ); 
			//GfxLineTo( i-(enbar[i]-stbar[i]) + relbar, price ); 
			GfxLineTo( i-(enba[i]-fiba[i]) + relbar, price ); 
			//GfxLineTo( enba[i] + relbar, price );
			_TRACE("End Bar = "+price);	
			}
		
	}
	
}


RequestTimedRefresh(1,True);

image

  1. You assume that matrix size would be equal to barcount length. That's why you get error because it is not the case. So (some of your) error(s) are in that function DSVolPro as your loops are incorrect.
  2. Your function DSVolPro (with your incorrect loops) does not require any looping code at all. So instead you should replace them.
  3. There are other flaws in your entire code in addition.... (but I only commented about reason of the error you got)
1 Like

Thank you fxshrat for your reply. I tried entire day tweaking the code but in vain. Let me explain my idea. Plotting volume at exact close price with 1 minute intra day data. Graph plotting to start (Gfxhmoveto) from at the end of the day bar of previous day and to be extended up to 1/3 or 1/2 of the length of the day (Gfxlineto). First bar is day() != ref(day(),-1) and last bar is day != ref(day(),1) for a completed day. And for current day (for live data) first bar is day() != ref(day(),-1) and last bar is the bar that is updating. How to extract the data.
I managed with the help of your previous post (post 4) by replacing pricevolumedistribution with below code.

mx = PriceVolDistribution( C, C-0.0000000000000001, V, x/0.05, False, i-(enbar[i]-stbar[i]), i );
//where enbar is last bar of the day and stbar is first bar of the day
// x is difference between (highest close of the day - (minus) lowest close of the day)/tick size

And the result is below chart
image
Is all of my efforts are in right way?. I would be very thankful for your valuable suggestions.

Hi fxshrat
I have successfully plotted volume at exact close. Now my task is to add the volume of the same price points in intraday. Your various code snippets in the forum helped me to learn a lot.
I have registered in proboards only to follow your posts. Thanks once again.

Hello @fxshrat
Below is the image of volume price distribution in intra day. I thank @swalsh for his code on volume price distribution. I used C>O for bullbar and C<O for bearbar . Please suggest what will be the better alternative for deciding bull volume or bear volume in intraday.
image

@appasri: can you link the code of swalsh please? EDIT: found it: How to get the values of PriceVolDistribution() bins using gfxTextOut or exploration or in title
May I ask you what data feed you are using for intraday?
What are the lines you are drawing on the graph?
Thanks :slight_smile:

Hello @JeanChristophe
The data is NSE of India provided by a authorized vendor. I am inspired by @fxshrat post at proboards and I used @swalsh code as mentioned in the link of your above post . The bars are volume price distribution in intraday. Please verify @fxshrat post volume at price buying and selling at proboards. It looks very nice compared to my above screenshot.

Here is another one

This topic was automatically closed 100 days after the last reply. New replies are no longer allowed.