У меня есть ежедневные данные о прибыли, и я пытаюсь найти лучшие комбинации двух активов, которые будут приносить наибольшую прибыль. Мне нужно купить один актив длинным и коротким другого и найти наиболее эффективную пару за промежуток времени.
Я могу сделать это sh, просматривая все перестановки, но это очень медленно. (нет ничего удивительного) Я думаю это может быть тип проблемы, подходящей для линейной оптимизации с такой библиотекой, как PuLP.
Вот пример полного решения проблемы. Я намеренно сохраняю данные простыми, но у меня есть 1000 активов, которые мне нужно найти. До финиша sh потребовалось около 45 минут с неэффективным, ручным подходом, который я обрисовал в общих чертах ниже.
Примечание: потому что длинная «Альфа» и короткая «Браво» отличаются от длинных «Браво» и коротко "Альфа", я использую перестановки, а не комбинации.
Редактировать: в случае, если некоторые не знакомы с longing и shorting Я пытаюсь соединить наивысшую прибыль с наименьшей прибылью (с short , я получаю больше прибыли, чем более отрицательное значение)
Логика c будет читать что-то например:
Для всех перестановок узлов добавьте прибыль в один узел к обратной прибыли в два узла, чтобы получить общую прибыль. Найдите пару с самой высокой общей прибылью.
Вот моя очень неэффективная (но работающая) реализация:
# Sample data
profits = [
('2019-11-18', 'Alpha', -79.629698),
('2019-11-19', 'Alpha', -17.452517),
('2019-11-20', 'Alpha', -19.069558),
('2019-11-21', 'Alpha', -66.061564),
('2019-11-18', 'Bravo', -87.698670),
('2019-11-19', 'Bravo', -73.812616),
('2019-11-20', 'Bravo', 198.513246),
('2019-11-21', 'Bravo', -69.579466),
('2019-11-18', 'Charlie', 66.302287),
('2019-11-19', 'Charlie', -16.132065),
('2019-11-20', 'Charlie', -123.735898),
('2019-11-21', 'Charlie', -30.046416),
('2019-11-18', 'Delta', -131.682322),
('2019-11-19', 'Delta', 13.296473),
('2019-11-20', 'Delta', 23.595053),
('2019-11-21', 'Delta', 14.103027),
]
profits_df = pd.DataFrame(profits, columns=('Date','Node','Profit')).sort_values('Date')
profits_df
выглядит так:
+----+------------+---------+-------------+
| | Date | Node | Profit |
+----+------------+---------+-------------+
| 0 | 2019-11-18 | Alpha | -79.629698 |
| 4 | 2019-11-18 | Bravo | -87.698670 |
| 8 | 2019-11-18 | Charlie | 66.302287 |
| 12 | 2019-11-18 | Delta | -131.682322 |
| 1 | 2019-11-19 | Alpha | -17.452517 |
+----+------------+---------+-------------+
Чтобы решить проблему вручную, я могу сделать это:
date_dfs = []
# I needed a way to take my rows and combine them pairwise, this
# is kind of gross but it does work
for date, date_df in profits_df.groupby('Date'):
tuples = [tuple(x) for x in date_df[['Node', 'Profit']].to_numpy()]
pp = list(itertools.permutations(tuples, 2))
flat_pp = [[p[0][0], p[0][1], p[1][0], p[1][1]] for p in pp]
df = pd.DataFrame(flat_cc, columns=['Long', 'LP', 'Short', 'SP'])
date_dfs.append(df)
result_df = pd.concat(daily_dfs)
result_df['Pair'] = result_df['Long'] + '/' + result_df['Short']
result_df['Profit'] = result_df['LP'] + result_df['SP'].multiply(-1)
result_df.groupby('Pair')['Profit'].sum().sort_values(ascending=False)
Вычисляя прибыль для всех перестановок каждый день, а затем суммируя их, я получаю следующий результат:
+-----------------------------+
| Pair |
+-----------------------------+
| Bravo/Alpha 149.635831 |
| Delta/Alpha 101.525568 |
| Charlie/Alpha 78.601245 |
| Bravo/Charlie 71.034586 |
| Bravo/Delta 48.110263 |
| Delta/Charlie 22.924323 |
| Charlie/Delta -22.924323 |
| Delta/Bravo -48.110263 |
| Charlie/Bravo -71.034586 |
| Alpha/Charlie -78.601245 |
| Alpha/Delta -101.525568 |
| Alpha/Bravo -149.635831 |
+-----------------------------+
Я уверен, что есть более эффективный способ go об этом. Я не понимаю тонкостей оптимизации, но знаю, что из достаточно, чтобы понять, что это возможное решение. Я не понимаю разницы между линейной оптимизацией и нелинейной, поэтому я прошу прощения, если я неправильно понимаю номенклатуру.
Может кто-нибудь предложить подход, который я должен попробовать?