事件研究-如何将输出打包成可管理的形式?

时间:2018-12-27 10:18:40

标签: python python-3.x pandas finance quantitative-finance

我正在进行事件研究,并希望将功能的结果打包为易于管理的形式。下面的函数以以下形式返回结果:

Results

结果是针对一个事件窗口(-5,+ 5天)分析的一个索引。我需要分析17个索引和120多个活动日,这需要大量的输出才能进行进一步的计算。

我尝试将结果打包到字典中,但是输出是多级字典,我不知道如何将其解压缩成有意义的形状。

我正在考虑将结果附加到np.ndarray或替换函数的输出,以便它将值的列表/系列/数组作为输入,然后汇总输出。

不幸的是,这超出了我的技能水平,因为我对Python相当陌生,但是我正在尝试学习尽可能多的东西,因此任何建议/帮助都将不胜感激。

功能:

def get_cum_returns(prices, sid, date, days_before, days_after, benchmark_sid):
"""
Calculates cumulative and abnormal returns for the sid & benchmark

Parameters
----------
prices : pd.DataFrame
    Pricing history DataFrame obtained from `get_pricing`. Index should
    be the datetime index and sids should be columns.
sid : int or zipline.assets._assets.Equity object
    Security that returns are being calculated for.
date : datetime object
    Date that will be used as t=0 for cumulative return calcuations. All
    returns will be calculated around this date.
days_before, days_after : int
    Days before/after to be used to calculate returns for.
benchmark :  int or zipline.assets._assets.Equity object

Returns
-------
sid_returns : pd.Series
    Cumulative returns time series from days_before ~ days_after from date
    for sid
benchmark_returns : pd.Series
    Cumulative returns time series for benchmark sid
abnormal_returns : pd.Series
    Abnomral cumulative returns time series for sid compared against benchmark
"""

day_zero_index = prices.index.searchsorted(date)
starting_index = max(day_zero_index - days_before, 0)
ending_index   = min(day_zero_index + days_after + 1, len(prices.index) - 1)

if starting_index < 0 or ending_index >= len(prices.index):
    return None

if sid == benchmark_sid:
    temp_price = prices.iloc[starting_index:ending_index,:].loc[:,[sid]]
else:
    temp_price = prices.iloc[starting_index:ending_index,:].loc[:,[sid, benchmark_sid]]

beta = calc_beta(sid, benchmark_sid, temp_price)
if beta is None:
    return

daily_ret = temp_price.pct_change().fillna(0)

daily_ret['abnormal_returns'] = daily_ret[sid] - beta*daily_ret[benchmark_sid]

cum_returns = (daily_ret + 1).cumprod() - 1

try:
    # If there's not enough data for event study,
    # return None
    cum_returns.index = range(starting_index - day_zero_index,
                              ending_index - day_zero_index)
except:
    return None

sid_returns      = cum_returns[sid] - cum_returns[sid].iloc[0]
bench_returns    = cum_returns[benchmark_sid] - cum_returns[benchmark_sid].iloc[0]
abnormal_returns = cum_returns['abnormal_returns'] - cum_returns['abnormal_returns'].iloc[0]

return sid_returns, bench_returns, abnormal_returns

非常感谢,

1 个答案:

答案 0 :(得分:0)

是的,您的输出看起来像这样吗?

array = [pd.Series([1, 2, 3, 4, 5], index = [-3, -2, -1, 0, 1], name='first'),
         pd.Series([11, 22, 33, 44, 55, 66], index = [-4, -3, -2, -1, 0, 1], name='second'),
         pd.Series([111, 222, 333, 444, 555, 666, 777], index = [-4, -3, -2, -1, 0, 1, 2], name='last')]

退出:

[-3    1
 -2    2
 -1    3
  0    4
  1    5
 Name: first, dtype: int64, -4    11
 -3    22
 -2    33
 -1    44
  0    55
  1    66
 Name: second, dtype: int64, -4    111
 -3    222
 -2    333
 -1    444
  0    555
  1    666
  2    777
 Name: last, dtype: int64]

如果我是对的,则可以使用pd.concat串联系列。

df = pd.concat(array, axis=1)

退出:

    first  second  last
-4    NaN    11.0   111
-3    1.0    22.0   222
-2    2.0    33.0   333
-1    3.0    44.0   444
 0    4.0    55.0   555
 1    5.0    66.0   666
 2    NaN     NaN   777

此后,如果需要,可以用df.fillna(value)填充NaN值,其中value应该是一个数字。如果需要,可以得到一个矩阵:

pd.concat(array, axis=1).fillna(0).as_matrix()

退出:

array([[  0.,  11., 111.],
       [  1.,  22., 222.],
       [  2.,  33., 333.],
       [  3.,  44., 444.],
       [  4.,  55., 555.],
       [  5.,  66., 666.],
       [  0.,   0., 777.]])

希望对您有帮助。

UPD:

也许对您来说,任务最好有一个表(天,值,id)。

array = [pd.DataFrame(data=series.rename('value')).assign(ID = i) for i, series in enumerate(array)]

退出:

[    value  ID
 -3      1   0
 -2      2   0
 -1      3   0
  0      4   0
  1      5   0,     value  ID
 -4     11   1
 -3     22   1
 -2     33   1
 -1     44   1
  0     55   1
  1     66   1,     value  ID
 -4    111   2
 -3    222   2
 -2    333   2
 -1    444   2
  0    555   2
  1    666   2
  2    777   2]

table = pd.concat(array, axis=0).reset_index().rename(columns={'index': 'day'})

退出:

    day  value  ID
0    -3      1   0
1    -2      2   0
2    -1      3   0
3     0      4   0
4     1      5   0
5    -4     11   1
6    -3     22   1
7    -2     33   1
8    -1     44   1
9     0     55   1
10    1     66   1
11   -4    111   2
12   -3    222   2
13   -2    333   2
14   -1    444   2
15    0    555   2
16    1    666   2
17    2    777   2

之后,您可以按天或ID分组,然后做您想做的事。