Поскольку sum
является встроенной функцией в Python, я бы хотел заменить ее на z
. И поскольку у вас есть ограничение на то, что level
будет идентичным в (buy_A
, sell_B
), а также (sell_A
, buy_B
), давайте изменим ваше уравнение, чтобы сделать это более понятным:
z = buy_A + buy_B - sell_A - sell_B
= (buy_A - sell_B) + (buy_B - sell_A)
= x + y
Давайте углубимся в ваш вопрос. Первое, что мы делаем, это переформатируем исходный фрейм данных для выравнивания уровней:
tmp = df.rename({'price1': 'sell', 'price2': 'buy'}, axis=1) \
.set_index(['level', 'type']) \
.unstack()
# tmp:
sell buy
type A B A B
level
5250 0.2330 0.0040 0.2865 0.0060
5500 0.1970 0.0055 0.2545 0.0075
5750 0.1615 0.0075 0.2230 0.0090
6000 0.1270 0.0105 0.1925 0.0125
6250 0.1215 0.0135 0.1635 0.0165
Затем вычисляем наши x
и y
:
x = tmp[('buy', 'A')] - tmp[('sell', 'B')]
y = tmp[('buy', 'B')] - tmp[('sell', 'A')]
Далее нам нужно рассчитать z
. z
не просто x
+ y
, но каждое значение в x
добавляется к каждому значению в y
; следовательно, z
является квадратной матрицей. Но нам не нужна вся матрица. Нам нужен только треугольник ниже главной диагональной линии. Модуль numpy.ma
предоставляет функции для замаскированных массивов, где мы можем пометить определенные элементы, как если бы они не существовали.
import numpy.ma as ma
# Mask away the upper triangle, including the main diagonal
# len(x) == len(y)
mask = np.triu(np.ones((len(x), len(y))))
# Use numpy broadcasting to add every value in `x` to every value in `y`
# `x` and `y` are pandas Series. `.values` get the underlying numpy array
#
# `y.values[:, None]` raises `y` to another dimension. This is what
# triggers numpy's array broadcasting and make `z` a square matrix
z = -ma.array(x.values + y.values[:, None], mask=mask)
# If you want to visualize `z`, type this into the debugger
# pd.DataFrame(z, index=tmp.index, columns=tmp.index)
Последний шаг - получить уровни, которые дают максимальное значение при сложении вместе. Если есть несколько ячеек с максимальным значением, будет получена только первая:
i,j = np.unravel_index(z.argmax(), z.shape)
# The level with the max sum
level1, level2 = tmp.index[[i,j]] # 7250, 7000
# The max value of the sums
z[i,j] # -0.043