python做事件研究法_EventStudy(附Python代码)(⼀)过年回国就赶上了肺炎...也突然有时间来写写专栏了!第⼀个话题就写写事件研究法,event study吧,原因之⼀当然就是这个肺炎事件,可能我还太年轻,才发现瘟疫事件对⾦融市场的影响,富时A50指数,⽇经225已经连续跌两天了,美国股市也是从年前就已经闻到了瘟疫带来的恐慌早早开始避险。所以是时候来讨论⼀下event study了。不知道会不会有未来会有很多关于写这次瘟疫的event study的⽂章。
所以根据字⾯意思,事件研究法就是研究某⼀个事件对股价(收益率)的影响,某个积极(也可能是消极)信息对于股价的影响,说到这⼉,就不得不提⼀下宗师 Eugene F. Fama了——event study基本上还是根据有效市场假说⽽来,市场消化新的信息,并且对新的信息作出显著的反应。当然这个反应是⽴刻⽽且及时的,在事件公布之后,股价或许会归于正常,或许会因为是⼀个很差的消息⽽⼀蹶不振,也可能影响
根本不显著。也就是如本⽂封⾯:
(当然这个图⽚来⾃于Journal of Economic Literature)超额收益 -- AR -- Abnormal Return
进⼊正题,⾸先要定义两个区间,estimation window和event window,也就是⽤来估计market model的⼀个时间段(estimation),另外⼀个event window⽤来计算超额收益:
,
其中,
也就是 abnormal return 在 第 i 期的超额收益,
是实际第 i 期的实际收益,
也就是如果没有 X 事件发⽣条件下的期望收益。所以计算超额收益,主要就是计算这个
delphi开发什么语言。⽽此项则是需要⽤到 estimation window中的估计参数。那么我们来定义⼀下这两个window:
⽅便起见,estiamtion window为
,event window为
python基础代码大全加翻译。通常来说,estimation的跨度设置为250个交易⽇,event的跨度设置为20个交易⽇(完全⾃由,当然也取决于事件长度)。
下⼀步我们来设置我们benchmark model,也就是⼀个能代表市场期望收益的模型,在我的例⼦中,我就使⽤ Fama 的经典三因⼦模型:将上边的三因⼦模型以矩阵的形式求解,
⼀个
的向量,
为⼀个
的矩阵,t为我们estimation window的长度,可得:
也就是我们的超额收益啦(abnormal return)。我们根据统计检验⼀下,
是否显著:
AAR -- Aggregated Abnormal Return
Emmmm这个词不知道怎么翻译了,总之就是做⼀个简单算数平均数,由于我们研究⼀个event可能涉及到多个公司,⽽这些公司并不⼀定都会在 event date 出现显著的超额收益,所以可以看⼀下在整个截⾯上,是否整体的超额收益是否显著,当然,这⾥涉及到⼀个⽐较复杂的问题,我们需要假设,所有公司⾯临的事件的时间跨度并⽆重叠,否则就很难辨认是不是公司间的 correlation 导致可能的同涨同跌现象,在我所给的例⼦中,就存在这样的时间重叠,所以需要考虑这个问题。CAR -- Cumulative Abnormal Return 和 CAAR --Cumulative Aggregated Abnormal Return
顾名思义, 现在就要看⼀下在整个 event window 中是否这个 超额收益 都显著:
根据统计推断,
; 同理,计算CAAR是⼀个截⾯上的期望,再在这样的期望上计算其对应的置信区间。栗⼦(含代码)!
我的栗⼦中选取的是16家曾发⽣过财务/经营丑闻的公司分别是:
estimation window = 250, event window = 20; 开始:
# 调必要的包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import statsmodels.api as sm
import statsmodels.formula.api as smf
import scipy.stats as st
fig = plt.figure()
sns.set_palette("GnBu_d")ssl协议端口
sns.set_style('whitegrid')
%matplotlib inlineposix消息队列
#(导⼊数据各有各的⽅式,就不展⽰啦)
## 导⼊的数据中包含上述公司的历史收益率,以及发⽣event date保存为datetime格式,以及对应的
## 三因⼦历史数据,将历史收益率和三因⼦数据按datetime合并在⼀个DataFrame中;将event date
## 单独留在⼀个DataFrame中备⽤。
## 如下:
def eventstudy(returndata=return_df, eventdata=event_data, stocklist=stocklist):
"""returndata: is a dataframe with the market returns of the different firmseventdata: eventdata for the different firmsstocklist: a list of the firms involved in the analysisReturns:abnreturn: a dictionary of the abnormal returns for each firm in their respective eventwindows -/+20"""
abnreturn ={} # abnormal returns on the event window
returndata = set_index()
Bse = []
for stock in stocklist:
mythologicaleventindex = int(returndata[returndata['Date'] == str(eventdata.at[stock,'EventDate'])].index.values)
print(eventindex)
event_df = returndata.loc[eventindex-20: eventindex+20, ['Date',stock,'RF', 'Mkt_RF','SMB','HML' ]]
estimation_df = returndata.loc[eventindex-270: eventindex-21, ["Date",stock, "RF", "Mkt_RF","SMB","HML" ]]
formula = stock + " - RF ~ Mkt_RF + SMB + HML"
beta_Mkt = sm.OLS.from_formula(formula, data=estimation_df).fit().params["Mkt_RF"]
beta_SMB = sm.OLS.from_formula(formula, data=estimation_df).fit().params["SMB"]
beta_HML = sm.OLS.from_formula(formula, data=estimation_df).fit().params["HML"]
alpha = sm.OLS.from_formula(formula, data=estimation_df).fit().params["Intercept"]
standard_error = sm.OLS.from_formula(formula, data=estimation_df).fit().bse
Bse.append(standard_error)
print("{}, beta_Mkt= {}, beta_SMB = {}, beta_HML = {}, alpha= {}".format(stock, beta_Mkt, beta_SMB, beta_HML, alpha))
#expected returns for each firm in the estimation window
expectedreturn_eventwindow = ((event_df[['Mkt_RF']].values * beta_Mkt) + (event_df[['SMB']].values *
beta_SMB) + (event_df[['HML']].values * beta_HML ) + alpha)
#abnormal returns on the event window - AR
abnormal_return = event_df[stock].values - list(flatten(expectedreturn_eventwindow))
abnreturn[stock] = abnormal_return
abnormalreturns_df = pd.DataFrame(abnreturn)
abnormalreturns_df.index = abnormalreturns_df.index-20
return abnormalreturns_df
这⼀步应该是最复杂的⼀步,也是event study的难点,因为要将不同的时间跨度组合在⼀起,同时要这16家公司重新index,其中 event date 的index为0,前后各20天的window,所以整个window的长度为41。下图为所有公司的假设检验结果:
可以看到只有⼀个公司的超额收益并不显著,我们在把结果可视化:
plt.figure(figsize=(24,16))
for i in range(1,17):
plt.subplot(4,4,i)
abnormalreturns_df[lumns[i-1]].plot()
plt.xlabel('Event Window')
plt.ylabel('Return')
plt.axhline(y=(np.sqrt((abnormalreturns_df.iloc[:,i-1].std()**2/41))*1.96),color='red',linestyle='--')
plt.axhline(y=(np.sqrt((abnormalreturns_df.iloc[:,i-1].std()**2/41))*-1.96),color='red',linestyle='--')
plt.title(lumns[i-1])
结果就很明显了吧(红线为95%的置信区间)?再看⼀下AAR,同样with plot:
mean_AAR = an(axis = 1)
var_AAR = (abnormalreturns_df.std())**2
var_matrix = pd.DataFrame(var_AAR)
var_matrix = var_matrix.T
var_AAR = sum(var_matrix.iloc[0])/16**2
Std_AAR = np.sqrt(var_AAR)
mean_AAR.plot()
plt.axhline(y=Std_AAR*1.96,color='red',linestyle='--')
plt.axhline(y=Std_AAR*-1.96,color='red',linestyle='--')
总体来说,事件对与公司的影响还是很显著的!我们再来看⼀下CAR和CAAR,照旧我们将曲线与对应的置信区间加上:
def CAR_se(Abnormal_return=abnormalreturns_df, stock_list=stocklist):
"""To get the standard error of Cumulative Abnormal Return for each stockInput: the Abnormal Return datafram or matrix, a list of company namesOutput: a dataframe of cumulative standard error for eac
h stock"""
residual_sigma_single = pd.DataFrame()类风湿可以彻底根治吗
residual_sigma_cum_single = pd.DataFrame()
resi_single = []
d = {}
for x in stocklist:
resistd = abnormalreturns_df[x].std()/16
d.update({x:resistd})
residual_sigma_single = pd.DataFrame(d,index=Abnormal_return.index)
residual_sigma_cum_single = np.sqrt(residual_sigma_single.cumsum())
se_cum_single = np.sqrt(((residual_sigma_cum_single**2)/16))
return se_cum_single
def CAAR_se(Abnormal_return=abnormalreturns_df, stock_list=stocklist):
"""To get the standard error of Cumulative Average Abnormal ReturnInput: the Abnormal Return datafram or matrix, a list
of company namesOutput: a list of cumulative standard error"""
residual_sigma = pd.DataFrame()
resi = []
d = {}
for x in stocklist:
resistd = abnormalreturns_df[x].std()/16
d.update({x:resistd})
residual_sigma = pd.DataFrame(d,index=Abnormal_return.index)
residual_sigma_cum = np.sqrt(residual_sigma.cumsum())
se_cum = np.sqrt(((residual_sigma_cum**2)/16).mean(axis=1))
return se_cum
CAR_df = abnormalreturns_df.cumsum()
plt.figure(figsize=(24,16))
for i in range(1,17):
plt.subplot(4,4,i)
CAR_df[lumns[i-1]].plot()
plt.plot(se_cum_single.iloc[:,i-1]*1.96, color='red',linestyle='--')
plt.plot(se_cum_single.iloc[:,i-1]*-1.96, color='red',linestyle='--')
plt.xlabel('Event Window')
plt.ylabel('CAR')
plt.title(lumns[i-1])
Var_AAR = ((an(axis=1))**2)/16
Std_AAR = np.sqrt(Var_AAR)
# CAAR
CAAR = mean_AAR.cumsum()
# Plot CAAR
CAAR.plot(figsize=(12,8))
plt.xlabel("Event Window")
plt.plot(se*1.96, color='red',linestyle='--')
plt.plot(se*-1.96, color='red',linestyle='--')
plt.ylabel("Cumulative Return")
plt.title("Cumulative Average Abnormal Return")
注意,CAR和CAAR的置信区间是⼀个累计的过程哦。可见,总的来说,事件对公司的影响还是很显著的!欢迎⼤家讨论,⾮科班出⾝,代码可能⽐较屎,欢迎⼤家debug。
如果有想要数据来复现结果的同学,可以私信我
P.s 现在数据量还不够,希望⼀个⽉后可以做⼀个这次肺炎的event study。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论