Скользящее окно локальных минимумов / максимумов - PullRequest
0 голосов
/ 09 марта 2020

Я создал скрипт (показанный ниже), который помогает определять локальные максимумы, используя исторические данные о запасах. Он использует дневные максимумы, чтобы выделить локальные уровни сопротивления. Прекрасно работает, но я хотел бы, чтобы в любой данный момент времени (или строку в данных о запасах) я хотел знать, какой самый последний уровень сопротивления был непосредственно перед этой точкой. Я хочу это в своем собственном столбце в наборе данных. Например:

Demonstration

Верхняя серая линия - это максимумы за каждый день, а нижняя серая линия - это закрытие каждого дня. Грубо говоря, набор данных для этого раздела будет выглядеть следующим образом:

High            Close
216.8099976     216.3399963
215.1499939     213.2299957
214.6999969     213.1499939
215.7299957     215.2799988 <- First blue dot at high
213.6900024     213.3699951
214.8800049     213.4100037 <- 2nd blue dot at high
214.5899963     213.4199982 
216.0299988     215.8200073
217.5299988     217.1799927 <- 3rd blue dot at high
216.8800049     215.9900055
215.2299957     214.2400055
215.6799927     215.5700073
....

Сейчас этот скрипт просматривает весь набор данных одновременно, чтобы определить локальные индексы максимумов для максимумов, а затем для любого заданного точка в истории запасов (т. е. любая заданная строка), она ищет СЛЕДУЮЩИЕ максимумы в списке всех найденных максимумов. Это был бы способ определить, где находится следующий уровень сопротивления, но я не хочу этого из-за предвзятости. Я просто хочу иметь столбец самого последнего уровня сопротивления в прошлом или, может быть, даже последние 2 последних пункта в 2 столбцах. На самом деле это было бы идеально.

Таким образом, мой окончательный результат будет выглядеть так для 1 столбца:

High            Close           Most_Rec_Max
216.8099976     216.3399963     0
215.1499939     213.2299957     0
214.6999969     213.1499939     0
215.7299957     215.2799988     0
213.6900024     213.3699951     215.7299957
214.8800049     213.4100037     215.7299957
214.5899963     213.4199982     214.8800049
216.0299988     215.8200073     214.8800049
217.5299988     217.1799927     214.8800049
216.8800049     215.9900055     217.5299988
215.2299957     214.2400055     217.5299988
215.6799927     215.5700073     217.5299988
....

Вы заметите, что точка появляется только в самом последнем столбце после нее уже был обнаружен.

Вот код, который я использую:

real_close_prices = df['Close'].to_numpy()

highs = df['High'].to_numpy()

max_indexes = (np.diff(np.sign(np.diff(highs))) < 0).nonzero()[0] + 1 # local max
# +1 due to the fact that diff reduces the original index number

max_values_at_indexes = highs[max_indexes]
curr_high = [c for c in highs]
max_values_at_indexes.sort()
for m in max_values_at_indexes:
    for i, c in enumerate(highs):
        if m > c and curr_high[i] == c:
            curr_high[i] = m
#print(nextbig)
df['High_Resistance'] = curr_high

# plot
plt.figure(figsize=(12, 5))
plt.plot(x, highs, color='grey')
plt.plot(x, real_close_prices, color='grey')
plt.plot(x[max_indexes], highs[max_indexes], "o", label="max", color='b')
plt.show()

Надеюсь, кто-то сможет помочь мне с этим. Спасибо!

Ответы [ 2 ]

1 голос
/ 10 марта 2020

Я только что натолкнулся на эту функцию, которая может вам очень помочь: scipy.signal.find_peaks .

На основе вашего образца данных мы можем сделать следующее:

from scipy.signal import find_peaks

## Grab the minimum high value as a threshold.
min_high = df["High"].min()

### Run the High values through the function. The docs explain more,
### but we can set our height to the minimum high value.
### We just need one out of two return values.

peaks, _ = find_peaks(df["High"], height=min_high)

### Do some maintenance and add a column to mark peaks

# Merge on our index values
df1 = df.merge(peaks_df, how="left", left_index=True, right_index=True)

# Set non-null values to 1 and null values to 0; Convert column to integer type.
df1.loc[~df1["local_high"].isna(), "local_high"] = 1
df1.loc[df1["local_high"].isna(), "local_high"] = 0
df1["local_high"] = df1["local_high"].astype(int)

Тогда ваш фрейм данных должен выглядеть следующим образом:

          High         Low  local_high
0   216.809998  216.339996           0
1   215.149994  213.229996           0
2   214.699997  213.149994           0
3   215.729996  215.279999           1
4   213.690002  213.369995           0
5   214.880005  213.410004           1
6   214.589996  213.419998           0
7   216.029999  215.820007           0
8   217.529999  217.179993           1
9   216.880005  215.990005           0
10  215.229996  214.240005           0
11  215.679993  215.570007           0
1 голос
/ 10 марта 2020

Вот один из подходов. Как только вы узнаете, где находятся пики, вы можете сохранить пиковые индексы в p_ids и пиковые значения в p_vals. Чтобы назначить k 'самый последний пик, обратите внимание, что p_vals[:-k] будет происходить при p_ids[k:]. Остальное - прямое наполнение.

# find all local maxima in the series by comparing to shifted values
peaks = (df.High > df.High.shift(1)) & (df.High > df.High.shift(-1))
# pass peak value if peak is achieved and NaN otherwise
# forward fill with previous peak value & handle leading NaNs with fillna
df['Most_Rec_Max'] = (df.High * peaks.replace(False, np.nan)).ffill().fillna(0)

# for finding n-most recent peak
p_ids, = np.where(peaks)
p_vals = df.High[p_ids].values
for n in [1,2]:
  col_name = f'{n+1}_Most_Rec_Max'
  df[col_name] = np.nan
  df.loc[p_ids[n:], col_name] = p_vals[:-n]
  df[col_name].ffill(inplace=True)
  df[col_name].fillna(0, inplace=True)


#           High       Close  Most_Rec_Max  2_Most_Rec_Max  3_Most_Rec_Max
# 0   216.809998  216.339996      0.000000        0.000000        0.000000
# 1   215.149994  213.229996      0.000000        0.000000        0.000000
# 2   214.699997  213.149994      0.000000        0.000000        0.000000
# 3   215.729996  215.279999    215.729996        0.000000        0.000000
# 4   213.690002  213.369995    215.729996        0.000000        0.000000
# 5   214.880005  213.410004    214.880005      215.729996        0.000000
# 6   214.589996  213.419998    214.880005      215.729996        0.000000
# 7   216.029999  215.820007    214.880005      215.729996        0.000000
# 8   217.529999  217.179993    217.529999      214.880005      215.729996
# 9   216.880005  215.990006    217.529999      214.880005      215.729996
# 10  215.229996  214.240006    217.529999      214.880005      215.729996
# 11  215.679993  215.570007    217.529999      214.880005      215.729996
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...