Хорошо, вот оно
df['trade_price'] = df.apply(lambda x: x['bid'] if x['trade']=='bid' else x['ask'], axis=1)
df['vwap'] = (df['trade_price'] * df['trade_size']).cumsum() / df['trade_size'].fillna(0).cumsum()
Первая строка:
Он сохраняет trade_price в новом столбце, поэтому его проще получить позже.
Если вы хотите, вы можете удалить эту строку и сделать функцию (возможно, ее легче читать). Но я предпочитаю видеть промежуточные результаты.
Вопрос: почему он имеет значения, даже когда нет торговли?
A: из-за того, как написана лямбда. else
захватывает цену ask
. Но это не будет иметь значения из-за следующего шага.
Вторая строка:
Здесь происходит реальный расчет.
В первой части рассчитывается общий объем торгов до этого момента (как вы сказали, использование кумулятивных сумм облегчает жизнь).
Вторая часть вычисляет общий объем торгов до этого момента (опять же, кумулятивные суммы).
Если хотите, можете разбить эту строку и создать дополнительные промежуточные столбцы.
Q: почему fillna(0)
?
A: таким образом, общий объем не получится NaNs
, и вы не получите ошибку деления
В: почему так много NaNs
в столбце vwap
?
A: Из-за линий, у которых нет торговли. Вы можете заполнить их 0s
, но было бы лучше сохранить информацию об отсутствии торговли.
Ps .: вы можете получить неправильный результат, так как он учитывает объем и цену только в одном направлении. Но вы можете попытаться инвертировать некоторый сигнал, чтобы зафиксировать объем так, как вы ожидаете (например: изменение цены ask
на отрицательную).
и вывод этого кода:
trade_price vwap
1 152.54 NaN
2 152.54 NaN
3 152.54 NaN
4 152.54 NaN
5 152.54 NaN
6 152.54 NaN
7 152.54 NaN
8 152.54 152.54
9 152.54 NaN
10 152.54 NaN
11 152.54 NaN
12 152.54 152.54
13 152.55 NaN
14 152.54 152.54
15 152.55 NaN
16 152.55 NaN
17 152.55 NaN
18 152.55 NaN
19 152.55 NaN
20 152.55 NaN