Bars since higher or equal value

Hi

I am trying to use arrays to calculate how many bars before there is a higher or equal value, to the current bar.

Is this possible?

Bars since highest counting from some event
http://www.amibroker.com/f?highestsincebars
or (bars since highest in given period):
http://www.amibroker.com/f?hhvbars
or (bars since all time highest):
http://www.amibroker.com/f?highestbars

Hi

Yes, I know these. What I want is different.

Suppose I have a bar with a Close at 1.50. I want to look back (to the left) and find the first bar that has equal or higher Close value.

Is this possible with array programming? I want to avoid loops and writing a plugin.

you can use valuewhen with parameter 0.

i made the code but it is not very elegant, but works. Probably also other ways to do it using the reverse function for instance

SetBarsRequired( sbrAll, sbrAll );

tog1 = ParamToggle( "Compare", "Equal or Higher|Within Range", 0 );

GraphXSpace = 5;
SetChartBkColor( ColorRGB( 0, 0, 0 ) ); //solid fill or axes color
SetChartOptions( 1, chartShowDates, chartGridMiddle, 0, 0, 0 );
SetBarFillColor( IIf( C > O, ColorRGB( 0, 150, 0 ), IIf( C < O, ColorRGB( 150, 0, 0 ), ColorRGB( 150, 150, 150 ) ) ) );
Plot( C, "", IIf( C > O, ColorRGB( 0, 255, 0 ) , IIf( C < O, ColorRGB( 255, 0, 0 ), ColorRGB( 150, 150, 150 ) ) ), 64, Null, Null, 0, 0, 1 );

dn = BarIndex();
sd = SelectedValue( dn );
endarray = IIf( sd == dn, 1, 0 );
idx0 = LastValue( ValueWhen( endarray, BarIndex() ) );
endarray[0] = 1;
prc = C;

if( tog1 )
{
    kk = ValueWhen( endarray, prc, 0 );
    kk = IIf( BarIndex() < sd, kk, Null );
    kkidx = IIf( kk > L && kk < H && !IsEmpty(kk), 1, 0 );
    idx = LastValue( ValueWhen( kkidx, BarIndex() ) );
    startarray = IIf( idx == BarIndex(), 1, 0 );
    result = IIf( Flip( startarray, endarray ), kk, Null );
    result[idx0] = prc[idx0];
    Plot( result, "", colorWhite, 1 );
}
else
{
    kk = ValueWhen( endarray, prc, 0 );
    kk = IIf( BarIndex() < sd, kk, Null );
    kkidx = IIf( prc >= kk, 1, 0 );
    idx = LastValue( ValueWhen( kkidx, BarIndex() ) );
    startarray = IIf( idx == BarIndex(), 1, 0 );
    result = IIf( Flip( startarray, endarray ), kk, Null );
    result[idx0] = prc[idx0];
    Plot( result, "", colorWhite, 1 );
}
1 Like

Hello empottasch

Thanks for the code, I sure have a lot to learn from it.

I noticed you use the "SelectedValue" function. This will not work in an Analysis window. It works only for the selected/current value.

What I want is to create an array of all the distances between the current bar and the previous bar with the same or higher value.

will get back to you mañana. I used SelectedValue as per example. So you can move the cursor around in the chart and see the result.

I am sorry, you are right. Selectedvalue works great for demonstration. I just got worried it would not work for entire array.

I am reading on your code...

@empottasch

Interesting, I liked the use of FLIP.

It is always easier when working with one value. I tried to modify your code and make it work for an entire array but I am unable to do it.

@bobptz: I believe that to populate the entire array you will need to use a loop. If someone else offers a non-looping solution I will have learned something new and I will be very impressed!

If you do write your own loop, it might be more efficient to do your own scanning of the array rather than calling BarsSince() on every iteration of the loop.

1 Like

@empottasch
Now that I fully understood what you wrote, I tried to optimize the code.

SetBarsRequired( sbrAll, sbrAll );

GraphXSpace = 5;
SetChartBkColor( ColorRGB( 0, 0, 0 ) ); //solid fill or axes color
SetChartOptions( 1, chartShowDates, chartGridMiddle, 0, 0, 0 );
SetBarFillColor( IIf( C > O, ColorRGB( 0, 150, 0 ), IIf( C < O, ColorRGB( 150, 0, 0 ), ColorRGB( 150, 150, 150 ) ) ) );
Plot( C, "", IIf( C > O, ColorRGB( 0, 255, 0 ) , IIf( C < O, ColorRGB( 255, 0, 0 ), ColorRGB( 150, 150, 150 ) ) ), 64, Null, Null, 0, 0, 1 );

prc=High;
bi = BarIndex();
current_bi = SelectedValue(bi);
current_price = prc[current_bi]; 
temp = ValueWhen( prc>= current_price, bi, 2);
past_bi = temp[current_bi];
result = iif((bi>= past_bi ) AND (bi <= current_bi),current_price, null);
Plot( result, "", colorWhite, 1 );

However I think I will need to make a plugin to populate the array fast. I think @mradtke is right.

Here is the plugin:

// find how many bars passed since a previous bar had a higher value than the current bar.
// if a bar is highest than all past bars, then it takes the NULL value (EMPTY_VAL)
// input :  an array with prices (SrcArray)
// output : returns the resulting array.
// call from AFL:   BarsSinceHigherValue(H);
AmiVar VBarsSinceHigherValue( int NumArgs, AmiVar *ArgsTable )
{
    int currentIndex,prevIndex;
    float currentval;
    AmiVar result;

    result = gSite.AllocArrayResult();
    int nSize = gSite.GetArraySize();

    float *SrcArray = ArgsTable[ 0 ].array;

    // start populating the array from left to right 
    for( currentIndex = 0; currentIndex < nSize; currentIndex++ )    
	{
        result.array[currentIndex] = EMPTY_VAL;   // initialize
        currentval = SrcArray[currentIndex];      // current value in the array. We will search past bars for higher values
        prevIndex = currentIndex - 1;         
        
        // scan from the previous bar, and continue to the left
        while( 0 <= prevIndex ) {
            if ( currentval < SrcArray[prevIndex]  )
            {
                result.array[currentIndex] = currentIndex - prevIndex;  // just found the previous bar with higher value
                break;
            }
	        else   
			    // previous bar is lower or equal to the current bar, 
				// We have already done the job for the previous bar, take advantage of it.
				// Jump to the corresponding previous higher bar from the previous bar and continue checking from there.
				// ie skip all the bars that we know already they are lower
				prevIndex = prevIndex - result.array[prevIndex] ;  
       }
	}

    return   result;   
} 

FunctionTag gFunctionTable[] = {	"BarsSinceHigherValue", { VBarsSinceHigherValue, 1, 0, 0, 0, NULL}
};

Here is the AFL code:

SetBarsRequired( sbrAll, sbrAll );

GraphXSpace = 5;
SetChartBkColor( ColorRGB( 0, 0, 0 ) ); //solid fill or axes color
SetChartOptions( 1, chartShowDates, chartGridMiddle, 0, 0, 0 );
SetBarFillColor( IIf( C > O, ColorRGB( 0, 150, 0 ), IIf( C < O, ColorRGB( 150, 0, 0 ), ColorRGB( 150, 150, 150 ) ) ) );
Plot( C, "", IIf( C > O, ColorRGB( 0, 255, 0 ) , IIf( C < O, ColorRGB( 255, 0, 0 ), ColorRGB( 150, 150, 150 ) ) ), 64, Null, Null, 0, 0, 1 );

prc=High;
bi = BarIndex();
sbi = SelectedValue(bi);
vBarsSinceHigherValue = BarsSinceHigherValue( prc );
result = iif((bi>= sbi - vBarsSinceHigherValue[sbi]) AND (bi <= sbi),prc[sbi], null);
Plot( result, "", colorWhite, 1 );

I spent 10-15 hours scratching my head wondering how to do it faster with arrays and questioning my abilities to code in AFL. I spent 1 hour to code and test in C++ (and I am very louzy at C++).

@mradtke I am wondering, are there any fast rules to determine if something is feasible with array programming?

From my experience, whenever I have to use the SelectedValue function, then I cannot make an array-only formula that wil populate an entire array with the solution.

Maybe @Tomasz can help with this question?

6 Likes

@bobptz: No fast rules that I know of. I think over time you add to your personal repertoire of problems that CAN be solved with array programming, and learn to recognize those quickly. For "new" problems, this is my top secret process for finding resolution:

  1. Sit in front of the computer for an hour thinking and experimenting.
  2. If no answer, take the dog for a walk.
  3. If still no answer, sleep on it. Amazing how often this one works!
  4. If still no answer, ask the forum crowd.
  5. If still no answer, just code the darn loop.
6 Likes

for the entire array, you mean for every data point you want to find the first bar (in the past) that has an equal or higher "prc" value.

In my opinion you can then only store at each bar the number of bars it takes to get to the first bar in the past that has an equal or higher "prc". If you want to use a single array that is.

May i ask how you intend to use this in trading?

Exactly!

I am trying to implement Price Action logic with AFL programming. Not very easy to do. AFL is perfect for indicators. I find it very difficult for PA.

A swing high is defined by a bar with two lower bars to the left and two lower bars to the right (simple case). OR we may also have a series of bars with equal hight, and maybe some single bars in between with lower value. But we need to have two bars lower to the left and right.

So I define RightL = true if I have two lower bars to the right.
LeftL=true if I have two bars lower to the left.

Normally SwingHigh= RightL AND LeftL. This would sufficy for the simple case. But I need to take care that between RightL and LeftL I have a series of bars that are of equal and maybe lower height(at most one bar at a time).

So I want to see how far away to the left I have a higher bar ( BarsSinceHigherValue ). If my current bar has RightL=true and BarsSinceHigherValue is a bigger number than the distance to the LeftL, then I have my swingHigh.

Actually now I am writting a simpler plugin that will directly match LeftL with RightL. It will be much faster.

@mradtke, I don't have a dog, this is why I was scratching my head for hours. Need to modify my algo for this. Maybe I can optimize by taking more frequent naps.

1 Like

ok thanks. Not sure I completely understand. The pivots you describe sound like the Bill Williams fractal pivots.

Since your original algorithm needs two nested loops AND inner loop does NOT have fixed length (known in advance) then it is difficult to write pure array code.

Additional problem with this particular algorithm is that the inner loop works backwards (from newest to oldest) which is not natural direction of array processing functions. So solution needs some trickery (reversing arrays).

General array solution would be twisted, and probably not worth the effort, but in your case, in your example AFL formula you are just using selected value, so you could write simpler code like this that does not require loops:

function BarsSinceHigherValueSelectedVal( SrcArray )
{
	bi = BarIndex();
	sbi = SelectedValue( bi );
	
	hs = Reverse( HighestSinceBars( Reverse( bi == sbi ), Reverse( SrcArray ) ) ) ;
	
	hs = Ref( bi - ValueWhen( hs == 0, bi ), -1 ) + 1;
		
	shs = SelectedValue( hs );
	
	return IIf( bi >= sbi - shs AND bi <= sbi, SrcArray[ sbi ], Null );
}

Plot( C, "", colorDefault, styleCandle );
Plot( BarsSinceHigherValueSelectedVal( High ), "array", colorOrange );
7 Likes

Hi Tomasz

We used AFL-selected value only because we could not do a full-array AFL code.

Since your original algorithm needs two nested loops AND inner loop does NOT have fixed length (known in advance) then it is difficult to write pure array code.

Additional problem with this particular algorithm is that the inner loop works backwards (from newest to oldest) which is not natural direction of array processing functions. So solution needs some trickery (reversing arrays).

General array solution would be twisted, and probably not worth the effort

Yes, we want to keep things simple. Even if I manage to write it, I will go back later to maintain the code and I won;t be able to read it.

Thank you very much for your input.

PS: @Tomasz Maybe you can introduce a new feature in future versions that will make this kind of calculation a breeze?

I think the following code is what bobptz is looking for. It gives one the Barindex for the bar that had a higher high than the current Bar. Such an array is essential for validating Tested Pivots.

SetBarsRequired(sbrAll);


CBHH=Highest(H);

StartDTBar=IIf(H==CBHH,-1,0);// A Check so that the Current Bar is not the highest High
StarDwTBar[0]=0;



for (i=(BarCount-1);i>1;i--)

{



if (StartDtBar[i]==0)
	{

j=i;

while(H[j]<=H[i])
{

j=j-1;
StartDwTBar[i]=j;
}

	}







else
{StartDwTBar[i]=0;}
}



Plot(StartDwtBar," ",colorBlue,styleHistogram);



Thank you @wildeazoscar

I was looking for an array only solution. Don;t worry about it. I have written a plugin and the issue is not a problem any more.

The solution was already given in this very thread: Bars since higher or equal value