siat 3.7.1__py3-none-any.whl → 3.7.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
siat/event_study.py CHANGED
@@ -43,6 +43,7 @@ if __name__=='__main__':
43
43
  start='2024-3-1'; end='2024-4-30'
44
44
  event_window=[1,1] #事件发生时股市已经收盘,故检测下一个交易日的股市反应
45
45
  market_index='000001.SS' #贵州茅台在上交所上市,故使用上证综合指数
46
+ RF=0
46
47
 
47
48
  #测试组2
48
49
  ticker=['600519.SS','399997.SZ']
@@ -51,6 +52,17 @@ if __name__=='__main__':
51
52
  start='2024-3-1'; end='2024-3-30'
52
53
  event_window=[1,2]
53
54
  market_index='000300.SS'
55
+ RF="market model"
56
+
57
+ #测试组3
58
+ ticker=['600519.SS','399997.SZ']
59
+
60
+ event_date='2024-4-2' #贵州茅台2023年报披露日
61
+ start='auto'; end='auto'
62
+ event_window=[0,1]
63
+ method='CAPM'
64
+ market_index='000001.SS'
65
+ RF="1YCNY.B"
54
66
 
55
67
  #共同部分
56
68
  post_event_days=7
@@ -58,11 +70,11 @@ if __name__=='__main__':
58
70
  early_response_days=-2
59
71
  estimation_window_days=-365
60
72
 
61
- RF=0
62
73
  ret_type="Daily Adj Ret%"
63
74
  ticker_type='stock' #贵州茅台为股票
64
75
  facecolor="whitesmoke"
65
- show_AR='auto'
76
+ show_AR=True
77
+ show_RF=True
66
78
  loc='best'
67
79
 
68
80
  es=event_study("600519.SS",event_date="2024-4-2", \
@@ -89,17 +101,18 @@ if __name__=='__main__':
89
101
 
90
102
 
91
103
  def event_study(ticker,event_date, \
92
- start='MRM',end='today', \
93
- event_window=[0,0], \
94
- post_event_days=7, \
104
+ start='auto',end='auto', \
105
+ event_window=[1,3], \
106
+ post_event_days=0, \
95
107
  method='CAPM', \
96
108
  early_response_days=-2, \
97
109
  estimation_window_days=-365, \
98
110
  market_index='000300.SS', \
99
- RF=0, \
111
+ RF="market index", \
100
112
  ret_type="Daily Adj Ret%", \
101
113
  ticker_type='auto', \
102
- facecolor="whitesmoke",show_AR='auto',loc='best'):
114
+ facecolor="whitesmoke",show_AR='auto',show_RF=False, \
115
+ loc='best'):
103
116
  """
104
117
 
105
118
  功能:展示事件研究法的累计异常收益率CAR。
@@ -113,7 +126,7 @@ def event_study(ticker,event_date, \
113
126
  注意:事件窗口不一定包括事件日(适用于事件日在非交易日的情形,例如周末或假日)
114
127
  如果事件日为非交易日,事件窗口需要后移至事件日后的第一个交易日。
115
128
  如果怀疑市场提前对事件发生反应,可以考虑前移事件窗口的开始日期。
116
- post_event_days:用于分析事件窗口后的漂移效应,取事件窗口后多少天,默认取7天。
129
+ post_event_days:用于分析事件窗口后的漂移效应,取事件窗口后多少天。默认不分析,取0天。
117
130
  method:估计事件窗口以及事件后窗口收益率预期值的方法,默认为CAPM(主要用于ticker为股票等)
118
131
  如果ticker为股票等,也可以直接使用指数的收益率为其预期收益率,此时method为Market或Index。
119
132
  如果ticker为指数,无法再借助指数,method只能使用Random Walk,即使用前一个收益率为预期收益率。
@@ -125,12 +138,17 @@ def event_study(ticker,event_date, \
125
138
  默认在事件窗口开始日期+提前反应天数前的365个自然日(约250个交易日)。
126
139
  market_index:当method为CAPM时,用于计算市场收益率。默认中国市场采用000300.SS。
127
140
  注意:需要根据不同市场采取不同的市场指数,例如香港市场为恒生指数,美国市场为标普500指数等。
141
+ RF:年化无风险收益率,默认使用市场模型"market index",无需指定;可直接指定具体数值;
142
+ 也可指定特定指标,例如一年期中国国债收益率"1YCNY.B"或一年期美债收益率"1YUSY.B"等。
143
+ show_RF:在使用市场模型或指定指标时是否显示计算出的RF均值,默认为False。
128
144
  ticker_type:显式指明ticker的证券类型,当siat误判其类型(中国内地股票/债券/基金)时使用,默认'auto'。
129
145
  facecolor:显式指定绘图背景颜色,默认"whitesmoke"。
130
- show_AR:是否绘图时绘制异常收益率AR,默认'auto'(单个ticker时绘制,多个时不绘制),也可指定True/False强行绘制/不绘制。
146
+ show_AR:是否绘图时绘制异常收益率AR,默认'auto'(单个ticker时绘制,多个时不绘制)。
147
+ 也可指定True/False强行绘制/不绘制。
131
148
  """
132
149
 
133
150
  DEBUG=False
151
+ DEBUG2=False
134
152
 
135
153
  #=====事件研究各个日期的计算与调整===========================================
136
154
  if isinstance(event_date,str):
@@ -142,34 +160,45 @@ def event_study(ticker,event_date, \
142
160
  return None
143
161
  event_date.sort() #升序排序
144
162
 
145
- #事件窗口日期计算与调整
163
+ #事件窗口日期:遇到周末需要调整,提前或顺延至最近的工作日
146
164
  event_window_new=event_window.copy() #列表的普通赋值仅为指针,新列表的改动也会影响原列表
147
165
  adjust_start=0
148
166
  event_window_start=date_adjust(event_date[0],adjust=event_window[0])
149
167
  if week_day(event_window_start) == 5: #周六
150
- adjust_start=2
168
+ if event_window[0] >= 0:
169
+ adjust_start=2
170
+ else:
171
+ adjust_start=-1
151
172
  elif week_day(event_window_start) == 6: #周日
152
- adjust_start=1
173
+ if event_window[0] >= 0:
174
+ adjust_start=1
175
+ else:
176
+ adjust_start=-2
153
177
  event_window_start=date_adjust(event_window_start,adjust=adjust_start)
154
178
  event_window_new[0]=event_window[0]+adjust_start
155
179
 
156
180
  adjust_end=0
157
181
  event_window_end=date_adjust(event_window_start,adjust=event_window[1]-event_window[0])
158
182
  if week_day(event_window_end) == 5: #周六
159
- adjust_end=2
183
+ if event_window[1] >= 0:
184
+ adjust_end=2
185
+ else:
186
+ adjust_end=-1
160
187
  elif week_day(event_window_end) == 6: #周日
161
- adjust_end=1
188
+ if event_window[1] >= 0:
189
+ adjust_end=1
190
+ else:
191
+ adjust_end=-2
162
192
  event_window_end=date_adjust(event_window_end,adjust=adjust_end)
163
193
  event_window_new[1]=event_window[1]+adjust_start+adjust_end
164
-
165
194
 
166
195
  if DEBUG:
167
196
  print(" DEBUG: event window is between {0} to {1}".format(event_window_start,event_window_end))
168
197
 
169
198
  if event_window_new != event_window:
170
- print(" #Notice: event window adjusted to {} because of crossing weekend".format(event_window_new))
199
+ print(" #Notice: event window adjusted from {0} to {1} because of weekend".format(event_window,event_window_new))
171
200
 
172
- #事件后窗口日期的计算与调整
201
+ #事件后窗口日期
173
202
  post_event_start=date_adjust(event_window_end,adjust=0)
174
203
  if week_day(post_event_start) == 5: #周六
175
204
  post_event_start=date_adjust(post_event_start,adjust=2)
@@ -189,7 +218,7 @@ def event_study(ticker,event_date, \
189
218
  print(" DEBUG: post event window is between {0} to {1}".format(post_event_start,post_event_end))
190
219
 
191
220
 
192
- #事件窗口前日期计算与调整
221
+ #事件窗口前日期
193
222
  event_eve_date=date_adjust(event_window_start,adjust=-1)
194
223
  if week_day(event_eve_date) == 5: #周六
195
224
  event_eve_date=date_adjust(event_eve_date,adjust=-1)
@@ -199,7 +228,7 @@ def event_study(ticker,event_date, \
199
228
  if DEBUG:
200
229
  print(" DEBUG: event eve is on {}".format(event_eve_date))
201
230
 
202
- #提前反应日期计算与调整
231
+ #提前反应日期
203
232
  early_response_date=date_adjust(event_date[0],adjust=early_response_days)
204
233
  if week_day(early_response_date) == 5: #周六
205
234
  early_response_date=date_adjust(early_response_date,adjust=-1)
@@ -211,7 +240,18 @@ def event_study(ticker,event_date, \
211
240
 
212
241
  #估计窗口日期的计算
213
242
  est_window_end=date_adjust(early_response_date,adjust=-1)
214
- est_window_start=date_adjust(est_window_end,adjust=estimation_window_days)
243
+ est_window_start=date_adjust(est_window_end,adjust=estimation_window_days)
244
+ if DEBUG:
245
+ print(" DEBUG: regression period starts from {0} to {1}".format(est_window_start,est_window_end))
246
+
247
+ #处理绘图时显示的日期范围
248
+ if start=='auto':
249
+ start=date_adjust(early_response_date,adjust=-7)
250
+ if end=='auto':
251
+ if len(ticker) == 1 or show_AR:
252
+ end=date_adjust(post_event_end,adjust=7)
253
+ else:
254
+ end=date_adjust(post_event_end,adjust=2)
215
255
 
216
256
  #=====判断ticker是否为指数,调整预期收益率计算方法============================
217
257
  if isinstance(ticker,str):
@@ -223,45 +263,84 @@ def event_study(ticker,event_date, \
223
263
  return None
224
264
 
225
265
  if market_index in ticker:
226
- print(" #Warning(event_study): market_index {0} in ticker {1}, removed from ticker".format(market_index,ticker))
266
+ print(" #Warning(event_study): market_index {0} duplicated in and removed from ticker {1}".format(market_index,ticker))
227
267
  ticker.remove(market_index)
228
268
 
229
- tname=ticker_name(ticker[0],ticker_type)
269
+ #tname=ticker_name(ticker[0],ticker_type)
230
270
  #检查ticker是否为指数或国债收益率
231
271
  """
232
272
  if ("指数" in tname or "index" in tname.lower()) or ("收益率" in tname or "yield" in tname.lower()):
233
273
  if not ("random" in method.lower() or "walk" in method.lower()):
234
274
  print(" #Notice: check the applicability of ticker {0}, method {1} with market index {2}".format(ticker[0],method,market_index))
235
275
  """
276
+
236
277
  #=====获取证券价格和/或相关指数数据==========================================
237
- if 'capm' in method.lower() or 'market' in method.lower() or 'index' in method.lower():
278
+ #基于CAPM获取数据
279
+ if 'capm' in method.lower():
280
+ method_type="capm"
281
+ df_ret=compare_msecurity(tickers=ticker+[market_index],measure=ret_type, \
282
+ start=est_window_start,end=end, \
283
+ ticker_type=ticker_type, \
284
+ graph=False)
285
+
286
+ if isinstance(RF,int) or isinstance(RF,float):
287
+ #RF为具体数值
288
+ RF_type="value"
289
+
290
+ elif "market" in (str(RF)).lower() or "index" in (str(RF)).lower():
291
+ #RF通过市场模型计算,无需指定
292
+ RF_type="model"
293
+ else:
294
+ #指定RF代码,例如1YCNY.B,注意1:得到的是年化收益率%,注意2:中国的只有近一年的数据
295
+ RF_type="code"
296
+
297
+ if RF_type=="code":
298
+ df_rf=compare_msecurity(tickers=RF,measure='Close', \
299
+ start=est_window_start,end=end, \
300
+ graph=False)
301
+ RF=df_rf[list(df_rf)[0]].mean() / 100.0
302
+
303
+ #基于市场指数获取数据
304
+ elif 'market' in method.lower() or 'index' in method.lower():
305
+ method_type="market"
238
306
  df_ret=compare_msecurity(tickers=ticker+[market_index],measure=ret_type, \
239
307
  start=est_window_start,end=end, \
240
308
  ticker_type=ticker_type, \
241
309
  graph=False)
242
- """
243
- for t in ticker+[market_index]:
244
- df_ret.rename(columns={ticker_name(t,ticker_type):t},inplace=True)
245
- """
246
- if 'random' in method.lower() or 'walk' in method.lower():
310
+
311
+ elif 'random' in method.lower() or 'walk' in method.lower():
312
+ method_type="random"
247
313
  df_ret=compare_msecurity(tickers=ticker,measure=ret_type, \
248
314
  start=est_window_start,end=end, \
249
315
  ticker_type=ticker_type, \
250
316
  graph=False)
251
317
  for t in ticker_name(ticker,ticker_type):
252
- #df_ret.rename(columns={ticker_name(t,ticker_type):t},inplace=True)
253
- df_ret[t+"_predicted"]=df_ret[t].shift(1)
318
+ try:
319
+ df_ret[t+"_predicted"]=df_ret[t].shift(1)
320
+ except:
321
+ #print(" #Warning(event_study): info not found for ticker {}".format(t))
322
+ continue
323
+
324
+ else:
325
+ print(" #Warning(event_study): unexpected type of AR method {}".format(method))
326
+ return None
254
327
 
255
328
  #=====计算异常收益率AR=====
256
329
  df_cols=list(df_ret)
257
- if 'market' in method.lower() or 'index' in method.lower():
330
+ if method_type=='market':
258
331
  for t in ticker_name(ticker,ticker_type):
259
- df_ret[t+'_AR']=df_ret[t]-df_ret[ticker_name(market_index)]
260
- elif 'random' in method.lower() or 'walk' in method.lower():
332
+ try:
333
+ df_ret[t+'_AR']=df_ret[t] - df_ret[ticker_name(market_index)]
334
+ except: continue
335
+
336
+ elif method_type=='random':
261
337
  for t in ticker_name(ticker,ticker_type):
262
- df_ret[t+'_AR']=df_ret[t]-df_ret[t+"_predicted"]
338
+ try:
339
+ df_ret[t+'_AR']=df_ret[t] - df_ret[t+"_predicted"]
340
+ except: continue
341
+
263
342
  else: #按CAPM计算
264
- #回归CAPM
343
+ #CAPM回归期间数据
265
344
  est_window_startpd=pd.to_datetime(est_window_start)
266
345
  est_window_endpd =pd.to_datetime(est_window_end)
267
346
  df_reg=df_ret[(df_ret.index >=est_window_startpd) & (df_ret.index <=est_window_endpd)].copy()
@@ -270,49 +349,111 @@ def event_study(ticker,event_date, \
270
349
  df_reg=df_reg.replace([np.nan, None], np.nan).dropna()
271
350
 
272
351
  import statsmodels.api as sm
273
- X=df_reg[ticker_name(market_index)] - RF #无截距项回归,需要RF
274
- beta_dict={}
352
+ if RF_type in ["value","code"]:
353
+ if not ("%" in ret_type): #注意:RF是年化收益率(需要转化为日收益率),这里不是百分比
354
+ X=df_reg[ticker_name(market_index)] - RF/365.0 #无截距项回归,指定RF具体数值
355
+ else:
356
+ X=df_reg[ticker_name(market_index)] - RF/365.0 * 100.0 #这里需要转化为日收益率百分比%
357
+
358
+ else: #RF_type=="model"
359
+ X=df_reg[ticker_name(market_index)]
360
+ X=sm.add_constant(X) #有截距项回归,基于市场模型
361
+
362
+ if DEBUG:
363
+ print(" DEBUG: method_type={0}, RF_type={1}, RF={2}".format(method_type,RF_type,RF))
364
+
365
+ #CAPM回归
366
+ beta_dict={}; intercept_dict={}; pvalue_dict={}; rf_dict={}
275
367
  for t in ticker_name(ticker,ticker_type):
276
- y=df_reg[t] - RF
277
- model = sm.OLS(y,X) #定义回归模型R-Rf=beta(Rm-Rf),X可为多元矩阵
368
+ try:
369
+ if RF_type in ["value","code"]:
370
+ if not ("%" in ret_type): #注意:RF是年化收益率(需要转化为日收益率),不是百分比
371
+ y=df_reg[t] - RF/365.0
372
+ else:
373
+ y=df_reg[t] - RF/365.0 * 100.0
374
+
375
+ else: #RF_type=="model"
376
+ y=df_reg[t]
377
+ except: continue
378
+
379
+ model = sm.OLS(y,X) #定义回归模型y=X
278
380
  results = model.fit() #进行OLS回归
279
- beta=results.params[0] #提取回归系数
280
381
 
281
- beta_dict[t] = beta
282
-
283
- #有截距回归,无需RF
284
- #from scipy import stats
285
- #(beta,alpha,r_value,p_value,std_err)=stats.linregress(df_reg[market_index],df_reg[ticker])
286
-
287
- if DEBUG:
288
- print(" DEBUG: RF={0}, beta={1}".format(RF,beta_dict))
382
+ if DEBUG2:
383
+ print(" DEBUG: RF_type={0}, results.params={1},results.pvalues={2}".format(RF_type,results.params,results.pvalues))
384
+
385
+ #提取回归系数,详细信息见results.summary()
386
+ if RF_type=="model":
387
+ intercept=results.params[0]
388
+ beta=results.params[1]; pvalue=results.pvalues[1]
389
+ try:
390
+ #此处回归得到的rf应该为日收益率,转为年化收益率。
391
+ #注意:不同证券回归出的结果可能差异较大,原因可能是混入了回归残差!
392
+ if not ("%" in ret_type):
393
+ rf=intercept / (1-beta) * 365.0
394
+ else:
395
+ rf=intercept / (1-beta) / 100.0 * 365.0
396
+ except: rf=0
397
+
398
+ else: #RF_type in ["value","code"]
399
+ intercept=0
400
+ beta=results.params[0]; pvalue=results.pvalues[0]
401
+ rf=RF
402
+
403
+ beta_dict[t] = beta; intercept_dict[t] = intercept; pvalue_dict[t] = pvalue; rf_dict[t]=rf
404
+ if DEBUG2:
405
+ print(" DEBUG: t={0}, intercept={1}, beta={2}, pvalue={3}, annualized rf={4}".format(t,round(intercept,4),round(beta,4),round(pvalue,4),round(rf,4)))
289
406
 
407
+ #计算收益率预期和AR
290
408
  for t in ticker_name(ticker,ticker_type):
291
- df_ret[t+"_predicted"]=(df_ret[ticker_name(market_index)] - RF)*beta_dict[t] + RF
292
- df_ret[t+"_AR"]=df_ret[t]-df_ret[t+"_predicted"]
409
+ try:
410
+ if RF_type in ["value","code"]:
411
+ #CAPM模型:E(R) = RF + (Rm-RF)*beta
412
+ RF_text=str(round(RF*100.0,4))[:6]+'%'
413
+ if not ("%" in ret_type): #注意:RF是年化收益率,此处不是百分比
414
+ df_ret[t+"_predicted"]=(df_ret[ticker_name(market_index)] - RF/365.0)*beta_dict[t] + RF/365.0
415
+ else:
416
+ df_ret[t+"_predicted"]=(df_ret[ticker_name(market_index)] - RF*100.0/365.0)*beta_dict[t] + RF*100.0/365.0
417
+
418
+ else: #RF_type=="model"
419
+ #市场模型:E(R) = intercept + Rm*beta
420
+ RF_text="基于市场模型回归"
421
+ df_ret[t+"_predicted"]=df_ret[ticker_name(market_index)]*beta_dict[t] + intercept_dict[t]
422
+
423
+ df_ret[t+"_AR"]=df_ret[t] - df_ret[t+"_predicted"]
424
+ except: continue
293
425
 
294
- #=====计算CAR=====
426
+ if DEBUG2:
427
+ print(" DEBUG: RF_type={0}, RF_text={1}, rf_dict={2}".format(RF_type,RF_text, rf_dict))
428
+
429
+ #=====计算CAR==============================================================
295
430
  for t in ticker_name(ticker,ticker_type):
296
- df_ret[t+"_CAR"]=0
431
+ try:
432
+ df_ret[t+"_CAR"]=0
433
+ except: continue
434
+
297
435
  event_window_startpd=pd.to_datetime(event_window_start)
298
436
  event_window_endpd=pd.to_datetime(event_window_end)
299
437
  post_event_endpd=pd.to_datetime(post_event_end)
300
-
301
438
  startpd=pd.to_datetime(start); endpd=pd.to_datetime(end)
302
- #df_ret_event=df_ret[(df_ret.index >=event_window_startpd) & (df_ret.index <=post_event_endpd)]
439
+
440
+ #计算CAR
303
441
  df_ret_event=df_ret[(df_ret.index >=event_window_startpd) & (df_ret.index <=endpd)]
304
442
  for t in ticker_name(ticker,ticker_type):
305
- df_ret_event[t+'_CAR'] = df_ret_event[t+'_AR'].cumsum()
443
+ try:
444
+ df_ret_event[t+'_CAR'] = df_ret_event[t+'_AR'].cumsum()
445
+ except: continue
306
446
 
447
+ #合成事件前期间
307
448
  df_ret_before_event=df_ret[(df_ret.index >=startpd) & (df_ret.index < event_window_startpd)]
308
449
  for t in ticker_name(ticker,ticker_type):
309
- df_ret_before_event[t+'_CAR']=np.nan
450
+ try:
451
+ df_ret_before_event[t+'_CAR']=np.nan
452
+ except: continue
310
453
 
311
- #df_ret_after_event=df_ret[(df_ret.index >post_event_endpd)]
312
- #df_ret_after_event['CAR']=np.nan
313
-
314
- #df_show=pd.concat([df_ret_before_event,df_ret_event,df_ret_after_event])
315
454
  df_show=pd.concat([df_ret_before_event,df_ret_event])
455
+
456
+ #是否显示AR:默认单证券显示,多证券不显示
316
457
  df_show_cols=[]
317
458
  for c in list(df_show):
318
459
  if show_AR=='auto':
@@ -339,28 +480,38 @@ def event_study(ticker,event_date, \
339
480
 
340
481
  y_label="收益率%"
341
482
 
342
-
483
+ #横轴注释
343
484
  footnote1="首事件日{0},事件窗口{1},事件后窗口天数{2},市场提前反应天数{3}".format(event_date[0],event_window_new,post_event_days,early_response_days)
344
485
  footnote2="收益率类型:"+ectranslate(ret_type)
345
486
 
346
- if "market" in method.lower() or "index" in method.lower():
347
- method_name="市场指数"
348
- elif "random" in method.lower() or "walk" in method.lower():
349
- method_name="随机漫步"
487
+ if method_type == "market":
488
+ method_name="市场指数基准"
489
+ elif method_type == "random":
490
+ method_name="随机漫步模型"
350
491
  else:
351
- method_name="CAPM"
492
+ method_name="CAPM模型"
352
493
 
353
494
  footnote3=",收益率预期方法:"+method_name
354
- if not ('random' in method.lower() or 'walk' in method.lower()):
495
+ if not method_type == "random":
355
496
  footnote4=',市场指数:'+ticker_name(market_index)
356
497
  else:
357
498
  footnote4=''
358
499
 
359
- #显著性检验:异于零的t检验
500
+ #显著性检验:异于零的t检验,事件窗口
360
501
  df_event_window=df0[(df0.index >=event_window_start) & (df0.index <=event_window_end)]
361
- footnote5="事件窗口CARp值:"
502
+ footnote5="事件窗口CAR(终值,p值):"
362
503
  for c in list(df_event_window):
363
504
  if 'CAR' in c.upper():
505
+ c_name=c[:-4]
506
+
507
+ event_window_endpd=pd.to_datetime(event_window_end)
508
+ #car_value=df_event_window[df_event_window.index == event_window_endpd][c].values[0]
509
+ car_value=df_event_window[c][-1]
510
+ if car_value > 0:
511
+ car_value_str=str(round(car_value,4))[:6]
512
+ else:
513
+ car_value_str=str(round(car_value,4))[:7]
514
+
364
515
  if len(df_event_window[c])==1:
365
516
  if abs(df_event_window[c].values[0]) > 0.01:
366
517
  p_value=0.0
@@ -368,22 +519,51 @@ def event_study(ticker,event_date, \
368
519
  p_value=1.0
369
520
  else:
370
521
  p_value=ttest(df_event_window[c],0)
371
- footnote5=footnote5+c[:-4]+str(p_value)[:6]+","
372
- footnote5=footnote5.strip(",")
522
+ if p_value > 0:
523
+ p_value_str=str(round(p_value,4))[:6]
524
+ else:
525
+ p_value_str=str(round(p_value,4))[:7]
526
+ #footnote5=footnote5+c_name+p_value_str+","
527
+ footnote5=footnote5+"{0}({1}, {2}), ".format(c_name,car_value_str,p_value_str)
528
+ footnote5=footnote5.strip(", ")
373
529
 
530
+ #显著性检验:异于零的t检验,事件后窗口
374
531
  df_post_event_window=df0[(df0.index >event_window_end) & (df0.index <=post_event_end)]
375
- footnote6="事件后窗口CAR的p值:"
376
- for c in list(df_post_event_window):
377
- if 'CAR' in c.upper():
378
- if len(df_post_event_window[c])==1:
379
- if abs(df_post_event_window[c].values[0]) > 0.01:
380
- p_value=0.0
532
+ if len(df_post_event_window) == 0:
533
+ footnote6=''
534
+
535
+ elif len(df_post_event_window) == 0:
536
+ footnote6=''
537
+ else:
538
+ footnote6="事件后窗口CAR(终值,p值):"
539
+ for c in list(df_post_event_window):
540
+ if 'CAR' in c.upper():
541
+ c_name=c[:-4]
542
+ post_event_endpd=pd.to_datetime(post_event_end)
543
+ if DEBUG2:
544
+ print(" DEBUG: c={0},post_event_end={1},df_post_event_window={2}".format(c,post_event_end,df_post_event_window))
545
+ #car_value=df_post_event_window[df_post_event_window.index == post_event_endpd][c].values[0]
546
+ car_value=df_post_event_window[c][-1]
547
+ if car_value > 0:
548
+ car_value_str=str(round(car_value,4))[:6]
381
549
  else:
382
- p_value=1.0
383
- else:
384
- p_value=ttest(df_post_event_window[c],0)
385
- footnote6=footnote6+c[:-4]+str(p_value)[:6]+","
386
- footnote6=footnote6.strip(",")
550
+ car_value_str=str(round(car_value,4))[:7]
551
+
552
+ if len(df_post_event_window[c])==1:
553
+ if abs(df_post_event_window[c].values[0]) > 0.01:
554
+ p_value=0.0
555
+ else:
556
+ p_value=1.0
557
+ else:
558
+ p_value=ttest(df_post_event_window[c],0)
559
+ if p_value > 0:
560
+ p_value_str=str(round(p_value,4))[:6]
561
+ else:
562
+ p_value_str=str(round(p_value,4))[:7]
563
+
564
+ #footnote6=footnote6+c[:-4]+str(p_value)[:6]+","
565
+ footnote6=footnote6+"{0}({1}, {2}), ".format(c_name,car_value_str,p_value_str)
566
+ footnote6=footnote6.strip(", ")
387
567
 
388
568
  footnote7="数据来源:Sina/EM/Yahoo/Stooq/SWHY,"+stoday
389
569
 
@@ -467,20 +647,25 @@ def event_study(ticker,event_date, \
467
647
  event_text="事件日"+str(pos+1)
468
648
  df1["事件标记"]=df1.apply(lambda x: event_text if x["日期"]==d else x["事件标记"],axis=1)
469
649
 
470
- event_text=",事件窗口开始日"
650
+ #event_text=",事件窗口开始日"
651
+ event_text="\n事件窗开始"
471
652
  df1["事件标记"]=df1.apply(lambda x: x["事件标记"]+event_text if x["日期"]==event_window_start else x["事件标记"],axis=1)
472
- event_text=",事件窗口结束日"
653
+ #event_text=",事件窗口结束日"
654
+ event_text="\n事件窗结束"
473
655
  df1["事件标记"]=df1.apply(lambda x: x["事件标记"]+event_text if x["日期"]==event_window_end else x["事件标记"],axis=1)
474
- event_text="事件后窗口结束日"
475
- df1["事件标记"]=df1.apply(lambda x: x["事件标记"]+event_text if x["日期"]==post_event_end else x["事件标记"],axis=1)
656
+
657
+ #event_text=",事件后窗口结束日"
658
+ if post_event_end > event_window_end:
659
+ event_text="\n事件后窗结束"
660
+ df1["事件标记"]=df1.apply(lambda x: x["事件标记"]+event_text if x["日期"]==post_event_end else x["事件标记"],axis=1)
476
661
 
477
- event_text=",事件窗口"
662
+ event_text="\n事件窗"
478
663
  df1["事件标记"]=df1.apply(lambda x: x["事件标记"]+event_text if (x["日期"] > event_window_start) and (x["日期"] < event_window_end) else x["事件标记"],axis=1)
479
664
 
480
- event_text=",事件后窗口"
665
+ event_text="\n事件后窗"
481
666
  df1["事件标记"]=df1.apply(lambda x: x["事件标记"]+event_text if (x["日期"] > event_window_end) and (x["日期"] < post_event_end) else x["事件标记"],axis=1)
482
667
 
483
- df1["事件标记"]=df1["事件标记"].apply(lambda x: x.strip(''))
668
+ df1["事件标记"]=df1["事件标记"].apply(lambda x: x.strip('\n'))
484
669
 
485
670
  #显示表格
486
671
  df0_list=list(df0)
@@ -489,18 +674,26 @@ def event_study(ticker,event_date, \
489
674
  #title_txt=title_txt+",窗口收益率"
490
675
 
491
676
  if "CAPM" in method.upper():
492
- footnotex="CAPM回归期间:{0}至{1}".format(est_window_start,est_window_end)
677
+ footnotex="CAPM回归期间:{0}至{1},无风险收益率{2}".format(est_window_start,est_window_end,RF_text)
493
678
  footnotey="CAPM贝塔系数:"
494
679
  for k in beta_dict:
495
680
  footnotey=footnotey+k+str(round(beta_dict[k],4))[:6]+","
496
681
  footnotey=footnotey.strip(",")
497
-
498
- footnote=footnote2+footnote3+footnote4+'\n'+footnotex+'\n'+footnotey+'\n'+footnote5+'\n'+footnote6
682
+
683
+ if show_RF:
684
+ footnotez="无风险收益率均值:"
685
+ for r in rf_dict:
686
+ footnotez=footnotez+r+str(round(rf_dict[r]*100.0,4))[:6]+"%, "
687
+
688
+ footnotez=footnotez.strip(", ")
689
+ footnote=footnote2+footnote3+footnote4+'\n'+footnotex+'\n'+footnotey+'\n'+footnotez+'\n'+footnote5+'\n'+footnote6
690
+ else:
691
+ footnote=footnote2+footnote3+footnote4+'\n'+footnotex+'\n'+footnotey+'\n'+footnote5+'\n'+footnote6
499
692
  else:
500
693
  footnote=footnote2+footnote3+footnote4+'\n'+footnote5+'\n'+footnote6
501
694
 
502
-
503
- df_display_CSS(df1,titletxt=title_txt,footnote=footnote,facecolor='papayawhip',decimals=4, \
695
+ #显示结果表格
696
+ df_display_CSS(df1,titletxt=title_txt,footnote=footnote,facecolor=facecolor,decimals=4, \
504
697
  first_col_align='left',second_col_align='left', \
505
698
  last_col_align='center',other_col_align='center')
506
699
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: siat
3
- Version: 3.7.1
3
+ Version: 3.7.3
4
4
  Summary: Securities Investment Analysis Tools (siat)
5
5
  Home-page: https://pypi.org/project/siat/
6
6
  Author: Prof. WANG Dehong, International Business School, Beijing Foreign Studies University
@@ -32,7 +32,7 @@ siat/economy.py,sha256=ijMAVA5ydghbQDgNDDdz8fz9NPd2eq90RzpJSRGWz5c,78638
32
32
  siat/economy_test.py,sha256=6vjNlPz7W125pJb7simCddobSEp3jmLIMvVkLRZ7zW8,13339
33
33
  siat/esg.py,sha256=GMhaonIKtvOK83rhpQUH5aJt2OL3HQBSVfD__Yw-0oo,19040
34
34
  siat/esg_test.py,sha256=Z9m6GUt8O7oHZSEG9aDYpGdvvrv2AiRJdHTiU6jqmZ0,2944
35
- siat/event_study.py,sha256=GCZSMGOAxthVEcRVv9eerIX4RYT_9cnnR6PvIx2mMXE,23833
35
+ siat/event_study.py,sha256=Q_AdnJzxxL6udCjn5LP6rdhOngsDRWPu5udFkK1CJZw,32223
36
36
  siat/exchange_bond_china.pickle,sha256=zDqdPrFacQ0nqjP_SuF6Yy87EgijIRsFvFroW7FAYYY,1265092
37
37
  siat/fama_french.py,sha256=aUTC-67t_CEPbLk4u79woW_zfZ7OCP6Fo4z5EdWCSkQ,48051
38
38
  siat/fama_french_test.py,sha256=M4O23lBKsJxhWHRluwCb3l7HSEn3OFTjzGMpehcevRg,4678
@@ -141,8 +141,8 @@ siat/valuation_china.py,sha256=CVp1IwIsF3Om0J29RGkyxZLt4n9Ug-ua_RKhLwL9fUQ,69624
141
141
  siat/valuation_market_china_test.py,sha256=gbJ0ioauuo4koTPH6WKUkqcXiQPafnbhU5eKJ6lpdLA,1571
142
142
  siat/var_model_validation.py,sha256=R0caWnuZarrRg9939hxh3vJIIpIyPfvelYmzFNZtPbo,14910
143
143
  siat/yf_name.py,sha256=r0Q67cSMMlfebEkI9h9pdGlJCooEq7hw_3M5IUs4cSI,20081
144
- siat-3.7.1.dist-info/LICENSE,sha256=NTEMMROY9_4U1szoKC3N2BLHcDd_o5uTgqdVH8tbApw,1071
145
- siat-3.7.1.dist-info/METADATA,sha256=QEq7a5uvfG4GBQLwJDP2ARnKHjAG-4T_A16Bp45lBZc,8009
146
- siat-3.7.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
147
- siat-3.7.1.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
148
- siat-3.7.1.dist-info/RECORD,,
144
+ siat-3.7.3.dist-info/LICENSE,sha256=NTEMMROY9_4U1szoKC3N2BLHcDd_o5uTgqdVH8tbApw,1071
145
+ siat-3.7.3.dist-info/METADATA,sha256=CTwHox9UQtS4g3RRebTz5dH5GgC62g4WOxJr8mr1tEo,8009
146
+ siat-3.7.3.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
147
+ siat-3.7.3.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
148
+ siat-3.7.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: bdist_wheel (0.41.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
File without changes