siat 3.10.132__py3-none-any.whl → 3.10.133__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- siat/__init__.py +0 -0
- siat/allin.py +0 -0
- siat/assets_liquidity.py +0 -0
- siat/beta_adjustment.py +0 -0
- siat/beta_adjustment_china.py +0 -0
- siat/blockchain.py +0 -0
- siat/bond.py +0 -0
- siat/bond_base.py +0 -0
- siat/bond_china.py +0 -0
- siat/bond_zh_sina.py +0 -0
- siat/capm_beta.py +0 -0
- siat/capm_beta2.py +0 -0
- siat/compare_cross.py +0 -0
- siat/copyrights.py +0 -0
- siat/cryptocurrency.py +0 -0
- siat/economy.py +0 -0
- siat/economy2.py +0 -0
- siat/esg.py +0 -0
- siat/event_study.py +0 -0
- siat/exchange_bond_china.pickle +0 -0
- siat/fama_french.py +0 -0
- siat/fin_stmt2_yahoo.py +0 -0
- siat/financial_base.py +0 -0
- siat/financial_statements.py +0 -0
- siat/financials.py +0 -0
- siat/financials2.py +0 -0
- siat/financials_china.py +0 -0
- siat/financials_china2.py +0 -0
- siat/fund.py +0 -0
- siat/fund_china.pickle +0 -0
- siat/fund_china.py +0 -0
- siat/future_china.py +0 -0
- siat/google_authenticator.py +0 -0
- siat/grafix.py +0 -0
- siat/holding_risk.py +0 -0
- siat/luchy_draw.py +0 -0
- siat/market_china.py +0 -0
- siat/markowitz.py +0 -0
- siat/markowitz2.py +0 -0
- siat/markowitz2_20250704.py +0 -0
- siat/markowitz2_20250705.py +0 -0
- siat/markowitz_simple.py +0 -0
- siat/ml_cases.py +0 -0
- siat/ml_cases_example.py +0 -0
- siat/option_china.py +0 -0
- siat/option_pricing.py +0 -0
- siat/other_indexes.py +0 -0
- siat/risk_adjusted_return.py +0 -0
- siat/risk_adjusted_return2.py +0 -0
- siat/risk_evaluation.py +0 -0
- siat/risk_free_rate.py +0 -0
- siat/sector_china.py +0 -0
- siat/security_price2.py +0 -0
- siat/security_prices.py +40 -2
- siat/security_trend.py +0 -0
- siat/security_trend2.py +0 -0
- siat/stock.py +0 -0
- siat/stock_advice_linear.py +0 -0
- siat/stock_base.py +0 -0
- siat/stock_china.py +0 -0
- siat/stock_info.pickle +0 -0
- siat/stock_prices_kneighbors.py +0 -0
- siat/stock_prices_linear.py +0 -0
- siat/stock_profile.py +0 -0
- siat/stock_technical.py +0 -0
- siat/stooq.py +0 -0
- siat/transaction.py +0 -0
- siat/translate.py +0 -0
- siat/valuation.py +0 -0
- siat/valuation_china.py +0 -0
- siat/var_model_validation.py +0 -0
- siat/yf_name.py +0 -0
- {siat-3.10.132.dist-info/licenses → siat-3.10.133.dist-info}/LICENSE +0 -0
- {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/METADATA +232 -235
- siat-3.10.133.dist-info/RECORD +78 -0
- {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/WHEEL +1 -1
- {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/top_level.txt +0 -1
- build/lib/build/lib/siat/__init__.py +0 -75
- build/lib/build/lib/siat/allin.py +0 -137
- build/lib/build/lib/siat/assets_liquidity.py +0 -915
- build/lib/build/lib/siat/beta_adjustment.py +0 -1058
- build/lib/build/lib/siat/beta_adjustment_china.py +0 -548
- build/lib/build/lib/siat/blockchain.py +0 -143
- build/lib/build/lib/siat/bond.py +0 -2900
- build/lib/build/lib/siat/bond_base.py +0 -992
- build/lib/build/lib/siat/bond_china.py +0 -100
- build/lib/build/lib/siat/bond_zh_sina.py +0 -143
- build/lib/build/lib/siat/capm_beta.py +0 -783
- build/lib/build/lib/siat/capm_beta2.py +0 -887
- build/lib/build/lib/siat/common.py +0 -5360
- build/lib/build/lib/siat/compare_cross.py +0 -642
- build/lib/build/lib/siat/copyrights.py +0 -18
- build/lib/build/lib/siat/cryptocurrency.py +0 -667
- build/lib/build/lib/siat/economy.py +0 -1471
- build/lib/build/lib/siat/economy2.py +0 -1853
- build/lib/build/lib/siat/esg.py +0 -536
- build/lib/build/lib/siat/event_study.py +0 -815
- build/lib/build/lib/siat/fama_french.py +0 -1521
- build/lib/build/lib/siat/fin_stmt2_yahoo.py +0 -982
- build/lib/build/lib/siat/financial_base.py +0 -1160
- build/lib/build/lib/siat/financial_statements.py +0 -598
- build/lib/build/lib/siat/financials.py +0 -2339
- build/lib/build/lib/siat/financials2.py +0 -1278
- build/lib/build/lib/siat/financials_china.py +0 -4433
- build/lib/build/lib/siat/financials_china2.py +0 -2212
- build/lib/build/lib/siat/fund.py +0 -629
- build/lib/build/lib/siat/fund_china.py +0 -3307
- build/lib/build/lib/siat/future_china.py +0 -551
- build/lib/build/lib/siat/google_authenticator.py +0 -47
- build/lib/build/lib/siat/grafix.py +0 -3636
- build/lib/build/lib/siat/holding_risk.py +0 -867
- build/lib/build/lib/siat/luchy_draw.py +0 -638
- build/lib/build/lib/siat/market_china.py +0 -1168
- build/lib/build/lib/siat/markowitz.py +0 -2363
- build/lib/build/lib/siat/markowitz2.py +0 -3150
- build/lib/build/lib/siat/markowitz2_20250704.py +0 -2969
- build/lib/build/lib/siat/markowitz2_20250705.py +0 -3158
- build/lib/build/lib/siat/markowitz_simple.py +0 -373
- build/lib/build/lib/siat/ml_cases.py +0 -2291
- build/lib/build/lib/siat/ml_cases_example.py +0 -60
- build/lib/build/lib/siat/option_china.py +0 -3069
- build/lib/build/lib/siat/option_pricing.py +0 -1925
- build/lib/build/lib/siat/other_indexes.py +0 -409
- build/lib/build/lib/siat/risk_adjusted_return.py +0 -1576
- build/lib/build/lib/siat/risk_adjusted_return2.py +0 -1900
- build/lib/build/lib/siat/risk_evaluation.py +0 -2218
- build/lib/build/lib/siat/risk_free_rate.py +0 -351
- build/lib/build/lib/siat/sector_china.py +0 -4140
- build/lib/build/lib/siat/security_price2.py +0 -727
- build/lib/build/lib/siat/security_prices.py +0 -3408
- build/lib/build/lib/siat/security_trend.py +0 -402
- build/lib/build/lib/siat/security_trend2.py +0 -646
- build/lib/build/lib/siat/stock.py +0 -4284
- build/lib/build/lib/siat/stock_advice_linear.py +0 -934
- build/lib/build/lib/siat/stock_base.py +0 -26
- build/lib/build/lib/siat/stock_china.py +0 -2095
- build/lib/build/lib/siat/stock_prices_kneighbors.py +0 -910
- build/lib/build/lib/siat/stock_prices_linear.py +0 -386
- build/lib/build/lib/siat/stock_profile.py +0 -707
- build/lib/build/lib/siat/stock_technical.py +0 -3305
- build/lib/build/lib/siat/stooq.py +0 -74
- build/lib/build/lib/siat/transaction.py +0 -347
- build/lib/build/lib/siat/translate.py +0 -5183
- build/lib/build/lib/siat/valuation.py +0 -1378
- build/lib/build/lib/siat/valuation_china.py +0 -2076
- build/lib/build/lib/siat/var_model_validation.py +0 -444
- build/lib/build/lib/siat/yf_name.py +0 -811
- build/lib/siat/__init__.py +0 -75
- build/lib/siat/allin.py +0 -137
- build/lib/siat/assets_liquidity.py +0 -915
- build/lib/siat/beta_adjustment.py +0 -1058
- build/lib/siat/beta_adjustment_china.py +0 -548
- build/lib/siat/blockchain.py +0 -143
- build/lib/siat/bond.py +0 -2900
- build/lib/siat/bond_base.py +0 -992
- build/lib/siat/bond_china.py +0 -100
- build/lib/siat/bond_zh_sina.py +0 -143
- build/lib/siat/capm_beta.py +0 -783
- build/lib/siat/capm_beta2.py +0 -887
- build/lib/siat/common.py +0 -5360
- build/lib/siat/compare_cross.py +0 -642
- build/lib/siat/copyrights.py +0 -18
- build/lib/siat/cryptocurrency.py +0 -667
- build/lib/siat/economy.py +0 -1471
- build/lib/siat/economy2.py +0 -1853
- build/lib/siat/esg.py +0 -536
- build/lib/siat/event_study.py +0 -815
- build/lib/siat/fama_french.py +0 -1521
- build/lib/siat/fin_stmt2_yahoo.py +0 -982
- build/lib/siat/financial_base.py +0 -1160
- build/lib/siat/financial_statements.py +0 -598
- build/lib/siat/financials.py +0 -2339
- build/lib/siat/financials2.py +0 -1278
- build/lib/siat/financials_china.py +0 -4433
- build/lib/siat/financials_china2.py +0 -2212
- build/lib/siat/fund.py +0 -629
- build/lib/siat/fund_china.py +0 -3307
- build/lib/siat/future_china.py +0 -551
- build/lib/siat/google_authenticator.py +0 -47
- build/lib/siat/grafix.py +0 -3636
- build/lib/siat/holding_risk.py +0 -867
- build/lib/siat/luchy_draw.py +0 -638
- build/lib/siat/market_china.py +0 -1168
- build/lib/siat/markowitz.py +0 -2363
- build/lib/siat/markowitz2.py +0 -3150
- build/lib/siat/markowitz2_20250704.py +0 -2969
- build/lib/siat/markowitz2_20250705.py +0 -3158
- build/lib/siat/markowitz_simple.py +0 -373
- build/lib/siat/ml_cases.py +0 -2291
- build/lib/siat/ml_cases_example.py +0 -60
- build/lib/siat/option_china.py +0 -3069
- build/lib/siat/option_pricing.py +0 -1925
- build/lib/siat/other_indexes.py +0 -409
- build/lib/siat/risk_adjusted_return.py +0 -1576
- build/lib/siat/risk_adjusted_return2.py +0 -1900
- build/lib/siat/risk_evaluation.py +0 -2218
- build/lib/siat/risk_free_rate.py +0 -351
- build/lib/siat/sector_china.py +0 -4140
- build/lib/siat/security_price2.py +0 -727
- build/lib/siat/security_prices.py +0 -3408
- build/lib/siat/security_trend.py +0 -402
- build/lib/siat/security_trend2.py +0 -646
- build/lib/siat/stock.py +0 -4284
- build/lib/siat/stock_advice_linear.py +0 -934
- build/lib/siat/stock_base.py +0 -26
- build/lib/siat/stock_china.py +0 -2095
- build/lib/siat/stock_prices_kneighbors.py +0 -910
- build/lib/siat/stock_prices_linear.py +0 -386
- build/lib/siat/stock_profile.py +0 -707
- build/lib/siat/stock_technical.py +0 -3305
- build/lib/siat/stooq.py +0 -74
- build/lib/siat/transaction.py +0 -347
- build/lib/siat/translate.py +0 -5183
- build/lib/siat/valuation.py +0 -1378
- build/lib/siat/valuation_china.py +0 -2076
- build/lib/siat/var_model_validation.py +0 -444
- build/lib/siat/yf_name.py +0 -811
- 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
|
-
#==============================================================================
|