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,1160 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""
|
3
|
+
本模块功能:上市公司的财务报表分析,数据层
|
4
|
+
所属工具包:证券投资分析工具SIAT
|
5
|
+
SIAT:Security Investment Analysis Tool
|
6
|
+
创建日期:2020年9月1日
|
7
|
+
最新修订日期:2020年9月8日
|
8
|
+
作者:王德宏 (WANG Dehong, Peter)
|
9
|
+
作者单位:北京外国语大学国际商学院
|
10
|
+
版权所有:王德宏
|
11
|
+
用途限制:仅限研究与教学使用,不可商用!商用需要额外授权。
|
12
|
+
特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
|
13
|
+
|
14
|
+
注释:容易出现无规律的抓取失败,需要多次重复才能成功。
|
15
|
+
本部分功能作为备胎使用,当yfinance和yahooquery的财务报表功能失效时。
|
16
|
+
"""
|
17
|
+
|
18
|
+
#==============================================================================
|
19
|
+
#关闭所有警告
|
20
|
+
import warnings; warnings.filterwarnings('ignore')
|
21
|
+
from siat.common import *
|
22
|
+
from siat.translate import *
|
23
|
+
from siat.security_prices import *
|
24
|
+
from siat.security_price2 import *
|
25
|
+
#==============================================================================
|
26
|
+
#本模块直接使用爬虫抓取雅虎财经
|
27
|
+
#==============================================================================
|
28
|
+
class YahooFin():
|
29
|
+
|
30
|
+
BASE_URL = 'https://query1.finance.yahoo.com/v10/finance/quoteSummary/'
|
31
|
+
|
32
|
+
def __init__(self, ticker):
|
33
|
+
"""Initiates the ticker
|
34
|
+
Args: ticker (str): Stock-ticker Ex. 'AAPL'
|
35
|
+
"""
|
36
|
+
self.ticker = ticker
|
37
|
+
|
38
|
+
def make_request(self, url):
|
39
|
+
"""Makes a GET request"""
|
40
|
+
import requests
|
41
|
+
headers = {
|
42
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
43
|
+
}
|
44
|
+
return requests.get(url,headers=headers)
|
45
|
+
|
46
|
+
def get_data(self):
|
47
|
+
"""Returns a json object from a GET request"""
|
48
|
+
try:
|
49
|
+
return self.make_request(self.url).json()
|
50
|
+
except KeyError as e:
|
51
|
+
print("#Error(get_data):",e)
|
52
|
+
|
53
|
+
def data(self):
|
54
|
+
"""Returns query result from json object"""
|
55
|
+
data_temp = self.get_data()
|
56
|
+
try:
|
57
|
+
return data_temp.get('quoteSummary').get("result")
|
58
|
+
except KeyError as e:
|
59
|
+
print("Something went wrong:",e)
|
60
|
+
|
61
|
+
def convert_timestamp(self, raw):
|
62
|
+
"""Converts UNIX-timestamp to YYYY-MM-DD"""
|
63
|
+
from datetime import datetime
|
64
|
+
return datetime.utcfromtimestamp(raw).strftime('%Y-%m-%d')
|
65
|
+
|
66
|
+
def extract_raw(func):
|
67
|
+
"""Decorator to remove keys from from json data
|
68
|
+
that is retreived from the yahoo-module
|
69
|
+
"""
|
70
|
+
def wrapper_extract_raw(self, *args, **kwargs):
|
71
|
+
sheet = func(self)
|
72
|
+
for items in sheet:
|
73
|
+
for key, value in items.items():
|
74
|
+
if type(value) == dict and 'fmt' in value:
|
75
|
+
del value['fmt']
|
76
|
+
if type(value) == dict and 'longFmt' in value:
|
77
|
+
del value['longFmt']
|
78
|
+
return sheet
|
79
|
+
return wrapper_extract_raw
|
80
|
+
|
81
|
+
def create_dict(self):
|
82
|
+
"""Creates a dict from extracted data"""
|
83
|
+
balance_sheet = []
|
84
|
+
temp_data = self._dict
|
85
|
+
for d in temp_data:
|
86
|
+
temp_dict = {}
|
87
|
+
for key, value in d.items():
|
88
|
+
if type(value) == dict and 'raw' in value:
|
89
|
+
v = value['raw']
|
90
|
+
temp_dict[key] = v
|
91
|
+
balance_sheet.append(temp_dict)
|
92
|
+
return balance_sheet
|
93
|
+
|
94
|
+
|
95
|
+
def to_df(self):
|
96
|
+
"""Creates a pandas Dataframe from dict"""
|
97
|
+
import pandas as pd
|
98
|
+
self._df = pd.DataFrame.from_dict(self.create_dict())
|
99
|
+
for index, row in self._df.iterrows():
|
100
|
+
self._df.loc[index, 'endDate'] = self.convert_timestamp(self._df.at[index, 'endDate'])
|
101
|
+
self._df = self._df.iloc[::-1]
|
102
|
+
return self._df
|
103
|
+
|
104
|
+
#==============================================================================
|
105
|
+
class BalanceSheetQ(YahooFin):
|
106
|
+
|
107
|
+
def __init__(self, ticker):
|
108
|
+
super().__init__(ticker)
|
109
|
+
self._module = 'balanceSheetHistoryQuarterly'
|
110
|
+
self._url = (f'https://query1.finance.yahoo.com/v10/finance/quoteSummary/'
|
111
|
+
f'{self.ticker}?'
|
112
|
+
f'modules={self.module}')
|
113
|
+
self._dict = self._balance_sheet()
|
114
|
+
self._df = None
|
115
|
+
|
116
|
+
@property
|
117
|
+
def module(self):
|
118
|
+
return self._module
|
119
|
+
|
120
|
+
@property
|
121
|
+
def url(self):
|
122
|
+
return self._url
|
123
|
+
|
124
|
+
@property
|
125
|
+
def df(self):
|
126
|
+
return self._df
|
127
|
+
|
128
|
+
@YahooFin.extract_raw
|
129
|
+
def _balance_sheet(self):
|
130
|
+
"""Returns a balance sheet statement"""
|
131
|
+
data = self.data()
|
132
|
+
query = data[0]
|
133
|
+
balance_sheet_qty = query['balanceSheetHistoryQuarterly']
|
134
|
+
balance_sheet_statements = balance_sheet_qty['balanceSheetStatements']
|
135
|
+
return balance_sheet_statements
|
136
|
+
|
137
|
+
#==============================================================================
|
138
|
+
def get_bsQ(ticker):
|
139
|
+
"""
|
140
|
+
功能: 获取最近4个季度资产负债表
|
141
|
+
注意:数字单位为K
|
142
|
+
"""
|
143
|
+
try:
|
144
|
+
bsdata = BalanceSheetQ(ticker)
|
145
|
+
except:
|
146
|
+
bsdata = BalanceSheetQ(ticker)
|
147
|
+
|
148
|
+
bsdf=bsdata.to_df()
|
149
|
+
bsdf['ticker']=ticker
|
150
|
+
bsdf['date']=bsdf['endDate']
|
151
|
+
bsdf.set_index(['date'],inplace=True)
|
152
|
+
return bsdf
|
153
|
+
|
154
|
+
if __name__ == '__main__':
|
155
|
+
ticker='AAPL'
|
156
|
+
bsq = get_bsQ(ticker)
|
157
|
+
|
158
|
+
#==============================================================================
|
159
|
+
class BalanceSheetA(YahooFin):
|
160
|
+
|
161
|
+
def __init__(self, ticker):
|
162
|
+
super().__init__(ticker)
|
163
|
+
self._module = 'balanceSheetHistory'
|
164
|
+
self._url = (f'https://query1.finance.yahoo.com/v10/finance/quoteSummary/'
|
165
|
+
f'{self.ticker}?'
|
166
|
+
f'modules={self.module}')
|
167
|
+
self._dict = self._balance_sheet()
|
168
|
+
self._df = None
|
169
|
+
|
170
|
+
@property
|
171
|
+
def module(self):
|
172
|
+
return self._module
|
173
|
+
|
174
|
+
@property
|
175
|
+
def url(self):
|
176
|
+
return self._url
|
177
|
+
|
178
|
+
@property
|
179
|
+
def df(self):
|
180
|
+
return self._df
|
181
|
+
|
182
|
+
@YahooFin.extract_raw
|
183
|
+
def _balance_sheet(self):
|
184
|
+
"""Returns a balance sheet statement"""
|
185
|
+
data = self.data()
|
186
|
+
|
187
|
+
#print(data)
|
188
|
+
query = data[0]
|
189
|
+
balance_sheet_qty = query['balanceSheetHistory']
|
190
|
+
balance_sheet_statements = balance_sheet_qty['balanceSheetStatements']
|
191
|
+
return balance_sheet_statements
|
192
|
+
|
193
|
+
#==============================================================================
|
194
|
+
def get_bsA(ticker):
|
195
|
+
"""
|
196
|
+
功能: 获取最近4个年度资产负债表
|
197
|
+
注意:数字单位为K
|
198
|
+
"""
|
199
|
+
try:
|
200
|
+
bsdata = BalanceSheetA(ticker)
|
201
|
+
except:
|
202
|
+
bsdata = BalanceSheetA(ticker)
|
203
|
+
|
204
|
+
bsdf=bsdata.to_df()
|
205
|
+
bsdf['ticker']=ticker
|
206
|
+
bsdf['date']=bsdf['endDate']
|
207
|
+
bsdf.set_index(['date'],inplace=True)
|
208
|
+
return bsdf
|
209
|
+
|
210
|
+
if __name__ == '__main__':
|
211
|
+
ticker='AAPL'
|
212
|
+
bsa = get_bsA(ticker)
|
213
|
+
|
214
|
+
#==============================================================================
|
215
|
+
class IncomeStatementQ(YahooFin):
|
216
|
+
|
217
|
+
def __init__(self, ticker):
|
218
|
+
super().__init__(ticker)
|
219
|
+
self._module = 'incomeStatementHistoryQuarterly'
|
220
|
+
self._url = (f'https://query1.finance.yahoo.com/v10/finance/quoteSummary/'
|
221
|
+
f'{self.ticker}?'
|
222
|
+
f'modules={self.module}')
|
223
|
+
self._dict = self._income_statement()
|
224
|
+
self._df = None
|
225
|
+
|
226
|
+
@property
|
227
|
+
def module(self):
|
228
|
+
return self._module
|
229
|
+
|
230
|
+
@property
|
231
|
+
def url(self):
|
232
|
+
return self._url
|
233
|
+
|
234
|
+
@property
|
235
|
+
def df(self):
|
236
|
+
return self._df
|
237
|
+
|
238
|
+
@YahooFin.extract_raw
|
239
|
+
def _income_statement(self):
|
240
|
+
"""Returns a income statement"""
|
241
|
+
data = self.data()
|
242
|
+
query = data[0]
|
243
|
+
income_statement_qty = query['incomeStatementHistoryQuarterly']
|
244
|
+
income_statement_statements = income_statement_qty['incomeStatementHistory']
|
245
|
+
return income_statement_statements
|
246
|
+
|
247
|
+
|
248
|
+
if __name__ == '__main__':
|
249
|
+
isdata = IncomeStatementQ('AAPL')
|
250
|
+
isdf=isdata.to_df()
|
251
|
+
print(isdf)
|
252
|
+
|
253
|
+
#==============================================================================
|
254
|
+
def get_isQ(ticker):
|
255
|
+
"""
|
256
|
+
功能: 获取最近4个季度利润表
|
257
|
+
注意:数字单位为K
|
258
|
+
"""
|
259
|
+
try:
|
260
|
+
isdata = IncomeStatementQ(ticker)
|
261
|
+
except:
|
262
|
+
isdata = IncomeStatementQ(ticker)
|
263
|
+
|
264
|
+
isdf=isdata.to_df()
|
265
|
+
|
266
|
+
isdf['ticker']=ticker
|
267
|
+
isdf['date']=isdf['endDate']
|
268
|
+
isdf.set_index(['date'],inplace=True)
|
269
|
+
return isdf
|
270
|
+
|
271
|
+
if __name__ == '__main__':
|
272
|
+
ticker='AAPL'
|
273
|
+
isq = getQ(ticker)
|
274
|
+
|
275
|
+
#==============================================================================
|
276
|
+
class IncomeStatementA(YahooFin):
|
277
|
+
|
278
|
+
def __init__(self, ticker):
|
279
|
+
super().__init__(ticker)
|
280
|
+
self._module = 'incomeStatementHistory'
|
281
|
+
self._url = (f'https://query1.finance.yahoo.com/v10/finance/quoteSummary/'
|
282
|
+
f'{self.ticker}?'
|
283
|
+
f'modules={self.module}')
|
284
|
+
self._dict = self._income_statement()
|
285
|
+
self._df = None
|
286
|
+
|
287
|
+
@property
|
288
|
+
def module(self):
|
289
|
+
return self._module
|
290
|
+
|
291
|
+
@property
|
292
|
+
def url(self):
|
293
|
+
return self._url
|
294
|
+
|
295
|
+
@property
|
296
|
+
def df(self):
|
297
|
+
return self._df
|
298
|
+
|
299
|
+
@YahooFin.extract_raw
|
300
|
+
def _income_statement(self):
|
301
|
+
"""Returns a income statement"""
|
302
|
+
data = self.data()
|
303
|
+
#print(data)
|
304
|
+
query = data[0]
|
305
|
+
income_statement_qty = query['incomeStatementHistory']
|
306
|
+
income_statement_statements = income_statement_qty['incomeStatementHistory']
|
307
|
+
return income_statement_statements
|
308
|
+
|
309
|
+
|
310
|
+
if __name__ == '__main__':
|
311
|
+
isdata = IncomeStatementA('AAPL')
|
312
|
+
isdf=isdata.to_df()
|
313
|
+
print(isdf)
|
314
|
+
|
315
|
+
#==============================================================================
|
316
|
+
def get_isA(ticker):
|
317
|
+
"""
|
318
|
+
功能: 获取最近4个年度利润表
|
319
|
+
注意:数字单位为K
|
320
|
+
"""
|
321
|
+
try:
|
322
|
+
isdata = IncomeStatementA(ticker)
|
323
|
+
except:
|
324
|
+
isdata = IncomeStatementA(ticker)
|
325
|
+
|
326
|
+
isdf=isdata.to_df()
|
327
|
+
|
328
|
+
isdf['ticker']=ticker
|
329
|
+
isdf['date']=isdf['endDate']
|
330
|
+
isdf.set_index(['date'],inplace=True)
|
331
|
+
return isdf
|
332
|
+
|
333
|
+
if __name__ == '__main__':
|
334
|
+
ticker='AAPL'
|
335
|
+
isa = get_isA(ticker)
|
336
|
+
|
337
|
+
#==============================================================================
|
338
|
+
class CashFlowQ(YahooFin):
|
339
|
+
|
340
|
+
def __init__(self, ticker):
|
341
|
+
super().__init__(ticker)
|
342
|
+
self._module = 'cashflowStatementHistoryQuarterly'
|
343
|
+
self._url = (f'https://query1.finance.yahoo.com/v10/finance/quoteSummary/'
|
344
|
+
f'{self.ticker}?'
|
345
|
+
f'modules={self.module}')
|
346
|
+
self._dict = self._cash_flow()
|
347
|
+
self._df = None
|
348
|
+
|
349
|
+
@property
|
350
|
+
def module(self):
|
351
|
+
return self._module
|
352
|
+
|
353
|
+
@property
|
354
|
+
def url(self):
|
355
|
+
return self._url
|
356
|
+
|
357
|
+
@property
|
358
|
+
def df(self):
|
359
|
+
return self._df
|
360
|
+
|
361
|
+
@YahooFin.extract_raw
|
362
|
+
def _cash_flow(self):
|
363
|
+
"""Returns a cash flow statement"""
|
364
|
+
data = self.data()
|
365
|
+
query = data[0]
|
366
|
+
#print(data)
|
367
|
+
cash_flow_qty = query['cashflowStatementHistoryQuarterly']
|
368
|
+
#print(cash_flow_qty)
|
369
|
+
cash_flow_statements = cash_flow_qty['cashflowStatements']
|
370
|
+
return cash_flow_statements
|
371
|
+
|
372
|
+
|
373
|
+
if __name__ == '__main__':
|
374
|
+
cfdata = CashFlowQ('AAPL')
|
375
|
+
cfdf=cfdata.to_df()
|
376
|
+
print(cfdf)
|
377
|
+
|
378
|
+
#==============================================================================
|
379
|
+
def get_cfQ(ticker):
|
380
|
+
"""
|
381
|
+
功能: 获取最近4个季度现金流量表
|
382
|
+
注意:数字单位为K
|
383
|
+
"""
|
384
|
+
try:
|
385
|
+
cfdata = CashFlowQ(ticker)
|
386
|
+
except:
|
387
|
+
cfdata = CashFlowQ(ticker)
|
388
|
+
|
389
|
+
cfdf=cfdata.to_df()
|
390
|
+
cfdf['ticker']=ticker
|
391
|
+
cfdf['date']=cfdf['endDate']
|
392
|
+
cfdf.set_index(['date'],inplace=True)
|
393
|
+
return cfdf
|
394
|
+
|
395
|
+
if __name__ == '__main__':
|
396
|
+
ticker='AAPL'
|
397
|
+
cfq = get_cfQ(ticker)
|
398
|
+
|
399
|
+
|
400
|
+
#==============================================================================
|
401
|
+
class CashFlowA(YahooFin):
|
402
|
+
|
403
|
+
def __init__(self, ticker):
|
404
|
+
super().__init__(ticker)
|
405
|
+
self._module = 'cashflowStatementHistory'
|
406
|
+
self._url = (f'https://query1.finance.yahoo.com/v10/finance/quoteSummary/'
|
407
|
+
f'{self.ticker}?'
|
408
|
+
f'modules={self.module}')
|
409
|
+
self._dict = self._cash_flow()
|
410
|
+
self._df = None
|
411
|
+
|
412
|
+
@property
|
413
|
+
def module(self):
|
414
|
+
return self._module
|
415
|
+
|
416
|
+
@property
|
417
|
+
def url(self):
|
418
|
+
return self._url
|
419
|
+
|
420
|
+
@property
|
421
|
+
def df(self):
|
422
|
+
return self._df
|
423
|
+
|
424
|
+
@YahooFin.extract_raw
|
425
|
+
def _cash_flow(self):
|
426
|
+
"""Returns a cash flow statement"""
|
427
|
+
data=self.data()
|
428
|
+
#print(data)
|
429
|
+
#print(data)
|
430
|
+
query=data[0]
|
431
|
+
#print(query)
|
432
|
+
|
433
|
+
cash_flow_qty = query['cashflowStatementHistory']
|
434
|
+
#print(cash_flow_qty)
|
435
|
+
|
436
|
+
cash_flow_statements = cash_flow_qty['cashflowStatements']
|
437
|
+
#print(cash_flow_qty)
|
438
|
+
|
439
|
+
return cash_flow_statements
|
440
|
+
|
441
|
+
|
442
|
+
if __name__ == '__main__':
|
443
|
+
cfdata = CashFlowA('AAPL')
|
444
|
+
cfdf=cfdata.to_df()
|
445
|
+
print(cfdf)
|
446
|
+
|
447
|
+
|
448
|
+
#==============================================================================
|
449
|
+
def get_cfA(ticker):
|
450
|
+
"""
|
451
|
+
功能: 获取最近4个年度现金流量表
|
452
|
+
注意:数字单位为K
|
453
|
+
"""
|
454
|
+
try:
|
455
|
+
cfdata = CashFlowA(ticker)
|
456
|
+
except:
|
457
|
+
try:
|
458
|
+
cfdata = CashFlowA(ticker)
|
459
|
+
except:
|
460
|
+
cfdata = CashFlowA(ticker)
|
461
|
+
|
462
|
+
cfdf=cfdata.to_df()
|
463
|
+
cfdf['ticker']=ticker
|
464
|
+
cfdf['date']=cfdf['endDate']
|
465
|
+
cfdf.set_index(['date'],inplace=True)
|
466
|
+
return cfdf
|
467
|
+
|
468
|
+
if __name__ == '__main__':
|
469
|
+
ticker='AAPL'
|
470
|
+
cfa = get_cfA(ticker)
|
471
|
+
|
472
|
+
#==============================================================================
|
473
|
+
def get_balance_sheet(ticker):
|
474
|
+
"""
|
475
|
+
功能:获取雅虎财经上一只股票所有的年度和季度资产负债表
|
476
|
+
"""
|
477
|
+
#获取年报
|
478
|
+
try:
|
479
|
+
fsa = get_bsA(ticker)
|
480
|
+
except:
|
481
|
+
print("#Error(get_balance_sheet): no annual info available for",ticker)
|
482
|
+
return None
|
483
|
+
fsa['reportType']="Annual"
|
484
|
+
colsa=list(fsa)
|
485
|
+
|
486
|
+
#获取季度报
|
487
|
+
try:
|
488
|
+
fsq = get_bsQ(ticker)
|
489
|
+
except:
|
490
|
+
print("#Error(get_balance_sheet): no quarterly info available for",ticker)
|
491
|
+
return None
|
492
|
+
fsq['reportType']="Quarterly"
|
493
|
+
colsq=list(fsq)
|
494
|
+
|
495
|
+
#两个列表中的共同部分
|
496
|
+
cols= [x for x in colsa if x in colsq] #两个列表中都存在
|
497
|
+
colsdiff=[y for y in (colsa + colsq) if y not in cols] #两个列表中的不同元素
|
498
|
+
|
499
|
+
#合并年度和季度报表
|
500
|
+
import pandas as pd
|
501
|
+
fs=pd.concat([fsa[cols],fsq[cols]])
|
502
|
+
#排序
|
503
|
+
fs.sort_values(by=['endDate','reportType'],inplace=True)
|
504
|
+
#去掉重复记录
|
505
|
+
fs.drop_duplicates(subset=['endDate'],keep='first',inplace=True)
|
506
|
+
|
507
|
+
return fs
|
508
|
+
|
509
|
+
if __name__ == '__main__':
|
510
|
+
ticker='AAPL'
|
511
|
+
fs=get_balance_sheet('AAPL')
|
512
|
+
fs_aapl=get_balance_sheet('AAPL')
|
513
|
+
fs_msft=get_balance_sheet('MSFT')
|
514
|
+
fs_c=get_balance_sheet('C')
|
515
|
+
|
516
|
+
#==============================================================================
|
517
|
+
def get_income_statements(ticker):
|
518
|
+
"""
|
519
|
+
功能:获取雅虎财经上一只股票所有的年度和季度利润表
|
520
|
+
"""
|
521
|
+
#获取年报
|
522
|
+
try:
|
523
|
+
fsa = get_isA(ticker)
|
524
|
+
except:
|
525
|
+
print("#Error(get_income_statements): no annual info available for",ticker)
|
526
|
+
return None
|
527
|
+
fsa['reportType']="Annual"
|
528
|
+
colsa=list(fsa)
|
529
|
+
|
530
|
+
#获取季度报
|
531
|
+
try:
|
532
|
+
fsq = get_isQ(ticker)
|
533
|
+
except:
|
534
|
+
print("#Error(get_income_statements): no quarterly info available for",ticker)
|
535
|
+
return None
|
536
|
+
fsq['reportType']="Quarterly"
|
537
|
+
colsq=list(fsq)
|
538
|
+
|
539
|
+
#两个列表中的共同部分
|
540
|
+
cols= [x for x in colsa if x in colsq] #两个列表中都存在
|
541
|
+
colsdiff=[y for y in (colsa + colsq) if y not in cols] #两个列表中的不同元素
|
542
|
+
|
543
|
+
#合并年度和季度报表
|
544
|
+
import pandas as pd
|
545
|
+
fs=pd.concat([fsa[cols],fsq[cols]])
|
546
|
+
#排序
|
547
|
+
fs.sort_values(by=['endDate','reportType'],inplace=True)
|
548
|
+
#去掉重复记录
|
549
|
+
fs.drop_duplicates(subset=['endDate'],keep='first',inplace=True)
|
550
|
+
|
551
|
+
return fs
|
552
|
+
|
553
|
+
if __name__ == '__main__':
|
554
|
+
ticker='AAPL'
|
555
|
+
fs=get_income_statements('AAPL')
|
556
|
+
fs_aapl=get_income_statements('AAPL')
|
557
|
+
fs_msft=get_income_statements('MSFT')
|
558
|
+
fs_c=get_income_statements('C')
|
559
|
+
|
560
|
+
#==============================================================================
|
561
|
+
def get_cashflow_statements(ticker):
|
562
|
+
"""
|
563
|
+
功能:获取雅虎财经上一只股票所有的年度和季度现金流量表
|
564
|
+
"""
|
565
|
+
#获取年报
|
566
|
+
try:
|
567
|
+
fsa = get_cfA(ticker)
|
568
|
+
except:
|
569
|
+
print("#Error(get_cashflow_statements): no annual info available for",ticker)
|
570
|
+
return None
|
571
|
+
fsa['reportType']="Annual"
|
572
|
+
colsa=list(fsa)
|
573
|
+
|
574
|
+
#获取季度报
|
575
|
+
try:
|
576
|
+
fsq = get_cfQ(ticker)
|
577
|
+
except:
|
578
|
+
print("#Error(get_cashflow_statements): no quarterly info available for",ticker)
|
579
|
+
return None
|
580
|
+
fsq['reportType']="Quarterly"
|
581
|
+
colsq=list(fsq)
|
582
|
+
|
583
|
+
#两个列表中的共同部分
|
584
|
+
cols= [x for x in colsa if x in colsq] #两个列表中都存在
|
585
|
+
colsdiff=[y for y in (colsa + colsq) if y not in cols] #两个列表中的不同元素
|
586
|
+
|
587
|
+
#合并年度和季度报表
|
588
|
+
import pandas as pd
|
589
|
+
fs=pd.concat([fsa[cols],fsq[cols]])
|
590
|
+
#排序
|
591
|
+
fs.sort_values(by=['endDate','reportType'],inplace=True)
|
592
|
+
#去掉重复记录
|
593
|
+
fs.drop_duplicates(subset=['endDate'],keep='first',inplace=True)
|
594
|
+
|
595
|
+
return fs
|
596
|
+
|
597
|
+
if __name__ == '__main__':
|
598
|
+
ticker='AAPL'
|
599
|
+
fs=get_cashflow_statements('AAPL')
|
600
|
+
fs_aapl=get_cashflow_statements('AAPL')
|
601
|
+
fs_msft=get_cashflow_statements('MSFT')
|
602
|
+
fs_c=get_cashflow_statements('C')
|
603
|
+
|
604
|
+
#==============================================================================
|
605
|
+
def get_financial_statements(ticker):
|
606
|
+
"""
|
607
|
+
功能:获取雅虎财经上一只股票所有的年度和季度财务报表
|
608
|
+
"""
|
609
|
+
print("...Searching for financial info of",ticker,"\b, please wait...")
|
610
|
+
#获取资产负债表
|
611
|
+
try:
|
612
|
+
fbs = get_balance_sheet(ticker)
|
613
|
+
except:
|
614
|
+
import time; time.sleep(3)
|
615
|
+
try:
|
616
|
+
fbs = get_balance_sheet(ticker)
|
617
|
+
except:
|
618
|
+
import time; time.sleep(5)
|
619
|
+
try:
|
620
|
+
fbs = get_balance_sheet(ticker)
|
621
|
+
except:
|
622
|
+
print("#Error(get_financial_statements): balance sheet info not available for",ticker)
|
623
|
+
return None
|
624
|
+
if fbs is None:
|
625
|
+
print("#Error(get_financial_statements): balance sheet info not available for",ticker)
|
626
|
+
return None
|
627
|
+
|
628
|
+
#获取利润表
|
629
|
+
try:
|
630
|
+
fis = get_income_statements(ticker)
|
631
|
+
except:
|
632
|
+
import time; time.sleep(3)
|
633
|
+
try:
|
634
|
+
fis = get_income_statements(ticker)
|
635
|
+
except:
|
636
|
+
import time; time.sleep(5)
|
637
|
+
try:
|
638
|
+
fis = get_income_statements(ticker)
|
639
|
+
except:
|
640
|
+
print("#Error(get_financial_statements): income info not available for",ticker)
|
641
|
+
return None
|
642
|
+
if fis is None:
|
643
|
+
print("#Error(get_financial_statements): income info not available for",ticker)
|
644
|
+
return None
|
645
|
+
|
646
|
+
#获取现金流量表
|
647
|
+
try:
|
648
|
+
fcf = get_cashflow_statements(ticker)
|
649
|
+
except:
|
650
|
+
import time; time.sleep(3)
|
651
|
+
try:
|
652
|
+
fcf = get_cashflow_statements(ticker)
|
653
|
+
except:
|
654
|
+
import time; time.sleep(5)
|
655
|
+
try:
|
656
|
+
fcf = get_cashflow_statements(ticker)
|
657
|
+
except:
|
658
|
+
print("#Error(get_financial_statements): cash flow info not available for",ticker)
|
659
|
+
return None
|
660
|
+
if fcf is None:
|
661
|
+
print("#Error(get_financial_statements): cash flow info not available for",ticker)
|
662
|
+
return None
|
663
|
+
|
664
|
+
#合并1:资产负债表+利润表
|
665
|
+
cols= [x for x in fis if x not in fbs] #不在第2个列表中在第1个列表
|
666
|
+
import pandas as pd
|
667
|
+
fbs_fis=pd.merge(fbs,fis[cols+['endDate']],on='endDate')
|
668
|
+
#合并2:+现金流量表
|
669
|
+
cols= [x for x in fcf if x not in fbs_fis] #不在第1个列表中只在第2个列表
|
670
|
+
fbs_fis_fcf=pd.merge(fbs_fis,fcf[cols+['endDate']],on='endDate')
|
671
|
+
|
672
|
+
#建立索引
|
673
|
+
fbs_fis_fcf['date']=fbs_fis_fcf['endDate']
|
674
|
+
bic=fbs_fis_fcf.set_index('date')
|
675
|
+
|
676
|
+
#某些金融企业缺乏一些字段,特殊处理:
|
677
|
+
cols=list(bic)
|
678
|
+
cols_special=['inventory','totalCashFromOperatingActivities','interestExpense','dividendsPaid']
|
679
|
+
for e in cols_special:
|
680
|
+
if not (e in cols):
|
681
|
+
bic[e]=0
|
682
|
+
|
683
|
+
return bic
|
684
|
+
|
685
|
+
if __name__ == '__main__':
|
686
|
+
ticker='AAPL'
|
687
|
+
fs=get_financial_statements('AAPL')
|
688
|
+
fs_aapl=get_financial_statements('AAPL')
|
689
|
+
fs_msft=get_financial_statements('MSFT')
|
690
|
+
fs_c=get_financial_statements('C')
|
691
|
+
|
692
|
+
"""
|
693
|
+
最终获得的bic表结构:
|
694
|
+
['cash',
|
695
|
+
'shortTermInvestments',
|
696
|
+
'netReceivables',
|
697
|
+
'inventory',
|
698
|
+
'otherCurrentAssets',
|
699
|
+
'totalCurrentAssets',
|
700
|
+
'longTermInvestments',
|
701
|
+
'propertyPlantEquipment',
|
702
|
+
'otherAssets',
|
703
|
+
'totalAssets',
|
704
|
+
'accountsPayable',
|
705
|
+
'shortLongTermDebt',
|
706
|
+
'otherCurrentLiab',
|
707
|
+
'longTermDebt',
|
708
|
+
'otherLiab',
|
709
|
+
'totalCurrentLiabilities',
|
710
|
+
'totalLiab',
|
711
|
+
'commonStock',
|
712
|
+
'retainedEarnings',
|
713
|
+
'treasuryStock',
|
714
|
+
'otherStockholderEquity',
|
715
|
+
'totalStockholderEquity',
|
716
|
+
'netTangibleAssets',
|
717
|
+
|
718
|
+
'ticker',
|
719
|
+
'reportType',
|
720
|
+
|
721
|
+
'totalRevenue',
|
722
|
+
'costOfRevenue',
|
723
|
+
'grossProfit',
|
724
|
+
'researchDevelopment',
|
725
|
+
'sellingGeneralAdministrative',
|
726
|
+
'totalOperatingExpenses',
|
727
|
+
'operatingIncome',
|
728
|
+
'totalOtherIncomeExpenseNet',
|
729
|
+
'ebit',
|
730
|
+
'interestExpense',
|
731
|
+
'incomeBeforeTax',
|
732
|
+
'incomeTaxExpense',
|
733
|
+
'netIncomeFromContinuingOps',
|
734
|
+
'netIncome',
|
735
|
+
'netIncomeApplicableToCommonShares',
|
736
|
+
|
737
|
+
'depreciation',
|
738
|
+
'changeToNetincome',
|
739
|
+
'changeToAccountReceivables',
|
740
|
+
'changeToLiabilities',
|
741
|
+
'changeToInventory',
|
742
|
+
'changeToOperatingActivities',
|
743
|
+
'totalCashFromOperatingActivities',
|
744
|
+
'capitalExpenditures',
|
745
|
+
'investments',
|
746
|
+
'otherCashflowsFromInvestingActivities',
|
747
|
+
'totalCashflowsFromInvestingActivities',
|
748
|
+
'dividendsPaid',
|
749
|
+
'netBorrowings',
|
750
|
+
'otherCashflowsFromFinancingActivities',
|
751
|
+
'totalCashFromFinancingActivities',
|
752
|
+
'changeInCash',
|
753
|
+
|
754
|
+
'repurchaseOfStock',
|
755
|
+
'issuanceOfStock']
|
756
|
+
"""
|
757
|
+
|
758
|
+
#==============================================================================
|
759
|
+
def get_EPS(fsdf):
|
760
|
+
"""
|
761
|
+
功能:抓取股票的EPS,并计算流通股数
|
762
|
+
"""
|
763
|
+
ticker=list(fsdf['ticker'])[0]
|
764
|
+
print("...Searching for EPS info of",ticker,"\b, please wait...")
|
765
|
+
|
766
|
+
#局限:目前取不到非美股的EPS信息!
|
767
|
+
from yahoo_earnings_calendar import YahooEarningsCalendar
|
768
|
+
# 实例化装饰器
|
769
|
+
yec = YahooEarningsCalendar()
|
770
|
+
earnings = yec.get_earnings_of(ticker)
|
771
|
+
|
772
|
+
import pandas as pd
|
773
|
+
earnings_df = pd.DataFrame.from_records(earnings)
|
774
|
+
if (earnings_df is None) or (len(earnings_df)==0):
|
775
|
+
print("#Error(get_EPS): no EPS info available for",ticker)
|
776
|
+
return False,fsdf
|
777
|
+
|
778
|
+
earnings_df['datedt']=pd.to_datetime(earnings_df.startdatetime)
|
779
|
+
datecvt=lambda x: str(x)[0:10]
|
780
|
+
earnings_df['publish_date']=earnings_df['datedt'].apply(datecvt)
|
781
|
+
eps=earnings_df[['ticker','epsactual','publish_date']]
|
782
|
+
eps.dropna(inplace=True)
|
783
|
+
if (eps is None) or (len(eps)==0):
|
784
|
+
print("#Error(get_EPS): no EPS info available for",ticker)
|
785
|
+
return False,fsdf
|
786
|
+
|
787
|
+
eps.drop_duplicates(['publish_date'],keep='first',inplace=True)
|
788
|
+
eps.sort_values('publish_date',inplace=True)
|
789
|
+
|
790
|
+
epsdf=pd.DataFrame(columns=('endDate','publishDate','EPS'))
|
791
|
+
|
792
|
+
edatelist=list(fsdf['endDate'])
|
793
|
+
for d in edatelist:
|
794
|
+
eps_sub=eps[eps['publish_date']>d]
|
795
|
+
pdate=list(eps_sub['publish_date'])[0]
|
796
|
+
epsactual=list(eps_sub['epsactual'])[0]
|
797
|
+
|
798
|
+
#记录股价
|
799
|
+
row=pd.Series({'endDate':d,'publishDate':pdate,'EPS':epsactual})
|
800
|
+
try:
|
801
|
+
epsdf=epsdf.append(row,ignore_index=True)
|
802
|
+
except:
|
803
|
+
epsdf=epsdf._append(row,ignore_index=True)
|
804
|
+
|
805
|
+
fsdf1=pd.merge(fsdf,epsdf,on='endDate')
|
806
|
+
fsdf1['outstandingStock']=fsdf1['netIncomeApplicableToCommonShares']/fsdf1['EPS']
|
807
|
+
|
808
|
+
return True,fsdf1
|
809
|
+
|
810
|
+
if __name__ == '__main__':
|
811
|
+
fsdf=get_financial_statements('AAPL')
|
812
|
+
result,fsdf1=get_EPS(fsdf)
|
813
|
+
fsdf=get_financial_statements('0700.HK')
|
814
|
+
result,fsdf1=get_EPS(fsdf)
|
815
|
+
|
816
|
+
#==============================================================================
|
817
|
+
def get_PE(fsdf):
|
818
|
+
"""
|
819
|
+
功能:计算PE
|
820
|
+
"""
|
821
|
+
#获得各个报表的日期范围,适当扩大以规避非交易日
|
822
|
+
start=min(list(fsdf['endDate']))
|
823
|
+
fromdate=date_adjust(start,adjust=-30)
|
824
|
+
end=max(list(fsdf['endDate']))
|
825
|
+
todate=date_adjust(end,adjust=30)
|
826
|
+
|
827
|
+
#获取股价
|
828
|
+
ticker=list(fsdf['ticker'])[0]
|
829
|
+
prices=get_price(ticker, fromdate, todate)
|
830
|
+
prices['datedt']=prices.index.date
|
831
|
+
datecvt=lambda x: str(x)[0:10]
|
832
|
+
prices['Date']=prices['datedt'].apply(datecvt)
|
833
|
+
|
834
|
+
#报表日期列表
|
835
|
+
datelist_fs=list(fsdf['endDate'])
|
836
|
+
#价格日期列表
|
837
|
+
datelist_price=list(prices['Date'])
|
838
|
+
date_price_min=min(datelist_price)
|
839
|
+
date_price_max=max(datelist_price)
|
840
|
+
|
841
|
+
#股价列表
|
842
|
+
pricelist=list(prices['Close'])
|
843
|
+
|
844
|
+
import pandas as pd
|
845
|
+
pricedf=pd.DataFrame(columns=('endDate','actualDate','Price'))
|
846
|
+
for d in datelist_fs:
|
847
|
+
found=False
|
848
|
+
d1=d
|
849
|
+
if d in datelist_price:
|
850
|
+
found=True
|
851
|
+
pos=datelist_price.index(d)
|
852
|
+
p=pricelist[pos]
|
853
|
+
else:
|
854
|
+
while (d1 >= date_price_min) and not found:
|
855
|
+
d1=date_adjust(d1,adjust=-1)
|
856
|
+
if d1 in datelist_price:
|
857
|
+
found=True
|
858
|
+
pos=datelist_price.index(d1)
|
859
|
+
p=pricelist[pos]
|
860
|
+
while (d1 <= date_price_max) and not found:
|
861
|
+
d1=date_adjust(d1,adjust=1)
|
862
|
+
if d1 in datelist_price:
|
863
|
+
found=True
|
864
|
+
pos=datelist_price.index(d1)
|
865
|
+
p=pricelist[pos]
|
866
|
+
#记录股价
|
867
|
+
row=pd.Series({'endDate':d,'actualDate':d1,'Price':p})
|
868
|
+
try:
|
869
|
+
pricedf=pricedf.append(row,ignore_index=True)
|
870
|
+
except:
|
871
|
+
pricedf=pricedf._append(row,ignore_index=True)
|
872
|
+
|
873
|
+
#合成表
|
874
|
+
fsdf1=pd.merge(fsdf,pricedf,on='endDate')
|
875
|
+
fsdf1['PE']=fsdf1['Price']/fsdf1['EPS']
|
876
|
+
|
877
|
+
return fsdf1
|
878
|
+
|
879
|
+
if __name__ == '__main__':
|
880
|
+
fs=get_financial_statements('AAPL')
|
881
|
+
fsdf=get_EPS(fs)
|
882
|
+
fsdf1=get_PE(fsdf)
|
883
|
+
|
884
|
+
#==============================================================================
|
885
|
+
def calcFinRates(fsdf):
|
886
|
+
"""
|
887
|
+
功能:基于财报计算各种指标
|
888
|
+
"""
|
889
|
+
#前后填充缺失值
|
890
|
+
fs = fsdf.fillna(method='ffill').fillna(method='bfill')
|
891
|
+
|
892
|
+
#短期偿债能力指标
|
893
|
+
#流动比率:流动资产 / 流动负债
|
894
|
+
fs['Current Ratio']=fs['totalCurrentAssets']/fs['totalCurrentLiabilities']
|
895
|
+
fs['Current Ratio']=round(fs['Current Ratio'],2)
|
896
|
+
#速动比率:(流动资产-存货) / 流动负债
|
897
|
+
fs['Quick Ratio']=(fs['totalCurrentAssets']-fs['inventory'])/fs['totalCurrentLiabilities']
|
898
|
+
fs['Quick Ratio']=round(fs['Quick Ratio'],2)
|
899
|
+
#现金比率: (现金+现金等价物) / 流动负债
|
900
|
+
fs['Cash Ratio']=fs['cash']/fs['totalCurrentLiabilities']
|
901
|
+
fs['Cash Ratio']=round(fs['Cash Ratio'],2)
|
902
|
+
#现金流量比率:经营活动现金流量 / 流动负债
|
903
|
+
fs['Cash Flow Ratio']=fs['totalCashFromOperatingActivities']/fs['totalCurrentLiabilities']
|
904
|
+
fs['Cash Flow Ratio']=round(fs['Cash Flow Ratio'],2)
|
905
|
+
#到期债务本息偿付比率:经营活动现金净流量 / (本期到期债务本金+现金利息支出)
|
906
|
+
fs['Debt Service Ratio']=fs['totalCashFromOperatingActivities']/(fs['shortLongTermDebt']+fs['interestExpense'])
|
907
|
+
fs['Debt Service Ratio']=round(fs['Debt Service Ratio'],2)
|
908
|
+
|
909
|
+
#长期偿债能力指标
|
910
|
+
#资产负债率:负债总额 / 资产总额
|
911
|
+
fs['Debt to Asset Ratio']=fs['totalLiab']/fs['totalAssets']
|
912
|
+
fs['Debt to Asset Ratio']=round(fs['Debt to Asset Ratio'],2)
|
913
|
+
#股东权益比率:股东权益总额 / 资产总额
|
914
|
+
fs['Equity to Asset Ratio']=fs['totalStockholderEquity']/fs['totalAssets']
|
915
|
+
fs['Equity to Asset Ratio']=round(fs['Equity to Asset Ratio'],2)
|
916
|
+
#权益乘数:资产总额 / 股东权益总额
|
917
|
+
fs['Equity Multiplier']=fs['totalAssets']/fs['totalStockholderEquity']
|
918
|
+
fs['Equity Multiplier']=round(fs['Equity Multiplier'],2)
|
919
|
+
#负债股权比率:负债总额 / 股东权益总额
|
920
|
+
fs['Debt to Equity Ratio']=fs['totalLiab']/fs['totalStockholderEquity']
|
921
|
+
fs['Debt to Equity Ratio']=round(fs['Debt to Equity Ratio'],2)
|
922
|
+
#有形净值债务率:负债总额 / (股东权益-无形资产净额)
|
923
|
+
fs['netIntangibleAssets']=fs['totalAssets']-fs['netTangibleAssets']
|
924
|
+
fs['Debt to Tangible Net Asset Ratio']=fs['totalAssets']/(fs['totalStockholderEquity']-fs['netIntangibleAssets'])
|
925
|
+
fs['Debt to Tangible Net Asset Ratio']=round(fs['Debt to Tangible Net Asset Ratio'],2)
|
926
|
+
#偿债保障比率:负债总额 / 经营活动现金净流量
|
927
|
+
fs['Debt Service Coverage Ratio']=fs['totalLiab']/fs['totalCashFromOperatingActivities']
|
928
|
+
fs['Debt Service Coverage Ratio']=round(fs['Debt Service Coverage Ratio'],2)
|
929
|
+
#利息保障倍数:(税前利润+利息费用)/ 利息费用
|
930
|
+
fs['Times Interest Earned Ratio']=fs['incomeBeforeTax']/fs['interestExpense']+1
|
931
|
+
fs['Times Interest Earned Ratio']=round(fs['Times Interest Earned Ratio'],2)
|
932
|
+
#现金利息保障倍数:(经营活动现金净流量+付现所得税) / 现金利息支出
|
933
|
+
fs['Cash Interest Coverage Ratio']=(fs['totalCashFromOperatingActivities']+fs['incomeTaxExpense'])/fs['interestExpense']
|
934
|
+
fs['Cash Interest Coverage Ratio']=round(fs['Cash Interest Coverage Ratio'],2)
|
935
|
+
|
936
|
+
#营运能力指标
|
937
|
+
#存货周转率:销售成本 / 平均存货
|
938
|
+
fs['avgInventory']=(fs['inventory']+fs['inventory'].shift(1))/2.0
|
939
|
+
fs['Inventory Turnover']=fs['costOfRevenue']/fs['avgInventory']
|
940
|
+
fs['Inventory Turnover']=round(fs['Inventory Turnover'],2)
|
941
|
+
#应收账款周转率:赊销收入净额 / 平均应收账款余额
|
942
|
+
fs['avgReceivables']=(fs['netReceivables']+fs['netReceivables'].shift(1))/2.0
|
943
|
+
fs['Receivable Turnover']=fs['totalRevenue']/fs['avgReceivables']
|
944
|
+
fs['Receivable Turnover']=round(fs['Receivable Turnover'],2)
|
945
|
+
#流动资产周转率:销售收入 / 平均流动资产余额
|
946
|
+
fs['avgCurrentAssets']=(fs['totalCurrentAssets']+fs['totalCurrentAssets'].shift(1))/2.0
|
947
|
+
fs['Current Asset Turnover']=fs['totalRevenue']/fs['avgCurrentAssets']
|
948
|
+
fs['Current Asset Turnover']=round(fs['Current Asset Turnover'],2)
|
949
|
+
#固定资产周转率:销售收入 / 平均固定资产净额
|
950
|
+
fs['avgPPE']=(fs['propertyPlantEquipment']+fs['propertyPlantEquipment'].shift(1))/2.0
|
951
|
+
fs['Fixed Asset Turnover']=fs['totalRevenue']/fs['avgPPE']
|
952
|
+
fs['Fixed Asset Turnover']=round(fs['Fixed Asset Turnover'],2)
|
953
|
+
#总资产周转率:销售收入 / 平均资产总额
|
954
|
+
fs['avgTotalAssets']=(fs['totalAssets']+fs['totalAssets'].shift(1))/2.0
|
955
|
+
fs['Total Asset Turnover']=fs['totalRevenue']/fs['avgTotalAssets']
|
956
|
+
fs['Total Asset Turnover']=round(fs['Total Asset Turnover'],2)
|
957
|
+
|
958
|
+
#主营业务利润率=主营业务利润/主营业务收入*100%
|
959
|
+
fs['Operating Profit%']=fs['operatingIncome']/fs['totalRevenue']*100.0
|
960
|
+
fs['Operating Profit%']=round(fs['Operating Profit%'],2)
|
961
|
+
|
962
|
+
#发展潜力指标
|
963
|
+
#营业收入增长率:本期营业收入增长额 / 上年同期营业收入总额
|
964
|
+
fs['Revenue Growth%']=(fs['totalRevenue']-fs['totalRevenue'].shift(1))/(fs['totalRevenue'].shift(1))*100.0
|
965
|
+
fs['Revenue Growth%']=round(fs['Revenue Growth%'],2)
|
966
|
+
#资本积累率:本期所有者权益增长额 / 年初所有者权益
|
967
|
+
fs['Capital Accumulation%']=(fs['totalStockholderEquity']-fs['totalStockholderEquity'].shift(1))/(fs['totalStockholderEquity'].shift(1))*100.0
|
968
|
+
fs['Capital Accumulation%']=round(fs['Capital Accumulation%'],2)
|
969
|
+
#总资产增长率:本期总资产增长额 / 年初资产总额
|
970
|
+
fs['Total Asset Growth%']=(fs['totalAssets']-fs['totalAssets'].shift(1))/(fs['totalAssets'].shift(1))*100.0
|
971
|
+
fs['Total Asset Growth%']=round(fs['Total Asset Growth%'],2)
|
972
|
+
#固定资产成新率:平均固定资产净值 / 平均固定资产原值。又称“固定资产净值率”或“有用系数”
|
973
|
+
#fs['avgPPE']=(fs['propertyPlantEquipment']+fs['propertyPlantEquipment'].shift(1))/2.0
|
974
|
+
fs['avgLTInvestments']=(fs['longTermInvestments']+fs['longTermInvestments'].shift(1))/2.0
|
975
|
+
fs['Fixed Asset Net Value%']=fs['avgPPE']/fs['avgLTInvestments']*100.0
|
976
|
+
fs['Fixed Asset Net Value%']=round(fs['Fixed Asset Net Value%'],2)
|
977
|
+
|
978
|
+
#其他指标
|
979
|
+
|
980
|
+
#盈利能力指标
|
981
|
+
#资产报酬率(息前税后):利润总额+利息支出 / 平均资产总额
|
982
|
+
#fs['avgTotalAssets']=(fs['totalAssets']+fs['totalAssets'].shift(1))/2.0
|
983
|
+
fs['Return on Asset']=(fs['netIncome']+fs['interestExpense'])/fs['avgTotalAssets']
|
984
|
+
fs['Return on Asset']=round(fs['Return on Asset'],2)
|
985
|
+
fs['ROA']=fs['Return on Asset']
|
986
|
+
#资本回报率(Return on Invested Capital,简称ROIC)
|
987
|
+
#ROIC=NOPLAT(息前税后经营利润)/IC(投入资本)
|
988
|
+
#NOPLAT=EBIT×(1-T)=(营业利润+财务费用-非经常性投资损益) ×(1-所得税率)
|
989
|
+
#IC=有息负债+净资产-超额现金-非经营性资产
|
990
|
+
fs['Return on Invested Capital']=(fs['netIncome']+fs['interestExpense'])/fs['avgTotalAssets']
|
991
|
+
fs['Return on Invested Capital']=round(fs['Return on Invested Capital'],2)
|
992
|
+
fs['ROIC']=fs['Return on Invested Capital']
|
993
|
+
#净资产报酬率:净利润 / 平均净资产
|
994
|
+
fs['avgTotalEquity']=(fs['totalStockholderEquity']+fs['totalStockholderEquity'].shift(1))/2.0
|
995
|
+
fs['Return on Net Asset']=fs['netIncome']/fs['avgTotalEquity']
|
996
|
+
fs['Return on Net Asset']=round(fs['Return on Net Asset'],2)
|
997
|
+
#股东权益报酬率:净利润 / 平均股东权益总额
|
998
|
+
fs['Return on Equity']=fs['netIncome']/fs['avgTotalEquity']
|
999
|
+
fs['Return on Equity']=round(fs['Return on Equity'],2)
|
1000
|
+
fs['ROE']=fs['Return on Equity']
|
1001
|
+
#毛利率:销售毛利 / 销售收入净额
|
1002
|
+
fs['Gross Profit%']=fs['grossProfit']/fs['totalRevenue']*100.0
|
1003
|
+
fs['Gross Profit%']=round(fs['Gross Profit%'],2)
|
1004
|
+
#销售净利率:净利润 / 销售收入净额
|
1005
|
+
fs['Net Profit%']=fs['netIncome']/fs['totalRevenue']*100.0
|
1006
|
+
fs['Net Profit%']=round(fs['Net Profit%'],2)
|
1007
|
+
#成本费用净利率:净利润 / 成本费用总额
|
1008
|
+
fs['Net Profit on Costs%']=fs['netIncome']/fs['costOfRevenue']*100.0
|
1009
|
+
fs['Net Profit on Costs%']=round( fs['Net Profit on Costs%'],2)
|
1010
|
+
#股利发放率:每股股利 / 每股利润
|
1011
|
+
fs['Payout Ratio%']=fs['dividendsPaid']/fs['netIncome']*100.0
|
1012
|
+
fs['Payout Ratio%']=round(fs['Payout Ratio%'],2)
|
1013
|
+
|
1014
|
+
###每股指标,受EPS可用性影响
|
1015
|
+
#每股利润:(净利润-优先股股利) / 流通在外股数。基本EPS
|
1016
|
+
#注意:流通股股数=期初commonStock-treasuryStock,加本年增加的股数issuanceOfStock*月份占比-本年减少的股数repurchaseOfStock*月份占比
|
1017
|
+
fsdf=fs.copy()
|
1018
|
+
result,fs=get_EPS(fsdf)
|
1019
|
+
if not result:
|
1020
|
+
ticker=list(fsdf['ticker'])[0]
|
1021
|
+
print("#Error(calcFinRates): EPS info unavailable for",ticker)
|
1022
|
+
print("#Side effect: per-share related rates are not calculateable, others are still useable.")
|
1023
|
+
else:
|
1024
|
+
fs['Earnings per Share']=fs['EPS']
|
1025
|
+
#每股现金流量:(经营活动现金净流量-优先股股利) / 流通在外股数
|
1026
|
+
fs['Cash Flow per Share']=fs['totalCashFromOperatingActivities']/fs['outstandingStock']
|
1027
|
+
fs['Cash Flow per Share']=round(fs['Cash Flow per Share'],2)
|
1028
|
+
fs['CFPS']=fs['Cash Flow per Share']
|
1029
|
+
#每股股利:(现金股利总额-优先股股利) /流通在外股数
|
1030
|
+
fs['Dividend per Share']=fs['dividendsPaid']/fs['outstandingStock']
|
1031
|
+
fs['Dividend per Share']=round(fs['Dividend per Share'],2)
|
1032
|
+
fs['DPS']=fs['Dividend per Share']
|
1033
|
+
#每股净资产:股东权益总额 / 流通在外股数
|
1034
|
+
fs['Net Asset per Share']=fs['totalStockholderEquity']/fs['outstandingStock']
|
1035
|
+
fs['Net Asset per Share']=round(fs['Net Asset per Share'],2)
|
1036
|
+
|
1037
|
+
#市盈率:每股市价 / 每股利润,依赖EPS反推出的流通股数量
|
1038
|
+
fsdf=fs.copy()
|
1039
|
+
fs=get_PE(fsdf)
|
1040
|
+
fs['Price Earnings Ratio']=fs['PE']
|
1041
|
+
|
1042
|
+
fs['date']=fs['endDate']
|
1043
|
+
fs.set_index('date',inplace=True)
|
1044
|
+
|
1045
|
+
return fs
|
1046
|
+
|
1047
|
+
|
1048
|
+
if __name__ == '__main__':
|
1049
|
+
ticker='AAPL'
|
1050
|
+
fsdf=get_financial_statements('AAPL')
|
1051
|
+
fs=calcFinRates(fsdf)
|
1052
|
+
|
1053
|
+
#==============================================================================
|
1054
|
+
def get_financial_rates(ticker):
|
1055
|
+
"""
|
1056
|
+
功能:获得股票的财务报表和财务比率
|
1057
|
+
财务报表:资产负债表,利润表,现金流量表
|
1058
|
+
财务比率:短期还债能力,长期还债能力,营运能力,盈利能力,发展能力
|
1059
|
+
|
1060
|
+
短期偿债能力分析:
|
1061
|
+
1、流动比率,计算公式: 流动资产 / 流动负债
|
1062
|
+
2、速动比率,计算公式: (流动资产-存货) / 流动负债
|
1063
|
+
3、现金比率,计算公式: (现金+现金等价物) / 流动负债
|
1064
|
+
4、现金流量比率,计算公式: 经营活动现金流量 / 流动负债
|
1065
|
+
5、到期债务本息偿付比率,计算公式: 经营活动现金净流量 / (本期到期债务本金+现金利息支出)
|
1066
|
+
|
1067
|
+
长期偿债能力分析:
|
1068
|
+
1、资产负债率,计算公式: 负债总额 / 资产总额
|
1069
|
+
2、股东权益比率,计算公式: 股东权益总额 / 资产总额
|
1070
|
+
3、权益乘数,计算公式: 资产总额 / 股东权益总额
|
1071
|
+
4、负债股权比率,计算公式: 负债总额 / 股东权益总额
|
1072
|
+
5、有形净值债务率,计算公式: 负债总额 / (股东权益-无形资产净额)
|
1073
|
+
6、偿债保障比率,计算公式: 负债总额 / 经营活动现金净流量
|
1074
|
+
7、利息保障倍数,计算公式: (税前利润+利息费用)/ 利息费用
|
1075
|
+
8、现金利息保障倍数,计算公式: (经营活动现金净流量+付现所得税) / 现金利息支出
|
1076
|
+
|
1077
|
+
营运分析
|
1078
|
+
1、存货周转率,计算公式: 销售成本 / 平均存货
|
1079
|
+
2、应收账款周转率,计算公式: 赊销收入净额 / 平均应收账款余额
|
1080
|
+
3、流动资产周转率,计算公式: 销售收入 / 平均流动资产余额
|
1081
|
+
4、固定资产周转率,计算公式: 销售收入 / 平均固定资产净额
|
1082
|
+
5、总资产周转率,计算公式: 销售收入 / 平均资产总额
|
1083
|
+
|
1084
|
+
盈利分析
|
1085
|
+
1、资产报酬率,计算公式: 利润总额+利息支出 / 平均资产总额
|
1086
|
+
2、净资产报酬率,计算公式: 净利润 / 平均净资产
|
1087
|
+
3、股东权益报酬率,计算公式: 净利润 / 平均股东权益总额
|
1088
|
+
4、毛利率,计算公式: 销售毛利 / 销售收入净额
|
1089
|
+
5、销售净利率,计算公式: 净利润 / 销售收入净额
|
1090
|
+
6、成本费用净利率,计算公式: 净利润 / 成本费用总额
|
1091
|
+
7、每股利润,计算公式: (净利润-优先股股利) / 流通在外股数
|
1092
|
+
8、每股现金流量,计算公式: (经营活动现金净流量-优先股股利) / 流通在外股数
|
1093
|
+
9、每股股利,计算公式: (现金股利总额-优先股股利) /流通在外股数
|
1094
|
+
10、股利发放率,计算公式: 每股股利 / 每股利润
|
1095
|
+
11、每股净资产,计算公式: 股东权益总额 / 流通在外股数
|
1096
|
+
12、市盈率,计算公式: 每股市价 / 每股利润
|
1097
|
+
13、主营业务利润率=主营业务利润/主营业务收入*100%
|
1098
|
+
|
1099
|
+
发展分析
|
1100
|
+
1、营业增长率,计算公式: 本期营业增长额 / 上年同期营业收入总额
|
1101
|
+
2、资本积累率,计算公式: 本期所有者权益增长额 / 年初所有者权益
|
1102
|
+
3、总资产增长率,计算公式: 本期总资产增长额 / 年初资产总额
|
1103
|
+
4、固定资产成新率,计算公式: 平均固定资产净值 / 平均固定资产原值
|
1104
|
+
|
1105
|
+
返回:报表+比率
|
1106
|
+
"""
|
1107
|
+
# 变换港股代码5位-->4位
|
1108
|
+
result,prefix,suffix=split_prefix_suffix(ticker)
|
1109
|
+
if result & (suffix=='HK'):
|
1110
|
+
if len(prefix)==5:
|
1111
|
+
ticker=ticker[1:]
|
1112
|
+
|
1113
|
+
print("\nAnalyzing financial rates of",ticker,"\b, it may take lots of time...")
|
1114
|
+
|
1115
|
+
#抓取股票的财务报表
|
1116
|
+
try:
|
1117
|
+
fsdf=get_financial_statements(ticker)
|
1118
|
+
except:
|
1119
|
+
print("......Failed to get financial statements of",ticker,"\b!")
|
1120
|
+
print("......If the stock code",ticker,"\b is correct, please try a few minutes later.")
|
1121
|
+
return None
|
1122
|
+
|
1123
|
+
#抓取股票的稀释后EPS,计算财务比率
|
1124
|
+
fsr=calcFinRates(fsdf)
|
1125
|
+
"""
|
1126
|
+
try:
|
1127
|
+
fsr=calcFinRates(fsdf)
|
1128
|
+
except:
|
1129
|
+
print("......Failed to calculate financial rates of",ticker,"\b, please retry later!")
|
1130
|
+
return None
|
1131
|
+
"""
|
1132
|
+
#整理列名:将股票代码、截止日期、报表类型排在开头
|
1133
|
+
cols=list(fsr)
|
1134
|
+
cols.remove('endDate')
|
1135
|
+
cols.remove('ticker')
|
1136
|
+
cols.remove('reportType')
|
1137
|
+
fsr2=fsr[['ticker','endDate','reportType']+cols]
|
1138
|
+
|
1139
|
+
return fsr2
|
1140
|
+
|
1141
|
+
|
1142
|
+
#==============================================================================
|
1143
|
+
#==============================================================================
|
1144
|
+
#==============================================================================
|
1145
|
+
#==============================================================================
|
1146
|
+
#==============================================================================
|
1147
|
+
#==============================================================================
|
1148
|
+
#==============================================================================
|
1149
|
+
|
1150
|
+
|
1151
|
+
|
1152
|
+
|
1153
|
+
|
1154
|
+
|
1155
|
+
|
1156
|
+
|
1157
|
+
|
1158
|
+
|
1159
|
+
|
1160
|
+
|