0

我有一个 csv 文件,其中包含过去 1 年许多债券的买卖价格(使用 ISIN 标识符)。使用这些历史价格,我试图计算每只债券的历史波动率。尽管这通常应该是一件容易的事,但问题在于并非所有债券都具有完全相同的交易价格数据天数,而它们都在同一列中并且没有堆叠。因此,如果我需要计算滚动标准偏差,我不能选择 1 年 252 天的标准滚动窗口。

数据集具有这种格式-

营业日期 伊辛 出价
日期 1 ISIN1 P1 P2
日期 2 ISIN1 P1 P2
日期 252 ISIN1 P1 P2
日期 1 ISIN2 P1 P2
日期 2 ISIN2 P1 P2

……

& 很快。

我当前的代码如下 -

vol_df = pd.read_csv('hist_prices.csv')
vol_df['BusinessDate'] = pd.to_datetime(vol_df['BusinessDate'])
vol_df[Mid Price'] = vol_df[['Bid', 'Ask']].mean(axis = 1)
vol_df['log_return'] = vol_df.groupby('ISIN')['Mid Price'].apply(lambda x: np.log(x) - np.log(x.shift(1)))
vol_df['hist_vol'] = vol_df['log_return'].std() * np.sqrt(252)

最后一行代码似乎给出了列中的所有 NaN 值。这很可能是因为计算标准偏差的操作发生在同一行号上,而不是针对数字列表。我尝试替换最后一行以使用 rolling_std-

vol_df.set_index('BusinessDate').groupby('ISIN').rolling(window = 1, freq = 'A').std()['log_return']

但这也无济于事。它为每个 ISIN 提供 2 个数字。我还尝试使用 pivot() 将 ISIN 放在列中,将 BusinessDate 作为索引,将价格作为“值”。但它给出了一个错误。此外,我有近 9,000 个不同的 ISIN,因此将它们放在列中以计算每列的 std() 可能不是最好的方法。关于如何解决这个问题的任何线索?

4

2 回答 2

0

好的,这现在几乎可以工作了。

每个 ISIN 确实需要一些数学运算来计算滚动期,我在示例中只使用了 3 和 2,您可能需要计算一年中的交易天数或其他什么,并以某种方式将其修复为每个 ISIN。

然后你需要弄清楚如何将数据合并回来。输出实际上有错误,因为它更新了一个副本,但这正是我在这里寻找的。我相信知道更多的人可以在这一点上解决它。我无法让它进行合并。

toy_data={'BusinessDate': ['10/5/2020','10/6/2020','10/7/2020','10/8/2020','10/9/2020',
                           '10/12/2020','10/13/2020','10/14/2020','10/15/2020','10/16/2020',
                           '10/5/2020','10/6/2020','10/7/2020','10/8/2020'],
          'ISIN': [1,1,1,1,1, 1,1,1,1,1, 2,2,2,2],
          'Bid': [0.295,0.295,0.295,0.295,0.295,
                  0.296, 0.296,0.297,0.298,0.3,
                  2.5,2.6,2.71,2.8],
          'Ask': [0.301,0.305,0.306,0.307,0.308,
                  0.315,0.326,0.337,0.348,0.37,
                  2.8,2.7,2.77,2.82]}
#vol_df = pd.read_csv('hist_prices.csv')
vol_df = pd.DataFrame(toy_data)

vol_df['BusinessDate'] = pd.to_datetime(vol_df['BusinessDate'])
vol_df['Mid Price'] = vol_df[['Bid', 'Ask']].mean(axis = 1)
vol_df['log_return'] = vol_df.groupby('ISIN')['Mid Price'].apply(lambda x: np.log(x) - np.log(x.shift(1)))
vol_df.dropna(subset = ['log_return'], inplace=True)
# do some math here to calculate how many days you want to roll for an ISIN
# maybe count how many days over a 1 year period exist???
# not really sure how you'd miss days unless stuff just doesnt trade
# (but I don't need to understand it anyway)
rolling = {1: 3, 2: 2}
for isin in vol_df['ISIN'].unique():
    roll = rolling[isin]
    print(f'isin={isin}, roll={roll}')
    df_single = vol_df[vol_df['ISIN']==isin]
    df_single['rolling'] = df_single['log_return'].rolling(roll).std()
    # i can't get the right syntax to merge data back, but this shows it
    vol_df[isin, 'rolling'] = df_single['rolling']
    print(df_single)
print(vol_df)

输出(减去警告错误):

isin=1, roll=3
  BusinessDate  ISIN    Bid    Ask  Mid Price  log_return   rolling
1   2020-10-06     1  0.295  0.305     0.3000    0.006689       NaN
2   2020-10-07     1  0.295  0.306     0.3005    0.001665       NaN
3   2020-10-08     1  0.295  0.307     0.3010    0.001663  0.002901
4   2020-10-09     1  0.295  0.308     0.3015    0.001660  0.000003
5   2020-10-12     1  0.296  0.315     0.3055    0.013180  0.006650
6   2020-10-13     1  0.296  0.326     0.3110    0.017843  0.008330
7   2020-10-14     1  0.297  0.337     0.3170    0.019109  0.003123
8   2020-10-15     1  0.298  0.348     0.3230    0.018751  0.000652
9   2020-10-16     1  0.300  0.370     0.3350    0.036478  0.010133
isin=2, roll=2
   BusinessDate  ISIN   Bid  ...    log_return  (1, rolling)   rolling
11   2020-10-06     2  2.60  ...  2.220446e-16           NaN       NaN
12   2020-10-07     2  2.71  ...  3.339828e-02           NaN  0.023616
13   2020-10-08     2  2.80  ...  2.522656e-02           NaN  0.005778

[3 rows x 8 columns]
   BusinessDate  ISIN    Bid  ...    log_return  (1, rolling)  (2, rolling)
1    2020-10-06     1  0.295  ...  6.688988e-03           NaN           NaN
2    2020-10-07     1  0.295  ...  1.665279e-03           NaN           NaN
3    2020-10-08     1  0.295  ...  1.662511e-03      0.002901           NaN
4    2020-10-09     1  0.295  ...  1.659751e-03      0.000003           NaN
5    2020-10-12     1  0.296  ...  1.317976e-02      0.006650           NaN
6    2020-10-13     1  0.296  ...  1.784313e-02      0.008330           NaN
7    2020-10-14     1  0.297  ...  1.910886e-02      0.003123           NaN
8    2020-10-15     1  0.298  ...  1.875055e-02      0.000652           NaN
9    2020-10-16     1  0.300  ...  3.647821e-02      0.010133           NaN
11   2020-10-06     2  2.600  ...  2.220446e-16           NaN           NaN
12   2020-10-07     2  2.710  ...  3.339828e-02           NaN      0.023616
13   2020-10-08     2  2.800  ...  2.522656e-02           NaN      0.005778
于 2021-08-19T21:40:23.280 回答
0

我能够以粗略的方式解决这个问题-

vol_df_2 = vol_df.groupby('ISIN')['logret'].std()
vol_df_3 = vol_df_2.to_frame()
vol_df_3.rename(columns = {'logret':'daily_std}, inplace = True)

上面的第一行是返回一个系列和名为“logret”的标准偏差列。因此,第 2 行和第 3 行代码将其转换为数据框并重命名每日标准偏差。最后,可以使用 sqrt(252) 计算年度成交量。

如果有人有更好的方法在同一个数据框中完成它而不是创建一个系列,那就太好了。

于 2021-08-23T10:43:12.810 回答