siat 3.10.75__py3-none-any.whl → 3.10.125__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/common.py CHANGED
@@ -21,6 +21,27 @@ import pandas as pd
21
21
  SUFFIX_LIST_CN=['SS','SZ','BJ','SW','SH']
22
22
  SUFFIX_LIST_HK=['HK']
23
23
  #==============================================================================
24
+
25
+ if __name__=='__main__':
26
+ ticker='000858.SZ'
27
+ ticker='AAPL'
28
+
29
+ security_in_China(ticker)
30
+
31
+ def security_in_China(ticker):
32
+ """
33
+ 功能:判断证券代码,是否在中国市场
34
+ """
35
+
36
+ tlist=ticker.split('.')
37
+ if len(tlist) == 1: return False
38
+ else:
39
+ if tlist[1] in SUFFIX_LIST_CN:
40
+ return True
41
+ else:
42
+ return False
43
+
44
+ #==============================================================================
24
45
  #设置全局语言环境
25
46
  import pickle
26
47
 
@@ -523,7 +544,7 @@ def portfolio_name(portfolio):
523
544
  name=portfolio[keylist[0]][2]
524
545
  except:
525
546
  #name="PF1"
526
- e=text_lang("投资组合","Investment Portfolio")
547
+ name=text_lang("投资组合","Portfolio")
527
548
 
528
549
  return name
529
550
 
@@ -912,6 +933,10 @@ def regparms(results):
912
933
  df_pvalues=pd.DataFrame(pvalues)
913
934
  df_pvalues.columns=['p_values']
914
935
 
936
+ #取rsquared_adj值:单个数值,非数组
937
+ rsquared=results.rsquared
938
+ rsquared_adj=results.rsquared_adj
939
+
915
940
  #生成星星
916
941
  df_pvalues['sig']=df_pvalues['p_values'].apply(lambda x:sigstars(x))
917
942
 
@@ -920,8 +945,10 @@ def regparms(results):
920
945
  how='inner',left_index=True,right_index=True)
921
946
  parms2=pd.merge(parms1,df_pvalues, \
922
947
  how='inner',left_index=True,right_index=True)
923
-
948
+
949
+
924
950
  return parms2
951
+
925
952
  #==============================================================================
926
953
  if __name__=='__main__':
927
954
  txt='QDII-指数'
@@ -2509,7 +2536,7 @@ def list2str(alist):
2509
2536
 
2510
2537
  #==============================================================================
2511
2538
  # FUNCTION TO REMOVE TIMEZONE
2512
- def remove_timezone(dt):
2539
+ def remove_timezone_dt(dt):
2513
2540
 
2514
2541
  # HERE `dt` is a python datetime
2515
2542
  # object that used .replace() method
@@ -2517,7 +2544,7 @@ def remove_timezone(dt):
2517
2544
  #==============================================================================
2518
2545
  def remove_df_index_timezone(df):
2519
2546
  df['timestamp']=df.index
2520
- df['timestamp'] = df['timestamp'].apply(remove_timezone)
2547
+ df['timestamp'] = df['timestamp'].apply(remove_timezone_dt)
2521
2548
  df.index=df['timestamp']
2522
2549
  del df['timestamp']
2523
2550
 
@@ -3760,6 +3787,7 @@ if __name__=='__main__':
3760
3787
  df_display_CSS(df,titletxt,footnote,facecolor,decimals)
3761
3788
 
3762
3789
  def df_display_CSS(df,titletxt='',footnote='',facecolor='papayawhip',decimals=2, \
3790
+ hide_columns=False,
3763
3791
  first_col_align='left',second_col_align='right', \
3764
3792
  last_col_align='right',other_col_align='right', \
3765
3793
  titile_font_size='16px',heading_font_size='15px', \
@@ -3788,7 +3816,10 @@ def df_display_CSS(df,titletxt='',footnote='',facecolor='papayawhip',decimals=2,
3788
3816
  facecolor_default='papayawhip'
3789
3817
 
3790
3818
  #不显示索引列,注意style1已经不是DaraFrame了
3791
- style1=df.style.hide()
3819
+ style1=df.style.hide()
3820
+
3821
+ if hide_columns:
3822
+ style1=df.style.hide(axis='index').hide(axis='columns')
3792
3823
 
3793
3824
  #设置数值字段的千分位符号,同时设置数值字段的小数点精度
3794
3825
  style2=style1.format(precision=decimals,thousands=',',na_rep='-')
@@ -3966,10 +3997,21 @@ def df_index_timezone_remove(df):
3966
3997
  功能:去掉df索引日期中的时区信息,避免日期过滤时出错
3967
3998
  注意:从雅虎财经获取的数据中日期索引项很可能带有时区
3968
3999
  """
4000
+ DEBUG=False
4001
+
4002
+ # 检查是否因为处理时区而丢失了数据
4003
+ if DEBUG:
4004
+ print(f"BEFORE processing timezone, counts={len(df)}, from {df.index[0]} to {df.index[-1]}")
4005
+
3969
4006
  import pandas as pd
3970
- df.index = pd.to_datetime(df.index)
4007
+
4008
+ #可能无法处理某些复杂的时区情况
4009
+ df.index = pd.to_datetime(df.index,utc=True)
3971
4010
  df.index = df.index.tz_localize(None)
3972
-
4011
+
4012
+ if DEBUG:
4013
+ print(f"AFTER processing timezone, counts={len(df)}, from {df.index[0]} to {df.index[-1]}")
4014
+
3973
4015
  return df
3974
4016
  #==============================================================================
3975
4017
 
@@ -5107,5 +5149,44 @@ def is_A_share(ticker):
5107
5149
  return False
5108
5150
 
5109
5151
 
5152
+ #==============================================================================
5153
+
5154
+ def print2CSS(data_dict, \
5155
+ titletxt='',footnote='',facecolor='papayawhip',decimals=2, \
5156
+ hide_columns=True,
5157
+ first_col_align='left',second_col_align='right', \
5158
+ last_col_align='right',other_col_align='right', \
5159
+ titile_font_size='14px',heading_font_size='14px', \
5160
+ data_font_size='14px',footnote_font_size='11px'):
5161
+ """
5162
+ 功能:将字典中的数据转化为df,使用CSS形式实现整齐输出
5163
+ """
5164
+ import pandas as pd
5165
+ disp_df=pd.DataFrame(columns=['Item','Value'])
5166
+
5167
+ keys=list(data_dict.keys())
5168
+ for key in keys:
5169
+ value=data_dict[key]
5170
+
5171
+ s=pd.Series({'Item':key,'Value':value})
5172
+ disp_df=disp_df._append(s,ignore_index=True)
5173
+
5174
+ df_display_CSS(disp_df,titletxt=titletxt,footnote=footnote, \
5175
+ facecolor=facecolor,decimals=decimals, \
5176
+ hide_columns=hide_columns,
5177
+ first_col_align=first_col_align,second_col_align=second_col_align, \
5178
+ last_col_align=last_col_align,other_col_align=other_col_align, \
5179
+ titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
5180
+ data_font_size=data_font_size,footnote_font_size=footnote_font_size)
5181
+
5182
+ return
5183
+
5184
+ #==============================================================================
5185
+ #==============================================================================
5110
5186
  #==============================================================================
5111
5187
  #==============================================================================
5188
+ #==============================================================================
5189
+ #==============================================================================
5190
+ #==============================================================================
5191
+ #==============================================================================
5192
+
siat/economy2.py CHANGED
@@ -1367,6 +1367,68 @@ def economic_translate(indicator):
1367
1367
  'GDP per capita, PPP (constant 2021 international $)',
1368
1368
  'GDP per capita, PPP (constant 2021 international $)'],
1369
1369
 
1370
+ # NY.GNP.MKTP:国民总收入GNI总量=======================================
1371
+ ['NY.GNP.MKTP.CD','GNI(美元现价)',
1372
+ 'GNI (current US$)',
1373
+ 'GNI (current US$)'],
1374
+
1375
+ ['NY.GNP.MKTP.CN','GNI(本币现价)',
1376
+ 'GNI (current LCU)',
1377
+ 'GNI (current LCU)'],
1378
+
1379
+ ['NY.GNP.MKTP.CN.AD','GNI(统计口径调整后,本币现价)',
1380
+ 'GNI: linked series (current LCU)',
1381
+ 'GNI: linked series (current LCU)'],
1382
+
1383
+ ['NY.GNP.MKTP.KD','GNI(2015美元不变价格)',
1384
+ 'GNI (constant 2015 US$)',
1385
+ 'GNI (constant 2015 US$)'],
1386
+
1387
+ ['NY.GNP.MKTP.KD.ZG','GNI年增速%(2015美元不变价格)',
1388
+ 'GNI growth (annual %, constant 2015 US$)',
1389
+ 'GNI growth (annual %, constant 2015 US$)'],
1390
+
1391
+ ['NY.GNP.MKTP.KN','GNI(本币不变价格)',
1392
+ 'GNI (constant LCU)',
1393
+ 'GNI (constant LCU)'],
1394
+
1395
+ ['NY.GNP.MKTP.PP.CD','GNI(购买力平价,国际美元现价)',
1396
+ 'GNI(PPP, current international $)',
1397
+ 'GNI(PPP, current international $)'],
1398
+
1399
+ ['NY.GNP.MKTP.PP.KD','GNI(购买力平价,2021国际美元不变价格)',
1400
+ 'GNI(PPP, constant 2021 international $)',
1401
+ 'GNI(PPP, constant 2021 international $)'],
1402
+
1403
+ # NY.GNP.PCAP:GNI人均=======================================
1404
+ ['NY.GNP.PCAP.CD','人均GNI(美元现价)',
1405
+ 'GNI per capita (current US$)',
1406
+ 'GNI per capita (current US$)'],
1407
+
1408
+ ['NY.GNP.PCAP.CN','人均GNI(本币现价)',
1409
+ 'GNI per capita (current LCU)',
1410
+ 'GNI per capita (current LCU)'],
1411
+
1412
+ ['NY.GNP.PCAP.KD','人均GNI(2015美元不变价格)',
1413
+ 'GNI per capita (constant 2015 US$)',
1414
+ 'GNI per capita (constant 2015 US$)'],
1415
+
1416
+ ['NY.GNP.PCAP.KD.ZG','人均GNI年增速%(2015美元不变价格)',
1417
+ 'GNI per capita growth (annual %, constant 2015 US$)',
1418
+ 'GNI per capita growth (annual %, constant 2015 US$)'],
1419
+
1420
+ ['NY.GNP.PCAP.KN','人均GNI(本币不变价格)',
1421
+ 'GNI per capita (constant LCU)',
1422
+ 'GNI per capita (constant LCU)'],
1423
+
1424
+ ['NY.GNP.PCAP.PP.CD','人均GNI(购买力平价,国际美元现价)',
1425
+ 'GNI per capita, PPP (current international $)',
1426
+ 'GNI per capita, PPP (current international $)'],
1427
+
1428
+ ['NY.GNP.PCAP.PP.KD','人均GNI(购买力平价,2021国际美元不变价格)',
1429
+ 'GNI per capita, PPP (constant 2021 international $)',
1430
+ 'GNI per capita, PPP (constant 2021 international $)'],
1431
+
1370
1432
  #######################################################################
1371
1433
  #“International $”(国际美元)是一种标准化的货币单位,用于消除汇率差异,
1372
1434
  #使不同国家的经济指标(如 GDP)在购买力平价(PPP)基础上更具可比性。
@@ -1387,6 +1449,10 @@ def economic_translate(indicator):
1387
1449
  #######################################################################
1388
1450
 
1389
1451
  # GFDD.DM:证券市场-股票、权益与债券=====================================
1452
+ ['CM.MKT.LCAP.GD.ZS','国内上市公司市值占GDP%',
1453
+ 'Market cap of domestic listed companies to GDP (%)',
1454
+ 'Market cap of domestic listed companies to GDP (%)'],
1455
+
1390
1456
  ['GFDD.DM.01','股票市场总市值占GDP%',
1391
1457
  'Stock market capitalization to GDP (%)',
1392
1458
  'Stock market capitalization to GDP (%)'],
@@ -1494,7 +1560,15 @@ def economic_translate(indicator):
1494
1560
  ['FM.LBL.BMNY.CN','广义货币(本币现价)',
1495
1561
  'Broad money (current LCU)',
1496
1562
  'Broad money (current LCU)'],
1497
-
1563
+
1564
+ ['FM.LBL.BMNY.ZG','广义货币年增速%',
1565
+ 'Broad money growth (annual %)',
1566
+ 'Broad money growth (annual %)'],
1567
+
1568
+ ['FM.LBL.MQMY.XD','货币流通速度(GDP/M2)',
1569
+ 'Income velocity of money (GDP/M2)',
1570
+ 'Income velocity of money (GDP/M2)'],
1571
+
1498
1572
  ['FM.LBL.BMNY.GD.ZS','广义货币(占GDP%)',
1499
1573
  'Broad money (% of GDP)',
1500
1574
  'Broad money (% of GDP)'],
Binary file
siat/fama_french.py CHANGED
@@ -63,10 +63,112 @@ def convert2freq(df,new_freq='daily'):
63
63
 
64
64
  return df
65
65
  #==============================================================================
66
+ #==============================================================================
67
+ if __name__=='__main__':
68
+ start='auto'; end='today'
69
+
70
+ scope='US'
71
+ factor='FF3'
72
+ freq='yearly'
73
+
74
+ show_ff_factors(ticker='US',indicator='FF3',freq='yearly')
66
75
 
76
+ def show_ff_factors(market='US',indicator='FF3', \
77
+ start='auto',end='today',freq='yearly'):
78
+ """
79
+ 功能:套壳函数get_ff3_factors/get_ffc4_factors/get_ff5_factors
80
+
81
+ 【支持的因子种类(factor)】
82
+ FF3: FF3各个因子
83
+ FFC4: FFC4各个因子
84
+ FF5: FF5各个因子
85
+
86
+ 【支持的国家/地区(scope)】
87
+ US: 美国
88
+ North_America:北美(美国+加拿大)
89
+ Global: 全球
90
+ Global_ex_US: 全球(除美国外)
91
+ Asia_Pacific_ex_Japan: 亚太(除日本外)
92
+ China: 中国
93
+ Japan: 日本
94
+ Europe: 欧洲
95
+
96
+ 【支持的取样频率(freq)】
97
+ yearly: 年
98
+ monthly: 月
99
+ daily: 日
100
+ """
101
+ ticker=market
102
+
103
+ indicator1=indicator.lower()
104
+ factorlist=['ff3','ffc4','ff5']
105
+ if not (indicator1 in factorlist):
106
+ print(f" #Error(show_ff_factors): unsupported factor {indicator}")
107
+ print(f" Supported factors for FF models: {factorlist}")
108
+ return
109
+
110
+ import datetime; todaydt = datetime.date.today(); todaystr=str(todaydt)
111
+ if end == 'today': end=todaystr
112
+
113
+ if start == 'auto':
114
+ if freq == 'yearly':
115
+ start=date_adjust(end,adjust=-365*5)
116
+ elif freq == 'monthly':
117
+ start=date_adjust(end,adjust=-31*8)
118
+ else: #freq=='daily'
119
+ start=date_adjust(end,adjust=-60)
120
+
121
+ start,end=start_end_preprocess(start,end)
122
+
123
+ freq=freq.lower()
124
+ if freq == 'daily':
125
+ print("Looking for daily factors, it may take time ...")
126
+
127
+ if indicator1=='ff3':
128
+ df=get_ff3_factors(start=start,end=end,scope=ticker,freq=freq)
129
+ elif indicator1=='ffc4':
130
+ df=get_ffc4_factors(start=start,end=end,scope=ticker,freq=freq)
131
+ elif indicator1=='ff5':
132
+ df=get_ff5_factors(start=start,end=end,scope=ticker,freq=freq)
133
+ else:
134
+ pass
135
+
136
+ #处理无数据情形
137
+ if df is None:
138
+ print(f" #Warning(show_ff_factors): got none data from {start} to {end}")
139
+ print(f" Suggestion: may specify an earlier start date and try again")
140
+ return
141
+ if len(df) == 0:
142
+ print(f" #Warning(show_ff_factors): got zero data from {start} to {end}")
143
+ print(f" Suggestion: may specify an earlier start date and try again")
144
+ return
145
+
146
+ #处理RF小数位数
147
+ df['RF']=df['RF'].apply(lambda x: str(round(x,4)))
148
+
149
+ #titletxt="Asset Pricing Factors: "+indicator.upper()+'Model, '+freq+' @ '+ticker
150
+ titletxt=indicator.upper()+'模型定价因子:'+freq.title()+' @'+ticker
151
+
152
+ if freq == 'yearly':
153
+ ft0="说明:RF为年化无风险利率%(美短债收益率)"
154
+ elif freq == 'monthly':
155
+ ft0="说明:RF为月度无风险利率%(美短债收益率)"
156
+ else:
157
+ ft0="说明:RF为日频无风险利率%(基于短期美债收益率)"
158
+
159
+ #footnote="Data source: Dartmouth College, "+todaystr
160
+ footnote=ft0+'\n'+"数据来源:Dartmouth College,"+todaystr
161
+
162
+ df_display_CSS(df,titletxt=titletxt,footnote=footnote,facecolor='papayawhip', \
163
+ decimals=2, \
164
+ first_col_align='center',second_col_align='center', \
165
+ last_col_align='center',other_col_align='center')
166
+
167
+ return
168
+
169
+ #==============================================================================
67
170
  if __name__=='__main__':
68
- start='2025-1-1'
69
- end='2025-6-13'
171
+ start='2020-1-1'; end='2025-4-30'
70
172
 
71
173
  scope='Europe'
72
174
  factor='Mom'
@@ -74,13 +176,14 @@ if __name__=='__main__':
74
176
 
75
177
  scope='US'
76
178
  factor='FF3'
179
+ freq='yearly'
77
180
  freq='daily'
78
181
 
79
182
  ff3d=get_ff_factors(start,end,scope,factor,freq='daily')
80
183
  ff3mth=get_ff_factors(start,end,scope,factor,freq='monthly')
81
184
  ff3y=get_ff_factors(start,end,scope,factor,freq='yearly')
82
185
 
83
- def get_ff_factors(start,end,scope='US',factor='FF3',freq='monthly'):
186
+ def get_ff_factors(start,end,scope='US',factor='FF3',freq='monthly',retry=10):
84
187
  """
85
188
  功能:套壳函数get_ff_factors0,应对freq='daily'经常失败的变通方法
86
189
  """
@@ -88,7 +191,12 @@ def get_ff_factors(start,end,scope='US',factor='FF3',freq='monthly'):
88
191
  startpd=pd.to_datetime(start)
89
192
  endpd=pd.to_datetime(end)
90
193
 
91
- fff=get_ff_factors0(start=start,end=end,scope=scope,factor=factor,freq=freq)
194
+ fff=None
195
+ for i in range(retry):
196
+ if not (fff is None): break
197
+ fff=get_ff_factors0(start=start,end=end,scope=scope,factor=factor,freq=freq)
198
+
199
+ #多次尝试后仍未成功做变通处理:针对日度数据,使用月/年数据均匀化为日度数据
92
200
  if fff is None:
93
201
  if freq == 'daily':
94
202
  start1=date_adjust(start,adjust=-31)
@@ -117,6 +225,14 @@ def get_ff_factors(start,end,scope='US',factor='FF3',freq='monthly'):
117
225
  else:
118
226
  ff_factors=fff
119
227
 
228
+ #加入日期
229
+ cols=list(ff_factors)
230
+ ff_factors['Date']=ff_factors.index
231
+ if freq == 'daily':
232
+ ff_factors['Date']=ff_factors['Date'].apply(lambda x: x.strftime("%Y-%m-%d"))
233
+
234
+ ff_factors=ff_factors[['Date']+cols]
235
+
120
236
  return ff_factors
121
237
 
122
238
 
@@ -812,7 +928,8 @@ def get_ffc4_factors(start,end,scope='US',freq='yearly'):
812
928
  Mom['date']=pd.to_datetime(Mom['date'].astype('str'))
813
929
  Mom.set_index('date',drop=True, inplace=True)
814
930
 
815
- ffc4_factors=pd.merge(ff3,Mom,how='left',left_index=True,right_index=True)
931
+ #ffc4_factors=pd.merge(ff3,Mom,how='left',left_index=True,right_index=True)
932
+ ffc4_factors=pd.merge(ff3,Mom,how='inner',on='Date')
816
933
  #del ffc4_factors['date']
817
934
 
818
935
  return ffc4_factors
@@ -1003,11 +1120,15 @@ def reg_ff3_betas(ticker,start,end,scope='US',graph=True):
1003
1120
  ret=ret.rename(columns={'Close':'dRet'})
1004
1121
 
1005
1122
  #抓取FF3因子
1123
+ print(" Looking for factors for FF3 model ...")
1006
1124
  freq='daily'
1007
1125
  ff3=get_ff3_factors(start,end,scope,freq)
1008
1126
  if ff3 is None:
1009
1127
  print(" #Warning(reg_ff3_betas): factors unavailable for",scope,freq,'from',start,'to',end)
1010
1128
  return None
1129
+ if len(ff3) == 0:
1130
+ print(" #Warning(reg_ff3_betas): zero factors retrieved for",scope,freq,'from',start,'to',end)
1131
+ return None
1011
1132
 
1012
1133
  #改造索引类型为时间戳索引(DatetimeIndex),便于与ret合成
1013
1134
  ff3['Date']=ff3.index.strftime("%m/%d/%Y")
@@ -1032,7 +1153,7 @@ def reg_ff3_betas(ticker,start,end,scope='US',graph=True):
1032
1153
  #输出结果并绘制横向柱状图
1033
1154
  if graph == True:
1034
1155
  gparms=parms.iloc[[1,2,3]]
1035
- print("\n",parms)
1156
+ #print("\n",parms)
1036
1157
  title=ticker_name(ticker)+": FF3模型的贝塔系数"
1037
1158
  plt.title(title,fontsize=12,fontweight='bold')
1038
1159
  plt.ylabel("贝塔系数",fontsize=12,fontweight='bold')
@@ -1093,6 +1214,13 @@ if __name__=='__main__':
1093
1214
 
1094
1215
 
1095
1216
  #==============================================================================
1217
+ if __name__=='__main__':
1218
+ ticker='MSFT'
1219
+ start='2022-5-1'; end='2025-4-30'
1220
+ scope='US'; graph=True
1221
+
1222
+
1223
+
1096
1224
  def reg_ffc4_betas(ticker,start,end,scope='US',graph=True):
1097
1225
  """
1098
1226
  功能:测试一只股票对于FFC4各个因子的系数大小、符号方向和显著性
@@ -1121,16 +1249,20 @@ def reg_ffc4_betas(ticker,start,end,scope='US',graph=True):
1121
1249
  ret=ret.rename(columns={'Close':'dRet'})
1122
1250
 
1123
1251
  #抓取每日FFC4因子
1252
+ print(" Looking for factors for FFC4 model ...")
1124
1253
  freq='daily'
1125
1254
  ffc4=get_ffc4_factors(start,end,scope,freq)
1126
1255
  if ffc4 is None:
1127
1256
  print(" #Warning(reg_ffc4_betas): factors not available for",scope,freq,'from',start,'to',end)
1128
1257
  return None
1258
+ if len(ffc4) == 0:
1259
+ print(" #Warning(reg_ffc4_betas): zero factors retrieved for",scope,freq,'from',start,'to',end)
1260
+ return None
1129
1261
 
1130
1262
  #改造索引类型为时间戳索引(DatetimeIndex),便于与ret合成
1131
- ffc4['Date']=ffc4.index.strftime("%m/%d/%Y")
1263
+ #ffc4['Date']=ffc4.index.strftime("%m/%d/%Y")
1132
1264
  ffc4['Date']=pd.to_datetime(ffc4['Date'])
1133
- ffc4.set_index('Date',inplace=True)
1265
+ ffc4.set_index('Date',drop=True,inplace=True)
1134
1266
 
1135
1267
  #合成股票日收益率+每日FF3因子
1136
1268
  sample=pd.merge(ret,ffc4,how='inner',left_index=True,right_index=True)
@@ -1152,7 +1284,7 @@ def reg_ffc4_betas(ticker,start,end,scope='US',graph=True):
1152
1284
  #输出结果并绘制横向柱状图
1153
1285
  gparms=parms.iloc[[1,2,3,4]]
1154
1286
  if graph == True:
1155
- print("\n",parms)
1287
+ #print("\n",parms)
1156
1288
  title=ticker_name(ticker)+": FFC4模型的贝塔系数"
1157
1289
  plt.title(title,fontsize=12,fontweight='bold')
1158
1290
  plt.ylabel("贝塔系数",fontsize=12,fontweight='bold')
@@ -1213,6 +1345,11 @@ if __name__=='__main__':
1213
1345
  test_ffc4_betas()
1214
1346
 
1215
1347
  #==============================================================================
1348
+ if __name__=='__main__':
1349
+ ticker='MSFT'
1350
+ start='2024-5-1'; end='2025-4-30'
1351
+ scope='US'; graph=True
1352
+
1216
1353
  def reg_ff5_betas(ticker,start,end,scope='US',graph=True):
1217
1354
  """
1218
1355
  功能:测试一只股票对于FF5各个因子的系数大小、符号方向和显著性
@@ -1240,12 +1377,16 @@ def reg_ff5_betas(ticker,start,end,scope='US',graph=True):
1240
1377
  #命名日收益率字段为dRet
1241
1378
  ret=ret.rename(columns={'Close':'dRet'})
1242
1379
 
1243
- #抓取每日FF3因子
1380
+ #抓取每日FF5因子
1381
+ print(" Looking for factors for FF5 model ...")
1244
1382
  freq='daily'
1245
1383
  ff5=get_ff5_factors(start,end,scope,freq)
1246
1384
  if ff5 is None:
1247
1385
  print(" #Warning(reg_ff5_betas): factors not available for",scope,freq,'from',start,'to',end)
1248
1386
  return None
1387
+ if len(ff5) is None:
1388
+ print(" #Warning(reg_ff5_betas): zero factors retrieved for",scope,freq,'from',start,'to',end)
1389
+ return None
1249
1390
 
1250
1391
  #改造索引类型为时间戳索引(DatetimeIndex),便于与ret合成
1251
1392
  ff5['Date']=ff5.index.strftime("%m/%d/%Y")
@@ -1269,7 +1410,7 @@ def reg_ff5_betas(ticker,start,end,scope='US',graph=True):
1269
1410
  #输出结果并绘制横向柱状图
1270
1411
  gparms=parms.iloc[[1,2,3,4,5]]
1271
1412
  if graph == True:
1272
- print("\n",parms)
1413
+ #print("\n",parms)
1273
1414
  title=ticker_name(ticker)+":FF5模型的贝塔系数"
1274
1415
  plt.title(title,fontsize=12,fontweight='bold')
1275
1416
  plt.ylabel("贝塔系数",fontsize=12,fontweight='bold')
@@ -1329,4 +1470,52 @@ def test_ff5_betas():
1329
1470
  if __name__=='__main__':
1330
1471
  test_ff5_betas()
1331
1472
 
1332
- #==============================================================================
1473
+ #==============================================================================
1474
+
1475
+
1476
+
1477
+ def reg_ff_betas(ticker,start,end='today',indicator='FF3',market='US'):
1478
+ """
1479
+ 功能:套壳函数reg_ff3_betas/reg_ffc4_betas/reg_ff5_betas
1480
+ 参数:
1481
+ indicator:默认'FF3',还可为'FFC4'或'FF5'
1482
+ scope:默认'US',还可为'China'或'Japan'或'Europe'等
1483
+ """
1484
+ scope=market
1485
+
1486
+ start,end=start_end_preprocess(start,end)
1487
+
1488
+ indicator1=indicator.lower()
1489
+ factorlist=['ff3','ffc4','ff5']
1490
+ if not (indicator1 in factorlist):
1491
+ print(f" #Error(show_ff_factors): unsupported factor {indicator}")
1492
+ print(f" Supported factors for FF models: {factorlist}")
1493
+ return
1494
+
1495
+ if indicator1=='ff3':
1496
+ df=reg_ff3_betas(ticker=ticker,start=start,end=end,scope=scope)
1497
+ elif indicator1=='ffc4':
1498
+ df=reg_ffc4_betas(ticker=ticker,start=start,end=end,scope=scope)
1499
+ elif indicator1=='ff5':
1500
+ df=reg_ff5_betas(ticker=ticker,start=start,end=end,scope=scope)
1501
+ else:
1502
+ pass
1503
+
1504
+ #打印回归结果
1505
+ cols=list(df)
1506
+ df['const']=df.index
1507
+ df=df[['const']+cols]
1508
+
1509
+ titletxt=ticker_name(ticker)+":"+indicator.upper()+'模型回归结果'
1510
+ import datetime; todaydt = datetime.date.today(); todaystr=str(todaydt)
1511
+ footnote="数据来源:Dartmouth College/sina/stooq/Yahoo等,"+todaystr
1512
+
1513
+ df.rename(columns={'const':'Constant','coef':'Coefficient', \
1514
+ 'sig':'Significance'},inplace=True)
1515
+
1516
+ df_display_CSS(df,titletxt=titletxt,footnote=footnote,facecolor='papayawhip', \
1517
+ decimals=4, \
1518
+ first_col_align='center',second_col_align='center', \
1519
+ last_col_align='center',other_col_align='center')
1520
+
1521
+ return df