siat 3.10.132__py3-none-any.whl → 3.11.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. siat/__init__.py +0 -0
  2. siat/allin.py +8 -0
  3. siat/assets_liquidity.py +0 -0
  4. siat/beta_adjustment.py +0 -0
  5. siat/beta_adjustment_china.py +0 -0
  6. siat/blockchain.py +0 -0
  7. siat/bond.py +0 -0
  8. siat/bond_base.py +0 -0
  9. siat/bond_china.py +0 -0
  10. siat/bond_zh_sina.py +0 -0
  11. siat/capm_beta.py +0 -0
  12. siat/capm_beta2.py +4 -4
  13. siat/common.py +9 -6
  14. siat/compare_cross.py +0 -0
  15. siat/copyrights.py +0 -0
  16. siat/cryptocurrency.py +0 -0
  17. siat/economy.py +0 -0
  18. siat/economy2.py +0 -0
  19. siat/esg.py +0 -0
  20. siat/event_study.py +0 -0
  21. siat/exchange_bond_china.pickle +0 -0
  22. siat/fama_french.py +0 -0
  23. siat/fin_stmt2_yahoo.py +0 -0
  24. siat/financial_base.py +0 -0
  25. siat/financial_statements.py +0 -0
  26. siat/financials.py +0 -0
  27. siat/financials2.py +0 -0
  28. siat/financials_china.py +0 -0
  29. siat/financials_china2.py +0 -0
  30. siat/fund.py +0 -0
  31. siat/fund_china.pickle +0 -0
  32. siat/fund_china.py +0 -0
  33. siat/future_china.py +0 -0
  34. siat/google_authenticator.py +0 -0
  35. siat/grafix.py +55 -4
  36. siat/holding_risk.py +0 -0
  37. siat/luchy_draw.py +0 -0
  38. siat/market_china.py +0 -0
  39. siat/markowitz.py +0 -0
  40. siat/markowitz2.py +1 -0
  41. siat/markowitz2_20250704.py +0 -0
  42. siat/markowitz2_20250705.py +0 -0
  43. siat/markowitz_simple.py +0 -0
  44. siat/ml_cases.py +0 -0
  45. siat/ml_cases_example.py +0 -0
  46. siat/option_china.py +0 -0
  47. siat/option_pricing.py +0 -0
  48. siat/other_indexes.py +0 -0
  49. siat/risk_adjusted_return.py +0 -0
  50. siat/risk_adjusted_return2.py +8 -4
  51. siat/risk_evaluation.py +0 -0
  52. siat/risk_free_rate.py +0 -0
  53. siat/save2docx.py +345 -0
  54. siat/save2pdf.py +145 -0
  55. siat/sector_china.py +0 -0
  56. siat/security_price2.py +0 -0
  57. siat/security_prices.py +168 -6
  58. siat/security_trend.py +0 -0
  59. siat/security_trend2.py +2 -2
  60. siat/stock.py +11 -1
  61. siat/stock_advice_linear.py +0 -0
  62. siat/stock_base.py +0 -0
  63. siat/stock_china.py +0 -0
  64. siat/stock_info.pickle +0 -0
  65. siat/stock_prices_kneighbors.py +0 -0
  66. siat/stock_prices_linear.py +0 -0
  67. siat/stock_profile.py +0 -0
  68. siat/stock_technical.py +0 -0
  69. siat/stooq.py +0 -0
  70. siat/transaction.py +0 -0
  71. siat/translate.py +0 -0
  72. siat/valuation.py +0 -0
  73. siat/valuation_china.py +0 -0
  74. siat/var_model_validation.py +0 -0
  75. siat/yf_name.py +0 -0
  76. {siat-3.10.132.dist-info/licenses → siat-3.11.1.dist-info}/LICENSE +0 -0
  77. {siat-3.10.132.dist-info → siat-3.11.1.dist-info}/METADATA +234 -235
  78. siat-3.11.1.dist-info/RECORD +80 -0
  79. {siat-3.10.132.dist-info → siat-3.11.1.dist-info}/WHEEL +1 -1
  80. {siat-3.10.132.dist-info → siat-3.11.1.dist-info}/top_level.txt +0 -1
  81. build/lib/build/lib/siat/__init__.py +0 -75
  82. build/lib/build/lib/siat/allin.py +0 -137
  83. build/lib/build/lib/siat/assets_liquidity.py +0 -915
  84. build/lib/build/lib/siat/beta_adjustment.py +0 -1058
  85. build/lib/build/lib/siat/beta_adjustment_china.py +0 -548
  86. build/lib/build/lib/siat/blockchain.py +0 -143
  87. build/lib/build/lib/siat/bond.py +0 -2900
  88. build/lib/build/lib/siat/bond_base.py +0 -992
  89. build/lib/build/lib/siat/bond_china.py +0 -100
  90. build/lib/build/lib/siat/bond_zh_sina.py +0 -143
  91. build/lib/build/lib/siat/capm_beta.py +0 -783
  92. build/lib/build/lib/siat/capm_beta2.py +0 -887
  93. build/lib/build/lib/siat/common.py +0 -5360
  94. build/lib/build/lib/siat/compare_cross.py +0 -642
  95. build/lib/build/lib/siat/copyrights.py +0 -18
  96. build/lib/build/lib/siat/cryptocurrency.py +0 -667
  97. build/lib/build/lib/siat/economy.py +0 -1471
  98. build/lib/build/lib/siat/economy2.py +0 -1853
  99. build/lib/build/lib/siat/esg.py +0 -536
  100. build/lib/build/lib/siat/event_study.py +0 -815
  101. build/lib/build/lib/siat/fama_french.py +0 -1521
  102. build/lib/build/lib/siat/fin_stmt2_yahoo.py +0 -982
  103. build/lib/build/lib/siat/financial_base.py +0 -1160
  104. build/lib/build/lib/siat/financial_statements.py +0 -598
  105. build/lib/build/lib/siat/financials.py +0 -2339
  106. build/lib/build/lib/siat/financials2.py +0 -1278
  107. build/lib/build/lib/siat/financials_china.py +0 -4433
  108. build/lib/build/lib/siat/financials_china2.py +0 -2212
  109. build/lib/build/lib/siat/fund.py +0 -629
  110. build/lib/build/lib/siat/fund_china.py +0 -3307
  111. build/lib/build/lib/siat/future_china.py +0 -551
  112. build/lib/build/lib/siat/google_authenticator.py +0 -47
  113. build/lib/build/lib/siat/grafix.py +0 -3636
  114. build/lib/build/lib/siat/holding_risk.py +0 -867
  115. build/lib/build/lib/siat/luchy_draw.py +0 -638
  116. build/lib/build/lib/siat/market_china.py +0 -1168
  117. build/lib/build/lib/siat/markowitz.py +0 -2363
  118. build/lib/build/lib/siat/markowitz2.py +0 -3150
  119. build/lib/build/lib/siat/markowitz2_20250704.py +0 -2969
  120. build/lib/build/lib/siat/markowitz2_20250705.py +0 -3158
  121. build/lib/build/lib/siat/markowitz_simple.py +0 -373
  122. build/lib/build/lib/siat/ml_cases.py +0 -2291
  123. build/lib/build/lib/siat/ml_cases_example.py +0 -60
  124. build/lib/build/lib/siat/option_china.py +0 -3069
  125. build/lib/build/lib/siat/option_pricing.py +0 -1925
  126. build/lib/build/lib/siat/other_indexes.py +0 -409
  127. build/lib/build/lib/siat/risk_adjusted_return.py +0 -1576
  128. build/lib/build/lib/siat/risk_adjusted_return2.py +0 -1900
  129. build/lib/build/lib/siat/risk_evaluation.py +0 -2218
  130. build/lib/build/lib/siat/risk_free_rate.py +0 -351
  131. build/lib/build/lib/siat/sector_china.py +0 -4140
  132. build/lib/build/lib/siat/security_price2.py +0 -727
  133. build/lib/build/lib/siat/security_prices.py +0 -3408
  134. build/lib/build/lib/siat/security_trend.py +0 -402
  135. build/lib/build/lib/siat/security_trend2.py +0 -646
  136. build/lib/build/lib/siat/stock.py +0 -4284
  137. build/lib/build/lib/siat/stock_advice_linear.py +0 -934
  138. build/lib/build/lib/siat/stock_base.py +0 -26
  139. build/lib/build/lib/siat/stock_china.py +0 -2095
  140. build/lib/build/lib/siat/stock_prices_kneighbors.py +0 -910
  141. build/lib/build/lib/siat/stock_prices_linear.py +0 -386
  142. build/lib/build/lib/siat/stock_profile.py +0 -707
  143. build/lib/build/lib/siat/stock_technical.py +0 -3305
  144. build/lib/build/lib/siat/stooq.py +0 -74
  145. build/lib/build/lib/siat/transaction.py +0 -347
  146. build/lib/build/lib/siat/translate.py +0 -5183
  147. build/lib/build/lib/siat/valuation.py +0 -1378
  148. build/lib/build/lib/siat/valuation_china.py +0 -2076
  149. build/lib/build/lib/siat/var_model_validation.py +0 -444
  150. build/lib/build/lib/siat/yf_name.py +0 -811
  151. build/lib/siat/__init__.py +0 -75
  152. build/lib/siat/allin.py +0 -137
  153. build/lib/siat/assets_liquidity.py +0 -915
  154. build/lib/siat/beta_adjustment.py +0 -1058
  155. build/lib/siat/beta_adjustment_china.py +0 -548
  156. build/lib/siat/blockchain.py +0 -143
  157. build/lib/siat/bond.py +0 -2900
  158. build/lib/siat/bond_base.py +0 -992
  159. build/lib/siat/bond_china.py +0 -100
  160. build/lib/siat/bond_zh_sina.py +0 -143
  161. build/lib/siat/capm_beta.py +0 -783
  162. build/lib/siat/capm_beta2.py +0 -887
  163. build/lib/siat/common.py +0 -5360
  164. build/lib/siat/compare_cross.py +0 -642
  165. build/lib/siat/copyrights.py +0 -18
  166. build/lib/siat/cryptocurrency.py +0 -667
  167. build/lib/siat/economy.py +0 -1471
  168. build/lib/siat/economy2.py +0 -1853
  169. build/lib/siat/esg.py +0 -536
  170. build/lib/siat/event_study.py +0 -815
  171. build/lib/siat/fama_french.py +0 -1521
  172. build/lib/siat/fin_stmt2_yahoo.py +0 -982
  173. build/lib/siat/financial_base.py +0 -1160
  174. build/lib/siat/financial_statements.py +0 -598
  175. build/lib/siat/financials.py +0 -2339
  176. build/lib/siat/financials2.py +0 -1278
  177. build/lib/siat/financials_china.py +0 -4433
  178. build/lib/siat/financials_china2.py +0 -2212
  179. build/lib/siat/fund.py +0 -629
  180. build/lib/siat/fund_china.py +0 -3307
  181. build/lib/siat/future_china.py +0 -551
  182. build/lib/siat/google_authenticator.py +0 -47
  183. build/lib/siat/grafix.py +0 -3636
  184. build/lib/siat/holding_risk.py +0 -867
  185. build/lib/siat/luchy_draw.py +0 -638
  186. build/lib/siat/market_china.py +0 -1168
  187. build/lib/siat/markowitz.py +0 -2363
  188. build/lib/siat/markowitz2.py +0 -3150
  189. build/lib/siat/markowitz2_20250704.py +0 -2969
  190. build/lib/siat/markowitz2_20250705.py +0 -3158
  191. build/lib/siat/markowitz_simple.py +0 -373
  192. build/lib/siat/ml_cases.py +0 -2291
  193. build/lib/siat/ml_cases_example.py +0 -60
  194. build/lib/siat/option_china.py +0 -3069
  195. build/lib/siat/option_pricing.py +0 -1925
  196. build/lib/siat/other_indexes.py +0 -409
  197. build/lib/siat/risk_adjusted_return.py +0 -1576
  198. build/lib/siat/risk_adjusted_return2.py +0 -1900
  199. build/lib/siat/risk_evaluation.py +0 -2218
  200. build/lib/siat/risk_free_rate.py +0 -351
  201. build/lib/siat/sector_china.py +0 -4140
  202. build/lib/siat/security_price2.py +0 -727
  203. build/lib/siat/security_prices.py +0 -3408
  204. build/lib/siat/security_trend.py +0 -402
  205. build/lib/siat/security_trend2.py +0 -646
  206. build/lib/siat/stock.py +0 -4284
  207. build/lib/siat/stock_advice_linear.py +0 -934
  208. build/lib/siat/stock_base.py +0 -26
  209. build/lib/siat/stock_china.py +0 -2095
  210. build/lib/siat/stock_prices_kneighbors.py +0 -910
  211. build/lib/siat/stock_prices_linear.py +0 -386
  212. build/lib/siat/stock_profile.py +0 -707
  213. build/lib/siat/stock_technical.py +0 -3305
  214. build/lib/siat/stooq.py +0 -74
  215. build/lib/siat/transaction.py +0 -347
  216. build/lib/siat/translate.py +0 -5183
  217. build/lib/siat/valuation.py +0 -1378
  218. build/lib/siat/valuation_china.py +0 -2076
  219. build/lib/siat/var_model_validation.py +0 -444
  220. build/lib/siat/yf_name.py +0 -811
  221. siat-3.10.132.dist-info/RECORD +0 -218
@@ -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