How to calculate Volume Weighted Average Price (VWAP) using a pandas dataframe with ask and bid price?

随声附和 提交于 2020-01-04 18:02:10

问题


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 NaNs

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!