siat 3.10.130__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.
- build/lib/build/lib/siat/__init__.py +75 -0
- build/lib/build/lib/siat/allin.py +137 -0
- build/lib/build/lib/siat/assets_liquidity.py +915 -0
- build/lib/build/lib/siat/beta_adjustment.py +1058 -0
- build/lib/build/lib/siat/beta_adjustment_china.py +548 -0
- build/lib/build/lib/siat/blockchain.py +143 -0
- build/lib/build/lib/siat/bond.py +2900 -0
- build/lib/build/lib/siat/bond_base.py +992 -0
- build/lib/build/lib/siat/bond_china.py +100 -0
- build/lib/build/lib/siat/bond_zh_sina.py +143 -0
- build/lib/build/lib/siat/capm_beta.py +783 -0
- build/lib/build/lib/siat/capm_beta2.py +887 -0
- build/lib/build/lib/siat/common.py +5360 -0
- build/lib/build/lib/siat/compare_cross.py +642 -0
- build/lib/build/lib/siat/copyrights.py +18 -0
- build/lib/build/lib/siat/cryptocurrency.py +667 -0
- build/lib/build/lib/siat/economy.py +1471 -0
- build/lib/build/lib/siat/economy2.py +1853 -0
- build/lib/build/lib/siat/esg.py +536 -0
- build/lib/build/lib/siat/event_study.py +815 -0
- build/lib/build/lib/siat/fama_french.py +1521 -0
- build/lib/build/lib/siat/fin_stmt2_yahoo.py +982 -0
- build/lib/build/lib/siat/financial_base.py +1160 -0
- build/lib/build/lib/siat/financial_statements.py +598 -0
- build/lib/build/lib/siat/financials.py +2339 -0
- build/lib/build/lib/siat/financials2.py +1278 -0
- build/lib/build/lib/siat/financials_china.py +4433 -0
- build/lib/build/lib/siat/financials_china2.py +2212 -0
- build/lib/build/lib/siat/fund.py +629 -0
- build/lib/build/lib/siat/fund_china.py +3307 -0
- build/lib/build/lib/siat/future_china.py +551 -0
- build/lib/build/lib/siat/google_authenticator.py +47 -0
- build/lib/build/lib/siat/grafix.py +3636 -0
- build/lib/build/lib/siat/holding_risk.py +867 -0
- build/lib/build/lib/siat/luchy_draw.py +638 -0
- build/lib/build/lib/siat/market_china.py +1168 -0
- build/lib/build/lib/siat/markowitz.py +2363 -0
- build/lib/build/lib/siat/markowitz2.py +3150 -0
- build/lib/build/lib/siat/markowitz2_20250704.py +2969 -0
- build/lib/build/lib/siat/markowitz2_20250705.py +3158 -0
- build/lib/build/lib/siat/markowitz_simple.py +373 -0
- build/lib/build/lib/siat/ml_cases.py +2291 -0
- build/lib/build/lib/siat/ml_cases_example.py +60 -0
- build/lib/build/lib/siat/option_china.py +3069 -0
- build/lib/build/lib/siat/option_pricing.py +1925 -0
- build/lib/build/lib/siat/other_indexes.py +409 -0
- build/lib/build/lib/siat/risk_adjusted_return.py +1576 -0
- build/lib/build/lib/siat/risk_adjusted_return2.py +1900 -0
- build/lib/build/lib/siat/risk_evaluation.py +2218 -0
- build/lib/build/lib/siat/risk_free_rate.py +351 -0
- build/lib/build/lib/siat/sector_china.py +4140 -0
- build/lib/build/lib/siat/security_price2.py +727 -0
- build/lib/build/lib/siat/security_prices.py +3408 -0
- build/lib/build/lib/siat/security_trend.py +402 -0
- build/lib/build/lib/siat/security_trend2.py +646 -0
- build/lib/build/lib/siat/stock.py +4284 -0
- build/lib/build/lib/siat/stock_advice_linear.py +934 -0
- build/lib/build/lib/siat/stock_base.py +26 -0
- build/lib/build/lib/siat/stock_china.py +2095 -0
- build/lib/build/lib/siat/stock_prices_kneighbors.py +910 -0
- build/lib/build/lib/siat/stock_prices_linear.py +386 -0
- build/lib/build/lib/siat/stock_profile.py +707 -0
- build/lib/build/lib/siat/stock_technical.py +3305 -0
- build/lib/build/lib/siat/stooq.py +74 -0
- build/lib/build/lib/siat/transaction.py +347 -0
- build/lib/build/lib/siat/translate.py +5183 -0
- build/lib/build/lib/siat/valuation.py +1378 -0
- build/lib/build/lib/siat/valuation_china.py +2076 -0
- build/lib/build/lib/siat/var_model_validation.py +444 -0
- build/lib/build/lib/siat/yf_name.py +811 -0
- build/lib/siat/__init__.py +75 -0
- build/lib/siat/allin.py +137 -0
- build/lib/siat/assets_liquidity.py +915 -0
- build/lib/siat/beta_adjustment.py +1058 -0
- build/lib/siat/beta_adjustment_china.py +548 -0
- build/lib/siat/blockchain.py +143 -0
- build/lib/siat/bond.py +2900 -0
- build/lib/siat/bond_base.py +992 -0
- build/lib/siat/bond_china.py +100 -0
- build/lib/siat/bond_zh_sina.py +143 -0
- build/lib/siat/capm_beta.py +783 -0
- build/lib/siat/capm_beta2.py +887 -0
- build/lib/siat/common.py +5360 -0
- build/lib/siat/compare_cross.py +642 -0
- build/lib/siat/copyrights.py +18 -0
- build/lib/siat/cryptocurrency.py +667 -0
- build/lib/siat/economy.py +1471 -0
- build/lib/siat/economy2.py +1853 -0
- build/lib/siat/esg.py +536 -0
- build/lib/siat/event_study.py +815 -0
- build/lib/siat/fama_french.py +1521 -0
- build/lib/siat/fin_stmt2_yahoo.py +982 -0
- build/lib/siat/financial_base.py +1160 -0
- build/lib/siat/financial_statements.py +598 -0
- build/lib/siat/financials.py +2339 -0
- build/lib/siat/financials2.py +1278 -0
- build/lib/siat/financials_china.py +4433 -0
- build/lib/siat/financials_china2.py +2212 -0
- build/lib/siat/fund.py +629 -0
- build/lib/siat/fund_china.py +3307 -0
- build/lib/siat/future_china.py +551 -0
- build/lib/siat/google_authenticator.py +47 -0
- build/lib/siat/grafix.py +3636 -0
- build/lib/siat/holding_risk.py +867 -0
- build/lib/siat/luchy_draw.py +638 -0
- build/lib/siat/market_china.py +1168 -0
- build/lib/siat/markowitz.py +2363 -0
- build/lib/siat/markowitz2.py +3150 -0
- build/lib/siat/markowitz2_20250704.py +2969 -0
- build/lib/siat/markowitz2_20250705.py +3158 -0
- build/lib/siat/markowitz_simple.py +373 -0
- build/lib/siat/ml_cases.py +2291 -0
- build/lib/siat/ml_cases_example.py +60 -0
- build/lib/siat/option_china.py +3069 -0
- build/lib/siat/option_pricing.py +1925 -0
- build/lib/siat/other_indexes.py +409 -0
- build/lib/siat/risk_adjusted_return.py +1576 -0
- build/lib/siat/risk_adjusted_return2.py +1900 -0
- build/lib/siat/risk_evaluation.py +2218 -0
- build/lib/siat/risk_free_rate.py +351 -0
- build/lib/siat/sector_china.py +4140 -0
- build/lib/siat/security_price2.py +727 -0
- build/lib/siat/security_prices.py +3408 -0
- build/lib/siat/security_trend.py +402 -0
- build/lib/siat/security_trend2.py +646 -0
- build/lib/siat/stock.py +4284 -0
- build/lib/siat/stock_advice_linear.py +934 -0
- build/lib/siat/stock_base.py +26 -0
- build/lib/siat/stock_china.py +2095 -0
- build/lib/siat/stock_prices_kneighbors.py +910 -0
- build/lib/siat/stock_prices_linear.py +386 -0
- build/lib/siat/stock_profile.py +707 -0
- build/lib/siat/stock_technical.py +3305 -0
- build/lib/siat/stooq.py +74 -0
- build/lib/siat/transaction.py +347 -0
- build/lib/siat/translate.py +5183 -0
- build/lib/siat/valuation.py +1378 -0
- build/lib/siat/valuation_china.py +2076 -0
- build/lib/siat/var_model_validation.py +444 -0
- build/lib/siat/yf_name.py +811 -0
- 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/common.py +94 -30
- 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/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.py +0 -0
- siat/future_china.py +0 -0
- siat/google_authenticator.py +0 -0
- siat/grafix.py +1 -1
- siat/holding_risk.py +0 -0
- siat/luchy_draw.py +0 -0
- siat/market_china.py +7 -1
- siat/markowitz.py +0 -0
- siat/markowitz2.py +240 -39
- siat/markowitz2_20250704.py +2969 -0
- siat/markowitz2_20250705.py +3158 -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 +3 -1
- siat/security_trend.py +0 -0
- siat/security_trend2.py +1 -1
- siat/stock.py +4 -2
- siat/stock_advice_linear.py +0 -0
- siat/stock_base.py +0 -0
- siat/stock_china.py +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 +11 -11
- 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.130.dist-info → siat-3.10.132.dist-info}/METADATA +11 -11
- siat-3.10.132.dist-info/RECORD +218 -0
- siat-3.10.132.dist-info/top_level.txt +4 -0
- siat-3.10.130.dist-info/RECORD +0 -76
- siat-3.10.130.dist-info/top_level.txt +0 -1
- {siat-3.10.130.dist-info → siat-3.10.132.dist-info}/WHEEL +0 -0
- {siat-3.10.130.dist-info → siat-3.10.132.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,2212 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
"""
|
4
|
+
本模块功能:计算财务报表指标,基于东方财富,仅限于中国大陆上市的企业
|
5
|
+
所属工具包:证券投资分析工具SIAT
|
6
|
+
SIAT:Security Investment Analysis Tool
|
7
|
+
创建日期:2024年4月21日
|
8
|
+
最新修订日期:2022年5月18日
|
9
|
+
作者:王德宏 (WANG Dehong, Peter)
|
10
|
+
作者单位:北京外国语大学国际商学院
|
11
|
+
作者邮件:wdehong2000@163.com
|
12
|
+
版权所有:王德宏
|
13
|
+
用途限制:仅限研究与教学使用,不可商用!商用需要额外授权。
|
14
|
+
特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
|
15
|
+
"""
|
16
|
+
#==============================================================================
|
17
|
+
#本模块的公共引用
|
18
|
+
import pandas as pd
|
19
|
+
import akshare as ak
|
20
|
+
|
21
|
+
# 这条语句似乎有时失灵!?
|
22
|
+
from siat.stock_china import *
|
23
|
+
from siat.financials_china import *
|
24
|
+
from siat.translate import *
|
25
|
+
#==============================================================================
|
26
|
+
#==============================================================================
|
27
|
+
if __name__=='__main__':
|
28
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
29
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
30
|
+
|
31
|
+
tickers = ['002415.SZ',#海康威视
|
32
|
+
'002236.SZ',#大华股份
|
33
|
+
"002528.SZ",#英飞拓
|
34
|
+
"300275.SZ",#梅安森
|
35
|
+
"603019.SS",#中科曙光
|
36
|
+
]
|
37
|
+
|
38
|
+
fsdates = ['2022-12-31','2021-12-31','2020-12-31','2019-12-31']
|
39
|
+
|
40
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
41
|
+
|
42
|
+
def get_fin_stmt_ak_multi(tickers,fsdates):
|
43
|
+
"""
|
44
|
+
功能:获得多个股票的全部财报,基于akshare,合成,排序:股票代码+财报日期降序
|
45
|
+
选择:仅保留fsdates日期的数据。注意:fsdates要比预计的多一项,以便计算期初数
|
46
|
+
"""
|
47
|
+
from siat.financials_china import get_fin_stmt_ak
|
48
|
+
from siat.financials_china import fs_entry_begin_china
|
49
|
+
|
50
|
+
#循环获取全部股票的财报,并合成
|
51
|
+
df=pd.DataFrame()
|
52
|
+
for t in tickers:
|
53
|
+
dft=get_fin_stmt_ak(t)
|
54
|
+
if dft is None:
|
55
|
+
print(" #Warning(get_fin_stmt_ak_multi): currently data unavailable for",t)
|
56
|
+
continue
|
57
|
+
if len(dft) ==0:
|
58
|
+
print(" #Warning(get_fin_stmt_ak_multi): zero records available for",t)
|
59
|
+
continue
|
60
|
+
|
61
|
+
#按日期升序
|
62
|
+
dft.sort_index(ascending=True,inplace=True)
|
63
|
+
#选择指定的日期
|
64
|
+
dfs=dft[dft['endDate'].isin(fsdates)]
|
65
|
+
|
66
|
+
#列改名
|
67
|
+
dfs.rename(columns={'所有者权益(或股东权益)合计':'所有者权益合计',
|
68
|
+
'一、营业总收入':'营业总收入',
|
69
|
+
'加:营业外收入':'营业外收入',
|
70
|
+
'二、营业总成本':'营业总成本',
|
71
|
+
'三、营业利润':'营业利润',
|
72
|
+
'四、利润总额':'利润总额',
|
73
|
+
'归属于母公司所有者的净利润':'归母净利润',
|
74
|
+
'减:所得税费用':'所得税费用',
|
75
|
+
'处置固定资产、无形资产和其他长期资产的损失':'资产处置损失',
|
76
|
+
'减:营业外支出':'营业外支出',
|
77
|
+
|
78
|
+
#'经营活动产生现金流量净额':'经营活动现金流净额',
|
79
|
+
'经营活动产生的现金流量净额':'经营活动现金流净额',
|
80
|
+
'经营活动现金流入小计':'经营活动现金流入',
|
81
|
+
'经营活动现金流出小计':'经营活动现金流出',
|
82
|
+
'投资活动产生的现金流量净额':'投资活动现金流净额',
|
83
|
+
'投资活动现金流入小计':'投资活动现金流入',
|
84
|
+
'投资活动现金流出小计':'投资活动现金流出',
|
85
|
+
'筹资活动产生的现金流量净额':'筹资活动现金流净额',
|
86
|
+
'筹资活动现金流入小计':'筹资活动现金流入',
|
87
|
+
'筹资活动现金流出小计':'筹资活动现金流出',
|
88
|
+
'汇率变动对现金及现金等价物的影响':'汇率对现金流的影响',
|
89
|
+
'现金及现金等价物净增加额':'现金流量净增加额',
|
90
|
+
'基本每股收益(元/股)':'基本每股收益',
|
91
|
+
'稀释每股收益(元/股)':'稀释每股收益',
|
92
|
+
|
93
|
+
#特殊改名,针对银行业
|
94
|
+
|
95
|
+
},inplace=True)
|
96
|
+
|
97
|
+
#计算指标
|
98
|
+
entry_list=list(dfs)
|
99
|
+
#dfs['应收账款占比%']=round(dfs['应收账款']/dfs['资产总计']*100,2)
|
100
|
+
dfs['应收账款占比%']=dfs.apply(lambda x:round(x['应收账款']/x['资产总计']*100,2),axis=1)
|
101
|
+
|
102
|
+
#dfs['存货占比%']=round(dfs['存货']/dfs['资产总计']*100,2)
|
103
|
+
dfs['存货占比%']=dfs.apply(lambda x:round(x['存货']/x['资产总计']*100,2),axis=1)
|
104
|
+
|
105
|
+
if ('流动资产合计' in entry_list) and ('流动负债合计' in entry_list):
|
106
|
+
dfs['流动比率%']=dfs.apply(lambda x:round(x['流动资产合计']/x['流动负债合计']*100,2),axis=1)
|
107
|
+
dfs['速动资产合计']=dfs.apply(lambda x:x['流动资产合计']-x['存货'],axis=1)
|
108
|
+
dfs['速动比率%']=dfs.apply(lambda x:round(x['速动资产合计']/x['流动负债合计']*100,2),axis=1)
|
109
|
+
dfs['资产负债率%']=dfs.apply(lambda x:round(x['负债合计']/x['资产总计']*100,2),axis=1)
|
110
|
+
|
111
|
+
if not ('营业总收入' in entry_list) and ('营业收入' in entry_list):
|
112
|
+
dfs['营业总收入']=dfs['营业收入']
|
113
|
+
if not ('营业成本' in entry_list) and ('营业收入' in entry_list) and ('营业利润' in entry_list):
|
114
|
+
dfs['营业成本']=dfs['营业收入'] - dfs['营业利润']
|
115
|
+
|
116
|
+
dfs['毛利润']=dfs.apply(lambda x:x['营业总收入']-x['营业成本'],axis=1)
|
117
|
+
dfs['毛利润率%']=dfs.apply(lambda x:round(x['毛利润']/x['营业总收入']*100,2),axis=1)
|
118
|
+
dfs['营业利润率%']=dfs.apply(lambda x:round(x['营业利润']/x['营业总收入']*100,2),axis=1)
|
119
|
+
|
120
|
+
if '销售费用' in entry_list:
|
121
|
+
dfs['销售费用率%']=dfs.apply(lambda x:round(x['销售费用']/x['营业总收入']*100,2),axis=1)
|
122
|
+
|
123
|
+
if not ('管理费用' in entry_list) and ('业务及管理费用' in entry_list):
|
124
|
+
dfs['管理费用']=dfs['业务及管理费用']
|
125
|
+
dfs['管理费用率%']=dfs.apply(lambda x:round(x['管理费用']/x['营业总收入']*100,2),axis=1)
|
126
|
+
try:
|
127
|
+
dfs['研发费用率%']=dfs.apply(lambda x:round(x['研发费用']/x['营业总收入']*100,2),axis=1)
|
128
|
+
except:
|
129
|
+
dfs['研发费用率%']='-'
|
130
|
+
|
131
|
+
if not ('营业外收入' in entry_list) and ('加:营业外收入' in entry_list):
|
132
|
+
dfs['营业外收入']=dfs['加:营业外收入']
|
133
|
+
if not ('营业外支出' in entry_list) and ('减:营业外支出' in entry_list):
|
134
|
+
dfs['营业外支出']=dfs['减:营业外支出']
|
135
|
+
dfs['营业外收支']=dfs.apply(lambda x:x['营业外收入']-x['营业外支出'],axis=1)
|
136
|
+
dfs['税前利润']=dfs['利润总额']
|
137
|
+
dfs['税前利润率%']=dfs.apply(lambda x:round(x['利润总额']/x['营业总收入']*100,2),axis=1)
|
138
|
+
|
139
|
+
if not ('所得税费用' in entry_list) and ('减:所得税' in entry_list):
|
140
|
+
dfs['所得税费用']=dfs['减:所得税']
|
141
|
+
if '所得税费用' in list(dfs):
|
142
|
+
dfs['实际所得税率%']=dfs.apply(lambda x:round(x['所得税费用']/x['利润总额']*100,2),axis=1)
|
143
|
+
|
144
|
+
dfs['净利润率%']=dfs.apply(lambda x:round(x['净利润']/x['营业总收入']*100,2),axis=1)
|
145
|
+
|
146
|
+
#dfs['流通股股数']=dfs.apply(lambda x:round(x['净利润']/x['基本每股收益'],0),axis=1)
|
147
|
+
"""
|
148
|
+
if '流动负债合计' in entry_list:
|
149
|
+
dfs['短期现金偿债能力%']=dfs.apply(lambda x:round(x['经营活动现金流净额']/x['流动负债合计']*100,2),axis=1)
|
150
|
+
dfs['长期现金偿债能力%']=dfs.apply(lambda x:round(x['经营活动现金流净额']/x['负债合计']*100,2),axis=1)
|
151
|
+
#dfs['现金支付股利能力(元)']=dfs.apply(lambda x:round(x['经营活动现金流净额']/x['流通股股数'],2),axis=1)
|
152
|
+
|
153
|
+
if not ('所有者权益合计' in entry_list) and ('负债及股东权益总计' in entry_list) and ('负债合计' in entry_list):
|
154
|
+
dfs['所有者权益合计']=dfs['负债及股东权益总计'] - dfs['负债合计']
|
155
|
+
dfs['现金综合支付能力%']=dfs.apply(lambda x:round(x['经营活动现金流净额']/x['所有者权益合计']*100,2),axis=1)
|
156
|
+
dfs['销售现金比率%']=dfs.apply(lambda x:round(x['经营活动现金流入']/x['营业总收入']*100,2),axis=1)
|
157
|
+
dfs['盈利现金比率%']=dfs.apply(lambda x:round(x['经营活动现金流净额']/x['净利润'],2),axis=1)
|
158
|
+
dfs['资产现金回收率%']=dfs.apply(lambda x:round(x['经营活动现金流净额']/x['资产总计']*100,2),axis=1)
|
159
|
+
dfs['现金流入流出比率%']=dfs.apply(lambda x:round(x['经营活动现金流入']/x['经营活动现金流出']*100,2),axis=1)
|
160
|
+
|
161
|
+
if not (((dfs['销售商品、提供劳务收到的现金']==0).all()) or ((dfs['购买商品、接受劳务支付的现金']==0).all())):
|
162
|
+
dfs['现金购销比率%']=dfs.apply(lambda x:round(x['购买商品、接受劳务支付的现金']/x['销售商品、提供劳务收到的现金']*100,2),axis=1)
|
163
|
+
dfs['营业现金回笼率%']=dfs.apply(lambda x:round(x['销售商品、提供劳务收到的现金']/x['营业总收入']*100,2),axis=1)
|
164
|
+
dfs['支付给职工的现金比率%']=dfs.apply(lambda x:round(x['支付给职工以及为职工支付的现金']/x['销售商品、提供劳务收到的现金']*100,2),axis=1)
|
165
|
+
"""
|
166
|
+
# 自定义财务比率
|
167
|
+
|
168
|
+
#获取字段列表,增加期初项目
|
169
|
+
#去掉重复的列
|
170
|
+
dfst=dfs.T
|
171
|
+
dfst['index_tmp']=dfst.index #防止仅仅因为数值相同而被当作重复项误删
|
172
|
+
dfst.drop_duplicates(subset='index_tmp',keep='first',inplace=True)
|
173
|
+
dfst.drop(columns=['index_tmp'],axis=1,inplace=True)
|
174
|
+
dfs=dfst.T
|
175
|
+
|
176
|
+
col_list=list(dfs)
|
177
|
+
for c in col_list:
|
178
|
+
#print(c)
|
179
|
+
"""
|
180
|
+
if isinstance(c,float) or isinstance(c,int):
|
181
|
+
dfs[c+"_期初"]=dfs[c].shift(1)
|
182
|
+
"""
|
183
|
+
"""
|
184
|
+
if not (c+"_期初" in col_list):
|
185
|
+
try:
|
186
|
+
dfs[c+"_期初"]=dfs[c].shift(1)
|
187
|
+
except:
|
188
|
+
print(" #Warning(get_fin_stmt_ak_multi): problematic column",c,'in the fin statements of',t)
|
189
|
+
else:
|
190
|
+
continue
|
191
|
+
"""
|
192
|
+
dfs=fs_entry_begin_china(dfs,account_entry=c,suffix='_期初')
|
193
|
+
|
194
|
+
#给字段排序,便于检查对比
|
195
|
+
col_list_qc=list(dfs)
|
196
|
+
col_list2=sorted(col_list_qc)
|
197
|
+
dfs2=dfs[col_list2]
|
198
|
+
|
199
|
+
#合成
|
200
|
+
try:
|
201
|
+
df=df.append(dfs2)
|
202
|
+
except:
|
203
|
+
df=df._append(dfs2)
|
204
|
+
|
205
|
+
if df is None:
|
206
|
+
return None
|
207
|
+
if len(df)==0:
|
208
|
+
return None
|
209
|
+
|
210
|
+
#删除空值行:谨慎!!!
|
211
|
+
#df.dropna(inplace=True)
|
212
|
+
|
213
|
+
#删除多余的列,修改列名
|
214
|
+
#del df['ticker_期初']
|
215
|
+
df.rename(columns={'endDate_期初':'endDate_上期'},inplace=True)
|
216
|
+
|
217
|
+
#标注股票简称,去掉其中的(A股)字样
|
218
|
+
df["股票简称"]=df['ticker'].apply(lambda x: ticker_name(x,'stock').replace("(A股)",''))
|
219
|
+
|
220
|
+
"""
|
221
|
+
# 替换nan为-
|
222
|
+
df.fillna('-',inplace=True)
|
223
|
+
df.replace(0,'-',inplace=True)
|
224
|
+
"""
|
225
|
+
|
226
|
+
return df
|
227
|
+
|
228
|
+
#==============================================================================
|
229
|
+
if __name__=='__main__':
|
230
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
231
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
232
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
233
|
+
|
234
|
+
ticker="000002.SZ"
|
235
|
+
fsdate='2021-12-31'
|
236
|
+
item="货币资金"
|
237
|
+
|
238
|
+
select_item(df,ticker,fsdate,item)
|
239
|
+
|
240
|
+
def select_item(df,ticker,fsdate,item):
|
241
|
+
"""
|
242
|
+
功能:根据股票代码、财报日期和科目(含期初)查询金额;若全为零则提示
|
243
|
+
"""
|
244
|
+
|
245
|
+
col_list=['ticker',"股票简称",'endDate',"endDate_上期",item,item+"_期初"]
|
246
|
+
dfs=df[(df['ticker']==ticker) & (df['endDate']==fsdate)][col_list]
|
247
|
+
|
248
|
+
try:
|
249
|
+
item_value=dfs[item].values[0]
|
250
|
+
item_value_qc=dfs[item+"_期初"].values[0]
|
251
|
+
except:
|
252
|
+
print(" #Warning(select_item):",ticker+"在"+fsdate+"的"+item+"未找到")
|
253
|
+
nann=float("nan")
|
254
|
+
return nann,nann,nann
|
255
|
+
|
256
|
+
#全为零提示
|
257
|
+
"""
|
258
|
+
if (item_value==0) & (item_value_qc==0):
|
259
|
+
print(" #Warning(select_item):",ticker+"在"+fsdate+"的"+item+"及其期初数均为零")
|
260
|
+
"""
|
261
|
+
return item_value,item_value_qc,dfs
|
262
|
+
#==============================================================================
|
263
|
+
if __name__=='__main__':
|
264
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
265
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
266
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
267
|
+
|
268
|
+
itemword1="固定资产"
|
269
|
+
itemword1="资产"
|
270
|
+
itemword2="计"
|
271
|
+
|
272
|
+
dfs=find_fs_items(df,itemword1,itemword2)
|
273
|
+
|
274
|
+
def find_fs_items(df,itemword1,itemword2='',printout=True):
|
275
|
+
"""
|
276
|
+
功能:搜索财务报表中含有关键词itemword的项目,并判断这些项目是否整列全为零
|
277
|
+
"""
|
278
|
+
|
279
|
+
col_list=list(df)
|
280
|
+
col_yes=[]
|
281
|
+
for c in col_list:
|
282
|
+
if (itemword1 in c) & (itemword2 in c):
|
283
|
+
col_yes=col_yes+[c]
|
284
|
+
|
285
|
+
dfs=pd.DataFrame(columns=['报表项目','是否全为零'])
|
286
|
+
for cy in col_yes:
|
287
|
+
allzero=(df[cy].std()==0)
|
288
|
+
|
289
|
+
row=pd.Series({'报表项目':cy,'是否全为零':allzero})
|
290
|
+
try:
|
291
|
+
dfs=dfs.append(row,ignore_index=True)
|
292
|
+
except:
|
293
|
+
dfs=dfs._append(row,ignore_index=True)
|
294
|
+
|
295
|
+
if printout:
|
296
|
+
#设置打印对齐
|
297
|
+
pd.set_option('display.max_columns', 1000)
|
298
|
+
pd.set_option('display.width', 1000)
|
299
|
+
pd.set_option('display.max_colwidth', 1000)
|
300
|
+
pd.set_option('display.unicode.ambiguous_as_wide', True)
|
301
|
+
pd.set_option('display.unicode.east_asian_width', True)
|
302
|
+
|
303
|
+
#无序号打印
|
304
|
+
print('')
|
305
|
+
print(dfs.to_string(index=False))
|
306
|
+
|
307
|
+
return dfs
|
308
|
+
|
309
|
+
#==============================================================================
|
310
|
+
if __name__=='__main__':
|
311
|
+
title_txt="===== 重要指标的同行业对比 ====="
|
312
|
+
|
313
|
+
def title_position_original(title_txt,dfp):
|
314
|
+
"""
|
315
|
+
废弃
|
316
|
+
功能:对dfp直接打印时计算让标题居中的位置,通过寻找各个回车符的位置。
|
317
|
+
"""
|
318
|
+
|
319
|
+
#各个记录的长度
|
320
|
+
cuan=dfp.to_string(index=False)
|
321
|
+
pos_prev=0
|
322
|
+
pos=cuan.find('\n')
|
323
|
+
rowlen=pos
|
324
|
+
while pos != -1:
|
325
|
+
pos_prev=pos
|
326
|
+
pos=cuan.find('\n',pos_prev+1)
|
327
|
+
rowlen_new=pos - pos_prev
|
328
|
+
if rowlen_new > rowlen:
|
329
|
+
rowlen=rowlen_new
|
330
|
+
|
331
|
+
#抬头的长度
|
332
|
+
collist=list(dfp)
|
333
|
+
collen=0
|
334
|
+
for c in collist:
|
335
|
+
collen=collen+len(c)
|
336
|
+
collen=collen+(len(collist)-1)*2
|
337
|
+
if collen > rowlen:
|
338
|
+
rowlen=collen
|
339
|
+
|
340
|
+
blanknum=int((rowlen - len(title_txt))/2)
|
341
|
+
|
342
|
+
return blanknum-4
|
343
|
+
#==============================================================================
|
344
|
+
if __name__=='__main__':
|
345
|
+
title_txt="===== 重要指标的同行业对比 ====="
|
346
|
+
|
347
|
+
def title_position(title_txt,dfp):
|
348
|
+
"""
|
349
|
+
功能:对dfp直接打印时计算让标题居中的位置,通过寻找各个回车符的位置。
|
350
|
+
"""
|
351
|
+
|
352
|
+
#各个记录的长度
|
353
|
+
cuan=dfp.to_string(index=False)+'\n'
|
354
|
+
pos=0
|
355
|
+
rowlen=0
|
356
|
+
while pos != -1:
|
357
|
+
pos_new=cuan.find('\n',pos+1)
|
358
|
+
sub_cuan=cuan[pos+1:pos_new]
|
359
|
+
rowlen_new=hzlen(sub_cuan)
|
360
|
+
#print(pos,pos_new,rowlen_new,sub_cuan)
|
361
|
+
|
362
|
+
if rowlen_new > rowlen:
|
363
|
+
rowlen=rowlen_new
|
364
|
+
pos=pos_new
|
365
|
+
|
366
|
+
title_len=hzlen(title_txt)+2
|
367
|
+
#blanknum=int((rowlen - title_len)/2)
|
368
|
+
blanknum=int((rowlen - title_len)/2)+(len(list(dfp))-2)
|
369
|
+
|
370
|
+
return blanknum
|
371
|
+
|
372
|
+
if __name__=='__main__':
|
373
|
+
title_txt="===== 重要指标的同行业对比 ====="
|
374
|
+
blanknum=title_position(title_txt,dfp)
|
375
|
+
|
376
|
+
print(' '*blanknum,title_txt)
|
377
|
+
print(dfp.to_string(index=False))
|
378
|
+
|
379
|
+
#==============================================================================
|
380
|
+
if __name__=='__main__':
|
381
|
+
title_txt="万科A财报:重要指标的同行业对比\n(财报截止日期:2021-12-31)"
|
382
|
+
footnote="*数据来源:新浪财经,2022年5月23日\n**股票列表第一项为分析对象\n*日期列表第一项为分析日期"
|
383
|
+
title_break=False
|
384
|
+
foot_break=True
|
385
|
+
foot_center=False
|
386
|
+
foot_start=4
|
387
|
+
|
388
|
+
def df_directprint_original(dfp,title_txt,footnote, \
|
389
|
+
title_break=True,foot_break=True,foot_center=False,foot_start=1, \
|
390
|
+
facecolor='papayawhip'):
|
391
|
+
"""
|
392
|
+
功能:对dfp直接打印,让标题居中,让脚注居中或指定开始位置。
|
393
|
+
"""
|
394
|
+
print('')
|
395
|
+
|
396
|
+
#解析标题各行并居中打印
|
397
|
+
title_txt1=title_txt+'\n'
|
398
|
+
pos,pos_new=0,0
|
399
|
+
while pos_new != -1:
|
400
|
+
pos_new=title_txt1.find('\n',pos)
|
401
|
+
linetxt=title_txt1[pos:pos_new]
|
402
|
+
#print(linetxt)
|
403
|
+
|
404
|
+
blanknum=title_position(linetxt,dfp)
|
405
|
+
|
406
|
+
if linetxt != '\n':
|
407
|
+
print(' '*blanknum,linetxt)
|
408
|
+
|
409
|
+
pos=pos_new+1
|
410
|
+
|
411
|
+
#设置打印对齐
|
412
|
+
"""
|
413
|
+
pd.set_option('display.max_columns', 1000)
|
414
|
+
pd.set_option('display.width', 1000)
|
415
|
+
pd.set_option('display.max_colwidth', 1000)
|
416
|
+
pd.set_option('display.unicode.ambiguous_as_wide', True)
|
417
|
+
pd.set_option('display.unicode.east_asian_width', True)
|
418
|
+
"""
|
419
|
+
|
420
|
+
#打印数据框本身
|
421
|
+
#print(dfp.to_string(index=False))
|
422
|
+
colalign=['left']+['right']*(len(list(dfp)) - 1)
|
423
|
+
print(dfp.to_markdown(tablefmt='Simple',index=False,colalign=colalign))
|
424
|
+
|
425
|
+
#解析脚注各行并打印
|
426
|
+
if foot_break: print('')
|
427
|
+
footnote1=footnote+'\n'
|
428
|
+
pos,pos_new=0,0
|
429
|
+
while pos_new != -1:
|
430
|
+
pos_new=footnote1.find('\n',pos)
|
431
|
+
linetxt=footnote1[pos:pos_new]
|
432
|
+
#print(linetxt)
|
433
|
+
if foot_center:
|
434
|
+
blanknum=title_position(linetxt,dfp)
|
435
|
+
else:
|
436
|
+
blanknum=foot_start-1
|
437
|
+
|
438
|
+
if linetxt != '\n':
|
439
|
+
if blanknum >2:
|
440
|
+
print(' '*blanknum,linetxt)
|
441
|
+
else:
|
442
|
+
print(linetxt)
|
443
|
+
|
444
|
+
pos=pos_new+1
|
445
|
+
|
446
|
+
return
|
447
|
+
|
448
|
+
#==============================================================================
|
449
|
+
"""
|
450
|
+
def df_directprint(dfp,title_txt,footnote, \
|
451
|
+
title_break=True,foot_break=True,foot_center=False,foot_start=1, \
|
452
|
+
decimals=2,facecolor='papayawhip'):
|
453
|
+
"""
|
454
|
+
def df_directprint(dfp,title_txt,footnote,decimals=2,facecolor='papayawhip',font_size='16px'):
|
455
|
+
"""
|
456
|
+
功能:对dfp直接打印,使用pandas style打印,套壳函数df_display_CSS
|
457
|
+
"""
|
458
|
+
#替换nan和inf
|
459
|
+
import pandas as pd
|
460
|
+
import numpy as np
|
461
|
+
dfp.replace([np.inf, -np.inf],'-', inplace=True)
|
462
|
+
dfp.replace([np.nan],'-', inplace=True)
|
463
|
+
|
464
|
+
#print('') #空一行
|
465
|
+
|
466
|
+
"""
|
467
|
+
#解析标题各行并居中打印
|
468
|
+
title_txt1=title_txt+'\n'
|
469
|
+
pos,pos_new=0,0
|
470
|
+
while pos_new != -1:
|
471
|
+
pos_new=title_txt1.find('\n',pos)
|
472
|
+
linetxt=title_txt1[pos:pos_new]
|
473
|
+
#print(linetxt)
|
474
|
+
|
475
|
+
blanknum=title_position(linetxt,dfp)
|
476
|
+
|
477
|
+
if linetxt != '\n':
|
478
|
+
print(' '*blanknum,linetxt)
|
479
|
+
|
480
|
+
pos=pos_new+1
|
481
|
+
"""
|
482
|
+
|
483
|
+
#确定表格字体大小
|
484
|
+
titile_font_size=font_size
|
485
|
+
heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
|
486
|
+
|
487
|
+
df_display_CSS(dfp,titletxt=title_txt,footnote=footnote,facecolor=facecolor, \
|
488
|
+
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
489
|
+
data_font_size=data_font_size)
|
490
|
+
|
491
|
+
"""
|
492
|
+
disph=dfp.style.hide() #不显示索引列
|
493
|
+
dispp=disph.format(precision=decimals) #设置带有小数点的列精度调整为小数点后2位
|
494
|
+
|
495
|
+
#设置标题/列名
|
496
|
+
dispt=dispp.set_caption(title_txt).set_table_styles(
|
497
|
+
[{'selector':'caption', #设置标题对齐
|
498
|
+
'props':[('color','black'),('font-size','18px'),('font-weight','bold')]}, \
|
499
|
+
{'selector':'th.col_heading', #设置列名对齐
|
500
|
+
'props':[('color','black'),('background-color',facecolor), \
|
501
|
+
('font-size','17px'),('text-align','center'),('margin','auto')]}])
|
502
|
+
|
503
|
+
#设置数据对齐
|
504
|
+
dispt1=dispt.set_properties(**{'font-size':'17px'})
|
505
|
+
dispf=dispt1.set_properties(**{'text-align':'center'})
|
506
|
+
|
507
|
+
#设置前景背景颜色
|
508
|
+
try:
|
509
|
+
dispf2=dispf.set_properties(**{'background-color':facecolor,'color':'black'})
|
510
|
+
except:
|
511
|
+
print(" #Warning(df_directprint): unknown color",facecolor,"\b, changed to default one")
|
512
|
+
dispf2=dispf.set_properties(**{'background-color':'papayawhip','color':'black'})
|
513
|
+
|
514
|
+
#打印数据框本身
|
515
|
+
from IPython.display import display
|
516
|
+
display(dispf2)
|
517
|
+
"""
|
518
|
+
"""
|
519
|
+
#print(dfp.to_string(index=False))
|
520
|
+
colalign=['left']+['right']*(len(list(dfp)) - 1)
|
521
|
+
print(dfp.to_markdown(tablefmt='Simple',index=False,colalign=colalign))
|
522
|
+
"""
|
523
|
+
|
524
|
+
#解析脚注各行并打印
|
525
|
+
"""
|
526
|
+
if foot_break: print('')
|
527
|
+
footnote1=footnote+'\n'
|
528
|
+
pos,pos_new=0,0
|
529
|
+
while pos_new != -1:
|
530
|
+
pos_new=footnote1.find('\n',pos)
|
531
|
+
linetxt=footnote1[pos:pos_new]
|
532
|
+
#print(linetxt)
|
533
|
+
if foot_center:
|
534
|
+
blanknum=title_position(linetxt,dfp)
|
535
|
+
else:
|
536
|
+
blanknum=foot_start-1
|
537
|
+
|
538
|
+
if linetxt != '\n':
|
539
|
+
if blanknum >2:
|
540
|
+
print(' '*blanknum,linetxt)
|
541
|
+
else:
|
542
|
+
print(linetxt)
|
543
|
+
|
544
|
+
pos=pos_new+1
|
545
|
+
"""
|
546
|
+
#print('') #空一行
|
547
|
+
#print(footnote,'\n')
|
548
|
+
|
549
|
+
return
|
550
|
+
#==============================================================================
|
551
|
+
|
552
|
+
if __name__=='__main__':
|
553
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
554
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
555
|
+
|
556
|
+
tickers=['601328.SS','601398.SS','601288.SS','601988.SS','601939.SS','601658.SS']
|
557
|
+
fsdates=['2022-12-31','2021-12-31','2010-12-31','2019-12-31']
|
558
|
+
|
559
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
560
|
+
|
561
|
+
ticker="601328.SS"
|
562
|
+
fsdate='2022-12-31'
|
563
|
+
items=["货币资金","应收票据","应收账款"]
|
564
|
+
dfp=fs_item_analysis_1(df,ticker,fsdate,items)
|
565
|
+
|
566
|
+
def fs_item_analysis_1(df,ticker,fsdate,items,title_txt='',notes='', \
|
567
|
+
facecolor='papayawhip',font_size='16px'):
|
568
|
+
"""
|
569
|
+
功能:比较给定财报日期的资产项目、期初数、期末数、变动额和变动幅度%
|
570
|
+
"""
|
571
|
+
|
572
|
+
#循环获取科目
|
573
|
+
dfp=pd.DataFrame(columns=['报表项目','期初数', '期末数', '变动额', '变动幅度%'])
|
574
|
+
yiyuan=100000000
|
575
|
+
|
576
|
+
import math
|
577
|
+
for i in items:
|
578
|
+
i_value,i_value_qc,dft=select_item(df,ticker,fsdate,i)
|
579
|
+
|
580
|
+
"""
|
581
|
+
if not(i_value != 0 or i_value_qc != 0):
|
582
|
+
print(" #Warning(income_cost_analysis_1): 因其零值而忽略"+i+"项目")
|
583
|
+
continue
|
584
|
+
"""
|
585
|
+
|
586
|
+
if not math.isnan(i_value):
|
587
|
+
i_value_yy=round(i_value/yiyuan,4)
|
588
|
+
i_value_qc_yy=round(i_value_qc/yiyuan,4)
|
589
|
+
i_value_chg_yy=round(i_value_yy - i_value_qc_yy,2)
|
590
|
+
if not(i_value_qc_yy==0):
|
591
|
+
i_value_chg_pct=round(i_value_chg_yy/i_value_qc_yy*100,2)
|
592
|
+
#对于变动幅度符号的修正
|
593
|
+
if (i_value_chg_pct < 0) and (i_value_qc_yy < 0):
|
594
|
+
i_value_chg_pct=abs(i_value_chg_pct)
|
595
|
+
else:
|
596
|
+
i_value_chg_pct='-'
|
597
|
+
else:
|
598
|
+
i_value_qc_yy,i_value_yy,i_value_chg_yy,i_value_chg_pct='-','-','-','-'
|
599
|
+
|
600
|
+
row=pd.Series({'报表项目':i,'期初数':i_value_qc_yy, \
|
601
|
+
'期末数':i_value_yy, '变动额':i_value_chg_yy, \
|
602
|
+
'变动幅度%':i_value_chg_pct})
|
603
|
+
try:
|
604
|
+
dfp=dfp.append(row,ignore_index=True)
|
605
|
+
except:
|
606
|
+
dfp=dfp._append(row,ignore_index=True)
|
607
|
+
|
608
|
+
dfp=dfp.replace(0,'-')
|
609
|
+
dfp=dfp.fillna('-')
|
610
|
+
|
611
|
+
#无序号打印
|
612
|
+
if title_txt=='':
|
613
|
+
tname=ticker_name(ticker,'stock').replace("(A股)",'')
|
614
|
+
title_txt=tname+"财报分析:重要项目的变动情况\n(截至"+fsdate+")"
|
615
|
+
import datetime; todaydt=datetime.date.today()
|
616
|
+
#footnote="*单位:亿元,数据来源:新浪财经,"+str(today)
|
617
|
+
#footnote="*单位:亿元,本期报表日期:"+fsdate+',数据来源:新浪财经'
|
618
|
+
footnote="单位:亿元,数据来源:新浪财经,"+str(todaydt)
|
619
|
+
|
620
|
+
if notes=='':
|
621
|
+
foottext=footnote
|
622
|
+
else:
|
623
|
+
foottext=notes+'\n'+footnote
|
624
|
+
|
625
|
+
#确定表格字体大小
|
626
|
+
titile_font_size=font_size
|
627
|
+
heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
|
628
|
+
|
629
|
+
#df_directprint(dfp,title_txt,foottext,facecolor=facecolor)
|
630
|
+
df_display_CSS(df=dfp,titletxt=title_txt,footnote=foottext, \
|
631
|
+
first_col_align='left', \
|
632
|
+
facecolor=facecolor,decimals=2, \
|
633
|
+
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
634
|
+
data_font_size=data_font_size)
|
635
|
+
|
636
|
+
return dfp
|
637
|
+
|
638
|
+
|
639
|
+
#==============================================================================
|
640
|
+
if __name__=='__main__':
|
641
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
642
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
643
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
644
|
+
|
645
|
+
ticker="000002.SZ"
|
646
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31']
|
647
|
+
items=["应收账款","资产总计"]
|
648
|
+
find_fs_items(df,itemword1="应收账款",itemword2='')
|
649
|
+
find_fs_items(df,itemword1="资产",itemword2='计')
|
650
|
+
|
651
|
+
dfp=fs_item_analysis_2(df,ticker,fsdates,items)
|
652
|
+
|
653
|
+
def fs_item_analysis_2(df,ticker,fsdates,items,title_txt='',notes='', \
|
654
|
+
facecolor='papayawhip',font_size='16px'):
|
655
|
+
"""
|
656
|
+
功能:比较给定财报日期的报表项目、最近几年fsdates、占比%
|
657
|
+
"""
|
658
|
+
fsdates1=sorted(fsdates,reverse=True)
|
659
|
+
|
660
|
+
#循环获取科目
|
661
|
+
col_list=['报表项目(亿元)']+fsdates1
|
662
|
+
dfp=pd.DataFrame(columns=col_list)
|
663
|
+
|
664
|
+
yiyuan=100000000
|
665
|
+
import math
|
666
|
+
|
667
|
+
for i in items:
|
668
|
+
row_list=[i]
|
669
|
+
for fd in fsdates1:
|
670
|
+
i_value,_,_=select_item(df,ticker,fd,i)
|
671
|
+
row_list=row_list+[round(i_value/yiyuan,4)]
|
672
|
+
dfp.loc[len(dfp)] = row_list
|
673
|
+
|
674
|
+
last_row=[items[0]+"占比%"]
|
675
|
+
for fd in fsdates1:
|
676
|
+
rate=round(dfp[fd][0]/dfp[fd][1]*100,2)
|
677
|
+
last_row=last_row+[rate]
|
678
|
+
dfp.loc[len(dfp)] = last_row
|
679
|
+
|
680
|
+
dfp=dfp.replace(0,'-')
|
681
|
+
dfp=dfp.fillna('-')
|
682
|
+
|
683
|
+
#无序号打印
|
684
|
+
if title_txt=='':
|
685
|
+
tname=ticker_name(ticker,'stock').replace("(A股)",'')
|
686
|
+
title_txt=tname+"财报分析:重要项目占比的变动趋势"
|
687
|
+
import datetime; todaydt=datetime.date.today()
|
688
|
+
footnote="数据来源:新浪财经,"+str(todaydt)
|
689
|
+
|
690
|
+
if notes=='':
|
691
|
+
foottext=footnote
|
692
|
+
else:
|
693
|
+
foottext=notes+'\n'+footnote
|
694
|
+
|
695
|
+
#确定表格字体大小
|
696
|
+
titile_font_size=font_size
|
697
|
+
heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
|
698
|
+
|
699
|
+
#df_directprint(dfp,title_txt,foottext,facecolor=facecolor)
|
700
|
+
df_display_CSS(df=dfp,titletxt=title_txt,footnote=foottext, \
|
701
|
+
first_col_align='left', \
|
702
|
+
facecolor=facecolor,decimals=2, \
|
703
|
+
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
704
|
+
data_font_size=data_font_size)
|
705
|
+
|
706
|
+
return dfp
|
707
|
+
|
708
|
+
#==============================================================================
|
709
|
+
if __name__=='__main__':
|
710
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
711
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
712
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
713
|
+
|
714
|
+
ticker="000002.SZ"
|
715
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31']
|
716
|
+
|
717
|
+
dfp=fs_item_analysis_3(df,ticker,fsdates)
|
718
|
+
|
719
|
+
def fs_item_analysis_3(df,ticker,fsdates,title_txt='',notes='', \
|
720
|
+
facecolor='papayawhip',font_size='16px'):
|
721
|
+
"""
|
722
|
+
功能:比较给定财报日期的流动比率、最近几年fsdates
|
723
|
+
"""
|
724
|
+
fsdates1=sorted(fsdates,reverse=True)
|
725
|
+
|
726
|
+
#循环获取科目
|
727
|
+
col_list=['报表项目(亿元)']+fsdates1
|
728
|
+
dfp=pd.DataFrame(columns=col_list)
|
729
|
+
yiyuan=100000000
|
730
|
+
|
731
|
+
items=['流动资产合计','流动负债合计']
|
732
|
+
for i in items:
|
733
|
+
row_list=[i]
|
734
|
+
for fd in fsdates1:
|
735
|
+
i_value,_,_=select_item(df,ticker,fd,i)
|
736
|
+
row_list=row_list+[round(i_value/yiyuan,4)]
|
737
|
+
dfp.loc[len(dfp)] = row_list
|
738
|
+
|
739
|
+
last_row=["流动比率%"]
|
740
|
+
for fd in fsdates1:
|
741
|
+
rate=round(dfp[fd][0]/dfp[fd][1]*100,2)
|
742
|
+
last_row=last_row+[rate]
|
743
|
+
dfp.loc[len(dfp)] = last_row
|
744
|
+
|
745
|
+
dfp=dfp.replace(0,'-')
|
746
|
+
dfp=dfp.fillna('-')
|
747
|
+
|
748
|
+
#无序号打印
|
749
|
+
if title_txt=='':
|
750
|
+
tname=ticker_name(ticker,'stock').replace("(A股)",'')
|
751
|
+
title_txt=tname+"财报分析:流动比率的变动趋势"
|
752
|
+
import datetime; todaydt=datetime.date.today()
|
753
|
+
footnote="数据来源:新浪财经,"+str(todaydt)
|
754
|
+
|
755
|
+
if notes=='':
|
756
|
+
foottext=footnote
|
757
|
+
else:
|
758
|
+
foottext=notes+'\n'+footnote
|
759
|
+
|
760
|
+
#确定表格字体大小
|
761
|
+
titile_font_size=font_size
|
762
|
+
heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
|
763
|
+
|
764
|
+
#确定表格字体大小
|
765
|
+
titile_font_size=font_size
|
766
|
+
heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
|
767
|
+
|
768
|
+
#df_directprint(dfp,title_txt,foottext,facecolor=facecolor)
|
769
|
+
df_display_CSS(df=dfp,titletxt=title_txt,footnote=foottext, \
|
770
|
+
first_col_align='left', \
|
771
|
+
facecolor=facecolor,decimals=2, \
|
772
|
+
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
773
|
+
data_font_size=data_font_size)
|
774
|
+
|
775
|
+
return dfp
|
776
|
+
|
777
|
+
#==============================================================================
|
778
|
+
if __name__=='__main__':
|
779
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
780
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
781
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
782
|
+
|
783
|
+
ticker="000002.SZ"
|
784
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31']
|
785
|
+
|
786
|
+
dfp=fs_item_analysis_4(df,ticker,fsdates)
|
787
|
+
|
788
|
+
def fs_item_analysis_4(df,ticker,fsdates,title_txt='',notes='', \
|
789
|
+
facecolor='papayawhip',font_size='16px'):
|
790
|
+
"""
|
791
|
+
功能:比较给定财报日期的流动比率、最近几年fsdates
|
792
|
+
"""
|
793
|
+
fsdates1=sorted(fsdates,reverse=True)
|
794
|
+
|
795
|
+
#循环获取科目
|
796
|
+
col_list=['报表项目(亿元)']+fsdates1
|
797
|
+
dfp=pd.DataFrame(columns=col_list)
|
798
|
+
yiyuan=100000000
|
799
|
+
|
800
|
+
i='流动资产合计'
|
801
|
+
row_list=[i]
|
802
|
+
for fd in fsdates1:
|
803
|
+
i_value,_,_=select_item(df,ticker,fd,i)
|
804
|
+
row_list=row_list+[round(i_value/yiyuan,4)]
|
805
|
+
dfp.loc[len(dfp)] = row_list
|
806
|
+
|
807
|
+
i='存货'
|
808
|
+
row_list=['其中:'+i]
|
809
|
+
for fd in fsdates1:
|
810
|
+
i_value,_,_=select_item(df,ticker,fd,i)
|
811
|
+
row_list=row_list+[round(i_value/yiyuan,4)]
|
812
|
+
dfp.loc[len(dfp)] = row_list
|
813
|
+
|
814
|
+
i='速动资产合计'
|
815
|
+
row_list=[i]
|
816
|
+
for fd in fsdates1:
|
817
|
+
rate=round(dfp[fd][0]-dfp[fd][1],2)
|
818
|
+
row_list=row_list+[rate]
|
819
|
+
dfp.loc[len(dfp)] = row_list
|
820
|
+
|
821
|
+
i='流动负债合计'
|
822
|
+
row_list=[i]
|
823
|
+
for fd in fsdates1:
|
824
|
+
i_value,_,_=select_item(df,ticker,fd,i)
|
825
|
+
row_list=row_list+[round(i_value/yiyuan,4)]
|
826
|
+
dfp.loc[len(dfp)] = row_list
|
827
|
+
|
828
|
+
last_row=["速动比率%"]
|
829
|
+
for fd in fsdates1:
|
830
|
+
rate=round(dfp[fd][2]/dfp[fd][3]*100,2)
|
831
|
+
last_row=last_row+[rate]
|
832
|
+
dfp.loc[len(dfp)] = last_row
|
833
|
+
|
834
|
+
dfp=dfp.replace(0,'-')
|
835
|
+
dfp=dfp.fillna('-')
|
836
|
+
|
837
|
+
#无序号打印
|
838
|
+
if title_txt=='':
|
839
|
+
tname=ticker_name(ticker,'stock').replace("(A股)",'')
|
840
|
+
title_txt=tname+"财报分析:速动比率的变动趋势"
|
841
|
+
import datetime; todaydt=datetime.date.today()
|
842
|
+
footnote="数据来源:新浪财经,"+str(todaydt)
|
843
|
+
|
844
|
+
if notes=='':
|
845
|
+
foottext=footnote
|
846
|
+
else:
|
847
|
+
foottext=notes+'\n'+footnote
|
848
|
+
|
849
|
+
#确定表格字体大小
|
850
|
+
titile_font_size=font_size
|
851
|
+
heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
|
852
|
+
|
853
|
+
#df_directprint(dfp,title_txt,foottext,facecolor=facecolor)
|
854
|
+
df_display_CSS(df=dfp,titletxt=title_txt,footnote=foottext, \
|
855
|
+
first_col_align='left', \
|
856
|
+
facecolor=facecolor,decimals=2, \
|
857
|
+
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
858
|
+
data_font_size=data_font_size)
|
859
|
+
return dfp
|
860
|
+
|
861
|
+
#==============================================================================
|
862
|
+
if __name__=='__main__':
|
863
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
864
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
865
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
866
|
+
|
867
|
+
ticker="000002.SZ"
|
868
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31']
|
869
|
+
|
870
|
+
dfp=fs_item_analysis_5(df,ticker,fsdates)
|
871
|
+
|
872
|
+
def fs_item_analysis_5(df,ticker,fsdates,title_txt='',notes='', \
|
873
|
+
facecolor='papayawhip',font_size='16px'):
|
874
|
+
"""
|
875
|
+
功能:比较给定财报日期的流动比率、最近几年fsdates
|
876
|
+
"""
|
877
|
+
|
878
|
+
#循环获取科目
|
879
|
+
col_list=['报表项目(亿元)']+fsdates
|
880
|
+
dfp=pd.DataFrame(columns=col_list)
|
881
|
+
yiyuan=100000000
|
882
|
+
|
883
|
+
fsdates1=sorted(fsdates,reverse=True)
|
884
|
+
items=['资产总计','负债合计']
|
885
|
+
for i in items:
|
886
|
+
row_list=[i]
|
887
|
+
for fd in fsdates1:
|
888
|
+
i_value,_,_=select_item(df,ticker,fd,i)
|
889
|
+
row_list=row_list+[round(i_value/yiyuan,4)]
|
890
|
+
dfp.loc[len(dfp)] = row_list
|
891
|
+
|
892
|
+
last_row=["资产负债率%"]
|
893
|
+
for fd in fsdates1:
|
894
|
+
rate=round(dfp[fd][1]/dfp[fd][0]*100,2)
|
895
|
+
last_row=last_row+[rate]
|
896
|
+
dfp.loc[len(dfp)] = last_row
|
897
|
+
|
898
|
+
dfp=dfp.replace(0,'-')
|
899
|
+
dfp=dfp.fillna('-')
|
900
|
+
|
901
|
+
#无序号打印
|
902
|
+
if title_txt=='':
|
903
|
+
tname=ticker_name(ticker,'stock').replace("(A股)",'')
|
904
|
+
title_txt=tname+"财报分析:资产负债率的变动趋势"
|
905
|
+
import datetime; todaydt=datetime.date.today()
|
906
|
+
footnote="数据来源:新浪财经,"+str(todaydt)
|
907
|
+
|
908
|
+
if notes=='':
|
909
|
+
foottext=footnote
|
910
|
+
else:
|
911
|
+
foottext=notes+'\n'+footnote
|
912
|
+
|
913
|
+
#确定表格字体大小
|
914
|
+
titile_font_size=font_size
|
915
|
+
heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
|
916
|
+
|
917
|
+
#df_directprint(dfp,title_txt,foottext,facecolor=facecolor)
|
918
|
+
df_display_CSS(df=dfp,titletxt=title_txt,footnote=foottext, \
|
919
|
+
first_col_align='left', \
|
920
|
+
facecolor=facecolor,decimals=2, \
|
921
|
+
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
922
|
+
data_font_size=data_font_size)
|
923
|
+
return dfp
|
924
|
+
|
925
|
+
#==============================================================================
|
926
|
+
if __name__=='__main__':
|
927
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
928
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
929
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
930
|
+
|
931
|
+
ticker="000002.SZ"
|
932
|
+
fsdates=['2021-12-31','2020-12-31']
|
933
|
+
items=['应收账款','营业收入']
|
934
|
+
|
935
|
+
dfp=fs_item_analysis_6(df,ticker,fsdates,items)
|
936
|
+
|
937
|
+
def fs_item_analysis_6_original(df,ticker,fsdates,items,title_txt='',notes=''):
|
938
|
+
"""
|
939
|
+
废弃!!!
|
940
|
+
功能:比较给定财报日期的应收账款与营业收入增幅、最近几年fsdates
|
941
|
+
"""
|
942
|
+
|
943
|
+
#循环获取科目
|
944
|
+
items1=[]
|
945
|
+
for i in items:
|
946
|
+
items1=items1+[i+'(亿元)']
|
947
|
+
|
948
|
+
col_list=['报表日期']+items1
|
949
|
+
dfp=pd.DataFrame(columns=col_list)
|
950
|
+
yiyuan=100000000
|
951
|
+
|
952
|
+
fsdates1=sorted(fsdates,reverse=False)
|
953
|
+
for fd in fsdates1:
|
954
|
+
row_list=[fd]
|
955
|
+
for i in items:
|
956
|
+
i_value,_,_=select_item(df,ticker,fd,i)
|
957
|
+
row_list=row_list+[round(i_value/yiyuan,4)]
|
958
|
+
dfp.loc[len(dfp)] = row_list
|
959
|
+
|
960
|
+
last_row=["增幅%"]
|
961
|
+
for i in items1:
|
962
|
+
rate=round((dfp[i][1]/dfp[i][0]-1)*100,2)
|
963
|
+
last_row=last_row+[rate]
|
964
|
+
dfp.loc[len(dfp)] = last_row
|
965
|
+
|
966
|
+
# 替换nan
|
967
|
+
dfp=dfp.fillna('-')
|
968
|
+
dfp=dfp.replace(0,'-')
|
969
|
+
|
970
|
+
#无序号打印
|
971
|
+
if title_txt=='':
|
972
|
+
tname=ticker_name(ticker,'stock').replace("(A股)",'')
|
973
|
+
title_txt=tname+"财报分析:重要关联项目的增幅对比"
|
974
|
+
import datetime; todaydt=datetime.date.today()
|
975
|
+
footnote="数据来源:新浪财经,"+str(todaydt)
|
976
|
+
|
977
|
+
if notes=='':
|
978
|
+
foottext=footnote
|
979
|
+
else:
|
980
|
+
foottext=notes+'\n'+footnote
|
981
|
+
|
982
|
+
df_directprint(dfp,title_txt,foottext)
|
983
|
+
|
984
|
+
return dfp
|
985
|
+
#==============================================================================
|
986
|
+
if __name__=='__main__':
|
987
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
988
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
989
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
990
|
+
|
991
|
+
ticker="000002.SZ"
|
992
|
+
fsdates=['2021-12-31','2020-12-31']
|
993
|
+
items=['应收账款','营业收入']
|
994
|
+
|
995
|
+
dfp=fs_item_analysis_6(df,ticker,fsdates,items)
|
996
|
+
|
997
|
+
def fs_item_analysis_6(df,ticker,fsdates,items,title_txt='',notes='', \
|
998
|
+
facecolor='papayawhip',font_size='16px'):
|
999
|
+
"""
|
1000
|
+
功能:比较给定财报日期的应收账款与营业收入增幅、最近几年fsdates
|
1001
|
+
"""
|
1002
|
+
|
1003
|
+
col_list=['报表日期']+items
|
1004
|
+
dfp=pd.DataFrame(columns=col_list)
|
1005
|
+
yiyuan=100000000
|
1006
|
+
yiyuan_foot=False
|
1007
|
+
|
1008
|
+
fsdates1=sorted(fsdates,reverse=False)
|
1009
|
+
for fd in fsdates1:
|
1010
|
+
row_list=[fd]
|
1011
|
+
for i in items:
|
1012
|
+
i_value,_,_=select_item(df,ticker,fd,i)
|
1013
|
+
if not('%' in i) and not('(元)' in i):
|
1014
|
+
row_list=row_list+[round(i_value/yiyuan,4)]
|
1015
|
+
yiyuan_foot=True
|
1016
|
+
else:
|
1017
|
+
row_list=row_list+[i_value]
|
1018
|
+
dfp.loc[len(dfp)] = row_list
|
1019
|
+
|
1020
|
+
last_row=["增幅%"]
|
1021
|
+
for i in items:
|
1022
|
+
rate=round((dfp[i][1]/dfp[i][0]-1)*100,2)
|
1023
|
+
last_row=last_row+[rate]
|
1024
|
+
dfp.loc[len(dfp)] = last_row
|
1025
|
+
|
1026
|
+
# 替换nan
|
1027
|
+
dfp=dfp.fillna('-')
|
1028
|
+
dfp=dfp.replace(0,'-')
|
1029
|
+
|
1030
|
+
#无序号打印
|
1031
|
+
if title_txt=='':
|
1032
|
+
tname=ticker_name(ticker,'stock').replace("(A股)",'')
|
1033
|
+
title_txt=tname+"财报分析:重要关联项目的增幅对比"
|
1034
|
+
import datetime; todaydt=datetime.date.today()
|
1035
|
+
if yiyuan_foot:
|
1036
|
+
footnote="单位:亿元,数据来源:新浪财经,"+str(todaydt)
|
1037
|
+
else:
|
1038
|
+
footnote="数据来源:新浪财经,"+str(todaydt)
|
1039
|
+
|
1040
|
+
if notes=='':
|
1041
|
+
foottext=footnote
|
1042
|
+
else:
|
1043
|
+
foottext=notes+'\n'+footnote
|
1044
|
+
|
1045
|
+
#确定表格字体大小
|
1046
|
+
titile_font_size=font_size
|
1047
|
+
heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
|
1048
|
+
|
1049
|
+
#df_directprint(dfp,title_txt,foottext,facecolor=facecolor)
|
1050
|
+
df_display_CSS(df=dfp,titletxt=title_txt,footnote=foottext, \
|
1051
|
+
first_col_align='left', \
|
1052
|
+
facecolor=facecolor,decimals=2, \
|
1053
|
+
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
1054
|
+
data_font_size=data_font_size)
|
1055
|
+
return dfp
|
1056
|
+
|
1057
|
+
#==============================================================================
|
1058
|
+
if __name__=='__main__':
|
1059
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
1060
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
1061
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
1062
|
+
|
1063
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
1064
|
+
fsdate='2021-12-31'
|
1065
|
+
items=['存货','资产总计','存货占比%']
|
1066
|
+
|
1067
|
+
dfp=fs_item_analysis_7(df,tickers,fsdate,items)
|
1068
|
+
|
1069
|
+
def fs_item_analysis_7_original(df,tickers,fsdate,items,title_txt=''):
|
1070
|
+
"""
|
1071
|
+
废弃!!!
|
1072
|
+
功能:比较给定财报日期fsdate的项目和指标,与同业相比
|
1073
|
+
"""
|
1074
|
+
|
1075
|
+
#循环获取科目
|
1076
|
+
items1=[]
|
1077
|
+
for i in items:
|
1078
|
+
if not('%' in i):
|
1079
|
+
items1=items1+[i+'(亿元)']
|
1080
|
+
else:
|
1081
|
+
items1=items1+[i]
|
1082
|
+
|
1083
|
+
col_list=['上市公司']+items1
|
1084
|
+
dfp=pd.DataFrame(columns=col_list)
|
1085
|
+
yiyuan=100000000
|
1086
|
+
yiyuan_foot=False
|
1087
|
+
|
1088
|
+
for t in tickers:
|
1089
|
+
tname=ticker_name(t,'stock').replace("(A股)",'')
|
1090
|
+
row_list=[tname]
|
1091
|
+
for i in items:
|
1092
|
+
i_value,_,_=select_item(df,t,fsdate,i)
|
1093
|
+
if not('%' in i) and not('(元)' in i):
|
1094
|
+
row_list=row_list+[round(i_value/yiyuan,4)]
|
1095
|
+
yiyuan_foot=True
|
1096
|
+
else:
|
1097
|
+
row_list=row_list+[i_value]
|
1098
|
+
dfp.loc[len(dfp)] = row_list
|
1099
|
+
|
1100
|
+
#主要项目排序
|
1101
|
+
|
1102
|
+
dfp=dfp.replace(0,'-')
|
1103
|
+
dfp=dfp.fillna('-')
|
1104
|
+
|
1105
|
+
#无序号打印
|
1106
|
+
if title_txt=='':
|
1107
|
+
title_txt="=== 重要指标的同行业对比 ==="
|
1108
|
+
ticker=tickers[0]
|
1109
|
+
tname=ticker_name(ticker,'stock').replace("(A股)",'')
|
1110
|
+
title_txt=tname+"财报分析:重要指标的同行业对比\n(截至"+fsdate+")"
|
1111
|
+
import datetime; todaydt=datetime.date.today()
|
1112
|
+
if yiyuan_foot:
|
1113
|
+
footnote="单位:亿元,数据来源:新浪财经,"+str(todaydt)
|
1114
|
+
else:
|
1115
|
+
footnote="数据来源:新浪财经,"+str(todaydt)
|
1116
|
+
df_directprint(dfp,title_txt,footnote)
|
1117
|
+
|
1118
|
+
return dfp
|
1119
|
+
#==============================================================================
|
1120
|
+
if __name__=='__main__':
|
1121
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
1122
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
1123
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
1124
|
+
|
1125
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
1126
|
+
fsdate='2021-12-31'
|
1127
|
+
items=['存货','资产总计','存货占比%']
|
1128
|
+
|
1129
|
+
dfp=fs_item_analysis_7(df,tickers,fsdate,items)
|
1130
|
+
|
1131
|
+
def fs_item_analysis_7(df,tickers,fsdate,items,title_txt='',notes='', \
|
1132
|
+
facecolor='papayawhip',font_size='16px'):
|
1133
|
+
"""
|
1134
|
+
功能:比较给定财报日期fsdate的项目和指标,与同业相比
|
1135
|
+
"""
|
1136
|
+
|
1137
|
+
col_list=['上市公司']+items
|
1138
|
+
dfp=pd.DataFrame(columns=col_list)
|
1139
|
+
yiyuan=100000000
|
1140
|
+
yiyuan_foot=False
|
1141
|
+
|
1142
|
+
for t in tickers:
|
1143
|
+
tname=ticker_name(t,'stock').replace("(A股)",'')
|
1144
|
+
row_list=[tname]
|
1145
|
+
for i in items:
|
1146
|
+
i_value,_,_=select_item(df,t,fsdate,i)
|
1147
|
+
if not('%' in i) and not('(元)' in i):
|
1148
|
+
row_list=row_list+[round(i_value/yiyuan,4)]
|
1149
|
+
yiyuan_foot=True
|
1150
|
+
else:
|
1151
|
+
row_list=row_list+[i_value]
|
1152
|
+
dfp.loc[len(dfp)] = row_list
|
1153
|
+
|
1154
|
+
dfp=dfp.replace(0,'-')
|
1155
|
+
dfp=dfp.fillna('-')
|
1156
|
+
|
1157
|
+
#对主要项目排序
|
1158
|
+
lastitem=items[1]
|
1159
|
+
for i in items:
|
1160
|
+
if '%' in i:
|
1161
|
+
lastitem=i
|
1162
|
+
break
|
1163
|
+
else:
|
1164
|
+
continue
|
1165
|
+
|
1166
|
+
try:
|
1167
|
+
dfp.sort_values(by=lastitem,ascending=False,inplace=True)
|
1168
|
+
except:
|
1169
|
+
#因混有字符串和数值而排序失败,全转换为字符串再度排序
|
1170
|
+
dfp[lastitem]=dfp[lastitem].apply(lambda x: str(x))
|
1171
|
+
dfp.sort_values(by=lastitem,ascending=False,inplace=True)
|
1172
|
+
|
1173
|
+
dfp.reset_index(drop=True,inplace=True)
|
1174
|
+
dfp.index=dfp.index+1
|
1175
|
+
|
1176
|
+
#无序号打印
|
1177
|
+
if title_txt=='':
|
1178
|
+
title_txt="=== 重要指标的同行业对比 ==="
|
1179
|
+
ticker=tickers[0]
|
1180
|
+
tname=ticker_name(ticker,'stock').replace("(A股)",'')
|
1181
|
+
title_txt=tname+"财报分析:重要指标的同行业对比\n(截至"+fsdate+")"
|
1182
|
+
import datetime; todaydt=datetime.date.today()
|
1183
|
+
if yiyuan_foot:
|
1184
|
+
#footnote="*单位:亿元,数据来源:新浪财经,"+str(today)
|
1185
|
+
#footnote="*单位:亿元,本期报表日期:"+fsdate+',数据来源:新浪财经'
|
1186
|
+
footnote="单位:亿元,数据来源:新浪财经,"+str(todaydt)
|
1187
|
+
else:
|
1188
|
+
#footnote="*数据来源:新浪财经,"+str(today)
|
1189
|
+
#footnote="*本期报表日期:"+fsdate+',数据来源:新浪财经'
|
1190
|
+
footnote='数据来源:新浪财经,'+str(todaydt)
|
1191
|
+
|
1192
|
+
if notes=='':
|
1193
|
+
foottext=footnote
|
1194
|
+
else:
|
1195
|
+
foottext=notes+'\n'+footnote
|
1196
|
+
|
1197
|
+
#确定表格字体大小
|
1198
|
+
titile_font_size=font_size
|
1199
|
+
heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
|
1200
|
+
|
1201
|
+
#df_directprint(dfp,title_txt,foottext,facecolor=facecolor)
|
1202
|
+
df_display_CSS(df=dfp,titletxt=title_txt,footnote=foottext, \
|
1203
|
+
first_col_align='left', \
|
1204
|
+
facecolor=facecolor,decimals=2, \
|
1205
|
+
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
1206
|
+
data_font_size=data_font_size)
|
1207
|
+
return dfp
|
1208
|
+
|
1209
|
+
#==============================================================================
|
1210
|
+
if __name__=='__main__':
|
1211
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
1212
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
1213
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
1214
|
+
|
1215
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
1216
|
+
fsdate='2021-12-31'
|
1217
|
+
items=['资产总计','资产负债率%','流动比率%','速动比率%']
|
1218
|
+
dfp=fs_item_analysis_8(df,tickers,fsdate,items)
|
1219
|
+
|
1220
|
+
def fs_item_analysis_8(df,tickers,fsdate,items,title_txt='',notes='', \
|
1221
|
+
facecolor='papayawhip',font_size='16px'):
|
1222
|
+
"""
|
1223
|
+
功能:比较给定财报日期fsdate的项目和指标,与同业相比
|
1224
|
+
区别:项目不带‘(亿元)’字样,避免行过长
|
1225
|
+
"""
|
1226
|
+
|
1227
|
+
#循环获取科目
|
1228
|
+
col_list=['上市公司']+items
|
1229
|
+
dfp=pd.DataFrame(columns=col_list)
|
1230
|
+
yiyuan=100000000
|
1231
|
+
yiyuan_foot=False
|
1232
|
+
|
1233
|
+
for t in tickers:
|
1234
|
+
tname=ticker_name(t,'stock').replace("(A股)",'')
|
1235
|
+
row_list=[tname]
|
1236
|
+
for i in items:
|
1237
|
+
i_value,_,_=select_item(df,t,fsdate,i)
|
1238
|
+
if not('%' in i) and not('(元)' in i):
|
1239
|
+
row_list=row_list+[round(i_value/yiyuan,4)]
|
1240
|
+
yiyuan_foot=True
|
1241
|
+
else:
|
1242
|
+
row_list=row_list+[i_value]
|
1243
|
+
dfp.loc[len(dfp)] = row_list
|
1244
|
+
|
1245
|
+
#对主要项目排序
|
1246
|
+
lastitem=items[1]
|
1247
|
+
for i in items:
|
1248
|
+
if '%' in i:
|
1249
|
+
lastitem=i
|
1250
|
+
break
|
1251
|
+
else:
|
1252
|
+
continue
|
1253
|
+
|
1254
|
+
try:
|
1255
|
+
dfp.sort_values(by=lastitem,ascending=False,inplace=True)
|
1256
|
+
except:
|
1257
|
+
#因混有字符串和数值而排序失败,全转换为字符串再度排序
|
1258
|
+
dfp[lastitem]=dfp[lastitem].apply(lambda x: str(x))
|
1259
|
+
dfp.sort_values(by=lastitem,ascending=False,inplace=True)
|
1260
|
+
|
1261
|
+
dfp.reset_index(drop=True,inplace=True)
|
1262
|
+
dfp.index=dfp.index+1
|
1263
|
+
|
1264
|
+
dfp=dfp.replace(0,'-')
|
1265
|
+
dfp=dfp.fillna('-')
|
1266
|
+
|
1267
|
+
#无序号打印
|
1268
|
+
if title_txt=='':
|
1269
|
+
ticker=tickers[0]
|
1270
|
+
tname=ticker_name(ticker,'stock').replace("(A股)",'')
|
1271
|
+
title_txt=tname+"财报分析:重要指标的同行业对比\n(截至"+fsdate+")"
|
1272
|
+
|
1273
|
+
import datetime; todaydt=datetime.date.today()
|
1274
|
+
if yiyuan_foot:
|
1275
|
+
#footnote="*单位:亿元,数据来源:新浪财经,"+str(today)
|
1276
|
+
#footnote="*单位:亿元,本期报表日期:"+fsdate+',数据来源:新浪财经'
|
1277
|
+
footnote="单位:亿元,"+'数据来源:新浪财经,'+str(todaydt)
|
1278
|
+
else:
|
1279
|
+
#footnote="*数据来源:新浪财经,"+str(today)
|
1280
|
+
#footnote="*本期报表日期:"+fsdate+',数据来源:新浪财经'
|
1281
|
+
footnote='数据来源:新浪财经,'+str(todaydt)
|
1282
|
+
|
1283
|
+
if notes=='':
|
1284
|
+
foottext=footnote
|
1285
|
+
else:
|
1286
|
+
foottext=notes+'\n'+footnote
|
1287
|
+
|
1288
|
+
#确定表格字体大小
|
1289
|
+
titile_font_size=font_size
|
1290
|
+
heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
|
1291
|
+
|
1292
|
+
#df_directprint(dfp,title_txt,foottext,facecolor=facecolor)
|
1293
|
+
df_display_CSS(df=dfp,titletxt=title_txt,footnote=foottext, \
|
1294
|
+
first_col_align='left', \
|
1295
|
+
facecolor=facecolor,decimals=2, \
|
1296
|
+
titile_font_size=titile_font_size,heading_font_size=heading_font_size, \
|
1297
|
+
data_font_size=data_font_size)
|
1298
|
+
return dfp
|
1299
|
+
|
1300
|
+
#==============================================================================
|
1301
|
+
if __name__=='__main__':
|
1302
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
1303
|
+
fsdates=['2022-12-31','2021-12-31','2020-12-31','2019-12-31']
|
1304
|
+
asset_liab_structure_china(tickers,fsdates)
|
1305
|
+
|
1306
|
+
def asset_liab_china(tickers,fsdates,facecolor='papayawhip',font_size='16px'):
|
1307
|
+
"""
|
1308
|
+
套壳函数asset_liab_structure_china
|
1309
|
+
"""
|
1310
|
+
asset_liab_structure_china(tickers,fsdates,facecolor=facecolor,font_size=font_size)
|
1311
|
+
|
1312
|
+
return
|
1313
|
+
|
1314
|
+
|
1315
|
+
def asset_liab_structure_china(tickers,fsdates,facecolor='papayawhip',font_size='16px'):
|
1316
|
+
"""
|
1317
|
+
功能:分析上市公司的资产负债基本结构,并与同业公司对比。
|
1318
|
+
注意1:分析近三期情况,fsdates要给出四个报表日期,以便获得期初数。
|
1319
|
+
注意2:可以分析连续的年报或季报,但不能混个年报和季报。
|
1320
|
+
注意3:tickers中的第一家公司为主要分析对象。
|
1321
|
+
注意4:fsdates中的日期要降序排列,第一个日期建议为最近的财报日。
|
1322
|
+
"""
|
1323
|
+
# 检查证券个数
|
1324
|
+
if isinstance(tickers,str):
|
1325
|
+
print(" #Warning(asset_liab_structure_china): expecting multiple tickers in a list for",tickers)
|
1326
|
+
return
|
1327
|
+
|
1328
|
+
# 检查财报日期个数
|
1329
|
+
if isinstance(fsdates,str):
|
1330
|
+
|
1331
|
+
fsdateslist=[fsdates]
|
1332
|
+
y4int=int(fsdates[0:4])
|
1333
|
+
mmddstr=fsdates[4:len(fsdates)]
|
1334
|
+
for y in range(1,4):
|
1335
|
+
y4next=y4int - y
|
1336
|
+
fsdateslist=fsdateslist+[str(y4next)+mmddstr]
|
1337
|
+
print(" #Notice(asset_liab_structure_china): extended to 4 dates for financial statements")
|
1338
|
+
fsdates=fsdateslist
|
1339
|
+
|
1340
|
+
# 检查日期个数是否为4个,最后一个作为上期对比。最终列示前3项的结果
|
1341
|
+
if len(fsdates) <= 3:
|
1342
|
+
print(" #Warning(asset_liab_structure_china): expecting 4 consecutive dates for financial statements")
|
1343
|
+
return
|
1344
|
+
|
1345
|
+
comparator=tickers[0]
|
1346
|
+
comparee=tickers[1:]
|
1347
|
+
print(" Conducting asset-liability analysis ...")
|
1348
|
+
print(" Focus on:",ticker_name(comparator,'stock'))
|
1349
|
+
#print(" Comparee :",ticker_name(comparee))
|
1350
|
+
print(" Peers:",end='')
|
1351
|
+
if comparee != []:
|
1352
|
+
print_list(ticker_name(comparee,'stock'))
|
1353
|
+
else:
|
1354
|
+
print(" N/A")
|
1355
|
+
|
1356
|
+
#主要分析对象
|
1357
|
+
ticker=tickers[0]
|
1358
|
+
|
1359
|
+
#将日期规范化,以便排序正确
|
1360
|
+
fsdates1=[]
|
1361
|
+
for d in fsdates:
|
1362
|
+
result,fd=check_date2(d)
|
1363
|
+
if not result:
|
1364
|
+
print(" #Warning(asset_liab_structure_china): invalid date",d)
|
1365
|
+
return
|
1366
|
+
fsdates1=fsdates1+[fd]
|
1367
|
+
fsdates=fsdates1
|
1368
|
+
|
1369
|
+
#检查是否定期报告日期
|
1370
|
+
reportdates=['03-31','06-30','09-30','12-31']
|
1371
|
+
for d in fsdates:
|
1372
|
+
mm_dd=d[5:]
|
1373
|
+
if not (mm_dd in reportdates):
|
1374
|
+
print(" #Warning(asset_liab_structure_china): invalid date for financial statements in China",d)
|
1375
|
+
return
|
1376
|
+
|
1377
|
+
#最近的财报日
|
1378
|
+
fsdates=sorted(fsdates,reverse=True)
|
1379
|
+
fsdate=fsdates[0]
|
1380
|
+
|
1381
|
+
#获取所有比较公司tickers的所有财报fsdates
|
1382
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
1383
|
+
if df is None:
|
1384
|
+
print(" #Warning(asset_liab_structure_china): failed to retrieve any info for tickers in the periods")
|
1385
|
+
print(" Solution: check ticker spelling and try at least 10 minutes later")
|
1386
|
+
return
|
1387
|
+
|
1388
|
+
#title_head=ticker_name(comparator,'stock')+"资产负债分析:"
|
1389
|
+
title_head=ticker_name(comparator,'stock')+":"
|
1390
|
+
|
1391
|
+
### 资产负债表的主要项目
|
1392
|
+
#资产变动趋势2
|
1393
|
+
title_txt=title_head+"主要资产项目,"+fsdate
|
1394
|
+
items2=["货币资金","应收账款","存货","长期股权投资","固定资产净额","资产总计"]
|
1395
|
+
"""
|
1396
|
+
notes1="注1:货币资金包括库存现金、银行存款和其他货币资金三个部分"
|
1397
|
+
notes2="注2:其他货币资金包括银行汇(本)票存款、信用证保证金存款和信用卡存款等"
|
1398
|
+
notes3="注3:长期股权投资是指企业对其子公司、合营企业及联营企业的权益性投资"
|
1399
|
+
notes4="注4:固定资产净额 = 固定资产原值 - 累计折旧 - 资产减值准备"
|
1400
|
+
"""
|
1401
|
+
notes1="注:\n货币资金包括库存现金、银行存款和其他货币资金三个部分"
|
1402
|
+
notes2="其他货币资金包括银行汇(本)票存款、信用证保证金存款和信用卡存款等"
|
1403
|
+
notes3="长期股权投资是指企业对其子公司、合营企业及联营企业的权益性投资"
|
1404
|
+
notes4="固定资产净额 = 固定资产原值 - 累计折旧 - 资产减值准备"
|
1405
|
+
|
1406
|
+
notes=notes1+'\n'+notes2+'\n'+notes3+'\n'+notes4
|
1407
|
+
dfp2=fs_item_analysis_1(df,ticker,fsdate,items2,title_txt,notes, \
|
1408
|
+
facecolor=facecolor,font_size=font_size)
|
1409
|
+
|
1410
|
+
#负债变动趋势
|
1411
|
+
title_txt=title_head+"主要负债项目,"+fsdate
|
1412
|
+
items3=["短期借款","长期借款","应付账款","预收款项","应交税费","应付职工薪酬","负债合计"]
|
1413
|
+
dfp3=fs_item_analysis_1(df,ticker,fsdate,items3,title_txt, \
|
1414
|
+
facecolor=facecolor,font_size=font_size)
|
1415
|
+
|
1416
|
+
#所有者权益变动趋势
|
1417
|
+
title_txt=title_head+"主要权益项目,"+fsdate
|
1418
|
+
items4=["实收资本(或股本)","资本公积","盈余公积","未分配利润","所有者权益合计"]
|
1419
|
+
"""
|
1420
|
+
notes1="注1:实收资本(或股本,Paid-in Capital)指企业实际收到的投资人投入的资本"
|
1421
|
+
notes2="注2:资本公积是由股东投入的因故不能计入实收资本(或股本)中的那部分投入资金"
|
1422
|
+
notes3=" 资本公积包括资本(股本)溢价、其他资本公积、资产评估增值、资本折算差额"
|
1423
|
+
notes4=" 资本(股本)溢价是公司发行权益证券时价格超出票面价值的部分"
|
1424
|
+
notes5=" 其他资本公积包括金融资产公允价值变动、被投资单位净利润以外的变动等"
|
1425
|
+
notes6=" 资产评估增值是重估企业资产时,重估价高于资产的账面净值的部分"
|
1426
|
+
notes7=" 资本折算差额是外币资本因汇率变动产生的差额"
|
1427
|
+
notes8="注3:盈余公积是企业按照要求从税后利润中提取的、属于留存收益范畴的资金"
|
1428
|
+
notes9=" 企业从历年利润中提取的留存于企业的内部积累,包括盈余公积和未分配利润"
|
1429
|
+
notes10=" 公司制企业的盈余公积包括法定盈余公积和任意盈余公积"
|
1430
|
+
notes11=" 法定盈余公积是指企业按照规定比例从净利润中必须提取的盈余公积"
|
1431
|
+
notes12=" 任意盈余公积是指企业内部可自主决定比例提取的盈余公积"
|
1432
|
+
notes13=" 企业提取的盈余公积可用于弥补亏损、转增资本、发放现金股利或利润等"
|
1433
|
+
notes14="注4:未分配利润是净利润经弥补亏损、提取盈余公积和向投资者分配利润后的资金"
|
1434
|
+
"""
|
1435
|
+
notes1="注:\n实收资本(或股本,Paid-in Capital)指企业实际收到的投资人投入的资本"
|
1436
|
+
notes2="资本公积是由股东投入的因故不能计入实收资本(或股本)中的那部分投入资金"
|
1437
|
+
notes3="资本公积包括资本(股本)溢价、其他资本公积、资产评估增值、资本折算差额"
|
1438
|
+
notes4="资本(股本)溢价是公司发行权益证券时价格超出票面价值的部分"
|
1439
|
+
notes5="其他资本公积包括金融资产公允价值变动、被投资单位净利润以外的变动等"
|
1440
|
+
notes6="资产评估增值是重估企业资产时,重估价高于资产的账面净值的部分"
|
1441
|
+
notes7="资本折算差额是外币资本因汇率变动产生的差额"
|
1442
|
+
notes8="盈余公积是企业按照要求从税后利润中提取的、属于留存收益范畴的资金"
|
1443
|
+
notes9="企业从历年利润中提取的留存于企业的内部积累,包括盈余公积和未分配利润"
|
1444
|
+
notes10="公司制企业的盈余公积包括法定盈余公积和任意盈余公积"
|
1445
|
+
notes11="法定盈余公积是指企业按照规定比例从净利润中必须提取的盈余公积"
|
1446
|
+
notes12="任意盈余公积是指企业内部可自主决定比例提取的盈余公积"
|
1447
|
+
notes13="企业提取的盈余公积可用于弥补亏损、转增资本、发放现金股利或利润等"
|
1448
|
+
notes14="未分配利润是净利润经弥补亏损、提取盈余公积和向投资者分配利润后的资金"
|
1449
|
+
|
1450
|
+
notesA=notes1+'\n'+notes2+'\n'+notes3+'\n'+notes4+'\n'+notes5+'\n'+notes6+'\n'+notes7
|
1451
|
+
notesB=notes8+'\n'+notes9+'\n'+notes10+'\n'+notes11+'\n'+notes12+'\n'+notes13+'\n'+notes14
|
1452
|
+
|
1453
|
+
notes=notesA+'\n'+notesB
|
1454
|
+
dfp4=fs_item_analysis_1(df,ticker,fsdate,items4,title_txt,notes, \
|
1455
|
+
facecolor=facecolor,font_size=font_size)
|
1456
|
+
|
1457
|
+
### 货币资金与应收项目
|
1458
|
+
#资产变动趋势1:"货币资金","应收票据","应收账款"
|
1459
|
+
title_txt=title_head+"货币资金与应收项目,"+fsdate
|
1460
|
+
items1=["货币资金","应收票据","应收账款"]
|
1461
|
+
dfp1=fs_item_analysis_1(df,ticker,fsdate,items1,title_txt, \
|
1462
|
+
facecolor=facecolor,font_size=font_size)
|
1463
|
+
|
1464
|
+
#应收账款占比变动分析
|
1465
|
+
fsdates1=fsdates[:3]
|
1466
|
+
items5=["应收账款","资产总计"]
|
1467
|
+
title_txt=title_head+"应收账款占比变动情况"
|
1468
|
+
dfp5=fs_item_analysis_2(df,ticker,fsdates1,items5,title_txt, \
|
1469
|
+
facecolor=facecolor,font_size=font_size)
|
1470
|
+
|
1471
|
+
#应收与营业收入增幅对比
|
1472
|
+
fsdates2=fsdates[:2]
|
1473
|
+
items6=['应收账款',"应收票据",'营业总收入']
|
1474
|
+
title_txt=title_head+"应收项目与营业收入增幅对比"
|
1475
|
+
dfp6=fs_item_analysis_6(df,ticker,fsdates2,items6,title_txt, \
|
1476
|
+
facecolor=facecolor,font_size=font_size)
|
1477
|
+
|
1478
|
+
#应收账款占比同行对比
|
1479
|
+
items7=['应收账款','资产总计','应收账款占比%']
|
1480
|
+
#title_txt=title_head+"应收账款占比同行对比"
|
1481
|
+
title_txt="应收账款占比同行对比:"+fsdate
|
1482
|
+
dfp7=fs_item_analysis_7(df,tickers,fsdate,items7,title_txt, \
|
1483
|
+
facecolor=facecolor,font_size=font_size)
|
1484
|
+
|
1485
|
+
### 存货
|
1486
|
+
#存货占比变动分析
|
1487
|
+
items8=["存货","资产总计"]
|
1488
|
+
title_txt=title_head+"存货占比变动情况"
|
1489
|
+
dfp8=fs_item_analysis_2(df,ticker,fsdates1,items8,title_txt, \
|
1490
|
+
facecolor=facecolor,font_size=font_size)
|
1491
|
+
"""
|
1492
|
+
items9=["存货","营业总收入"]
|
1493
|
+
dfp9=fs_item_analysis_6(df,ticker,fsdates2,items9)
|
1494
|
+
"""
|
1495
|
+
#存货与营业收入增幅对比分析
|
1496
|
+
items10=['存货','流动资产合计',"速动资产合计","资产总计"]
|
1497
|
+
title_txt=title_head+"存货与资产项目增幅对比"
|
1498
|
+
dfp10=fs_item_analysis_6(df,ticker,fsdates2,items10,title_txt, \
|
1499
|
+
facecolor=facecolor,font_size=font_size)
|
1500
|
+
|
1501
|
+
#存货占比与行业对比
|
1502
|
+
items11=['存货','资产总计','存货占比%']
|
1503
|
+
#title_txt=title_head+"存货占比情况同行对比"
|
1504
|
+
title_txt="存货占比情况同行对比:"+fsdate
|
1505
|
+
dfp11=fs_item_analysis_7(df,tickers,fsdate,items11,title_txt, \
|
1506
|
+
facecolor=facecolor,font_size=font_size)
|
1507
|
+
|
1508
|
+
### 偿债能力
|
1509
|
+
#流动比率变动分析
|
1510
|
+
title_txt=title_head+"流动比率变动情况"
|
1511
|
+
dfp12=fs_item_analysis_3(df,ticker,fsdates1,title_txt, \
|
1512
|
+
facecolor=facecolor,font_size=font_size)
|
1513
|
+
|
1514
|
+
#速动比率变动分析
|
1515
|
+
title_txt=title_head+"速动比率变动情况"
|
1516
|
+
dfp13=fs_item_analysis_4(df,ticker,fsdates1,title_txt, \
|
1517
|
+
facecolor=facecolor,font_size=font_size)
|
1518
|
+
|
1519
|
+
#资产负债率变动分析
|
1520
|
+
title_txt=title_head+"资产负债率变动情况"
|
1521
|
+
dfp14=fs_item_analysis_5(df,ticker,fsdates1,title_txt, \
|
1522
|
+
facecolor=facecolor,font_size=font_size)
|
1523
|
+
|
1524
|
+
#资产负债率同行比较
|
1525
|
+
#title_txt=title_head+"资产负债率同行比较"
|
1526
|
+
title_txt="资产负债率同行比较:"+fsdate
|
1527
|
+
items15=['资产总计','资产负债率%','流动比率%','速动比率%']
|
1528
|
+
dfp15=fs_item_analysis_8(df,tickers,fsdate,items15,title_txt, \
|
1529
|
+
facecolor=facecolor,font_size=font_size)
|
1530
|
+
|
1531
|
+
return
|
1532
|
+
|
1533
|
+
#==============================================================================
|
1534
|
+
if __name__=='__main__':
|
1535
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
1536
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
1537
|
+
income_cost_structure_china(tickers,fsdates)
|
1538
|
+
|
1539
|
+
def income_cost_china(tickers,fsdates,facecolor='papayawhip',font_size='16px'):
|
1540
|
+
"""
|
1541
|
+
套壳函数income_cost_structure_china
|
1542
|
+
"""
|
1543
|
+
income_cost_structure_china(tickers,fsdates,facecolor=facecolor,font_size=font_size)
|
1544
|
+
|
1545
|
+
return
|
1546
|
+
|
1547
|
+
def income_cost_structure_china(tickers,fsdates,facecolor='papayawhip',font_size='16px'):
|
1548
|
+
"""
|
1549
|
+
功能:分析上市公司的收入成本基本结构,并与同业公司对比。
|
1550
|
+
注意1:分析近三期情况,fsdates要给出四个报表日期,以便获得期初数。
|
1551
|
+
注意2:可以分析连续的年报或季报,但不能混个年报和季报。
|
1552
|
+
注意3:tickers中的第一家公司为主要分析对象。
|
1553
|
+
注意4:fsdates中的日期要降序排列,第一个日期建议为最近的财报日。
|
1554
|
+
"""
|
1555
|
+
# 检查证券个数
|
1556
|
+
if isinstance(tickers,str):
|
1557
|
+
print(" #Warning(income_cost_structure_china): expecting multiple tickers in a list for",tickers)
|
1558
|
+
return
|
1559
|
+
|
1560
|
+
# 检查财报日期个数
|
1561
|
+
if isinstance(fsdates,str):
|
1562
|
+
fsdateslist=[fsdates]
|
1563
|
+
y4int=int(fsdates[0:4])
|
1564
|
+
mmddstr=fsdates[4:len(fsdates)]
|
1565
|
+
for y in range(1,4):
|
1566
|
+
y4next=y4int - y
|
1567
|
+
fsdateslist=fsdateslist+[str(y4next)+mmddstr]
|
1568
|
+
print(" #Warning(income_cost_structure_china): extended to 4 dates for financial statements")
|
1569
|
+
fsdates=fsdateslist
|
1570
|
+
|
1571
|
+
# 检查日期个数是否为4个,最后一个作为上期对比。最终列示前3项的结果
|
1572
|
+
if len(fsdates) <= 3:
|
1573
|
+
print(" #Warning(income_cost_structure_china): expecting 4 consecutive dates for financial statements")
|
1574
|
+
return
|
1575
|
+
|
1576
|
+
#将日期规范化,以便排序正确
|
1577
|
+
fsdates1=[]
|
1578
|
+
for d in fsdates:
|
1579
|
+
result,fd=check_date2(d)
|
1580
|
+
if not result:
|
1581
|
+
print(" #Warning(income_cost_structure_china): invalid date",d)
|
1582
|
+
return
|
1583
|
+
fsdates1=fsdates1+[fd]
|
1584
|
+
fsdates=fsdates1
|
1585
|
+
|
1586
|
+
comparator=tickers[0]
|
1587
|
+
comparee=tickers[1:]
|
1588
|
+
print(" Conducting income-cost analysis ...")
|
1589
|
+
print(" Focus on:",ticker_name(comparator,'stock'))
|
1590
|
+
#print(" Comparee :",ticker_name(comparee))
|
1591
|
+
print(" Peers:",end='')
|
1592
|
+
if comparee != []:
|
1593
|
+
print_list(ticker_name(comparee,'stock'))
|
1594
|
+
else:
|
1595
|
+
print(" N/A")
|
1596
|
+
|
1597
|
+
#主要分析对象
|
1598
|
+
ticker=tickers[0]
|
1599
|
+
#最近的财报日
|
1600
|
+
fsdates=sorted(fsdates,reverse=True)
|
1601
|
+
fsdate=fsdates[0]
|
1602
|
+
|
1603
|
+
#获取所有比较公司tickers的所有财报fsdates
|
1604
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
1605
|
+
if df is None:
|
1606
|
+
print(" #Warning(income_cost_structure_china): failed to retrieve info for the tickers in the dates")
|
1607
|
+
#print(" Possible reasons: no access to data source or invalid tickers")
|
1608
|
+
return
|
1609
|
+
|
1610
|
+
title_head=ticker_name(comparator,'stock')+":"
|
1611
|
+
|
1612
|
+
#收入成本总体变动趋势
|
1613
|
+
title_txt=title_head+"主要利润表项目,"+fsdate
|
1614
|
+
items1=["营业总收入","营业总成本","营业成本","毛利润","营业利润","营业外收支","税前利润","所得税费用","净利润","归母净利润"]
|
1615
|
+
dfp1=fs_item_analysis_1(df,ticker,fsdate,items1,title_txt, \
|
1616
|
+
facecolor=facecolor,font_size=font_size)
|
1617
|
+
|
1618
|
+
#成本变动趋势
|
1619
|
+
title_txt=title_head+"主要成本费用项目,"+fsdate
|
1620
|
+
print('')
|
1621
|
+
"""
|
1622
|
+
items2=["营业总成本","营业成本","营业税金及附加","销售费用","管理费用","研发费用",
|
1623
|
+
"应付利息","公允价值变动损失","非流动资产处置损失",
|
1624
|
+
"资产减值损失","营业外支出"]
|
1625
|
+
"""
|
1626
|
+
items2=["营业总成本","营业成本","营业税金及附加","销售费用","管理费用","研发费用",
|
1627
|
+
"应付利息","非流动资产处置损失",
|
1628
|
+
"资产减值损失","营业外支出"]
|
1629
|
+
dfp2=fs_item_analysis_1(df,ticker,'2021-12-31',items2,title_txt, \
|
1630
|
+
facecolor=facecolor,font_size=font_size)
|
1631
|
+
|
1632
|
+
#占比变动分析:近三年
|
1633
|
+
title_txt=title_head+"营业总成本占营业总收入比例情况"
|
1634
|
+
fsdates1=fsdates[:3]
|
1635
|
+
items3=["营业总成本","营业总收入"]
|
1636
|
+
"""
|
1637
|
+
notes1="注1:营业总成本包括营业成本、营业税金及附加、三大费用和资产减值损失"
|
1638
|
+
notes2="注2:营业收入=主营业务收入和其他非主营业务收入"
|
1639
|
+
notes3="注3:营业总收入=营业收入+非营业收入(投资收益、营业外收入等)"
|
1640
|
+
"""
|
1641
|
+
notes1="注:\n营业总成本包括营业成本、营业税金及附加、三大费用和资产减值损失"
|
1642
|
+
notes2="营业收入=主营业务收入和其他非主营业务收入"
|
1643
|
+
notes3="营业总收入=营业收入+非营业收入(投资收益、营业外收入等)"
|
1644
|
+
|
1645
|
+
notes=notes1+'\n'+notes2+'\n'+notes3
|
1646
|
+
dfp3=fs_item_analysis_2(df,ticker,fsdates1,items3,title_txt,notes, \
|
1647
|
+
facecolor=facecolor,font_size=font_size)
|
1648
|
+
#====================================================================
|
1649
|
+
title_txt=title_head+"营业成本占营业总成本比例情况"
|
1650
|
+
items4=["营业成本","营业总成本"]
|
1651
|
+
"""
|
1652
|
+
notes1="注1:营业成本是经营活动中发生的可归属于产品/劳务成本等的费用"
|
1653
|
+
notes2="注2:营业总成本包括营业成本、营业税金及附加、三大费用和资产减值损失"
|
1654
|
+
"""
|
1655
|
+
notes1="注:\n营业成本是经营活动中发生的可归属于产品/劳务成本等的费用"
|
1656
|
+
notes2="营业总成本包括营业成本、营业税金及附加、三大费用和资产减值损失"
|
1657
|
+
|
1658
|
+
notes=notes1+'\n'+notes2
|
1659
|
+
dfp4=fs_item_analysis_2(df,ticker,fsdates1,items4,title_txt,notes, \
|
1660
|
+
facecolor=facecolor,font_size=font_size)
|
1661
|
+
|
1662
|
+
title_txt=title_head+"营业成本占营业总收入比例情况"
|
1663
|
+
items5=["营业成本","营业总收入"]
|
1664
|
+
dfp5=fs_item_analysis_2(df,ticker,fsdates1,items5,title_txt, \
|
1665
|
+
facecolor=facecolor,font_size=font_size)
|
1666
|
+
|
1667
|
+
title_txt=title_head+"营业成本增幅分析"
|
1668
|
+
fsdates2=fsdates[:2]
|
1669
|
+
items12=['营业成本','营业总成本','营业总收入']
|
1670
|
+
dfp12=fs_item_analysis_6(df,ticker,fsdates2,items12,title_txt, \
|
1671
|
+
facecolor=facecolor,font_size=font_size)
|
1672
|
+
|
1673
|
+
#====================================================================
|
1674
|
+
title_txt=title_head+"销售费用占营业总收入比例情况"
|
1675
|
+
items6=["销售费用","营业总收入"]
|
1676
|
+
|
1677
|
+
notes="注:销售费用是企业销售过程中发生的各种费用"
|
1678
|
+
dfp6=fs_item_analysis_2(df,ticker,fsdates1,items6,title_txt,notes, \
|
1679
|
+
facecolor=facecolor,font_size=font_size)
|
1680
|
+
#====================================================================
|
1681
|
+
title_txt=title_head+"管理费用占营业总收入比例情况"
|
1682
|
+
items7=["管理费用","营业总收入"]
|
1683
|
+
|
1684
|
+
notes="注:管理费用是行政管理部门为组织生产/经营活动发生的各种费用"
|
1685
|
+
dfp7=fs_item_analysis_2(df,ticker,fsdates1,items7,title_txt,notes, \
|
1686
|
+
facecolor=facecolor,font_size=font_size)
|
1687
|
+
|
1688
|
+
#title_txt=title_head+"三项费用率同行对比"
|
1689
|
+
title_txt="三项费用率同行对比:"+fsdate
|
1690
|
+
items14=['营业总收入','销售费用率%','管理费用率%','研发费用率%']
|
1691
|
+
"""
|
1692
|
+
notes1="注1:销售费用率 = 销售费用 / 营业总收入"
|
1693
|
+
notes2="注2:管理费用率 = 管理费用 / 营业总收入"
|
1694
|
+
notes3="注3:研发费用率 = 研发费用 / 营业总收入"
|
1695
|
+
"""
|
1696
|
+
notes1="注:\n销售费用率 = 销售费用 / 营业总收入"
|
1697
|
+
notes2="管理费用率 = 管理费用 / 营业总收入"
|
1698
|
+
notes3="研发费用率 = 研发费用 / 营业总收入"
|
1699
|
+
|
1700
|
+
notes=notes1+'\n'+notes2+'\n'+notes3
|
1701
|
+
|
1702
|
+
dfp12=fs_item_analysis_8(df,tickers,fsdate,items14,title_txt,notes, \
|
1703
|
+
facecolor=facecolor,font_size=font_size)
|
1704
|
+
#====================================================================
|
1705
|
+
title_txt=title_head+"毛利润占营业总收入比例情况"
|
1706
|
+
items8=["毛利润","营业总收入"]
|
1707
|
+
dfp8=fs_item_analysis_2(df,ticker,fsdates1,items8,title_txt, \
|
1708
|
+
facecolor=facecolor,font_size=font_size)
|
1709
|
+
#====================================================================
|
1710
|
+
title_txt=title_head+"营业利润占营业总收入比例情况"
|
1711
|
+
items9=["营业利润","营业总收入"]
|
1712
|
+
dfp8=fs_item_analysis_2(df,ticker,fsdates1,items9,title_txt, \
|
1713
|
+
facecolor=facecolor,font_size=font_size)
|
1714
|
+
#====================================================================
|
1715
|
+
title_txt=title_head+"税前利润占营业总收入比例情况"
|
1716
|
+
items10=["税前利润","营业总收入"]
|
1717
|
+
dfp9=fs_item_analysis_2(df,ticker,fsdates1,items10,title_txt, \
|
1718
|
+
facecolor=facecolor,font_size=font_size)
|
1719
|
+
#====================================================================
|
1720
|
+
title_txt=title_head+"净利润占营业总收入比例情况"
|
1721
|
+
items11=["净利润","营业总收入"]
|
1722
|
+
dfp9=fs_item_analysis_2(df,ticker,fsdates1,items11,title_txt, \
|
1723
|
+
facecolor=facecolor,font_size=font_size)
|
1724
|
+
|
1725
|
+
#增幅分析:近两年
|
1726
|
+
title_txt=title_head+"四种利润对比"
|
1727
|
+
items13=['毛利润','营业利润','税前利润','净利润']
|
1728
|
+
dfp11=fs_item_analysis_6(df,ticker,fsdates2,items13,title_txt, \
|
1729
|
+
facecolor=facecolor,font_size=font_size)
|
1730
|
+
|
1731
|
+
#同行比较
|
1732
|
+
#title_txt=title_head+"利润率同行对比"
|
1733
|
+
title_txt="利润率同行对比:"+fsdate
|
1734
|
+
#items15=['营业利润','营业利润率%','税前利润率%','实际所得税率%','净利润','净利润率%']
|
1735
|
+
#items15=['毛利润率%','营业利润率%','税前利润率%','净利润率%']
|
1736
|
+
items15=['净利润率%','税前利润率%','营业利润率%','毛利润率%']
|
1737
|
+
dfp12=fs_item_analysis_8(df,tickers,fsdate,items15,title_txt, \
|
1738
|
+
facecolor=facecolor,font_size=font_size)
|
1739
|
+
|
1740
|
+
return
|
1741
|
+
|
1742
|
+
#==============================================================================
|
1743
|
+
if __name__=='__main__':
|
1744
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
1745
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
1746
|
+
cash_flow_structure_china(tickers,fsdates)
|
1747
|
+
|
1748
|
+
def cash_flow_china(tickers,fsdates,facecolor='papayawhip',font_size='16px'):
|
1749
|
+
"""
|
1750
|
+
套壳函数cash_flow_structure_china
|
1751
|
+
"""
|
1752
|
+
cash_flow_structure_china(tickers,fsdates,facecolor=facecolor,font_size=font_size)
|
1753
|
+
|
1754
|
+
return
|
1755
|
+
|
1756
|
+
|
1757
|
+
def cash_flow_structure_china(tickers,fsdates,facecolor='papayawhip',font_size='16px'):
|
1758
|
+
"""
|
1759
|
+
功能:分析上市公司的现金流量基本结构,并与同业公司对比。
|
1760
|
+
注意1:分析近三期情况,fsdates要给出四个报表日期,以便获得期初数。
|
1761
|
+
注意2:可以分析连续的年报或季报,但不能混个年报和季报。
|
1762
|
+
注意3:tickers中的第一家公司为主要分析对象。
|
1763
|
+
注意4:fsdates中的日期要降序排列,第一个日期建议为最近的财报日。
|
1764
|
+
"""
|
1765
|
+
if isinstance(tickers,str):
|
1766
|
+
print(" #Warning(cash_flow_structure_china): expecting multiple tickers in a list for",tickers)
|
1767
|
+
return
|
1768
|
+
|
1769
|
+
# 检查财报日期个数
|
1770
|
+
if isinstance(fsdates,str):
|
1771
|
+
fsdateslist=[fsdates]
|
1772
|
+
y4int=int(fsdates[0:4])
|
1773
|
+
mmddstr=fsdates[4:len(fsdates)]
|
1774
|
+
for y in range(1,4):
|
1775
|
+
y4next=y4int - y
|
1776
|
+
fsdateslist=fsdateslist+[str(y4next)+mmddstr]
|
1777
|
+
print(" #Warning(cash_flow_structure_china): extended to 4 dates for financial statements")
|
1778
|
+
fsdates=fsdateslist
|
1779
|
+
|
1780
|
+
# 检查日期个数是否为4个,最后一个作为上期对比。最终列示前3项的结果
|
1781
|
+
if len(fsdates) <= 3:
|
1782
|
+
print(" #Warning(cash_flow_structure_china): expecting 4 consecutive dates for financial statements")
|
1783
|
+
return
|
1784
|
+
|
1785
|
+
#将日期规范化,以便排序正确
|
1786
|
+
fsdates1=[]
|
1787
|
+
for d in fsdates:
|
1788
|
+
result,fd=check_date2(d)
|
1789
|
+
if not result:
|
1790
|
+
print(" #Warning(cash_flow_structure_china): invalid date",d)
|
1791
|
+
return
|
1792
|
+
fsdates1=fsdates1+[fd]
|
1793
|
+
fsdates=fsdates1
|
1794
|
+
|
1795
|
+
comparator=tickers[0]
|
1796
|
+
comparee=tickers[1:]
|
1797
|
+
print(" Conducting cash flow analysis ...")
|
1798
|
+
print(" Focus on:",ticker_name(comparator,'stock'))
|
1799
|
+
print(" Peers:",end='')
|
1800
|
+
if comparee != []:
|
1801
|
+
print_list(ticker_name(comparee,'stock'))
|
1802
|
+
else:
|
1803
|
+
print(" N/A")
|
1804
|
+
|
1805
|
+
#主要分析对象
|
1806
|
+
ticker=tickers[0]
|
1807
|
+
#最近的财报日
|
1808
|
+
fsdates=sorted(fsdates,reverse=True)
|
1809
|
+
fsdate=fsdates[0]
|
1810
|
+
|
1811
|
+
#获取所有比较公司tickers的所有财报fsdates
|
1812
|
+
df=get_fin_stmt_ak_multi(tickers,fsdates)
|
1813
|
+
if df is None:
|
1814
|
+
print(" #Warning(cash_flow_structure_china): failed to retrieve info for the tickers in the dates")
|
1815
|
+
#print(" Possible reasons: no access to data source or invalid tickers")
|
1816
|
+
return
|
1817
|
+
|
1818
|
+
title_head=ticker_name(comparator,'stock')+":"
|
1819
|
+
|
1820
|
+
#总体变动趋势
|
1821
|
+
title_txt=title_head+"主要现金流项目,"+fsdate
|
1822
|
+
items1=["经营活动现金流净额","经营活动现金流入","经营活动现金流出",
|
1823
|
+
"投资活动现金流净额","投资活动现金流入","投资活动现金流出",
|
1824
|
+
"筹资活动现金流净额","筹资活动现金流入","筹资活动现金流出",
|
1825
|
+
"汇率对现金流的影响","现金流量净增加额"]
|
1826
|
+
dfp1=fs_item_analysis_1(df,ticker,fsdate,items1,title_txt, \
|
1827
|
+
facecolor=facecolor,font_size=font_size)
|
1828
|
+
|
1829
|
+
#占比变动分析:近三年
|
1830
|
+
title_txt=title_head+"经营活动现金流入占比情况"
|
1831
|
+
fsdates1=fsdates[:3]
|
1832
|
+
items3=["经营活动现金流入","营业总收入"]
|
1833
|
+
dfp3=fs_item_analysis_2(df,ticker,fsdates1,items3,title_txt, \
|
1834
|
+
facecolor=facecolor,font_size=font_size)
|
1835
|
+
|
1836
|
+
title_txt=title_head+"经营活动现金流净额占比情况"
|
1837
|
+
items4=["经营活动现金流净额","营业利润"]
|
1838
|
+
dfp3=fs_item_analysis_2(df,ticker,fsdates1,items4,title_txt, \
|
1839
|
+
facecolor=facecolor,font_size=font_size)
|
1840
|
+
|
1841
|
+
#增幅分析:近两年
|
1842
|
+
title_txt=title_head+"经营活动现金流增幅情况"
|
1843
|
+
fsdates2=fsdates[:2]
|
1844
|
+
items12=['经营活动现金流入','经营活动现金流出','经营活动现金流净额']
|
1845
|
+
dfp12=fs_item_analysis_6(df,ticker,fsdates2,items12,title_txt, \
|
1846
|
+
facecolor=facecolor,font_size=font_size)
|
1847
|
+
|
1848
|
+
#同行比较
|
1849
|
+
title_txt=title_head+"现金收入能力同行比较,"+fsdate
|
1850
|
+
items16=['销售现金比率%','现金购销比率%','营业现金回笼率%']
|
1851
|
+
"""
|
1852
|
+
notes1="注1:销售现金比率 = 经营活动现金流入 / 营业总收入"
|
1853
|
+
notes2="注2:现金购销比率 = 经营活动现金流出 / 经营活动现金流入"
|
1854
|
+
notes3="注3:营业现金回笼率 = 经营活动现金流入 / 营业总收入"
|
1855
|
+
"""
|
1856
|
+
notes1="注:\n销售现金比率 = 经营活动现金流入 / 营业总收入"
|
1857
|
+
notes2="现金购销比率 = 经营活动现金流出 / 经营活动现金流入"
|
1858
|
+
notes3="营业现金回笼率 = 经营活动现金流入 / 营业总收入"
|
1859
|
+
|
1860
|
+
notes=notes1+'\n'+notes2+'\n'+notes3
|
1861
|
+
dfp12=fs_item_analysis_8(df,tickers,fsdate,items16,title_txt,notes, \
|
1862
|
+
facecolor=facecolor,font_size=font_size)
|
1863
|
+
|
1864
|
+
title_txt=title_head+"现金偿债能力同行比较,"+fsdate
|
1865
|
+
items14=['短期现金偿债能力%','长期现金偿债能力%']
|
1866
|
+
"""
|
1867
|
+
notes1="注1:短期现金偿债能力 = 经营活动现金流净额 / 流动负债合计"
|
1868
|
+
notes2="注2:长期现金偿债能力 = 经营活动现金流净额 / 负债合计"
|
1869
|
+
"""
|
1870
|
+
notes1="注:\n短期现金偿债能力 = 经营活动现金流净额 / 流动负债合计"
|
1871
|
+
notes2="长期现金偿债能力 = 经营活动现金流净额 / 负债合计"
|
1872
|
+
|
1873
|
+
notes=notes1+'\n'+notes2
|
1874
|
+
dfp12=fs_item_analysis_8(df,tickers,fsdate,items14,title_txt,notes, \
|
1875
|
+
facecolor=facecolor,font_size=font_size)
|
1876
|
+
|
1877
|
+
title_txt=title_head+"现金支付能力同行比较,"+fsdate
|
1878
|
+
items15=['现金支付股利能力(元)','现金综合支付能力%','支付给职工的现金比率%']
|
1879
|
+
"""
|
1880
|
+
notes1="注1:现金支付股利能力 = 经营活动现金流净额 / 流通股股数"
|
1881
|
+
notes2="注2:现金综合支付能力 = 经营活动现金流净额 / 所有者权益合计"
|
1882
|
+
notes3="注3:支付给职工的现金比率 = 支付给(为)职工支付的现金 / 经营活动现金流入"
|
1883
|
+
"""
|
1884
|
+
notes1="注:\n现金支付股利能力 = 经营活动现金流净额 / 流通股股数"
|
1885
|
+
notes2="现金综合支付能力 = 经营活动现金流净额 / 所有者权益合计"
|
1886
|
+
notes3="支付给职工的现金比率 = 支付给(为)职工支付的现金 / 经营活动现金流入"
|
1887
|
+
|
1888
|
+
notes=notes1+'\n'+notes2+'\n'+notes3
|
1889
|
+
dfp12=fs_item_analysis_8(df,tickers,fsdate,items15,title_txt,notes, \
|
1890
|
+
facecolor=facecolor,font_size=font_size)
|
1891
|
+
|
1892
|
+
title_txt=title_head+"财务指标含金量同行比较,"+fsdate
|
1893
|
+
items17=['盈利现金比率%','现金流入流出比率%','资产现金回收率%']
|
1894
|
+
"""
|
1895
|
+
notes1="注1:盈利现金比率 = 经营活动现金流净额 / 净利润"
|
1896
|
+
notes2="注2:现金流入流出比率 = 经营活动现金流入 / 经营活动现金流出"
|
1897
|
+
notes3="注3:资产现金回收率 = 经营活动现金流净额 / 资产总计"
|
1898
|
+
"""
|
1899
|
+
notes1="注:\n盈利现金比率 = 经营活动现金流净额 / 净利润"
|
1900
|
+
notes2="现金流入流出比率 = 经营活动现金流入 / 经营活动现金流出"
|
1901
|
+
notes3="资产现金回收率 = 经营活动现金流净额 / 资产总计"
|
1902
|
+
|
1903
|
+
notes=notes1+'\n'+notes2+'\n'+notes3
|
1904
|
+
dfp12=fs_item_analysis_8(df,tickers,fsdate,items17,title_txt,notes, \
|
1905
|
+
facecolor=facecolor,font_size=font_size)
|
1906
|
+
|
1907
|
+
return
|
1908
|
+
|
1909
|
+
#==============================================================================
|
1910
|
+
if __name__=='__main__':
|
1911
|
+
date1='2022-12-31'
|
1912
|
+
num=4
|
1913
|
+
gen_yoy_dates(date1,4)
|
1914
|
+
|
1915
|
+
def gen_yoy_dates(date1,num=4):
|
1916
|
+
"""
|
1917
|
+
功能:生成date1的num个同比的日期
|
1918
|
+
"""
|
1919
|
+
if not isinstance(date1,str):
|
1920
|
+
print(" #Error(gen_yoy_dates): invalid date",date1)
|
1921
|
+
return date1
|
1922
|
+
|
1923
|
+
y4=int(date1[:4])
|
1924
|
+
mmdd=date1[4:]
|
1925
|
+
|
1926
|
+
datelist=[]
|
1927
|
+
for i in range(0,num):
|
1928
|
+
date_tmp=str(y4-i)+mmdd
|
1929
|
+
datelist=datelist+[date_tmp]
|
1930
|
+
|
1931
|
+
return datelist
|
1932
|
+
|
1933
|
+
|
1934
|
+
|
1935
|
+
if __name__=='__main__':
|
1936
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
1937
|
+
fsdates='2021-12-31'
|
1938
|
+
analysis_type='Balance Sheet'
|
1939
|
+
analysis_type='Income Statement'
|
1940
|
+
analysis_type='Cash Flow Statement'
|
1941
|
+
|
1942
|
+
fs_analysis_china(tickers,fsdates,analysis_type='balance sheet')
|
1943
|
+
fs_analysis_china(tickers,fsdates,analysis_type='income statement')
|
1944
|
+
fs_analysis_china(tickers,fsdates,analysis_type='cash flow statement')
|
1945
|
+
|
1946
|
+
tickers=["000002.SZ","600266.SS",'600383.SS','600048.SS']
|
1947
|
+
fsdates=['2021-12-31','2020-12-31','2019-12-31','2018-12-31']
|
1948
|
+
fs_analysis_china(tickers,fsdates,analysis_type='fs summary')
|
1949
|
+
fs_analysis_china(tickers,fsdates,analysis_type='financial indicator')
|
1950
|
+
|
1951
|
+
tickers='000001.SZ'
|
1952
|
+
fs_analysis_china(tickers,fsdates,analysis_type='profile')
|
1953
|
+
fs_analysis_china(tickers,fsdates,analysis_type='profile',category='shareholder')
|
1954
|
+
fs_analysis_china(tickers,fsdates,analysis_type='profile',category='dividend')
|
1955
|
+
fs_analysis_china(tickers,fsdates,analysis_type='profile',category='business')
|
1956
|
+
fs_analysis_china(tickers,fsdates,analysis_type='profile',category='business',business_period='annual')
|
1957
|
+
fs_analysis_china(tickers,fsdates,analysis_type='profile',category='valuation')
|
1958
|
+
fs_analysis_china(tickers,fsdates,analysis_type='profile',category='financial')
|
1959
|
+
|
1960
|
+
def fs_analysis_china(tickers,fsdates=[],analysis_type='balance sheet', \
|
1961
|
+
category='profile',business_period='recent', \
|
1962
|
+
sort='PM',printout=False,gview=False, \
|
1963
|
+
loc1='best',loc2='best', \
|
1964
|
+
facecolor='papayawhip',font_size='16px'):
|
1965
|
+
"""
|
1966
|
+
===========================================================================
|
1967
|
+
功能:财务报表分析,仅适用于中国A股,注意不适用于港股和美股(含中概股)
|
1968
|
+
|
1969
|
+
选项tickers:必选
|
1970
|
+
单只股票:用于单只股票历史财报对比
|
1971
|
+
股票列表:用于股票之间同期财报横向对比
|
1972
|
+
|
1973
|
+
选项fsdates:必选
|
1974
|
+
单个财报日期:适用于选项tickers为股票列表时
|
1975
|
+
财报日期列表:适用于选项tickers为单只股票时,至少四个财报日期,便于对比
|
1976
|
+
|
1977
|
+
选项analysis_type:
|
1978
|
+
资产负债表分析(默认):balance sheet, asset liability
|
1979
|
+
利润表分析:income statement, cost, expense, earning
|
1980
|
+
现金流量表分析:cash flow, cashflow statement
|
1981
|
+
财报概述:financial summary
|
1982
|
+
财务指标:financial indicator
|
1983
|
+
股票画像:stock profile, 下面还可分别选择不同的category项目
|
1984
|
+
杜邦分析:dupont identify, dupont analysis
|
1985
|
+
杜邦分解:dupont decompose,需要安装graphviz插件
|
1986
|
+
|
1987
|
+
选项category:
|
1988
|
+
基本信息(默认):profile
|
1989
|
+
股东信息:shareholder
|
1990
|
+
历史分红:dividend
|
1991
|
+
主营业务:business,目前无法获取数据!
|
1992
|
+
市场估值:valuation
|
1993
|
+
财务概况:financial
|
1994
|
+
|
1995
|
+
选项business_period:
|
1996
|
+
最新(默认):recent,可能为最新可获得的季报或中报或年报
|
1997
|
+
最新的季报:quarterly
|
1998
|
+
最新的中报:semiannual
|
1999
|
+
最新的年报:annual
|
2000
|
+
|
2001
|
+
选项loc1/loc2:适用于需要绘图时指定图例的位置,仅在双图例重叠时手动调整
|
2002
|
+
|
2003
|
+
选项facecolor:指定表格/绘图的背景颜色
|
2004
|
+
烟白色(默认):whitesmoke
|
2005
|
+
其他颜色:参见matplotlib颜色列表,例如淡雅小麦色papayawhip
|
2006
|
+
|
2007
|
+
示例:
|
2008
|
+
千方科技='002373.SZ'
|
2009
|
+
# 企业快照1:大股东
|
2010
|
+
sp1=fs_analysis_china(千方科技,analysis_type='profile',category='shareholder')
|
2011
|
+
# 企业快照2:主营业务
|
2012
|
+
sp2 = fs_analysis_china(千方科技, analysis_type='profile', category='business')
|
2013
|
+
# 企业快照3:股利分红
|
2014
|
+
sp3=fs_analysis_china(千方科技,analysis_type='profile',category='dividend')
|
2015
|
+
# 企业快照4:财务概况
|
2016
|
+
sp4 = fs_analysis_china(千方科技, analysis_type='profile', category='financial')
|
2017
|
+
# 同行业绩对比
|
2018
|
+
# 主要竞争对手:并非所有业务重叠
|
2019
|
+
peers=[ #定义主要竞争对手
|
2020
|
+
'002279.SZ',#久其软件
|
2021
|
+
'002368.SZ',#太极股份
|
2022
|
+
'600410.SS',#华胜天成
|
2023
|
+
'603927.SS',#中科软
|
2024
|
+
'002405.SZ',#四维图新
|
2025
|
+
]
|
2026
|
+
players=[千方科技]+peers
|
2027
|
+
competitors = fs_analysis_china(players, fsdates='2023-12-31', analysis_type='summary')
|
2028
|
+
# 资产负债表分析
|
2029
|
+
fsdates=['2023-12-31','2022-12-31','2021-12-31','2020-12-31','2019-12-31']
|
2030
|
+
fs_analysis_china(千方科技,fsdates,analysis_type='balance sheet')
|
2031
|
+
# 利润表分析
|
2032
|
+
fs_analysis_china(千方科技,fsdates,analysis_type='income statement')
|
2033
|
+
# 现金流量表分析
|
2034
|
+
fs_analysis_china(千方科技,fsdates,analysis_type='cashflow statement')
|
2035
|
+
# 杜邦分析
|
2036
|
+
dd = fs_analysis_china(千方科技, fsdates='2023-12-31', analysis_type='dupont decompose')
|
2037
|
+
# 投资-风险性价比分析
|
2038
|
+
# 以一年期国债收益率作为无风险收益率
|
2039
|
+
RF=0.01657
|
2040
|
+
# 短期分析
|
2041
|
+
rar1=security_trend(players,indicator='sharpe',ret_type='Exp Ret%',start='MRM',RF=RF,loc1='lower left')
|
2042
|
+
rar2 = security_trend(players, indicator='alpha', ret_type='Exp Ret%', start='MRM', RF=RF, loc1='lower left')
|
2043
|
+
# 中长期分析
|
2044
|
+
rar3=security_trend(players,indicator='sharpe',ret_type='Exp Ret%',start='L3Y',RF=RF,loc1='lower left')
|
2045
|
+
|
2046
|
+
备注:封装说明
|
2047
|
+
套壳函数1:tickers为股票列表,fsdates为财报日期,可为单个日期或日期列表
|
2048
|
+
asset_liab_china, income_cost_china, cash_flow_china
|
2049
|
+
|
2050
|
+
套壳函数2:tickers为股票列表,fsdates为财报日期,可为单个日期或日期列表
|
2051
|
+
compare_fin_summary_china
|
2052
|
+
|
2053
|
+
套壳函数3:tickers为股票代码或股票列表,fsdates为财报日期列表
|
2054
|
+
compare_fin_indicator_china
|
2055
|
+
|
2056
|
+
套壳函数4:tickers为股票代码,fsdates不需要,
|
2057
|
+
stock_profile_china
|
2058
|
+
|
2059
|
+
套壳函数5/6:杜邦分析compare_dupont_china / 杜邦分解dupont_decompose
|
2060
|
+
"""
|
2061
|
+
|
2062
|
+
# 统一转小写,便于判断
|
2063
|
+
analysis_type1=analysis_type.lower()
|
2064
|
+
|
2065
|
+
if ('balance' in analysis_type1) or ('sheet' in analysis_type1) \
|
2066
|
+
or ('asset' in analysis_type1) or ('liability' in analysis_type1):
|
2067
|
+
# 检查股票列表
|
2068
|
+
if not isinstance(tickers,list):
|
2069
|
+
tickers=[tickers]
|
2070
|
+
|
2071
|
+
if not isinstance(fsdates,list):
|
2072
|
+
fsdates=gen_yoy_dates(fsdates,num=4)
|
2073
|
+
|
2074
|
+
# 分析资产负债表
|
2075
|
+
asset_liab_china(tickers,fsdates,facecolor=facecolor,font_size=font_size)
|
2076
|
+
return
|
2077
|
+
|
2078
|
+
elif ('income' in analysis_type1) or ('cost' in analysis_type1) \
|
2079
|
+
or ('expense' in analysis_type1) or ('earning' in analysis_type1):
|
2080
|
+
# 检查股票列表
|
2081
|
+
if not isinstance(tickers,list):
|
2082
|
+
tickers=[tickers]
|
2083
|
+
|
2084
|
+
if not isinstance(fsdates,list):
|
2085
|
+
fsdates=gen_yoy_dates(fsdates,num=4)
|
2086
|
+
|
2087
|
+
# 分析利润表
|
2088
|
+
income_cost_china(tickers,fsdates,facecolor=facecolor,font_size=font_size)
|
2089
|
+
return
|
2090
|
+
|
2091
|
+
elif ('cash' in analysis_type1) or ('flow' in analysis_type1):
|
2092
|
+
# 检查股票列表
|
2093
|
+
if not isinstance(tickers,list):
|
2094
|
+
tickers=[tickers]
|
2095
|
+
|
2096
|
+
if not isinstance(fsdates,list):
|
2097
|
+
fsdates=gen_yoy_dates(fsdates,num=4)
|
2098
|
+
|
2099
|
+
# 分析现金流量表
|
2100
|
+
cash_flow_china(tickers,fsdates,facecolor=facecolor,font_size=font_size)
|
2101
|
+
return
|
2102
|
+
|
2103
|
+
elif ('summary' in analysis_type1):
|
2104
|
+
# 股票可为单只股票(单只股票深度分析)或股票列表(多只股票对比)
|
2105
|
+
# 检查股票
|
2106
|
+
if isinstance(tickers,str):
|
2107
|
+
if not isinstance(fsdates,list):
|
2108
|
+
fsdates=gen_yoy_dates(fsdates,num=4)
|
2109
|
+
"""
|
2110
|
+
print(" #Warning(fs_analysis_china): must be date list for",fsdates)
|
2111
|
+
return
|
2112
|
+
"""
|
2113
|
+
|
2114
|
+
# 检查股票列表
|
2115
|
+
if isinstance(tickers,list):
|
2116
|
+
if not isinstance(fsdates,str):
|
2117
|
+
fsdates=fsdates[0]
|
2118
|
+
"""
|
2119
|
+
print(" #Warning(fs_analysis_china): must be a date for",fsdates)
|
2120
|
+
return
|
2121
|
+
"""
|
2122
|
+
|
2123
|
+
# 分析财报摘要
|
2124
|
+
from siat.financials_china import compare_fin_summary_china
|
2125
|
+
df_summary=compare_fin_summary_china(tickers,fsdates,facecolor=facecolor,font_size=font_size)
|
2126
|
+
return
|
2127
|
+
|
2128
|
+
elif ('indicator' in analysis_type1):
|
2129
|
+
# 股票可为单只股票(单只股票深度分析)或股票列表(多只股票对比)
|
2130
|
+
# 检查股票
|
2131
|
+
if isinstance(tickers,str):
|
2132
|
+
if not isinstance(fsdates,list):
|
2133
|
+
fsdates=gen_yoy_dates(fsdates,num=4)
|
2134
|
+
"""
|
2135
|
+
print(" #Warning(fs_analysis_china): must be date list for",fsdates)
|
2136
|
+
return
|
2137
|
+
"""
|
2138
|
+
|
2139
|
+
# 检查股票列表
|
2140
|
+
if isinstance(tickers,list):
|
2141
|
+
if not isinstance(fsdates,str):
|
2142
|
+
fsdates=fsdates[0]
|
2143
|
+
"""
|
2144
|
+
print(" #Warning(fs_analysis_china): must be a date for",fsdates)
|
2145
|
+
return
|
2146
|
+
"""
|
2147
|
+
|
2148
|
+
# 分析主要财务指标和比率
|
2149
|
+
from siat.financials_china import compare_fin_indicator_china
|
2150
|
+
df_ind=compare_fin_indicator_china(tickers,fsdates,facecolor=facecolor,font_size=font_size)
|
2151
|
+
return
|
2152
|
+
|
2153
|
+
elif ('profile' in analysis_type1):
|
2154
|
+
# 股票需为单只股票
|
2155
|
+
if not isinstance(tickers,str):
|
2156
|
+
print(" #Warning(fs_analysis_china): must be one ticker for",tickers)
|
2157
|
+
return
|
2158
|
+
|
2159
|
+
# 分析单只股票的全方位概况
|
2160
|
+
stock_profile_china(tickers,category,business_period,loc1=loc1,loc2=loc2, \
|
2161
|
+
facecolor=facecolor,font_size=font_size)
|
2162
|
+
return
|
2163
|
+
|
2164
|
+
elif ('dupont' in analysis_type1) and (('identity' in analysis_type1) or ('analysis' in analysis_type1)):
|
2165
|
+
# 股票需为股票列表
|
2166
|
+
if not isinstance(tickers,list):
|
2167
|
+
print(" #Warning(fs_analysis_china): must be ticker list for",tickers)
|
2168
|
+
return
|
2169
|
+
# 日期需为一个日期
|
2170
|
+
if not isinstance(fsdates,str):
|
2171
|
+
fsdates=fsdates[0]
|
2172
|
+
"""
|
2173
|
+
print(" #Warning(fs_analysis_china): must one date for",fsdates)
|
2174
|
+
return
|
2175
|
+
"""
|
2176
|
+
|
2177
|
+
# 多只股票的杜邦分析对比
|
2178
|
+
from siat.financials_china import compare_dupont_china
|
2179
|
+
df_db=compare_dupont_china(tickers,fsdate=fsdates,sort=sort,printout=printout, \
|
2180
|
+
facecolor=facecolor,font_size=font_size,loc=loc1)
|
2181
|
+
return
|
2182
|
+
|
2183
|
+
elif ('dupont' in analysis_type1) and ('decompose' in analysis_type1):
|
2184
|
+
# 股票需为单只股票列表
|
2185
|
+
if not isinstance(tickers,str):
|
2186
|
+
if isinstance(tickers,list):
|
2187
|
+
tickers=tickers[0]
|
2188
|
+
else:
|
2189
|
+
print(" #Warning(fs_analysis_china): must be one ticker for",tickers)
|
2190
|
+
return
|
2191
|
+
# 日期需为一个日期
|
2192
|
+
if not isinstance(fsdates,str):
|
2193
|
+
if isinstance(fsdates,list):
|
2194
|
+
fsdates=fsdates[0]
|
2195
|
+
else:
|
2196
|
+
print(" #Warning(fs_analysis_china): must one date for",fsdates)
|
2197
|
+
return
|
2198
|
+
|
2199
|
+
# 单只股票的多层杜邦分解
|
2200
|
+
from siat.financials_china import dupont_decompose_china
|
2201
|
+
df_dbd=dupont_decompose_china(ticker=tickers,fsdate=fsdates,gview=gview,facecolor=facecolor)
|
2202
|
+
return
|
2203
|
+
|
2204
|
+
else:
|
2205
|
+
print(" #Warning(fs_analysis_china): sorry, no idea on what to do for",analysis_type)
|
2206
|
+
|
2207
|
+
return
|
2208
|
+
|
2209
|
+
|
2210
|
+
#==============================================================================
|
2211
|
+
#==============================================================================
|
2212
|
+
#==============================================================================
|