Duplicate: Bars since price was this high/low

Can anyone think of a fast way to calculate the number of bars since price was higher/lower than it is now? I'm sure it can be done with looping, but I'm hoping for a fast vectorized solution.

To clarify, for each bar, I want to determine when was the last time price was higher/lower than this bar's price level and return the number of bars since then. It needs to be an array, not a scalar.

I understand what you want to achieve as I have made functions for
"bars since higher/lower than current value" in C (because of nested loop) years ago.
I haven't figured out a way with inbuilt AFL functions.
So I think if you need fast ones then you may go C-route too.

@Steve you might need to send an practical output example (visual or data grid) of what you are after because from the description, it is guessing game. How to ask a good question

@Steve,

Since you do not seem to have any code yet...
Is this one what you look for?

Get the number of bars back of previous element that is first one being higher than "current" element in array.

So in example picture below... for selected element previous one being higher than that "current" (selected) one is located 9 bars back.
34


Same chart, same symbol
Now other selected element's previous first element being higher than that selected one is located 4 bars back.
35

Similar for finding lowest ones...

If that is what @Steve wants you need two loops for that because you are scanning in two opposite directions (forward (outer loop) and backward (inner loop)).

@fxshrat @Tomasz Thanks for reaching out. Yes, fxshrat, you understand the idea correctly. Thanks for providing a visual example. There is also the special case that the current bar is the all-time high. In this case, the function could either return zero, or perhaps the current bar index.

I was hoping this problem could be solved with clever use of ValueWhen(), but I haven't worked it out yet. One possible solution as mentioned above is to use a loop and call BarsSince inside the loop.

You can't do that with ValueWhen because it scans in single direction, while what you are asking needs scanning in two opposite directions.

BTW: this is a duplicate topic. Existing topic already provides solutions Bars since higher or equal value - #16 by Tomasz

Thank you Tomasz, I will study the prior existing topic.

You probably don't want to do that, because BarsSince will calculate the entire array each time you call it. If you call it inside your loop, then the total number of calculations to be done is BarCount * BarCount. As a general rule, calling array functions from inside a loop is not computationally efficient. You're likely better off writing a nested loop, and if that's not fast enough, using a language like C or C++ as @fxshrat suggested. You may also gain some speed by only calculating your "bars since higher/lower value" for those array elements where you actually need that value, rather than calculating it for every element of the array.

I can add such function, but just tell me if name BarsSinceHigher() , BarsSinceLower() sounds good or maybe you have other ideas for name (I would like to avoid lenghty names such as BarsSinceArrayWasHigherThanNow)

5 Likes

@Tomasz Sounds good to me, thank you!

Names sound good.

May I suggest to add two function arguments... first one being current array and second argument being the one to be compared with function's first argument and that 2nd one being either scalar or some other array of choice.

3 Likes

How about:

BarsSinceCompared( past_array, compare, current_array );

You would call it like this

BarsSinceCompared( Close, ">", Close ); // get bars since close was last time higher than current close
BarsSinceCompared( Low, ">", Close ); // get bars since low was last time higher than current close
BarsSinceCompared( Low, ">=", Close ); // get bars since low was last time higher than or equal than current close
BarsSinceCompared( High, "<=", Low ); // get bars since high was lower than or equal than current low

Or maybe BarsSinceComparePast() or BarsSinceLastTime() would be better name ?

You might wonder why do I care about the name so much?
Well, I don't want to create confusion among users and don't want this function to be abused when it is not needed at all.

Example: even @fxshrat mentioned this:

two function arguments... 2nd one being either scalar

Now, this function is strictly for ARRAYS and ARRAYS ONLY.

Using it for scalars make no sense because if one of things being compared is a scalar you should just use much faster BarsSince() function

x = BarsSince( array > 5 ); // if one arg is a scalar BarsSince does the job perfectly

The point is that BarsSinceCompare() function is computationally intensive (complexity O(n2)), therefore it should only be used when really needed (when BOTH arguments are arrays)

6 Likes

This is a useful function - thank you.

BarsSinceCompared or BarsSinceCompare

No, no, don't worry.
I did not mean to add scalar comparison to the latter complex *Compare function suggestion that deals with several comparison operators ( >, <, >=, <=, ==, !=).
It was just meant as "gimmick" for previous single comparison function BarsSinceHigher and BarsSinceLower ideas but those are obsolete now anyway.
Also I did not mean to use nested loop for array to scalar comparison but rather

if ( is_scalar ) {
   // BarsSince() algorithm (single loop)
} else if ( is_array ) {
  // more complex algorithm (nested loop)
} else
   // incorrect argument type

Anyway main purpose was array to array comparison. Array to scale comparison is well, totally secondary interest.

Long story short,...

Array to array only is completely fine. :wink:

1 Like

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