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/assets_liquidity.py +168 -30
- siat/bond.py +34 -7
- siat/capm_beta.py +34 -9
- siat/common.py +88 -7
- siat/economy2.py +75 -1
- siat/exchange_bond_china.pickle +0 -0
- siat/fama_french.py +201 -12
- siat/financial_statements.py +26 -85
- siat/financials.py +114 -14
- siat/financials_china.py +1 -1
- siat/fund_china.py +6 -5
- siat/future_china.py +8 -2
- siat/holding_risk.py +38 -31
- siat/market_china.py +20 -10
- siat/markowitz2.py +72 -10
- siat/option_china.py +45 -17
- siat/option_pricing.py +3 -0
- siat/other_indexes.py +16 -3
- siat/risk_adjusted_return.py +182 -114
- siat/risk_evaluation.py +252 -20
- siat/sector_china.py +12 -9
- siat/security_price2.py +19 -4
- siat/security_prices.py +222 -23
- siat/security_trend2.py +3 -3
- siat/stock.py +32 -0
- siat/translate.py +18 -9
- siat/var_model_validation.py +59 -0
- {siat-3.10.75.dist-info → siat-3.10.125.dist-info}/METADATA +1 -1
- {siat-3.10.75.dist-info → siat-3.10.125.dist-info}/RECORD +32 -32
- {siat-3.10.75.dist-info → siat-3.10.125.dist-info}/LICENSE +0 -0
- {siat-3.10.75.dist-info → siat-3.10.125.dist-info}/WHEEL +0 -0
- {siat-3.10.75.dist-info → siat-3.10.125.dist-info}/top_level.txt +0 -0
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
|
-
|
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
|
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(
|
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
|
-
|
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)'],
|
siat/exchange_bond_china.pickle
CHANGED
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='
|
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=
|
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
|
-
#抓取每日
|
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
|