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,1058 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- """
4
- 版权:王德宏,北京外国语大学国际商学院
5
- 功能:计算CAPM模型贝塔系数的调整值
6
- 版本:2.1,2019-7-25
7
- """
8
-
9
- #==============================================================================
10
- #关闭所有警告
11
- import warnings; warnings.filterwarnings('ignore')
12
- from siat.common import *
13
- from siat.translate import *
14
- from siat.grafix import *
15
- from siat.security_prices import *
16
- from siat.security_price2 import *
17
- #==============================================================================
18
- import matplotlib.pyplot as plt
19
-
20
- #处理绘图汉字乱码问题
21
- import sys; czxt=sys.platform
22
- if czxt in ['win32','win64']:
23
- plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体
24
- mpfrc={'font.family': 'SimHei'}
25
-
26
- if czxt in ['darwin']: #MacOSX
27
- plt.rcParams['font.family']= ['Heiti TC']
28
- mpfrc={'font.family': 'Heiti TC'}
29
-
30
- if czxt in ['linux']: #website Jupyter
31
- plt.rcParams['font.family']= ['Heiti TC']
32
- mpfrc={'font.family':'Heiti TC'}
33
-
34
- # 解决保存图像时'-'显示为方块的问题
35
- plt.rcParams['axes.unicode_minus'] = False
36
- #==============================================================================
37
- def prepare_capm(stkcd,mktidx,start,end):
38
- """
39
- 函数功能:准备计算一只股票CAPM模型贝塔系数的数据,并标记年度
40
- 输入参数:
41
- stkcd: 股票代码
42
- mktidx: 指数代码
43
- start:使用股票价格数据的开始日期,MM/DD/YYYY
44
- end:使用股票价格数据的结束日期,MM/DD/YYYY
45
- 输出数据:
46
- 返回数据:带年度标记的可直接用于capm回归的股票收益率数据
47
- """
48
-
49
- #仅用于调试,正式使用前应注释掉
50
- #stkcd='002504.SZ'; mktidx='000001.SS'
51
- #start="12/31/2011"; end="12/31/2018"
52
-
53
- #抓取股价和指数
54
- stock=get_price(stkcd,start,end)
55
- if stock is None:
56
- print(" #Error(prepare_capm): no data retrieved from server!")
57
- return None
58
- market=get_price(mktidx,start,end)
59
- if market is None:
60
- print(" #Error(prepare_capm): no index data retrieved from server!")
61
- return None
62
-
63
- #计算日收益率
64
- import pandas as pd
65
- stkret=pd.DataFrame(stock['Close'].pct_change())
66
- mktret=pd.DataFrame(market['Close'].pct_change())
67
-
68
- #合并,去掉空缺
69
- R=pd.merge(mktret,stkret,how='left',left_index=True,right_index=True)
70
- R=R.dropna()
71
-
72
- #标记各个年度
73
- R['Year']=R.index.strftime("%Y")
74
-
75
- #返回带年份的股票收益率序列
76
- return R
77
-
78
- if __name__=='__main__':
79
- R1=prepare_capm('0700.HK','^HSI','2014-01-01','2018-12-31')
80
-
81
- #==============================================================================
82
- #==============================================================================
83
- def get_beta_ML(stkcd,mktidx,yearlist,printout=True,graph=True):
84
- """
85
- 函数功能:使用ML方法调整一只股票的CAPM模型贝塔系数
86
- 输入参数:
87
- stkcd: 股票代码
88
- mktidx: 指数代码
89
- yearlist:年度列表,列出其中期间的贝塔系数
90
- 输出数据:
91
- 显示CAPM市场模型回归的beta, 以及ML调整后的beta系数
92
- 返回数据:年度CAPM贝塔系数和ML调整后的beta系数
93
- """
94
-
95
- #仅为测试用,完成后应立即注释掉
96
- #stkcd='0700.HK'
97
- #mktidx='^HSI'
98
- #yearlist=['2015','2016','2017','2018']
99
-
100
- Y4=str(int(yearlist[0])-1)
101
- start=Y4+'-01-01'
102
- end=yearlist[-1]+'-12-31'
103
-
104
- #读取股价并准备好收益率数据
105
- try:
106
- R=prepare_capm(stkcd,mktidx,start,end)
107
- except:
108
- print(" #Error(get_beta_ML): Preparing CAPM data failed!")
109
- return None
110
-
111
- if (R is None):
112
- print(" #Error(get_beta_ML): server time out")
113
- return None
114
- if (len(R) == 0):
115
- print(" #Error(get_beta_ML): server returned empty data")
116
- return None
117
-
118
- #用于保存beta(CAPM)和beta(ML)
119
- import pandas as pd
120
- betas=pd.DataFrame(columns=('Year','Beta(CAPM)','Beta(ML)'))
121
-
122
- #计算Merrill-Lynch方法贝塔系数调整
123
- from scipy import stats
124
- for year in yearlist:
125
- r=R[R['Year']==year]
126
- if len(r) != 0:
127
- output=stats.linregress(r['Close_x'],r['Close_y'])
128
- (beta,alpha,r_value,p_value,std_err)=output
129
- beta_ML=beta*2.0/3.0+1.0/3.0
130
- #整齐输出
131
- #print(year,"%6.4f "%(beta),"%6.4f "%(beta_ML))
132
-
133
- row=pd.Series({'Year':year,'Beta(CAPM)':beta,'Beta(ML)':beta_ML})
134
- try:
135
- betas=betas.append(row,ignore_index=True)
136
- except:
137
- betas=betas._append(row,ignore_index=True)
138
-
139
- betas.set_index(["Year"], inplace=True)
140
-
141
- if printout == True: printdf_betas(betas,2)
142
- if graph == True:
143
- model="贝塔系数的简单调整法"
144
- draw2_betas(model,mktidx,stkcd,betas)
145
-
146
- return betas
147
-
148
- #==============================================================================
149
- def printdf_betas(df,decimal=2):
150
- """
151
- 功能:整齐地显示数据框的内容,自动调整各列宽度
152
- """
153
- #打印时保留的小数点位数
154
- dec="%."+str(decimal)+"f"
155
- format=lambda x: dec % x
156
- df1=df.applymap(format)
157
-
158
- import pandas as pd
159
- #调整最佳列宽
160
- old_width = pd.get_option('display.max_colwidth')
161
- pd.set_option('display.max_colwidth', -1)
162
- print(df1)
163
- pd.set_option('display.max_colwidth', old_width)
164
-
165
- return
166
-
167
- if __name__=='__main__':
168
- yearlist=gen_yearlist['2010','2019']
169
- betas=get_beta_ML('AAPL','^GSPC',yearlist)
170
- betas2=get_beta_ML('BILI','^GSPC',yearlist)
171
- betas3=get_beta_ML('0700.HK','^HSI',yearlist)
172
- yearlist1=['2015','2016','2017','2018']
173
- betas3=get_beta_ML('0700.HK','^HSI',yearlist1)
174
-
175
- #==============================================================================
176
- def draw2_betas(model,scope,ticker,betas):
177
- """
178
- 功能:绘制双曲线的贝塔因子变化图
179
- 输入参数:
180
- model: 模型类型, 任意字符串(例如Merrill-Lynch Beta Adjustment)
181
- scope: 市场指数, 任意字符串(例如Standard & Poor 500)
182
- ticker:股票代码
183
- 输出:图形
184
- """
185
- #仅用作测试,完成后应注释掉
186
- #model="Merrill-Lynch Beta Adjustment"
187
- #scope="Standard & Poor 500"
188
- #ticker="AAPL"
189
-
190
- #取得股票和指数名字,对于非美股可能耗时较长
191
- """
192
- import yfinance as yf
193
- mktidx= yf.Ticker(scope)
194
- idxinfo=mktidx.info
195
- idxname=idxinfo['shortName']
196
- stkcd=yf.Ticker(ticker)
197
- stkinfo=stkcd.info
198
- stkname=stkinfo['shortName']
199
- title1="\n"+stkname+"\n"+model+"\n(Benchmark on "+idxname+")"
200
- """
201
- title1=ticker_name(ticker)+": "+model+"\n(基于"+ticker_name(scope)+")"
202
-
203
- #转换索引类型为DatetimeIndex,便于后续处理
204
- """
205
- import pandas as pd
206
- betas['Date']=betas.index
207
- betas['Date']=pd.to_datetime(betas['Date'])
208
- betas.set_index('Date',inplace=True)
209
- """
210
-
211
- #获得列明
212
- betalist=betas.columns.values.tolist()
213
- beta1=betalist[0]
214
- beta2=betalist[1]
215
-
216
- try:
217
- plt.plot(betas[beta1],label=beta1,marker='o',color='red')
218
- plt.plot(betas[beta2],label=beta2,marker='*',linewidth=2,ls='-.',color='blue')
219
- except:
220
- print(" #Error(draw2_betas): no available data for drawing!")
221
- return
222
- plt.axhline(y=1.0,color='b',linestyle=':',label='市场线')
223
- plt.title(title1,fontsize=12,fontweight='bold')
224
- plt.ylabel("贝塔系数",fontsize=12,fontweight='bold')
225
-
226
- plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
227
- plt.gca().set_facecolor('whitesmoke')
228
-
229
- #plt.xticks(rotation=30)
230
- plt.legend(loc='best')
231
-
232
- import datetime; today = datetime.date.today()
233
- plt.xlabel("数据来源:新浪,"+str(today))
234
-
235
- plt.show()
236
-
237
- return
238
-
239
- if __name__=='__main__':
240
- model="ML Beta Adjustment"
241
- scope="SP500"
242
- ticker="AAPL"
243
- draw2_betas(model,scope,ticker,betas)
244
-
245
-
246
- #==============================================================================
247
- def get_beta_SW(stkcd,mktidx,yearlist,printout=True,graph=True):
248
- """
249
- 函数功能:使用SW方法调整一只股票的CAPM模型贝塔系数
250
- 输入参数:
251
- stkcd: 股票代码
252
- mktidx: 指数代码
253
- yearlist:年度列表,列出其中期间的贝塔系数
254
- 输出数据:显示CAPM市场模型回归的beta, 以及调整后的beta系数
255
- 返回数据:CAPM市场模型回归的beta, 以及调整后的beta系数
256
- """
257
-
258
- #仅为测试用,完成后应立即注释掉
259
- #stkcd='0700.HK'
260
- #mktidx='^HSI'
261
- #yearlist=['2015','2016','2017','2018']
262
-
263
- #生成开始结束日期
264
- Y4=str(int(yearlist[0])-1)
265
- start=Y4+'-01-01'
266
- end=yearlist[-1]+'-12-31'
267
-
268
- #读取股价并准备好收益率数据
269
- try:
270
- R=prepare_capm(stkcd,mktidx,start,end)
271
- except:
272
- print(" #Error(get_beta_SW): preparing CAPM data failed!")
273
- return None
274
-
275
- if (R is None):
276
- print(" #Error(get_beta_SW): server time out")
277
- return None
278
- if (len(R) == 0):
279
- print(" #Error(get_beta_SW): server returned empty data")
280
- return None
281
-
282
- #用于保存beta(CAPM)和beta(SW)
283
- import pandas as pd
284
- betas=pd.DataFrame(columns=('Year','Beta(CAPM)','Beta(SW)'))
285
-
286
- #计算Scholes-William调整
287
- R['Close_x+1']=R['Close_x'].shift(1)
288
- R['Close_x-1']=R['Close_x'].shift(-1)
289
- R=R.dropna() #stats.linregress不接受空缺值
290
-
291
- from scipy import stats
292
- for year in yearlist:
293
- r=R[R['Year']==year]
294
- if len(r) != 0:
295
- output=stats.linregress(r['Close_x'],r['Close_y'])
296
- (beta0,alpha,r_value,p_value,std_err)=output
297
-
298
- output=stats.linregress(r['Close_x+1'],r['Close_y'])
299
- (beta1,alpha,r_value,p_value,std_err)=output
300
-
301
- output=stats.linregress(r['Close_x-1'],r['Close_y'])
302
- (beta_1,alpha,r_value,p_value,std_err)=output
303
-
304
- output=stats.linregress(r['Close_x-1'],r['Close_x'])
305
- (rou,alpha,r_value,p_value,std_err)=output
306
-
307
- beta_SW=(beta_1+beta0+beta1)/(1.0+2.0*rou)
308
- row=pd.Series({'Year':year,'Beta(CAPM)':beta0,'Beta(SW)':beta_SW})
309
- try:
310
- betas=betas.append(row,ignore_index=True)
311
- except:
312
- betas=betas._append(row,ignore_index=True)
313
-
314
- betas.set_index(["Year"], inplace=True)
315
-
316
- if printout == True: printdf_betas(betas,2)
317
- if graph == True:
318
- model="贝塔系数的Scholes-Williams调整法"
319
- draw2_betas(model,mktidx,stkcd,betas)
320
-
321
- return betas
322
-
323
-
324
- if __name__=='__main__':
325
- yearlist=gen_yearlist('2010','2019')
326
- betas_AAPL=get_beta_SW('AAPL','^GSPC',yearlist)
327
-
328
- model="SW Beta Adjustment"
329
- scope="SP500"
330
- ticker="AAPL"
331
- draw2_betas(model,scope,ticker,betas_AAPL)
332
-
333
- #==============================================================================
334
- def get_beta_dimson(stkcd,mktidx,yearlist,printout=True,graph=True):
335
- """
336
- 函数功能:使用Dimson(1979)方法调整一只股票的CAPM模型贝塔系数
337
- 输入参数:
338
- stkcd: 股票代码
339
- mktidx: 指数代码
340
- yearlist:年度列表,用于计算年度贝塔系数
341
- 输出数据:显示CAPM市场模型回归的beta, 以及调整后的beta系数
342
- 返回数据:CAPM的beta, 以及调整后的beta系数
343
- """
344
-
345
- #仅为测试用,完成后应立即注释掉
346
- #stkcd='0700.HK'
347
- #mktidx='^HSI'
348
- #yearlist=['2015','2016','2017','2018']
349
-
350
- #生成开始结束日期
351
- Y4=str(int(yearlist[0])-1)
352
- start=Y4+'-01-01'
353
- end=yearlist[-1]+'-12-31'
354
-
355
- #读取股价并准备好收益率数据
356
- try:
357
- R=prepare_capm(stkcd,mktidx,start,end)
358
- except:
359
- print(" #Error(get_beta_dimson): preparing CAPM data failed!")
360
- return None
361
-
362
- if (R is None):
363
- print(" #Error(get_beta_dimson): server did not respond")
364
- return None
365
- if (len(R) == 0):
366
- print(" #Error(get_beta_dimson): server returned empty data")
367
- return None
368
-
369
- #用于保存beta(CAPM)和beta(Dimson)
370
- import pandas as pd
371
- betas=pd.DataFrame(columns=('Year','Beta(CAPM)','Beta(Dimson)'))
372
-
373
- #计算Dimson(1979)调整
374
- R['Close_x+1']=R['Close_x'].shift(1)
375
- R['Close_x-1']=R['Close_x'].shift(-1)
376
- R=R.dropna()
377
-
378
- from scipy import stats
379
- import statsmodels.api as sm
380
- for year in yearlist:
381
- r=R[R['Year']==year]
382
- if len(r) != 0:
383
- output=stats.linregress(r['Close_x'],r['Close_y'])
384
- (beta_capm,alpha,r_value,p_value,std_err)=output
385
-
386
- #三个解释变量
387
- RX=r[['Close_x-1','Close_x','Close_x+1']]
388
- X1=sm.add_constant(RX) #要求回归具有截距项
389
- Y=r['Close_y']
390
- model = sm.OLS(Y,X1) #定义回归模型,X1为多元矩阵
391
- results = model.fit() #进行OLS回归
392
-
393
- (alpha,beta_1,beta0,beta1)=results.params #提取回归系数
394
- beta_dimson=beta_1+beta0+beta1
395
-
396
- row=pd.Series({'Year':year,'Beta(CAPM)':beta_capm, \
397
- 'Beta(Dimson)':beta_dimson})
398
- try:
399
- betas=betas.append(row,ignore_index=True)
400
- except:
401
- betas=betas._append(row,ignore_index=True)
402
-
403
- betas.set_index(["Year"], inplace=True)
404
-
405
- if printout == True: printdf_betas(betas,2)
406
- if graph == True:
407
- model="贝塔系数的Dimson调整法"
408
- draw2_betas(model,mktidx,stkcd,betas)
409
-
410
- return betas
411
-
412
- if __name__=='__main__':
413
- yearlist=gen_yearlist('2010','2019')
414
- betas_MSFT=get_beta_dimson('MSFT','^GSPC',yearlist)
415
-
416
- model="Dimson Beta Adjustment"
417
- scope="SP500"
418
- ticker="MSFT"
419
- draw2_betas(model,scope,ticker,betas_MSFT)
420
-
421
- betas_MSFT2=get_beta_dimson('MSFT','^DJI',yearlist)
422
-
423
- model="Dimson Beta Adjustment"
424
- scope="DJIA"
425
- ticker="MSFT"
426
- draw2_betas(model,scope,ticker,betas_MSFT2)
427
-
428
- #==============================================================================
429
- #==============================================================================
430
- #==============================================================================
431
-
432
- def prepare_hamada_patch_is(ticker):
433
- """
434
- 在雅虎财经接口获取利润表数据失败时,改从tushare获取
435
- 获取的项目:所得税费用,税前利润
436
- """
437
- import pandas as pd
438
- import tushare as ts
439
- pro=init_ts()
440
-
441
- #财报期限
442
- import datetime
443
- today=datetime.date.today()
444
- thisyear=today.year
445
- fouryrsago=thisyear-4-2
446
- fromdate=str(fouryrsago)+"0101"
447
- todate=str(thisyear)+"1231"
448
-
449
- #利润表
450
- ticker1=ticker.upper()
451
- suffix=ticker1[-3:]
452
- if suffix in ['.SS']:
453
- ticker1=ticker1.replace('.SS','.SH',1)
454
- if not (suffix in ['.SS','.SZ']):
455
- print(" #Error(prepare_hamada_patch_is): no financials available for",ticker)
456
- return None
457
-
458
- fis=pro.income(ts_code=ticker1,start_date=fromdate,end_date=todate)
459
- #去除非年报
460
- stripfmt=lambda x:(x.strip())[-4:]
461
- fis['yrtag']=fis['end_date'].apply(stripfmt)
462
- fis1=fis[fis['report_type']=='1'] #合并报表
463
- fis2=fis1[fis1['yrtag']=="1231"] #年报
464
- fis3=fis2.drop_duplicates(subset=['end_date'],keep='first') #去重
465
- fis4=fis3 #保留最新4年,与yfinance结果保持一致
466
- fis4.sort_values(by=['end_date'],ascending=True,inplace=True) #升序排序
467
-
468
- #重建索引
469
- fis4['date']=pd.to_datetime(fis4['end_date'])
470
- fis4.set_index('date',inplace=True)
471
-
472
- #提取需要的项目:所得税费用,税前利润
473
- fis4['Income Tax Expense']=fis4['income_tax']
474
- fis4['Income Before Tax']=fis4['total_profit']
475
- fis5=fis4[['Income Tax Expense','Income Before Tax']].copy()
476
-
477
- return fis5
478
-
479
- if __name__=='__main__':
480
- ticker="600519.SS"
481
-
482
-
483
- #==============================================================================
484
- def prepare_hamada_patch_bs(ticker):
485
- """
486
- 在雅虎财经接口获取资产负债表数据失败时,改从tushare获取
487
- 获取的项目:负债合计,股东权益合计
488
- """
489
- import pandas as pd
490
- import tushare as ts
491
- pro=init_ts()
492
-
493
- #财报期限
494
- import datetime
495
- today=datetime.date.today()
496
- thisyear=today.year
497
- fouryrsago=thisyear-4-2
498
- fromdate=str(fouryrsago)+"0101"
499
- todate=str(thisyear)+"1231"
500
-
501
- #利润表
502
- ticker1=ticker.upper()
503
- suffix=ticker1[-3:]
504
- if suffix in ['.SS']:
505
- ticker1=ticker1.replace('.SS','.SH',1)
506
- if not (suffix in ['.SS','.SZ']):
507
- print(" #Error(prepare_hamada_patch_bs): no financials available for",ticker)
508
- return None
509
-
510
- fis=pro.balancesheet(ts_code=ticker1,start_date=fromdate,end_date=todate)
511
- #去除非年报
512
- stripfmt=lambda x:(x.strip())[-4:]
513
- fis['yrtag']=fis['end_date'].apply(stripfmt)
514
- fis1=fis[fis['report_type']=='1'] #合并报表
515
- fis2=fis1[fis1['yrtag']=="1231"] #年报
516
- fis3=fis2.drop_duplicates(subset=['end_date'],keep='first') #去重
517
- fis4=fis3 #保留最新4年,与yfinance结果保持一致
518
- fis4.sort_values(by=['end_date'],ascending=True,inplace=True) #升序排序
519
-
520
- #重建索引
521
- fis4['date']=pd.to_datetime(fis4['end_date'])
522
- fis4.set_index('date',inplace=True)
523
-
524
- #提取需要的项目:所得税费用,税前利润
525
- fis4['Total Liab']=fis4['total_liab']
526
- fis4['Total Stockholder Equity']=fis4['total_hldr_eqy_inc_min_int']
527
- fis5=fis4[['Total Liab','Total Stockholder Equity']].copy()
528
-
529
- return fis5
530
-
531
- if __name__=='__main__':
532
- ticker="600519.SS"
533
-
534
-
535
- #==============================================================================
536
- if __name__ =="__main__":
537
- ticker='0700.HK'
538
-
539
- def prepare_hamada_yearly_yahoo(ticker):
540
- """
541
- 功能:从雅虎财经下载财报数据,计算hamada模型需要的因子
542
- 局限:只能下载最近4年的财报
543
- 输入:股票代码
544
- 输出:
545
- 寻找数据项:所得税费用,税前利润,计算实际税率;
546
- 总负债,所有者权益,计算财务杠杆
547
- 数据框, CFLB,贝塔Lev对贝塔Unlev的倍数
548
- 年度列表
549
- """
550
- print("... Searching for financial information, please wait ...")
551
- import yfinance as yf
552
- stock=yf.Ticker(ticker)
553
-
554
- #利润表
555
- try:
556
- is0=stock.financials
557
- is1=is0.T
558
- except:
559
- is1=prepare_hamada_patch_is(ticker)
560
-
561
- if len(is0)==0: #yfinance失效
562
- is1=prepare_hamada_patch_is(ticker)
563
-
564
- is1['income tax expense']=is1['Income Tax Expense'].astype('float')
565
- is1['income before tax']=is1['Income Before Tax'].astype('float')
566
- is1['tax rate']=is1['income tax expense']/is1['income before tax']
567
-
568
- import pandas as pd
569
- is1['date']=pd.to_datetime(is1.index)
570
- is1.set_index(["date"], inplace=True)
571
- is2=is1.sort_index(axis=0,ascending=True)
572
- tax=pd.DataFrame(is2['tax rate'])
573
-
574
- #资产负债表
575
- try:
576
- bs0=stock.balance_sheet
577
- bs1=bs0.T
578
- except:
579
- bs1=prepare_hamada_patch_bs(ticker)
580
- if len(bs0)==0: #yfinance失效
581
- bs1=prepare_hamada_patch_bs(ticker)
582
-
583
- bs1['total liabilities']=bs1['Total Liab'].astype('float')
584
- bs1['total equities']=bs1["Total Stockholder Equity"].astype('float')
585
- bs1['lev ratio']=bs1['total liabilities']/bs1['total equities']
586
- bs1['date']=pd.to_datetime(bs1.index)
587
- bs1.set_index(['date'],inplace=True)
588
- bs2=bs1.sort_index(axis=0,ascending=True)
589
- lev=pd.DataFrame(bs2['lev ratio'])
590
-
591
- #合成,计算
592
- fac=pd.merge(lev,tax,how='left',left_index=True,right_index=True)
593
- fac['CFLB%']=1/(1+(1/fac['lev ratio'])*(1/abs(1-fac['tax rate'])))*100
594
- fac['lev_unlev']=1+fac['lev ratio']*(1-fac['tax rate'])
595
- fac['year']=fac.index.strftime("%Y")
596
- yearlist=list(fac['year'])
597
-
598
- return fac,yearlist
599
-
600
- if __name__ =="__main__":
601
- ticker="600519.SS"
602
- ticker="AAPL"
603
- ticker='000002.SZ'
604
- fac,yl=prepare_hamada_yearly_yahoo("MSFT")
605
-
606
- #==============================================================================
607
- if __name__ =="__main__":
608
- stkcd='0700.HK'
609
- mktidx='^HSI'
610
- yearlist=['2015','2016','2017','2018']
611
-
612
-
613
- def get_beta_hamada(stkcd,mktidx,yearlist,printout=True,graph=True):
614
- """
615
- 函数功能:使用Hamada(1972)方法,计算无杠杆贝塔系数
616
- 输入参数:
617
- stkcd: 股票代码
618
- mktidx: 指数代码
619
- yearlist:年度列表,用于计算年度贝塔系数
620
- 输出数据:显示CAPM市场模型回归的beta, 以及调整后的beta系数
621
- 返回数据:CAPM的beta, Hamada beta,CFLB(债务融资对CAPM beta系数的贡献率)
622
- """
623
-
624
- #计算Hamada参数,并返回可用的年度列表
625
- fac,yearlist=prepare_hamada_yearly_yahoo(stkcd)
626
- if fac is None:
627
- print("#Error(get_beta_hamada): no financial info available for",stkcd)
628
- return None
629
-
630
- #生成开始结束日期
631
- Y4=str(int(yearlist[0])-1)
632
- start=Y4+'-01-01'
633
- end=yearlist[-1]+'-12-31'
634
-
635
- #读取股价并准备好收益率数据
636
- try:
637
- R=prepare_capm(stkcd,mktidx,start,end)
638
- except:
639
- print(" #Error(get_beta_hamada): preparing CAPM data failed!")
640
- print("Info:",stkcd,mktidx,yearlist)
641
- return None
642
-
643
- if (R is None):
644
- print(" #Error(get_beta_hamada): server time out")
645
- return None
646
- if (len(R) == 0):
647
- print(" #Error(get_beta_hamada): server returned empty data")
648
- return None
649
- R=R.dropna()
650
-
651
- #用于保存beta(CAPM)和beta(Hamada)
652
- import pandas as pd
653
- betas=pd.DataFrame(columns=('Year','Beta(CAPM)','Beta(Unlevered)','CFLB%'))
654
-
655
- from scipy import stats
656
- for year in yearlist:
657
- r=R[R['Year']==year]
658
- if len(r) != 0:
659
- output=stats.linregress(r['Close_x'],r['Close_y'])
660
- (beta_capm,alpha,r_value,p_value,std_err)=output
661
-
662
- #Hamada无杠杆因子
663
- lev_unlev=fac[fac['year']==year]['lev_unlev'].values[0]
664
- beta_hamada=beta_capm/lev_unlev
665
- cflb=fac[fac['year']==year]['CFLB%'].values[0]
666
-
667
- row=pd.Series({'Year':year,'Beta(CAPM)':beta_capm, \
668
- 'Beta(Unlevered)':beta_hamada,'CFLB%':cflb})
669
- try:
670
- betas=betas.append(row,ignore_index=True)
671
- except:
672
- betas=betas._append(row,ignore_index=True)
673
-
674
- betas.set_index(["Year"], inplace=True)
675
-
676
- if printout == True:
677
- printdf_betas(betas,2)
678
- if graph == True:
679
- model="Hamada Unlevered Beta"
680
- draw2_betas(model,mktidx,stkcd,betas)
681
-
682
- #绘制CFLB
683
- if len(betas)<=1: return betas
684
-
685
- plt.plot(betas['CFLB%'],marker='o',color='red',lw=3)
686
-
687
- bmin=min(list(betas['CFLB%']))
688
- bmax=max(list(betas['CFLB%']))
689
- axhmin=(int(bmin/10)+1)*10
690
- if bmin <= axhmin <= bmax:
691
- plt.axhline(y=axhmin,color='b',linestyle=':')
692
- axhmax=(int(bmax/10))*10
693
- if bmin <= axhmax <= bmax:
694
- plt.axhline(y=axhmax,color='b',linestyle=':')
695
-
696
- title1=stkcd+": Contribution of Financial Leverage to Beta"+ \
697
- "\n(Benchmark on Market Index "+mktidx+")"
698
- plt.title(title1,fontsize=12,fontweight='bold')
699
- plt.ylabel("CFLB %",fontsize=12,fontweight='bold')
700
- #plt.legend(loc='best')
701
- plt.grid(ls='-.')
702
- #查看可用的样式:print(plt.style.available)
703
- #样式:bmh(好),classic,ggplot(好,图大),tableau-colorblind10,
704
- #样式:seaborn-bright,seaborn-poster,seaborn-whitegrid
705
- plt.style.use('bmh')
706
-
707
- plt.gca().set_facecolor('whitesmoke')
708
- plt.show()
709
-
710
- return betas
711
-
712
- if __name__=='__main__':
713
- stkcd='000002.SZ'
714
- mktidx='000001.SS'
715
- yearlist=gen_yearlist('2010','2019')
716
- betas1=get_beta_hamada('MSFT','^GSPC',yearlist)
717
-
718
- #==============================================================================
719
- #==============================================================================
720
- #==============================================================================
721
- def draw_hamada_factors(stkcd,mktidx,betas):
722
- """
723
- 功能:绘制Hamada模型因子的变化折线图,企业实际所得税税率,资产负债率,CFLB
724
- """
725
- if len(betas)<=1: return
726
-
727
- #计算资产负债率:由 D/E到 D/(A=D+E)
728
- betas['Debt/Assets%']=1/(1+1/(betas['Debt Ratio%']/100))*100
729
-
730
- #fig=plt.figure(figsize=(12.8,6.4))
731
- fig=plt.figure()
732
- ax1=fig.add_subplot(111)
733
- ax1.plot(betas['CFLB%'],marker='o',color='green',lw=3,label='CFLB%')
734
- ax1.plot(betas['Debt/Assets%'],marker='o',color='red',lw=2,ls='--', \
735
- label='Debt/Assets%')
736
- ax1.set_ylabel("CFLB%, Debt/Assets%")
737
- ax1.legend(loc='upper left')
738
- ax1.set_xticklabels(betas.index,rotation=45)
739
-
740
- ax2=ax1.twinx()
741
- ax2.plot(betas['Tax Rate%'],marker='o',color='black',lw=2,ls='-.', \
742
- label='Income Tax%')
743
- ax2.set_ylabel('Income Tax%')
744
- ax2.legend(loc='lower right')
745
- ax2.set_xticklabels(betas.index,rotation=45)
746
-
747
- title1=stkcd+": Impact of Hamada Factors on Beta"+ \
748
- "\n(Benchmark on Market Index "+mktidx+")"
749
- plt.title(title1,fontsize=12,fontweight='bold')
750
- plt.style.use('ggplot')
751
-
752
- plt.gca().set_facecolor('whitesmoke')
753
- plt.show()
754
-
755
- return
756
- #==============================================================================
757
- #==============================================================================
758
- #==============================================================================
759
- if __name__ =="__main__":
760
- stkcd='0700.HK'
761
- stkcd='AAPL'
762
- stkcd='GS'
763
- stkcd='BA'
764
- mktidx='^HSI'
765
- stkcd='000002.SZ'
766
- stkcd='600606.SS'
767
- mktidx='000001.SS'
768
-
769
- def get_beta_hamada2(stkcd,mktidx,printout=True,graph=True):
770
- """
771
- 函数功能:使用Hamada(1972)方法,计算无杠杆贝塔系数,绘图
772
- 输入参数:
773
- stkcd: 股票代码
774
- mktidx: 指数代码
775
- 输出数据:显示CAPM市场模型回归的beta, 以及调整后的beta系数
776
- 返回数据:CAPM的beta, Hamada beta,CFLB(债务融资对CAPM beta系数的贡献率)
777
- """
778
-
779
- #计算Hamada参数,并返回可用的年度列表
780
- fac=prepare_hamada_yahoo(stkcd)
781
- if fac is None:
782
- print(" #Error(get_beta_hamada2): no financial info available for",stkcd)
783
- return None
784
- datecvt=lambda x: str(x.strftime("%Y-%m-%d"))
785
- fac['fsdate']=fac.index.date
786
- fac['fsdate']=fac['fsdate'].apply(datecvt)
787
-
788
- #生成开始结束日期
789
- end0=fac.index[-1]
790
- end=date_adjust(end0,adjust=14)
791
- start0=fac.index[0]
792
- start=date_adjust(start0,adjust=-366)
793
-
794
- #读取股价并准备好收益率数据
795
- try:
796
- R=prepare_capm(stkcd,mktidx,start,end)
797
- except:
798
- print(" #Error(get_beta_hamada2): preparing CAPM data failed for",stkcd,mktidx)
799
- return None
800
- if (R is None) or (len(R) == 0):
801
- print(" #Error(get_beta_hamada2): retrieved empty info in CAPM for",stkcd,mktidx)
802
- return None
803
- R=R.dropna()
804
- R['prcdate']=R.index.date
805
- R['prcdate']=R['prcdate'].apply(datecvt)
806
-
807
- #用于保存beta(CAPM)和beta(Hamada)
808
- import pandas as pd
809
- betas=pd.DataFrame(columns=('Date','Beta(CAPM)','Beta(Unlevered)','CFLB%'))
810
- fsdatelist=list(fac['fsdate'])
811
- from scipy import stats
812
- for d in fsdatelist:
813
- dstart=date_adjust(d,adjust=-365)
814
- r=R[R['prcdate'] >= dstart]
815
- r=r[r['prcdate'] <= d]
816
- if len(r) != 0:
817
- output=stats.linregress(r['Close_x'],r['Close_y'])
818
- (beta_capm,alpha,r_value,p_value,std_err)=output
819
-
820
- #Hamada无杠杆因子
821
- lev_unlev=fac[fac['fsdate']==d]['lev_unlev'].values[0]
822
- beta_hamada=beta_capm/lev_unlev
823
- cflb=fac[fac['fsdate']==d]['CFLB%'].values[0]
824
-
825
- row=pd.Series({'Date':d,'Beta(CAPM)':beta_capm, \
826
- 'Beta(Unlevered)':beta_hamada,'CFLB%':cflb})
827
- try:
828
- betas=betas.append(row,ignore_index=True)
829
- except:
830
- betas=betas._append(row,ignore_index=True)
831
- betas.set_index(["Date"], inplace=True)
832
-
833
- #打印
834
- if printout == True:
835
- printdf_betas(betas,2)
836
-
837
- #绘图:两种杠杆对比图,CFLB图
838
- if graph == True:
839
-
840
- #绘制Hamada对比图
841
- model="滨田无杠杆贝塔系数"
842
- draw2_betas(model,mktidx,stkcd,betas)
843
-
844
- #绘制CFLB单图
845
- if len(betas)<=1:
846
- print(" #Notice(get_beta_hamada2): too few info for graphics of",stkcd)
847
- return betas
848
-
849
- plt.plot(betas['CFLB%'],marker='o',color='red',lw=3,label='CFLB%')
850
-
851
- #绘制均值虚线
852
- cflb_avg=betas['CFLB%'].mean()
853
- cflb_avg_txt='均值: '+str(round(cflb_avg,1))+'%'
854
- plt.axhline(y=cflb_avg,color='b',linestyle=':',label=cflb_avg_txt)
855
-
856
- title1=ticker_name(stkcd)+": 财务杠杆对于贝塔系数的贡献度(CFLB)"
857
- #plt.title(title1,fontsize=12,fontweight='bold')
858
- plt.title(title1)
859
- #plt.ylabel("CFLB %",fontsize=12,fontweight='bold')
860
- footnote="注: 基于"+ticker_name(mktidx)
861
-
862
- import datetime; today = datetime.date.today()
863
- footnote2="\n数据来源: 新浪,"+str(today)
864
- plt.xlabel(footnote+footnote2)
865
-
866
- plt.grid(ls='-.')
867
- #查看可用的样式:print(plt.style.available)
868
- #样式:bmh(好),classic,ggplot(好,图大),tableau-colorblind10,
869
- #样式:seaborn-bright,seaborn-poster,seaborn-whitegrid
870
- plt.style.use('bmh')
871
- plt.gcf().autofmt_xdate() # 优化标注(自动倾斜)
872
- plt.gca().set_facecolor('whitesmoke')
873
- plt.legend(loc='best')
874
- plt.show(); plt.close()
875
-
876
- #绘制CFLB+财务杠杆双图
877
- df1=betas; df2=fac.set_index(["fsdate"])
878
- ticker1=ticker2=stkcd
879
- colname1='CFLB%'; colname2='lev ratio'
880
- label1='CFLB%'; label2='财务杠杆'
881
- titletxt=ticker_name(stkcd)+": CFLB与财务杠杆之间的关系"
882
- footnote='注: 这里的财务杠杆使用的是负债/所有者权益'
883
-
884
- plot_line2_twinx(df1,ticker1,colname1,label1,df2,ticker2,colname2,label2, \
885
- titletxt,footnote+footnote2)
886
-
887
- #绘制CFLB+税率双图
888
- #df1=betas; df2=fac.set_index(["fsdate"])
889
- #ticker1=ticker2=stkcd
890
- colname1='CFLB%'; colname2='tax rate'
891
- label1='CFLB%'; label2='实际税率'
892
- titletxt=ticker_name(stkcd)+": CFLB与税率之间的关系"
893
- footnote='注: 这里使用的是实际税率'
894
-
895
- plot_line2_twinx(df1,ticker1,colname1,label1,df2,ticker2,colname2,label2, \
896
- titletxt,footnote+footnote2)
897
-
898
- return betas
899
-
900
- if __name__=='__main__':
901
- betas1=get_beta_hamada2('MSFT','^GSPC')
902
-
903
- #==============================================================================
904
- if __name__ =="__main__":
905
- ticker='0700.HK'
906
- ticker="600519.SS"
907
- ticker="AAPL"
908
- ticker="BA"
909
-
910
- def prepare_hamada_yahoo(ticker):
911
- """
912
- 功能:从雅虎财经下载财报数据,计算hamada模型需要的因子
913
- 局限:只能下载最近4年+4个季度的财报
914
- 输入:股票代码
915
- 输出:
916
- 寻找数据项:所得税费用,税前利润,计算实际税率;
917
- 总负债,所有者权益,计算财务杠杆
918
- 数据框, CFLB,贝塔Lev对贝塔Unlev的倍数
919
- 年度列表
920
- """
921
- print("...Searching for financial information, please wait ...")
922
-
923
- #利润表
924
- try:
925
- import siat.financial_statements as fs
926
- is1=fs.get_income_statements(ticker)
927
- except:
928
- print(" #Error(prepare_hamada_yahoo): failed to retrieve income info of",ticker)
929
- return None
930
- if (is1 is None) or (len(is1)==0):
931
- print(" #Error(prepare_hamada_yahoo): retrieve empty income info of",ticker)
932
- return None
933
-
934
- is1['tax rate']=is1['TaxRateForCalcs'].astype('float')
935
- is1['ticker']=is1.index
936
- is1['date']=is1['asOfDate']
937
- is1.set_index(["date"], inplace=True)
938
- is1.sort_index(axis=0,ascending=True,inplace=True)
939
-
940
- import pandas as pd
941
- tax=pd.DataFrame(is1['tax rate'])
942
-
943
- #资产负债表
944
- try:
945
- bs1=fs.get_balance_sheet(ticker)
946
- except:
947
- print(" #Error(prepare_hamada_yahoo): failed to retrieve balance sheet of",ticker)
948
- return None
949
- if (bs1 is None) or (len(bs1)==0):
950
- print(" #Error(prepare_hamada_yahoo): retrieve empty balance sheet of",ticker)
951
- return None
952
-
953
- bs1['lev ratio']=bs1['TotalLiabilities']/bs1['TotalEquities']
954
- bs1['date']=bs1['asOfDate']
955
- bs1.set_index(['date'],inplace=True)
956
- bs1.sort_index(axis=0,ascending=True,inplace=True)
957
- lev=pd.DataFrame(bs1['lev ratio'])
958
-
959
- #合成,计算
960
- fac=pd.merge(lev,tax,how='left',left_index=True,right_index=True)
961
- fac['CFLB%']=1/(1+(1/fac['lev ratio'])*(1/abs(1-fac['tax rate'])))*100
962
- fac['lev_unlev']=1+fac['lev ratio']*(1-fac['tax rate'])
963
-
964
- return fac
965
-
966
- if __name__ =="__main__":
967
- fac,yl=prepare_hamada_yahoo("MSFT")
968
-
969
- #==============================================================================
970
-
971
- if __name__=='__main__':
972
- tickers = ['000858.SZ','600779.SS','000596.SZ','603589.SS']
973
- market_index="000001.SS"
974
-
975
- def compare_mhamada(tickers,market_index="000001.SS"):
976
- """
977
- 功能:计算多只股票的财务杠杆对贝塔系数贡献度比率CFLB,并绘图对比
978
- """
979
- #检查tickers是否为列表且不少于两只股票
980
-
981
- #隐藏print输出
982
- import os,sys
983
- class HiddenPrints:
984
- def __enter__(self):
985
- self._original_stdout = sys.stdout
986
- sys.stdout = open(os.devnull, 'w')
987
-
988
- def __exit__(self, exc_type, exc_val, exc_tb):
989
- sys.stdout.close()
990
- sys.stdout = self._original_stdout
991
-
992
- import pandas as pd
993
- df=pd.DataFrame()
994
- print("Starting to retrieve and calculate Hamada ratios, please wait ......")
995
- for t in tickers:
996
-
997
- with HiddenPrints():
998
- df_tmp=get_beta_hamada2(t,market_index,printout=False,graph=False)
999
-
1000
- if df_tmp is None:
1001
- print(" Warning(compare_mhamada): data not available for",t)
1002
- continue
1003
- else:
1004
- dft=df_tmp[['CFLB%']]
1005
- dft.rename(columns={'CFLB%':ticker_name(t)},inplace=True)
1006
-
1007
- if len(df)==0:
1008
- #第一个
1009
- df=dft
1010
- else:
1011
- df=pd.merge(df,dft,left_index=True,right_index=True)
1012
-
1013
- if len(df)==0:
1014
- print(" Warning(compare_mhamada): no data available for",tickers)
1015
- return None
1016
-
1017
- #绘制多条曲线
1018
- import datetime; today = datetime.date.today()
1019
-
1020
- lang=check_language()
1021
- if lang == 'English':
1022
-
1023
- y_label='CFLB%'
1024
- footnote0='CFLB: Contribution of Financial Leverage to Beta'
1025
- x_label=footnote0+'\n'+"Source: sina/stooq, "+str(today)
1026
- title_txt="Compare Multiple CFLB"
1027
- else:
1028
- y_label='CFLB%'
1029
- footnote0='CFLB:财务杠杆对贝塔系数的贡献度'
1030
- x_label=footnote0+'\n'+"数据来源: 新浪/stooq,"+str(today)
1031
- title_txt="比较多只证券的CFLB指标"
1032
-
1033
- draw_lines(df,y_label,x_label,axhline_value=0,axhline_label='', \
1034
- title_txt=title_txt,data_label=False)
1035
-
1036
- return df
1037
-
1038
- if __name__=='__main__':
1039
- tickers = ['000858.SZ','600779.SS','000596.SZ','603589.SS','000001.SS']
1040
- df=compare_mhamada(tickers,market_index)
1041
-
1042
- #==============================================================================
1043
- #==============================================================================
1044
- #==============================================================================
1045
- #==============================================================================
1046
- #==============================================================================
1047
-
1048
-
1049
-
1050
-
1051
-
1052
-
1053
-
1054
-
1055
-
1056
-
1057
-
1058
-