3

I'm making a trading strategy that uses support and resistance levels. One of the ways i'm finding those is by searching for maxima's/minima's (prices that are higher/lower than the previous and next 5 prices).

I have an array of smoothed closing prices and i first tried to find them with a for loop :

def find_max_min(smoothed_prices) # smoothed_prices = np.array([1.873,...])
    avg_delta = np.diff(smoothed_prices).mean()
    maximas = []
    minimas = []
    for index in range(len(smoothed_prices)):
        if index < 5 or index > len(smoothed_prices) - 6:
            continue

        current_value = smoothed_prices[index]
        previous_points = smoothed_prices[index - 5:index]
        next_points = smoothed_prices [index+1:index+6]

        previous_are_higher = all(x > current_value for x in previous_points)
        next_are_higher = all(x > current_value for x in next_points)

        previous_are_smaller = all(x < current_value for x in previous_points)
        next_are_smaller = all(x < current_value for x in next_points)

        previous_delta_is_enough = abs(previous[0] - current_value) > avg_delta 
        next_delta_is_enough = abs(next_points[-1] - current_value) > avg_delta
        delta_is_enough = previous_delta_is_enough and next_delta_is_enough  

        if previous_are_higher and next_are_higher and delta_is_enough:
            minimas.append(current_value)

        elif previous_are_higher and next_are_higher and delta_is_enough:
            maximas.append(current_value)

        else:
            continue

        return maximas, minimas

(This isn't the actual code that i used because i erased it, this may not work but is was something like that)

So this code could find the maximas and minimas but it was way too slow and i need to use the function multiple times per secs on huge arrays.

My question is : is it possible to do it with a numpy mask in a similar way as this :

smoothed_prices = s
minimas = s[all(x > s[index] for x in s[index-5:index]) and all(x > s[index] for x in s[index+1:index+6])]
maximas = ...

or do you know how i could to it in another efficient numpy way ?

igor
  • 33
  • 3

2 Answers2

1

I have thought of a way, it should be faster than the for loop you presented, but it uses more memory. Simply put, it creates a intermediate matrix of windows, then it just gets the max and min of each window:

def find_max_min(arr, win_pad_size=5):
    windows = np.zeros((len(arr) - 2 * win_pad_size, 2 * win_pad_size + 1))
    for i in range(2 * win_pad_size + 1):
        windows[:, i] = arr[i:i+windows.shape[0]]
    return windows.max(axis=1), windows.min(axis=1)

Edit: I found a faster way to calculate the sub-sequences (I had called windows) from Split Python sequence into subsequences. It doesn't use more memory, instead, it creates a view of the array.

def subsequences(ts, window):
    shape = (ts.size - window + 1, window)
    strides = ts.strides * 2
    return np.lib.stride_tricks.as_strided(ts, shape=shape, strides=strides)

def find_max_min(arr, win_pad_size=5):
    windows = subsequences(arr, 2 * win_pad_size + 1)
    return windows.max(axis=1), windows.min(axis=1)
Gabriel A.
  • 609
  • 3
  • 7
0

You can do it easily by:

from skimage.util import view_as_windows
a = smoothed_prices[4:-5]
a[a == view_as_windows(smoothed_prices, (10)).min(-1)]

Please note that since you are looking at minimas within +/- 5 of the index, they can be in indices [4:-5] of your array.

Ehsan
  • 12,072
  • 2
  • 20
  • 33