# How to get the values of PriceVolDistribution() bins using gfxTextOut or exploration or in title

Can any one tell me how to get the value of this five bins

``````

bi = BarIndex();
fvb = Max( 0, FirstVisibleValue( bi ) );
lvb = Max( 0, LastVisibleValue( bi ) );

PYO = TimeFrameGetPrice("O", indaily,0 );
PYH = TimeFrameGetPrice("H", indaily,0 );
PYL = TimeFrameGetPrice("L", indaily,0 );
PYC = TimeFrameGetPrice("C", indaily,0 );

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

GfxSetCoordsMode( 1 );

GfxSelectPen( colorRed );

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 );
}

Plot(c ,"",colorGreen,styleLine);

Plot( C, "Price", colorDefault, styleBar );
SetChartOptions( 0, chartShowDates );
``````

@sandy the result of PriceVolDistribution() is a matrix.

So the easiest way to inspect the values of the bins is to use the MxToString() function, like in the following snippet (to be added to your code):

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

s = mxToString( mx );
// debug log
_TRACE( s );
// output / intepretation
printf( s );

// gfx
wd = Status( "pxchartwidth" );
hg = Status( "pxchartheight" );
// remove the braces to make it more readable
s = StrReplace( StrReplace( mxToString( mx ), "{", "" ), "}", "" );
GfxSelectFont( "Tahoma", 16, 600 );
GfxSetBkMode( 1 );
GfxSetTextColor( colorOrange );
GfxDrawText( s, 0, 20, wd, hg );
``````

Obviously, you can also simply "print" the values of the variables "price" and "relvolume" in your loop that is accessing the individual matrix elements.

2 Likes

thanks beppe, iam looking this for backtesting purpose and iam getting two comma separated values
what i need is previous days 3 bins with price

``````

bi = BarIndex();
fvb = Max( 0, FirstVisibleValue( bi ) );
lvb = Max( 0, LastVisibleValue( bi ) );

PYO = TimeFrameGetPrice("O", indaily,-1 );
PYH = TimeFrameGetPrice("H", indaily,-1 );
PYL = TimeFrameGetPrice("L", indaily,-1 );
PYv = TimeFrameGetPrice("v", indaily,-1 );

mx = PriceVolDistribution( PYH, pyL, pyV,5 , False, fvb, lvb );

s = mxToString( mx );
// debug log
_TRACE( s );
// output / intepretation
printf( s );

// gfx
wd = Status( "pxchartwidth" );
hg = Status( "pxchartheight" );
// remove the braces to make it more readable
s = StrReplace( StrReplace( mxToString( mx ), "{", "" ), "}", "" );
GfxSelectFont( "Tahoma", 16, 600 );
GfxSetBkMode( 1 );
GfxSetTextColor( colorOrange );
GfxDrawText( s, 0, 20, wd, hg );
//Plot(c ,"",colorGreen,styleLine);

Plot( C, "Price", colorDefault, styleBar );
SetChartOptions( 0, chartShowDates );
``````

@Sandy, please, review the documentation of the PriceVolDistribution() function.

If you need to see a distribution for the last few days, you should change your code accordingly.

Play a little with this modified snippet (where I also added some user-defined param to show the different results you get using the "absolute" vs. the "relative" parameter) and to change the bins and bar range to include (either using visible bars or the last few bars).

``````
// The absolute parameter decides whenever returned volumes are absolute sum or relative (0...1) values.
absoluteMode = ParamToggle( "Print Volume values as", "Relative|Absolute", 0 );
numBins = Param( "Number of bins", 7, 2, 10, 1 );
lbBars  = Param( "Number of lookback bars", 10, 2, 50, 1 );
lastBarsMode = ParamToggle( "Distribution matrix on", "Visible Bars|Last bars", 0 );
vapColor = ParamColor( "Color used for text and VAP lines", colorGold );

if( lastBarsMode )
SetBarsRequired( sbrAll, sbrAll );

bi = BarIndex();

if( lastBarsMode ) // the calculation is done based on the last bars
lvb = LastValue( bi );
else              // the calculation is done based on the visible bars
lvb = LastVisibleValue( bi );

fvb = Max( 0, lvb - ( lbBars - 1 ) );

// calculate the Volume distribution in the selected mode
mx = PriceVolDistribution( H, L, V, numBins, absoluteMode, fvb, lvb );
bins = MxGetSize( mx, 0 );

// additional loop used to calculate the absolute percentages / total volume
totVolume = 0;
totPercent = 0;

for( i = 0; i < bins; i++ )
{
if( absoluteMode )
{
absVolume = mx[ i ][ 1 ];
totVolume += absVolume;
}
else
{
relPercent = mx[ i ][ 1 ]; // relative volume in a range 0..1
totPercent += relPercent;
}
}

// Low-level printout of values
GfxSelectFont( "Tahoma", 10 );
GfxSetBkMode( 1 );
GfxSetTextColor( vapColor );
lc = 1; // line counter used to calculate the y coordinate

for( i = 0; i < bins; i++ )
{
// Print Price level
price     = mx[ i ][ 0 ]; // price level
s = StrFormat( "%02.0f - Price: %2.2f", i + 1, price );
GfxTextOut( s, 10, 20 * lc );
lc++;

// Print corresponding Volume
if( absoluteMode )
{
absVolume = mx[ i ][ 1 ]; // this is zero for absolute mode when volume data is zero
pctVolume = IIf( totVolume == 0, 0, absVolume / totVolume );
s = StrFormat( "%02.0f - Volume: %1.0f (%2.2f%%)", i + 1, absVolume, pctVolume * 100 );
GfxTextOut( s, 10, 20 * lc );
}
else
{
relVolume = mx[ i ][ 1 ]; // relative volume in a range 0.1 - multiply it by 100 to get %
// treat {empty} values as zero
relVolume = IIf( relVolume, relVolume, 0 );
totPercent = IIf( totPercent, totPercent, 0 );
absPercent = IIf( totPercent == 0, 0, relVolume / totPercent );
s = StrFormat( "%02.0f - Rel. Volume: %2.2f%% - Absolute %2.2f%%", i + 1, relVolume * 100, absPercent * 100 );
GfxTextOut( s, 10, 20 * lc );
}

lc++;
}

if( absoluteMode )
GfxTextOut( StrFormat( "-- Total Volume: %1.0f", totVolume ), 10, 20 * lc );

// Plot the "relative" distribution matrix, as per the examples
// To make it simple recalculate it, if needed, with relative parameter
if( absoluteMode )
mx = PriceVolDistribution( H, L, V, numBins, false, fvb, lvb );

GfxSelectPen( vapColor );
GfxSetCoordsMode( 1 );
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 );
}

Plot( C, "Price", colorDefault, styleCandle );
SetChartOptions( 0, chartShowDates );

``````

It is not clear to me how you may use these values in your strategies, but I hope the example will give you some hints to go ahead.

In any case, there are (at least) a couple of previous threads where the PriceVolDistribution() function is used in a very clever way (I recommend you to study the supplied code):

11 Likes

i will look it in deep , and i like the way you put the code

Building on Tomasz Janeczko, Anderson Wilson and Beppe's code and ideas, I came up with the following AFL that shows the percentage of volume in the various rectangles representing the close in the candle thirds. Select the range required for the VAP by double clicking on the chart for your desired start and end candle. Double click on the blank region (right) to revert to all visible bars.

Here is the AFL:

``````/*
Author: Anderson Wilson, Beppe, Steve Walsh
based on PriceVolDistribution demo written by Tomasz Janeczko

Volume-by-Price is an indicator that shows the amount of volume for a particular price range,
The Volume-by-Price bars are horizontal and shown on the left side of the chart to correspond
with these price ranges. Bar colors indicate Bull (SeaGreen) / Bear (Custom16) / Total (Grey40) volume
Use double click to define range.
*/
SetChartOptions( 0, chartShowArrows | chartShowDates );
GraphXSpace = 15;
//
Plot( C, "", colorAqua, styleCandle );
Title = GetFnData( "Alias" ) + " - " + StrFormat( "{{FULLNAME}} - {{INTERVAL}}: {{DATE}}, VAP Absolute Values, Open %g, Hi %g, Lo %g, Close %g (%.1f%%), Vol(mil) %.2f (%.0f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ),  V / 1000000, SelectedValue( ROC( V, 1 ) ) );
//
bi = BarIndex();
fvb = BeginValue( bi );
lvb = EndValue( bi );

if( fvb == 0 && lvb == LastValue( bi ) )
{
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );
}

fvb = Max( 0, fvb );
lvb = Max( 0, lvb );

bins = Param( "Bins", 10, 3, 100, 1 );
pRecHeight = Param( "Rectangle Height", 0.90, 0.10, 1, 0.05 );

BullBearZone = ( High - Low ) / 3;
bullbar = C > ( High - BullBearZone );
bearbar = C < ( Low + BullBearZone );

// mx = [row 0][col 0]
// price levels in first column [0][0] and relative volume at that level in second column [0][1]
// https://www.amibroker.com/guide/afl/pricevoldistribution.html
mx = PriceVolDistribution( H, L, V, bins, True, fvb, lvb );
mx1 = PriceVolDistribution( H, L, IIf( bullbar, V, 0 ), bins, True, fvb, lvb );
mx2 = PriceVolDistribution( H, L, IIf( bearbar, V, 0 ), bins, True, fvb, lvb );

bins = MxGetSize( mx, 0 );
bins1 = MxGetSize( mx1, 0 );
bins2 = MxGetSize( mx2, 0 );

GfxSetOverlayMode( 1 );
GfxSetCoordsMode( 1 );

if( bins > 1 && bins == bins1 && bins == bins2 )
{

MaxVolume = mx[ 0 ][ 1 ];

// find max volume
for( i = 1; i < bins; i++ )
{
if( mx[ i ][ 1 ] > MaxVolume )
MaxVolume = mx[ i ][ 1 ]; // Volume for that bin 1...

//printf( "mx=%g", MaxVolume / 100000 );
}

// rectangle height
RecHeight = ( mx[ 1 ][ 0 ] - mx[ 0 ][ 0 ] ) / 2 * pRecHeight;
GfxSelectFont( "Arial", 7 ); // Change the text size here

for( i = 0; i < bins; i++ )
{
// mx1 = Bull
price = mx1[ i ][ 0 ]; // price level
absVolume = mx1[ i ][ 1 ];
VolAcum = absVolume;
relvolume = absVolume / MaxVolume;
relbar = relvolume * ( lvb - fvb + 1 );
// upper left corner of the rectangle.
x1 = fvb;
y1 = price + RecHeight;
// lower right corner of the rectangle.
x2 = fvb + relbar;
y2 = price - RecHeight;
bullColor = ColorBlend( colorSeaGreen, GetChartBkColor(), 0.2 );
GfxFillSolidRect( x1, y1, x2, y2, bullColor );
GfxSetBkColor( bullColor );
GfxSetTextColor( colorBrightGreen );
GfxTextOut( NumToStr( round( relvolume * 100 ), 2.0 ) + "%", x1, y1 );

// mx2 = Bear
absVolume = mx2[ i ][ 1 ];
VolAcum += absVolume;
relvolume = absVolume / MaxVolume;
relbar2 = relvolume * ( lvb - fvb + 1 );
x1 = x2;
x2 = x1 + relbar2;
bearColor = ColorBlend( colorCustom16, GetChartBkColor(), 0.2 );
GfxFillSolidRect( x1, y1, x2, y2, bearColor );
GfxSetBkColor( bearColor );
GfxSetTextColor( colorRed );
GfxTextOut( NumToStr( round( relvolume * 100 ), 2.0 ) + "%", x1, y1 );

// mx = All Bars
absVolume = mx[ i ][ 1 ];
relvolume = ( absVolume - VolAcum ) / MaxVolume;
relbar3 = relvolume * ( lvb - fvb + 1 );
x1 = x2;
x2 = x1 + relbar3;
midColor = ColorBlend( colorGrey40, GetChartBkColor(), 0.2 );
GfxFillSolidRect( x1, y1, x2, y2, midColor );
GfxSetBkColor( midColor );
GfxSetTextColor( colorBlack );
GfxTextOut( NumToStr( round( relvolume * 100 ), 2.0 ) + "%", x1, y1 );
}
}

``````
16 Likes

Thanks to all the authors.

Also appreciate the efforts put by @swalsh .

Just , I would like to request all the experts : please briefly describe how to interprete the chart, especially the coloured horizontal volume bars

Hi Santy. The horizontal bars represent volume at a particular price. The longer the bar (all three colors) the more volume at that price. The longest bar is the most traded price. You will note that the longest bar's percentages add up to approximately 100% (some variation due to rounding). Shorter bars are relative to the longest bar. This gives you a good indication of possible support and resistance at the boundaries of the bars - particularly the longest. You can change the number of bins to increase/decrease them. You can also double click on your chart to set the first and last bars to be included in the indicator. Double click on the blank area to the right to reset to the default.

The different bar colors are an indication of the volume in relation to the close at the price bar. The price bar is divided into three areas. If the volume is associated with a close at the top 1/3 of the bar it is colored green. If the close is in the lower third, the associated volume is red. For volume where the close is in the middle of the bar the volume is grey.

This indicator is actually a combination of VPA (Volume Price Analysis) and a VSA (Volume Spread Analysis). It provides a bit more information than the classic PlotVAPOverlayA built into AmiBroker which only gives VPA.

2 Likes

For more of a discussion around VSA and VPA see this link: VSA and VPA

Another good link on VSA: VSA Overview

2 Likes

Here are two practical examples (both using weekly data).

The theory behind the VSA (green and red bars) is that demand (buying) tends to lift the closing price into the upper third of the candles (green), while selling tends to lower the closing price into the lower third of the candles (red).

Example 1 - Accumulation Phase

There is broad agreement (equilibrium) between close in upper and lower thirds of the candle for much of the accumulation phase, which lasts one year. Below and above this equilibrium area, the close is in the upper third of the candle suggesting that buying predominates over selling. The ideal would be to go long perhaps with a limit order below the lower border of the equilibrium. This could be easier to spot on a daily chart.

Example 2 - Mark Down

There is equilibrium between the close in the upper and lower thirds of the candles at the top of the traded range. The bottom of the equilibrium forms the resistance level for subsequent prices. There is a partial equilibrium in the middle of the mark down phase - probably due to covering shorts. Prices fall further with a predominance of closes in the lowest third of the candles. The lower equilibrium area is not clearly defined on the weekly chart but occurs in the region of the arrow between the bars. This also marks the area of lower support.

Your feedback would be greatly appreciated.

6 Likes

Nice one i have some few questions
i had changed this to one day
fvb is first bar
lvb is the current candle
and i tried to plot for all dates and failed

``````_SECTION_BEGIN("PriceVolDistribution demo written");
/*
Author: Anderson Wilson, Beppe, Steve Walsh
based on PriceVolDistribution demo written by Tomasz Janeczko

Volume-by-Price is an indicator that shows the amount of volume for a particular price range,
The Volume-by-Price bars are horizontal and shown on the left side of the chart to correspond
with these price ranges. Bar colors indicate Bull (SeaGreen) / Bear (Custom16) / Total (Grey40) volume
Use double click to define range.
*/
SetChartOptions( 0, chartShowArrows | chartShowDates );
GraphXSpace = 15;
//
Plot( C, "", colorAqua, styleCandle );
Title = GetFnData( "Alias" ) + " - " + StrFormat( "{{FULLNAME}} - {{INTERVAL}}: {{DATE}}, VAP Absolute Values, Open %g, Hi %g, Lo %g, Close %g (%.1f%%), Vol(mil) %.2f (%.0f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ),  V / 1000000, SelectedValue( ROC( V, 1 ) ) );
//

Yo = TimeFrameGetPrice("o", inDaily,-1);
Yesterdayclose= TimeFrameGetPrice("c", inDaily,-1);

dn = Day();
BI = BarIndex();

newDay = dn != Ref( dn, -1 ); // New Day, not needed just here for clarification/illustration
pdfb = LastValue(ValueWhen(NewDay, bi, 2)); // first bar of previous day
LastBarYesterday = dn != Ref( dn, 1 ); // Yesterday's last bar (you are using intra-day data)

//fvb = ValueWhen( newDay, pdfb ); // value of the Bar Index on that bar
fvb = ValueWhen( newDay, bi ); // value of the Bar Index on that bar
fvb = LastValue( fvb );
lvb = LastValue( bi );
//lvb = ValueWhen(newDay, LastBarYesterday );
//Lvb = LastValue(lvb  );

//pdfb = LastValue(ValueWhen(NewDay, bi, 2)); // first bar of previous day
//LastBarYesterday = dn != Ref( dn, 1 ); // Yesterday's last bar (you are using intra-day data)

fvb = Max( 0, fvb );
lvb = Max( 0, lvb );

bins = Param( "Bins", 10, 3, 100, 1 );
pRecHeight = Param( "Rectangle Height", 0.90, 0.10, 1, 0.05 );

BullBearZone = ( High - Low ) / 3;
bullbar = C > ( High - BullBearZone );
bearbar = C < ( Low + BullBearZone );

// mx = [row 0][col 0]
// price levels in first column [0][0] and relative volume at that level in second column [0][1]
// https://www.amibroker.com/guide/afl/pricevoldistribution.html
mx = PriceVolDistribution( H, L, V, bins, True, fvb, lvb );
mx1 = PriceVolDistribution( H, L, IIf( bullbar, V, 0 ), bins, True, fvb, lvb );
mx2 = PriceVolDistribution( H, L, IIf( bearbar, V, 0 ), bins, True, fvb, lvb );

bins = MxGetSize( mx, 0 );
bins1 = MxGetSize( mx1, 0 );
bins2 = MxGetSize( mx2, 0 );

GfxSetOverlayMode( 1 );
GfxSetCoordsMode( 1 );

if( bins > 1 && bins == bins1 && bins == bins2 )
{

MaxVolume = mx[ 0 ][ 1 ];

// find max volume
for( i = 1; i < bins; i++ )
{
if( mx[ i ][ 1 ] > MaxVolume )
MaxVolume = mx[ i ][ 1 ]; // Volume for that bin 1...

//printf( "mx=%g", MaxVolume / 100000 );
}

// rectangle height
RecHeight = ( mx[ 1 ][ 0 ] - mx[ 0 ][ 0 ] ) / 2 * pRecHeight;
GfxSelectFont( "Arial", 7 ); // Change the text size here

for( i = 0; i < bins; i++ )
{
// mx1 = Bull
price = mx1[ i ][ 0 ]; // price level
absVolume = mx1[ i ][ 1 ];
VolAcum = absVolume;
relvolume = absVolume / MaxVolume;
relbar = relvolume * ( lvb - fvb + 1 );
// upper left corner of the rectangle.
x1 = fvb;
y1 = price + RecHeight;
// lower right corner of the rectangle.
x2 = fvb + relbar;
y2 = price - RecHeight;
bullColor = ColorBlend( colorSeaGreen, GetChartBkColor(), 0.2 );
GfxFillSolidRect( x1, y1, x2, y2, bullColor );
GfxSetBkColor( bullColor );
GfxSetTextColor( colorBrightGreen );
GfxTextOut( NumToStr( round( relvolume * 100 ), 2.0 ) + "%", x1, y1 );

// mx2 = Bear
absVolume = mx2[ i ][ 1 ];
VolAcum += absVolume;
relvolume = absVolume / MaxVolume;
relbar2 = relvolume * ( lvb - fvb + 1 );
x1 = x2;
x2 = x1 + relbar2;
bearColor = ColorBlend( colorCustom16, GetChartBkColor(), 0.2 );
GfxFillSolidRect( x1, y1, x2, y2, bearColor );
GfxSetBkColor( bearColor );
GfxSetTextColor( colorRed );
GfxTextOut( NumToStr( round( relvolume * 100 ), 2.0 ) + "%", x1, y1 );

// mx = All Bars
absVolume = mx[ i ][ 1 ];
relvolume = ( absVolume - VolAcum ) / MaxVolume;
relbar3 = relvolume * ( lvb - fvb + 1 );
x1 = x2;
x2 = x1 + relbar3;
midColor = ColorBlend( colorGrey40, GetChartBkColor(), 0.2 );
GfxFillSolidRect( x1, y1, x2, y2, midColor );
GfxSetBkColor( midColor );
GfxSetTextColor( colorBlack );
GfxTextOut( NumToStr( round( relvolume * 100 ), 2.0 ) + "%", x1, y1 );
}
}
_SECTION_END();

``````

How to put for all the dates where
the fvb is the first bar of the day and
lvb is for the last bar of the day

1 Like

Hi Sandy. I think you want to use this indicator on intraday data. I only have EOD on my side, but you should be able to open an intraday chart and just left mouse click on the first bar of the day to anchor the indicator there. The indicator should automatically update itself as each new bar arrives. Hope this helps.

[quote="swalsh, post:6, topic:8403"]

@swalsh, Thank you for sharing.. You have built an outstanding chart and very useful for analysis. If i may kindly need your help on 2 question below:

1. If on the very bottom of your code i add a simple exploration such as:
``````Filter=1;
``````

then there is a notice warning came up and suddenly the exploration stop. Below is the caption:

Maybe you have any idea why this is happening and how to fix it?

1. How to create an exploration that shows the price range of each bar?

Thank you so much for your help.

Hi Surya.
To show the price range for each bar: "Just select a quote and press F12 for begin and SHIFT+F12 for the range end. You can switch off the range marker by pressing CTRL+F12 key or double clicking in the same place twice." - from the AB User's Guide. Once you have defined a range, count the number of bars/candles and change the number of bins accordingly. (See the chart - 19 candles and 19 bins.)

I cannot explain the Notice with adding your filter and AddColumn(C,"Close",1.0). I added your two lines to the end of my AFL and got the same Notice. Then I changed it to AddColumn( C, "Close", 1.2 ) - no Notice. Changed it back to AddColumn( C, "Close", 1.0 ) - once again no Notice. I am using AB 6.30.0.

2 Likes

@swalsh

The notice warning is gone now. Thank you for your solution.

Regarding the PriceVolDistribution, could you kindly show me how to code an exploration that shows all the price range?

Thank you

Hi Surya, I am not sure what you want. I thought I answered you with the previous explanation but I got it wrong. Is it a line-by-line exploration that shows where the close of each candle occurs – upper, middle or lower third? Or the total range (High-Low) for each bar?

Remember to set your FILTER = 1; (or whatever your criteria are)

If its the total range: AddColumn( H-L, "Range", 1.2 );

To add the relationship to the Close position:

``````AddColumn( IIF( bullbar, 1, 0 ), "Top", 1.2 );
AddColumn( IIF( bearbar, 1, 0 ), "Bottom", 1.2 );
AddColumn( IIF( NOT bearbar AND NOT bullbar, 1, 0 ), "Middle", 1.2 );
``````

Dear @swalsh,
I'm seeking how to code an exploration that shows the price range of each horizontal bar (PriceVolDistribution) that you shows in the chart. Lets say the time range is 3 months.

Also i've add the code as you suggested:

``````/*
Author: Anderson Wilson, Beppe, Steve Walsh
based on PriceVolDistribution demo written by Tomasz Janeczko

Volume-by-Price is an indicator that shows the amount of volume for a particular price range,
The Volume-by-Price bars are horizontal and shown on the left side of the chart to correspond
with these price ranges. Bar colors indicate Bull (SeaGreen) / Bear (Custom16) / Total (Grey40) volume
Use double click to define range.
*/
SetChartOptions( 0, chartShowArrows | chartShowDates );
GraphXSpace = 15;
//
Plot( C, "", colorAqua, styleCandle );
Title = GetFnData( "Alias" ) + " - " + StrFormat( "{{FULLNAME}} - {{INTERVAL}}: {{DATE}}, VAP Absolute Values, Open %g, Hi %g, Lo %g, Close %g (%.1f%%), Vol(mil) %.2f (%.0f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ),  V / 1000000, SelectedValue( ROC( V, 1 ) ) );
//
bi = BarIndex();
fvb = BeginValue( bi );
lvb = EndValue( bi );

if( fvb == 0 && lvb == LastValue( bi ) )
{
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );
}

fvb = Max( 0, fvb );
lvb = Max( 0, lvb );

bins = Param( "Bins", 10, 3, 100, 1 );
pRecHeight = Param( "Rectangle Height", 0.90, 0.10, 1, 0.05 );

BullBearZone = ( High - Low ) / 3;
bullbar = C > ( High - BullBearZone );
bearbar = C < ( Low + BullBearZone );

// mx = [row 0][col 0]
// price levels in first column [0][0] and relative volume at that level in second column [0][1]
// https://www.amibroker.com/guide/afl/pricevoldistribution.html
mx = PriceVolDistribution( H, L, V, bins, True, fvb, lvb );
mx1 = PriceVolDistribution( H, L, IIf( bullbar, V, 0 ), bins, True, fvb, lvb );
mx2 = PriceVolDistribution( H, L, IIf( bearbar, V, 0 ), bins, True, fvb, lvb );

bins = MxGetSize( mx, 0 );
bins1 = MxGetSize( mx1, 0 );
bins2 = MxGetSize( mx2, 0 );

GfxSetOverlayMode( 1 );
GfxSetCoordsMode( 1 );

if( bins > 1 && bins == bins1 && bins == bins2 )
{

MaxVolume = mx[ 0 ][ 1 ];

// find max volume
for( i = 1; i < bins; i++ )
{
if( mx[ i ][ 1 ] > MaxVolume )
MaxVolume = mx[ i ][ 1 ]; // Volume for that bin 1...

//printf( "mx=%g", MaxVolume / 100000 );
}

// rectangle height
RecHeight = ( mx[ 1 ][ 0 ] - mx[ 0 ][ 0 ] ) / 2 * pRecHeight;
GfxSelectFont( "Arial", 7 ); // Change the text size here

for( i = 0; i < bins; i++ )
{
// mx1 = Bull
price = mx1[ i ][ 0 ]; // price level
absVolume = mx1[ i ][ 1 ];
VolAcum = absVolume;
relvolume = absVolume / MaxVolume;
relbar = relvolume * ( lvb - fvb + 1 );
// upper left corner of the rectangle.
x1 = fvb;
y1 = price + RecHeight;
// lower right corner of the rectangle.
x2 = fvb + relbar;
y2 = price - RecHeight;
bullColor = ColorBlend( colorSeaGreen, GetChartBkColor(), 0.2 );
GfxFillSolidRect( x1, y1, x2, y2, bullColor );
GfxSetBkColor( bullColor );
GfxSetTextColor( colorBrightGreen );
GfxTextOut( NumToStr( round( relvolume * 100 ), 2.0 ) + "%", x1, y1 );

// mx2 = Bear
absVolume = mx2[ i ][ 1 ];
VolAcum += absVolume;
relvolume = absVolume / MaxVolume;
relbar2 = relvolume * ( lvb - fvb + 1 );
x1 = x2;
x2 = x1 + relbar2;
bearColor = ColorBlend( colorCustom16, GetChartBkColor(), 0.2 );
GfxFillSolidRect( x1, y1, x2, y2, bearColor );
GfxSetBkColor( bearColor );
GfxSetTextColor( colorRed );
GfxTextOut( NumToStr( round( relvolume * 100 ), 2.0 ) + "%", x1, y1 );

// mx = All Bars
absVolume = mx[ i ][ 1 ];
relvolume = ( absVolume - VolAcum ) / MaxVolume;
relbar3 = relvolume * ( lvb - fvb + 1 );
x1 = x2;
x2 = x1 + relbar3;
midColor = ColorBlend( colorGrey40, GetChartBkColor(), 0.2 );
GfxFillSolidRect( x1, y1, x2, y2, midColor );
GfxSetBkColor( midColor );
GfxSetTextColor( colorBlack );
GfxTextOut( NumToStr( round( relvolume * 100 ), 2.0 ) + "%", x1, y1 );
}
}
Filter=1;
AddColumn( IIF( bullbar, 1, 0 ), "Top", 1.2 );
AddColumn( IIF( bearbar, 1, 0 ), "Bottom", 1.2 );
AddColumn( IIF( NOT bearbar AND NOT bullbar, 1, 2 ), "Middle", 1.2 );

``````

I don't know why but it keeps resulting error notice in the exploration

2 Likes

To add the average price for each bin or the average volume for each bin, add the following to your exploration:

``````for( i = 0; i < bins; i++ )
{
AddColumn( mx[i][0], "Avg Price Bin " + i, 1.2 );
AddColumn( mx[i][1], "Avg Volume Bin " + i, 1.2 );
}
``````

You will see that the bins are counted from bottom (0) to top (number of bins - 1). Just comment out the AddColumn for Price or Vol, whichever you don't want.

Moderator comment: You MUST USE the CODE TAGS!

I am not sure how to give you each bin's range (H-L) as the matrix the
PriceVolDistribution produces only gives the average (H-L)/2. You could do this manually by subtracting your lowest low from your highest high in the selected range and dividing it by the bin number. This will give you the width of each bin. There must be a way to do this using AFL, but its a bit beyond me.