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
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 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)
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.
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.
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)
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.