siat 3.10.132__py3-none-any.whl → 3.10.133__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/__init__.py +0 -0
- siat/allin.py +0 -0
- siat/assets_liquidity.py +0 -0
- siat/beta_adjustment.py +0 -0
- siat/beta_adjustment_china.py +0 -0
- siat/blockchain.py +0 -0
- siat/bond.py +0 -0
- siat/bond_base.py +0 -0
- siat/bond_china.py +0 -0
- siat/bond_zh_sina.py +0 -0
- siat/capm_beta.py +0 -0
- siat/capm_beta2.py +0 -0
- siat/compare_cross.py +0 -0
- siat/copyrights.py +0 -0
- siat/cryptocurrency.py +0 -0
- siat/economy.py +0 -0
- siat/economy2.py +0 -0
- siat/esg.py +0 -0
- siat/event_study.py +0 -0
- siat/exchange_bond_china.pickle +0 -0
- siat/fama_french.py +0 -0
- siat/fin_stmt2_yahoo.py +0 -0
- siat/financial_base.py +0 -0
- siat/financial_statements.py +0 -0
- siat/financials.py +0 -0
- siat/financials2.py +0 -0
- siat/financials_china.py +0 -0
- siat/financials_china2.py +0 -0
- siat/fund.py +0 -0
- siat/fund_china.pickle +0 -0
- siat/fund_china.py +0 -0
- siat/future_china.py +0 -0
- siat/google_authenticator.py +0 -0
- siat/grafix.py +0 -0
- siat/holding_risk.py +0 -0
- siat/luchy_draw.py +0 -0
- siat/market_china.py +0 -0
- siat/markowitz.py +0 -0
- siat/markowitz2.py +0 -0
- siat/markowitz2_20250704.py +0 -0
- siat/markowitz2_20250705.py +0 -0
- siat/markowitz_simple.py +0 -0
- siat/ml_cases.py +0 -0
- siat/ml_cases_example.py +0 -0
- siat/option_china.py +0 -0
- siat/option_pricing.py +0 -0
- siat/other_indexes.py +0 -0
- siat/risk_adjusted_return.py +0 -0
- siat/risk_adjusted_return2.py +0 -0
- siat/risk_evaluation.py +0 -0
- siat/risk_free_rate.py +0 -0
- siat/sector_china.py +0 -0
- siat/security_price2.py +0 -0
- siat/security_prices.py +40 -2
- siat/security_trend.py +0 -0
- siat/security_trend2.py +0 -0
- siat/stock.py +0 -0
- siat/stock_advice_linear.py +0 -0
- siat/stock_base.py +0 -0
- siat/stock_china.py +0 -0
- siat/stock_info.pickle +0 -0
- siat/stock_prices_kneighbors.py +0 -0
- siat/stock_prices_linear.py +0 -0
- siat/stock_profile.py +0 -0
- siat/stock_technical.py +0 -0
- siat/stooq.py +0 -0
- siat/transaction.py +0 -0
- siat/translate.py +0 -0
- siat/valuation.py +0 -0
- siat/valuation_china.py +0 -0
- siat/var_model_validation.py +0 -0
- siat/yf_name.py +0 -0
- {siat-3.10.132.dist-info/licenses → siat-3.10.133.dist-info}/LICENSE +0 -0
- {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/METADATA +232 -235
- siat-3.10.133.dist-info/RECORD +78 -0
- {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/WHEEL +1 -1
- {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/top_level.txt +0 -1
- build/lib/build/lib/siat/__init__.py +0 -75
- build/lib/build/lib/siat/allin.py +0 -137
- build/lib/build/lib/siat/assets_liquidity.py +0 -915
- build/lib/build/lib/siat/beta_adjustment.py +0 -1058
- build/lib/build/lib/siat/beta_adjustment_china.py +0 -548
- build/lib/build/lib/siat/blockchain.py +0 -143
- build/lib/build/lib/siat/bond.py +0 -2900
- build/lib/build/lib/siat/bond_base.py +0 -992
- build/lib/build/lib/siat/bond_china.py +0 -100
- build/lib/build/lib/siat/bond_zh_sina.py +0 -143
- build/lib/build/lib/siat/capm_beta.py +0 -783
- build/lib/build/lib/siat/capm_beta2.py +0 -887
- build/lib/build/lib/siat/common.py +0 -5360
- build/lib/build/lib/siat/compare_cross.py +0 -642
- build/lib/build/lib/siat/copyrights.py +0 -18
- build/lib/build/lib/siat/cryptocurrency.py +0 -667
- build/lib/build/lib/siat/economy.py +0 -1471
- build/lib/build/lib/siat/economy2.py +0 -1853
- build/lib/build/lib/siat/esg.py +0 -536
- build/lib/build/lib/siat/event_study.py +0 -815
- build/lib/build/lib/siat/fama_french.py +0 -1521
- build/lib/build/lib/siat/fin_stmt2_yahoo.py +0 -982
- build/lib/build/lib/siat/financial_base.py +0 -1160
- build/lib/build/lib/siat/financial_statements.py +0 -598
- build/lib/build/lib/siat/financials.py +0 -2339
- build/lib/build/lib/siat/financials2.py +0 -1278
- build/lib/build/lib/siat/financials_china.py +0 -4433
- build/lib/build/lib/siat/financials_china2.py +0 -2212
- build/lib/build/lib/siat/fund.py +0 -629
- build/lib/build/lib/siat/fund_china.py +0 -3307
- build/lib/build/lib/siat/future_china.py +0 -551
- build/lib/build/lib/siat/google_authenticator.py +0 -47
- build/lib/build/lib/siat/grafix.py +0 -3636
- build/lib/build/lib/siat/holding_risk.py +0 -867
- build/lib/build/lib/siat/luchy_draw.py +0 -638
- build/lib/build/lib/siat/market_china.py +0 -1168
- build/lib/build/lib/siat/markowitz.py +0 -2363
- build/lib/build/lib/siat/markowitz2.py +0 -3150
- build/lib/build/lib/siat/markowitz2_20250704.py +0 -2969
- build/lib/build/lib/siat/markowitz2_20250705.py +0 -3158
- build/lib/build/lib/siat/markowitz_simple.py +0 -373
- build/lib/build/lib/siat/ml_cases.py +0 -2291
- build/lib/build/lib/siat/ml_cases_example.py +0 -60
- build/lib/build/lib/siat/option_china.py +0 -3069
- build/lib/build/lib/siat/option_pricing.py +0 -1925
- build/lib/build/lib/siat/other_indexes.py +0 -409
- build/lib/build/lib/siat/risk_adjusted_return.py +0 -1576
- build/lib/build/lib/siat/risk_adjusted_return2.py +0 -1900
- build/lib/build/lib/siat/risk_evaluation.py +0 -2218
- build/lib/build/lib/siat/risk_free_rate.py +0 -351
- build/lib/build/lib/siat/sector_china.py +0 -4140
- build/lib/build/lib/siat/security_price2.py +0 -727
- build/lib/build/lib/siat/security_prices.py +0 -3408
- build/lib/build/lib/siat/security_trend.py +0 -402
- build/lib/build/lib/siat/security_trend2.py +0 -646
- build/lib/build/lib/siat/stock.py +0 -4284
- build/lib/build/lib/siat/stock_advice_linear.py +0 -934
- build/lib/build/lib/siat/stock_base.py +0 -26
- build/lib/build/lib/siat/stock_china.py +0 -2095
- build/lib/build/lib/siat/stock_prices_kneighbors.py +0 -910
- build/lib/build/lib/siat/stock_prices_linear.py +0 -386
- build/lib/build/lib/siat/stock_profile.py +0 -707
- build/lib/build/lib/siat/stock_technical.py +0 -3305
- build/lib/build/lib/siat/stooq.py +0 -74
- build/lib/build/lib/siat/transaction.py +0 -347
- build/lib/build/lib/siat/translate.py +0 -5183
- build/lib/build/lib/siat/valuation.py +0 -1378
- build/lib/build/lib/siat/valuation_china.py +0 -2076
- build/lib/build/lib/siat/var_model_validation.py +0 -444
- build/lib/build/lib/siat/yf_name.py +0 -811
- build/lib/siat/__init__.py +0 -75
- build/lib/siat/allin.py +0 -137
- build/lib/siat/assets_liquidity.py +0 -915
- build/lib/siat/beta_adjustment.py +0 -1058
- build/lib/siat/beta_adjustment_china.py +0 -548
- build/lib/siat/blockchain.py +0 -143
- build/lib/siat/bond.py +0 -2900
- build/lib/siat/bond_base.py +0 -992
- build/lib/siat/bond_china.py +0 -100
- build/lib/siat/bond_zh_sina.py +0 -143
- build/lib/siat/capm_beta.py +0 -783
- build/lib/siat/capm_beta2.py +0 -887
- build/lib/siat/common.py +0 -5360
- build/lib/siat/compare_cross.py +0 -642
- build/lib/siat/copyrights.py +0 -18
- build/lib/siat/cryptocurrency.py +0 -667
- build/lib/siat/economy.py +0 -1471
- build/lib/siat/economy2.py +0 -1853
- build/lib/siat/esg.py +0 -536
- build/lib/siat/event_study.py +0 -815
- build/lib/siat/fama_french.py +0 -1521
- build/lib/siat/fin_stmt2_yahoo.py +0 -982
- build/lib/siat/financial_base.py +0 -1160
- build/lib/siat/financial_statements.py +0 -598
- build/lib/siat/financials.py +0 -2339
- build/lib/siat/financials2.py +0 -1278
- build/lib/siat/financials_china.py +0 -4433
- build/lib/siat/financials_china2.py +0 -2212
- build/lib/siat/fund.py +0 -629
- build/lib/siat/fund_china.py +0 -3307
- build/lib/siat/future_china.py +0 -551
- build/lib/siat/google_authenticator.py +0 -47
- build/lib/siat/grafix.py +0 -3636
- build/lib/siat/holding_risk.py +0 -867
- build/lib/siat/luchy_draw.py +0 -638
- build/lib/siat/market_china.py +0 -1168
- build/lib/siat/markowitz.py +0 -2363
- build/lib/siat/markowitz2.py +0 -3150
- build/lib/siat/markowitz2_20250704.py +0 -2969
- build/lib/siat/markowitz2_20250705.py +0 -3158
- build/lib/siat/markowitz_simple.py +0 -373
- build/lib/siat/ml_cases.py +0 -2291
- build/lib/siat/ml_cases_example.py +0 -60
- build/lib/siat/option_china.py +0 -3069
- build/lib/siat/option_pricing.py +0 -1925
- build/lib/siat/other_indexes.py +0 -409
- build/lib/siat/risk_adjusted_return.py +0 -1576
- build/lib/siat/risk_adjusted_return2.py +0 -1900
- build/lib/siat/risk_evaluation.py +0 -2218
- build/lib/siat/risk_free_rate.py +0 -351
- build/lib/siat/sector_china.py +0 -4140
- build/lib/siat/security_price2.py +0 -727
- build/lib/siat/security_prices.py +0 -3408
- build/lib/siat/security_trend.py +0 -402
- build/lib/siat/security_trend2.py +0 -646
- build/lib/siat/stock.py +0 -4284
- build/lib/siat/stock_advice_linear.py +0 -934
- build/lib/siat/stock_base.py +0 -26
- build/lib/siat/stock_china.py +0 -2095
- build/lib/siat/stock_prices_kneighbors.py +0 -910
- build/lib/siat/stock_prices_linear.py +0 -386
- build/lib/siat/stock_profile.py +0 -707
- build/lib/siat/stock_technical.py +0 -3305
- build/lib/siat/stooq.py +0 -74
- build/lib/siat/transaction.py +0 -347
- build/lib/siat/translate.py +0 -5183
- build/lib/siat/valuation.py +0 -1378
- build/lib/siat/valuation_china.py +0 -2076
- build/lib/siat/var_model_validation.py +0 -444
- build/lib/siat/yf_name.py +0 -811
- siat-3.10.132.dist-info/RECORD +0 -218
build/lib/siat/fama_french.py
DELETED
@@ -1,1521 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
"""
|
3
|
-
版权:王德宏,北京外国语大学国际商学院
|
4
|
-
功能:Fama-French股票市场资产定价因子(中国大陆市场为估计值)
|
5
|
-
版本:2.1,2019-10-10
|
6
|
-
"""
|
7
|
-
#==============================================================================
|
8
|
-
#关闭所有警告
|
9
|
-
import warnings; warnings.filterwarnings('ignore')
|
10
|
-
#==============================================================================
|
11
|
-
from siat.common import *
|
12
|
-
from siat.translate import *
|
13
|
-
from siat.security_prices import *
|
14
|
-
from siat.security_price2 import *
|
15
|
-
#==============================================================================
|
16
|
-
import matplotlib.pyplot as plt
|
17
|
-
|
18
|
-
#处理绘图汉字乱码问题
|
19
|
-
import sys; czxt=sys.platform
|
20
|
-
if czxt in ['win32','win64']:
|
21
|
-
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体
|
22
|
-
mpfrc={'font.family': 'SimHei'}
|
23
|
-
|
24
|
-
if czxt in ['darwin']: #MacOSX
|
25
|
-
plt.rcParams['font.family']= ['Heiti TC']
|
26
|
-
mpfrc={'font.family': 'Heiti TC'}
|
27
|
-
|
28
|
-
if czxt in ['linux']: #website Jupyter
|
29
|
-
plt.rcParams['font.family']= ['Heiti TC']
|
30
|
-
mpfrc={'font.family':'Heiti TC'}
|
31
|
-
|
32
|
-
# 解决保存图像时'-'显示为方块的问题
|
33
|
-
plt.rcParams['axes.unicode_minus'] = False
|
34
|
-
#==============================================================================
|
35
|
-
def convert2freq(df,new_freq='daily'):
|
36
|
-
"""
|
37
|
-
功能:将月度或年度频度的数据均匀化为日度数据
|
38
|
-
"""
|
39
|
-
dfcols=list(df)
|
40
|
-
|
41
|
-
import pandas as pd
|
42
|
-
df['datetmp']=df.index
|
43
|
-
df['Date']=df['datetmp'].apply(lambda x: x.to_timestamp())
|
44
|
-
df.set_index('Date',inplace=True)
|
45
|
-
#df['Date']=df['date']
|
46
|
-
if not isinstance(df.index, pd.DatetimeIndex):
|
47
|
-
df.index = pd.to_datetime(df.index)
|
48
|
-
|
49
|
-
if new_freq == 'daily':
|
50
|
-
df = df.asfreq('D')
|
51
|
-
elif new_freq == 'monthly':
|
52
|
-
df = df.asfreq('M')
|
53
|
-
else:
|
54
|
-
df = df.asfreq('Y')
|
55
|
-
|
56
|
-
for c in dfcols:
|
57
|
-
df[c] = df[c].ffill()
|
58
|
-
df[c] = df[c].bfill()
|
59
|
-
|
60
|
-
df.drop(columns=['datetmp'], inplace=True)
|
61
|
-
|
62
|
-
#df=df[['Date']+dfcols]
|
63
|
-
|
64
|
-
return df
|
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')
|
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
|
-
#==============================================================================
|
170
|
-
if __name__=='__main__':
|
171
|
-
start='2020-1-1'; end='2025-4-30'
|
172
|
-
|
173
|
-
scope='Europe'
|
174
|
-
factor='Mom'
|
175
|
-
freq='yearly'
|
176
|
-
|
177
|
-
scope='US'
|
178
|
-
factor='FF3'
|
179
|
-
freq='yearly'
|
180
|
-
freq='daily'
|
181
|
-
|
182
|
-
ff3d=get_ff_factors(start,end,scope,factor,freq='daily')
|
183
|
-
ff3mth=get_ff_factors(start,end,scope,factor,freq='monthly')
|
184
|
-
ff3y=get_ff_factors(start,end,scope,factor,freq='yearly')
|
185
|
-
|
186
|
-
def get_ff_factors(start,end,scope='US',factor='FF3',freq='monthly',retry=10):
|
187
|
-
"""
|
188
|
-
功能:套壳函数get_ff_factors0,应对freq='daily'经常失败的变通方法
|
189
|
-
"""
|
190
|
-
import pandas as pd
|
191
|
-
startpd=pd.to_datetime(start)
|
192
|
-
endpd=pd.to_datetime(end)
|
193
|
-
|
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
|
-
#多次尝试后仍未成功做变通处理:针对日度数据,使用月/年数据均匀化为日度数据
|
200
|
-
if fff is None:
|
201
|
-
if freq == 'daily':
|
202
|
-
start1=date_adjust(start,adjust=-31)
|
203
|
-
end1=date_adjust(end,adjust=31)
|
204
|
-
fff=get_ff_factors0(start=start1,end=end1,scope=scope,factor=factor,freq='monthly')
|
205
|
-
if not (fff is None):
|
206
|
-
ff_factors0=convert2freq(fff,new_freq='daily')
|
207
|
-
ff_factors=ff_factors0[(ff_factors0.index >=startpd) & (ff_factors0.index <=endpd)]
|
208
|
-
else:
|
209
|
-
ff_factors=fff
|
210
|
-
|
211
|
-
elif freq == 'monthly':
|
212
|
-
start1=date_adjust(start,adjust=-365)
|
213
|
-
end1=date_adjust(end,adjust=365)
|
214
|
-
fff=get_ff_factors0(start=start1,end=end1,scope=scope,factor=factor,freq='yearly')
|
215
|
-
if not (fff is None):
|
216
|
-
ff_factors=convert2freq(fff,new_freq='monthly')
|
217
|
-
else:
|
218
|
-
ff_factors=fff
|
219
|
-
|
220
|
-
else:
|
221
|
-
start1=date_adjust(start,adjust=-365)
|
222
|
-
end1=date_adjust(end,adjust=365)
|
223
|
-
fff=get_ff_factors0(start=start1,end=end1,scope=scope,factor=factor,freq='yearly')
|
224
|
-
ff_factors=fff
|
225
|
-
else:
|
226
|
-
ff_factors=fff
|
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
|
-
|
236
|
-
return ff_factors
|
237
|
-
|
238
|
-
|
239
|
-
def get_ff_factors0(start,end,scope='US',factor='FF3',freq='yearly'):
|
240
|
-
"""
|
241
|
-
【支持的因子种类(factor)】
|
242
|
-
FF3: FF3各个因子
|
243
|
-
FF5: FF5各个因子
|
244
|
-
Mom: 动量因子
|
245
|
-
ST_Rev: 短期反转因子
|
246
|
-
LT_Rev: 长期反转因子
|
247
|
-
|
248
|
-
【支持的国家/地区(scope)】
|
249
|
-
US: 美国
|
250
|
-
North_America:北美(美国+加拿大)
|
251
|
-
Global: 全球
|
252
|
-
Global_ex_US: 全球(除美国外)
|
253
|
-
Asia_Pacific_ex_Japan: 亚太(除日本外),拟作近似中国
|
254
|
-
Japan: 日本
|
255
|
-
Europe: 欧洲
|
256
|
-
|
257
|
-
【支持的取样频率(freq)】
|
258
|
-
yearly: 年
|
259
|
-
monthly: 月
|
260
|
-
weekly: 周(仅支持美国FF3)
|
261
|
-
daily: 日
|
262
|
-
"""
|
263
|
-
|
264
|
-
import pandas as pd
|
265
|
-
s=pd.DataFrame([
|
266
|
-
['US','FF3','monthly','F-F_Research_Data_Factors',0],
|
267
|
-
['US','FF3','yearly','F-F_Research_Data_Factors',1],
|
268
|
-
['US','FF3','weekly','F-F_Research_Data_Factors_weekly',0],
|
269
|
-
['US','FF3','daily','F-F_Research_Data_Factors_daily',0],
|
270
|
-
['US','FF5','monthly','F-F_Research_Data_5_Factors_2x3',0],
|
271
|
-
['US','FF5','yearly','F-F_Research_Data_5_Factors_2x3',1],
|
272
|
-
['US','FF5','daily','F-F_Research_Data_5_Factors_2x3_daily',0],
|
273
|
-
['US','Mom','monthly','F-F_Momentum_Factor',0],
|
274
|
-
['US','Mom','yearly','F-F_Momentum_Factor',1],
|
275
|
-
['US','Mom','daily','F-F_Momentum_Factor_daily',0],
|
276
|
-
['US','ST_Rev','monthly','F-F_ST_Reversal_Factor',0],
|
277
|
-
['US','ST_Rev','yearly','F-F_ST_Reversal_Factor',1],
|
278
|
-
['US','ST_Rev','daily','F-F_ST_Reversal_Factor_daily',0],
|
279
|
-
['US','LT_Rev','monthly','F-F_LT_Reversal_Factor',0],
|
280
|
-
['US','LT_Rev','yearly','F-F_LT_Reversal_Factor',1],
|
281
|
-
['US','LT_Rev','daily','F-F_LT_Reversal_Factor_daily',0], \
|
282
|
-
|
283
|
-
['Global','FF3','monthly','Global_3_Factors',0],
|
284
|
-
['Global','FF3','yearly','Global_3_Factors',1],
|
285
|
-
['Global','FF3','daily','Global_3_Factors_Daily',0],
|
286
|
-
['Global_ex_US','FF3','monthly','Global_ex_US_3_Factors',0],
|
287
|
-
['Global_ex_US','FF3','yearly','Global_ex_US_3_Factors',1],
|
288
|
-
['Global_ex_US','FF3','daily','Global_ex_US_3_Factors_Daily',0],
|
289
|
-
['Europe','FF3','monthly','Europe_3_Factors',0],
|
290
|
-
['Europe','FF3','yearly','Europe_3_Factors',1],
|
291
|
-
['Europe','FF3','daily','Europe_3_Factors_Daily',0],
|
292
|
-
['Japan','FF3','monthly','Japan_3_Factors',0],
|
293
|
-
['Japan','FF3','yearly','Japan_3_Factors',1],
|
294
|
-
['Japan','FF3','daily','Japan_3_Factors_Daily',0],
|
295
|
-
['Asia_Pacific_ex_Japan','FF3','monthly','Asia_Pacific_ex_Japan_3_Factors',0],
|
296
|
-
['Asia_Pacific_ex_Japan','FF3','yearly','Asia_Pacific_ex_Japan_3_Factors',1],
|
297
|
-
['Asia_Pacific_ex_Japan','FF3','daily','Asia_Pacific_ex_Japan_3_Factors_Daily',0],
|
298
|
-
['North_America','FF3','monthly','North_America_3_Factors',0],
|
299
|
-
['North_America','FF3','yearly','North_America_3_Factors',1],
|
300
|
-
['North_America','FF3','daily','North_America_3_Factors_Daily',0], \
|
301
|
-
|
302
|
-
['Global','FF5','monthly','Global_5_Factors',0],
|
303
|
-
['Global','FF5','yearly','Global_5_Factors',1],
|
304
|
-
['Global','FF5','daily','Global_5_Factors_Daily',0],
|
305
|
-
['Global_ex_US','FF5','monthly','Global_ex_US_5_Factors',0],
|
306
|
-
['Global_ex_US','FF5','yearly','Global_ex_US_5_Factors',1],
|
307
|
-
['Global_ex_US','FF5','daily','Global_ex_US_5_Factors_Daily',0],
|
308
|
-
['Europe','FF5','monthly','Europe_5_Factors',0],
|
309
|
-
['Europe','FF5','yearly','Europe_5_Factors',1],
|
310
|
-
['Europe','FF5','daily','Europe_5_Factors_Daily',0],
|
311
|
-
['Japan','FF5','monthly','Japan_5_Factors',0],
|
312
|
-
['Japan','FF5','yearly','Japan_5_Factors',1],
|
313
|
-
['Japan','FF5','daily','Japan_5_Factors_Daily',0],
|
314
|
-
['Asia_Pacific_ex_Japan','FF5','monthly','Asia_Pacific_ex_Japan_5_Factors',0],
|
315
|
-
['Asia_Pacific_ex_Japan','FF5','yearly','Asia_Pacific_ex_Japan_5_Factors',1],
|
316
|
-
['Asia_Pacific_ex_Japan','FF5','daily','Asia_Pacific_ex_Japan_5_Factors_Daily',0],
|
317
|
-
['North_America','FF5','monthly','North_America_5_Factors',0],
|
318
|
-
['North_America','FF5','yearly','North_America_5_Factors',1],
|
319
|
-
['North_America','FF5','daily','North_America_5_Factors_Daily',0], \
|
320
|
-
|
321
|
-
['Global','Mom','monthly','Global_Mom_Factor',0],
|
322
|
-
['Global','Mom','yearly','Global_Mom_Factor',1],
|
323
|
-
['Global','Mom','daily','Global_Mom_Factor_Daily',0],
|
324
|
-
['Global_ex_US','Mom','monthly','Global_ex_US_Mom_Factor',0],
|
325
|
-
['Global_ex_US','Mom','yearly','Global_ex_US_Mom_Factor',1],
|
326
|
-
['Global_ex_US','Mom','daily','Global_ex_US_Mom_Factor_Daily',0],
|
327
|
-
['Europe','Mom','monthly','Europe_Mom_Factor',0],
|
328
|
-
['Europe','Mom','yearly','Europe_Mom_Factor',1],
|
329
|
-
['Europe','Mom','daily','Europe_Mom_Factor_Daily',0],
|
330
|
-
['Japan','Mom','monthly','Japan_Mom_Factor',0],
|
331
|
-
['Japan','Mom','yearly','Japan_Mom_Factor',1],
|
332
|
-
['Japan','Mom','daily','Japan_Mom_Factor_Daily',0],
|
333
|
-
['Asia_Pacific_ex_Japan','Mom','monthly','Asia_Pacific_ex_Japan_MOM_Factor',0],
|
334
|
-
['Asia_Pacific_ex_Japan','Mom','yearly','Asia_Pacific_ex_Japan_MOM_Factor',1],
|
335
|
-
['Asia_Pacific_ex_Japan','Mom','daily','Asia_Pacific_ex_Japan_MOM_Factor_Daily',0],
|
336
|
-
['North_America','Mom','monthly','North_America_Mom_Factor',0],
|
337
|
-
['North_America','Mom','yearly','North_America_Mom_Factor',1],
|
338
|
-
['North_America','Mom','daily','North_America_Mom_Factor_Daily',0]
|
339
|
-
], columns=['scope','factor','freq','symbol','seq'])
|
340
|
-
|
341
|
-
#数据源
|
342
|
-
source='famafrench'
|
343
|
-
if scope in ["China","HK","TW"]:
|
344
|
-
scope="Asia_Pacific_ex_Japan"
|
345
|
-
|
346
|
-
#匹配:scope+factor+freq
|
347
|
-
ss=s[s['scope'].isin([scope]) & s['factor'].isin([factor]) \
|
348
|
-
& s['freq'].isin([freq])]
|
349
|
-
#如果未找到匹配的模式,显示信息后返回
|
350
|
-
if len(ss)==0:
|
351
|
-
print(" #Warning(get_ff_factors): no data available for",scope,factor,freq)
|
352
|
-
print(" If all parameters are correct, try earlier dates than",start)
|
353
|
-
return None
|
354
|
-
|
355
|
-
#重新索引,第1行的索引编号为0
|
356
|
-
sss=ss.reset_index(drop=True)
|
357
|
-
#取出对应的symbol
|
358
|
-
symbol=sss.iloc[0]['symbol']
|
359
|
-
#取出对应的月(0)/年(1)编号
|
360
|
-
seq=sss.iloc[0]['seq']
|
361
|
-
|
362
|
-
#抓取数据
|
363
|
-
import pandas_datareader.data as web
|
364
|
-
try:
|
365
|
-
ds = web.DataReader(symbol, source, start, end)
|
366
|
-
except:
|
367
|
-
print(f" #Warning(get_ff_factors): time out to get {freq} data, working around ...")
|
368
|
-
return None
|
369
|
-
|
370
|
-
#提取希望的资产定价因子
|
371
|
-
try:
|
372
|
-
factor_df=ds[seq]
|
373
|
-
except:
|
374
|
-
factor_df=extract_DESCR(ds)
|
375
|
-
|
376
|
-
if len(factor_df)==0 or factor_df is None:
|
377
|
-
print(" #Warning(get_ff_factors): no data available for",start,end,scope,factor,freq)
|
378
|
-
#print("Tracing process:"s,ss,sss,symbol,seq,ds)
|
379
|
-
print(" If all parameters are correct, try earlier dates than",start)
|
380
|
-
return None
|
381
|
-
|
382
|
-
return factor_df
|
383
|
-
|
384
|
-
if __name__=='__main__':
|
385
|
-
ff3_factors_us=get_ff_factors("01/01/2009","07/18/2019",scope='US', \
|
386
|
-
factor='FF3',freq='yearly')
|
387
|
-
|
388
|
-
ff3_factors_jp=get_ff_factors("01/01/2009","07/18/2019",scope='Japan', \
|
389
|
-
factor='FF3',freq='yearly')
|
390
|
-
|
391
|
-
ff3_factors_eu=get_ff_factors("2009-01-01","2019-07-18",scope='Europe', \
|
392
|
-
factor='FF3',freq='yearly')
|
393
|
-
|
394
|
-
|
395
|
-
#==============================================================================
|
396
|
-
def get_rf(start,end,scope='US',freq='daily'):
|
397
|
-
"""
|
398
|
-
功能:按照市场获得无风险收益率,百分比表示
|
399
|
-
输入:开始日期,解释日期,市场,频率
|
400
|
-
|
401
|
-
注意:这里的rf利率指的是freq利率(日利率、周利率、月利率或年利率),而不都是年化利率!
|
402
|
-
"""
|
403
|
-
|
404
|
-
try:
|
405
|
-
rf_df=get_ff_factors(start,end,scope,'FF3',freq)
|
406
|
-
except:
|
407
|
-
print(" #Error(get_rf): rf server did not respond.")
|
408
|
-
return None
|
409
|
-
if rf_df is None:
|
410
|
-
#print(" #Warning(get_rf): fetching risk-free return failed")
|
411
|
-
return None
|
412
|
-
|
413
|
-
#强制转换索引格式,彻底消除后续并表的潜在隐患
|
414
|
-
rf_df['ffdate']=rf_df.index.astype('str')
|
415
|
-
import pandas as pd
|
416
|
-
rf_df['ffdate']=pd.to_datetime(rf_df['ffdate'])
|
417
|
-
rf_df.set_index(['ffdate'],inplace=True)
|
418
|
-
|
419
|
-
return rf_df
|
420
|
-
|
421
|
-
#==============================================================================
|
422
|
-
if __name__=='__main__':
|
423
|
-
mktidx='000001.SS'
|
424
|
-
start='2021-10-1'
|
425
|
-
end='2021-11-30'
|
426
|
-
rate_period='1Y'
|
427
|
-
rate_type='shibor'
|
428
|
-
|
429
|
-
def get_mkt_rf_daily_china(mktidx,start,end,rate_period='1Y',rate_type='shibor',RF=True):
|
430
|
-
"""
|
431
|
-
功能:为了某些特殊需要(RAR, Markowitz),构造中国内地的日频Mkt-RF和RF数据表,以百分比%表示
|
432
|
-
RF=True为抓取无风险利率,否则不使用无风险利率。
|
433
|
-
"""
|
434
|
-
#抓取日指数价格
|
435
|
-
from siat.security_prices import get_prices
|
436
|
-
prices=get_prices(mktidx,start,end)
|
437
|
-
#计算日收益率,表示为百分比
|
438
|
-
import pandas as pd
|
439
|
-
mkt_pf=pd.DataFrame(prices['Close'].pct_change())
|
440
|
-
mkt_pf=mkt_pf.dropna()
|
441
|
-
|
442
|
-
if RF:
|
443
|
-
#抓取无风险利率
|
444
|
-
rf_pf=rf_daily_china(start,end,rate_period,rate_type)
|
445
|
-
|
446
|
-
#合成
|
447
|
-
if not (rf_pf is None):
|
448
|
-
df=pd.merge(mkt_pf,rf_pf,how='inner',left_index=True,right_index=True)
|
449
|
-
else:
|
450
|
-
df=mkt_pf
|
451
|
-
df['rf_daily']=0
|
452
|
-
else:
|
453
|
-
df=mkt_pf
|
454
|
-
df['rf_daily']=0
|
455
|
-
|
456
|
-
df['Mkt-RF']=(df['Close']-df['rf_daily'])*100
|
457
|
-
df['RF']=df['rf_daily']*100
|
458
|
-
|
459
|
-
rf_df=df[['Mkt-RF','RF']]
|
460
|
-
|
461
|
-
return rf_df
|
462
|
-
|
463
|
-
if __name__=='__main__':
|
464
|
-
get_mkt_rf_daily_china('000001.SS','2021-1-1','2021-11-30','1Y','shibor')
|
465
|
-
get_mkt_rf_daily_china('000001.SS','2021-1-1','2021-11-30','3M','shibor')
|
466
|
-
get_mkt_rf_daily_china('000001.SS','2021-1-1','2021-11-30','1Y','treasury')
|
467
|
-
#==============================================================================
|
468
|
-
if __name__=='__main__':
|
469
|
-
start='2021-1-1'
|
470
|
-
end='2021-11-30'
|
471
|
-
scope='US'
|
472
|
-
rate_period='1Y'
|
473
|
-
rate_type='shibor'
|
474
|
-
|
475
|
-
rfd=get_rf_daily(start,end)
|
476
|
-
|
477
|
-
def get_rf_daily(start,end,scope='US',rate_period='1Y',rate_type='shibor'):
|
478
|
-
"""
|
479
|
-
功能:获得指定期间的日无风险利率,近期缺失部分使用最近的日期填补
|
480
|
-
"""
|
481
|
-
print(" Searching risk-free interest rates in",scope,'\b, which may take time ...')
|
482
|
-
|
483
|
-
if scope=='China':
|
484
|
-
rf_china=rf_daily_china(start,end,rate_period,rate_type)
|
485
|
-
rf_china['RF']=rf_china['rf_daily']
|
486
|
-
rf_df=rf_china[['date','RF']]
|
487
|
-
else:
|
488
|
-
rf_fred=get_rf(start,end,scope=scope,freq='daily')
|
489
|
-
if rf_fred is None:
|
490
|
-
print(" Recovering risk-free interest rates in FRED for",scope,'...')
|
491
|
-
start1=date_adjust(start, adjust=-60)
|
492
|
-
rf_fred=get_rf(start1,end,scope=scope,freq='daily')
|
493
|
-
if rf_fred is None:
|
494
|
-
return None
|
495
|
-
|
496
|
-
#使用最近日期的利率填补空缺的日期
|
497
|
-
rf_fred['date_dt']=rf_fred.index.date
|
498
|
-
rf_fred['date']=rf_fred['date_dt'].apply(lambda x: str(x))
|
499
|
-
rf_df0=rf_fred[['date','RF']]
|
500
|
-
latest_date=rf_df0['date'][-1:].values[0]
|
501
|
-
lastest_rate=rf_df0['RF'][-1:].values[0]
|
502
|
-
|
503
|
-
collist=list(rf_df0)
|
504
|
-
df_temp = pd.DataFrame(columns=collist)
|
505
|
-
end_dt=pd.to_datetime(end)
|
506
|
-
for i in range(100):
|
507
|
-
date1=date_adjust(latest_date,adjust=i+1)
|
508
|
-
date1_dt=pd.to_datetime(date1)
|
509
|
-
if date1_dt <= end_dt:
|
510
|
-
try:
|
511
|
-
df_temp=df_temp.append({'date':date1,'RF':lastest_rate},ignore_index=True)
|
512
|
-
except:
|
513
|
-
df_temp=df_temp._append({'date':date1,'RF':lastest_rate},ignore_index=True)
|
514
|
-
else:
|
515
|
-
break
|
516
|
-
|
517
|
-
df_temp['Date']=pd.to_datetime(df_temp['date'])
|
518
|
-
df_temp.set_index(['Date'],inplace=True)
|
519
|
-
|
520
|
-
try:
|
521
|
-
rf_df=rf_df0.append(df_temp)
|
522
|
-
except:
|
523
|
-
rf_df=rf_df0._append(df_temp)
|
524
|
-
rf_df.sort_values(by=['date'],ascending=[True],inplace=True)
|
525
|
-
|
526
|
-
rf_df['rf_daily']=rf_df['RF']/100
|
527
|
-
|
528
|
-
print(" Successfully retrieved",len(rf_df),"risk-free interest rates in",scope)
|
529
|
-
|
530
|
-
return rf_df
|
531
|
-
|
532
|
-
if __name__=='__main__':
|
533
|
-
rf=get_rf_daily(start,end,scope='US',rate_period='1Y',rate_type='shibor')
|
534
|
-
#==============================================================================
|
535
|
-
def extract_DESCR(ds):
|
536
|
-
"""
|
537
|
-
归纳:从字典的DESCR中提取年度因子信息 ,用于seq缺失1但误放置在DESCR中的情形
|
538
|
-
"""
|
539
|
-
try:
|
540
|
-
descr_str=factor_df=ds['DESCR']
|
541
|
-
except:
|
542
|
-
return None
|
543
|
-
|
544
|
-
wml_pos=descr_str.find("WML")
|
545
|
-
nn_pos=descr_str.find("\n\n ")
|
546
|
-
wml_post=descr_str[wml_pos+4:nn_pos]
|
547
|
-
wml_post1=wml_post.replace(' ,',',')
|
548
|
-
wml_post2=wml_post1.replace(' ,',',')
|
549
|
-
wml_post3=wml_post2+' '
|
550
|
-
|
551
|
-
#正则表达式提取配对
|
552
|
-
import re
|
553
|
-
wml_post_list=re.findall(r"(.+?),(.+?) ", wml_post3)
|
554
|
-
|
555
|
-
#将提取的配对串列表转换为pandas
|
556
|
-
import pandas as pd
|
557
|
-
df = pd.DataFrame(columns=('Date', 'WML'))
|
558
|
-
for i in wml_post_list:
|
559
|
-
#print(i[0],i[1])
|
560
|
-
s = pd.Series({'Date':pd.Period(i[0],freq='A-DEC'), 'WML':float(i[1])})
|
561
|
-
# 这里 Series 必须是 dict-like 类型
|
562
|
-
try:
|
563
|
-
df = df.append(s, ignore_index=True)
|
564
|
-
except:
|
565
|
-
df = df._append(s, ignore_index=True)
|
566
|
-
# 这里必须选择ignore_index=True 或者给 Series一个index值
|
567
|
-
df.set_index('Date',drop=True, inplace=True)
|
568
|
-
|
569
|
-
return df
|
570
|
-
|
571
|
-
|
572
|
-
#==============================================================================
|
573
|
-
|
574
|
-
def get_ff3_factors(start,end,scope='US',freq='yearly'):
|
575
|
-
"""
|
576
|
-
功能:抓取Fama-French三因子模型的三个市场因子
|
577
|
-
1)市场风险溢价(Rmarket-Rf,收益率风险溢价)
|
578
|
-
2)小市值风险溢价(SMB,规模因子,即小市值股票对比大市值股票的超额收益率)
|
579
|
-
3)高市净率风险溢价(HML,价值因子,高溢价股票对比低溢价股票的超额收益率)
|
580
|
-
|
581
|
-
输入参数:
|
582
|
-
start/end:开始/结束日期,格式为YYYY-MM-DD或MM/DD/YYYY
|
583
|
-
scope:地区(美国,日本,欧洲,全球,除美国外的全球,除日本外的亚太)
|
584
|
-
freq:采样周期(日、周、月、年,其中周仅支持美国市场)
|
585
|
-
输出:按照采样周期排列的指定地区的FF3因子(pandas格式)
|
586
|
-
"""
|
587
|
-
|
588
|
-
#仅为测试用
|
589
|
-
#start="2018-01-01"
|
590
|
-
#end="2018-12-31"
|
591
|
-
#scope='US'
|
592
|
-
#freq='monthly'
|
593
|
-
|
594
|
-
#抓取FF3因子
|
595
|
-
factor='FF3'
|
596
|
-
ff3_factors=get_ff_factors(start,end,scope,factor,freq)
|
597
|
-
|
598
|
-
return ff3_factors
|
599
|
-
|
600
|
-
if __name__=='__main__':
|
601
|
-
factors=get_ff3_factors("2018-01-01","2018-12-31",scope='US', \
|
602
|
-
freq='monthly')
|
603
|
-
print("\n",factors)
|
604
|
-
|
605
|
-
#==============================================================================
|
606
|
-
def test_ff3_factors():
|
607
|
-
"""
|
608
|
-
功能:交互式测试资产定价模型FF3的因子
|
609
|
-
输入:用户输入
|
610
|
-
显示:各个因子
|
611
|
-
返回值:无
|
612
|
-
"""
|
613
|
-
|
614
|
-
import easygui as g
|
615
|
-
|
616
|
-
title="Test the Factors of Fama-French 3-factor Model"
|
617
|
-
msg="Please fill in the information below"
|
618
|
-
fldnames=["Start date (YYYY-MM-DD)","End date (YYYY-MM-DD)", \
|
619
|
-
"Scope (US, China, Japan, Europe)", \
|
620
|
-
"Frequency (yearly, monthly, daily)"]
|
621
|
-
fldvalues=[]
|
622
|
-
values=("2018-01-01","2019-04-30","US","monthly")
|
623
|
-
fldvalues=g.multenterbox(msg,title=title,fields=fldnames,values=values)
|
624
|
-
"""
|
625
|
-
如果用户输入的值比选项少的话,则返回列表中的值用空字符串填充用户为输入的选项。
|
626
|
-
如果用户输入的值比选项多的话,则返回的列表中的值将截断为选项的数量。
|
627
|
-
如果用户取消操作,则返回域中的列表的值或者None值
|
628
|
-
"""
|
629
|
-
|
630
|
-
if fldvalues:
|
631
|
-
start=fldvalues[0]
|
632
|
-
end=fldvalues[1]
|
633
|
-
scope=fldvalues[2]
|
634
|
-
freq=fldvalues[3]
|
635
|
-
|
636
|
-
ff_factors=get_ff3_factors(start,end,scope,freq)
|
637
|
-
if ff_factors is None:
|
638
|
-
g.msgbox(msg="Sorry, no factor data available under the condition.", \
|
639
|
-
title=title)
|
640
|
-
else:
|
641
|
-
g.msgbox(msg=ff_factors,title=title)
|
642
|
-
else:
|
643
|
-
g.msgbox(msg="Sorry, user cancelled the operation, no data retrieved.", \
|
644
|
-
title=title)
|
645
|
-
|
646
|
-
return
|
647
|
-
|
648
|
-
if __name__=='__main__':
|
649
|
-
test_ff3_factors()
|
650
|
-
|
651
|
-
#==============================================================================
|
652
|
-
def draw1_ff_factors(model,scope,factors,factor_type):
|
653
|
-
"""
|
654
|
-
功能:绘制单曲线的FF因子变化图
|
655
|
-
输入参数:
|
656
|
-
model: 模型类型, 任意字符串(例如FF3, FFC4, FF5)
|
657
|
-
scope: 市场范围, 任意字符串(例如US, China, Europe)
|
658
|
-
factors:包括FF各个因子的数据框
|
659
|
-
factor_type:因子类型,严格限于RF/Mkt-RF/SMB/HML/MOM/RMW/CMA
|
660
|
-
输出:图形
|
661
|
-
返回值:无
|
662
|
-
"""
|
663
|
-
#仅用作测试,完成后应注释掉
|
664
|
-
#model="Fama-French 3-factor Model"
|
665
|
-
#scope="US"
|
666
|
-
#factor_type='ALL'
|
667
|
-
|
668
|
-
if factor_type in ['Mkt-RF']:
|
669
|
-
#绘制市场收益率风险溢价变化图
|
670
|
-
"""
|
671
|
-
线段的颜色:c='r',红色
|
672
|
-
线型:ls='-',实线;':'则为虚线
|
673
|
-
线段的粗细:lw=3
|
674
|
-
节点形状:marker='o',圆形
|
675
|
-
节点大小:ms=10
|
676
|
-
节点颜色:mfc='y',黄色
|
677
|
-
"""
|
678
|
-
try:
|
679
|
-
factors.plot(y=['Mkt-RF'], \
|
680
|
-
c='r',ls='-',lw=3,marker='o',ms=10,mfc='y')
|
681
|
-
except:
|
682
|
-
print(" #Warning(draw1_ff_factors): no MKT factor data available")
|
683
|
-
return
|
684
|
-
plt.axhline(y=0.0,color='b',linestyle=':') #画0点虚线X轴做基准
|
685
|
-
title1="\n"+model+": "+scope+", "+" Mkt-RF Factor"
|
686
|
-
plt.title(title1,fontsize=12,fontweight='bold')
|
687
|
-
plt.ylabel('Mkt-RF',fontsize=12,fontweight='bold')
|
688
|
-
plt.xticks(factors.index,fontsize=8,rotation=30)
|
689
|
-
plt.legend(loc='best')
|
690
|
-
|
691
|
-
plt.gca().set_facecolor('whitesmoke')
|
692
|
-
plt.show()
|
693
|
-
|
694
|
-
if factor_type in ['SMB']:
|
695
|
-
#绘制规模因子变化图
|
696
|
-
try:
|
697
|
-
factors.plot(y=['SMB'], \
|
698
|
-
c='b',ls='-',lw=3,marker='o',ms=10,mfc='r')
|
699
|
-
except:
|
700
|
-
print(" #Warning(draw1_ff_factors): no SMB factor data available")
|
701
|
-
return
|
702
|
-
plt.axhline(y=0.0,color='b',linestyle=':')
|
703
|
-
title1="\n"+model+": "+scope+", "+"SMB Factor"
|
704
|
-
plt.title(title1,fontsize=12,fontweight='bold')
|
705
|
-
plt.ylabel('SMB',fontsize=12,fontweight='bold')
|
706
|
-
plt.xticks(factors.index,fontsize=8,rotation=30)
|
707
|
-
plt.legend(loc='best')
|
708
|
-
|
709
|
-
plt.gca().set_facecolor('whitesmoke')
|
710
|
-
plt.show()
|
711
|
-
|
712
|
-
if factor_type in ['HML']:
|
713
|
-
#绘制价值因子变化图
|
714
|
-
try:
|
715
|
-
factors.plot(y=['HML'], \
|
716
|
-
c='c',ls='-',lw=3,marker='o',ms=10,mfc='r')
|
717
|
-
except:
|
718
|
-
print(" #Warning(draw1_ff_factors): no HML factor data available")
|
719
|
-
return
|
720
|
-
plt.axhline(y=0.0,color='b',linestyle=':') #画一条0点的虚线做基准参考
|
721
|
-
title1="\n"+model+": "+scope+", "+"HML Factor"
|
722
|
-
plt.title(title1,fontsize=12,fontweight='bold')
|
723
|
-
plt.ylabel('HML',fontsize=12,fontweight='bold')
|
724
|
-
plt.xticks(factors.index,fontsize=8,rotation=30)
|
725
|
-
plt.legend(loc='best')
|
726
|
-
|
727
|
-
plt.gca().set_facecolor('whitesmoke')
|
728
|
-
plt.show()
|
729
|
-
|
730
|
-
if factor_type in ['RF']:
|
731
|
-
#绘制无风险收益率变化图
|
732
|
-
try:
|
733
|
-
factors.plot(y=['RF'], \
|
734
|
-
c='g',ls='-',lw=3,marker='*',ms=14,mfc='r')
|
735
|
-
except:
|
736
|
-
print(" #Warning(draw1_ff_factors): no RF data available")
|
737
|
-
return
|
738
|
-
title1="\n"+model+": "+scope+", "+"HML Factor"
|
739
|
-
plt.title(title1,fontsize=12,fontweight='bold')
|
740
|
-
plt.ylabel('RF %',fontsize=12,fontweight='bold')
|
741
|
-
plt.xticks(factors.index,fontsize=8,rotation=30)
|
742
|
-
plt.legend(loc='best')
|
743
|
-
|
744
|
-
plt.gca().set_facecolor('whitesmoke')
|
745
|
-
plt.show()
|
746
|
-
|
747
|
-
if factor_type in ['MOM']:
|
748
|
-
#绘制动量因子变化图
|
749
|
-
try:
|
750
|
-
factors.plot(y=['MOM'], \
|
751
|
-
c='deeppink',ls='-',lw=3,marker='*',ms=15,mfc='y')
|
752
|
-
except:
|
753
|
-
print(" #Warning(draw1_ff_factors): no MOM factor data available")
|
754
|
-
return
|
755
|
-
plt.axhline(y=0.0,color='b',linestyle=':')
|
756
|
-
title1="\n"+model+": "+scope+", "+"MOM Factor"
|
757
|
-
plt.title(title1,fontsize=12,fontweight='bold')
|
758
|
-
plt.ylabel('Mom',fontsize=12,fontweight='bold')
|
759
|
-
plt.xticks(factors.index,fontsize=8)
|
760
|
-
plt.legend(loc='best')
|
761
|
-
|
762
|
-
plt.gca().set_facecolor('whitesmoke')
|
763
|
-
plt.show()
|
764
|
-
|
765
|
-
|
766
|
-
if factor_type in ['RMW']:
|
767
|
-
#绘制盈利因子变化图
|
768
|
-
try:
|
769
|
-
factors.plot(y=['RMW'], \
|
770
|
-
c='blue',ls='-',lw=3,marker='*',ms=15,mfc='r')
|
771
|
-
except:
|
772
|
-
print(" #Warning(draw1_ff_factors): no RMW factor data available")
|
773
|
-
return
|
774
|
-
plt.axhline(y=0.0,color='b',linestyle=':')
|
775
|
-
title1="\n"+model+": "+scope+", "+"RMW Factor"
|
776
|
-
plt.title(title1,fontsize=12,fontweight='bold')
|
777
|
-
plt.ylabel('RMW',fontsize=12,fontweight='bold')
|
778
|
-
plt.xticks(factors.index,fontsize=8)
|
779
|
-
plt.legend(loc='best')
|
780
|
-
|
781
|
-
plt.gca().set_facecolor('whitesmoke')
|
782
|
-
plt.show()
|
783
|
-
|
784
|
-
if factor_type in ['CMA']:
|
785
|
-
#绘制投资因子变化图
|
786
|
-
try:
|
787
|
-
factors.plot(y=['CMA'], \
|
788
|
-
c='black',ls='-',lw=3,marker='*',ms=15,mfc='r')
|
789
|
-
except:
|
790
|
-
print(" #Warning(draw1_ff_factors): no CMA factor data available")
|
791
|
-
return
|
792
|
-
plt.axhline(y=0.0,color='b',linestyle=':')
|
793
|
-
title1="\n"+model+": "+scope+", "+"CMA Factor"
|
794
|
-
plt.title(title1,fontsize=12,fontweight='bold')
|
795
|
-
plt.ylabel('CMA',fontsize=12,fontweight='bold')
|
796
|
-
plt.xticks(factors.index,fontsize=8)
|
797
|
-
plt.legend(loc='best')
|
798
|
-
|
799
|
-
plt.gca().set_facecolor('whitesmoke')
|
800
|
-
plt.show()
|
801
|
-
|
802
|
-
return
|
803
|
-
|
804
|
-
|
805
|
-
if __name__=='__main__':
|
806
|
-
factors1=get_ff3_factors("2018-01-01","2018-12-31",scope='US', \
|
807
|
-
freq='monthly')
|
808
|
-
factors2=get_ff3_factors("2018-01-01","2018-12-31",scope='China', \
|
809
|
-
freq='monthly')
|
810
|
-
draw1_ff_factors("FF3 model","US",factors1,"SMB")
|
811
|
-
draw1_ff_factors("FF3 model","Japan",factors2,"SMB")
|
812
|
-
|
813
|
-
#==============================================================================
|
814
|
-
def draw2_ff_factors(model,scope1,scope2,factors1,factors2,factor_type):
|
815
|
-
"""
|
816
|
-
功能:绘制双曲线的FF因子变化图
|
817
|
-
输入参数:
|
818
|
-
model: 模型类型, 任意字符串(例如FF3, FFC4, FF5)
|
819
|
-
scope: 市场范围, 任意字符串(例如US, China, Europe)
|
820
|
-
factors1/2:用于对比的包括FF各个因子的两个数据框
|
821
|
-
factor_type:因子类型,严格限于RF/MKT/SMB/HML/MOM/RMW/CMA
|
822
|
-
输出:图形
|
823
|
-
返回值:无
|
824
|
-
"""
|
825
|
-
#仅用作测试,完成后应注释掉
|
826
|
-
#model="FF3 Model"
|
827
|
-
#scope1="US"
|
828
|
-
#scope2="Europe"
|
829
|
-
#factor_type='Mkt-RF'
|
830
|
-
|
831
|
-
#转换索引类型为DatetimeIndex,便于后续处理
|
832
|
-
import pandas as pd
|
833
|
-
factors1['Date']=factors1.index.strftime("%Y-%m-%d")
|
834
|
-
factors1['Date']=pd.to_datetime(factors1['Date'])
|
835
|
-
factors1.set_index('Date',inplace=True)
|
836
|
-
|
837
|
-
factors2['Date']=factors2.index.strftime("%Y-%m-%d")
|
838
|
-
factors2['Date']=pd.to_datetime(factors2['Date'])
|
839
|
-
factors2.set_index('Date',inplace=True)
|
840
|
-
|
841
|
-
try:
|
842
|
-
plt.plot(factors1[factor_type],label=scope1,marker='o')
|
843
|
-
plt.plot(factors2[factor_type],label=scope2,marker='*')
|
844
|
-
except:
|
845
|
-
print(" #Warning(draw2_ff_factors): no available data for factor",factor_type)
|
846
|
-
return
|
847
|
-
plt.axhline(y=0.0,color='b',linestyle=':')
|
848
|
-
title1="\n"+model+": "+scope1+" vs. "+scope2+", "+" Factor "+factor_type
|
849
|
-
plt.title(title1,fontsize=12,fontweight='bold')
|
850
|
-
plt.ylabel(factor_type,fontsize=12,fontweight='bold')
|
851
|
-
plt.legend(loc='best')
|
852
|
-
|
853
|
-
plt.gca().set_facecolor('whitesmoke')
|
854
|
-
plt.show()
|
855
|
-
|
856
|
-
return
|
857
|
-
|
858
|
-
if __name__=='__main__':
|
859
|
-
factors1=get_ff3_factors("2009-01-01","2018-12-31",scope='US', \
|
860
|
-
freq='yearly')
|
861
|
-
factors2=get_ff3_factors("2009-01-01","2018-12-31",scope='Europe', \
|
862
|
-
freq='yearly')
|
863
|
-
draw2_ff_factors("FF3 model","US","Europe",factors1,factors2,"Mkt-RF")
|
864
|
-
draw2_ff_factors("FF3 model","US","Europe",factors1,factors2,"SMB")
|
865
|
-
draw2_ff_factors("FF3 model","US","Europe",factors1,factors2,"HML")
|
866
|
-
|
867
|
-
#==============================================================================
|
868
|
-
if __name__=='__main__':
|
869
|
-
start='2016-1-1'
|
870
|
-
end='2021-1-1'
|
871
|
-
scope='Europe'
|
872
|
-
freq='yearly'
|
873
|
-
|
874
|
-
def get_ffc4_factors(start,end,scope='US',freq='yearly'):
|
875
|
-
"""
|
876
|
-
功能:抓取Fama-French-Carhart四因子模型的四个市场因子
|
877
|
-
1)市场风险溢价(Rmarket-Rf,收益率风险溢价)
|
878
|
-
2)小市值风险溢价(SMB,规模因子,即小市值股票对比大市值股票的超额收益率)
|
879
|
-
3)高市净率风险溢价(HML,价值因子,高溢价股票对比低溢价股票的超额收益率)
|
880
|
-
4)交易动量因子(MOM,市场交易中资本利差最高的那部分股票被称为赢家winner,
|
881
|
-
而最低的那部分股票被称为输家loser。短期内,赢家具有保持作为赢家的趋势,
|
882
|
-
输家具有继续作为输家的趋势。这种现象称为交易惯性,惯性即动量。动量因子
|
883
|
-
就是高收益率股票对比低收益率股票的超额收益率)
|
884
|
-
|
885
|
-
输入参数:
|
886
|
-
start/end:开始/结束日期,格式为YYYY-MM-DD或MM/DD/YYYY
|
887
|
-
scope:地区(美国,日本,欧洲,全球,除美国外的全球,除日本外的亚太)
|
888
|
-
freq:采样周期(日、周、月、年,其中周仅支持美国市场)
|
889
|
-
输出:按照采样周期排列的指定地区的FFC4因子(pandas格式)
|
890
|
-
"""
|
891
|
-
|
892
|
-
#仅为测试用
|
893
|
-
#start="2018-01-01"
|
894
|
-
#end="2018-12-31"
|
895
|
-
#scope='US'
|
896
|
-
#freq='monthly'
|
897
|
-
|
898
|
-
#抓取FF3因子
|
899
|
-
factor='FF3'
|
900
|
-
ff3=get_ff_factors(start,end,scope,factor,freq)
|
901
|
-
|
902
|
-
#抓取Mom因子
|
903
|
-
factor='Mom'
|
904
|
-
try:
|
905
|
-
Mom=get_ff_factors(start,end,scope,factor,freq)
|
906
|
-
except:
|
907
|
-
print(" #Error(get_ffc4_factors): connection to data source failed:-( Try later!")
|
908
|
-
return None
|
909
|
-
|
910
|
-
if (ff3 is None) or (Mom is None):
|
911
|
-
return None
|
912
|
-
|
913
|
-
#将动量数据列名一致化
|
914
|
-
if scope == 'US':
|
915
|
-
Mom=Mom.rename(columns={'Mom ':'MOM'}) #针对US数据
|
916
|
-
else:
|
917
|
-
Mom=Mom.rename(columns={'WML':'MOM'}) #针对非US数据
|
918
|
-
|
919
|
-
#合成FF3+Mom因子
|
920
|
-
import pandas as pd
|
921
|
-
#每日因子的日期类型需要转换,不然在非US时合成匹配不成功
|
922
|
-
if freq=='daily':
|
923
|
-
ff3['date']=ff3.index
|
924
|
-
ff3['date']=pd.to_datetime(ff3['date'].astype('str'))
|
925
|
-
ff3.set_index('date',drop=True, inplace=True)
|
926
|
-
|
927
|
-
Mom['date']=Mom.index
|
928
|
-
Mom['date']=pd.to_datetime(Mom['date'].astype('str'))
|
929
|
-
Mom.set_index('date',drop=True, inplace=True)
|
930
|
-
|
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')
|
933
|
-
#del ffc4_factors['date']
|
934
|
-
|
935
|
-
return ffc4_factors
|
936
|
-
|
937
|
-
|
938
|
-
if __name__=='__main__':
|
939
|
-
start="2018-01-01"
|
940
|
-
end="2018-12-31"
|
941
|
-
scope='Europe'
|
942
|
-
freq="monthly"
|
943
|
-
factors1=get_ffc4_factors("2009-01-01","2018-12-31",scope='US', \
|
944
|
-
freq='yearly')
|
945
|
-
factors2=get_ffc4_factors("2009-01-01","2018-12-31",scope='Japan', \
|
946
|
-
freq='yearly')
|
947
|
-
draw1_ff_factors("FFC4 model","US",factors1,"MOM")
|
948
|
-
|
949
|
-
|
950
|
-
#==============================================================================
|
951
|
-
def test_ffc4_factors():
|
952
|
-
"""
|
953
|
-
功能:交互式测试资产定价模型FFC4的因子
|
954
|
-
输入:用户输入
|
955
|
-
显示:各个因子
|
956
|
-
返回值:无
|
957
|
-
"""
|
958
|
-
|
959
|
-
import easygui as g
|
960
|
-
|
961
|
-
title="Test the Factors of Fama-French-Carhart 4-factor Model"
|
962
|
-
msg="Please fill in the information below"
|
963
|
-
fldnames=["Start date (YYYY-MM-DD)","End date (YYYY-MM-DD)", \
|
964
|
-
"Scope (US, China, Japan, Europe)", \
|
965
|
-
"Frequency (yearly, monthly, daily)"]
|
966
|
-
fldvalues=[]
|
967
|
-
values=("2018-01-01","2019-04-30","US","monthly")
|
968
|
-
fldvalues=g.multenterbox(msg,title=title,fields=fldnames,values=values)
|
969
|
-
"""
|
970
|
-
如果用户输入的值比选项少的话,则返回列表中的值用空字符串填充用户为输入的选项。
|
971
|
-
如果用户输入的值比选项多的话,则返回的列表中的值将截断为选项的数量。
|
972
|
-
如果用户取消操作,则返回域中的列表的值或者None值
|
973
|
-
"""
|
974
|
-
|
975
|
-
if fldvalues:
|
976
|
-
start=fldvalues[0]
|
977
|
-
end=fldvalues[1]
|
978
|
-
scope=fldvalues[2]
|
979
|
-
freq=fldvalues[3]
|
980
|
-
|
981
|
-
ff_factors=get_ffc4_factors(start,end,scope,freq)
|
982
|
-
if ff_factors is None:
|
983
|
-
g.msgbox(msg=" Sorry, no factor data available under the condition.", \
|
984
|
-
title=title)
|
985
|
-
else:
|
986
|
-
g.msgbox(msg=ff_factors,title=title)
|
987
|
-
else:
|
988
|
-
g.msgbox(msg=" Sorry, user cancelled the operation, no data retrieved.", \
|
989
|
-
title=title)
|
990
|
-
|
991
|
-
return
|
992
|
-
|
993
|
-
if __name__=='__main__':
|
994
|
-
test_ffc4_factors()
|
995
|
-
|
996
|
-
|
997
|
-
#==============================================================================
|
998
|
-
def get_ff5_factors(start,end,scope='US',freq='yearly'):
|
999
|
-
"""
|
1000
|
-
功能:抓取Fama-French五因子模型的五个市场因子
|
1001
|
-
1)市场风险溢价(Rmarket-Rf,收益率风险溢价)
|
1002
|
-
2)小市值风险溢价(SMB,规模因子,即小市值股票对比大市值股票的超额收益率)
|
1003
|
-
3)高市净率风险溢价(HML,价值因子,高溢价股票对比低溢价股票的超额收益率)
|
1004
|
-
4)盈利因子(RMW,盈利好和盈利差的多元化股票组合收益之间的差异。其中,盈利
|
1005
|
-
定义为年营业收入减去营业成本、利息费用、销售费用和管理费用后再除以t-1财年
|
1006
|
-
末的账面权益)
|
1007
|
-
5)投资因子(CMA:投资低和投资高的多元化股票组合收益之间的差异(投资高对长远
|
1008
|
-
未来有利,但将影响当年业绩。其中,投资定义为t-1财年的新增总资产除以t-2财年
|
1009
|
-
末的总资产)
|
1010
|
-
|
1011
|
-
输入参数:
|
1012
|
-
start/end:开始/结束日期,格式为YYYY-MM-DD或MM/DD/YYYY
|
1013
|
-
scope:地区(美国,日本,欧洲,全球,除美国外的全球,除日本外的亚太)
|
1014
|
-
freq:采样周期(日、周、月、年,其中周仅支持美国市场)
|
1015
|
-
输出:按照采样周期排列的指定地区的FF5因子(pandas格式)
|
1016
|
-
"""
|
1017
|
-
|
1018
|
-
#仅为测试用
|
1019
|
-
#start="2018-01-01"
|
1020
|
-
#end="2018-12-31"
|
1021
|
-
#scope='US'
|
1022
|
-
#freq='monthly'
|
1023
|
-
|
1024
|
-
#抓取FF5因子
|
1025
|
-
factor='FF5'
|
1026
|
-
ff5_factors=get_ff_factors(start,end,scope,factor,freq)
|
1027
|
-
|
1028
|
-
return ff5_factors
|
1029
|
-
|
1030
|
-
if __name__=='__main__':
|
1031
|
-
factors1=get_ff5_factors("2018-01-01","2018-12-31",scope='US', \
|
1032
|
-
freq='monthly')
|
1033
|
-
draw1_ff_factors("FFC4 model","US",factors1,"RMW")
|
1034
|
-
|
1035
|
-
factors2=get_ff5_factors("2018-01-01","2018-12-31",scope='Europe', \
|
1036
|
-
freq='monthly')
|
1037
|
-
draw1_ff_factors("FFC4 model","US",factors2,"CMA")
|
1038
|
-
draw2_ff_factors("FFC4 model","US","Europe",factors1,factors2,"RMW")
|
1039
|
-
|
1040
|
-
#==============================================================================
|
1041
|
-
def test_ff5_factors():
|
1042
|
-
"""
|
1043
|
-
功能:交互式测试资产定价模型FF5的因子
|
1044
|
-
输入:用户输入
|
1045
|
-
显示:各个因子
|
1046
|
-
返回值:无
|
1047
|
-
"""
|
1048
|
-
|
1049
|
-
import easygui as g
|
1050
|
-
|
1051
|
-
title="Test the Factors of Fama-French 5-factor Model"
|
1052
|
-
msg="Please fill in the information below"
|
1053
|
-
fldnames=["Start date (YYYY-MM-DD)","End date (YYYY-MM-DD)", \
|
1054
|
-
"Scope (US, China, Japan, Europe)", \
|
1055
|
-
"Frequency (yearly, monthly, daily)"]
|
1056
|
-
fldvalues=[]
|
1057
|
-
values=("2018-01-01","2019-04-30","US","monthly")
|
1058
|
-
fldvalues=g.multenterbox(msg,title=title,fields=fldnames,values=values)
|
1059
|
-
"""
|
1060
|
-
如果用户输入的值比选项少的话,则返回列表中的值用空字符串填充用户为输入的选项。
|
1061
|
-
如果用户输入的值比选项多的话,则返回的列表中的值将截断为选项的数量。
|
1062
|
-
如果用户取消操作,则返回域中的列表的值或者None值
|
1063
|
-
"""
|
1064
|
-
|
1065
|
-
if fldvalues:
|
1066
|
-
start=fldvalues[0]
|
1067
|
-
end=fldvalues[1]
|
1068
|
-
scope=fldvalues[2]
|
1069
|
-
freq=fldvalues[3]
|
1070
|
-
|
1071
|
-
ff_factors=get_ff5_factors(start,end,scope,freq)
|
1072
|
-
if ff_factors is None:
|
1073
|
-
g.msgbox(msg=" Sorry, no factor data available under the condition.", \
|
1074
|
-
title=title)
|
1075
|
-
else:
|
1076
|
-
g.msgbox(msg=ff_factors,title=title)
|
1077
|
-
else:
|
1078
|
-
g.msgbox(msg=" Sorry, user cancelled the operation, no data retrieved.", \
|
1079
|
-
title=title)
|
1080
|
-
|
1081
|
-
return
|
1082
|
-
|
1083
|
-
if __name__=='__main__':
|
1084
|
-
test_ff5_factors()
|
1085
|
-
|
1086
|
-
|
1087
|
-
#==============================================================================
|
1088
|
-
if __name__=='__main__':
|
1089
|
-
ticker='BIDU'
|
1090
|
-
start='2025-1-1'
|
1091
|
-
end='2025-5-30'
|
1092
|
-
scope='US'
|
1093
|
-
graph=True
|
1094
|
-
|
1095
|
-
|
1096
|
-
def reg_ff3_betas(ticker,start,end,scope='US',graph=True):
|
1097
|
-
"""
|
1098
|
-
功能:测试一只股票对于FF3各个因子的系数大小、符号方向和显著性
|
1099
|
-
输入:
|
1100
|
-
ticker: 股票代码
|
1101
|
-
start/end: 开始/结束日期,格式:YYYY-MM-DD或MM/DD/YYYY
|
1102
|
-
scope: 股票市场地域
|
1103
|
-
输出:FF3模型对于一只股票日收益率的回归结果
|
1104
|
-
"""
|
1105
|
-
|
1106
|
-
#仅为测试使用,过后应注释掉
|
1107
|
-
#scope='Japan'
|
1108
|
-
#ticker='9983.T'
|
1109
|
-
#start='01/01/2018'
|
1110
|
-
#end='06/30/2019'
|
1111
|
-
|
1112
|
-
#抓取每日股价
|
1113
|
-
price=get_price(ticker,start,end)
|
1114
|
-
|
1115
|
-
#计算股票日收益率
|
1116
|
-
import pandas as pd
|
1117
|
-
ret=pd.DataFrame(price['Close'].pct_change()*100)
|
1118
|
-
ret=ret.dropna()
|
1119
|
-
#命名日收益率字段为dRet
|
1120
|
-
ret=ret.rename(columns={'Close':'dRet'})
|
1121
|
-
|
1122
|
-
#抓取FF3因子
|
1123
|
-
print(" Looking for factors for FF3 model ...")
|
1124
|
-
freq='daily'
|
1125
|
-
ff3=get_ff3_factors(start,end,scope,freq)
|
1126
|
-
if ff3 is None:
|
1127
|
-
print(" #Warning(reg_ff3_betas): factors unavailable for",scope,freq,'from',start,'to',end)
|
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
|
1132
|
-
|
1133
|
-
#改造索引类型为时间戳索引(DatetimeIndex),便于与ret合成
|
1134
|
-
ff3['Date']=ff3.index.strftime("%m/%d/%Y")
|
1135
|
-
ff3['Date']=pd.to_datetime(ff3['Date'])
|
1136
|
-
ff3.set_index('Date',inplace=True)
|
1137
|
-
|
1138
|
-
#内连接:股票日收益率+每日FF3因子
|
1139
|
-
sample=pd.merge(ret,ff3,how='inner',left_index=True,right_index=True)
|
1140
|
-
sample=sample.dropna()
|
1141
|
-
|
1142
|
-
#回归FF3模型
|
1143
|
-
import statsmodels.api as sm
|
1144
|
-
y=sample['dRet']
|
1145
|
-
X=sample[['Mkt-RF','SMB','HML']]
|
1146
|
-
X1=sm.add_constant(X)
|
1147
|
-
results=sm.OLS(y,X1).fit()
|
1148
|
-
|
1149
|
-
#生成回归参数
|
1150
|
-
#dir(results) #查看回归结果results的属性
|
1151
|
-
parms=regparms(results)
|
1152
|
-
|
1153
|
-
#输出结果并绘制横向柱状图
|
1154
|
-
if graph == True:
|
1155
|
-
gparms=parms.iloc[[1,2,3]]
|
1156
|
-
#print("\n",parms)
|
1157
|
-
title=ticker_name(ticker)+": FF3模型的贝塔系数"
|
1158
|
-
plt.title(title,fontsize=12,fontweight='bold')
|
1159
|
-
plt.ylabel("贝塔系数",fontsize=12,fontweight='bold')
|
1160
|
-
|
1161
|
-
import datetime; today = datetime.date.today()
|
1162
|
-
footnote="FF3因子"+"\n数据来源:雅虎财经, "+str(today)
|
1163
|
-
plt.xlabel(footnote,fontsize=12,fontweight='bold')
|
1164
|
-
plt.bar(gparms.index,gparms.coef,0.5,color=['r','g','b'],alpha=0.5)
|
1165
|
-
plt.axhline(y=0.0,color='blue',linestyle=':')
|
1166
|
-
|
1167
|
-
return parms
|
1168
|
-
|
1169
|
-
if __name__=='__main__':
|
1170
|
-
reg_ff3_betas=reg_ff3_betas('9983.T',"2018-01-01","2018-12-31",scope='Japan')
|
1171
|
-
|
1172
|
-
#==============================================================================
|
1173
|
-
def test_ff3_betas():
|
1174
|
-
"""
|
1175
|
-
功能:交互式测试资产定价因子的贝塔系数
|
1176
|
-
输入:用户输入
|
1177
|
-
显示:各个因子的贝塔系数
|
1178
|
-
返回值:无
|
1179
|
-
"""
|
1180
|
-
|
1181
|
-
import easygui as g
|
1182
|
-
|
1183
|
-
title="Calculate A Stock's Betas Using FF3 Model"
|
1184
|
-
msg="Please fill in the information below"
|
1185
|
-
fldnames=["Start date (YYYY-MM-DD)","End date (YYYY-MM-DD)", \
|
1186
|
-
"Scope (US, China, Japan, Europe)", \
|
1187
|
-
"Stock code (mind the suffix for no-US stocks)"]
|
1188
|
-
fldvalues=[]
|
1189
|
-
values=("2018-01-01","2019-04-30","US","AAPL")
|
1190
|
-
fldvalues=g.multenterbox(msg,title=title,fields=fldnames,values=values)
|
1191
|
-
|
1192
|
-
if fldvalues:
|
1193
|
-
start=fldvalues[0]
|
1194
|
-
end=fldvalues[1]
|
1195
|
-
scope=fldvalues[2]
|
1196
|
-
if scope == "China": scope="Asia_Pacific_ex_Japan"
|
1197
|
-
ticker=fldvalues[3]
|
1198
|
-
|
1199
|
-
parms=reg_ff3_betas(ticker,start,end,scope)
|
1200
|
-
if parms is None:
|
1201
|
-
g.msgbox(msg=" Sorry, no beta data available under the condition.", \
|
1202
|
-
title=title)
|
1203
|
-
else:
|
1204
|
-
title=ticker+"'s Betas Using FF3 Model"
|
1205
|
-
g.msgbox(msg=parms,title=title)
|
1206
|
-
else:
|
1207
|
-
g.msgbox(msg=" Sorry, user cancelled the operation, no data retrieved.", \
|
1208
|
-
title=title)
|
1209
|
-
|
1210
|
-
return
|
1211
|
-
|
1212
|
-
if __name__=='__main__':
|
1213
|
-
test_ff3_betas()
|
1214
|
-
|
1215
|
-
|
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
|
-
|
1224
|
-
def reg_ffc4_betas(ticker,start,end,scope='US',graph=True):
|
1225
|
-
"""
|
1226
|
-
功能:测试一只股票对于FFC4各个因子的系数大小、符号方向和显著性
|
1227
|
-
输入:
|
1228
|
-
ticker: 股票代码
|
1229
|
-
start/end: 开始/结束日期,格式:YYYY-MM-DD或MM/DD/YYYY
|
1230
|
-
scope: 股票市场地域
|
1231
|
-
输出:FFC4模型对于一只股票日收益率的回归结果
|
1232
|
-
"""
|
1233
|
-
|
1234
|
-
#仅为测试使用,过后应注释掉
|
1235
|
-
#scope='US'
|
1236
|
-
#ticker='AAPL'
|
1237
|
-
#start='01/01/2018'
|
1238
|
-
#end='06/30/2019'
|
1239
|
-
|
1240
|
-
#抓取每日股价
|
1241
|
-
import siat.security_prices as ssp
|
1242
|
-
price=get_price(ticker,start,end)
|
1243
|
-
|
1244
|
-
#计算股票日收益率
|
1245
|
-
import pandas as pd
|
1246
|
-
ret=pd.DataFrame(price['Close'].pct_change()*100)
|
1247
|
-
ret=ret.dropna()
|
1248
|
-
#命名日收益率字段为dRet
|
1249
|
-
ret=ret.rename(columns={'Close':'dRet'})
|
1250
|
-
|
1251
|
-
#抓取每日FFC4因子
|
1252
|
-
print(" Looking for factors for FFC4 model ...")
|
1253
|
-
freq='daily'
|
1254
|
-
ffc4=get_ffc4_factors(start,end,scope,freq)
|
1255
|
-
if ffc4 is None:
|
1256
|
-
print(" #Warning(reg_ffc4_betas): factors not available for",scope,freq,'from',start,'to',end)
|
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
|
1261
|
-
|
1262
|
-
#改造索引类型为时间戳索引(DatetimeIndex),便于与ret合成
|
1263
|
-
#ffc4['Date']=ffc4.index.strftime("%m/%d/%Y")
|
1264
|
-
ffc4['Date']=pd.to_datetime(ffc4['Date'])
|
1265
|
-
ffc4.set_index('Date',drop=True,inplace=True)
|
1266
|
-
|
1267
|
-
#合成股票日收益率+每日FF3因子
|
1268
|
-
sample=pd.merge(ret,ffc4,how='inner',left_index=True,right_index=True)
|
1269
|
-
sample=sample.dropna()
|
1270
|
-
|
1271
|
-
#回归FF3模型
|
1272
|
-
import statsmodels.api as sm
|
1273
|
-
y=sample['dRet']
|
1274
|
-
try:
|
1275
|
-
X=sample[['Mkt-RF','SMB','HML','MOM']]
|
1276
|
-
except:
|
1277
|
-
X=sample[['Mkt-RF','SMB','HML','Mom']]
|
1278
|
-
X1=sm.add_constant(X)
|
1279
|
-
results=sm.OLS(y,X1).fit()
|
1280
|
-
|
1281
|
-
#生成回归参数
|
1282
|
-
parms=regparms(results)
|
1283
|
-
|
1284
|
-
#输出结果并绘制横向柱状图
|
1285
|
-
gparms=parms.iloc[[1,2,3,4]]
|
1286
|
-
if graph == True:
|
1287
|
-
#print("\n",parms)
|
1288
|
-
title=ticker_name(ticker)+": FFC4模型的贝塔系数"
|
1289
|
-
plt.title(title,fontsize=12,fontweight='bold')
|
1290
|
-
plt.ylabel("贝塔系数",fontsize=12,fontweight='bold')
|
1291
|
-
|
1292
|
-
import datetime; today = datetime.date.today()
|
1293
|
-
footnote="FFC4因子"+"\n数据来源:雅虎财经, "+str(today)
|
1294
|
-
plt.xlabel(footnote,fontsize=12,fontweight='bold')
|
1295
|
-
plt.bar(gparms.index,gparms.coef,0.5,color=['r','g','b'],alpha=0.5)
|
1296
|
-
plt.axhline(y=0.0,color='blue',linestyle=':')
|
1297
|
-
|
1298
|
-
return parms
|
1299
|
-
|
1300
|
-
|
1301
|
-
if __name__=='__main__':
|
1302
|
-
ffc4=reg_ffc4_betas('AAPL',"2018-01-01","2019-06-30",scope='US')
|
1303
|
-
|
1304
|
-
#==============================================================================
|
1305
|
-
def test_ffc4_betas():
|
1306
|
-
"""
|
1307
|
-
功能:交互式测试资产定价因子的贝塔系数
|
1308
|
-
输入:用户输入
|
1309
|
-
显示:各个因子的贝塔系数
|
1310
|
-
返回值:无
|
1311
|
-
"""
|
1312
|
-
|
1313
|
-
import easygui as g
|
1314
|
-
|
1315
|
-
title="Calculate A Stock's Betas Using FFC4 Model"
|
1316
|
-
msg="Please fill in the information below"
|
1317
|
-
fldnames=["Start date (YYYY-MM-DD)","End date (YYYY-MM-DD)", \
|
1318
|
-
"Scope (US, China, Japan, Europe)", \
|
1319
|
-
"Stock code (mind the suffix for no-US stocks)"]
|
1320
|
-
fldvalues=[]
|
1321
|
-
values=("2018-01-01","2019-04-30","Europe","BMW.DE")
|
1322
|
-
fldvalues=g.multenterbox(msg,title=title,fields=fldnames,values=values)
|
1323
|
-
|
1324
|
-
if fldvalues:
|
1325
|
-
start=fldvalues[0]
|
1326
|
-
end=fldvalues[1]
|
1327
|
-
scope=fldvalues[2]
|
1328
|
-
if scope == "China": scope="Asia_Pacific_ex_Japan"
|
1329
|
-
ticker=fldvalues[3]
|
1330
|
-
|
1331
|
-
parms=reg_ffc4_betas(ticker,start,end,scope)
|
1332
|
-
if parms is None:
|
1333
|
-
g.msgbox(msg=" Sorry, no beta data available under the condition.", \
|
1334
|
-
title=title)
|
1335
|
-
else:
|
1336
|
-
title=ticker+"'s Betas Using FFC4 Model"
|
1337
|
-
g.msgbox(msg=parms,title=title)
|
1338
|
-
else:
|
1339
|
-
g.msgbox(msg=" Sorry, user cancelled the operation, no data retrieved.", \
|
1340
|
-
title=title)
|
1341
|
-
|
1342
|
-
return
|
1343
|
-
|
1344
|
-
if __name__=='__main__':
|
1345
|
-
test_ffc4_betas()
|
1346
|
-
|
1347
|
-
#==============================================================================
|
1348
|
-
if __name__=='__main__':
|
1349
|
-
ticker='MSFT'
|
1350
|
-
start='2024-5-1'; end='2025-4-30'
|
1351
|
-
scope='US'; graph=True
|
1352
|
-
|
1353
|
-
def reg_ff5_betas(ticker,start,end,scope='US',graph=True):
|
1354
|
-
"""
|
1355
|
-
功能:测试一只股票对于FF5各个因子的系数大小、符号方向和显著性
|
1356
|
-
输入:
|
1357
|
-
ticker: 股票代码
|
1358
|
-
start/end: 开始/结束日期,格式:YYYY-MM-DD或MM/DD/YYYY
|
1359
|
-
scope: 股票市场地域
|
1360
|
-
输出:FF5模型对于一只股票日收益率的回归结果
|
1361
|
-
"""
|
1362
|
-
|
1363
|
-
#仅为测试使用,过后应注释掉
|
1364
|
-
#scope='US'
|
1365
|
-
#ticker='AAPL'
|
1366
|
-
#start='01/01/2018'
|
1367
|
-
#end='06/30/2019'
|
1368
|
-
|
1369
|
-
#抓取每日股价
|
1370
|
-
import siat.security_prices as ssp
|
1371
|
-
price=get_price(ticker,start,end)
|
1372
|
-
|
1373
|
-
#计算股票日收益率
|
1374
|
-
import pandas as pd
|
1375
|
-
ret=pd.DataFrame(price['Close'].pct_change()*100)
|
1376
|
-
ret=ret.dropna()
|
1377
|
-
#命名日收益率字段为dRet
|
1378
|
-
ret=ret.rename(columns={'Close':'dRet'})
|
1379
|
-
|
1380
|
-
#抓取每日FF5因子
|
1381
|
-
print(" Looking for factors for FF5 model ...")
|
1382
|
-
freq='daily'
|
1383
|
-
ff5=get_ff5_factors(start,end,scope,freq)
|
1384
|
-
if ff5 is None:
|
1385
|
-
print(" #Warning(reg_ff5_betas): factors not available for",scope,freq,'from',start,'to',end)
|
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
|
1390
|
-
|
1391
|
-
#改造索引类型为时间戳索引(DatetimeIndex),便于与ret合成
|
1392
|
-
ff5['Date']=ff5.index.strftime("%m/%d/%Y")
|
1393
|
-
ff5['Date']=pd.to_datetime(ff5['Date'])
|
1394
|
-
ff5.set_index('Date',inplace=True)
|
1395
|
-
|
1396
|
-
#合成股票日收益率+每日FF3因子
|
1397
|
-
sample=pd.merge(ret,ff5,how='inner',left_index=True,right_index=True)
|
1398
|
-
sample=sample.dropna()
|
1399
|
-
|
1400
|
-
#回归FF3模型
|
1401
|
-
import statsmodels.api as sm
|
1402
|
-
y=sample['dRet']
|
1403
|
-
X=sample[['Mkt-RF','SMB','HML','RMW','CMA']]
|
1404
|
-
X1=sm.add_constant(X)
|
1405
|
-
results=sm.OLS(y,X1).fit()
|
1406
|
-
|
1407
|
-
#生成回归参数
|
1408
|
-
parms=regparms(results)
|
1409
|
-
|
1410
|
-
#输出结果并绘制横向柱状图
|
1411
|
-
gparms=parms.iloc[[1,2,3,4,5]]
|
1412
|
-
if graph == True:
|
1413
|
-
#print("\n",parms)
|
1414
|
-
title=ticker_name(ticker)+":FF5模型的贝塔系数"
|
1415
|
-
plt.title(title,fontsize=12,fontweight='bold')
|
1416
|
-
plt.ylabel("贝塔系数",fontsize=12,fontweight='bold')
|
1417
|
-
|
1418
|
-
import datetime; today = datetime.date.today()
|
1419
|
-
footnote="FF5因子"+"\n数据来源:雅虎财经, "+str(today)
|
1420
|
-
plt.xlabel(footnote,fontsize=12,fontweight='bold')
|
1421
|
-
plt.bar(gparms.index,gparms.coef,0.5,color=['r','g','b'],alpha=0.5)
|
1422
|
-
plt.axhline(y=0.0,color='blue',linestyle=':')
|
1423
|
-
|
1424
|
-
return parms
|
1425
|
-
|
1426
|
-
|
1427
|
-
if __name__=='__main__':
|
1428
|
-
ff5_betas=reg_ff5_betas('AAPL',"2018-01-01","2019-07-18",scope='US')
|
1429
|
-
|
1430
|
-
#==============================================================================
|
1431
|
-
def test_ff5_betas():
|
1432
|
-
"""
|
1433
|
-
功能:交互式测试资产定价因子的贝塔系数
|
1434
|
-
输入:用户输入
|
1435
|
-
显示:各个因子的贝塔系数
|
1436
|
-
返回值:无
|
1437
|
-
"""
|
1438
|
-
|
1439
|
-
import easygui as g
|
1440
|
-
|
1441
|
-
title="Calculate A Stock's Betas Using FF5 Model"
|
1442
|
-
msg="Please fill in the information below"
|
1443
|
-
fldnames=["Start date (YYYY-MM-DD)","End date (YYYY-MM-DD)", \
|
1444
|
-
"Scope (US, China, Japan, Europe)", \
|
1445
|
-
"Stock code (mind the suffix for no-US stocks)"]
|
1446
|
-
fldvalues=[]
|
1447
|
-
values=("2018-01-01","2019-04-30","Japan","9983.T")
|
1448
|
-
fldvalues=g.multenterbox(msg,title=title,fields=fldnames,values=values)
|
1449
|
-
|
1450
|
-
if fldvalues:
|
1451
|
-
start=fldvalues[0]
|
1452
|
-
end=fldvalues[1]
|
1453
|
-
scope=fldvalues[2]
|
1454
|
-
if scope == "China": scope="Asia_Pacific_ex_Japan"
|
1455
|
-
ticker=fldvalues[3]
|
1456
|
-
|
1457
|
-
parms=reg_ff5_betas(ticker,start,end,scope)
|
1458
|
-
if parms is None:
|
1459
|
-
g.msgbox(msg="Sorry, no beta data available under the condition.", \
|
1460
|
-
title=title)
|
1461
|
-
else:
|
1462
|
-
title=ticker+"'s Betas Using FF5 Model"
|
1463
|
-
g.msgbox(msg=parms,title=title)
|
1464
|
-
else:
|
1465
|
-
g.msgbox(msg="Sorry, user cancelled the operation, no data retrieved.", \
|
1466
|
-
title=title)
|
1467
|
-
|
1468
|
-
return
|
1469
|
-
|
1470
|
-
if __name__=='__main__':
|
1471
|
-
test_ff5_betas()
|
1472
|
-
|
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
|