Looking for median deviation of the median price

Hello Guys and Gals. New user here and stuck allready.

For a volatility filter I am trying to find the median distance from a median price. In other words the 50th percentile of the distances to the 50th percentile of the past X Bars.

For example (Period 5 Bars) if the past 5 Bars of a certain Stock had closing prices
of 22, 25, 26, 26, 29 the Median would be the middle or 26. Then i would like to
know the Median of the differences (positive values only) to that median(26).
22-26=4, 25-26=1, 26-26=0, 26-26=0, 29-26=3. Results 4,1,0,0,3.
List sorted would be 0,0,1,3,4 the Median deviation in this case would be again the
middle Value which would be 1.

I am a former Multicharts (Power Language) user which currently is not realy helping
me in my thinking.
I tried to code a Function to do the above calculation. It will give me the correct Value
for the LAST bar only, but not for the rest of the Bars that came before.

Here is the function

function MAD( array, period ) 
{ 
    result = Null;
    
	for( i = BarCount - Period; i < BarCount; i++ ) 
	{
		rawprice[i] = array[i];
	}
    rawprice = Sort(rawprice);
	
	for( i = BarCount - Period; i < BarCount; i++ ) 
	{
		rawmad[i] = abs( array[i] - rawprice[ (BarCount-1-Period) + ceil(.5*Period) ] ); // substracting the seperate closing values to the median calculated in the loop above to find the differences
	}
    rawmad = Sort(rawmad);
    result = rawmad[ (BarCount-1-Period) + ceil(.5*Period) ];
    
	return result;
}

Now i am sure i made some terrible mistakes here and i am not sure if i even need
to do looping in Amibroker to achieve what i would like to do, and i most likely have not understooth how arrays are calculated in AmiBroker.

Could someone be so kind and point me the right direction ?

I don't think there is BarCount loop required

Example using MxSort

/// ###############################################################################################
/// @link https://forum.amibroker.com/t/how-to-find-out-the-2nd-highest-or-2nd-lowest-value/8913/8
/// @link https://forum.amibroker.com/t/arranging-the-past-5-days-close-either-in-ascending-or-descending-order/26534/8
/// @link https://forum.amibroker.com/t/looking-for-median-deviation-of-the-median-price/26660/2
/// ###############################################################################################
period = 5;
med = Median(C,period);

ranks = period;
mat_source = Matrix(BarCount, ranks);
rownum = MxGetSize(mat_source,0);
colnum = MxGetSize(mat_source,1);
for ( j = 0; j < colnum; j++ ) {
	mat_source = MxSetBlock(mat_source, 0, rownum-1, j, j, abs(med-Ref(C,-j)));
}

// sorted custom array
mat_sort = MxSort(mat_source, 0, 0);

Filter = 1;
SetSortColumns(-2);

// 1-dim array output
for ( j = 0; j < colnum; j++ ) {
	block = MxGetBlock(mat_sort, 0, rownum-1, j, j, True);
	color = IIf((j+1)==ceil(0.5*period), colorRed, colorDefault);
	Plot(block, "Median Diff"+(j+1), color);
	AddColumn(block, "Median Diff"+(j+1), 1.2, colorDefault, color);
}

SetBarsRequired(period);

24

3 Likes
/// CODE IS BASED ON original work found: ###############################################################################################
/// @link https://forum.amibroker.com/t/how-to-find-out-the-2nd-highest-or-2nd-lowest-value/8913/8
/// @link https://forum.amibroker.com/t/arranging-the-past-5-days-close-either-in-ascending-or-descending-order/26534/8
/// @link https://forum.amibroker.com/t/looking-for-median-deviation-of-the-median-price/26660/2
/// ###############################################################################################


function MAD( array, period )
{
    median_array = Percentile( array, period, 50 );
    mx = Matrix( BarCount, period );

    for( i = 0; i < period; i++ )
    {
        mx = MxSetBlock( mx, 0, BarCount - 1, i, i, abs( Ref( array, -i ) - median_array ) );
    }

    mx = MxSort( mx, 0 );

    i = floor( period / 2 );

    if( period % 2 ) // odd period
    {
        median_diff = MxGetBlock( mx, 0, BarCount - 1, i, i, True );
    }
    else // even
    {
        lower = MxGetBlock( mx, 0, BarCount - 1, i - 1, i - 1, True );
        upper = MxGetBlock( mx, 0, BarCount - 1, i, i, True );
        median_diff = ( lower + upper ) / 2;
    }

    return median_diff;
}

Moderator note: added required references for original work.

1 Like

No need to copy with slow Percentile function.

1 Like

If you want the median for even periods as the average of upper and lower median, then correctness is better than speed.

1 Like

Your so called "correctness" is in eye of beholder. Nothing more nothing less.

1 Like

Thank you to both
@fxshrat and @bysoaa

This will work and does exactly what i need. :+1:

@bysoaa - if you copy someone's other code changing just one line you should KEEP REFERENCES given in original formula so original author is credited for work.

1 Like

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