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