siat 3.6.7__py3-none-any.whl → 3.7.1__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/allin.py CHANGED
@@ -117,6 +117,9 @@ from siat.compare_cross import *
117
117
  # 股票技术分析
118
118
  from siat.stock_technical import *
119
119
 
120
+ # 事件研究法
121
+ from siat.event_study import *
122
+
120
123
  # 2FA: Google Authenticator
121
124
  from siat.google_authenticator import *
122
125
 
siat/common.py CHANGED
@@ -3943,6 +3943,24 @@ def df_swap_columns(df, col1, col2):
3943
3943
  cols[i2], cols[i1] = cols[i1], cols[i2]
3944
3944
 
3945
3945
  return df[cols]
3946
+
3947
+ #==============================================================================
3948
+ if __name__=='__main__':
3949
+ adate="2024-6-8"
3950
+ week_day(adate)
3951
+ week_day("2024-11-16")
3952
+ week_day("2024-11-17")
3953
+
3954
+ def week_day(adate):
3955
+ import pandas as pd
3956
+ try:
3957
+ datepd=pd.to_datetime(adate)
3958
+ except:
3959
+ return 0,False
3960
+
3961
+ weekday = datepd.weekday()
3962
+ return weekday # 周六和周日的索引值分别为5和6
3963
+
3946
3964
  #==============================================================================
3947
3965
  if __name__=='__main__':
3948
3966
  adate="2024-6-8"
@@ -3956,7 +3974,7 @@ def is_weekend(adate):
3956
3974
  return False
3957
3975
 
3958
3976
  weekday = datepd.weekday()
3959
- return weekday == 5 or weekday == 6 # 周五和周六的索引值分别为5和6
3977
+ return weekday == 5 or weekday == 6 # 周六和周日的索引值分别为5和6
3960
3978
 
3961
3979
 
3962
3980
  #==============================================================================
@@ -4410,3 +4428,55 @@ def annual_compound_growth(df,column="Close"):
4410
4428
  return
4411
4429
  #==============================================================================
4412
4430
  #==============================================================================
4431
+ if __name__ == '__main__':
4432
+ sample1=[1,2,3]
4433
+ sample2=0
4434
+
4435
+ ttest(sample1,sample2)
4436
+
4437
+
4438
+ def ttest(sample1,sample2):
4439
+ """
4440
+
4441
+ 功能:对比sample1与sample2之间是否存在显著差异,配对学生检验
4442
+ sample1:可为数值型的列表或序列,不可为空
4443
+ sample2:可为数值型的列表或序列或单个数值,若为列表或序列需与sample1个数相同
4444
+ """
4445
+ import pandas as pd
4446
+ import numpy as np
4447
+ from scipy import stats
4448
+
4449
+ #检查与预处理
4450
+ if not (isinstance(sample1,list) or isinstance(sample1,pd.Series)):
4451
+ print(" #Error(ttest): sample1 must be a list or series",sample1)
4452
+ return None
4453
+
4454
+ if not (isinstance(sample2,list) or isinstance(sample2,pd.Series)):
4455
+ if isinstance(sample2,int) or isinstance(sample2,float):
4456
+ sample2=[sample2]
4457
+ sample2=[item for s in sample2 for item in [s]*len(sample1)]
4458
+ else:
4459
+ print(" #Error(ttest): sample2 must be a list or series or a value",sample2)
4460
+ return None
4461
+
4462
+
4463
+ # 转换样本数据
4464
+ sample1 = pd.Series(sample1)
4465
+ sample1=sample1.astype(float)
4466
+ sample1 = np.array(sample1)
4467
+
4468
+ sample2 = pd.Series(sample2)
4469
+ sample2=sample2.astype(float)
4470
+ sample2 = np.array(sample2)
4471
+
4472
+ # 执行t检验
4473
+ t_stat, p_value = stats.ttest_ind(sample1, sample2)
4474
+
4475
+ return round(p_value,4)
4476
+
4477
+ #==============================================================================
4478
+ #==============================================================================
4479
+ #==============================================================================
4480
+ #==============================================================================
4481
+ #==============================================================================
4482
+ #==============================================================================
siat/event_study.py ADDED
@@ -0,0 +1,521 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 本模块功能:证券事件分析法
4
+ 所属工具包:证券投资分析工具SIAT
5
+ SIAT:Security Investment Analysis Tool
6
+ 创建日期:2024年11月14日
7
+ 最新修订日期:
8
+ 作者:王德宏 (WANG Dehong, Peter)
9
+ 作者单位:北京外国语大学国际商学院
10
+ 作者邮件:wdehong2000@163.com
11
+ 版权所有:王德宏
12
+ 用途限制:仅限研究与教学使用!
13
+ 特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
14
+ """
15
+
16
+ #==============================================================================
17
+ #关闭所有警告
18
+ import warnings; warnings.filterwarnings('ignore')
19
+ #==============================================================================
20
+ from siat.common import *
21
+ from siat.translate import *
22
+ #from siat.security_trend2 import *
23
+
24
+ from siat.stock import *
25
+ #from siat.security_prices import *
26
+ #from siat.security_price2 import *
27
+ #from siat.capm_beta2 import *
28
+ #from siat.risk_adjusted_return2 import *
29
+ #from siat.valuation import *
30
+
31
+ from siat.grafix import *
32
+
33
+ import pandas as pd; import numpy as np
34
+
35
+ import datetime as dt; stoday=str(dt.date.today())
36
+ #==============================================================================
37
+ #==============================================================================
38
+ if __name__=='__main__':
39
+ #测试组1
40
+ ticker='600519.SS'
41
+
42
+ event_date='2024-4-2' #贵州茅台2023年报于2024年4月2日晚披露
43
+ start='2024-3-1'; end='2024-4-30'
44
+ event_window=[1,1] #事件发生时股市已经收盘,故检测下一个交易日的股市反应
45
+ market_index='000001.SS' #贵州茅台在上交所上市,故使用上证综合指数
46
+
47
+ #测试组2
48
+ ticker=['600519.SS','399997.SZ']
49
+
50
+ event_date='2024-3-15' #315晚会
51
+ start='2024-3-1'; end='2024-3-30'
52
+ event_window=[1,2]
53
+ market_index='000300.SS'
54
+
55
+ #共同部分
56
+ post_event_days=7
57
+ method='CAPM'
58
+ early_response_days=-2
59
+ estimation_window_days=-365
60
+
61
+ RF=0
62
+ ret_type="Daily Adj Ret%"
63
+ ticker_type='stock' #贵州茅台为股票
64
+ facecolor="whitesmoke"
65
+ show_AR='auto'
66
+ loc='best'
67
+
68
+ es=event_study("600519.SS",event_date="2024-4-2", \
69
+ start='2024-3-1',end='2024-4-30', \
70
+ event_window=[0,0],post_event_days=7, \
71
+ method='CAPM', \
72
+ market_index='000001.SS',RF=0.0143)
73
+
74
+ es=event_study("600519.SS",event_date="2024-4-2", \
75
+ start='2024-3-15',end='2024-4-20', \
76
+ event_window=[0,1],post_event_days=7, \
77
+ method='CAPM', \
78
+ market_index='000001.SS',RF=0.0143)
79
+
80
+ es=event_study("600519.SS",event_date="2024-4-2", \
81
+ start='2024-3-1',end='2024-4-30', \
82
+ event_window=[0,0],post_event_days=7, \
83
+ method='market',market_index='000001.SS')
84
+
85
+ es=event_study("600519.SS",event_date="2024-4-2", \
86
+ start='2024-3-1',end='2024-4-30', \
87
+ event_window=[0,0],post_event_days=7, \
88
+ method='random walk')
89
+
90
+
91
+ def event_study(ticker,event_date, \
92
+ start='MRM',end='today', \
93
+ event_window=[0,0], \
94
+ post_event_days=7, \
95
+ method='CAPM', \
96
+ early_response_days=-2, \
97
+ estimation_window_days=-365, \
98
+ market_index='000300.SS', \
99
+ RF=0, \
100
+ ret_type="Daily Adj Ret%", \
101
+ ticker_type='auto', \
102
+ facecolor="whitesmoke",show_AR='auto',loc='best'):
103
+ """
104
+
105
+ 功能:展示事件研究法的累计异常收益率CAR。
106
+ 参数:
107
+ ticker:证券代码,可为股票、债券、基金、指数、国债收益率等。可为单个或多个。
108
+ event_date:事件发生日(注意时区的影响),以此日期为基期0,该日期可能在周末或假日。
109
+ 注意:允许标注多个事件日,但仅以第一个事件日计算相关日期。
110
+ start/end:展示事件影响的起止日期,至少需要将事件日、事件窗口和事件后窗口包括在内,主要用于绘图。
111
+ 注意:如果不绘制AR仅绘制CAR,事件窗口前CAR均为空,start日期在绘图中将不起作用。
112
+ event_window:事件窗口的起止日期,为相对事件日的相对日期,默认[0,0],即事件当日一天。
113
+ 注意:事件窗口不一定包括事件日(适用于事件日在非交易日的情形,例如周末或假日)
114
+ 如果事件日为非交易日,事件窗口需要后移至事件日后的第一个交易日。
115
+ 如果怀疑市场提前对事件发生反应,可以考虑前移事件窗口的开始日期。
116
+ post_event_days:用于分析事件窗口后的漂移效应,取事件窗口后多少天,默认取7天。
117
+ method:估计事件窗口以及事件后窗口收益率预期值的方法,默认为CAPM(主要用于ticker为股票等)
118
+ 如果ticker为股票等,也可以直接使用指数的收益率为其预期收益率,此时method为Market或Index。
119
+ 如果ticker为指数,无法再借助指数,method只能使用Random Walk,即使用前一个收益率为预期收益率。
120
+ 注意:不管多个ticker时里面的不同证券类型,仅按第一个ticker的类型判断,并使用同一种证券类型。
121
+ early_response_days:默认为-2,即提前2天市场就开始有反应。
122
+ 市场很可能对事件提前发生反应(因为泄密等原因),例如中国市场规定上市公司董事会开完后两天内必须披露。
123
+ 很可能刚开完董事会,市场就得到了消息。为规避这种情况对估计窗口的影响,可以调节此参数。
124
+ estimation_window_days:当method使用CAPM时,用于估计贝塔系数和截距项,以便计算预期收益率。
125
+ 默认在事件窗口开始日期+提前反应天数前的365个自然日(约250个交易日)。
126
+ market_index:当method为CAPM时,用于计算市场收益率。默认中国市场采用000300.SS。
127
+ 注意:需要根据不同市场采取不同的市场指数,例如香港市场为恒生指数,美国市场为标普500指数等。
128
+ ticker_type:显式指明ticker的证券类型,当siat误判其类型(中国内地股票/债券/基金)时使用,默认'auto'。
129
+ facecolor:显式指定绘图背景颜色,默认"whitesmoke"。
130
+ show_AR:是否绘图时绘制异常收益率AR,默认'auto'(单个ticker时绘制,多个时不绘制),也可指定True/False强行绘制/不绘制。
131
+ """
132
+
133
+ DEBUG=False
134
+
135
+ #=====事件研究各个日期的计算与调整===========================================
136
+ if isinstance(event_date,str):
137
+ event_date=[date_adjust(event_date,adjust=0)]
138
+ elif isinstance(event_date,list):
139
+ event_date=[date_adjust(ed,adjust=0) for ed in event_date]
140
+ else:
141
+ print(" #Warning(event_study): invalid date or list of dates {}".format(event_date))
142
+ return None
143
+ event_date.sort() #升序排序
144
+
145
+ #事件窗口日期计算与调整
146
+ event_window_new=event_window.copy() #列表的普通赋值仅为指针,新列表的改动也会影响原列表
147
+ adjust_start=0
148
+ event_window_start=date_adjust(event_date[0],adjust=event_window[0])
149
+ if week_day(event_window_start) == 5: #周六
150
+ adjust_start=2
151
+ elif week_day(event_window_start) == 6: #周日
152
+ adjust_start=1
153
+ event_window_start=date_adjust(event_window_start,adjust=adjust_start)
154
+ event_window_new[0]=event_window[0]+adjust_start
155
+
156
+ adjust_end=0
157
+ event_window_end=date_adjust(event_window_start,adjust=event_window[1]-event_window[0])
158
+ if week_day(event_window_end) == 5: #周六
159
+ adjust_end=2
160
+ elif week_day(event_window_end) == 6: #周日
161
+ adjust_end=1
162
+ event_window_end=date_adjust(event_window_end,adjust=adjust_end)
163
+ event_window_new[1]=event_window[1]+adjust_start+adjust_end
164
+
165
+
166
+ if DEBUG:
167
+ print(" DEBUG: event window is between {0} to {1}".format(event_window_start,event_window_end))
168
+
169
+ if event_window_new != event_window:
170
+ print(" #Notice: event window adjusted to {} because of crossing weekend".format(event_window_new))
171
+
172
+ #事件后窗口日期的计算与调整
173
+ post_event_start=date_adjust(event_window_end,adjust=0)
174
+ if week_day(post_event_start) == 5: #周六
175
+ post_event_start=date_adjust(post_event_start,adjust=2)
176
+ elif week_day(post_event_start) == 6: #周日
177
+ post_event_start=date_adjust(post_event_start,adjust=1)
178
+
179
+ post_event_end=date_adjust(post_event_start,adjust=post_event_days)
180
+ if week_day(post_event_end) == 5: #周六
181
+ post_event_end=date_adjust(post_event_end,adjust=2)
182
+ elif week_day(post_event_end) == 6: #周日
183
+ post_event_end=date_adjust(post_event_end,adjust=1)
184
+
185
+ if post_event_end > stoday:
186
+ post_event_end = stoday
187
+
188
+ if DEBUG:
189
+ print(" DEBUG: post event window is between {0} to {1}".format(post_event_start,post_event_end))
190
+
191
+
192
+ #事件窗口前日期计算与调整
193
+ event_eve_date=date_adjust(event_window_start,adjust=-1)
194
+ if week_day(event_eve_date) == 5: #周六
195
+ event_eve_date=date_adjust(event_eve_date,adjust=-1)
196
+ elif week_day(event_eve_date) == 6: #周日
197
+ event_eve_date=date_adjust(event_eve_date,adjust=-2)
198
+
199
+ if DEBUG:
200
+ print(" DEBUG: event eve is on {}".format(event_eve_date))
201
+
202
+ #提前反应日期计算与调整
203
+ early_response_date=date_adjust(event_date[0],adjust=early_response_days)
204
+ if week_day(early_response_date) == 5: #周六
205
+ early_response_date=date_adjust(early_response_date,adjust=-1)
206
+ elif week_day(early_response_date) == 6: #周日
207
+ early_response_date=date_adjust(early_response_date,adjust=-2)
208
+
209
+ if DEBUG:
210
+ print(" DEBUG: early response started on {}".format(early_response_date))
211
+
212
+ #估计窗口日期的计算
213
+ est_window_end=date_adjust(early_response_date,adjust=-1)
214
+ est_window_start=date_adjust(est_window_end,adjust=estimation_window_days)
215
+
216
+ #=====判断ticker是否为指数,调整预期收益率计算方法============================
217
+ if isinstance(ticker,str):
218
+ ticker=[ticker]
219
+ elif isinstance(ticker,list):
220
+ ticker=ticker
221
+ else:
222
+ print(" #Warning(event_study): unexpected type of ticker {}".format(ticker))
223
+ return None
224
+
225
+ if market_index in ticker:
226
+ print(" #Warning(event_study): market_index {0} in ticker {1}, removed from ticker".format(market_index,ticker))
227
+ ticker.remove(market_index)
228
+
229
+ tname=ticker_name(ticker[0],ticker_type)
230
+ #检查ticker是否为指数或国债收益率
231
+ """
232
+ if ("指数" in tname or "index" in tname.lower()) or ("收益率" in tname or "yield" in tname.lower()):
233
+ if not ("random" in method.lower() or "walk" in method.lower()):
234
+ print(" #Notice: check the applicability of ticker {0}, method {1} with market index {2}".format(ticker[0],method,market_index))
235
+ """
236
+ #=====获取证券价格和/或相关指数数据==========================================
237
+ if 'capm' in method.lower() or 'market' in method.lower() or 'index' in method.lower():
238
+ df_ret=compare_msecurity(tickers=ticker+[market_index],measure=ret_type, \
239
+ start=est_window_start,end=end, \
240
+ ticker_type=ticker_type, \
241
+ 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():
247
+ df_ret=compare_msecurity(tickers=ticker,measure=ret_type, \
248
+ start=est_window_start,end=end, \
249
+ ticker_type=ticker_type, \
250
+ graph=False)
251
+ 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)
254
+
255
+ #=====计算异常收益率AR=====
256
+ df_cols=list(df_ret)
257
+ if 'market' in method.lower() or 'index' in method.lower():
258
+ 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():
261
+ for t in ticker_name(ticker,ticker_type):
262
+ df_ret[t+'_AR']=df_ret[t]-df_ret[t+"_predicted"]
263
+ else: #按CAPM计算
264
+ #回归CAPM
265
+ est_window_startpd=pd.to_datetime(est_window_start)
266
+ est_window_endpd =pd.to_datetime(est_window_end)
267
+ df_reg=df_ret[(df_ret.index >=est_window_startpd) & (df_ret.index <=est_window_endpd)].copy()
268
+
269
+ #删除空缺值,否则回归会出错
270
+ df_reg=df_reg.replace([np.nan, None], np.nan).dropna()
271
+
272
+ import statsmodels.api as sm
273
+ X=df_reg[ticker_name(market_index)] - RF #无截距项回归,需要RF
274
+ beta_dict={}
275
+ 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可为多元矩阵
278
+ results = model.fit() #进行OLS回归
279
+ beta=results.params[0] #提取回归系数
280
+
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))
289
+
290
+ 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"]
293
+
294
+ #=====计算CAR=====
295
+ for t in ticker_name(ticker,ticker_type):
296
+ df_ret[t+"_CAR"]=0
297
+ event_window_startpd=pd.to_datetime(event_window_start)
298
+ event_window_endpd=pd.to_datetime(event_window_end)
299
+ post_event_endpd=pd.to_datetime(post_event_end)
300
+
301
+ 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)]
303
+ df_ret_event=df_ret[(df_ret.index >=event_window_startpd) & (df_ret.index <=endpd)]
304
+ for t in ticker_name(ticker,ticker_type):
305
+ df_ret_event[t+'_CAR'] = df_ret_event[t+'_AR'].cumsum()
306
+
307
+ df_ret_before_event=df_ret[(df_ret.index >=startpd) & (df_ret.index < event_window_startpd)]
308
+ for t in ticker_name(ticker,ticker_type):
309
+ df_ret_before_event[t+'_CAR']=np.nan
310
+
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
+ df_show=pd.concat([df_ret_before_event,df_ret_event])
316
+ df_show_cols=[]
317
+ for c in list(df_show):
318
+ if show_AR=='auto':
319
+ if len(ticker)==1:
320
+ if 'AR' in c or 'CAR' in c:
321
+ df_show_cols=df_show_cols+[c]
322
+ show_AR=True
323
+ else:
324
+ if 'CAR' in c:
325
+ df_show_cols=df_show_cols+[c]
326
+ show_AR=False
327
+ elif show_AR==True:
328
+ if 'AR' in c or 'CAR' in c:
329
+ df_show_cols=df_show_cols+[c]
330
+ else: #show_AR==False
331
+ if 'CAR' in c:
332
+ df_show_cols=df_show_cols+[c]
333
+
334
+ df_show2=df_show[df_show_cols]
335
+
336
+ #=====绘图=================================================================
337
+ #设置标签
338
+ df0=df_show2
339
+
340
+ y_label="收益率%"
341
+
342
+
343
+ footnote1="首事件日{0},事件窗口{1},事件后窗口天数{2},市场提前反应天数{3}".format(event_date[0],event_window_new,post_event_days,early_response_days)
344
+ footnote2="收益率类型:"+ectranslate(ret_type)
345
+
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="随机漫步"
350
+ else:
351
+ method_name="CAPM"
352
+
353
+ footnote3=",收益率预期方法:"+method_name
354
+ if not ('random' in method.lower() or 'walk' in method.lower()):
355
+ footnote4=',市场指数:'+ticker_name(market_index)
356
+ else:
357
+ footnote4=''
358
+
359
+ #显著性检验:异于零的t检验
360
+ df_event_window=df0[(df0.index >=event_window_start) & (df0.index <=event_window_end)]
361
+ footnote5="事件窗口CAR的p值:"
362
+ for c in list(df_event_window):
363
+ if 'CAR' in c.upper():
364
+ if len(df_event_window[c])==1:
365
+ if abs(df_event_window[c].values[0]) > 0.01:
366
+ p_value=0.0
367
+ else:
368
+ p_value=1.0
369
+ else:
370
+ p_value=ttest(df_event_window[c],0)
371
+ footnote5=footnote5+c[:-4]+str(p_value)[:6]+","
372
+ footnote5=footnote5.strip(",")
373
+
374
+ 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
381
+ 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(",")
387
+
388
+ footnote7="数据来源:Sina/EM/Yahoo/Stooq/SWHY,"+stoday
389
+
390
+ #x_label=footnote1+'\n'+footnote2+footnote3+footnote4+'\n'+footnote5+'\n'+footnote6+'\n'+footnote7
391
+ x_label=footnote1+'\n'+footnote2+footnote3+footnote4+'\n'+footnote7
392
+
393
+
394
+ axhline_value=0
395
+ axhline_label="零线"
396
+ title_txt="事件影响分析:"
397
+ for t in ticker_name(ticker,ticker_type):
398
+ title_txt=title_txt+t+','
399
+ title_txt=title_txt.strip(",")
400
+
401
+ #判断最新可获得日期
402
+ last_date=df0.index[-1].strftime("%Y-%m-%d")
403
+ if DEBUG:
404
+ print(" DEBUG: last_date={}".format(last_date))
405
+ if post_event_end > last_date:
406
+ post_event_end = last_date
407
+
408
+ if event_window_new[0] != event_window_new[1]:
409
+ attention_point_area=[event_window_start,event_window_end]
410
+ else:
411
+ attention_point_area=[event_window_start,post_event_end]
412
+
413
+ #去掉重复日期项标注且不改变顺序
414
+ event_date_new=[]
415
+ for d in event_date:
416
+ d_new=date_adjust(d,adjust=0)
417
+ event_date_new=event_date_new+[d_new]
418
+
419
+ attention_point=[event_eve_date,event_window_start,event_window_end,post_event_end]+event_date_new
420
+ if not show_AR:
421
+ period_days=calculate_days(event_eve_date,post_event_end)
422
+ if DEBUG:
423
+ print(" DEBUG: period_days={}".format(period_days))
424
+
425
+ if period_days< 6:
426
+ #绘图时横轴若少于6天会出现时间刻度,易误导需避免
427
+ draw_start_date=date_adjust(event_eve_date,adjust=period_days-6)
428
+ attention_point=[draw_start_date,event_window_start,event_window_end,post_event_end]+event_date_new
429
+ """
430
+ if show_AR:
431
+ attention_point=[event_eve_date,event_window_start,event_window_end,post_event_end]+event_date_new
432
+ else:
433
+ attention_point=[event_eve_date,event_window_start,event_window_end,post_event_end]+event_date_new
434
+ df0=df0[(df0.index >= start) & (df0.index <=post_event_end)]
435
+ """
436
+ attention_point.sort(reverse=False)
437
+ attention_point=list({}.fromkeys(attention_point).keys())
438
+
439
+ #绘图
440
+ draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
441
+ data_label=False, \
442
+ loc=loc,resample_freq='D',smooth=False, \
443
+ annotate=True,annotate_value=False, \
444
+ attention_point=attention_point, \
445
+ attention_point_area=attention_point_area, \
446
+ ticker_type=ticker_type,facecolor=facecolor)
447
+
448
+ #=====输出AR和/或CAR表格====================================================
449
+ df1=df0.copy()
450
+ #df1=df1.replace([np.nan, None], np.nan).dropna()
451
+ df1=df1.replace([np.nan, None],'-')
452
+ df1["日期"]=df1.index
453
+ df1["日期"]=df1["日期"].apply(lambda x: x.strftime("%Y-%m-%d"))
454
+
455
+ df1=df1[(df1["日期"] >= event_date[0]) & (df1["日期"] <= post_event_end)]
456
+ df1["星期"]=df1["日期"].apply(lambda x: week_day(x)+1)
457
+
458
+ df1["事件标记"]=''
459
+ for d in event_date_new:
460
+ if len(event_date_new)==1:
461
+ event_text="事件日"
462
+ else:
463
+ pos=event_date_new.index(d)
464
+ if pos==1:
465
+ event_text="首事件日"
466
+ else:
467
+ event_text="事件日"+str(pos+1)
468
+ df1["事件标记"]=df1.apply(lambda x: event_text if x["日期"]==d else x["事件标记"],axis=1)
469
+
470
+ event_text=",事件窗口开始日"
471
+ df1["事件标记"]=df1.apply(lambda x: x["事件标记"]+event_text if x["日期"]==event_window_start else x["事件标记"],axis=1)
472
+ event_text=",事件窗口结束日"
473
+ 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)
476
+
477
+ event_text=",事件窗口"
478
+ df1["事件标记"]=df1.apply(lambda x: x["事件标记"]+event_text if (x["日期"] > event_window_start) and (x["日期"] < event_window_end) else x["事件标记"],axis=1)
479
+
480
+ event_text=",事件后窗口"
481
+ df1["事件标记"]=df1.apply(lambda x: x["事件标记"]+event_text if (x["日期"] > event_window_end) and (x["日期"] < post_event_end) else x["事件标记"],axis=1)
482
+
483
+ df1["事件标记"]=df1["事件标记"].apply(lambda x: x.strip(','))
484
+
485
+ #显示表格
486
+ df0_list=list(df0)
487
+ df1_list=["事件标记","日期","星期"]+df0_list
488
+ df1=df1[df1_list]
489
+ #title_txt=title_txt+",窗口收益率"
490
+
491
+ if "CAPM" in method.upper():
492
+ footnotex="CAPM回归期间:{0}至{1}".format(est_window_start,est_window_end)
493
+ footnotey="CAPM贝塔系数:"
494
+ for k in beta_dict:
495
+ footnotey=footnotey+k+str(round(beta_dict[k],4))[:6]+","
496
+ footnotey=footnotey.strip(",")
497
+
498
+ footnote=footnote2+footnote3+footnote4+'\n'+footnotex+'\n'+footnotey+'\n'+footnote5+'\n'+footnote6
499
+ else:
500
+ footnote=footnote2+footnote3+footnote4+'\n'+footnote5+'\n'+footnote6
501
+
502
+
503
+ df_display_CSS(df1,titletxt=title_txt,footnote=footnote,facecolor='papayawhip',decimals=4, \
504
+ first_col_align='left',second_col_align='left', \
505
+ last_col_align='center',other_col_align='center')
506
+
507
+
508
+ return df_show2
509
+
510
+
511
+
512
+
513
+
514
+
515
+
516
+
517
+
518
+
519
+
520
+
521
+
siat/grafix.py CHANGED
@@ -291,6 +291,9 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
291
291
  atp_list=attention_point
292
292
  else:
293
293
  atp_list=[]
294
+ #去重,不打乱原来的顺序
295
+ atp_list=list(dict.fromkeys(atp_list))
296
+
294
297
  if not atp_list==[] and not atp_list==['']:
295
298
 
296
299
  for at in atp_list:
@@ -348,7 +351,7 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
348
351
  if haveLegend:
349
352
  plt.legend(loc=loc,fontsize=legend_txt_size)
350
353
 
351
- plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
354
+ plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
352
355
  try:
353
356
  plt.gca().set_facecolor(facecolor) #设置画布背景颜色
354
357
  except:
@@ -614,6 +617,10 @@ def plot_line2_coaxial(df01,ticker1,colname1,label1, \
614
617
  atp_list=attention_point
615
618
  else:
616
619
  atp_list=[]
620
+
621
+ #去重,不打乱原来的顺序
622
+ atp_list=list(dict.fromkeys(atp_list))
623
+
617
624
  if not atp_list==[] and not atp_list==['']:
618
625
 
619
626
  for at in atp_list:
@@ -710,7 +717,7 @@ def plot_line2_coaxial(df01,ticker1,colname1,label1, \
710
717
 
711
718
  # 同轴绘图时,loc1/loc2未用上!
712
719
  plt.legend(loc=loc1,fontsize=legend_txt_size)
713
- plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
720
+ plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
714
721
  try:
715
722
  plt.gca().set_facecolor(facecolor)
716
723
  except:
@@ -865,6 +872,9 @@ def plot_line2_coaxial2(df01,ticker1,colname1,label1, \
865
872
  atp_list=attention_point
866
873
  else:
867
874
  atp_list=[]
875
+ #去重,不打乱原来的顺序
876
+ atp_list=list(dict.fromkeys(atp_list))
877
+
868
878
  if not atp_list==[] and not atp_list==['']:
869
879
 
870
880
  for at in atp_list:
@@ -973,7 +983,7 @@ def plot_line2_coaxial2(df01,ticker1,colname1,label1, \
973
983
 
974
984
  # 同轴绘图时,loc1/loc2未用上!
975
985
  plt.legend(loc=loc1,fontsize=legend_txt_size)
976
- plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
986
+ plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
977
987
  try:
978
988
  plt.gca().set_facecolor(facecolor)
979
989
  except:
@@ -1067,6 +1077,8 @@ def plot_line2_twinx(df01,ticker1,colname1,label1, \
1067
1077
  atp_list=attention_point
1068
1078
  else:
1069
1079
  atp_list=[]
1080
+ #去重,不打乱原来的顺序
1081
+ atp_list=list(dict.fromkeys(atp_list))
1070
1082
 
1071
1083
  if DEBUG:
1072
1084
  print("In plot_line2_twinx")
@@ -1182,7 +1194,7 @@ def plot_line2_twinx(df01,ticker1,colname1,label1, \
1182
1194
  ax2.legend(loc=loc2,fontsize=legend_txt_size)
1183
1195
 
1184
1196
  #自动优化x轴标签
1185
- plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
1197
+ plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
1186
1198
 
1187
1199
  plt.title(titletxt,fontweight='bold',fontsize=title_txt_size)
1188
1200
  plt.show()
@@ -1295,6 +1307,8 @@ def plot_line2_twinx2(df01,ticker1,colname1,label1, \
1295
1307
  atp_list=attention_point
1296
1308
  else:
1297
1309
  atp_list=[]
1310
+ #去重,不打乱原来的顺序
1311
+ atp_list=list(dict.fromkeys(atp_list))
1298
1312
 
1299
1313
  if DEBUG:
1300
1314
  print("In plot_line2_twinx")
@@ -1426,7 +1440,7 @@ def plot_line2_twinx2(df01,ticker1,colname1,label1, \
1426
1440
  #自动优化x轴标签
1427
1441
  #格式化时间轴标注
1428
1442
  #plt.gca().xaxis.set_major_formatter(mdate.DateFormatter('%y-%m-%d'))
1429
- plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
1443
+ plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
1430
1444
 
1431
1445
  plt.title(titletxt,fontweight='bold',fontsize=title_txt_size)
1432
1446
  plt.show()
@@ -1634,9 +1648,9 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1634
1648
  color=last_line_color)
1635
1649
 
1636
1650
  #用于关注值的颜色列表
1637
- atv_color_list=["lightgray","paleturquoise","wheat","khaki","lightsage"]
1651
+ atv_color_list=["lightgray","paleturquoise","wheat","khaki","lightsage","hotpink","mediumslateblue"]
1638
1652
  #用于关注点的颜色列表
1639
- atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate"]
1653
+ atp_color_list=["crimson","dodgerblue","magenta","lightseagreen","chocolate","hotpink","mediumslateblue"]
1640
1654
 
1641
1655
  if not attention_value=='':
1642
1656
  if isinstance(attention_value,int) or isinstance(attention_value,float):
@@ -1663,11 +1677,21 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1663
1677
  atp_list=attention_point
1664
1678
  else:
1665
1679
  atp_list=[]
1680
+ #去重,不打乱原来的顺序
1681
+ atp_list=list(dict.fromkeys(atp_list))
1682
+
1666
1683
  if not atp_list==[] and not atp_list==['']:
1667
1684
 
1668
1685
  for at in atp_list:
1669
- pos=atp_list.index(at)
1670
- color=atp_color_list[pos]
1686
+ try:
1687
+ pos=atp_list.index(at)
1688
+ color=atp_color_list[pos]
1689
+ except:
1690
+ print("*** in draw_lines:")
1691
+ print("atp_list={0},at={1},pos={2}".format(atp_list,at,pos))
1692
+ print("atp_color_list={0}".format(atp_color_list))
1693
+
1694
+ color=atp_color_list[-1]
1671
1695
 
1672
1696
  #判断是否日期字符串
1673
1697
  try:
@@ -1725,7 +1749,7 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1725
1749
  #图示标题
1726
1750
  plt.title(title_txt,fontweight='bold',fontsize=title_txt_size)
1727
1751
 
1728
- plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
1752
+ plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
1729
1753
  try:
1730
1754
  plt.gca().set_facecolor(facecolor)
1731
1755
  except:
@@ -2006,6 +2030,9 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
2006
2030
  atp_list=attention_point
2007
2031
  else:
2008
2032
  atp_list=[]
2033
+ #去重,不打乱原来的顺序
2034
+ atp_list=list(dict.fromkeys(atp_list))
2035
+
2009
2036
  if not atp_list==[] and not atp_list==['']:
2010
2037
  for at in atp_list:
2011
2038
  pos=atp_list.index(at)
@@ -2037,7 +2064,7 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
2037
2064
  plt.xlabel(x_label,fontweight='bold',fontsize=xlabel_txt_size,ha='center')
2038
2065
  #图示标题
2039
2066
  plt.title(title_txt,fontweight='bold',fontsize=title_txt_size)
2040
- plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
2067
+ plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
2041
2068
  try:
2042
2069
  plt.gca().set_facecolor(facecolor)
2043
2070
  except:
@@ -2280,7 +2307,7 @@ def plot_2lines(df01,colname1,label1, \
2280
2307
  plt.xlabel(footnote,fontsize=xlabel_txt_size,ha='center')
2281
2308
  plt.legend(loc='best',fontsize=legend_txt_size)
2282
2309
 
2283
- plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
2310
+ plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
2284
2311
  try:
2285
2312
  plt.gca().set_facecolor(facecolor)
2286
2313
  except:
siat/option_pricing.py CHANGED
@@ -20,6 +20,7 @@ from siat.translate import *
20
20
  from siat.grafix import *
21
21
  from siat.security_prices import *
22
22
  from siat.security_trend2 import *
23
+ from siat.yf_name import *
23
24
  #==============================================================================
24
25
  import matplotlib.pyplot as plt
25
26
 
@@ -1160,11 +1161,17 @@ def binomial_american_put(S0,X,Days,r0,sigma,q0=0,steps=200,printout=True):
1160
1161
  #==============================================================================
1161
1162
  if __name__=='__main__':
1162
1163
  ticker="AAPL"
1164
+ ticker="SPY"
1163
1165
 
1164
1166
  def option_maturity(ticker,printout=True):
1165
1167
  """
1166
1168
  功能:获得期权的各个到期日期
1167
1169
  """
1170
+ """
1171
+ if not test_yahoo_access():
1172
+ print(" #Warning(option_maturity): failed to access data source Yahoo Finance")
1173
+ return None
1174
+ """
1168
1175
  import yfinance as yf
1169
1176
  opt = yf.Ticker(ticker)
1170
1177
 
@@ -1172,8 +1179,10 @@ def option_maturity(ticker,printout=True):
1172
1179
  try:
1173
1180
  exp_dates=opt.options
1174
1181
  except:
1175
- print("#Error(option_maturity): failed to get maturity dates for option",ticker)
1182
+ print(" #Error(option_maturity): failed to get option maturity dates for underlying",ticker)
1183
+ print(" Reasons: either",ticker,"does not exist or Yahoo Finance is currently inaccessible")
1176
1184
  return None
1185
+
1177
1186
  datelist=list(exp_dates)
1178
1187
  if not printout:
1179
1188
  return datelist
@@ -1231,7 +1240,8 @@ def option_chain(ticker,maturity_date='today',printout=True):
1231
1240
  try:
1232
1241
  optlist = opt.option_chain(mdate3)
1233
1242
  except:
1234
- print("#Error(option_chain): failed to get option chain for",ticker,'\b@',mdate)
1243
+ if printout:
1244
+ print(" #Error(option_chain): failed to get option chain for",ticker,'\b@',mdate)
1235
1245
  return None,None
1236
1246
 
1237
1247
  opt_call=optlist.calls
@@ -1332,7 +1342,7 @@ if __name__ =="__main__":
1332
1342
  #def predict_stock_trend_by_option(ticker,lastndays=7,power=4):
1333
1343
  def market_prospect_via_option(ticker,lastdays=7):
1334
1344
  """
1335
- 功能:根据股票期权行权价及交易量预测股价
1345
+ 功能:根据期权行权价及交易量预测标的物价格
1336
1346
  注意:本函数与price_prospect_via_option内容基本一致,图示方式略有不同
1337
1347
  """
1338
1348
  lastndays=lastdays
@@ -1423,7 +1433,7 @@ def market_prospect_via_option(ticker,lastdays=7):
1423
1433
 
1424
1434
  #绘图2:OTM Calls vs OTM Puts相对比例
1425
1435
  colname1='OTM in Calls%'
1426
- label1='OTM in Calls%%'
1436
+ label1='OTM in Calls%'
1427
1437
  colname2='OTM in Puts%'
1428
1438
  label2='OTM in Puts%'
1429
1439
  ylabeltxt='Percentage'
@@ -1436,7 +1446,7 @@ def market_prospect_via_option(ticker,lastdays=7):
1436
1446
 
1437
1447
  #绘图3:OTM Calls vs OTM Puts绝对比例
1438
1448
  colname1='OTM Calls in Total%'
1439
- label1='OTM Calls in Total%%'
1449
+ label1='OTM Calls in Total%'
1440
1450
  colname2='OTM Puts in Total%'
1441
1451
  label2='OTM Puts in Total%'
1442
1452
  ylabeltxt='Percentage'
@@ -1447,7 +1457,7 @@ def market_prospect_via_option(ticker,lastdays=7):
1447
1457
  df2,ticker,colname2,label2, \
1448
1458
  ylabeltxt,titletxt,footnote)
1449
1459
 
1450
- #绘图4:股价预测
1460
+ #绘图4:标的物价格预测
1451
1461
  df2x=df2.drop(df2[df2['Total Options']<=1].index)
1452
1462
  """
1453
1463
  colname='WA Strike'
@@ -1613,14 +1623,14 @@ if __name__ =="__main__":
1613
1623
 
1614
1624
  def price_prospect_via_option(ticker,lastdays=7,cutoff=[1.1,5.0,10.0]):
1615
1625
  """
1616
- 功能:根据股票期权预测股价
1626
+ 功能:根据股票期权预测标的物价格
1617
1627
  算法:
1618
1628
  1、计算虚值看涨/看跌期权数量比例
1619
1629
  2、计算虚值看涨/看跌期权交易金额比例
1620
- 3、若虚值看涨期权占优,为看涨,并据此估计未来股价;
1621
- 4、若虚值看跌期权占优,为看跌,并据此估计未来股价;
1630
+ 3、若虚值看涨期权占优,为看涨,并据此估计未来标的物价格;
1631
+ 4、若虚值看跌期权占优,为看跌,并据此估计未来标的物价格;
1622
1632
  5、否则,为不明确
1623
- 返回:股票期权明细
1633
+ 返回:期权明细
1624
1634
  """
1625
1635
  lastndays=lastdays
1626
1636
 
@@ -1637,7 +1647,7 @@ def price_prospect_via_option(ticker,lastdays=7,cutoff=[1.1,5.0,10.0]):
1637
1647
  return None
1638
1648
  print("found",len(datelist),"maturity dates of options")
1639
1649
 
1640
- #最新的股价
1650
+ #最新的标的物价格
1641
1651
  #print("Searching recent close price for",ticker,'...',end='')
1642
1652
  try:
1643
1653
  #lastsdate,lastsprice=get_last_close1(ticker)
@@ -1661,10 +1671,25 @@ def price_prospect_via_option(ticker,lastdays=7,cutoff=[1.1,5.0,10.0]):
1661
1671
 
1662
1672
  if DEBUG: print("Analyzing options matured on",d,'...')
1663
1673
  opt_call,opt_put=option_chain(ticker,d,printout=False)
1664
- if (len(opt_call) == 0) or (len(opt_put) == 0):
1665
- print(" #Error(price_prospect_via_option): failed in retrieving options matured on",d)
1674
+
1675
+ if (opt_call is None) or (opt_put is None):
1676
+ if DEBUG:
1677
+ print(" #Warning(price_prospect_via_option): failed in retrieving options matured on",d)
1678
+ """
1666
1679
  break
1667
1680
  return None
1681
+ """
1682
+ continue
1683
+
1684
+ if (len(opt_call) == 0) or (len(opt_put) == 0):
1685
+ if DEBUG:
1686
+ print(" #Warning(price_prospect_via_option): retrieved zero options matured on",d)
1687
+ """
1688
+ break
1689
+ return None
1690
+ """
1691
+ continue
1692
+
1668
1693
  currency=list(opt_call['currency'])[0]
1669
1694
 
1670
1695
  ##########处理看涨期权##########
@@ -1820,13 +1845,13 @@ def price_prospect_via_option(ticker,lastdays=7,cutoff=[1.1,5.0,10.0]):
1820
1845
  df2,ticker,colname2,label2, \
1821
1846
  ylabeltxt,titletxt,footnote)
1822
1847
 
1823
- #绘图3:预测的股价
1848
+ #绘图3:预测的标的物价格
1824
1849
  df2['Benchmark']=lastsprice
1825
1850
  colname1='Estimated Price'
1826
- label1='预期股价'
1851
+ label1='预期价格'
1827
1852
  colname2='Benchmark'
1828
- label2='当前股价'
1829
- ylabeltxt='股价('+currency+')'
1853
+ label2='当前价格'
1854
+ ylabeltxt='价格('+currency+')'
1830
1855
  titletxt="期权链与标的价格预期: "+tname
1831
1856
 
1832
1857
  plot_line2(df2,ticker,colname1,label1, \
@@ -1844,22 +1869,22 @@ def price_prospect_via_option(ticker,lastdays=7,cutoff=[1.1,5.0,10.0]):
1844
1869
  pd.set_option('display.max_colwidth', 1000)
1845
1870
  pd.set_option('display.unicode.ambiguous_as_wide', True)
1846
1871
  pd.set_option('display.unicode.east_asian_width', True)
1847
- df3.columns=['日期','股价走势','股价预期','虚值看涨/看跌合约数量比例','虚值看涨/看跌交易金额比例']
1872
+ df3.columns=['日期','标的物价格走势','标的物价格预期','虚值看涨/看跌合约数量比例','虚值看涨/看跌交易金额比例']
1848
1873
  print(df3.to_string(index=False))
1849
1874
 
1850
1875
  print(" 注:")
1851
- print(" 1) 当前股价: "+currency+str(lastsprice),"\b,",lastsdate,'\b.')
1852
- print(" 2) +(-)表示股价将比当前变高(低), +/-表示趋势不明朗.")
1876
+ print(" 1) 当前价格: "+currency+str(lastsprice),"\b,",lastsdate,'\b.')
1877
+ print(" 2) +(-)表示价格将比当前变高(低), +/-表示趋势不明朗.")
1853
1878
  print(" 3) 期权交易样本期间: 最近"+str(lastndays)+"个日历日,且期间内未发生分拆.")
1854
- print(" 4) 股价估计可能随时变化,越远期的估计可能准确度越欠佳.")
1879
+ print(" 4) 价格估计可能随时变化,越远期的估计可能准确度越欠佳.")
1855
1880
  print(" "+footnote+'.')
1856
1881
  """
1857
1882
  titletxt="期权链与标的价格预期: "+tname
1858
1883
  footnote1="注:\n"
1859
- footnote2="1、当前股价: "+currency+str(lastsprice)+", "+lastsdate+'\n'
1860
- footnote3="2、+(-)表示股价将比当前变高(低), +/-表示趋势不明朗\n"
1884
+ footnote2="1、当前价格: "+currency+str(lastsprice)+", "+lastsdate+'\n'
1885
+ footnote3="2、+(-)表示价格将比当前变高(低), +/-表示趋势不明朗\n"
1861
1886
  footnote4="3、期权交易样本期间: 最近"+str(lastndays)+"个日历日,且期间内未发生分拆\n"
1862
- footnote5="4) 股价估计可能随时变化,越远期的估计可能准确度越欠佳\n"
1887
+ footnote5="4) 价格价格估计可能随时变化,越远期的估计可能准确度越欠佳\n"
1863
1888
 
1864
1889
  footnote9=footnote1+footnote2+footnote3+footnote4+footnote5+footnote
1865
1890
 
siat/yf_name.py CHANGED
@@ -44,7 +44,7 @@ def test_website(url):
44
44
  #print(f"Website {url} access failed,Code:{response.status_code}")
45
45
  return False
46
46
  except requests.exceptions.RequestException:
47
- print(f"Website {url} is inaccessible")
47
+ print(f" #Warning: website {url} is inaccessible")
48
48
  return False
49
49
 
50
50
  if __name__=='__main__':
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: siat
3
- Version: 3.6.7
3
+ Version: 3.7.1
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
@@ -1,6 +1,6 @@
1
1
  siat/__init__ -20240701.py,sha256=gP5uajXnJesnH5SL0ZPwq_Qhv59AG1bs4qwZv26Fo2Y,2894
2
2
  siat/__init__.py,sha256=sJP_LlLfNAssg5ZCPxxkVMi2v6h5x3WcSco3KBN5CsE,2040
3
- siat/allin.py,sha256=mGm28SxvGGiNAsg6RleiqgyFQvrpgQZERYqpPkdDzPw,2851
3
+ siat/allin.py,sha256=JLuxVmxtlOTDelnfulK6rPoFTIhzTNe5_GShXCiKGZY,2904
4
4
  siat/alpha_vantage_test.py,sha256=tKr-vmuFH3CZAqwmISz6jzjPHzV1JJl3sPfZdz8aTfM,747
5
5
  siat/assets_liquidity.py,sha256=o_UZdLs693uNWPEQB2OzxDH0mdWimOmq4qe_vx1pue0,28987
6
6
  siat/assets_liquidity_test.py,sha256=UWk6HIUlizU7LQZ890fGx8LwU1jMMrIZswg8cFUJWZ8,1285
@@ -18,7 +18,7 @@ siat/capm_beta.py,sha256=cxXdRVBQBllhbfz1LeTJAIWvyRYhW54nhtNUXv4HwS0,29063
18
18
  siat/capm_beta2.py,sha256=-ZYYp1HK7SkfTR3vBKZ0QVC4Q_tbST2O4MGbX_V77J0,32031
19
19
  siat/capm_beta_test.py,sha256=ImR0c5mc4hIl714XmHztdl7qg8v1E2lycKyiqnFj6qs,1745
20
20
  siat/cmat_commons.py,sha256=Nj9Kf0alywaztVoMVeVVL_EZk5jRERJy8R8kBw88_Tg,38116
21
- siat/common.py,sha256=dqvWnw2gyMVo7l2dMyhJeaJZJIyUCVcTMTXC1ryHQos,160442
21
+ siat/common.py,sha256=Ed89feCX9c7i_hbd_pcDk8h7Ie-VHOVKITSH4cKA02M,162842
22
22
  siat/compare_cross.py,sha256=3iP9TH2h3w27F2ARZc7FjKcErYCzWRc-TPiymOyoVtw,24171
23
23
  siat/compare_cross_test.py,sha256=xra5XYmQGEtfIZL2h-GssdH2hLdFIhG3eoCrkDrL3gY,3473
24
24
  siat/concepts_iwencai.py,sha256=m1YEDtECRT6FqtzlKm91pt2I9d3Z_XoP59BtWdRdu8I,3061
@@ -32,6 +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
36
  siat/exchange_bond_china.pickle,sha256=zDqdPrFacQ0nqjP_SuF6Yy87EgijIRsFvFroW7FAYYY,1265092
36
37
  siat/fama_french.py,sha256=aUTC-67t_CEPbLk4u79woW_zfZ7OCP6Fo4z5EdWCSkQ,48051
37
38
  siat/fama_french_test.py,sha256=M4O23lBKsJxhWHRluwCb3l7HSEn3OFTjzGMpehcevRg,4678
@@ -60,7 +61,7 @@ siat/future_china.py,sha256=F-HsIf2Op8Z22RzTjet1g8COzldgnMjFNSXsAkeGyWo,17595
60
61
  siat/future_china_test.py,sha256=BrSzmDVaOHki6rntOtosmRn-6dkfOBuLulJNqh7MOpc,1163
61
62
  siat/global_index_test.py,sha256=hnFp3wqqzzL-kAP8mgxDZ54Bd5Ijf6ENi5YJlGBgcXw,2402
62
63
  siat/google_authenticator.py,sha256=ZUbZR8OW0IAKDbcYtlqGqIpZdERpFor9NccFELxg9yI,1637
63
- siat/grafix.py,sha256=yhWxVk0b-u5ZbP_DS32tZLudl5rwFlUBquiF4JrhXq8,107612
64
+ siat/grafix.py,sha256=EYgRBCfUTgJ9B5rTCzhO9UoABM1amTPUVXkOeKWpgGg,108806
64
65
  siat/grafix_test.py,sha256=kXvcpLgQNO7wd30g_bWljLj5UH7bIVI0_dUtXbfiKR0,3150
65
66
  siat/holding_risk.py,sha256=G3wpaewAKF9CwEqRpr4khyuDu9SU2EGyQUHdk7cmHOA,30693
66
67
  siat/holding_risk_test.py,sha256=FRlw_9wFG98BYcg_cSj95HX5WZ1TvkGaOUdXD7-V86s,474
@@ -82,7 +83,7 @@ siat/ml_cases_example.py,sha256=xRGb3YTQEDTOnaWNzZN_myU5umQnA2RdMNiPrxTmn9c,1673
82
83
  siat/ml_cases_example1.py,sha256=xRGb3YTQEDTOnaWNzZN_myU5umQnA2RdMNiPrxTmn9c,1673
83
84
  siat/option_china.py,sha256=vPALLZDN_oIOmwpaLdB5V6dH4OuA4Q4rSy1K0ADkqYI,120954
84
85
  siat/option_china_test.py,sha256=UQ-YUHUjoGBQyanLcM-yzqeEIUQP_gCQIeT0W6rnUnA,16355
85
- siat/option_pricing.py,sha256=VEqe7VbPkdWX8lS7fJaL1GF9cQx2HRe3UBI2XZJouBQ,73237
86
+ siat/option_pricing.py,sha256=vyQNgBsjcJi70Pa-fJTVVIGK_3jWh80tkd1ESnn3sE4,74069
86
87
  siat/option_pricing_test.py,sha256=eeorV5Ja5vjlRXnP6fWJHetGU5Vb8SnLopkC6RV3GfA,2203
87
88
  siat/option_sina_api_test.py,sha256=dn-k_wrQnAaNKHoROvWJEc7lqlU0bwiV2Aa4usWAFGM,5908
88
89
  siat/proxy_test.py,sha256=erQJrmGs2X46z8Gb1h-7GYQ0rTUcaR8dxHExWoBz2eM,2610
@@ -139,9 +140,9 @@ siat/valuation.py,sha256=o5FsEBkYGCgyEg2m9oF3_KdTzUxPIsEeJCYtsTDZ8OE,50514
139
140
  siat/valuation_china.py,sha256=CVp1IwIsF3Om0J29RGkyxZLt4n9Ug-ua_RKhLwL9fUQ,69624
140
141
  siat/valuation_market_china_test.py,sha256=gbJ0ioauuo4koTPH6WKUkqcXiQPafnbhU5eKJ6lpdLA,1571
141
142
  siat/var_model_validation.py,sha256=R0caWnuZarrRg9939hxh3vJIIpIyPfvelYmzFNZtPbo,14910
142
- siat/yf_name.py,sha256=7uLAcOc8XwfYDjuLqWDiUZHfdMpEbytW7E2ayNNT3f4,20069
143
- siat-3.6.7.dist-info/LICENSE,sha256=NTEMMROY9_4U1szoKC3N2BLHcDd_o5uTgqdVH8tbApw,1071
144
- siat-3.6.7.dist-info/METADATA,sha256=vhM0Z4lhSt8gGEQbaP8AvVOSR-k63r5nc-5YnBXjts8,8009
145
- siat-3.6.7.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
146
- siat-3.6.7.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
147
- siat-3.6.7.dist-info/RECORD,,
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,,
File without changes
File without changes