How to make convert this long assignment statement into a function?

I have this long assignment statement.

num_times_above = iif(Ref(CLOSE, -0)>Ref(CLOSE, -4) , 1, 0)
					+ iif(Ref(CLOSE, -1)>Ref(CLOSE, -4), 1, 0)
					+ iif(Ref(CLOSE, -2)>Ref(CLOSE, -4), 1, 0)
					+ iif(Ref(CLOSE, -3)>Ref(CLOSE, -4), 1, 0)
					+ iif(Ref(CLOSE, -4)>Ref(CLOSE, -4), 1, 0)
					;

I would like to convert this long statement into a generic function that accepts a parameter n;

function get_num_times_above(n)
{
  //code
}

The code on top is for the case when n == 4. I am stuck at this seemingly simple problem because of the array format used in Amibroker.

if n == 3, the equivalent code will be;

num_times_above = iif(Ref(CLOSE, -0)>Ref(CLOSE, -3) , 1, 0)
					+ iif(Ref(CLOSE, -1)>Ref(CLOSE, -3), 1, 0)
					+ iif(Ref(CLOSE, -2)>Ref(CLOSE, -3), 1, 0)
					+ iif(Ref(CLOSE, -3)>Ref(CLOSE, -3), 1, 0)
					;

I think something like this untested function would work:

function get_num_times_above(n)
{
    num_times_above = iif(CLOSE>Ref(CLOSE, -n) , 1, 0);
    for (i=1; i<n; ++i)
    {
        num_times_above += iif(Ref(CLOSE, -i)>Ref(CLOSE, -n), 1, 0);
    }
    return num_times_above; // added by moderator
}
4 Likes
  1. You should actually return a function value.
  2. You don't need iif here.
  3. loop invariant code belongs to outside of code.
function get_num_times_above(n)
{
    num_times_above = 0;
    refn = Ref(C, -n);
    for (i=0; i<n; i++)	
		num_times_above += Ref(C, -i)>refn;
    return num_times_above;
}		

n = 4;
num_times_above = get_num_times_above(n);
6 Likes

Thanks for all the replies. The solutions will work if the function is required to return one value based on the last value of Close array. What if I want the function to return an array that can be plotted?

The modified function shown by @fxshrat already returns the entire array. Mine would have too, if I'd remembered the return statement. If it's not obvious to you yet that the function is operating on arrays, you should probably study the AFL tutorials a bit more. Sometimes it takes a while for that to "click", because AmiBroker makes it so easy to switch back and forth between scalars and arrays.

2 Likes

@thankyou18, I like the exploration as a tool to visualize array contents.

For instance, here below is an exploration formula using the @fxshrat's function (modified only to make it more generic accepting an array as the first parameter):

// Function based on @fxshrat code posted here:
// https://forum.amibroker.com/t/how-to-make-convert-this-long-assignment-statement-into-a-function/7181/3
function get_num_times_above( array, n )
{
    num_times_above = 0;
    refn = Ref( array, -n );

    for( i = 0; i < n; i++ )
        num_times_above += Ref( array, -i ) > refn;

    return num_times_above;
}

n = Param( "N. of the past element to reference", 4, 3, 15, 1 );
O_nta = get_num_times_above( O, n );
H_nta = get_num_times_above( H, n );
L_nta = get_num_times_above( L, n );
C_nta = get_num_times_above( C, n );

X_nta = O_nta + H_nta + L_nta + C_nta;

// Exploration sample
function getColor( a, n )
{
    return( IIf( a, ColorHSB( ( 32 + ( a / n ) * 32 ), 255, 255 ), colorDefault ) );
}
function getHeader( aName, n )
{
    return ( StrFormat( "%s... > Ref(%s, -%1.0f)", aName, aName, n ) );
}
Filter = 1;
AddColumn( O_nta, getHeader( "O", n ), 1, colorDefault, getColor( O_nta, n ) );
AddColumn( H_nta, getHeader( "H", n ), 1, colorDefault, getColor( H_nta, n ) );
AddColumn( L_nta, getHeader( "L", n ), 1, colorDefault, getColor( L_nta, n ) );
AddColumn( C_nta, getHeader( "C", n ), 1, colorDefault, getColor( C_nta, n ) );
AddColumn( X_nta, getHeader( "All", n ), 1, colorDefault, getColor( X_nta, n * 4 ) );
SetSortColumns( -2 ); // see most recent quotes first

Perhaps, here, it is fancier than needed, but sometimes it can be a useful alternative to the charts to examine the used arrays values.

4 Likes

@thankyou18 Here is an array solution.

It is based on this one: Faster array approach for this function instead of using slow for-loop approach

As you can see, you can get >, >=, <= and < ...
Here this can be used in combination with Reverse:

function num_times_above_ref(array, n)
{
rev_pr = PercentRank( -Reverse(array), n);
num_times_above = Ref( Reverse( rev_pr)* 0.01* n, -n);
//num_times_above = Ref( round( Reverse( rev_pr)* 0.01* n), -n);
return num_times_above;
}
1 Like