How to get result for PriceVolDistribution in plugin?

Is it possible to get result for PriceVolDistribution when we call it from AFL plugin?

If yes, how to get result for PriceVolDistribution as it returns a Matrix?

If I have a statement such as

AmiVar result = gSite.CallFunction( "PriceVolDistribution", 7, arg );

What would be the resut.type and how to retrieve matrix from result?

It is possible but you should not do this

@Tomasz, I do understand your concern.
I have already written the afl and it is working. But, it has a whole lot of processing of multiple profiles across different range of bars. So, I have decided to convert it into a plugin. I have many years of experience in writing C++ code and experienced access violations as well as core dumps over the years. For memory allocation, I am taking care to use only SiteInterface (AllocArrayResult and Alloc).

I have already understood how to get array and single value results after going through the docs.

So, can you help me to understand how to retrieve a Matrix result?

Hi @Tomasz , I checked the return from PriceVolDistribution for 20 bins. The result is as follows:

i0=2.8026e-44, i1=2.8026e-45, i2=10705, i3=0.191417, i4=10741.8, i5=0.432163, i6=10778.7, i7=0.111025, i8=10815.5, i9=0.155798, i10=10852.4, i11=0.151392, i12=10889.2, i13=0.326764, i14=10926.1, i15=0.278761, i16=10962.9, i17=0.451915, i18=10999.7, i19=0.310034, i20=11036.6, i21=0.137222, i22=11073.4, i23=0.486567, i24=11110.3, i25=0.146257, i26=11147.1, i27=0.304363, i28=11183.9, i29=0.444949, i30=11220.8, i31=0.70814, i32=11257.6, i33=0.881979, i34=11294.5, i35=1, i36=11331.3, i37=0.486313, i38=11368.2, i39=0.256732, i40=11405, i41=0.0895762

It is clear that even indexes have the price value and odd indexes have corresponding relative volume.
But the values for index 0 and 41 are different. They do not seem to have any corresponding price. What is the significance of the values in array elements 0 and 41?

I found similar pattern for 50 bins as well where I could not understand significance of values in elements 0 and 101.

Really there is zero code in your post so no one knows what you are actually doing.
Also no one knows whether it is AFL or C code. It might be latter one since it is plugins section but no one knows for certain.

Actually it does not matter. All that matter is: PriceVolDistribution is type matrix and it always has n-rows for all of its two columns. And there is always even number of elements.

Cells do not contain nothing. You simply misinterpret your output.
Your output is rather like this

i0=2.8026e-44, 
i1=2.8026e-45,

Now two columns with twenty rows follow (since you have set 20 bins).
First column is price and second column is volume (relative or absolute depending on setting).

i2=10705, i3=0.191417, 
i4=10741.8, i5=0.432163, 
i6=10778.7, i7=0.111025, 
i8=10815.5, i9=0.155798, 
i10=10852.4, i11=0.151392, 
i12=10889.2, i13=0.326764, 
i14=10926.1, i15=0.278761, 
i16=10962.9, i17=0.451915, 
i18=10999.7, i19=0.310034, 
i20=11036.6, i21=0.137222, 
i22=11073.4, i23=0.486567, 
i24=11110.3, i25=0.146257, 
i26=11147.1, i27=0.304363, 
i28=11183.9, i29=0.444949, 
i30=11220.8, i31=0.70814, 
i32=11257.6, i33=0.881979, 
i34=11294.5, i35=1, 
i36=11331.3, i37=0.486313, 
i38=11368.2, i39=0.256732, 
i40=11405, i41=0.0895762

i0 and i1 are some garbage output not related to distribution matrix (or result of incorrect code).
You need to check your code. It is your code. No one knows your code.

Since you have not posted code here is AB user guide code just adding print output.

/// a demo showing 
/// re-implementation of VAP overlay using 
/// PriceVolDistribution and low-level graphics 
/// @link https://www.amibroker.com/guide/afl/pricevoldistribution.html
bi = BarIndex();
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );

param_bins = Param( "Bins", 20, 10, 100, 1 );

mx = PriceVolDistribution( H, L, V, param_bins, False, fvb, lvb );
printf( "%s\n\n", MxToString(mx));

GfxSetCoordsMode( 1 );

GfxSelectPen( colorRed );

bins = MxGetSize( mx, 0 );

printf( "ALWAYS even number of matrix elements: %g\n\n", 
		MxGetSize(mx,0)*MxGetSize(mx,1));

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 );
    printf( "row idx: %g, %g, %g\n", i, price, relvolume);
    GfxMoveTo( fvb, price );
    GfxLineTo( fvb + relbar, price );
}

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

Setting n-bins results in n-rows for all columns.

Bottom line PriceVolDistribution function works fine and correctly.

8

1 Like

No, as I wrote: you should not be calling PriceVolDistribution from plugin. There is NO reason to do this. Performance from plugin will be worse than AFL.

It is one thing to advise against using afl plugin but another thing to completely deny help.

As I have already mentioned, my afl code is working fine. But the amount of processing (including nested loops) I am doing on result from PriceVolDistribution and the resultant slowing of my chart has forced me to decide to go along the plugin path. I will finally decide to continue using either plain afl code or afl plugin, whichever works faster for my use case.

Hi @fxshrat
Thanks for your reply. Since I had started the thread with plugin statement, I did not mention that I am doing this in plugin. My afl only code with PriceVolDistribution is working perfectly and I am able to plot the Profile without any issue. I do understand that PriceVolDistribution returns a matrix and I started this thread explicitly to understand retrieval of matrix result in plugin code. You can also refer to my messages above for previous details.

Call from sample afl to plugin is given below. VolProfile is the Function name in the function table.

barIdxArr = BarIndex();
startBar = Lookup(barIdxArr, StrToDateTime("2019-09-20 09:15:00"), 1);
endBar = Lookup(barIdxArr, StrToDateTime("2019-09-20 15:30:00"), 1);
volProfileMatrix = VolProfile(High, Low, Volume, 20, False, startBar, endBar);

My sample plugin code for the the profile is given below.

AmiVar VPriceVolDistribution( int NumArgs, AmiVar *ArgsTable )
{
    AmiVar arg[ 7 ];
    int i, j;
    ofstream outdata;

    arg[ 0 ].type = VAR_ARRAY;     arg[ 0 ].array = ArgsTable[ 0 ].array;

    arg[ 1 ].type = VAR_ARRAY;     arg[ 1 ].array = ArgsTable[ 1 ].array;

    arg[ 2 ].type = VAR_ARRAY;     arg[ 2 ].array = ArgsTable[ 2 ].array;

    arg[ 3 ].type = VAR_FLOAT;     arg[ 3 ].val = ArgsTable[ 3 ].val;

    arg[ 4 ].type = VAR_FLOAT;     arg[ 4 ].val = ArgsTable[ 4 ].val;

    arg[ 5 ].type = VAR_FLOAT;     arg[ 5 ].val = ArgsTable[ 5 ].val;

    arg[ 6 ].type = VAR_FLOAT;     arg[ 6 ].val = ArgsTable[ 6 ].val;

    AmiVar volProfile = gSite.CallFunction( "PriceVolDistribution", 7, arg );

    outdata.open("D:/VolumeProfile/profile.txt");
    outdata << "Profile: \n";
    for (i = 0; i < 42; i++)
        outdata << "i" << i << "=" << volProfile.array[i] << ",  ";
    outdata << "\n\n";

    return volProfile;
}

As given in previous post, output from this code is as follows:

Profile:
i0=2.8026e-44, i1=2.8026e-45, i2=10705, i3=0.191417, i4=10741.8, i5=0.432163, i6=10778.7, i7=0.111025, i8=10815.5, i9=0.155798, i10=10852.4, i11=0.151392, i12=10889.2, i13=0.326764, i14=10926.1, i15=0.278761, i16=10962.9, i17=0.451915, i18=10999.7, i19=0.310034, i20=11036.6, i21=0.137222, i22=11073.4, i23=0.486567, i24=11110.3, i25=0.146257, i26=11147.1, i27=0.304363, i28=11183.9, i29=0.444949, i30=11220.8, i31=0.70814, i32=11257.6, i33=0.881979, i34=11294.5, i35=1, i36=11331.3, i37=0.486313, i38=11368.2, i39=0.256732, i40=11405, i41=0.0895762

I am still wondering: What are those two initial values for i0 and i1?

If you must (you don't) write plugin for sake of writing plugins, call PriceVolDistribution from AFL. Convert to arrays using MxGetBlock. Put only processing intensive part (nested loops) in your plugin (expose function that takes input as arrays).

The way how many people write plugins (including you) is wrong. A plugin function SHOULD NOT be large block (or even whole programs) that calls many other AFL functions from inside. That PREVENTS multithreading. The functions exposed by plugin should be small, fast, math-like and ONLY doing their (small) job and NOT calling AFL functions.

What people do (rewriting whole AFL formulas into single DLL function) is fundamentally WRONG and it is against the design of plugin interface and prevents proper multithreading. So just do NOT do that.

I would probably add warnings for plugin exposed functions that take way to much time to return and prevent proper multithreading.

I won't tell you how to access matrix from DLL because this is SUBJECT TO CHANGE.
If I wrote that here, then it would block me from developing the program further because people would be relying on given interface and I would receive tons of complaints when changing the program would crash their plugins. So no, that won't happen.

And be aware that if you still forcefully try to do that your plugin will crash anyway in subsequent versions.

1 Like