问题
How do i create another column called vwap which calculates the vwap if my table is as shown below?
time bid_size bid ask ask_size trade trade_size phase
0 2019-01-07 07:45:01.064515 495 152.52 152.54 19 NaN NaN OPEN
1 2019-01-07 07:45:01.110072 31 152.53 152.54 19 NaN NaN OPEN
2 2019-01-07 07:45:01.116596 32 152.53 152.54 19 NaN NaN OPEN
3 2019-01-07 07:45:01.116860 32 152.53 152.54 21 NaN NaN OPEN
4 2019-01-07 07:45:01.116905 34 152.53 152.54 21 NaN NaN OPEN
5 2019-01-07 07:45:01.116982 34 152.53 152.54 31 NaN NaN OPEN
6 2019-01-07 07:45:01.147901 38 152.53 152.54 31 NaN NaN OPEN
7 2019-01-07 07:45:01.189971 38 152.53 152.54 31 ask 15.0 OPEN
8 2019-01-07 07:45:01.189971 38 152.53 152.54 16 NaN NaN OPEN
9 2019-01-07 07:45:01.190766 37 152.53 152.54 16 NaN NaN OPEN
10 2019-01-07 07:45:01.190856 37 152.53 152.54 15 NaN NaN OPEN
11 2019-01-07 07:45:01.190856 37 152.53 152.54 16 ask 1.0 OPEN
12 2019-01-07 07:45:01.193938 37 152.53 152.55 108 NaN NaN OPEN
13 2019-01-07 07:45:01.193938 37 152.53 152.54 15 ask 15.0 OPEN
14 2019-01-07 07:45:01.194326 2 152.54 152.55 108 NaN NaN OPEN
15 2019-01-07 07:45:01.194453 2 152.54 152.55 97 NaN NaN OPEN
16 2019-01-07 07:45:01.194479 6 152.54 152.55 97 NaN NaN OPEN
17 2019-01-07 07:45:01.194507 19 152.54 152.55 97 NaN NaN OPEN
18 2019-01-07 07:45:01.194532 19 152.54 152.55 77 NaN NaN OPEN
19 2019-01-07 07:45:01.194598 19 152.54 152.55 79 NaN NaN OPEN
Sorry, the table is not clear, but the second most right column is trade_size, on its left is trade, which shows the side of the trade( bid or ask). if both trade_size and trade are NaN, it indicates that no trade occur at that timestamp.
If df['trade'] == "ask", trade price will be the price in column 'ask' and if df['trade] == "bid", the trade price will be the price in column 'bid'. Since there are 2 prices, may I ask how can i calculate the vwap, df['vwap']?
My idea is to use np.cumsum(). Thank you!
回答1:
You can use np.where to give you the price from the correct column (bid
or ask
) depending on the value in the trade
column. Note that this gives you the bid price when no trade occurs, but because this is then multiplied by a NaN
trade size it won't matter. I also forward filled the VWAP.
volume = df['trade_size']
price = np.where(df['trade'].eq('ask'), df['ask'], df['bid'])
df = df.assign(VWAP=((volume * price).cumsum() / vol.cumsum()).ffill())
>>> df
time bid_size bid ask ask_size trade trade_size phase VWAP
0 2019-01-07 07:45:01.064515 495 152.52 152.54 19 NaN NaN OPEN NaN
1 2019-01-07 07:45:01.110072 31 152.53 152.54 19 NaN NaN OPEN NaN
2 2019-01-07 07:45:01.116596 32 152.53 152.54 19 NaN NaN OPEN NaN
3 2019-01-07 07:45:01.116860 32 152.53 152.54 21 NaN NaN OPEN NaN
4 2019-01-07 07:45:01.116905 34 152.53 152.54 21 NaN NaN OPEN NaN
5 2019-01-07 07:45:01.116982 34 152.53 152.54 31 NaN NaN OPEN NaN
6 2019-01-07 07:45:01.147901 38 152.53 152.54 31 NaN NaN OPEN NaN
7 2019-01-07 07:45:01.189971 38 152.53 152.54 31 ask 15.0 OPEN 152.54
8 2019-01-07 07:45:01.189971 38 152.53 152.54 16 NaN NaN OPEN 152.54
9 2019-01-07 07:45:01.190766 37 152.53 152.54 16 NaN NaN OPEN 152.54
10 2019-01-07 07:45:01.190856 37 152.53 152.54 15 NaN NaN OPEN 152.54
11 2019-01-07 07:45:01.190856 37 152.53 152.54 16 ask 1.0 OPEN 152.54
12 2019-01-07 07:45:01.193938 37 152.53 152.55 108 NaN NaN OPEN 152.54
13 2019-01-07 07:45:01.193938 37 152.53 152.54 15 ask 15.0 OPEN 152.54
14 2019-01-07 07:45:01.194326 2 152.54 152.55 108 NaN NaN OPEN 152.54
15 2019-01-07 07:45:01.194453 2 152.54 152.55 97 NaN NaN OPEN 152.54
16 2019-01-07 07:45:01.194479 6 152.54 152.55 97 NaN NaN OPEN 152.54
17 2019-01-07 07:45:01.194507 19 152.54 152.55 97 NaN NaN OPEN 152.54
18 2019-01-07 07:45:01.194532 19 152.54 152.55 77 NaN NaN OPEN 152.54
19 2019-01-07 07:45:01.194598 19 152.54 152.55 79 NaN NaN OPEN 152.54
回答2:
Here is one possible approach
Append VMAP
column full of NaN
s
df['VMAP'] = np.nan
Calculate VMAP
(based on this equation provided by the OP) and assign values based on ask
or bid
, as requierd by the OP
for trade in ['ask','bid']:
# Find indexes of `ask` or `buy`
bid_idx = df[df.trade==trade].index
# Slice DF based on `ask` or `buy`, using indexes
df.loc[bid_idx, 'VMAP'] = (
(df.loc[bid_idx, 'trade_size'] * df.loc[bid_idx, trade]).cumsum()
/
(df.loc[bid_idx, 'trade_size']).cumsum()
)
print(df.iloc[:,1:])
time bid_size bid ask ask_size trade trade_size phase VMAP
0 07:45:01.064515 495 152.52 152.54 19 NaN NaN OPEN NaN
1 07:45:01.110072 31 152.53 152.54 19 NaN NaN OPEN NaN
2 07:45:01.116596 32 152.53 152.54 19 NaN NaN OPEN NaN
3 07:45:01.116860 32 152.53 152.54 21 NaN NaN OPEN NaN
4 07:45:01.116905 34 152.53 152.54 21 NaN NaN OPEN NaN
5 07:45:01.116982 34 152.53 152.54 31 NaN NaN OPEN NaN
6 07:45:01.147901 38 152.53 152.54 31 NaN NaN OPEN NaN
7 07:45:01.189971 38 152.53 152.54 31 ask 15.0 OPEN 152.54
8 07:45:01.189971 38 152.53 152.54 16 NaN NaN OPEN NaN
9 07:45:01.190766 37 152.53 152.54 16 NaN NaN OPEN NaN
10 07:45:01.190856 37 152.53 152.54 15 NaN NaN OPEN NaN
11 07:45:01.190856 37 152.53 152.54 16 ask 1.0 OPEN 152.54
12 07:45:01.193938 37 152.53 152.55 108 NaN NaN OPEN NaN
13 07:45:01.193938 37 152.53 152.54 15 ask 15.0 OPEN 152.54
14 07:45:01.194326 2 152.54 152.55 108 NaN NaN OPEN NaN
15 07:45:01.194453 2 152.54 152.55 97 NaN NaN OPEN NaN
16 07:45:01.194479 6 152.54 152.55 97 NaN NaN OPEN NaN
17 07:45:01.194507 19 152.54 152.55 97 NaN NaN OPEN NaN
18 07:45:01.194532 19 152.54 152.55 77 NaN NaN OPEN NaN
19 07:45:01.194598 19 152.54 152.55 79 NaN NaN OPEN NaN
EDIT
As @edinho
correctly indicated, the VMAP
is the same as the trade_price
column.
回答3:
Ok, here it is
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()
The first line:
It saves the trade_price in a new column, so it is easier to retrieve it later.
If you want, you can delete this line and make a function (maybe it is easier to read). But I prefer to see the intermediary results.
Q: why it has values even when there is no trade?
A: because of the way the lambda is written. The else
captures the ask
price. But it won't make a difference, because of the next step.
Second line:
Here the real calculation takes places.
The first part calculate the total volume traded until that moment (as you said, using cumulative sums makes life easier).
The second part calculates the total volume traded until that moment (again, cumulative sums).
If you want, you can break this line and make more intermediary columns.
Q: why the fillna(0)
?
A: so the total volume don't get NaNs
and you don't get a division error
Q: why so many NaNs
in the vwap
column?
A: Because of the lines that don't have trade. You can fill them with 0s
, but would be better to keep the 'no trade' information.
Ps.: you may get a wrong result as it is considering volume and price only in the same direction. But, you could try to invert some signal to fix the volume in the way you expect (for instance: changing the ask
price to negative).
and this code output:
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
来源:https://stackoverflow.com/questions/55699494/how-to-calculate-volume-weighted-average-price-vwap-using-a-pandas-dataframe-w