Как улучшить алгоритм поиска поддержки/проторговки на временном ряде dataframe

Рейтинг: 1Ответов: 1Опубликовано: 22.07.2023

Есть такой DataFrame по ссылке: https://dropmefiles.com/y473o. Dataframe содержит временной ряд валютной пары USDCHF за определенный промежуток времени.

Кратко: поиск на данном dataframe уровня поддержки/проторговки (сам я занимаюсь профессионально трейдингом), т.е цены возле, которой чаще всего обнаруживались значения 'low' (и возможно 'close' тоже). Данное значение проторговки актуально, пока не будет обнаружено значение 'close' ниже чем искомое... надеюсь правильно изьясняюсь

Визуальное представление идеи: график валютной пары USDCHF 2

Мой алгоритм (приведен ниже) поиска нашел примерное значение, но я бы хотел его улучшить. Возможно вообще нужно использовать другой подход ) если будут предложения буду рад )). Проверял свой алгоритм поиска на другом dataframe и тоже нашел искомое для себя значение, но хотел сделать так чтобы в массив значений попадало меньше значений (меньше шума) не удовлетворяющих моим условиям!

import pandas as pd
import numpy as np
import time
# from tqdm import tqdm
# from tqdm import trange

df_csv = pd.read_csv('usdchf_07_2023_support.csv', index_col=0, delimiter='\t')
df_all = df_csv[["time",'open', 'high', 'low', 'close']]
df_all_new = df_all[["time",'open', 'high', 'low', 'close']].round(5)

# фильтрую отрезок временного ряда используя даты
filters = ((df_all_new.time>'2023-07-03 15:00:00') & (df_all_new.time<'2023-07-07 15:00:00'))
df_res = df_all_new[filters]   # данный отрезок dataframe и поиск далее в нем


def find_supports(dict_target: dict):
    "
    сам алгоритм поиска проторговки:
    итерируюсь по всему dataframe ищя возле каждого значения 'low' другие 
    значения 'low' в пределах погрешности delta
    "
    delta = 0.0005    # погрешность в пунктах (для поиска соседних близких зна)
    temp_dict = {}

    for i in range(len(dict_target)):
        # print(i, dict_target.time.iloc[i])
        value = dict_target.low.iloc[i]
        count = 0
        
        for j in range(i, len(dict_target)):
            distance_high = value + delta
            distance_low = value - delta
            if (distance_low < dict_target.low.iloc[j] < distance_high):
                count += 1
                # print(value, df_all_new.low.loc[j], j)
        temp_dict[str(value)]=count
        # print(count)

    # sorting our result_dict
    sorted_dict = sorted([(value, key) for (key, value) in temp_dict.items()])
    print('\n\n', sorted_dict)

find_supports(df_res)   # выполнение поиска (результатом выполнения которого будет вывод массива цен возле которой чаще всего находились значения 'low')

В результате получим массив: где и будет искомое значение (37, '0.89531') т.е возле значение цены 'low' = 0.89531 было обнаружено максимально близких других значений 'low', а именно = 37 !

Ответы

▲ 1Принят

Не совсем понятен вопрос, будем считать. что вы просто хоте использовать функционал pandas для поиска нужных значений, потому как в вашем коде вы его не используете почти совсем:

import pandas as pd
# чтение и подготовка данных
df = pd.read_csv("usdchf_07_2023_support.csv", index_col=0, delimiter='\t', usecols=["time",'open', 'high', 'low', 'close'])
df.index = pd.to_datetime(df.index)
df_res = df.loc[df.index.to_series().between('2023-07-03 15:00:00', '2023-07-07 15:00:00')]

# собственно, решение:
delta = 0.0005
df_res = df_res.assign(num_nearest =
                       df_res["low"].
                       apply(lambda x: abs(x-df_res.loc[:,"low"])
                             .le(delta).sum()))
print(df_res[df_res["num_nearest"] == df_res["num_nearest"]
      .max()].drop_duplicates(subset="low"))
                        open     high      low    close  num_nearest
time                                                                
2023-07-03 17:00:00  0.89691  0.89769  0.89531  0.89613           37
2023-07-03 19:00:00  0.89567  0.89620  0.89541  0.89615           37
2023-07-04 14:00:00  0.89556  0.89630  0.89542  0.89591           37
2023-07-06 22:00:00  0.89601  0.89601  0.89548  0.89548           37
2023-07-07 08:00:00  0.89584  0.89601  0.89538  0.89594           37

то есть, у вас будет 5 значений low (не считая дубликатов) с нужными вам критериями.

UPDATE

Если нужно разбить данные по позициям, где close пробивает или равно low, то можно сделать так, например:

import pandas as pd

df = pd.read_csv("usdchf_07_2023_support.csv", index_col=0, delimiter='\t', usecols=["time",'open', 'high', 'low', 'close'])
df.index = pd.to_datetime(df.index)
df_res = df.loc[df.index.to_series().between('2023-07-03 15:00:00', '2023-07-07 15:00:00')]

res = pd.DataFrame()
for i,g in df_res.groupby(df_res["close"].le(df_res["low"]).cumsum()): # здесь le
# (меньше или равно), поскольку в примере, как я понял, нет close ниже low.
# Если нужно строго меньше, то замените на lt
    g=g.assign(num_nearest =
                       g["low"].
                       apply(lambda x: abs(x-g.loc[:,"low"])
                             .le(delta).sum()))
    res = pd.concat([res, g[g["num_nearest"] == g["num_nearest"].
                     max()].drop_duplicates(subset="low")])

print(res)
                        open     high      low    close  num_nearest
time                                                                
2023-07-04 01:00:00  0.89615  0.89645  0.89578  0.89637            6
2023-07-04 04:00:00  0.89630  0.89651  0.89565  0.89647           15
2023-07-05 01:00:00  0.89671  0.89710  0.89668  0.89702           14
2023-07-06 01:00:00  0.89813  0.89860  0.89808  0.89855            8
2023-07-06 03:00:00  0.89853  0.89898  0.89824  0.89870            8
2023-07-06 04:00:00  0.89873  0.89905  0.89832  0.89835            8
2023-07-06 05:00:00  0.89835  0.89850  0.89805  0.89837            8
2023-07-06 07:00:00  0.89843  0.89911  0.89835  0.89849            8
2023-07-07 14:00:00  0.89530  0.89559  0.89509  0.89558           15

в этом случае точек больше, но и расстояние до соседей меньше, и это расстояние не превышает расстояние до ближайших "пробивающих" close.

** UPDATE 2 ** Узкое место алгоритма в том, что он в пределах выбранной группы не обращал внимание на строки в которых close ниже low в любой другой строке. Вероятно, придется итерировать, что, как очевидно, не самое эффективное про времени занятие:

import pandas as pd

df = pd.read_csv("usdcad_H1_04_2023_support.csv", index_col=0, delimiter='\t', usecols=["time",'open', 'high', 'low', 'close'])
df_res = df.loc[df.index.to_series().between('2023-07-03 15:00:00', '2023-07-07 15:00:00')]
delta = 0.0005
res = pd.DataFrame()
   
for i, g in df_res.groupby(df_res["close"].le(df_res["low"]).cumsum()):
    for row in g.itertuples():
        r = g[(g["close"]<row[3]).cumsum()==0]
        r=r.assign(num_nearest =
                           r["low"].
                           apply(lambda x: abs(x-r.loc[:,"low"])
                                 .le(delta).sum()))
        if len(r):
            res = pd.concat([res, r[r["num_nearest"] == r["num_nearest"].
                         max()].drop_duplicates(subset="low")])
print(res)

получаем res:

                        open     high      low    close  num_nearest
time                                                                
2023-07-03 15:00:00  1.32500  1.32618  1.32444  1.32515            1
2023-07-03 15:00:00  1.32500  1.32618  1.32444  1.32515            2
2023-07-03 16:00:00  1.32515  1.32624  1.32425  1.32443            2
2023-07-03 15:00:00  1.32500  1.32618  1.32444  1.32515            5
2023-07-03 15:00:00  1.32500  1.32618  1.32444  1.32515            5
2023-07-03 15:00:00  1.32500  1.32618  1.32444  1.32515            2
2023-07-03 16:00:00  1.32515  1.32624  1.32425  1.32443            2
2023-07-03 15:00:00  1.32500  1.32618  1.32444  1.32515            1
2023-07-03 15:00:00  1.32500  1.32618  1.32444  1.32515            1
2023-07-03 15:00:00  1.32500  1.32618  1.32444  1.32515            1
2023-07-04 01:00:00  1.32458  1.32504  1.32436  1.32495           10
2023-07-04 03:00:00  1.32482  1.32499  1.32440  1.32488           10
2023-07-04 04:00:00  1.32489  1.32567  1.32457  1.32477           10
2023-07-04 07:00:00  1.32477  1.32539  1.32435  1.32519           10
2023-07-04 01:00:00  1.32458  1.32504  1.32436  1.32495           10
2023-07-04 03:00:00  1.32482  1.32499  1.32440  1.32488           10
2023-07-04 04:00:00  1.32489  1.32567  1.32457  1.32477           10
2023-07-04 07:00:00  1.32477  1.32539  1.32435  1.32519           10
2023-07-04 09:00:00  1.32539  1.32553  1.32330  1.32330            1
2023-07-04 10:00:00  1.32329  1.32400  1.32291  1.32328            5
2023-07-04 11:00:00  1.32328  1.32436  1.32293  1.32374            5
2023-07-04 10:00:00  1.32329  1.32400  1.32291  1.32328            5
2023-07-04 11:00:00  1.32328  1.32436  1.32293  1.32374            5
2023-07-04 10:00:00  1.32329  1.32400  1.32291  1.32328            5
2023-07-04 11:00:00  1.32328  1.32436  1.32293  1.32374            5
2023-07-04 10:00:00  1.32329  1.32400  1.32291  1.32328            5
2023-07-04 11:00:00  1.32328  1.32436  1.32293  1.32374            5
2023-07-04 10:00:00  1.32329  1.32400  1.32291  1.32328            5
2023-07-04 11:00:00  1.32328  1.32436  1.32293  1.32374            5
2023-07-04 10:00:00  1.32329  1.32400  1.32291  1.32328            5
2023-07-04 11:00:00  1.32328  1.32436  1.32293  1.32374            5
2023-07-04 10:00:00  1.32329  1.32400  1.32291  1.32328            5
2023-07-04 11:00:00  1.32328  1.32436  1.32293  1.32374            5
2023-07-04 17:00:00  1.32226  1.32244  1.32136  1.32136            1
2023-07-04 20:00:00  1.32194  1.32276  1.32172  1.32240           10
2023-07-04 20:00:00  1.32194  1.32276  1.32172  1.32240           10
2023-07-05 23:00:00  1.32816  1.32864  1.32790  1.32790            1
2023-07-07 07:00:00  1.33640  1.33664  1.33601  1.33641           16
2023-07-07 07:00:00  1.33640  1.33664  1.33601  1.33641           16
2023-07-05 23:00:00  1.32816  1.32864  1.32790  1.32790            1
2023-07-07 07:00:00  1.33640  1.33664  1.33601  1.33641           16

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