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,1278 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- 本模块功能:计算财务报表比例,应用层
4
- 所属工具包:证券投资分析工具SIAT
5
- SIAT:Security Investment Analysis Tool
6
- 创建日期:2023年11月23日
7
- 最新修订日期:2023年11月23日
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.financials import *
24
- from siat.stock import *
25
- from siat.grafix import *
26
- #==============================================================================
27
- import matplotlib.pyplot as plt
28
-
29
- #plt.rcParams['figure.figsize']=(12.8,7.2)
30
- plt.rcParams['figure.figsize']=(12.8,6.4)
31
- plt.rcParams['figure.dpi']=300
32
- plt.rcParams['font.size'] = 13
33
- plt.rcParams['xtick.labelsize']=11 #横轴字体大小
34
- plt.rcParams['ytick.labelsize']=11 #纵轴字体大小
35
-
36
- title_txt_size=16
37
- ylabel_txt_size=14
38
- xlabel_txt_size=14
39
- legend_txt_size=14
40
-
41
- #设置绘图风格:网格虚线
42
- plt.rcParams['axes.grid']=True
43
- #plt.rcParams['grid.color']='steelblue'
44
- #plt.rcParams['grid.linestyle']='dashed'
45
- #plt.rcParams['grid.linewidth']=0.5
46
- #plt.rcParams['axes.facecolor']='whitesmoke'
47
-
48
- #处理绘图汉字乱码问题
49
- import sys; czxt=sys.platform
50
- if czxt in ['win32','win64']:
51
- plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置默认字体
52
- mpfrc={'font.family': 'SimHei'}
53
-
54
- if czxt in ['darwin']: #MacOSX
55
- plt.rcParams['font.family']= ['Heiti TC']
56
- mpfrc={'font.family': 'Heiti TC'}
57
-
58
- if czxt in ['linux']: #website Jupyter
59
- plt.rcParams['font.family']= ['Heiti TC']
60
- mpfrc={'font.family':'Heiti TC'}
61
-
62
- # 解决保存图像时'-'显示为方块的问题
63
- plt.rcParams['axes.unicode_minus'] = False
64
- #==============================================================================
65
- if __name__=='__main__':
66
- #测试1
67
- tickers="JD"
68
- analysis_type='Balance Sheet'
69
- fsdates='2023-12-31'
70
-
71
- font_size='16px'
72
- business_period='annual'
73
-
74
-
75
- tickers=["JD","00700.HK",'BABA','09999.HK']
76
- fsdates='2023-12-31'
77
-
78
- analysis_type='Balance Sheet'
79
- analysis_type='Income Statement'
80
- analysis_type='Cash Flow Statement'
81
-
82
- fs_analysis(tickers,fsdates,analysis_type='balance sheet')
83
- fs_analysis(tickers,fsdates,analysis_type='income statement')
84
- fs_analysis(tickers,fsdates,analysis_type='cash flow statement')
85
-
86
- tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
87
- fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
88
- fs_analysis(tickers,fsdates,analysis_type='fs summary')
89
- fs_analysis(tickers,fsdates,analysis_type='financial indicator')
90
-
91
- tickers='00700.HK'
92
- analysis_type='profile'
93
- category='profile'
94
- fs_analysis(tickers,fsdates,analysis_type='profile')
95
- fs_analysis(tickers,fsdates,analysis_type='profile',category='shareholder')
96
- fs_analysis(tickers,fsdates,analysis_type='profile',category='dividend')
97
- fs_analysis(tickers,fsdates,analysis_type='profile',category='business')
98
- fs_analysis(tickers,fsdates,analysis_type='profile',category='business',business_period='annual')
99
- fs_analysis(tickers,fsdates,analysis_type='profile',category='valuation')
100
- fs_analysis(tickers,fsdates,analysis_type='profile',category='financial')
101
-
102
- tickers='03333.HK'; analysis_type='financial indicator'
103
-
104
- def fs_analysis(tickers,fsdates=[],analysis_type='balance sheet', \
105
- category='profile',business_period='annual', \
106
- items_included='all', \
107
- scale1=10,scale2=10,dupont_sort='PM',
108
- printout=True, \
109
- #entry_sort=False, \
110
- facecolor='papayawhip',font_size='16px'
111
- ):
112
- """
113
- ===========================================================================
114
- 功能:分析境外上市公司财报信息
115
-
116
- 主要参数:
117
- tickers:股票列表,对比分析时需要多个股票,单列财报时仅取第一个股票
118
- fsdates:财报日期,可为单个日期或日期列表,注意境外上市公司财报日期与中国大陆的不同
119
-
120
- analysis_type:分析类型,可为企业概况('profile')、资产负债表简表('balance sheet')、
121
- 利润表简表('income statement')、现金流量表简表('cash flow')、财报概况('financial summary')、
122
- 财务比率('financial indicator')、杜邦分析('dupont identity')
123
-
124
- category:企业概况分类,,仅当analysis_type='profile'时有效,
125
- 可为基本信息'profile'、高管概况('officers')、分红('dividend')、股票分拆('split')、市场表现('market')、
126
- 财务状况('financial')、一般风险('risk')、ESG风险('esg')
127
-
128
- business_period:业务期间类型,可为季报'quarterly',默认年报'annual'、最近的6次报告'recent', 所有'all'
129
- items_included:默认输出所有报表项目,可以列表形式选择其中一部分。
130
- scale1:仅用于杜邦分析,放大倍数(以便缩小与EM之间的数量级差异),用于Profit Margin,默认10
131
- scale2:仅用于杜邦分析,放大倍数,用于Total Asset Turnover,默认10
132
- dupont_sort:仅用于杜邦分析,用于排序指标,默认净利润率'PM',还可为总资产周转率'TAT'或权益乘数'EM'
133
- printout:是否显示数据表,默认是True
134
- facecolor:背景颜色,默认小麦黄'papayawhip'
135
- font_size:标题字体大小,默认'16px'
136
-
137
- 示例:
138
- #指定上市公司的股票代码:苹果
139
- ticker='AAPL'
140
- #指定进行对比的上市公司股票代码:苹果,微软,英伟达,高通
141
- tickers=['AAPL','MSFT','NVDA','QCOM']
142
- # 公司基本信息
143
- profile=fs_analysis(ticker,analysis_type='profile')
144
- # 证券分红
145
- dividend=fs_analysis(ticker,analysis_type='profile',category='dividend')
146
- # 证券分拆
147
- split=fs_analysis(ticker,analysis_type='profile',category='split')
148
- # 基本市场指标
149
- frates=fs_analysis(ticker,analysis_type='profile',category='market')
150
- # 基本财务比率
151
- frates=fs_analysis(ticker,analysis_type='profile',category='financial')
152
- # 一般风险评估
153
- frates=fs_analysis(ticker,analysis_type='profile',category='risk')
154
- # ESG风险评估
155
- frates=fs_analysis(ticker,analysis_type='profile',category='esg')
156
- # Balance sheet
157
- bs=fs_analysis(ticker,
158
- analysis_type='balance sheet')
159
- # Income statement
160
- ist=fs_analysis(ticker,
161
- analysis_type='income statement')
162
- # Cash flow statement
163
- cfs=fs_analysis(ticker,
164
- analysis_type='cash flow statement')
165
- # Financial summary
166
- fs=fs_analysis(ticker,
167
- analysis_type='financial summary')
168
- # Financial ratios:单个企业
169
- fs=fs_analysis(ticker,
170
- analysis_type='financial indicator')
171
- # Financial ratios:同行对比。注意:美股上市公司年报日期不统一,可比性较差!
172
- fs=fs_analysis(tickers,
173
- analysis_type='financial indicator')
174
- # Dupont identity:同行对比
175
- fs=fs_analysis(tickers,
176
- analysis_type='dupont identity')
177
-
178
- 注意1:仅从雅虎财经获取数据
179
- 注意2:不同经济体上市公司报表币种可能不同,金额项目仅进行同公司对比,不进行公司间对比
180
- 注意3:公司间仅对比财务比率和杜邦分析
181
- 注意4:不同经济体上市公司年报季报日期不同,需要列示报表日期和类型(年报或季报)
182
-
183
- """
184
- DEBUG=False
185
-
186
- import numpy as np
187
- import pandas as pd
188
-
189
- #屏蔽函数内print信息输出的类
190
- import os, sys
191
- class HiddenPrints:
192
- def __enter__(self):
193
- self._original_stdout = sys.stdout
194
- sys.stdout = open(os.devnull, 'w')
195
-
196
- def __exit__(self, exc_type, exc_val, exc_tb):
197
- sys.stdout.close()
198
- sys.stdout = self._original_stdout
199
-
200
- # 统一转小写,便于判断
201
- analysis_type1=analysis_type.lower()
202
-
203
- # 今日
204
- import datetime as dt
205
- todaydt=dt.date.today().strftime('%Y-%m-%d')
206
-
207
- # 定义数量级
208
- million=1000000
209
- billion=million * 1000
210
-
211
- #确定表格字体大小
212
- titile_font_size=font_size
213
- heading_font_size=data_font_size=str(int(font_size.replace('px',''))-3)+'px'
214
-
215
- # 基于analysis_type1的类型分别处理
216
- #if ('profile' in analysis_type1):
217
- if contains_any(analysis_type1,['profile']):
218
- # 股票需为单只股票,若为列表则仅取第一个
219
- if not isinstance(tickers,str):
220
- if isinstance(tickers,list): tickers=tickers[0]
221
- else:
222
- print(" #Warning(fs_analysis_china): {} must be one ticker or ticker list".format(tickers))
223
- return None
224
-
225
- # 检查category
226
- #category_list=['profile','officers','market_rates','dividend','split','fin_rates','risk_general','risk_esg']
227
- category_list=['profile','officers','market rates','dividend','split','financial rates','general risk','esg']
228
-
229
- #if category == 'profile':
230
- if contains_any(category,['profile']):
231
- info=get_stock_profile(tickers)
232
- #elif category == 'dividend':
233
- elif contains_any(category,['dividend']):
234
- #info=stock_dividend(tickers,start='1990-1-1',end=todaydt)
235
- info=stock_dividend(tickers)
236
- #elif category == 'stock_split':
237
- elif contains_any(category,['split']):
238
- #info=stock_split(tickers,start='1990-1-1',end=todaydt)
239
- info=stock_split(tickers)
240
- elif contains_any(category,['market']):
241
- category='market_rates'
242
- info=get_stock_profile(tickers,info_type=category)
243
- elif contains_any(category,['financial']):
244
- category='fin_rates'
245
- info=get_stock_profile(tickers,info_type=category)
246
-
247
- elif contains_any(category,['risk']):
248
- #这里的是风险指标,数值越大风险越高,数值越小越好
249
- category='risk_general'
250
- info=get_stock_profile(tickers,info_type=category)
251
- elif contains_any(category,['esg']):
252
- #这里的ESG为风险指标,数值越大风险越高,数值越小越好
253
- category='risk_esg'
254
- info=get_stock_profile(tickers,info_type=category)
255
- else:
256
- print(" Unsupported category {}, supported categories:".format(category))
257
- print_list(category_list,leading_blanks=2)
258
-
259
- return info
260
- #elif ('balance' in analysis_type1) or ('sheet' in analysis_type1) or ('asset' in analysis_type1) or ('liability' in analysis_type1):
261
- #elif contains_any(analysis_type1,['balance','sheet','asset','liability']):
262
- elif contains_any(analysis_type1,['balance','sheet','asset','liability']):
263
- # 股票需为单只股票,若为列表则仅取第一个
264
- if not isinstance(tickers,str):
265
- if isinstance(tickers,list): tickers=tickers[0]
266
- else:
267
- print(" #Warning(fs_analysis_china): must be one ticker or first ticker in a list for",tickers)
268
- return None
269
-
270
- # 分析资产负债表
271
- fsdf=get_balance_sheet(symbol=tickers)
272
- if fsdf is None:
273
- print(f" #Warning(fs_analysis): failed to access financial info for {tickers}")
274
- if test_yahoo_access():
275
- print(f" Solution: if {tickers} are correct, then try again later")
276
- else:
277
- print(" Problem: no internet connection to Yahoo for retrieveing data")
278
- return None
279
-
280
- fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
281
- fsdf.set_index('reportDate',inplace=True)
282
- fsdf.fillna(0,inplace=True)
283
-
284
- fsdf2=fsdf.copy()
285
- collist=list(fsdf2)
286
- for c in collist:
287
- try:
288
- fsdf2[c]=round(fsdf2[c] / billion,2)
289
- except:
290
- continue
291
-
292
- # 变换年报/季报
293
- fsdf2['periodType']=fsdf2['periodType'].apply(lambda x: 'Annual' if x=='12M' else 'Quarterly')
294
-
295
- # 删除不用的列
296
- currency=fsdf2['currencyCode'].values[0]
297
- #droplist=['currencyCode','TA-TL-TE','asOfDate']
298
- droplist=['currencyCode','asOfDate']
299
- fsdf2.drop(droplist,axis=1,inplace=True)
300
-
301
- # 打印前处理
302
- if printout:
303
- # 降序排列
304
- fsdf3=fsdf2.sort_index(ascending=False)
305
-
306
- business_period=business_period.lower()
307
- if business_period == 'recent':
308
- fsdf4=fsdf3.head(6)
309
- elif business_period == 'quarterly':
310
- fsdf4=fsdf3[fsdf3['periodType']=='Quarterly']
311
- elif business_period == 'annual':
312
- fsdf4=fsdf3[fsdf3['periodType']=='Annual']
313
- else: #'all'
314
- #fsdf4=fsdf3[fsdf3['periodType'].isin(['Annual','Quarterly'])]
315
- fsdf4=fsdf3
316
-
317
- # 转置
318
- fsdf4=fsdf4.T
319
-
320
- fsdf4.replace(0,'---',inplace=True)
321
-
322
- #titletxt="\n***** "+ticker_name(tickers)+": BALANCE SHEET"+' *****\n'
323
- titletxt=ticker_name(tickers,'stock')+text_lang(":资产负债简表",": BALANCE SHEET")
324
- #print(titletxt)
325
- """
326
- tablefmt_list=["plain","simple","github","grid","simple_grid","rounded_grid", \
327
- "heavy_grid","mixed_grid","double_grid","fancy_grid","outline", \
328
- "simple_outline","rounded_outline","heavy_outline", \
329
- "mixed_outline","double_outline","fancy_outline","pipe", \
330
- "orgtbl","asciidoc","jira","presto","pretty","psql", \
331
- "rst","mediawiki","moinmoin","youtrack","html","unsafehtml", \
332
- "latex","latex_raw","latex_booktabs","latex_longtable", \
333
- "textile","tsv"]
334
- for t in tablefmt_list:
335
- print("\n\n ========== tablefmt: "+t+" ============\n")
336
- alignlist=['left']+['right']*(len(list(fsdf3))-1)
337
- print(fsdf3.to_markdown(tablefmt=t,index=True,colalign=alignlist))
338
- """
339
- #print(fsdf3)
340
- """
341
- collist=list(fsdf3)
342
- fsdf3['Item']=fsdf3.index
343
- fsdf4=fsdf3[['Item']+collist]
344
- pandas2prettytable(fsdf4,titletxt,firstColSpecial=False,leftColAlign='l',otherColAlign='r')
345
- """
346
- collist=list(fsdf4)
347
- fsdf4['Item']=fsdf4.index
348
- fsdf5=fsdf4[['Item']+collist]
349
- fsdf6=df_filter_row(fsdf5,exclude_collist=['Item'],symbol='---')
350
-
351
- fsdf6=df_sort_priority_list(fsdf6,sort_column='Item',priorityList=['periodType'],ascending=True)
352
- """
353
- alignlist=['left']+['right']*(len(list(fsdf5))-1)
354
- print(fsdf6.to_markdown(tablefmt='plain',index=False,colalign=alignlist))
355
- """
356
-
357
- footnote1="Amount unit: "+currency+" billion, exchange's local accounting standards"
358
- footnote2="Data source: Yahoo Finance, "+str(todaydt)
359
- footnote='Note:\n'+footnote1+'\n'+footnote2
360
- #print('\n',footnote1,'\n',footnote2)
361
-
362
- # 将Item科目名称拆分加空格和转大写
363
- fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
364
-
365
- # 判断是否仅输出部分科目
366
- if 'all' in items_included:
367
- fsdf7=fsdf6
368
- else:
369
- mask=fsdf6['Item'].isin(items_included)
370
- fsdf7=fsdf6[mask]
371
- # 将Item列转为分类类型,指定顺序
372
- fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
373
- # 按分类顺序排序
374
- fsdf7=fsdf7.sort_values(by='Item')
375
-
376
- df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
377
- titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
378
- data_font_size=data_font_size)
379
-
380
- return fsdf6
381
-
382
- else:
383
- return fsdf2
384
- #elif ('income' in analysis_type1) or ('cost' in analysis_type1) or ('expense' in analysis_type1) or ('earnings' in analysis_type1):
385
- elif contains_any(analysis_type1,['income','revenue','cost','expense','earnings']):
386
- # 股票需为单只股票,若为列表则仅取第一个
387
- if not isinstance(tickers,str):
388
- if isinstance(tickers,list): tickers=tickers[0]
389
- else:
390
- print(" #Warning(fs_analysis_china): must be one ticker or first ticker in a list for",tickers)
391
- return None
392
-
393
- # 分析利润表
394
- fsdf=get_income_statements(symbol=tickers)
395
- if fsdf is None:
396
- print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
397
- if test_yahoo_access():
398
- print(f" Solution: if {tickers} are correct, then try again later")
399
- else:
400
- print(" Problem: no internet connection to Yahoo for retrieveing data")
401
-
402
- return None
403
-
404
- fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
405
- fsdf.set_index('reportDate',inplace=True)
406
- fsdf.fillna(0,inplace=True)
407
-
408
- fsdf2=fsdf.copy()
409
- collist=list(fsdf2)
410
- for c in collist:
411
- try:
412
- fsdf2[c]=round(fsdf2[c] / billion,2)
413
- except:
414
- continue
415
-
416
- # 变换年报/季报
417
- fsdf2['periodType']=fsdf2['periodType'].apply(lambda x: 'Annual' if x=='12M' else 'Quarterly')
418
-
419
- # 删除不用的列
420
- currency=fsdf2['currencyCode'].values[0]
421
- droplist=['currencyCode','asOfDate']
422
- fsdf2.drop(droplist,axis=1,inplace=True)
423
-
424
- # 打印前处理
425
- if printout:
426
- # 降序排列
427
- fsdf3=fsdf2.sort_index(ascending=False)
428
-
429
- business_period=business_period.lower()
430
- if business_period == 'recent':
431
- fsdf4=fsdf3.head(6)
432
- elif business_period == 'quarterly':
433
- fsdf4=fsdf3[fsdf3['periodType']=='Quarterly']
434
- elif business_period == 'annual':
435
- fsdf4=fsdf3[fsdf3['periodType']=='Annual']
436
- else:
437
- fsdf4=fsdf3[fsdf3['periodType']=='Annual']
438
-
439
- # 转置
440
- fsdf4=fsdf4.T
441
-
442
- fsdf4.replace(0,'---',inplace=True)
443
-
444
- #titletxt="\n***** "+ticker_name(tickers)+": INCOME STATEMENTS"+' *****\n'
445
- titletxt=ticker_name(tickers,'stock')+text_lang(":利润简表",": INCOME STATEMENTS")
446
- #print(titletxt)
447
-
448
- collist=list(fsdf4)
449
- fsdf4['Item']=fsdf4.index
450
- fsdf5=fsdf4[['Item']+collist]
451
- fsdf6=df_filter_row(fsdf5,exclude_collist=['Item'],symbol='---')
452
-
453
- fsdf6=df_sort_priority_list(fsdf6,sort_column='Item',priorityList=['periodType'],ascending=True)
454
- """
455
- alignlist=['left']+['right']*(len(list(fsdf5))-1)
456
- print(fsdf6.to_markdown(tablefmt='plain',index=False,colalign=alignlist))
457
- """
458
- footnote1="Amount unit: "+currency+" billion, exchange's local accounting standards"
459
- footnote2="Data source: Yahoo Finance, "+str(todaydt)
460
- footnote='Note:\n'+footnote1+'\n'+footnote2
461
- #print('\n',footnote1,'\n',footnote2)
462
-
463
- # 将Item科目名称拆分加空格和转大写
464
- fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
465
-
466
- # 判断是否仅输出部分科目
467
- if 'all' in items_included:
468
- fsdf7=fsdf6
469
- else:
470
- mask=fsdf6['Item'].isin(items_included)
471
- fsdf7=fsdf6[mask]
472
- # 将Item列转为分类类型,指定顺序
473
- fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
474
- # 按分类顺序排序
475
- fsdf7=fsdf7.sort_values(by='Item')
476
-
477
- df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
478
- titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
479
- data_font_size=data_font_size)
480
-
481
- return fsdf6
482
-
483
- return fsdf2
484
- #elif ('cash' in analysis_type1) or ('flow' in analysis_type1):
485
- elif contains_any(analysis_type1,['cash','flow']):
486
- # 股票需为单只股票,若为列表则仅取第一个
487
- if not isinstance(tickers,str):
488
- if isinstance(tickers,list): tickers=tickers[0]
489
- else:
490
- print(" #Warning(fs_analysis_china): must be one ticker or first ticker in a list for",tickers)
491
- return None
492
-
493
- # 分析现金流量表
494
- fsdf=get_cashflow_statements(symbol=tickers)
495
- if fsdf is None:
496
- print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
497
- if test_yahoo_access():
498
- print(f" Solution: if {tickers} are correct, then try again later")
499
- else:
500
- print(" Problem: no internet connection to Yahoo for retrieveing data")
501
-
502
- return None
503
-
504
- fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
505
- fsdf.set_index('reportDate',inplace=True)
506
- fsdf.fillna(0,inplace=True)
507
-
508
- fsdf2=fsdf.copy()
509
- collist=list(fsdf2)
510
- for c in collist:
511
- try:
512
- fsdf2[c]=round(fsdf2[c] / billion,2)
513
- except:
514
- continue
515
-
516
- # 变换年报/季报
517
- fsdf2['periodType']=fsdf2['periodType'].apply(lambda x: 'Annual' if x=='12M' else 'Quarterly')
518
-
519
- # 删除不用的列
520
- currency=fsdf2['currencyCode'].values[0]
521
- droplist=['currencyCode','asOfDate']
522
- fsdf2.drop(droplist,axis=1,inplace=True)
523
-
524
- # 打印前处理
525
- if printout:
526
- # 降序排列
527
- fsdf3=fsdf2.sort_index(ascending=False)
528
-
529
- business_period=business_period.lower()
530
- if business_period == 'recent':
531
- fsdf4=fsdf3.head(6)
532
- elif business_period == 'quarterly':
533
- fsdf4=fsdf3[fsdf3['periodType']=='Quarterly']
534
- elif business_period == 'annual':
535
- fsdf4=fsdf3[fsdf3['periodType']=='Annual']
536
- else:
537
- fsdf4=fsdf3[fsdf3['periodType']=='Annual']
538
-
539
- # 转置
540
- fsdf4=fsdf4.T
541
-
542
- fsdf4.replace(0,'---',inplace=True)
543
-
544
- #titletxt="\n***** "+ticker_name(tickers)+": CASHFLOW STATEMENTS"+' *****\n'
545
- titletxt=ticker_name(tickers,'stock')+text_lang(":现金流量简表",": CASHFLOW STATEMENTS")
546
- #print(titletxt)
547
-
548
- collist=list(fsdf4)
549
- fsdf4['Item']=fsdf4.index
550
- fsdf5=fsdf4[['Item']+collist]
551
- fsdf6=df_filter_row(fsdf5,exclude_collist=['Item'],symbol='---')
552
-
553
- fsdf6=df_sort_priority_list(fsdf6,sort_column='Item',priorityList=['periodType'],ascending=True)
554
- """
555
- alignlist=['left']+['right']*(len(list(fsdf5))-1)
556
- print(fsdf6.to_markdown(tablefmt='plain',index=False,colalign=alignlist))
557
- """
558
- footnote1="Amount unit: "+currency+" billion, exchange's local accounting standards"
559
- footnote2="Data source: Yahoo Finance, "+str(todaydt)
560
- footnote='Note:\n'+footnote1+'\n'+footnote2
561
- #print('\n',footnote1,'\n',footnote2)
562
-
563
- # 将Item科目名称拆分加空格和转大写
564
- fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
565
-
566
- # 判断是否仅输出部分科目
567
- if 'all' in items_included:
568
- fsdf7=fsdf6
569
- else:
570
- mask=fsdf6['Item'].isin(items_included)
571
- fsdf7=fsdf6[mask]
572
- # 将Item列转为分类类型,指定顺序
573
- fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
574
- # 按分类顺序排序
575
- fsdf7=fsdf7.sort_values(by='Item')
576
-
577
- df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
578
- titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
579
- data_font_size=data_font_size)
580
- return fsdf6
581
-
582
- return fsdf2
583
- #elif ('summary' in analysis_type1):
584
- elif contains_any(analysis_type1,['summary']):
585
- itemlist1=[
586
- #资产负债表
587
- 'CashAndCashEquivalents','AccountsReceivable','Inventory', \
588
- 'CurrentAssets','NetPPE','Goodwill','TotalAssets', \
589
- 'CurrentLiabilities','LongTermDebt','TotalLiabilities','TotalEquities', \
590
- #利润表
591
- 'TotalRevenue','GrossProfit','OperatingRevenue','OperatingIncome', \
592
- 'GeneralAndAdministrativeExpense','EBITDA','PretaxIncome', \
593
- 'NetIncome', \
594
- 'NetIncomeCommonStockholders','NetIncomeContinuousOperations', \
595
- #现金表
596
- 'OperatingCashFlow', \
597
- 'FreeCashFlow', \
598
- ]
599
-
600
- itemlist2=[
601
- #财务指标
602
- 'BasicEPS','DilutedEPS', \
603
- 'Gross Margin','Operating Margin','Profit Margin', \
604
- 'Return on Equity','Return on Asset','Debt to Asset', \
605
- ]
606
- itemlist=itemlist1+itemlist2
607
-
608
- # 股票可为单只股票(单只股票深度分析)
609
- if isinstance(tickers,str):
610
- print(" Getting financial rates for financial summary of",tickers,"...")
611
- with HiddenPrints():
612
- fsdf=get_financial_rates(tickers)
613
- if fsdf is None:
614
- print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
615
- if test_yahoo_access():
616
- print(f" Solution: if {tickers} are correct, then try again later")
617
- else:
618
- print(" Problem: no internet connection to Yahoo for retrieveing data")
619
-
620
- return None
621
-
622
- fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
623
- fsdf.set_index('reportDate',inplace=True)
624
-
625
- fsdf.replace([np.inf, -np.inf], np.nan, inplace=True)
626
- fsdf.fillna(0,inplace=True)
627
-
628
- currency=fsdf['currencyCode'].values[0]
629
-
630
- # 变换年报/季报
631
- fsdf['periodType']=fsdf['periodType'].apply(lambda x: 'Annual' if x=='12M' else 'Quarterly')
632
-
633
- # 删除不用的列
634
- fsdf2=fsdf.copy()
635
- collist=list(fsdf2)
636
- keeplist=[]
637
- for c in itemlist:
638
- if c in collist:
639
- keeplist=keeplist+[c]
640
- if c in itemlist1:
641
- try:
642
- fsdf2[c]=fsdf2[c].apply(lambda x: round(x / billion,2))
643
- except: pass
644
- else:
645
- fsdf2[c]=fsdf2[c].apply(lambda x: round(x,4))
646
- else: pass
647
-
648
- keeplist=['periodType']+keeplist
649
- fsdf2=fsdf2[keeplist]
650
-
651
- # 打印处理
652
- if printout:
653
- # 降序排列
654
- fsdf3=fsdf2.sort_index(ascending=False)
655
-
656
- business_period=business_period.lower()
657
- if business_period == 'recent':
658
- fsdf4=fsdf3.head(6)
659
- elif business_period == 'quarterly':
660
- fsdf4=fsdf3[fsdf3['periodType']=='Quarterly']
661
- elif business_period == 'annual':
662
- fsdf4=fsdf3[fsdf3['periodType']=='Annual']
663
- elif business_period == 'all':
664
- fsdf4=fsdf3
665
- #fsdf4=fsdf3[fsdf3['periodType'].isin(['Annual','Quarterly'])]
666
- else:
667
- #fsdf4=fsdf3[fsdf3['periodType']=='Annual']
668
- fsdf4=fsdf3
669
-
670
- # 转置
671
- fsdf4=fsdf4.T
672
-
673
- fsdf4.replace(0,'---',inplace=True)
674
-
675
- #titletxt="\n***** "+ticker_name(tickers)+": FINANCIAL STATEMENT SUMMARY"+' *****\n'
676
- titletxt=ticker_name(tickers,'stock')+text_lang(":财报摘要",": FINANCIAL STATEMENT SUMMARY")
677
- #print(titletxt)
678
-
679
- collist=list(fsdf4)
680
- fsdf4['Item']=fsdf4.index
681
- fsdf5=fsdf4[['Item']+collist]
682
- fsdf6=df_filter_row(fsdf5,exclude_collist=['Item'],symbol='---')
683
-
684
- fsdf6=df_sort_priority_list(fsdf6,sort_column='Item',priorityList=['periodType'],ascending=True)
685
- """
686
- alignlist=['left']+['right']*(len(list(fsdf5))-1)
687
- print(fsdf6.to_markdown(tablefmt='plain',index=False,colalign=alignlist))
688
- """
689
- footnote1="Amount unit: "+currency+" billion, exchange's local accounting standards"
690
- footnote2="ROx/EM/turnover rates are based on periodic mean, others on end-term"
691
- footnote3="Data source: Yahoo Finance, "+todaydt
692
- footnote='Note:\n'+footnote1+'\n'+footnote2+'\n'+footnote3
693
- #print('\n',footnote1,'\n',footnote2,'\n',footnote3)
694
-
695
- # 将Item科目名称拆分加空格和转大写
696
- fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
697
-
698
- # 判断是否仅输出部分科目
699
- if 'all' in items_included:
700
- fsdf7=fsdf6
701
- else:
702
- mask=fsdf6['Item'].isin(items_included)
703
- fsdf7=fsdf6[mask]
704
- # 将Item列转为分类类型,指定顺序
705
- fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
706
- # 按分类顺序排序
707
- fsdf7=fsdf7.sort_values(by='Item')
708
-
709
- df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
710
- titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
711
- data_font_size=data_font_size)
712
- return fsdf6
713
-
714
- return fsdf2
715
-
716
- # 股票可为股票列表(多只股票对比)
717
- if isinstance(tickers,list):
718
-
719
- business_period=business_period.lower()
720
- fsdf=pd.DataFrame()
721
- for t in tickers:
722
- print(" Getting financial rates for financial summary of",t,"...")
723
- with HiddenPrints():
724
- dftmp=get_financial_rates(t)
725
- if dftmp is None:
726
- print(" #Warning(fs_analysis): financial info unaccessible for",t)
727
- if test_yahoo_access():
728
- print(f" Solution: if {t} are correct, then try again later")
729
- else:
730
- print(" Problem: no internet connection to Yahoo for retrieveing data")
731
- return None
732
-
733
- if not last_in_list(t,tickers):
734
- sleep_random(max_sleep=60)
735
-
736
- if business_period=='recent':
737
- dftmp2=dftmp.tail(1)
738
- elif business_period=='annual':
739
- dftmp2=dftmp[dftmp['periodType']=='12M'].tail(1)
740
- elif business_period=='quarterly':
741
- dftmp2=dftmp[dftmp['periodType']=='3M'].tail(1)
742
- else:
743
- dftmp2=dftmp.tail(1)
744
-
745
- """
746
- dftmp2=pd.DataFrame(dftmp2)
747
- fsdf=pd.concat([fsdf,dftmp2])
748
- """
749
- #删除重复的列名,若存在重复列会出现错误InvalidIndexError: Reindexing
750
- dftmp2t=dftmp2.T
751
- dftmp2t['item']=dftmp2t.index
752
- dftmp2t.drop_duplicates(keep='first',inplace=True)
753
- dftmp2t.drop(columns=['item'],inplace=True)
754
- dftmp3=dftmp2t.T
755
-
756
- if fsdf is None:
757
- fsdf=dftmp3
758
- else:
759
- fsdf=pd.concat([fsdf,dftmp3],ignore_index=True)
760
-
761
- # 变换年报/季报
762
- fsdf['periodType']=fsdf['periodType'].apply(lambda x: 'Annual' if x=='12M' else 'Quarterly')
763
- fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
764
- fsdf['Name']=fsdf['ticker'].apply(lambda x: ticker_name(x))
765
- fsdf.set_index('Name',inplace=True)
766
-
767
- fsdf.replace([np.inf, -np.inf], np.nan, inplace=True)
768
- fsdf.fillna(0,inplace=True)
769
- currency=fsdf['currencyCode'].values[0]
770
-
771
- # 删除不用的列
772
- fsdf2=fsdf.copy()
773
- collist=list(fsdf2)
774
- keeplist=[]
775
- for c in itemlist:
776
- if c in collist:
777
- keeplist=keeplist+[c]
778
- if c in itemlist1:
779
- try:
780
- fsdf2[c]=fsdf2[c].apply(lambda x: round(x / billion,2))
781
- except: pass
782
- else:
783
- fsdf2[c]=fsdf2[c].apply(lambda x: round(x,4))
784
- else: pass
785
-
786
- keeplist=['periodType','reportDate','currencyCode']+keeplist
787
- fsdf2=fsdf2[keeplist]
788
-
789
- # 打印处理
790
- if printout:
791
- # 降序排列
792
- #fsdf3=fsdf2.sort_index(ascending=False)
793
- fsdf4=fsdf2
794
- # 转置
795
- fsdf4=fsdf4.T
796
-
797
- fsdf4.replace(0,'---',inplace=True)
798
-
799
- #titletxt="\n***** PEER COMPARISON OF FINANCIAL STATEMENT SUMMARY *****\n"
800
- titletxt=text_lang("财报摘要对比","FINANCIAL STATEMENT SUMMARY: COMPARISON")
801
- #print(titletxt)
802
-
803
- collist=list(fsdf4)
804
- fsdf4['Item']=fsdf4.index
805
- fsdf5=fsdf4[['Item']+collist]
806
- fsdf6=df_filter_row(fsdf5,exclude_collist=['Item'],symbol='---')
807
-
808
- fsdf6=df_sort_priority_list(fsdf6,sort_column='Item',priorityList=['periodType','reportDate','currencyCode'],ascending=True)
809
- """
810
- alignlist=['left']+['right']*(len(list(fsdf5))-1)
811
- print(fsdf6.to_markdown(tablefmt='plain',index=False,colalign=alignlist))
812
- """
813
- footnote1="Amount unit: billion, based on exchange's local accounting standards"
814
- footnote2="ROx/EM/turnover rates are based on periodic mean, others on end-term"
815
- footnote3="Data source: Yahoo Finance, "+str(todaydt)
816
- footnote='Note:\n'+footnote1+'\n'+footnote2+'\n'+footnote3
817
- #print('\n',footnote1,'\n',footnote2,'\n',footnote3)
818
-
819
- # 将Item科目名称拆分加空格和转大写
820
- fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
821
-
822
- # 判断是否仅输出部分科目
823
- if 'all' in items_included:
824
- fsdf7=fsdf6
825
- else:
826
- mask=fsdf6['Item'].isin(items_included)
827
- fsdf7=fsdf6[mask]
828
- # 将Item列转为分类类型,指定顺序
829
- fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
830
- # 按分类顺序排序
831
- fsdf7=fsdf7.sort_values(by='Item')
832
-
833
- df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
834
- titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
835
- data_font_size=data_font_size)
836
- return fsdf6
837
-
838
- return fsdf2
839
- #elif ('indicator' in analysis_type1):
840
- elif contains_any(analysis_type1,['indicator']):
841
- itemlist=[
842
- #短期偿债能力
843
- 'Current Ratio','Quick Ratio','Cash Ratio','Cash Flow Ratio', \
844
- 'Times Interest Earned', \
845
- #长期偿债能力
846
- 'Debt to Asset','Equity to Asset','Equity Multiplier','Debt to Equity', \
847
- 'Debt Service Coverage', \
848
- #营运能力
849
- 'Inventory Turnover','Receivable Turnover','Current Asset Turnover', \
850
- 'Fixed Asset Turnover','Total Asset Turnover', \
851
- #盈利能力
852
- 'Gross Margin','Operating Margin','Profit Margin', \
853
- 'Net Profit on Costs','ROA','ROE','ROIC', \
854
- #股东持股
855
- #'Payout Ratio', \
856
- 'Cashflow per Share', \
857
- #'Dividend per Share', \
858
- 'Net Asset per Share','BasicEPS','DilutedEPS', \
859
- #发展潜力
860
- #'Revenue Growth', \
861
- #'Capital Accumulation', \
862
- #'Total Asset Growth' \
863
- ]
864
-
865
- # 股票可为单只股票(单只股票深度分析)
866
- if isinstance(tickers,str):
867
- print(" Getting financial rates for financial indicators of",tickers,"...")
868
- with HiddenPrints():
869
- fsdf=get_financial_rates(tickers)
870
- if fsdf is None:
871
- print(" #Warning(fs_analysis): financial info unaccessible for",tickers)
872
- if test_yahoo_access():
873
- print(f" Solution: if {tickers} are correct, then try again later")
874
- else:
875
- print(" Problem: no internet connection to Yahoo for retrieveing data")
876
-
877
- return None
878
-
879
- fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
880
- fsdf.set_index('reportDate',inplace=True)
881
-
882
- fsdf.replace([np.inf, -np.inf], np.nan, inplace=True)
883
- fsdf.fillna(0,inplace=True)
884
-
885
- currency=fsdf['currencyCode'].values[0]
886
-
887
- # 变换年报/季报
888
- fsdf['periodType']=fsdf['periodType'].apply(lambda x: 'Annual' if x=='12M' else 'Quarterly')
889
-
890
- # 删除不用的列
891
- fsdf2=fsdf.copy()
892
- collist=list(fsdf2)
893
- keeplist=[]
894
- for c in itemlist:
895
- if c in collist:
896
- keeplist=keeplist+[c]
897
- try:
898
- fsdf2[c]=fsdf2[c].apply(lambda x: round(x,4))
899
- except: pass
900
- else: pass
901
-
902
- keeplist=['periodType']+keeplist
903
- fsdf2=fsdf2[keeplist]
904
-
905
- # 打印处理
906
- if printout:
907
- # 降序排列
908
- fsdf3=fsdf2.sort_index(ascending=False)
909
-
910
- business_period=business_period.lower()
911
- if business_period == 'recent':
912
- fsdf4=fsdf3.head(6)
913
- elif business_period == 'quarterly':
914
- fsdf4=fsdf3[fsdf3['periodType']=='Quarterly']
915
- elif business_period == 'annual':
916
- fsdf4=fsdf3[fsdf3['periodType']=='Annual']
917
- elif business_period == 'all':
918
- fsdf4=fsdf3
919
- #fsdf4=fsdf3[fsdf3['periodType'].isin(['Annual','Quarterly'])]
920
- else:
921
- #fsdf4=fsdf3[fsdf3['periodType']=='Annual']
922
- fsdf4=fsdf3
923
-
924
- # 转置
925
- fsdf4=fsdf4.T
926
-
927
- fsdf4.replace(0,'---',inplace=True)
928
-
929
- #titletxt="\n***** "+ticker_name(tickers)+": FINANCIAL INDICATORS"+' *****\n'
930
- titletxt=ticker_name(tickers,'stock')+text_lang(":财务比率",": FINANCIAL INDICATORS")
931
- #print(titletxt)
932
-
933
- collist=list(fsdf4)
934
- fsdf4['Item']=fsdf4.index
935
- fsdf5=fsdf4[['Item']+collist]
936
- fsdf6=df_filter_row(fsdf5,exclude_collist=['Item'],symbol='---')
937
-
938
- fsdf6=df_sort_priority_list(fsdf6,sort_column='Item',priorityList=['periodType'],ascending=True)
939
- """
940
- alignlist=['left']+['right']*(len(list(fsdf5))-1)
941
- print(fsdf6.to_markdown(tablefmt='plain',index=False,colalign=alignlist))
942
- """
943
- footnote1="Amount unit: "+currency+" billion, exchange's local accounting standards"
944
- footnote2="ROx/EM/turnover rates are based on periodic mean, others on end-term"
945
- footnote3="Data source: Yahoo Finance, "+str(todaydt)
946
- footnote='Note:\n'+footnote1+'\n'+footnote2+'\n'+footnote3
947
- #print('\n',footnote1,'\n',footnote2,'\n',footnote3)
948
-
949
- # 将Item科目名称拆分加空格和转大写
950
- fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
951
-
952
- # 判断是否仅输出部分科目
953
- if 'all' in items_included:
954
- fsdf7=fsdf6
955
- else:
956
- mask=fsdf6['Item'].isin(items_included)
957
- fsdf7=fsdf6[mask]
958
- # 将Item列转为分类类型,指定顺序
959
- fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
960
- # 按分类顺序排序
961
- fsdf7=fsdf7.sort_values(by='Item')
962
-
963
- df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
964
- titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
965
- data_font_size=data_font_size)
966
- return fsdf6
967
-
968
- return fsdf2
969
-
970
- # 股票可为股票列表(多只股票对比)
971
- if isinstance(tickers,list):
972
-
973
- business_period=business_period.lower()
974
- fsdf=pd.DataFrame()
975
- print(" Working on financial rates, it may take long time ...")
976
-
977
- for t in tickers:
978
- print(" Getting financial rates for financial indicators of",t,"...")
979
- with HiddenPrints():
980
- dftmp=get_financial_rates(t)
981
- if dftmp is None:
982
- print(" #Warning(fs_analysis): financial info unaccessible for",t)
983
- if test_yahoo_access():
984
- print(f" Solution: if {t} are correct, then try again later")
985
- else:
986
- print(" Problem: no internet connection to Yahoo for retrieveing data")
987
-
988
- return None
989
-
990
- if len(dftmp) == 0:
991
- print(" #Warning(fs_analysis): zero financial indicators found for stock",t)
992
- continue
993
-
994
- if not last_in_list(t,tickers):
995
- sleep_random(max_sleep=60)
996
-
997
- if business_period=='recent':
998
- dftmp2=dftmp.tail(1)
999
- elif business_period=='annual':
1000
- dftmp2=dftmp[dftmp['periodType']=='12M'].tail(1)
1001
- elif business_period=='quarterly':
1002
- dftmp2=dftmp[dftmp['periodType']=='3M'].tail(1)
1003
- else:
1004
- dftmp2=dftmp.tail(1)
1005
-
1006
- #dftmp2=pd.DataFrame(dftmp2)
1007
- #dftmp2['ticker1']=dftmp2['ticker']
1008
- #dftmp2.set_index('ticker1',inplace=True)
1009
-
1010
- #删除重复的列名,若存在重复列会出现错误InvalidIndexError: Reindexing only valid with uniquely valued Index objects
1011
- dftmp2t=dftmp2.T
1012
- dftmp2t['item']=dftmp2t.index
1013
- dftmp2t.drop_duplicates(keep='first',inplace=True)
1014
- dftmp2t.drop(columns=['item'],inplace=True)
1015
- dftmp3=dftmp2t.T
1016
-
1017
- if fsdf is None:
1018
- fsdf=dftmp3
1019
- else:
1020
- fsdf=pd.concat([fsdf,dftmp3],ignore_index=True)
1021
-
1022
- # 变换年报/季报
1023
- fsdf['periodType']=fsdf['periodType'].apply(lambda x: 'Annual' if x=='12M' else 'Quarterly')
1024
- fsdf['reportDate']=fsdf['asOfDate'].apply(lambda x: x.strftime('%y-%m-%d'))
1025
- fsdf['Name']=fsdf['ticker'].apply(lambda x: ticker_name(x))
1026
- fsdf.set_index('Name',inplace=True)
1027
-
1028
- fsdf.replace([np.inf, -np.inf], np.nan, inplace=True)
1029
- fsdf.fillna(0,inplace=True)
1030
- currency=fsdf['currencyCode'].values[0]
1031
-
1032
- # 删除不用的列
1033
- fsdf2=fsdf.copy()
1034
- collist=list(fsdf2)
1035
- keeplist=[]
1036
- for c in itemlist:
1037
- if c in collist:
1038
- keeplist=keeplist+[c]
1039
- try:
1040
- fsdf2[c]=fsdf2[c].apply(lambda x: round(x,4))
1041
- except: pass
1042
- else: pass
1043
-
1044
- keeplist=['periodType','reportDate','currencyCode']+keeplist
1045
- fsdf2=fsdf2[keeplist]
1046
-
1047
- # 打印处理
1048
- if printout:
1049
- # 降序排列
1050
- #fsdf3=fsdf2.sort_index(ascending=False)
1051
- fsdf4=fsdf2
1052
- # 转置
1053
- fsdf4=fsdf4.T
1054
-
1055
- fsdf4.replace(0,'---',inplace=True)
1056
-
1057
- #titletxt="\n***** PEER COMPARISON OF FINANCIAL INDICATORS *****\n"
1058
- titletxt=text_lang("财务比率对比","FINANCIAL INDICATORS: COMPARISON")
1059
- #print(titletxt)
1060
-
1061
- collist=list(fsdf4)
1062
- fsdf4['Item']=fsdf4.index
1063
- fsdf5=fsdf4[['Item']+collist]
1064
- fsdf6=df_filter_row(fsdf5,exclude_collist=['Item'],symbol='---')
1065
-
1066
- fsdf6=df_sort_priority_list(fsdf6,sort_column='Item',priorityList=['periodType','reportDate','currencyCode'],ascending=True)
1067
- """
1068
- alignlist=['left']+['right']*(len(list(fsdf5))-1)
1069
- print(fsdf6.to_markdown(tablefmt='plain',index=False,colalign=alignlist))
1070
- """
1071
- footnote1="Amount unit: billion, based on exchange's local accounting standards"
1072
- footnote2="ROx/EM/turnover rates are based on periodic mean, others on end-term"
1073
- footnote3="Data source: Yahoo Finance, "+str(todaydt)
1074
- footnote='Note:\n'+footnote1+'\n'+footnote2+'\n'+footnote3
1075
- #print('\n',footnote1,'\n',footnote2,'\n',footnote3)
1076
-
1077
- # 将Item科目名称拆分加空格和转大写
1078
- fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
1079
-
1080
- # 将Item科目名称拆分加空格和转大写
1081
- fsdf6['Item']=fsdf6['Item'].apply(lambda x: text_separate(x))
1082
-
1083
- # 判断是否仅输出部分科目
1084
- if 'all' in items_included:
1085
- fsdf7=fsdf6
1086
- else:
1087
- mask=fsdf6['Item'].isin(items_included)
1088
- fsdf7=fsdf6[mask]
1089
- # 将Item列转为分类类型,指定顺序
1090
- fsdf7['Item'] = pd.Categorical(fsdf7['Item'], categories=items_included, ordered=True)
1091
- # 按分类顺序排序
1092
- fsdf7=fsdf7.sort_values(by='Item')
1093
-
1094
- df_display_CSS(fsdf7,titletxt=titletxt,footnote=footnote,facecolor=facecolor, \
1095
- titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
1096
- data_font_size=data_font_size)
1097
- return fsdf6
1098
-
1099
- return fsdf2
1100
-
1101
- #elif ('dupont' in analysis_type1) and (('identity' in analysis_type1) or ('analysis' in analysis_type1)):
1102
- elif contains_any(analysis_type1,['dupont','identity']):
1103
- # 股票需为股票列表
1104
- if not isinstance(tickers,list):
1105
- print(" #Warning(fs_analysis_china): must be a ticker list for",tickers)
1106
- return None
1107
-
1108
- business_period=business_period.lower()
1109
- fsdf=pd.DataFrame()
1110
- print(" Working on dupont identity, it may take long time ...")
1111
- for t in tickers:
1112
- print(" Getting financial rates for dupont identity of",t,"...")
1113
- with HiddenPrints():
1114
- dftmp=get_financial_rates(t)
1115
- if dftmp is None:
1116
- print(" #Warning(fs_analysis): financial info unaccessible for",t)
1117
- if test_yahoo_access():
1118
- print(f" Solution: if {t} are correct, then try again later")
1119
- else:
1120
- print(" Problem: no internet connection to Yahoo for retrieveing data")
1121
-
1122
- return None
1123
-
1124
- if not last_in_list(t,tickers):
1125
- sleep_random(max_sleep=60)
1126
-
1127
- if business_period=='recent':
1128
- dftmp2=dftmp.tail(1)
1129
- elif business_period=='annual':
1130
- dftmp2=dftmp[dftmp['periodType']=='12M'].tail(1)
1131
- elif business_period=='quarterly':
1132
- dftmp2=dftmp[dftmp['periodType']=='3M'].tail(1)
1133
- else:
1134
- dftmp2=dftmp.tail(1)
1135
-
1136
- """
1137
- dftmp2=pd.DataFrame(dftmp2)
1138
- fsdf=pd.concat([fsdf,dftmp2])
1139
- """
1140
- #删除重复的列名,若存在重复列会出现错误InvalidIndexError: Reindexing
1141
- dftmp2t=dftmp2.T
1142
- dftmp2t['item']=dftmp2t.index
1143
- dftmp2t.drop_duplicates(keep='first',inplace=True)
1144
- dftmp2t.drop(columns=['item'],inplace=True)
1145
- dftmp3=dftmp2t.T
1146
-
1147
- if fsdf is None:
1148
- fsdf=dftmp3
1149
- else:
1150
- fsdf=pd.concat([fsdf,dftmp3],ignore_index=True)
1151
-
1152
- # 多只股票的杜邦分析对比
1153
- fsdf['periodType']=fsdf['periodType'].apply(lambda x: 'Annual' if x=='12M' else 'Quarterly')
1154
- fsdf['Company']=fsdf['ticker'].apply(lambda x: ticker_name(x))
1155
-
1156
-
1157
- collist=['Company','periodType','endDate','Profit Margin','Total Asset Turnover','Equity Multiplier','Return on Equity']
1158
- df=fsdf[collist]
1159
- ticker='Company'
1160
- name1='Profit Margin'
1161
- name2='Total Asset Turnover'
1162
- name3='Equity Multiplier'
1163
- name4='Return on Equity'
1164
- name5='endDate'
1165
-
1166
- if dupont_sort=='PM':
1167
- df.sort_values(name1,ascending=False,inplace=True)
1168
- elif dupont_sort=='TAT':
1169
- df.sort_values(name2,ascending=False,inplace=True)
1170
- elif dupont_sort=='EM':
1171
- df.sort_values(name3,ascending=False,inplace=True)
1172
- else:
1173
- df.sort_values(name1,ascending=False,inplace=True)
1174
-
1175
- df2=df.copy()
1176
- df2[name1]=df2[name1].apply(lambda x: x * scale1)
1177
- df2[name2]=df2[name2].apply(lambda x: x * scale2)
1178
-
1179
- fin_period=df2['endDate'].values[0]
1180
-
1181
- #f,ax1 = plt.subplots(1,figsize=(10,5))
1182
- f,ax1 = plt.subplots(1,figsize=(12.8,6.4))
1183
- w = 0.75
1184
- x = [i+1 for i in range(len(df2[name1]))]
1185
- tick_pos = [i for i in x]
1186
-
1187
- hatchlist=['.', 'o', '\\']
1188
- ax1.bar(x,df2[name3],width=w,bottom=[i+j for i,j in zip(df2[name1],df2[name2])], \
1189
- label=name3,alpha=0.5,color='green',hatch=hatchlist[0], \
1190
- edgecolor='black',align='center')
1191
- ax1.bar(x,df2[name2],width=w,bottom=df2[name1],label=name2,alpha=0.5,color='red', \
1192
- hatch=hatchlist[1], edgecolor='black',align='center')
1193
- ax1.bar(x,df2[name1],width=w,label=name1,alpha=0.5,color='blue', \
1194
- hatch=hatchlist[2], edgecolor='black',align='center')
1195
-
1196
- plt.xticks(tick_pos,df2[ticker])
1197
- plt.ylabel("Items (Amplified)")
1198
-
1199
- footnote1="[Bar amplifier] "+name1+':x'+str(scale1)+','+name2+':x'+str(scale2)
1200
- footnote2='Statement period: '+fin_period+'. Bar height does not indicate ROE value.'
1201
- footnote3="Data source: Yahoo Finance,"+todaydt
1202
- footnote ='\n'+footnote1+'\n'+footnote2+'\n'+footnote3
1203
- plt.xlabel(footnote,fontsize=10)
1204
-
1205
- plt.legend(loc='best',fontsize=10)
1206
- plt.title(text_lang("杜邦分析对比","Dupont Identity Analysis"))
1207
- plt.xlim([min(tick_pos)-w,max(tick_pos)+w])
1208
-
1209
- plt.gca().set_facecolor(facecolor)
1210
- plt.show()
1211
-
1212
- if printout:
1213
- #title_txt="\n***** Dupont Identity Fact Sheet *****\n"
1214
- titletxt=text_lang("杜邦分析数据表","Dupont Identity Fact Sheet")
1215
- #print(titletxt)
1216
-
1217
- # 保留四位小数
1218
- collist=list(df)
1219
- for c in collist:
1220
- try:
1221
- df[c]=round(df[c],4)
1222
- except:
1223
- continue
1224
-
1225
- for d in list(df):
1226
- df[d]=df[d].apply(lambda x: round(x,5) if isinstance(x,float) else x)
1227
- """
1228
- alignlist=['left']+['right']*(len(list(df))-1)
1229
- print(df.to_markdown(tablefmt='plain',index=False,colalign=alignlist))
1230
- """
1231
- footnote1="Based on exchange's local accounting standards, EM/TAT are on periodic mean"
1232
- footnote2="Data source: Yahoo Finance, "+str(todaydt)
1233
- footnote='Note:\n'+footnote1+'\n'+footnote2
1234
- #print('\n',footnote1,'\b.',footnote2)
1235
-
1236
- # 将Item科目名称拆分加空格和转大写
1237
- df['Item']=df['Item'].apply(lambda x: text_separate(x))
1238
-
1239
- df_display_CSS(df,titletxt=titletxt,footnote=footnote,facecolor=facecolor,decimals=4, \
1240
- titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
1241
- data_font_size=data_font_size)
1242
- return df2
1243
-
1244
- else: # analysis_type1
1245
- print(" #Warning(fs_analysis): sorry, no idea on what to do for",analysis_type)
1246
- return None
1247
-
1248
-
1249
- #==============================================================================
1250
-
1251
- if __name__ == '__main__':
1252
- sort_column='Item'
1253
- priorityList=['periodType']
1254
-
1255
- df_sort_priority_list(df,sort_column='Item',priorityList=['periodType'],ascending=True)
1256
- df_sort_priority_list(df,sort_column='Item',priorityList=['periodType'],ascending=False)
1257
-
1258
- def df_sort_priority_list(df,sort_column='',priorityList=[],ascending=True):
1259
- """
1260
- 功能:为df排序,但保持某些优先项目按顺序排在前面
1261
- """
1262
- if sort_column == '': #无需排序
1263
- return df
1264
-
1265
- if len(priorityList) > 0: # 存在优先项目
1266
- df['priority_seq']=df[sort_column].apply(lambda x: priorityList.index(x) if x in priorityList else 9)
1267
-
1268
- df.sort_values(by=['priority_seq',sort_column],ascending=[True,ascending],inplace=True)
1269
-
1270
- df.drop('priority_seq',axis=1,inplace=True) #删除列
1271
- else:
1272
- df.sort_values(by=[sort_column],ascending=ascending,inplace=True)
1273
-
1274
- return df
1275
-
1276
-
1277
- #==============================================================================
1278
- #==============================================================================