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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. siat/__init__.py +0 -0
  2. siat/allin.py +0 -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 +0 -0
  13. siat/compare_cross.py +0 -0
  14. siat/copyrights.py +0 -0
  15. siat/cryptocurrency.py +0 -0
  16. siat/economy.py +0 -0
  17. siat/economy2.py +0 -0
  18. siat/esg.py +0 -0
  19. siat/event_study.py +0 -0
  20. siat/exchange_bond_china.pickle +0 -0
  21. siat/fama_french.py +0 -0
  22. siat/fin_stmt2_yahoo.py +0 -0
  23. siat/financial_base.py +0 -0
  24. siat/financial_statements.py +0 -0
  25. siat/financials.py +0 -0
  26. siat/financials2.py +0 -0
  27. siat/financials_china.py +0 -0
  28. siat/financials_china2.py +0 -0
  29. siat/fund.py +0 -0
  30. siat/fund_china.pickle +0 -0
  31. siat/fund_china.py +0 -0
  32. siat/future_china.py +0 -0
  33. siat/google_authenticator.py +0 -0
  34. siat/grafix.py +0 -0
  35. siat/holding_risk.py +0 -0
  36. siat/luchy_draw.py +0 -0
  37. siat/market_china.py +0 -0
  38. siat/markowitz.py +0 -0
  39. siat/markowitz2.py +0 -0
  40. siat/markowitz2_20250704.py +0 -0
  41. siat/markowitz2_20250705.py +0 -0
  42. siat/markowitz_simple.py +0 -0
  43. siat/ml_cases.py +0 -0
  44. siat/ml_cases_example.py +0 -0
  45. siat/option_china.py +0 -0
  46. siat/option_pricing.py +0 -0
  47. siat/other_indexes.py +0 -0
  48. siat/risk_adjusted_return.py +0 -0
  49. siat/risk_adjusted_return2.py +0 -0
  50. siat/risk_evaluation.py +0 -0
  51. siat/risk_free_rate.py +0 -0
  52. siat/sector_china.py +0 -0
  53. siat/security_price2.py +0 -0
  54. siat/security_prices.py +40 -2
  55. siat/security_trend.py +0 -0
  56. siat/security_trend2.py +0 -0
  57. siat/stock.py +0 -0
  58. siat/stock_advice_linear.py +0 -0
  59. siat/stock_base.py +0 -0
  60. siat/stock_china.py +0 -0
  61. siat/stock_info.pickle +0 -0
  62. siat/stock_prices_kneighbors.py +0 -0
  63. siat/stock_prices_linear.py +0 -0
  64. siat/stock_profile.py +0 -0
  65. siat/stock_technical.py +0 -0
  66. siat/stooq.py +0 -0
  67. siat/transaction.py +0 -0
  68. siat/translate.py +0 -0
  69. siat/valuation.py +0 -0
  70. siat/valuation_china.py +0 -0
  71. siat/var_model_validation.py +0 -0
  72. siat/yf_name.py +0 -0
  73. {siat-3.10.132.dist-info/licenses → siat-3.10.133.dist-info}/LICENSE +0 -0
  74. {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/METADATA +232 -235
  75. siat-3.10.133.dist-info/RECORD +78 -0
  76. {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/WHEEL +1 -1
  77. {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/top_level.txt +0 -1
  78. build/lib/build/lib/siat/__init__.py +0 -75
  79. build/lib/build/lib/siat/allin.py +0 -137
  80. build/lib/build/lib/siat/assets_liquidity.py +0 -915
  81. build/lib/build/lib/siat/beta_adjustment.py +0 -1058
  82. build/lib/build/lib/siat/beta_adjustment_china.py +0 -548
  83. build/lib/build/lib/siat/blockchain.py +0 -143
  84. build/lib/build/lib/siat/bond.py +0 -2900
  85. build/lib/build/lib/siat/bond_base.py +0 -992
  86. build/lib/build/lib/siat/bond_china.py +0 -100
  87. build/lib/build/lib/siat/bond_zh_sina.py +0 -143
  88. build/lib/build/lib/siat/capm_beta.py +0 -783
  89. build/lib/build/lib/siat/capm_beta2.py +0 -887
  90. build/lib/build/lib/siat/common.py +0 -5360
  91. build/lib/build/lib/siat/compare_cross.py +0 -642
  92. build/lib/build/lib/siat/copyrights.py +0 -18
  93. build/lib/build/lib/siat/cryptocurrency.py +0 -667
  94. build/lib/build/lib/siat/economy.py +0 -1471
  95. build/lib/build/lib/siat/economy2.py +0 -1853
  96. build/lib/build/lib/siat/esg.py +0 -536
  97. build/lib/build/lib/siat/event_study.py +0 -815
  98. build/lib/build/lib/siat/fama_french.py +0 -1521
  99. build/lib/build/lib/siat/fin_stmt2_yahoo.py +0 -982
  100. build/lib/build/lib/siat/financial_base.py +0 -1160
  101. build/lib/build/lib/siat/financial_statements.py +0 -598
  102. build/lib/build/lib/siat/financials.py +0 -2339
  103. build/lib/build/lib/siat/financials2.py +0 -1278
  104. build/lib/build/lib/siat/financials_china.py +0 -4433
  105. build/lib/build/lib/siat/financials_china2.py +0 -2212
  106. build/lib/build/lib/siat/fund.py +0 -629
  107. build/lib/build/lib/siat/fund_china.py +0 -3307
  108. build/lib/build/lib/siat/future_china.py +0 -551
  109. build/lib/build/lib/siat/google_authenticator.py +0 -47
  110. build/lib/build/lib/siat/grafix.py +0 -3636
  111. build/lib/build/lib/siat/holding_risk.py +0 -867
  112. build/lib/build/lib/siat/luchy_draw.py +0 -638
  113. build/lib/build/lib/siat/market_china.py +0 -1168
  114. build/lib/build/lib/siat/markowitz.py +0 -2363
  115. build/lib/build/lib/siat/markowitz2.py +0 -3150
  116. build/lib/build/lib/siat/markowitz2_20250704.py +0 -2969
  117. build/lib/build/lib/siat/markowitz2_20250705.py +0 -3158
  118. build/lib/build/lib/siat/markowitz_simple.py +0 -373
  119. build/lib/build/lib/siat/ml_cases.py +0 -2291
  120. build/lib/build/lib/siat/ml_cases_example.py +0 -60
  121. build/lib/build/lib/siat/option_china.py +0 -3069
  122. build/lib/build/lib/siat/option_pricing.py +0 -1925
  123. build/lib/build/lib/siat/other_indexes.py +0 -409
  124. build/lib/build/lib/siat/risk_adjusted_return.py +0 -1576
  125. build/lib/build/lib/siat/risk_adjusted_return2.py +0 -1900
  126. build/lib/build/lib/siat/risk_evaluation.py +0 -2218
  127. build/lib/build/lib/siat/risk_free_rate.py +0 -351
  128. build/lib/build/lib/siat/sector_china.py +0 -4140
  129. build/lib/build/lib/siat/security_price2.py +0 -727
  130. build/lib/build/lib/siat/security_prices.py +0 -3408
  131. build/lib/build/lib/siat/security_trend.py +0 -402
  132. build/lib/build/lib/siat/security_trend2.py +0 -646
  133. build/lib/build/lib/siat/stock.py +0 -4284
  134. build/lib/build/lib/siat/stock_advice_linear.py +0 -934
  135. build/lib/build/lib/siat/stock_base.py +0 -26
  136. build/lib/build/lib/siat/stock_china.py +0 -2095
  137. build/lib/build/lib/siat/stock_prices_kneighbors.py +0 -910
  138. build/lib/build/lib/siat/stock_prices_linear.py +0 -386
  139. build/lib/build/lib/siat/stock_profile.py +0 -707
  140. build/lib/build/lib/siat/stock_technical.py +0 -3305
  141. build/lib/build/lib/siat/stooq.py +0 -74
  142. build/lib/build/lib/siat/transaction.py +0 -347
  143. build/lib/build/lib/siat/translate.py +0 -5183
  144. build/lib/build/lib/siat/valuation.py +0 -1378
  145. build/lib/build/lib/siat/valuation_china.py +0 -2076
  146. build/lib/build/lib/siat/var_model_validation.py +0 -444
  147. build/lib/build/lib/siat/yf_name.py +0 -811
  148. build/lib/siat/__init__.py +0 -75
  149. build/lib/siat/allin.py +0 -137
  150. build/lib/siat/assets_liquidity.py +0 -915
  151. build/lib/siat/beta_adjustment.py +0 -1058
  152. build/lib/siat/beta_adjustment_china.py +0 -548
  153. build/lib/siat/blockchain.py +0 -143
  154. build/lib/siat/bond.py +0 -2900
  155. build/lib/siat/bond_base.py +0 -992
  156. build/lib/siat/bond_china.py +0 -100
  157. build/lib/siat/bond_zh_sina.py +0 -143
  158. build/lib/siat/capm_beta.py +0 -783
  159. build/lib/siat/capm_beta2.py +0 -887
  160. build/lib/siat/common.py +0 -5360
  161. build/lib/siat/compare_cross.py +0 -642
  162. build/lib/siat/copyrights.py +0 -18
  163. build/lib/siat/cryptocurrency.py +0 -667
  164. build/lib/siat/economy.py +0 -1471
  165. build/lib/siat/economy2.py +0 -1853
  166. build/lib/siat/esg.py +0 -536
  167. build/lib/siat/event_study.py +0 -815
  168. build/lib/siat/fama_french.py +0 -1521
  169. build/lib/siat/fin_stmt2_yahoo.py +0 -982
  170. build/lib/siat/financial_base.py +0 -1160
  171. build/lib/siat/financial_statements.py +0 -598
  172. build/lib/siat/financials.py +0 -2339
  173. build/lib/siat/financials2.py +0 -1278
  174. build/lib/siat/financials_china.py +0 -4433
  175. build/lib/siat/financials_china2.py +0 -2212
  176. build/lib/siat/fund.py +0 -629
  177. build/lib/siat/fund_china.py +0 -3307
  178. build/lib/siat/future_china.py +0 -551
  179. build/lib/siat/google_authenticator.py +0 -47
  180. build/lib/siat/grafix.py +0 -3636
  181. build/lib/siat/holding_risk.py +0 -867
  182. build/lib/siat/luchy_draw.py +0 -638
  183. build/lib/siat/market_china.py +0 -1168
  184. build/lib/siat/markowitz.py +0 -2363
  185. build/lib/siat/markowitz2.py +0 -3150
  186. build/lib/siat/markowitz2_20250704.py +0 -2969
  187. build/lib/siat/markowitz2_20250705.py +0 -3158
  188. build/lib/siat/markowitz_simple.py +0 -373
  189. build/lib/siat/ml_cases.py +0 -2291
  190. build/lib/siat/ml_cases_example.py +0 -60
  191. build/lib/siat/option_china.py +0 -3069
  192. build/lib/siat/option_pricing.py +0 -1925
  193. build/lib/siat/other_indexes.py +0 -409
  194. build/lib/siat/risk_adjusted_return.py +0 -1576
  195. build/lib/siat/risk_adjusted_return2.py +0 -1900
  196. build/lib/siat/risk_evaluation.py +0 -2218
  197. build/lib/siat/risk_free_rate.py +0 -351
  198. build/lib/siat/sector_china.py +0 -4140
  199. build/lib/siat/security_price2.py +0 -727
  200. build/lib/siat/security_prices.py +0 -3408
  201. build/lib/siat/security_trend.py +0 -402
  202. build/lib/siat/security_trend2.py +0 -646
  203. build/lib/siat/stock.py +0 -4284
  204. build/lib/siat/stock_advice_linear.py +0 -934
  205. build/lib/siat/stock_base.py +0 -26
  206. build/lib/siat/stock_china.py +0 -2095
  207. build/lib/siat/stock_prices_kneighbors.py +0 -910
  208. build/lib/siat/stock_prices_linear.py +0 -386
  209. build/lib/siat/stock_profile.py +0 -707
  210. build/lib/siat/stock_technical.py +0 -3305
  211. build/lib/siat/stooq.py +0 -74
  212. build/lib/siat/transaction.py +0 -347
  213. build/lib/siat/translate.py +0 -5183
  214. build/lib/siat/valuation.py +0 -1378
  215. build/lib/siat/valuation_china.py +0 -2076
  216. build/lib/siat/var_model_validation.py +0 -444
  217. build/lib/siat/yf_name.py +0 -811
  218. siat-3.10.132.dist-info/RECORD +0 -218
@@ -1,2339 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- 本模块功能:计算财务报表比例,应用层
4
- 所属工具包:证券投资分析工具SIAT
5
- SIAT:Security Investment Analysis Tool
6
- 创建日期:2020年9月8日
7
- 最新修订日期:2020年9月15日
8
- 作者:王德宏 (WANG Dehong, Peter)
9
- 作者单位:北京外国语大学国际商学院
10
- 作者邮件:wdehong2000@163.com
11
- 版权所有:王德宏
12
- 用途限制:仅限研究与教学使用,不可商用!商用需要额外授权。
13
- 特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
14
- """
15
- #==============================================================================
16
- #关闭所有警告
17
- import warnings; warnings.filterwarnings('ignore')
18
- #==============================================================================
19
- #本模块的公共引用
20
- from siat.common import *
21
- from siat.translate import *
22
- from siat.financial_statements import *
23
- from siat.grafix import *
24
- #==============================================================================
25
- import matplotlib.pyplot as plt
26
-
27
- #plt.rcParams['figure.figsize']=(12.8,7.2)
28
- plt.rcParams['figure.figsize']=(12.8,6.4)
29
- plt.rcParams['figure.dpi']=300
30
- plt.rcParams['font.size'] = 13
31
- plt.rcParams['xtick.labelsize']=11 #横轴字体大小
32
- plt.rcParams['ytick.labelsize']=11 #纵轴字体大小
33
-
34
- title_txt_size=16
35
- ylabel_txt_size=14
36
- xlabel_txt_size=14
37
- legend_txt_size=14
38
-
39
- #设置绘图风格:网格虚线
40
- plt.rcParams['axes.grid']=True
41
- #plt.rcParams['grid.color']='steelblue'
42
- #plt.rcParams['grid.linestyle']='dashed'
43
- #plt.rcParams['grid.linewidth']=0.5
44
- #plt.rcParams['axes.facecolor']='whitesmoke'
45
-
46
- #处理绘图汉字乱码问题
47
- import sys; czxt=sys.platform
48
- if czxt in ['win32','win64']:
49
- plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体
50
- mpfrc={'font.family': 'SimHei'}
51
-
52
- if czxt in ['darwin']: #MacOSX
53
- plt.rcParams['font.family']= ['Heiti TC']
54
- mpfrc={'font.family': 'Heiti TC'}
55
-
56
- if czxt in ['linux']: #website Jupyter
57
- plt.rcParams['font.family']= ['Heiti TC']
58
- mpfrc={'font.family':'Heiti TC'}
59
-
60
- # 解决保存图像时'-'显示为方块的问题
61
- plt.rcParams['axes.unicode_minus'] = False
62
- #==============================================================================
63
- if __name__ == '__main__':
64
- ticker=['AAPL','MSFT']
65
- indicator=['Current Ratio','Quick Ratio']
66
-
67
- ticker=['BABA','JD']
68
- indicator='Cashflow per Share'
69
-
70
- datatag=False
71
- power=0
72
- zeroline=False
73
- twinx=False
74
- loc1=loc2='best'
75
-
76
- def compare_history(ticker,indicator, \
77
- datatag=False,power=0,zeroline=False,twinx=False, \
78
- loc1='best',loc2='best',graph=True):
79
- """
80
- 功能:比较多个股票的时序数据,绘制折线图
81
- datatag=False: 不将数值标记在图形旁
82
- zeroline=False:不绘制水平零线
83
- twinx=False:单纵轴
84
- """
85
- tickers=ticker
86
- items=indicator
87
-
88
- #检查power的范围是否合理
89
- if not (power in range(0,80)):
90
- print(" #Error(compare_history): invalid parameter, power =",power)
91
- return None
92
-
93
- #检查股票个数
94
- ticker_num=1
95
- if isinstance(tickers,list):
96
- if len(tickers) >= 1: ticker1=tickers[0]
97
- if len(tickers) >= 2:
98
- ticker2=tickers[1]
99
- ticker_num=2
100
- if len(tickers) == 0:
101
- print(" #Error(compare_history): no stock code found",tickers)
102
- return None,None
103
- else:
104
- ticker1=tickers
105
-
106
- #检查指标个数
107
- item_num=1
108
- if isinstance(items,list):
109
- if len(items) >= 1: item1=items[0]
110
- if len(items) >= 2:
111
- item2=items[1]
112
- item_num=2
113
- if len(items) == 0:
114
- print(" #Error(compare_history): no analytical item found",items)
115
- return None,None
116
- else:
117
- item1=items
118
-
119
- #判断比较模式
120
- if (ticker_num == 1) and (item_num == 1): mode='T1I1'
121
- if (ticker_num == 1) and (item_num == 2): mode='T1I2'
122
- if (ticker_num == 2): mode='T2I1'
123
-
124
- #检查指标是否支持
125
- itemlist=[
126
- #短期偿债能力
127
- 'Current Ratio','Quick Ratio','Cash Ratio','Cash Flow Ratio', \
128
- #长期偿债能力
129
- 'Debt to Asset','Equity to Asset','Equity Multiplier','Debt to Equity', \
130
- #'Debt to Tangible Net Asset', \
131
- 'Debt Service Coverage','Times Interest Earned', \
132
- #营运能力
133
- 'Inventory Turnover','Receivable Turnover','Current Asset Turnover', \
134
- 'Fixed Asset Turnover','Total Asset Turnover', \
135
- #盈利能力
136
- 'Operating Margin','Gross Margin','Profit Margin', \
137
- 'Net Profit on Costs','ROA','ROIC','ROE', \
138
- #股东持股
139
- 'Payout Ratio','Cashflow per Share','CFPS','Dividend per Share','DPS', \
140
- 'Net Asset per Share','BasicEPS','DilutedEPS', \
141
- #发展潜力
142
- 'Revenue Growth','Capital Accumulation','Total Asset Growth','PPE Residual' \
143
- ]
144
-
145
- if item1 not in itemlist:
146
- print(" #Error(compare_history): unsupported item for",item1)
147
- print(" Supported items are as follows:\n",itemlist)
148
- return None,None
149
- if mode=='T1I2':
150
- if item2 not in itemlist:
151
- print(" #Error(compare_history): unsupported item for",item2)
152
- print(" Supported items are as follows:\n",itemlist)
153
- return None,None
154
-
155
- #抓取数据
156
- info1=get_financial_rates(ticker1)
157
- if info1 is None:
158
- print(f" #Warning(compare_history): unable to get data for {ticker1}, retrying ...")
159
- sleep_random(max_sleep=30)
160
- info1=get_financial_rates(ticker1)
161
- if info1 is None:
162
- print(" #Error(compare_history): failed to retrieved financials for",ticker1)
163
- return None,None
164
-
165
- cols1=['ticker','endDate','periodType',item1]
166
- df1=info1[cols1]
167
- df1['date']=df1['endDate']
168
- df1.set_index('date',inplace=True)
169
-
170
- if mode == 'T1I2':
171
- ticker2=ticker1
172
- cols2=['ticker','endDate','periodType',item2]
173
- df2=info1[cols2]
174
- df2['date']=df2['endDate']
175
- df2.set_index('date',inplace=True)
176
-
177
- if mode == 'T2I1':
178
- item2=item1
179
- info2=get_financial_rates(ticker2)
180
- if info2 is None:
181
- print(f" #Warning(compare_history): unable to get data for {ticker2}, retrying ...")
182
- sleep_random(max_sleep=30)
183
- info2=get_financial_rates(ticker2)
184
- if info2 is None:
185
- print(" #Error(compare_history): failed to retrieved financials for",ticker2)
186
- return None,None
187
-
188
- df2=info2[cols1]
189
- df2['date']=df2['endDate']
190
- df2.set_index('date',inplace=True)
191
-
192
- import datetime; todaydt=datetime.date.today()
193
- #绘图:T1I1,单折线
194
- if mode == 'T1I1'and graph:
195
- df=df1
196
- colname=item1
197
- collabel=ectranslate(item1)
198
- ylabeltxt=''
199
- #titletxt=ticker_name(ticker1)+texttranslate(": 基于年(季)报的业绩历史")
200
- titletxt=ticker_name(ticker1)+": 财报业绩历史"
201
- #footnote=texttranslate("数据来源: 雅虎财经,")+' '+str(today)
202
- footnote="数据来源: 雅虎财经,"+' '+str(todaydt)
203
-
204
- plot_line(df,colname,collabel,ylabeltxt,titletxt,footnote, \
205
- datatag=datatag,power=power,zeroline=zeroline,resample_freq='3M', \
206
- loc=loc1)
207
- return df1,None
208
- elif mode == 'T1I1'and not graph:
209
- return df1,None
210
- else:
211
- pass
212
-
213
- if not graph:
214
- return df1,df2
215
-
216
- #绘图:T1I2,单股票双折线
217
- if mode == 'T1I2':
218
- colname1=item1
219
- label1=ectranslate(item1)
220
- colname2=item2
221
- label2=ectranslate(item2)
222
- ylabeltxt=''
223
- #titletxt=ticker_name(ticker1)+texttranslate(": 基于年(季)报的业绩历史对比")
224
- titletxt=ticker_name(ticker1)+": 财报业绩历史对比"
225
- #footnote=texttranslate("数据来源: 雅虎财经,")+' '+str(today)
226
- footnote="数据来源: 雅虎财经,"+' '+str(today)
227
-
228
- plot_line2(df1,ticker1,colname1,label1, \
229
- df2,ticker2,colname2,label2, \
230
- ylabeltxt,titletxt,footnote, \
231
- power=power,zeroline=zeroline,twinx=twinx,resample_freq='3M', \
232
- loc1=loc1,loc2=loc2)
233
- return df1,df2
234
-
235
- #绘图:T2I1,双股票双折线
236
- if mode == 'T2I1':
237
- df1=df1.fillna(method='ffill').fillna(method='bfill')
238
- df2=df2.fillna(method='ffill').fillna(method='bfill')
239
- """
240
- #日期可能不一致,并表
241
- import pandas as pd
242
- df=pd.merge(df1,df2,how="outer",on="endDate")
243
- #df=df.fillna(method='ffill').fillna(method='bfill')
244
- df.dropna(inplace=True)
245
- dfx=df[['ticker_x','endDate','periodType_x',item1+'_x']]
246
- dfx=dfx.rename(columns={'ticker_x':'ticker','periodType_x':'periodType',item1+'_x':item1})
247
- dfx['date']=dfx['endDate']
248
- dfx.set_index('date',inplace=True)
249
-
250
- dfy=df[['ticker_y','endDate','periodType_y',item1+'_y']]
251
- dfy=dfy.rename(columns={'ticker_y':'ticker','periodType_y':'periodType',item1+'_y':item1})
252
- dfy['date']=dfy['endDate']
253
- dfy.set_index('date',inplace=True)
254
- """
255
-
256
- colname1=item1
257
- label1=ectranslate(item1)
258
- colname2=item2
259
- label2=ectranslate(item2)
260
- ylabeltxt=''
261
- #titletxt=ticker_name(ticker1)+" vs "+ticker_name(ticker2)+texttranslate(": 基于年(季)报的业绩历史对比")
262
- titletxt=ticker_name(ticker1)+" vs "+ticker_name(ticker2)+": 财报业绩历史对比"
263
- #footnote=texttranslate("数据来源: 雅虎财经,")+' '+str(today)
264
- footnote="数据来源: 雅虎财经,"+' '+str(todaydt)
265
-
266
- #克服双线绘制时第2条线错乱问题:两个df日期强制取齐,能解决问题,但原因不明
267
- tname1=ticker_name(ticker1)
268
- df1.rename(columns={item1:tname1},inplace=True)
269
- tname2=ticker_name(ticker2)
270
- df2.rename(columns={item2:ticker_name(ticker2)},inplace=True)
271
- df12=pd.merge(df1,df2,how='inner',left_index=True,right_index=True)
272
- df1t=df12[[tname1]]
273
- df2t=df12[[tname2]]
274
-
275
- plot_line2(df1t,ticker1,tname1,label1, \
276
- df2t,ticker2,tname2,label2, \
277
- ylabeltxt,titletxt,footnote, \
278
- power=power,zeroline=zeroline,twinx=twinx,resample_freq='3M', \
279
- loc1=loc1,loc2=loc2)
280
-
281
- return df1,df2
282
-
283
- if __name__ == '__main__':
284
- df1,df2=compare_history(tickers,items)
285
-
286
- #==============================================================================
287
- if __name__ == '__main__':
288
- ticker=['AAPL','MSFT','WMT']
289
- itemk='Current Ratio'
290
- itemk='Employees'
291
- indicator=itemk='PEG'
292
-
293
- multicolor=False
294
-
295
- tickers=['AMZN','EBAY']
296
- itemk='IGR'
297
-
298
- datatag=True
299
- tag_offset=0.01
300
- graph=True
301
- axisamp=1.3
302
-
303
-
304
- def compare_snapshot(ticker,indicator, \
305
- facecolor='lightblue',
306
- datatag=True,tag_offset=0.01, \
307
- graph=True,axisamp=1.2,px=True, \
308
- printout=True,numberPerLine=10):
309
- """
310
- 功能:比较多个股票的快照数据,绘制水平柱状图
311
- itemk需要通过对照表转换为内部的item
312
- datatag=True: 将数值标记在图形旁
313
- tag_offset=0.01:标记的数值距离图形的距离,若不理想可以手动调节,可为最大值1%-5%
314
- graph:是否将结果绘图,默认True
315
- axisamp:绘图时横轴放大系数,默认1.2。若标记数值超出右边界则增加数值,也可能需要负数数值
316
- px:是否使用plotly-express工具绘图,默认True。
317
- 其优点是无需调整axisamp,缺点是无法保存绘图结果在Jupyter Notebook中。
318
- printout:是否显示哪些股票找到或未找到相关数据,默认True
319
- numberPerLine:在显示相关数据时,每行显示的股票代码或名称个数,默认10
320
- """
321
- tickers=ticker; itemk=indicator
322
-
323
- #检查股票代码列表
324
- if not isinstance(tickers,list):
325
- print(" #Error(compare_snapshot): need more stock codes in",tickers)
326
- return None
327
- if len(tickers) < 2:
328
- print(" #Error(compare_snapshot): need more stock codes in",tickers)
329
- return None
330
-
331
- #检查指标
332
- if isinstance(itemk,list):
333
- print(" #Error(compare_snapshot): only 1 item allowed here",itemk)
334
- return None
335
-
336
- itemdict={
337
- #员工与ESG
338
- 'Employees':'fullTimeEmployees', \
339
- 'Total ESG':'totalEsg','Environment Score':'environmentScore', \
340
- 'Social Score':'socialScore','Governance Score':'governanceScore', \
341
- #偿债能力
342
- 'Current Ratio':'currentRatio','Quick Ratio':'quickRatio', \
343
- 'Debt to Equity':'debtToEquity', \
344
- #盈利能力
345
- 'EBITDA Margin':'ebitdaMargins','Operating Margin':'operatingMargins', \
346
- 'Gross Margin':'grossMargins','Profit Margin':'profitMargins', \
347
- 'ROA':'returnOnAssets','ROE':'returnOnEquity', \
348
- #股东持股
349
- 'Held Percent Insiders':'heldPercentInsiders', \
350
- 'Held Percent Institutions':'heldPercentInstitutions', \
351
- #股东回报
352
- 'Payout Ratio':'payoutRatio','Revenue per Share':'revenuePerShare', \
353
- 'Cashflow per Share':'totalCashPerShare', \
354
- 'Dividend Rate':'dividendRate','TTM Dividend Rate':'trailingAnnualDividendRate', \
355
- 'Dividend Yield':'dividendYield', \
356
- 'TTM Dividend Yield':'trailingAnnualDividendYield', \
357
- '5-Year Avg Dividend Yield':'fiveYearAvgDividendYield', \
358
- 'Trailing EPS':'trailingEps','Forward EPS':'forwardEps', \
359
- #发展潜力
360
- 'Revenue Growth':'revenueGrowth','Earnings Growth':'earningsGrowth', \
361
- 'Earnings Quarterly Growth':'earningsQuarterlyGrowth', \
362
- 'EV to Revenue':'enterpriseToRevenue','EV to EBITDA':'enterpriseToEbitda', \
363
- #市场看法
364
- 'Current Price':'currentPrice','Price to Book':'priceToBook', \
365
- 'TTM Price to Sales':'priceToSalesTrailing12Months', \
366
- 'beta':'beta','52-Week Change':'52WeekChange', \
367
- 'Trailing PE':'trailingPE','Forward PE':'forwardPE', \
368
- #'PEG':'pegRatio',#经常取不到数据
369
- #'IGR':'IGR','SGR':'SGR',#另起其他命令处理
370
- }
371
-
372
- itemlist=list(itemdict.keys())
373
- if itemk not in itemlist:
374
- print(" #Error(compare_snapshot): unsupported indicator",itemk)
375
- #print(" Supported indicators:\n",itemlist)
376
- print(" Supported indicators:")
377
- #printInLine(itemlist,numberPerLine=5,leadingBlanks=2)
378
- printInLine_md(itemlist,numberPerLine=5,colalign='left',font_size='16px')
379
-
380
- return None
381
-
382
- item=itemdict[itemk]
383
- import pandas as pd
384
- df=pd.DataFrame(columns=('ticker','item','value','name'))
385
- proxydict={'trailingPE':'forwardPE','forwardPE':'trailingPE', \
386
- 'trailingEps':'forwardEps','forwardEps':'trailingEps',}
387
-
388
- notfoundlist=[]
389
- total0=len(tickers)
390
- print(" Searching",itemk,"for designated companies ...")
391
- for t in tickers:
392
-
393
- current=tickers.index(t)
394
- total=total0 - len(notfoundlist)
395
- print_progress_percent(current,total,steps=10,leading_blanks=2)
396
-
397
- try:
398
- info=stock_info(t)
399
- except:
400
- notfoundlist=notfoundlist+[t]
401
- #print(" #Error(compare_snapshot): stock info not available for",t)
402
- continue
403
- if (info is None) or (len(info)==0):
404
- notfoundlist=notfoundlist+[t]
405
- #print(" #Error(compare_snapshot): failed to get info for",t,"\b, try later!")
406
- continue
407
- try:
408
- value=info[info.index == item]['Value'][0]
409
- except:
410
- try:
411
- itemp=proxydict[item]
412
- value=info[info.index == itemp]['Value'][0]
413
- notfoundlist=notfoundlist+[t]
414
- #print(" #Warning(compare_snapshot):",item,"unavailable for",t,'\b, using proxy',itemp)
415
- except:
416
- notfoundlist=notfoundlist+[t]
417
- #print(" #Error(compare_snapshot): failed to get info of",item,"for",t)
418
- continue
419
-
420
- name=ticker_name(t)
421
- row=pd.Series({'ticker':t,'item':item,'value':value,'name':name})
422
- try:
423
- df=df.append(row,ignore_index=True)
424
- except:
425
- df=df._append(row,ignore_index=True)
426
-
427
- # 尝试恢复失败的股票信息 1
428
- if len(notfoundlist) > 0:
429
- print("\n Recovering info of",itemk,"for",notfoundlist,"...")
430
- total0=len(notfoundlist)
431
- tickers2=notfoundlist.copy(); notfoundlist=[]
432
- for t in tickers2:
433
-
434
- current=tickers2.index(t)
435
- total=total0 - len(notfoundlist)
436
- print_progress_percent(current,total,steps=10,leading_blanks=2)
437
-
438
- try:
439
- info=stock_info(t)
440
- except:
441
- notfoundlist=notfoundlist+[t]
442
- continue
443
- if (info is None) or (len(info)==0):
444
- notfoundlist=notfoundlist+[t]
445
- continue
446
- try:
447
- value=info[info.index == item]['Value'][0]
448
- except:
449
- try:
450
- itemp=proxydict[item]
451
- value=info[info.index == itemp]['Value'][0]
452
- notfoundlist=notfoundlist+[t]
453
- except:
454
- notfoundlist=notfoundlist+[t]
455
- continue
456
-
457
- name=ticker_name(t)
458
- row=pd.Series({'ticker':t,'item':item,'value':value,'name':name})
459
- try:
460
- df=df.append(row,ignore_index=True)
461
- except:
462
- df=df._append(row,ignore_index=True)
463
-
464
-
465
- # 尝试恢复失败的股票信息 2
466
- if len(notfoundlist) > 0:
467
- print("\n Recovering info of",itemk,"for",notfoundlist,"...")
468
- total0=len(notfoundlist)
469
- tickers3=notfoundlist.copy(); notfoundlist=[]
470
- for t in tickers3:
471
-
472
- current=tickers3.index(t)
473
- total=total0 - len(notfoundlist)
474
- print_progress_percent(current,total,steps=10,leading_blanks=2)
475
-
476
- try:
477
- info=stock_info(t)
478
- except:
479
- notfoundlist=notfoundlist+[t]
480
- continue
481
- if (info is None) or (len(info)==0):
482
- notfoundlist=notfoundlist+[t]
483
- continue
484
- try:
485
- value=info[info.index == item]['Value'][0]
486
- except:
487
- try:
488
- itemp=proxydict[item]
489
- value=info[info.index == itemp]['Value'][0]
490
- notfoundlist=notfoundlist+[t]
491
- except:
492
- notfoundlist=notfoundlist+[t]
493
- continue
494
-
495
- name=ticker_name(t)
496
- row=pd.Series({'ticker':t,'item':item,'value':value,'name':name})
497
- try:
498
- df=df.append(row,ignore_index=True)
499
- except:
500
- df=df._append(row,ignore_index=True)
501
-
502
- # 未找到任何股票信息
503
- if len(df) == 0:
504
- print(f"\n #Warning(compare_snapshot): no {indicator} found for specified stocks")
505
- print(" Reasons: wrong codes, failed to access to or fetch info from Yahoo Finance")
506
- print(" Feel weired? upgrade yahooquery, which may need certain versions of lxml")
507
- return None
508
-
509
- #处理小数点
510
- try:
511
- df['value']=round(df['value'],3)
512
- except:
513
- pass
514
- df.sort_values(by='value',ascending=True,inplace=True)
515
- df['key']=df['name']
516
- df.set_index('key',inplace=True)
517
-
518
- #绘图
519
- if graph:
520
- print(" Calculating and rendering graph, please wait ...")
521
- colname='value'
522
-
523
- lang=check_language()
524
- if lang == 'Chinese':
525
- titletxt="企业对比: 指标快照"
526
- notestxt="注:财务指标为TTM数值"
527
- else:
528
- titletxt="Company Snapshot Comparison"
529
- notestxt="Note: TTM values for financial ratios"
530
-
531
- import datetime; today=datetime.date.today()
532
- lang=check_language()
533
- if lang=='English':
534
- footnote1="Source: Yahoo Finance, "
535
- else:
536
- footnote1="数据来源: 雅虎财经,"
537
- footnote=ectranslate(itemk)+" -->\n"+notestxt+'\n'+footnote1+str(today)
538
-
539
- df.rename(columns={'value':itemk},inplace=True)
540
- colname=itemk
541
-
542
- if not px:
543
- footnote=ectranslate(itemk)+" -->\n"+notestxt+'\n'+footnote1+str(today)
544
- plot_barh(df,colname,titletxt,footnote,datatag=datatag,tag_offset=tag_offset,axisamp=axisamp)
545
- else:
546
- #在Spyder中可能无法显示
547
- titletxt="企业快照:"+ectranslate(itemk)
548
- footnote=notestxt+','+footnote1+str(today)
549
- plot_barh2(df,colname,titletxt,footnote,facecolor=facecolor)
550
-
551
- if (len(notfoundlist) > 0):
552
- foundlist=[]
553
- for t in tickers:
554
- if not (t in notfoundlist):
555
- foundlist=foundlist+[t]
556
- else:
557
- foundlist=tickers
558
-
559
- """
560
- if len(foundlist) > 0:
561
- foundlist_names=ticker_name(foundlist)
562
- print("Results:",itemk,"info found for the stocks below")
563
- printInLine(foundlist_names,numberPerLine=numberPerLine,leadingBlanks=2)
564
- printInLine(foundlist,numberPerLine=numberPerLine,leadingBlanks=2)
565
- """
566
- if (len(notfoundlist) > 0):
567
- print(" [Warning]",itemk,"info not found for the stocks below:")
568
- notfoundlist_names=ticker_name(notfoundlist)
569
- printInLine(notfoundlist_names,numberPerLine=numberPerLine,leadingBlanks=2)
570
- print(" [Solution] re-run the command with more stable internet connection")
571
-
572
- return df
573
-
574
- if __name__ == '__main__':
575
- df=compare_snapshot(tickers,itemk)
576
-
577
- #==============================================================================
578
- def compare_snapshot2(ticker,indicator,graph=True):
579
- """
580
- 功能:比较多个股票的快照数据,绘制水平柱状图
581
- itemk需要通过对照表转换为内部的item
582
-
583
- 特点:与compare_snapshot相比如何?
584
- """
585
- tickers=ticker; itemk=indicator
586
-
587
- #检查股票代码列表
588
- if not isinstance(tickers,list):
589
- print(" #Error(compare_snapshot2): need more stock codes in",tickers)
590
- return None
591
- if len(tickers) < 2:
592
- print(" #Error(compare_snapshot2): need more stock codes in",tickers)
593
- return None
594
-
595
- #检查指标
596
- if isinstance(itemk,list):
597
- print(" #Error(compare_snapshot2): only 1 item allowed here",itemk)
598
- return None
599
-
600
- itemdict={
601
- #员工与ESG
602
- 'Employees':'fullTimeEmployees', \
603
- 'Total ESG':'totalEsg','Environment Score':'environmentScore', \
604
- 'Social Score':'socialScore','Governance Score':'governanceScore', \
605
- #偿债能力
606
- 'Current Ratio':'currentRatio','Quick Ratio':'quickRatio', \
607
- 'Debt to Equity':'debtToEquity', \
608
- #盈利能力
609
- 'EBITDA Margin':'ebitdaMargins','Operating Margin':'operatingMargins', \
610
- 'Gross Margin':'grossMargins','Profit Margin':'profitMargins', \
611
- 'ROA':'returnOnAssets','ROE':'returnOnEquity', \
612
- #股东持股
613
- 'Held Percent Insiders':'heldPercentInsiders', \
614
- 'Held Percent Institutions':'heldPercentInstitutions', \
615
- #股东回报
616
- 'Payout Ratio':'payoutRatio','Revenue per Share':'revenuePerShare', \
617
- 'Cashflow per Share':'totalCashPerShare', \
618
- 'Dividend Rate':'dividendRate','TTM Dividend Rate':'trailingAnnualDividendRate', \
619
- 'Dividend Yield':'dividendYield', \
620
- 'TTM Dividend Yield':'trailingAnnualDividendYield', \
621
- '5-Year Avg Dividend Yield':'fiveYearAvgDividendYield', \
622
- 'Trailing EPS':'trailingEps','Forward EPS':'forwardEps', \
623
- #发展潜力
624
- 'Revenue Growth':'revenueGrowth','Earnings Growth':'earningsGrowth', \
625
- 'Earnings Quarterly Growth':'earningsQuarterlyGrowth', \
626
- 'EV to Revenue':'enterpriseToRevenue','EV to EBITDA':'enterpriseToEbitda', \
627
- #市场看法
628
- 'Current Price':'currentPrice','Price to Book':'priceToBook', \
629
- #'TTM Price to Sales':'priceToSalesTrailing12Months', \
630
- 'Price to Sales':'priceToSalesTrailing12Months', \
631
- 'beta':'beta','52-Week Change':'52WeekChange', \
632
- 'Trailing PE':'trailingPE','Forward PE':'forwardPE', \
633
- #'PEG':'pegRatio',
634
- #'IGR':'IGR','SGR':'SGR'
635
- }
636
- itemlist=list(itemdict.keys())
637
- if itemk not in itemlist:
638
- print(" #Error(compare_snapshot): unsupported rate for",itemk)
639
- print(" Supported rates are as follows:\n",itemlist)
640
- return None
641
-
642
- item=itemdict[itemk]
643
- import pandas as pd
644
- #import siat.stock_base as sb
645
- df=pd.DataFrame(columns=('ticker','item','value','name'))
646
- print(f" Working on {indicator} for specified stocks ...")
647
- for t in tickers:
648
- print_progress_percent2(t,tickers,steps=5,leading_blanks=4)
649
-
650
- try:
651
- info=stock_info(t)
652
- except:
653
- print(" #Error(compare_snapshot): stock info not available for",t)
654
- continue
655
- if (info is None) or (len(info)==0):
656
- print(" #Error(compare_snapshot): failed to get info for",t,"\b, try later!")
657
- continue
658
- try:
659
- value=info[info.index == item]['Value'][0]
660
- except:
661
- print(" #Error(compare_snapshot): failed to get info of",item,"for",t)
662
- continue
663
- """
664
- name=info[info.index == 'shortName']['Value'][0]
665
- name1=name.split(' ',1)[0] #取空格分隔字符串的第一个单词
666
- name2=name1.split(',',1)[0]
667
- name3=name2.split('.',1)[0]
668
- """
669
- name=ticker_name(t)
670
- row=pd.Series({'ticker':t,'item':item,'value':value,'name':name})
671
- try:
672
- df=df.append(row,ignore_index=True)
673
- except:
674
- df=df._append(row,ignore_index=True)
675
-
676
- if len(df) == 0:
677
- print(" #Error(compare_snapshot): stock info not found in",tickers)
678
- return None
679
-
680
- #处理小数点
681
- try:
682
- df['value']=round(df['value'],3)
683
- except:
684
- pass
685
- df.sort_values(by='value',ascending=True,inplace=True)
686
- df['key']=df['name']
687
- df.set_index('key',inplace=True)
688
-
689
- #绘图
690
- if graph:
691
- print(" Calculating and rendering graph, please wait ...")
692
-
693
- df.rename(columns={'value':itemk},inplace=True)
694
- colname=itemk
695
- #titletxt="企业横向对比: "+ectranslate(itemk)+"(TTM)"
696
- titletxt=text_lang("企业对比: ","Comparing Company: ")+ectranslate(itemk)
697
- import datetime; today=datetime.date.today()
698
- footnote=text_lang("注:财务比率为TTM,数据来源: 雅虎财经, ","Note: TTM data, source: Yahoo Finance, ")+str(today)
699
- plot_barh2(df,colname,titletxt,footnote)
700
-
701
- return df
702
-
703
- if __name__ == '__main__':
704
- df=compare_snapshot(tickers,itemk)
705
-
706
- #==============================================================================
707
-
708
- if __name__ == '__main__':
709
- tickers=["0883.HK","0857.HK","0386.HK",'XOM','2222.SR','OXY','BP','RDSA.AS']
710
- graph=True
711
-
712
- def compare_tax(ticker,graph=True,axisamp=1.3,px=True):
713
- """
714
- 功能:比较公司最新的实际所得税率
715
- """
716
- tickers=ticker
717
-
718
- #检查股票代码列表
719
- if not isinstance(tickers,list):
720
- print(" #Error(compare_tax): need more stock codes in",tickers)
721
- return None
722
- if len(tickers) < 2:
723
- print(" #Error(compare_tax): need more stock codes in",tickers)
724
- return None
725
-
726
- import siat.beta_adjustment as badj
727
- import pandas as pd
728
- df=pd.DataFrame(columns=('ticker','name','date','tax rate'))
729
- print(" Working on tax info for specified stocks ...")
730
- for t in tickers:
731
- print_progress_percent2(t,tickers,steps=5,leading_blanks=4)
732
-
733
- try:
734
- df0=badj.prepare_hamada_yahoo(t)
735
- except:
736
- print(" #Warning(compare_tax): stock info not available for",t)
737
- continue
738
- df1=df0.tail(1)
739
- name=ticker_name(t)
740
- reportdate=df1.index[0]
741
- taxrate=df1['tax rate'][0]
742
- row=pd.Series({'ticker':t,'name':name,'date':reportdate,'tax rate':round(taxrate,3)})
743
- try:
744
- df=df.append(row,ignore_index=True)
745
- except:
746
- df=df._append(row,ignore_index=True)
747
-
748
- df.sort_values(by='tax rate',ascending=True,inplace=True)
749
- df['key']=df['name']
750
- df.set_index('key',inplace=True)
751
- #绘图
752
- if graph:
753
- print(" Calculating and rendering graph, please wait ...")
754
- lang=check_language()
755
- colname='tax rate'
756
- if lang == 'Chinese':
757
- titletxt="企业对比: 实际所得税率"
758
- itemk="实际所得税率"
759
- source_txt="数据来源: 雅虎财经,"
760
- else:
761
- titletxt=texttranslate("企业对比: 实际税率")
762
- itemk=texttranslate("实际所得税率")
763
- source_txt=texttranslate("数据来源: 雅虎财经,")
764
-
765
- import datetime; today=datetime.date.today()
766
- if not px:
767
- footnote=itemk+" -->\n"+source_txt+" "+str(today)
768
- plot_barh(df,colname,titletxt,footnote,axisamp=axisamp)
769
- else:
770
- footnote=source_txt+" "+str(today)
771
- plot_barh2(df,colname,titletxt,footnote)
772
-
773
- return df
774
- #==============================================================================
775
- if __name__ == '__main__':
776
- ticker='EBAY'
777
-
778
- def calc_igr_sgr(ticker):
779
-
780
-
781
- import siat.stock as stk
782
- sub_info=stk.get_stock_profile(ticker,info_type='fin_rates',printout=False)
783
- """
784
- #应对各种出错情形:执行出错,返回NoneType,返回空值
785
- try:
786
- info=stk.stock_info(ticker)
787
- except:
788
- print(" #Warning(calc_igr_sgr): failed to retrieve info of",ticker,"\b, recovering...")
789
- import time; time.sleep(5)
790
- try:
791
- info=stock_info(ticker)
792
- except:
793
- print(" #Error(calc_igr_sgr): failed to retrieve info of",ticker)
794
- return None
795
- if info is None:
796
- print(" #Error(calc_igr_sgr): retrieved none info of",ticker)
797
- return None
798
- if len(info) == 0:
799
- print(" #Error(calc_igr_sgr): retrieved empty info of",ticker)
800
- return None
801
- sub_info=stock_fin_rates(info)
802
- """
803
- if sub_info is None:
804
- return None,None
805
-
806
- roa=list(sub_info[sub_info.index=='returnOnAssets']['Value'])[0]
807
- roe=list(sub_info[sub_info.index=='returnOnEquity']['Value'])[0]
808
- try:
809
- b=1-list(sub_info[sub_info.index=='payoutRatio']['Value'])[0]
810
- except:
811
- b=1-0
812
-
813
- igr=round(roa*b/(1-roa*b),4)
814
- sgr=round(roe*b/(1-roe*b),4)
815
-
816
- return igr,sgr
817
-
818
- def compare_igr_sgr(ticker,graph=True,axisamp=1.0,px=True):
819
- """
820
- 功能:比较公司TTM的IGR和SGR
821
- """
822
- tickers=ticker
823
-
824
- #检查股票代码列表
825
- if not isinstance(tickers,list):
826
- print(" #Error(compare_igr_sgr): need more stock codes in",tickers)
827
- return None
828
- if len(tickers) < 2:
829
- print(" #Error(compare_igr_sgr): need more stock codes in",tickers)
830
- return None
831
-
832
- import pandas as pd
833
- df=pd.DataFrame(columns=('ticker','name','date','IGR','SGR'))
834
- print(" Working on IGR & SGR for specified stocks ...")
835
- for t in tickers:
836
- print_progress_percent2(t,tickers,steps=5,leading_blanks=4)
837
-
838
- try:
839
- igr,sgr=calc_igr_sgr(t)
840
- except:
841
- print(" #Warning(compare_igr_sgr): stock info not available for",t)
842
- continue
843
- if igr is None or sgr is None:
844
- print(" #Warning(compare_igr_sgr): stock info not available for",t)
845
- continue
846
- name=ticker_name(t)
847
- row=pd.Series({'ticker':t,'name':name,'IGR':round(igr,3),'SGR':round(sgr,3)})
848
- try:
849
- df=df.append(row,ignore_index=True)
850
- except:
851
- df=df._append(row,ignore_index=True)
852
-
853
- #绘制IGR
854
- df.sort_values(by='IGR',ascending=True,inplace=True)
855
- df['key']=df['name']
856
- df.set_index('key',inplace=True)
857
- #绘图
858
- lang=check_language()
859
- if graph:
860
- print("\n Calculating and rendering graph, please wait ...")
861
-
862
- colname='IGR'
863
- if lang == "Chinese":
864
- titletxt="企业对比: 内部增长率IGR"
865
- itemk="内部增长率(IGR)"
866
- source_txt="数据来源: 雅虎财经,"
867
- else:
868
- titletxt="Company Internal Growth Rate (IGR TTM)"
869
- itemk="Internal growth rate"
870
- source_txt="Source: Yahoo Finance,"
871
-
872
- import datetime; today=datetime.date.today()
873
- if not px:
874
- footnote=ectranslate(itemk)+" -->\n"+source_txt+" "+str(today)
875
- plot_barh(df,colname,titletxt,footnote,axisamp=axisamp)
876
- else:
877
- footnote=source_txt+" "+str(today)
878
- plot_barh2(df,colname,titletxt,footnote)
879
-
880
- #绘制SGR
881
- df.sort_values(by='SGR',ascending=True,inplace=True)
882
- df['key']=df['name']
883
- df.set_index('key',inplace=True)
884
- #绘图
885
- if graph:
886
- colname='SGR'
887
- if lang == 'Chinese':
888
- titletxt="企业对比: 可持续增长率SGR"
889
- itemk="可持续增长率(SGR)"
890
- else:
891
- titletxt="Company Sustainable Growth Rate (SGR TTM)"
892
- itemk="Sustainable growth rate"
893
-
894
- if not px:
895
- footnote=ectranslate(itemk)+" -->\n"+source_txt+" "+str(today)
896
- plot_barh(df,colname,titletxt,footnote,axisamp=axisamp)
897
- else:
898
- footnote=source_txt+" "+str(today)
899
- plot_barh2(df,colname,titletxt,footnote)
900
-
901
- return df
902
-
903
-
904
- #==============================================================================
905
- if __name__ == '__main__':
906
- fsdf=get_financial_statements('AAPL')
907
- fst=fsdf.T #查看科目名称更加方便
908
-
909
- def get_PE(fsdf):
910
- """
911
- 功能:计算PE
912
- """
913
- dateymd=lambda x:x.strftime('%Y-%m-%d')
914
- fsdf['endDate']=fsdf['asOfDate'].apply(dateymd)
915
-
916
- #获得各个报表的日期范围,适当扩大日期范围以规避非交易日
917
- start=min(list(fsdf['endDate']))
918
- fromdate=date_adjust(start,adjust=-30)
919
- end=max(list(fsdf['endDate']))
920
- todate=date_adjust(end,adjust=30)
921
-
922
- #获取股价
923
- ticker=list(fsdf['ticker'])[0]
924
- import siat.security_prices as ssp
925
- prices=ssp.get_price(ticker, fromdate, todate)
926
- if prices is None:
927
- print(" #Error(get_PE): retrieving stock price failed for",ticker,fromdate,todate,"\b, recovering...")
928
- import time; time.sleep(5)
929
- prices=ssp.get_price(ticker, fromdate, todate)
930
- if prices is None:
931
- print(" #Error(get_PE): failed retrieving stock price, retrying stopped")
932
- import numpy as np
933
- fsdf['BasicPE']=np.nan
934
- fsdf['DilutedPE']=np.nan
935
- return fsdf
936
-
937
- prices['datedt']=prices.index.date
938
- datecvt=lambda x: str(x)[0:10]
939
- prices['Date']=prices['datedt'].apply(datecvt)
940
-
941
- #报表日期列表
942
- datelist_fs=list(fsdf['endDate'])
943
- #价格日期列表
944
- datelist_price=list(prices['Date'])
945
- date_price_min=min(datelist_price)
946
- date_price_max=max(datelist_price)
947
-
948
- #股价列表
949
- pricelist=list(prices['Close'])
950
-
951
- import pandas as pd
952
- pricedf=pd.DataFrame(columns=('endDate','actualDate','Price'))
953
- for d in datelist_fs:
954
- found=False
955
- d1=d
956
- if d in datelist_price:
957
- found=True
958
- pos=datelist_price.index(d)
959
- p=pricelist[pos]
960
- else:
961
- while (d1 >= date_price_min) and not found:
962
- d1=date_adjust(d1,adjust=-1)
963
- if d1 in datelist_price:
964
- found=True
965
- pos=datelist_price.index(d1)
966
- p=pricelist[pos]
967
- while (d1 <= date_price_max) and not found:
968
- d1=date_adjust(d1,adjust=1)
969
- if d1 in datelist_price:
970
- found=True
971
- pos=datelist_price.index(d1)
972
- p=pricelist[pos]
973
- #记录股价
974
- row=pd.Series({'endDate':d,'actualDate':d1,'Price':p})
975
- try:
976
- pricedf=pricedf.append(row,ignore_index=True)
977
- except:
978
- pricedf=pricedf._append(row,ignore_index=True)
979
-
980
- #合成表
981
- fsdf1=pd.merge(fsdf,pricedf,on='endDate')
982
- fsdf1['BasicPE']=fsdf1['Price']/fsdf1['BasicEPS']
983
- fsdf1['DilutedPE']=fsdf1['Price']/fsdf1['DilutedEPS']
984
-
985
- return fsdf1
986
-
987
- if __name__ == '__main__':
988
- fsdf1=get_PE(fsdf)
989
-
990
- #==============================================================================
991
- if __name__ == '__main__':
992
- fsdf=get_financial_statements('AAPL')
993
- fst=fsdf.T #查看科目名称更加方便
994
-
995
- def calc_DebtToAsset(fsdf):
996
- """
997
- 功能:计算资产负债率
998
- """
999
-
1000
- fsdf1=fsdf.copy()
1001
-
1002
- #计算Debt to Asset
1003
- try:
1004
- fsdf1['Debt to Asset']=round(fsdf1['TotalLiabilities']/fsdf1['TotalAssets'],4)
1005
- except:
1006
- print(" #Error(get_DebtToAsset): failed in calculating DebtToAsset")
1007
-
1008
- #计算Debt to Equity
1009
- try:
1010
- fsdf1['Debt to Equity']=round(fsdf1['TotalLiabilities']/fsdf1['TotalEquities'],4)
1011
- except:
1012
- print(" #Error(get_DebtToAsset): failed in calculating DebtToEquity")
1013
-
1014
- return fsdf1
1015
-
1016
- if __name__ == '__main__':
1017
- fsdf1=get_DebtToAsset(fsdf)
1018
-
1019
-
1020
- #==============================================================================
1021
- if __name__ == '__main__':
1022
- fsdf=get_financial_statements('AAPL')
1023
- fst=fsdf.T #查看科目名称更加方便
1024
-
1025
- fsdf=get_financial_statements('3333.HK')
1026
- fsdf=get_financial_statements('601398.SS')
1027
-
1028
- def calc_fin_rates(fsdf):
1029
- """
1030
- 功能:基于财报计算各种指标
1031
- 注意:ROA/ROE/EM/turnover比率基于期初期末均值计算,其余仅基于期末数据计算!
1032
- """
1033
- #####前后填充缺失值
1034
- if fsdf is None: return None
1035
- fs = fsdf.fillna(method='ffill').fillna(method='bfill')
1036
-
1037
- """
1038
- #期初期末平均数
1039
- fs['avgInventory']=(fs['Inventory']+fs['Inventory'].shift(1))/2.0
1040
- fs['avgReceivables']=(fs['AccountsReceivable']+fs['AccountsReceivable'].shift(1))/2.0
1041
- fs['avgCurrentAsset']=(fs['CurrentAssets']+fs['CurrentAssets'].shift(1))/2.0
1042
- fs['avgPPE']=(fs['NetPPE']+fs['NetPPE'].shift(1))/2.0
1043
- fs['avgTotalAsset']=(fs['TotalAssets']+fs['TotalAssets'].shift(1))/2.0
1044
- fs['avgNetPPE']=(fs['NetPPE']+fs['NetPPE'].shift(1))/2.0
1045
- fs['avgGrossPPE']=(fs['GrossPPE']+fs['GrossPPE'].shift(1))/2.0
1046
- fs['avgTotalEquity']=(fs['TotalEquities']+fs['TotalEquities'].shift(1))/2.0
1047
- """
1048
-
1049
- #短期偿债能力指标
1050
- #流动比率:流动资产 / 流动负债
1051
- fs['Current Ratio']=fs['CurrentAssets']/fs['CurrentLiabilities']
1052
- #速动比率:(流动资产-存货) / 流动负债
1053
- fs['Quick Ratio']=(fs['CurrentAssets']-fs['Inventory'])/fs['CurrentLiabilities']
1054
- #现金比率: (现金+现金等价物) / 流动负债
1055
- fs['Cash Ratio']=fs['CashAndCashEquivalents']/fs['CurrentLiabilities']
1056
- #现金流量比率:经营活动现金流量 / 流动负债
1057
- fs['Cash Flow Ratio']=fs['OperatingCashFlow']/fs['CurrentLiabilities']
1058
-
1059
- #####长期偿债能力指标
1060
- #资产负债率:负债总额 / 资产总额
1061
- fs['Debt to Asset']=fs['TotalLiabilities']/fs['TotalAssets']
1062
- #股东权益比率:股东权益总额 / 资产总额
1063
- fs['Equity to Asset']=fs['TotalEquities']/fs['TotalAssets']
1064
-
1065
- #权益乘数:资产总额 / 股东权益总额,使用期初期末均值*****
1066
- fs=fs_entry_begin(fs,account_entry='TotalAssets',suffix='_begin')
1067
- fs=fs_entry_begin(fs,account_entry='TotalEquities',suffix='_begin')
1068
- fs['Equity Multiplier']=((fs['TotalAssets']+fs['TotalAssets_begin'])/2)/((fs['TotalEquities']+fs['TotalEquities_begin'])/2)
1069
- #fs['Equity Multiplier']=fs['avgTotalAsset']/fs['avgTotalEquity']
1070
-
1071
- #负债股权比率:负债总额 / 股东权益总额
1072
- fs['Debt to Equity']=fs['TotalLiabilities']/fs['TotalEquities']
1073
- #有形净值债务率:负债总额 / (股东权益-无形资产净额)
1074
- fs['netIntangibleAsset']=fs['TotalAssets']-fs['NetTangibleAssets']
1075
- fs['Debt to Tangible Net Asset']=fs['TotalLiabilities']/(fs['TotalEquities']-fs['netIntangibleAsset'])
1076
- #偿债保障比率:负债总额 / 经营活动现金净流量
1077
- fs['Debt Service Coverage']=fs['TotalLiabilities']/fs['OperatingCashFlow']
1078
- #利息保障倍数:(税前利润+利息费用)/ 利息费用
1079
- fs['Times Interest Earned']=fs['PretaxIncome']/fs['InterestExpense']+1
1080
-
1081
- #营运能力指标
1082
- #存货周转率:销售收入 / 期末存货,平均存货计算困难
1083
- #fs['Inventory Turnover']=fs['CostOfRevenue']/fs['avgInventory']
1084
- #fs['Inventory Turnover']=fs['CostOfRevenue']/fs['Inventory']
1085
- fs=fs_entry_begin(fs,account_entry='Inventory',suffix='_begin')
1086
- fs['Inventory Turnover']=fs['TotalRevenue']/((fs['Inventory']+fs['Inventory_begin'])/2)
1087
- #应收账款周转率:赊销收入净额 / 平均应收账款余额
1088
- #fs['Receivable Turnover']=fs['TotalRevenue']/fs['avgReceivables']
1089
- fs=fs_entry_begin(fs,account_entry='AccountsReceivable',suffix='_begin')
1090
- fs['Receivable Turnover']=fs['TotalRevenue']/((fs['AccountsReceivable']+fs['AccountsReceivable_begin'])/2)
1091
- #流动资产周转率:销售收入 / 平均流动资产余额
1092
- #fs['Current Asset Turnover']=fs['TotalRevenue']/fs['avgCurrentAsset']
1093
- fs=fs_entry_begin(fs,account_entry='CurrentAssets',suffix='_begin')
1094
- fs['Current Asset Turnover']=fs['TotalRevenue']/((fs['CurrentAssets']+fs['CurrentAssets_begin'])/2)
1095
- #固定资产周转率:销售收入 / 平均固定资产净额
1096
- #fs['Fixed Asset Turnover']=fs['TotalRevenue']/fs['avgPPE']
1097
- fs=fs_entry_begin(fs,account_entry='NetPPE',suffix='_begin')
1098
- fs['Fixed Asset Turnover']=fs['TotalRevenue']/((fs['NetPPE']+fs['NetPPE_begin'])/2)
1099
- #总资产周转率:销售收入 / 平均资产总额
1100
- #fs['Total Asset Turnover']=fs['TotalRevenue']/fs['avgTotalAsset']
1101
- fs['Total Asset Turnover']=fs['TotalRevenue']/((fs['TotalAssets']+fs['TotalAssets_begin'])/2)
1102
-
1103
- #主营业务利润率=主营业务利润/主营业务收入
1104
- fs['Operating Margin']=fs['OperatingIncome']/fs['OperatingRevenue']
1105
-
1106
- #发展潜力指标
1107
- #营业收入增长率:本期营业收入增长额 / 上年同期营业收入总额
1108
- fs['Revenue Growth']=fs['OperatingRevenue'].pct_change()
1109
- #资本积累率:本期所有者权益增长额 / 年初所有者权益
1110
- fs['Capital Accumulation']=fs['TotalEquities'].pct_change()
1111
- #总资产增长率:本期总资产增长额 / 年初资产总额
1112
- fs['Total Asset Growth']=fs['TotalAssets'].pct_change()
1113
- #固定资产成新率:平均固定资产净值 / 平均固定资产原值。又称“固定资产净值率”或“有用系数”
1114
- #fs['PPE Residual']=fs['avgNetPPE']/fs['avgGrossPPE']
1115
- if ('NetPPE' in list(fs)) and ('GrossPPE' in list(fs)):
1116
- fs['PPE Residual']=fs['NetPPE']/fs['GrossPPE']
1117
-
1118
- #其他指标
1119
- #盈利能力指标
1120
- #资产报酬率:净利润 / 期末资产总额,平均总资产计算困难
1121
- #fs['Return on Asset']=(fs['NetIncome']+fs['InterestExpense'])/fs['avgTotalAsset']
1122
- #fs['Return on Asset']=(fs['NetIncome']+fs['InterestExpense'])/fs['TotalAssets']
1123
- #fs=fs_entry_begin(fs,account_entry='TotalAssets',suffix='_begin')
1124
- fs['Return on Asset']=(fs['NetIncome'])/((fs['TotalAssets']+fs['TotalAssets_begin'])/2)
1125
- fs['ROA']=fs['Return on Asset']
1126
- #(投入)资本回报率(Return on Invested Capital,简称ROIC)
1127
- #ROIC=NOPLAT(息前税后经营利润)/IC(投入资本)
1128
- #NOPLAT=EBIT×(1-T)=(营业利润+财务费用-非经常性投资损益) ×(1-所得税率)
1129
- #IC=有息负债+净资产-超额现金-非经营性资产
1130
- #fs['Return on Invested Capital']=(fs['OperatingIncome']+fs['InterestExpense'])*(1-fs['TaxRateForCalcs'])/fs['InvestedCapital']
1131
- fs=fs_entry_begin(fs,account_entry='InvestedCapital',suffix='_begin')
1132
- fs['Return on Invested Capital']=(fs['OperatingIncome'])*(1-fs['TaxRateForCalcs'])/((fs['InvestedCapital']+fs['InvestedCapital_begin'])/2)
1133
- #fs['Return on Invested Capital']=fs['Return on Invested Capital']
1134
- fs['ROIC']=fs['Return on Invested Capital']
1135
- #净资产报酬率:净利润 / 平均净资产
1136
- #fs['Return on Net Asset']=fs['NetIncome']/fs['avgTotalEquity']
1137
-
1138
- fs['Return on Net Asset']=fs['NetIncome']/((fs['TotalEquities']+fs['TotalEquities_begin'])/2)
1139
- #股东权益报酬率:净利润 / 平均股东权益总额
1140
- fs['Return on Equity']=fs['Return on Net Asset']
1141
- fs['ROE']=fs['Return on Equity']
1142
- #毛利率:销售毛利 / 销售收入净额
1143
- fs['Gross Margin']=fs['GrossProfit']/fs['TotalRevenue']
1144
- #销售净利率:净利润 / 销售收入净额
1145
- fs['Profit Margin']=fs['NetIncome']/fs['TotalRevenue']
1146
- #成本费用净利率:净利润 / 成本费用总额
1147
- fs['Net Profit on Costs']=fs['NetIncome']/fs['CostOfRevenue']
1148
- #股利发放率:每股股利 / 每股利润
1149
- fs['Payout Ratio']=fs['CashDividendsPaid']/fs['NetIncome']
1150
-
1151
- ###每股指标,受EPS可用性影响
1152
- #每股利润:(净利润-优先股股利) / 加权流通在外股数。基本EPS
1153
- #注意:流通股股数=期初commonStock-treasuryStock,加本年增加的股数issuanceOfStock*月份占比-本年减少的股数repurchaseOfStock*月份占比
1154
- import numpy as np
1155
- fs['outstandingStock']=np.floor(fs['NetIncomeCommonStockholders']/fs['BasicEPS'])
1156
- #每股现金流量:(经营活动现金净流量-优先股股利) / 流通在外股数
1157
- fs['Cashflow per Share']=fs['OperatingCashFlow']/fs['outstandingStock']
1158
- fs['CFPS']=fs['Cashflow per Share']
1159
- #每股股利:(现金股利总额-优先股股利) /流通在外股数
1160
- fs['Dividend per Share']=fs['CashDividendsPaid']/fs['outstandingStock']
1161
- fs['DPS']=fs['Dividend per Share']
1162
- #每股净资产:股东权益总额 / 流通在外股数
1163
- fs['Net Asset per Share']=fs['CommonStockEquity']/fs['outstandingStock']
1164
-
1165
- #市盈率:每股市价 / 每股利润,依赖EPS反推出的流通股数量
1166
- #fs=get_PE(fs)
1167
- dateymd=lambda x:x.strftime('%Y-%m-%d')
1168
- fs['endDate']=fs['asOfDate'].apply(dateymd)
1169
-
1170
- fs['date']=fs['endDate']
1171
- fs.set_index('date',inplace=True)
1172
-
1173
- # 删除起初_begin字段
1174
- list_begin=[]
1175
- for b in list(fs):
1176
- if '_begin' in b:
1177
- list_begin=list_begin+[b]
1178
- fs.drop(list_begin,axis=1,inplace=True)
1179
-
1180
- return fs
1181
-
1182
-
1183
- if __name__ == '__main__':
1184
- fs=calc_fin_rates(fsdf)
1185
-
1186
- #==============================================================================
1187
- if __name__ == '__main__':
1188
- ticker='AAPL'
1189
- ticker='00700.HK'
1190
- ticker='601398.SS'
1191
-
1192
- fsr=get_financial_rates(ticker)
1193
-
1194
- def get_financial_rates(ticker):
1195
- """
1196
- 功能:获得股票的财务报表和财务比率
1197
- 财务报表:资产负债表,利润表,现金流量表
1198
- 财务比率:短期还债能力,长期还债能力,营运能力,盈利能力,发展能力
1199
- 返回:报表+比率
1200
- """
1201
- print("\n Analyzing financial rates of",ticker,"......")
1202
-
1203
- # 变换港股代码5位-->4位
1204
- result,prefix,suffix=split_prefix_suffix(ticker)
1205
- if result & (suffix=='HK'):
1206
- if len(prefix)==5:
1207
- ticker=ticker[1:]
1208
-
1209
- #抓取股票的财务报表
1210
- try:
1211
- fsdf=get_financial_statements(ticker)
1212
- except:
1213
- print(" Failed to get financial statements of",ticker,"\b, recovering")
1214
- sleep_random(max_sleep=60)
1215
- try:
1216
- fsdf=get_financial_statements(ticker)
1217
- except:
1218
- print(" Failed to get financial statements of",ticker,"\b!")
1219
- print(" If the stock code",ticker,"\b is correct, please try a few minutes later.")
1220
- return None
1221
-
1222
- #抓取股票的稀释后EPS,计算财务比率
1223
- fsr=calc_fin_rates(fsdf)
1224
- if fsr is None: return None
1225
- """
1226
- try:
1227
- fsr=calc_fin_rates(fsdf)
1228
- except:
1229
- print("......Failed to calculate some financial rates of",ticker,"\b!")
1230
- return None
1231
- """
1232
- #整理列名:将股票代码、截止日期、报表类型排在开头
1233
- cols=list(fsr)
1234
- cols.remove('endDate')
1235
- cols.remove('ticker')
1236
- cols.remove('periodType')
1237
- fsr2=fsr[['ticker','endDate','periodType']+cols]
1238
-
1239
- return fsr2
1240
-
1241
- """
1242
- 短期偿债能力分析:
1243
- 1、流动比率,计算公式: 流动资产 / 流动负债
1244
- 2、速动比率,计算公式: (流动资产-存货) / 流动负债
1245
- 3、现金比率,计算公式: (现金+现金等价物) / 流动负债
1246
- 4、现金流量比率,计算公式: 经营活动现金流量 / 流动负债
1247
-
1248
- 长期偿债能力分析:
1249
- 1、资产负债率,计算公式: 负债总额 / 资产总额
1250
- 2、股东权益比率,计算公式: 股东权益总额 / 资产总额
1251
- 3、权益乘数,计算公式: 资产总额 / 股东权益总额
1252
- 4、负债股权比率,计算公式: 负债总额 / 股东权益总额
1253
- 5、有形净值债务率,计算公式: 负债总额 / (股东权益-无形资产净额)
1254
- 6、偿债保障比率,计算公式: 负债总额 / 经营活动现金净流量
1255
- 7、利息保障倍数,计算公式: (税前利润+利息费用)/ 利息费用
1256
-
1257
- 营运分析
1258
- 1、存货周转率,计算公式: 销售成本 / 平均存货
1259
- 2、应收账款周转率,计算公式: 赊销收入净额 / 平均应收账款余额
1260
- 3、流动资产周转率,计算公式: 销售收入 / 平均流动资产余额
1261
- 4、固定资产周转率,计算公式: 销售收入 / 平均固定资产净额
1262
- 5、总资产周转率,计算公式: 销售收入 / 平均资产总额
1263
-
1264
- 盈利分析
1265
- 1、资产报酬率,计算公式: 利润总额+利息支出 / 平均资产总额
1266
- 2、净资产报酬率,计算公式: 净利润 / 平均净资产
1267
- 3、股东权益报酬率,计算公式: 净利润 / 平均股东权益总额
1268
- 4、毛利率,计算公式: 销售毛利 / 销售收入净额
1269
- 5、销售净利率,计算公式: 净利润 / 销售收入净额
1270
- 6、成本费用净利率,计算公式: 净利润 / 成本费用总额
1271
- 7、每股利润,计算公式: (净利润-优先股股利) / 流通在外股数
1272
- 8、每股现金流量,计算公式: (经营活动现金净流量-优先股股利) / 流通在外股数
1273
- 9、每股股利,计算公式: (现金股利总额-优先股股利) /流通在外股数
1274
- 10、股利发放率,计算公式: 每股股利 / 每股利润
1275
- 11、每股净资产,计算公式: 股东权益总额 / 流通在外股数
1276
- 12、市盈率,计算公式: 每股市价 / 每股利润
1277
- 13、主营业务利润率=主营业务利润/主营业务收入*100%
1278
-
1279
- 发展分析
1280
- 1、营业增长率,计算公式: 本期营业增长额 / 上年同期营业收入总额
1281
- 2、资本积累率,计算公式: 本期所有者权益增长额 / 年初所有者权益
1282
- 3、总资产增长率,计算公式: 本期总资产增长额 / 年初资产总额
1283
- 4、固定资产成新率,计算公式: 平均固定资产净值 / 平均固定资产原值
1284
- """
1285
- #==============================================================================
1286
- #==============================================================================
1287
- #==============================================================================
1288
- #####以上的指标为时间序列;以下的指标为非时间序列,类似于快照信息
1289
- #==============================================================================
1290
- if __name__=='__main__':
1291
- symbol='JD'
1292
- symbol='AAPL'
1293
- symbol='BABA'
1294
- symbol='2883.HK'
1295
- symbol='EBAY'
1296
-
1297
- stock_info(symbol)
1298
-
1299
- def stock_info(symbol):
1300
- """
1301
- 功能:返回静态信息
1302
- """
1303
- DEBUG=False
1304
- if DEBUG:
1305
- print(" DEBUG: in stock_info, symbol={}".format(symbol))
1306
-
1307
- from yahooquery import Ticker
1308
- stock = Ticker(symbol)
1309
-
1310
- """
1311
- Asset Profile:
1312
- Head office address/zip/country, Officers, Employees, industry/sector, phone/fax,
1313
- web site,
1314
- Risk ranks: auditRisk, boardRisk, compensationRisk, overallRisk, shareHolderRightRisk,
1315
- compensationRisk: 薪酬风险。Jensen 及 Meckling (1976)的研究指出薪酬與管理者的風險承擔
1316
- 具有關連性,站在管理者的立場來看,創新支出的投入使管理者承受更大的薪酬風險(compensation risk),
1317
- 管理者自然地要求更高的薪酬來補貼所面臨的風險,因此企業創新投資對管理者薪酬成正相關。
1318
- boardRisk: 董事会风险
1319
- shareHolderRightRisk:股权风险
1320
- """
1321
- adict=stock.asset_profile
1322
- keylist=list(adict[symbol].keys())
1323
- import pandas as pd
1324
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
1325
- ainfo=aframe.T
1326
- info=ainfo.copy()
1327
-
1328
-
1329
- """
1330
- ESG Scores: Risk measurements
1331
- peerGroup, ratingYear,
1332
- environmentScore, governanceScore, socialScore, totalEsg
1333
- dict: peerEnvironmentPerformance, peerGovernancePerformance, peerSocialPerformance,
1334
- peerEsgScorePerformance
1335
- """
1336
- adict=stock.esg_scores
1337
- try: #一些企业无此信息
1338
- keylist=list(adict[symbol].keys())
1339
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
1340
- ainfo=aframe.T
1341
- info=pd.concat([info,ainfo])
1342
- except:
1343
- pass
1344
-
1345
- """
1346
- Financial Data: TTM???
1347
- currentPrice, targetHighPrice, targetLowPrice, targetMeanPrice, targetMedianPrice,
1348
- currentRatio, debtToEquity, earningsGrowth, ebitda, ebitdaMargins, financialCurrency,
1349
- freeCashflow, grossMargins, grossProfits,
1350
- operatingCashflow, operatingMargins, profitMargins,
1351
- quickRatio, returnOnAssets, returnOnEquity, revenueGrowth, revenuePerShare,
1352
- totalCash, totalCashPerShare, totalDebt, totalRevenue,
1353
- """
1354
- adict=stock.financial_data
1355
- keylist=list(adict[symbol].keys())
1356
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
1357
- ainfo=aframe.T
1358
- info=pd.concat([info,ainfo])
1359
-
1360
-
1361
- """
1362
- Key Statistics: TTM???
1363
- 52WeekChang, SandP52WeekChang, beta, floatShares, sharesOutstanding,
1364
- bookValue, earningsQuarterlyGrowth, enterpriseToEbitda, enterpriseToRevenue,
1365
- enterpriseValue, netIncomeToCommon, priceToBook, profitMargins,
1366
- forwardEps, trailingEps,
1367
- heldPercentInsiders, heldPercentInstitutions,
1368
- lastFiscalYearEnd, lastSplitDate, lastSplitFactor, mostRecentQuarter, nextFiscalYearEnd,
1369
- """
1370
- adict=stock.key_stats
1371
- keylist=list(adict[symbol].keys())
1372
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
1373
- ainfo=aframe.T
1374
- info=pd.concat([info,ainfo])
1375
-
1376
-
1377
- """
1378
- Price Information:
1379
- currency, currencySymbol, exchange, exchangeName, shortName,
1380
- longName,
1381
- marketCap, marketState, quoteType,
1382
- regularMarketChange, regularMarketChangPercent, regularMarketHigh, regularMarketLow,
1383
- regularMarketOpen, regularMarketPreviousClose, regularMarketPrice, regularMarketTime,
1384
- regularMarketVolume,
1385
- """
1386
- adict=stock.price
1387
- keylist=list(adict[symbol].keys())
1388
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
1389
- ainfo=aframe.T
1390
- info=pd.concat([info,ainfo])
1391
-
1392
-
1393
- """
1394
- Quote Type:
1395
- exchange, firstTradeDateEpocUtc(上市日期), longName, quoteType(证券类型:股票),
1396
- shortName, symbol(当前代码), timeZoneFullName, timeZoneShortName, underlyingSymbol(原始代码),
1397
- """
1398
- adict=stock.quote_type
1399
- keylist=list(adict[symbol].keys())
1400
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
1401
- ainfo=aframe.T
1402
- info=pd.concat([info,ainfo])
1403
-
1404
-
1405
- """
1406
- Share Purchase Activity
1407
- period(6m), totalInsiderShares
1408
- """
1409
- adict=stock.share_purchase_activity
1410
- keylist=list(adict[symbol].keys())
1411
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
1412
- ainfo=aframe.T
1413
- info=pd.concat([info,ainfo])
1414
-
1415
-
1416
- """
1417
- # Summary detail
1418
- averageDailyVolume10Day, averageVolume, averageVolume10days, beta, currency,
1419
- dayHigh, dayLow, fiftyDayAverage, fiftyTwoWeekHigh, fiftyTwoWeekLow, open, previousClose,
1420
- regularMarketDayHigh, regularMarketDayLow, regularMarketOpen, regularMarketPreviousClose,
1421
- regularMarketVolume, twoHundredDayAverage, volume,
1422
- forwardPE, marketCap, priceToSalesTrailing12Months,
1423
- dividendRate, dividendYield, exDividendDate, payoutRatio, trailingAnnualDividendRate,
1424
- trailingAnnualDividendYield, trailingPE,
1425
- """
1426
- adict=stock.summary_detail
1427
- keylist=list(adict[symbol].keys())
1428
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
1429
- ainfo=aframe.T
1430
- info=pd.concat([info,ainfo])
1431
-
1432
-
1433
- """
1434
- summary_profile
1435
- address/city/country/zip, phone/fax, sector/industry, website/longBusinessSummary,
1436
- fullTimeEmployees,
1437
- """
1438
- adict=stock.summary_profile
1439
- keylist=list(adict[symbol].keys())
1440
- aframe=pd.DataFrame.from_dict(adict, orient='index', columns=keylist)
1441
- ainfo=aframe.T
1442
- info=pd.concat([info,ainfo])
1443
-
1444
- # 清洗数据项目
1445
- info.sort_index(inplace=True) #排序
1446
- info.dropna(inplace=True) #去掉空值
1447
- #去重
1448
- info['Item']=info.index
1449
- info.drop_duplicates(subset=['Item'],keep='last',inplace=True)
1450
-
1451
- #删除不需要的项目
1452
- delrows=['adult','alcoholic','animalTesting','ask','askSize','bid','bidSize', \
1453
- 'catholic','coal','controversialWeapons','furLeather','gambling', \
1454
- 'gmo','gmtOffSetMilliseconds','militaryContract','messageBoardId', \
1455
- 'nuclear','palmOil','pesticides','tobacco','uuid','maxAge']
1456
- for r in delrows:
1457
- info.drop(info[info['Item']==r].index,inplace=True)
1458
-
1459
- #修改列名
1460
- info.rename(columns={symbol:'Value'}, inplace=True)
1461
- del info['Item']
1462
-
1463
- infot=info.T
1464
- #有的股票信息中缺失returnOnAssets或payoutRatio
1465
- try:
1466
- #增加IGR
1467
- infot['IGR']=infot['returnOnAssets']*(1-infot['payoutRatio'])/(1-infot['returnOnAssets']*(1-infot['payoutRatio']))
1468
- except:
1469
- pass
1470
-
1471
- #增加SGR
1472
- try:
1473
- infot['SGR']=infot['returnOnEquity']*(1-infot['payoutRatio'])/(1-infot['returnOnEquity']*(1-infot['payoutRatio']))
1474
- except:
1475
- pass
1476
-
1477
- infott=infot.T
1478
-
1479
- return infott
1480
-
1481
-
1482
- if __name__=='__main__':
1483
- info=stock_info('AAPL')
1484
- info=stock_info('BABA')
1485
-
1486
- #==============================================================================
1487
- if __name__=='__main__':
1488
- info=stock_info('AAPL')
1489
-
1490
- def stock_basic(info):
1491
-
1492
- wishlist=['symbol','shortName','sector','industry', \
1493
-
1494
- #公司名称,业务
1495
- 'underlyingSymbol','longName', \
1496
-
1497
- #公司地址,网站
1498
- 'address1','address2','city','state','country','zip','phone','fax', \
1499
- 'timeZoneShortName','timeZoneFullName','website', \
1500
-
1501
- #员工人数
1502
- 'fullTimeEmployees', \
1503
-
1504
- #上市与交易所
1505
- 'exchange','exchangeName','quoteType', \
1506
-
1507
- #其他
1508
- 'beta','currency','currentPrice','marketCap','trailingPE', \
1509
-
1510
- 'ratingYear','ratingMonth']
1511
-
1512
- #按照wishlist的顺序从info中取值
1513
- rowlist=list(info.index)
1514
- import pandas as pd
1515
- info_sub=pd.DataFrame(columns=['Item','Value'])
1516
- infot=info.T
1517
- for w in wishlist:
1518
- if w in rowlist:
1519
- v=infot[w][0]
1520
- s=pd.Series({'Item':w,'Value':v})
1521
- try:
1522
- info_sub=info_sub.append(s,ignore_index=True)
1523
- except:
1524
- info_sub=info_sub._append(s,ignore_index=True)
1525
-
1526
- return info_sub
1527
-
1528
- if __name__=='__main__':
1529
- basic=stock_basic(info)
1530
-
1531
- #==============================================================================
1532
- if __name__=='__main__':
1533
- info=stock_info('AAPL')
1534
-
1535
- def stock_officers(info):
1536
-
1537
- wishlist=['symbol','shortName','sector','industry', \
1538
-
1539
- #公司高管
1540
- 'currency','companyOfficers', \
1541
-
1542
- ]
1543
-
1544
- #按照wishlist的顺序从info中取值
1545
- rowlist=list(info.index)
1546
- import pandas as pd
1547
- info_sub=pd.DataFrame(columns=['Item','Value'])
1548
- infot=info.T
1549
- for w in wishlist:
1550
- if w in rowlist:
1551
- v=infot[w][0]
1552
- s=pd.Series({'Item':w,'Value':v})
1553
- try:
1554
- info_sub=info_sub.append(s,ignore_index=True)
1555
- except:
1556
- info_sub=info_sub._append(s,ignore_index=True)
1557
-
1558
- return info_sub
1559
-
1560
- if __name__=='__main__':
1561
- sub_info=stock_officers(info)
1562
-
1563
- #==============================================================================
1564
- def stock_risk_general(info):
1565
-
1566
- wishlist=['symbol','shortName','sector','industry', \
1567
-
1568
- 'overallRisk','boardRisk','compensationRisk', \
1569
- 'shareHolderRightsRisk','auditRisk', \
1570
-
1571
- 'ratingYear','ratingMonth']
1572
-
1573
- #按照wishlist的顺序从info中取值
1574
- rowlist=list(info.index)
1575
- import pandas as pd
1576
- info_sub=pd.DataFrame(columns=['Item','Value'])
1577
- infot=info.T
1578
- for w in wishlist:
1579
- if w in rowlist:
1580
- v=infot[w][0]
1581
- s=pd.Series({'Item':w,'Value':v})
1582
- try:
1583
- info_sub=info_sub.append(s,ignore_index=True)
1584
- except:
1585
- info_sub=info_sub._append(s,ignore_index=True)
1586
-
1587
- return info_sub
1588
-
1589
- if __name__=='__main__':
1590
- risk_general=stock_risk_general(info)
1591
-
1592
- #==============================================================================
1593
- def stock_risk_esg(info):
1594
-
1595
- wishlist=['symbol','shortName','sector','industry', \
1596
-
1597
- 'totalEsg','esgPerformance','peerEsgScorePerformance', \
1598
- 'environmentScore','peerEnvironmentPerformance', \
1599
- 'socialScore','peerSocialPerformance', \
1600
- 'governanceScore','peerGovernancePerformance', \
1601
- 'peerGroup','relatedControversy','peerCount','percentile', \
1602
-
1603
- 'ratingYear','ratingMonth']
1604
-
1605
- #按照wishlist的顺序从info中取值
1606
- rowlist=list(info.index)
1607
- import pandas as pd
1608
- info_sub=pd.DataFrame(columns=['Item','Value'])
1609
- infot=info.T
1610
- for w in wishlist:
1611
- if w in rowlist:
1612
- v=infot[w][0]
1613
- s=pd.Series({'Item':w,'Value':v})
1614
- try:
1615
- info_sub=info_sub.append(s,ignore_index=True)
1616
- except:
1617
- info_sub=info_sub._append(s,ignore_index=True)
1618
-
1619
- return info_sub
1620
-
1621
- if __name__=='__main__':
1622
- risk_esg=stock_risk_esg(info)
1623
-
1624
- #==============================================================================
1625
- def stock_fin_rates(info):
1626
-
1627
- wishlist=['symbol','shortName','sector','industry', \
1628
-
1629
- 'financialCurrency', \
1630
-
1631
- #偿债能力
1632
- 'currentRatio','quickRatio','debtToEquity', \
1633
-
1634
- #盈利能力
1635
- 'ebitdaMargins','operatingMargins','grossMargins','profitMargins', \
1636
-
1637
- #股东回报率
1638
- 'returnOnAssets','returnOnEquity', \
1639
- 'dividendRate','trailingAnnualDividendRate','trailingEps', \
1640
- 'payoutRatio','revenuePerShare','totalCashPerShare', \
1641
-
1642
- #业务发展能力
1643
- 'revenueGrowth','earningsGrowth','earningsQuarterlyGrowth', \
1644
- 'enterpriseToRevenue','enterpriseToEbitda', \
1645
-
1646
- 'ratingYear','ratingMonth']
1647
-
1648
- #按照wishlist的顺序从info中取值
1649
- rowlist=list(info.index)
1650
- import pandas as pd
1651
- info_sub=pd.DataFrame(columns=['Item','Value'])
1652
- infot=info.T
1653
- for w in wishlist:
1654
- if w in rowlist:
1655
- v=infot[w][0]
1656
- s=pd.Series({'Item':w,'Value':v})
1657
- try:
1658
- info_sub=info_sub.append(s,ignore_index=True)
1659
- except:
1660
- info_sub=info_sub._append(s,ignore_index=True)
1661
-
1662
- return info_sub
1663
-
1664
- if __name__=='__main__':
1665
- fin_rates=stock_fin_rates(info)
1666
-
1667
- #==============================================================================
1668
- def stock_fin_statements(info):
1669
-
1670
- wishlist=['symbol','shortName','sector','industry', \
1671
-
1672
- 'financialCurrency','lastFiscalYearEnd','mostRecentQuarter','nextFiscalYearEnd', \
1673
-
1674
- #资产负债
1675
- 'enterpriseValue','totalDebt','marketCap', \
1676
-
1677
- #利润表
1678
- 'totalRevenue','grossProfits','ebitda','netIncomeToCommon', \
1679
-
1680
- #现金流量
1681
- 'operatingCashflow','freeCashflow','totalCash', \
1682
-
1683
- #股票数量
1684
- 'sharesOutstanding','floatShares','totalInsiderShares', \
1685
-
1686
- 'ratingYear','ratingMonth']
1687
-
1688
- #按照wishlist的顺序从info中取值
1689
- rowlist=list(info.index)
1690
- import pandas as pd
1691
- info_sub=pd.DataFrame(columns=['Item','Value'])
1692
- infot=info.T
1693
- for w in wishlist:
1694
- if w in rowlist:
1695
- v=infot[w][0]
1696
- s=pd.Series({'Item':w,'Value':v})
1697
- try:
1698
- info_sub=info_sub.append(s,ignore_index=True)
1699
- except:
1700
- info_sub=info_sub._append(s,ignore_index=True)
1701
-
1702
- return info_sub
1703
-
1704
- if __name__=='__main__':
1705
- fin_statements=stock_fin_statements(info)
1706
-
1707
- #==============================================================================
1708
- def stock_market_rates(info):
1709
-
1710
- wishlist=['symbol','shortName','sector','industry', \
1711
-
1712
- 'currency','currencySymbol', \
1713
-
1714
- #市场观察
1715
- 'priceToBook','priceToSalesTrailing12Months','recommendationKey', \
1716
-
1717
- #市场风险与收益
1718
- 'beta','52WeekChange','SandP52WeekChange', \
1719
- 'trailingEps','forwardEps','trailingPE','forwardPE','pegRatio', \
1720
-
1721
- #分红
1722
- 'dividendYield','fiveYearAvgDividendYield','trailingAnnualDividendYield', \
1723
-
1724
- #持股
1725
- 'heldPercentInsiders','heldPercentInstitutions', \
1726
-
1727
- #股票流通
1728
- 'sharesOutstanding','totalInsiderShares','floatShares', \
1729
- 'sharesPercentSharesOut','shortPercentOfFloat','shortRatio', \
1730
-
1731
- 'ratingYear','ratingMonth']
1732
-
1733
- #按照wishlist的顺序从info中取值
1734
- rowlist=list(info.index)
1735
- import pandas as pd
1736
- info_sub=pd.DataFrame(columns=['Item','Value'])
1737
- infot=info.T
1738
- for w in wishlist:
1739
- if w in rowlist:
1740
- v=infot[w][0]
1741
- s=pd.Series({'Item':w,'Value':v})
1742
- try:
1743
- info_sub=info_sub.append(s,ignore_index=True)
1744
- except:
1745
- info_sub=info_sub._append(s,ignore_index=True)
1746
-
1747
- return info_sub
1748
-
1749
- if __name__=='__main__':
1750
- market_rates=stock_market_rates(info)
1751
-
1752
- #==============================================================================
1753
- if __name__=='__main__':
1754
- ticker='01810.HK'
1755
- ticker='AAPL'
1756
- info_type='fin_rates'
1757
-
1758
- def get_stock_profile(ticker,info_type='basic',graph=True):
1759
- """
1760
- 功能:抓取和获得股票的信息
1761
- basic: 基本信息
1762
- fin_rates: 财务比率快照
1763
- fin_statements: 财务报表快照
1764
- market_rates: 市场比率快照
1765
- risk_general: 一般风险快照
1766
- risk_esg: 可持续发展风险快照(有些股票无此信息)
1767
- """
1768
- #print("\nSearching for snapshot info of",ticker,"\b, please wait...")
1769
-
1770
- typelist=['basic','officers','fin_rates','fin_statements','market_rates','risk_general','risk_esg','all']
1771
- if info_type not in typelist:
1772
- print(" #Sorry, info_type not supported for",info_type)
1773
- print(" Supported info_type:\n",typelist)
1774
- return None
1775
-
1776
- #改变港股代码,去掉前导的0或8
1777
- if '.HK' in ticker.upper():
1778
- ticker=ticker[-7:]
1779
-
1780
- info=stock_info(ticker)
1781
- if not graph: return info
1782
-
1783
- name=info.T['shortName'][0]
1784
- if info_type in ['basic','all']:
1785
- sub_info=stock_basic(info)
1786
- titletxt="***** "+name+": Basic Information *****"
1787
- printdf(sub_info,titletxt)
1788
-
1789
- if info_type in ['officers','all']:
1790
- sub_info=stock_officers(info)
1791
- titletxt="***** "+name+": Company Senior Management *****"
1792
- printdf(sub_info,titletxt)
1793
-
1794
- if info_type in ['fin_rates','all']:
1795
- sub_info=stock_fin_rates(info)
1796
- titletxt="***** "+name+": Fundamental Rates *****"
1797
- printdf(sub_info,titletxt)
1798
-
1799
- if info_type in ['fin_statements','all']:
1800
- sub_info=stock_fin_statements(info)
1801
- titletxt="***** "+name+": Financial Statements *****"
1802
- printdf(sub_info,titletxt)
1803
-
1804
- if info_type in ['market_rates','all']:
1805
- sub_info=stock_market_rates(info)
1806
- titletxt="***** "+name+": Market Rates *****"
1807
- printdf(sub_info,titletxt)
1808
-
1809
- if info_type in ['risk_general','all']:
1810
- sub_info=stock_risk_general(info)
1811
- titletxt="***** "+name+": Risk General *****"+ \
1812
- "\n(Bigger number means higher risk)"
1813
- printdf(sub_info,titletxt)
1814
-
1815
- if info_type in ['risk_esg','all']:
1816
- sub_info=stock_risk_esg(info)
1817
- if len(sub_info)==0:
1818
- print("#Error(get_stock_profile): esg info not available for",ticker)
1819
- else:
1820
- titletxt="***** "+name+": Sustainability Risk *****"+ \
1821
- "\n(Smaller number means less risky)"
1822
- printdf(sub_info,titletxt)
1823
-
1824
- return info
1825
-
1826
- if __name__=='__main__':
1827
- info=get_stock_profile(ticker,info_type='basic')
1828
- info=get_stock_profile(ticker,info_type='officers')
1829
- info=get_stock_profile(ticker,info_type='fin_rates')
1830
- info=get_stock_profile(ticker,info_type='fin_statements')
1831
- info=get_stock_profile(ticker,info_type='market_rates')
1832
- info=get_stock_profile(ticker,info_type='risk_general')
1833
- info=get_stock_profile(ticker,info_type='risk_esg')
1834
-
1835
- #==============================================================================
1836
- if __name__=='__main__':
1837
- ticker='AAPL'
1838
- info=stock_info(ticker)
1839
- sub_info=stock_officers(info)
1840
- titletxt="***** "+ticker+": Snr Management *****"
1841
-
1842
- def printdf(sub_info,titletxt):
1843
- """
1844
- 功能:整齐显示股票信息快照
1845
- """
1846
- print("\n"+titletxt)
1847
-
1848
- maxlen=0
1849
- for index,row in sub_info.iterrows():
1850
- if len(row['Item']) > maxlen: maxlen=len(row['Item'])
1851
-
1852
- for index,row in sub_info.iterrows():
1853
-
1854
- #特殊打印:高管信息
1855
- if row['Item']=="companyOfficers":
1856
- print_companyOfficers(sub_info)
1857
- continue
1858
-
1859
- #特殊打印:ESG同行状况
1860
- peerlist=["peerEsgScorePerformance","peerEnvironmentPerformance", \
1861
- "peerSocialPerformance","peerGovernancePerformance"]
1862
- if row['Item'] in peerlist:
1863
- print_peerPerformance(sub_info,row['Item'])
1864
- continue
1865
-
1866
- #特殊打印:ESG Social风险内容
1867
- if row['Item']=="relatedControversy":
1868
- print_controversy(sub_info,row['Item'])
1869
- continue
1870
-
1871
- thislen=maxlen-len(row['Item'])
1872
- print(row['Item'],'.'*thislen,'\b:',row['Value'])
1873
-
1874
- import datetime
1875
- today=datetime.date.today()
1876
- print("*** Source: Yahoo Finance,",today)
1877
-
1878
- return
1879
-
1880
- if __name__=='__main__':
1881
- printdf(sub_info,titletxt)
1882
-
1883
- #==============================================================================
1884
- if __name__=='__main__':
1885
- info=stock_info('AAPL')
1886
- sub_info=stock_officers(info)
1887
-
1888
- def print_companyOfficers(sub_info):
1889
- """
1890
- 功能:打印公司高管信息
1891
- """
1892
- item='companyOfficers'
1893
- itemtxt='Company officers:'
1894
- key1='name'
1895
- key2='title'
1896
- key3='yearBorn'
1897
- key4='age'
1898
- key6='totalPay'
1899
- key7='fiscalYear'
1900
- currency=list(sub_info[sub_info['Item'] == 'currency']['Value'])[0]
1901
- alist=list(sub_info[sub_info['Item'] == item]['Value'])[0]
1902
-
1903
- print(itemtxt)
1904
- for i in alist:
1905
- print(' '*4,i[key1])
1906
- print(' '*8,i[key2],'\b,',i[key4],'years old (born',i[key3],'\b)')
1907
- print(' '*8,'Total paid',currency+str(format(i[key6],',')),'@'+str(i[key7]))
1908
-
1909
- return
1910
-
1911
- if __name__=='__main__':
1912
- print_companyOfficers(sub_info)
1913
-
1914
- #==============================================================================
1915
- if __name__=='__main__':
1916
- info=stock_info('AAPL')
1917
- sub_info=stock_risk_esg(info)
1918
- item="peerEsgScorePerformance"
1919
-
1920
- def print_peerPerformance(sub_info,item):
1921
- """
1922
- 功能:打印ESG信息
1923
- """
1924
- maxlen=0
1925
- for index,row in sub_info.iterrows():
1926
- if len(row['Item']) > maxlen: maxlen=len(row['Item'])
1927
- thislen=maxlen-len(item)+2
1928
- itemtxt=item+'.'*thislen+'\b:'
1929
-
1930
- key1='min'
1931
- key2='avg'
1932
- key3='max'
1933
- i=list(sub_info[sub_info['Item'] == item]['Value'])[0]
1934
-
1935
- print(itemtxt)
1936
- print(' '*4,key1+':',i[key1],'\b,',key2+':',round(i[key2],2),'\b,',key3+':',i[key3])
1937
-
1938
- return
1939
-
1940
- if __name__=='__main__':
1941
- print_peerPerformance(sub_info,item)
1942
-
1943
- #==============================================================================
1944
- if __name__=='__main__':
1945
- info=stock_info('AAPL')
1946
- sub_info=stock_risk_esg(info)
1947
- item='relatedControversy'
1948
-
1949
- def print_controversy(sub_info,item):
1950
- """
1951
- 功能:打印ESG Social风险内容
1952
- """
1953
- maxlen=0
1954
- for index,row in sub_info.iterrows():
1955
- if len(row['Item']) > maxlen: maxlen=len(row['Item'])
1956
- thislen=maxlen-len(item)+2
1957
- itemtxt=item+'.'*thislen+'\b:'
1958
-
1959
- alist=list(sub_info[sub_info['Item'] == item]['Value'])[0]
1960
-
1961
- print(itemtxt)
1962
- for i in alist:
1963
- print(' '*4,i)
1964
-
1965
- return
1966
-
1967
- if __name__=='__main__':
1968
- print_controversy(sub_info,item)
1969
-
1970
- #==============================================================================
1971
- def calc_dupont(ticker):
1972
- """
1973
- 功能:计算股票ticker的杜邦分析项目
1974
- """
1975
- fsr2=get_financial_rates(ticker)
1976
- if fsr2 is None:
1977
- print(" #Error(calc_dupont): failed to retrieved info for",ticker)
1978
- return None
1979
-
1980
- dpidf=fsr2[['ticker','endDate','periodType','ROE','Profit Margin','Total Asset Turnover','Equity Multiplier']]
1981
- dpidf['pROE']=dpidf['Profit Margin']*dpidf['Total Asset Turnover']*dpidf['Equity Multiplier']
1982
-
1983
- return dpidf
1984
- #==============================================================================
1985
- if __name__=='__main__':
1986
- tickerlist=['AAPL','MSFT','FB']
1987
- fsdate='latest'
1988
- scale1 = 10
1989
- scale2 = 10
1990
- hatchlist=['.', 'o', '\\']
1991
-
1992
- def compare_dupont(tickerlist,fsdate='latest', \
1993
- sort='PM',facecolor='whitesmoke',font_size='16px', \
1994
- loc1='best',retry=10, \
1995
- scale1 = 10,scale2 = 10,hatchlist=['.', 'o', '\\']):
1996
- """
1997
- 功能:获得tickerlist中每只股票的杜邦分析项目,绘制柱状叠加比较图
1998
- tickerlist:股票代码列表,建议在10只以内
1999
- fsdate:财报日期,默认为最新一期季报/年报,或具体日期,格式:YYYY-MM-DD
2000
- scale1:用于放大销售净利率,避免与权益乘数数量级不一致导致绘图难看问题,可自行调整
2001
- scale2:用于放大总资产周转率,避免与权益乘数数量级不一致导致绘图难看问题,可自行调整
2002
- hatchlist:绘制柱状图的纹理,用于黑白打印时区分,可自定义,
2003
- 可用的符号:'-', '+', 'x', '\\', '*', 'o', 'O', '.'
2004
- """
2005
- import pandas as pd
2006
-
2007
- lang=check_language()
2008
- """
2009
- ticker ='Ticker'
2010
- name1 = 'Profit Margin'
2011
- name2 = 'Asset Turnover'
2012
- name3 = 'Equity Multiplier'
2013
- name4 = 'ROE'
2014
- name5 = 'Report Date'
2015
- name6 = 'Report Type'
2016
- """
2017
- ticker = '公司'
2018
- name1 = '销售净利率'
2019
- name2 = '总资产周转率'
2020
- name3 = '权益乘数'
2021
- name4 = '净资产收益率'
2022
- name5 = '财报日期'
2023
- name6 = '财报类型'
2024
-
2025
- import os, sys
2026
- class HiddenPrints:
2027
- def __enter__(self):
2028
- self._original_stdout = sys.stdout
2029
- sys.stdout = open(os.devnull, 'w')
2030
-
2031
- def __exit__(self, exc_type, exc_val, exc_tb):
2032
- sys.stdout.close()
2033
- sys.stdout = self._original_stdout
2034
-
2035
- dpidflist,dpilist,fsdatelist,fstypelist=[],[],[],[]
2036
- name1list,name2list,name3list,name4list,name5list,name6list=[],[],[],[],[],[]
2037
- newtickerlist=[]
2038
- print("Working on DuPont factsheet, it takes a very long time, take a breather ...")
2039
-
2040
- #第1次尝试
2041
- faillist=[]
2042
- for t in tickerlist:
2043
- try:
2044
- with HiddenPrints():
2045
- dpidf=calc_dupont(t)
2046
- except:
2047
- print(" #Warning(compare_dupont): found errors in accounting items, ignore",t)
2048
- continue
2049
-
2050
- #未出错,但未抓取到数据,再试
2051
- if dpidf is None:
2052
- faillist=faillist+[t]
2053
- #sleep_random(max_sleep=30)
2054
- continue
2055
-
2056
- if fsdate == 'latest':
2057
- try:
2058
- dpi=dpidf.tail(1)
2059
- except:
2060
- print(f" #Warning(compare_dupont): got empty data for {t} @ {fsdate} financials")
2061
- faillist=faillist+[t]
2062
- #sleep_random(max_sleep=30)
2063
- continue
2064
- elif fsdate == 'annual':
2065
- dpidf_tmp=dpidf[dpidf['periodType']=="12M"]
2066
- try:
2067
- dpi=dpidf_tmp.tail(1)
2068
- except:
2069
- print(f" #Warning(compare_dupont): got empty data for {t} @ {fsdate} financials")
2070
- faillist=faillist+[t]
2071
- #sleep_random(max_sleep=30)
2072
- continue
2073
-
2074
- elif fsdate == 'quarterly':
2075
- dpidf_tmp=dpidf[dpidf['periodType']=="3M"]
2076
- try:
2077
- dpi=dpidf_tmp.tail(1)
2078
- except:
2079
- print(f" #Warning(compare_dupont): got empty data for {t} @ {fsdate} financials")
2080
- faillist=faillist+[t]
2081
- #sleep_random(max_sleep=30)
2082
- continue
2083
- else: dpi=dpidf[dpidf['endDate']==fsdate]
2084
- if len(dpi) == 0:
2085
- print(" #Warning(compare_dupont): financial statements not found for",t,'@',fsdate)
2086
- faillist=faillist+[t]
2087
- #sleep_random(max_sleep=30)
2088
- continue
2089
-
2090
- newtickerlist=newtickerlist+[t]
2091
- dpidflist=dpidflist+[dpidf]
2092
- dpilist=dpilist+[dpi]
2093
- fsdatelist=fsdatelist+[dpi['endDate'][0]]
2094
- fstypelist=fstypelist+[dpi['periodType'][0]]
2095
-
2096
- name1list=name1list+[dpi['Profit Margin'][0]*scale1]
2097
- name2list=name2list+[dpi['Total Asset Turnover'][0]*scale2]
2098
- name3list=name3list+[dpi['Equity Multiplier'][0]]
2099
- name4list=name4list+[dpi['ROE'][0]]
2100
- name5list=name5list+[dpi['endDate'][0]]
2101
- name6list=name6list+[dpi['periodType'][0]]
2102
-
2103
- #显示进度
2104
- #print_progress_percent2(t,tickerlist,steps=5,leading_blanks=4)
2105
- print(f" *** Successfully obtained financial information for {t}")
2106
-
2107
- #第2次尝试
2108
- for i in range(retry):
2109
- if len(faillist) == 0: break
2110
-
2111
- tickerlist=faillist
2112
- faillist=[]
2113
-
2114
- for t in tickerlist:
2115
- try:
2116
- with HiddenPrints():
2117
- dpidf=calc_dupont(t)
2118
- except:
2119
- print(" #Warning(compare_dupont): found errors in accounting items, ignore",t)
2120
- continue
2121
-
2122
- #未出错,但未抓取到数据,再试
2123
- if dpidf is None:
2124
- faillist=faillist+[t]
2125
- #sleep_random(max_sleep=30)
2126
- continue
2127
-
2128
- if fsdate == 'latest':
2129
- try:
2130
- dpi=dpidf.tail(1)
2131
- except:
2132
- print(f" #Warning(compare_dupont): got empty data for {t} @ {fsdate} financials")
2133
- faillist=faillist+[t]
2134
- #sleep_random(max_sleep=30)
2135
- continue
2136
- elif fsdate == 'annual':
2137
- dpidf_tmp=dpidf[dpidf['periodType']=="12M"]
2138
- try:
2139
- dpi=dpidf_tmp.tail(1)
2140
- except:
2141
- print(f" #Warning(compare_dupont): got empty data for {t} @ {fsdate} financials")
2142
- faillist=faillist+[t]
2143
- #sleep_random(max_sleep=30)
2144
- continue
2145
-
2146
- elif fsdate == 'quarterly':
2147
- dpidf_tmp=dpidf[dpidf['periodType']=="3M"]
2148
- try:
2149
- dpi=dpidf_tmp.tail(1)
2150
- except:
2151
- print(f" #Warning(compare_dupont): got empty data for {t} @ {fsdate} financials")
2152
- faillist=faillist+[t]
2153
- #sleep_random(max_sleep=30)
2154
- continue
2155
- else: dpi=dpidf[dpidf['endDate']==fsdate]
2156
- if len(dpi) == 0:
2157
- print(" #Warning(compare_dupont): financial statements not found for",t,'@',fsdate)
2158
- faillist=faillist+[t]
2159
- #sleep_random(max_sleep=30)
2160
- continue
2161
-
2162
- newtickerlist=newtickerlist+[t]
2163
- dpidflist=dpidflist+[dpidf]
2164
- dpilist=dpilist+[dpi]
2165
- fsdatelist=fsdatelist+[dpi['endDate'][0]]
2166
- fstypelist=fstypelist+[dpi['periodType'][0]]
2167
-
2168
- name1list=name1list+[dpi['Profit Margin'][0]*scale1]
2169
- name2list=name2list+[dpi['Total Asset Turnover'][0]*scale2]
2170
- name3list=name3list+[dpi['Equity Multiplier'][0]]
2171
- name4list=name4list+[dpi['ROE'][0]]
2172
- name5list=name5list+[dpi['endDate'][0]]
2173
- name6list=name6list+[dpi['periodType'][0]]
2174
-
2175
- #显示进度
2176
- #print_progress_percent2(t,tickerlist,steps=5,leading_blanks=4)
2177
- print(f" *** Successfully obtained financial information for {t}")
2178
-
2179
-
2180
- if len(faillist) > 0:
2181
- print(f" ~~~ Pity: failed to fetch financials for {faillist}")
2182
-
2183
- tickerlist=newtickerlist
2184
- raw_data = {ticker:tickerlist,
2185
- name1:name1list,
2186
- name2:name2list,
2187
- name3:name3list,
2188
- name4:name4list,
2189
- name5:name5list,
2190
- name6:name6list}
2191
-
2192
- df = pd.DataFrame(raw_data,columns=[ticker,name1,name2,name3,name4,name5,name6])
2193
- num=len(df['公司'])
2194
- for i in range(num):
2195
- code=df.loc[i,'公司']
2196
- df.loc[i,'公司']=ticker_name(code)
2197
-
2198
- # 排序
2199
- if sort=='PM':
2200
- df.sort_values(name1,ascending=False,inplace=True)
2201
- sorttxt=text_lang(":按照"+name1+"降序排列",": By Descending"+name1)
2202
- elif sort=='TAT':
2203
- df.sort_values(name2,ascending=False,inplace=True)
2204
- sorttxt=text_lang(":按照"+name2+"降序排列",": By Descending"+name2)
2205
- elif sort=='EM':
2206
- df.sort_values(name3,ascending=False,inplace=True)
2207
- sorttxt=text_lang(":按照"+name3+"降序排列",": By Descending"+name3)
2208
- else:
2209
- df.sort_values(name1,ascending=False,inplace=True)
2210
- sorttxt=text_lang(":按照"+name1+"降序排列",": By Descending"+name1)
2211
-
2212
- # 绘图
2213
- #f,ax1 = plt.subplots(1,figsize=(10,5))
2214
- f,ax1 = plt.subplots(1,figsize=(12.8,6.4))
2215
- w = 0.75
2216
- x = [i+1 for i in range(len(df[name1]))]
2217
- #tick_pos = [i+(w/2.) for i in x]
2218
- tick_pos = [i for i in x]
2219
-
2220
- ax1.bar(x,df[name3],width=w,bottom=[i+j for i,j in zip(df[name1],df[name2])], \
2221
- label=ectranslate(name3),alpha=0.5,color='green',hatch=hatchlist[0], \
2222
- edgecolor='black',align='center')
2223
- ax1.bar(x,df[name2],width=w,bottom=df[name1],label=ectranslate(name2),alpha=0.5,color='red', \
2224
- hatch=hatchlist[1], edgecolor='black',align='center')
2225
- ax1.bar(x,df[name1],width=w,label=ectranslate(name1),alpha=0.5,color='blue', \
2226
- hatch=hatchlist[2], edgecolor='black',align='center')
2227
-
2228
- plt.xticks(tick_pos,df[ticker])
2229
- if lang == 'English':
2230
- plt.ylabel(texttranslate("杜邦分析分解项目"),fontsize=ylabel_txt_size)
2231
- else:
2232
- plt.ylabel("杜邦分析分解项目",fontsize=ylabel_txt_size)
2233
-
2234
- tickernamelist,fstypenamelist=[],[]
2235
- for i in range(num):
2236
- tickernamelist=tickernamelist+[ticker_name(tickerlist[i])]
2237
- if fstypelist[i]=='3M': fsname='季报'
2238
- else: fsname='年报'
2239
- fstypenamelist=fstypenamelist+[fsname]
2240
-
2241
- if lang == 'Chinese':
2242
- footnote='【'+'财报日期及类型'+'】'
2243
- else:
2244
- footnote='【'+texttranslate('财报日期及类型')+'】'
2245
-
2246
- #检查财报类型是否一致
2247
- name5types=len(df.groupby(name5).count())
2248
- if name5types > 1:
2249
- #财报类型不一致
2250
- linenum=0
2251
- for i in range(num):
2252
- if linenum % 4 == 3:
2253
- footnote=footnote+'\n'
2254
- footnote=footnote+ticker_name(tickerlist[i])+":"+fsdatelist[i]+","+fstypenamelist[i]
2255
- if linenum < num -1:
2256
- footnote=footnote+';'
2257
- linenum=linenum + 1
2258
- else:
2259
- footnote=footnote+fsdatelist[0]+","+fstypenamelist[0]
2260
-
2261
- import datetime; today=datetime.date.today()
2262
- #footnote1=footnote+'\n'+"【图示放大比例】"+name1+':x'+str(scale1)+','+name2+':x'+str(scale2)
2263
- if lang == 'Chinese':
2264
- footnote1="【图示放大比例】"+name1+':x'+str(scale1)+','+name2+':x'+str(scale2)
2265
- footnote2=footnote1+'\n'+"数据来源:雅虎财经,"+' '+str(today)
2266
- else:
2267
- footnote1=texttranslate("【图示放大比例】")+ectranslate(name1)+':x'+str(scale1)+','+ectranslate(name2)+':x'+str(scale2)
2268
- footnote2=footnote1+'\n'+texttranslate("数据来源: 雅虎财经,")+' '+str(today)
2269
- plt.xlabel(footnote2,fontsize=xlabel_txt_size)
2270
-
2271
- plt.legend(loc=loc1,fontsize=legend_txt_size)
2272
- if lang == 'Chinese':
2273
- plt.title("杜邦分析对比图"+sorttxt,fontsize=title_txt_size,fontweight='bold')
2274
- else:
2275
- plt.title(texttranslate("杜邦分析对比图")+sorttxt,fontsize=title_txt_size,fontweight='bold')
2276
- plt.xlim([min(tick_pos)-w,max(tick_pos)+w])
2277
-
2278
- plt.gca().set_facecolor('whitesmoke')
2279
- plt.show()
2280
-
2281
- #设置打印对齐
2282
- pd.set_option('display.max_columns', 1000)
2283
- pd.set_option('display.width', 1000)
2284
- pd.set_option('display.max_colwidth', 1000)
2285
- pd.set_option('display.unicode.ambiguous_as_wide', True)
2286
- pd.set_option('display.unicode.east_asian_width', True)
2287
-
2288
- df[name1]=df[name1]/scale1
2289
- df[name2]=df[name2]/scale2
2290
-
2291
- for i in range(num):
2292
- code=df.loc[i,'财报类型']
2293
- if code == '3M': df.loc[i,'财报类型']='季报'
2294
- else: df.loc[i,'财报类型']='年报'
2295
-
2296
- dfcols=list(df)
2297
- dfecols=[]
2298
- for c in dfcols:
2299
- ce=ectranslate(c)
2300
- dfecols=dfecols+[ce]
2301
- df[ce]=df[c]
2302
- df[ectranslate('财报类型')]=df['财报类型'].apply(lambda x:'Quarterly' if x=='季报' else 'Annual')
2303
- dfe=df[dfecols]
2304
-
2305
- titletxt=text_lang("杜邦分析分项数据表","Du Pont Identity Fact Sheet")
2306
- footnote=text_lang("数据来源: 雅虎财经","Data source: Yahoo Finance")+', '+str(today)
2307
- #确定表格字体大小
2308
- titile_font_size=font_size
2309
- heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
2310
-
2311
- df_display_CSS(df=df,titletxt=titletxt,footnote=footnote, \
2312
- facecolor=facecolor,decimals=4, \
2313
- titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
2314
- data_font_size=data_font_size)
2315
-
2316
-
2317
- #合并所有历史记录
2318
- alldf=pd.concat(dpidflist)
2319
- alldf.dropna(inplace=True)
2320
- del alldf['pROE']
2321
-
2322
- """
2323
- allnum=len(alldf)
2324
- for i in range(allnum):
2325
- code=alldf.loc[i,'periodType']
2326
- if code == '3M': alldf.loc[i,'periodType']='Quarterly'
2327
- else: alldf.loc[i,'periodType']='Annual'
2328
- """
2329
- return alldf
2330
-
2331
- if __name__=='__main__':
2332
- tickerlist=['IBM','DELL','WMT']
2333
- df=compare_dupont(tickerlist,fsdate='latest',scale1 = 100,scale2 = 10)
2334
- #==============================================================================
2335
-
2336
-
2337
-
2338
- #==============================================================================
2339
- #==============================================================================