siat 3.10.132__py3-none-any.whl → 3.10.133__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. siat/__init__.py +0 -0
  2. siat/allin.py +0 -0
  3. siat/assets_liquidity.py +0 -0
  4. siat/beta_adjustment.py +0 -0
  5. siat/beta_adjustment_china.py +0 -0
  6. siat/blockchain.py +0 -0
  7. siat/bond.py +0 -0
  8. siat/bond_base.py +0 -0
  9. siat/bond_china.py +0 -0
  10. siat/bond_zh_sina.py +0 -0
  11. siat/capm_beta.py +0 -0
  12. siat/capm_beta2.py +0 -0
  13. siat/compare_cross.py +0 -0
  14. siat/copyrights.py +0 -0
  15. siat/cryptocurrency.py +0 -0
  16. siat/economy.py +0 -0
  17. siat/economy2.py +0 -0
  18. siat/esg.py +0 -0
  19. siat/event_study.py +0 -0
  20. siat/exchange_bond_china.pickle +0 -0
  21. siat/fama_french.py +0 -0
  22. siat/fin_stmt2_yahoo.py +0 -0
  23. siat/financial_base.py +0 -0
  24. siat/financial_statements.py +0 -0
  25. siat/financials.py +0 -0
  26. siat/financials2.py +0 -0
  27. siat/financials_china.py +0 -0
  28. siat/financials_china2.py +0 -0
  29. siat/fund.py +0 -0
  30. siat/fund_china.pickle +0 -0
  31. siat/fund_china.py +0 -0
  32. siat/future_china.py +0 -0
  33. siat/google_authenticator.py +0 -0
  34. siat/grafix.py +0 -0
  35. siat/holding_risk.py +0 -0
  36. siat/luchy_draw.py +0 -0
  37. siat/market_china.py +0 -0
  38. siat/markowitz.py +0 -0
  39. siat/markowitz2.py +0 -0
  40. siat/markowitz2_20250704.py +0 -0
  41. siat/markowitz2_20250705.py +0 -0
  42. siat/markowitz_simple.py +0 -0
  43. siat/ml_cases.py +0 -0
  44. siat/ml_cases_example.py +0 -0
  45. siat/option_china.py +0 -0
  46. siat/option_pricing.py +0 -0
  47. siat/other_indexes.py +0 -0
  48. siat/risk_adjusted_return.py +0 -0
  49. siat/risk_adjusted_return2.py +0 -0
  50. siat/risk_evaluation.py +0 -0
  51. siat/risk_free_rate.py +0 -0
  52. siat/sector_china.py +0 -0
  53. siat/security_price2.py +0 -0
  54. siat/security_prices.py +40 -2
  55. siat/security_trend.py +0 -0
  56. siat/security_trend2.py +0 -0
  57. siat/stock.py +0 -0
  58. siat/stock_advice_linear.py +0 -0
  59. siat/stock_base.py +0 -0
  60. siat/stock_china.py +0 -0
  61. siat/stock_info.pickle +0 -0
  62. siat/stock_prices_kneighbors.py +0 -0
  63. siat/stock_prices_linear.py +0 -0
  64. siat/stock_profile.py +0 -0
  65. siat/stock_technical.py +0 -0
  66. siat/stooq.py +0 -0
  67. siat/transaction.py +0 -0
  68. siat/translate.py +0 -0
  69. siat/valuation.py +0 -0
  70. siat/valuation_china.py +0 -0
  71. siat/var_model_validation.py +0 -0
  72. siat/yf_name.py +0 -0
  73. {siat-3.10.132.dist-info/licenses → siat-3.10.133.dist-info}/LICENSE +0 -0
  74. {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/METADATA +232 -235
  75. siat-3.10.133.dist-info/RECORD +78 -0
  76. {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/WHEEL +1 -1
  77. {siat-3.10.132.dist-info → siat-3.10.133.dist-info}/top_level.txt +0 -1
  78. build/lib/build/lib/siat/__init__.py +0 -75
  79. build/lib/build/lib/siat/allin.py +0 -137
  80. build/lib/build/lib/siat/assets_liquidity.py +0 -915
  81. build/lib/build/lib/siat/beta_adjustment.py +0 -1058
  82. build/lib/build/lib/siat/beta_adjustment_china.py +0 -548
  83. build/lib/build/lib/siat/blockchain.py +0 -143
  84. build/lib/build/lib/siat/bond.py +0 -2900
  85. build/lib/build/lib/siat/bond_base.py +0 -992
  86. build/lib/build/lib/siat/bond_china.py +0 -100
  87. build/lib/build/lib/siat/bond_zh_sina.py +0 -143
  88. build/lib/build/lib/siat/capm_beta.py +0 -783
  89. build/lib/build/lib/siat/capm_beta2.py +0 -887
  90. build/lib/build/lib/siat/common.py +0 -5360
  91. build/lib/build/lib/siat/compare_cross.py +0 -642
  92. build/lib/build/lib/siat/copyrights.py +0 -18
  93. build/lib/build/lib/siat/cryptocurrency.py +0 -667
  94. build/lib/build/lib/siat/economy.py +0 -1471
  95. build/lib/build/lib/siat/economy2.py +0 -1853
  96. build/lib/build/lib/siat/esg.py +0 -536
  97. build/lib/build/lib/siat/event_study.py +0 -815
  98. build/lib/build/lib/siat/fama_french.py +0 -1521
  99. build/lib/build/lib/siat/fin_stmt2_yahoo.py +0 -982
  100. build/lib/build/lib/siat/financial_base.py +0 -1160
  101. build/lib/build/lib/siat/financial_statements.py +0 -598
  102. build/lib/build/lib/siat/financials.py +0 -2339
  103. build/lib/build/lib/siat/financials2.py +0 -1278
  104. build/lib/build/lib/siat/financials_china.py +0 -4433
  105. build/lib/build/lib/siat/financials_china2.py +0 -2212
  106. build/lib/build/lib/siat/fund.py +0 -629
  107. build/lib/build/lib/siat/fund_china.py +0 -3307
  108. build/lib/build/lib/siat/future_china.py +0 -551
  109. build/lib/build/lib/siat/google_authenticator.py +0 -47
  110. build/lib/build/lib/siat/grafix.py +0 -3636
  111. build/lib/build/lib/siat/holding_risk.py +0 -867
  112. build/lib/build/lib/siat/luchy_draw.py +0 -638
  113. build/lib/build/lib/siat/market_china.py +0 -1168
  114. build/lib/build/lib/siat/markowitz.py +0 -2363
  115. build/lib/build/lib/siat/markowitz2.py +0 -3150
  116. build/lib/build/lib/siat/markowitz2_20250704.py +0 -2969
  117. build/lib/build/lib/siat/markowitz2_20250705.py +0 -3158
  118. build/lib/build/lib/siat/markowitz_simple.py +0 -373
  119. build/lib/build/lib/siat/ml_cases.py +0 -2291
  120. build/lib/build/lib/siat/ml_cases_example.py +0 -60
  121. build/lib/build/lib/siat/option_china.py +0 -3069
  122. build/lib/build/lib/siat/option_pricing.py +0 -1925
  123. build/lib/build/lib/siat/other_indexes.py +0 -409
  124. build/lib/build/lib/siat/risk_adjusted_return.py +0 -1576
  125. build/lib/build/lib/siat/risk_adjusted_return2.py +0 -1900
  126. build/lib/build/lib/siat/risk_evaluation.py +0 -2218
  127. build/lib/build/lib/siat/risk_free_rate.py +0 -351
  128. build/lib/build/lib/siat/sector_china.py +0 -4140
  129. build/lib/build/lib/siat/security_price2.py +0 -727
  130. build/lib/build/lib/siat/security_prices.py +0 -3408
  131. build/lib/build/lib/siat/security_trend.py +0 -402
  132. build/lib/build/lib/siat/security_trend2.py +0 -646
  133. build/lib/build/lib/siat/stock.py +0 -4284
  134. build/lib/build/lib/siat/stock_advice_linear.py +0 -934
  135. build/lib/build/lib/siat/stock_base.py +0 -26
  136. build/lib/build/lib/siat/stock_china.py +0 -2095
  137. build/lib/build/lib/siat/stock_prices_kneighbors.py +0 -910
  138. build/lib/build/lib/siat/stock_prices_linear.py +0 -386
  139. build/lib/build/lib/siat/stock_profile.py +0 -707
  140. build/lib/build/lib/siat/stock_technical.py +0 -3305
  141. build/lib/build/lib/siat/stooq.py +0 -74
  142. build/lib/build/lib/siat/transaction.py +0 -347
  143. build/lib/build/lib/siat/translate.py +0 -5183
  144. build/lib/build/lib/siat/valuation.py +0 -1378
  145. build/lib/build/lib/siat/valuation_china.py +0 -2076
  146. build/lib/build/lib/siat/var_model_validation.py +0 -444
  147. build/lib/build/lib/siat/yf_name.py +0 -811
  148. build/lib/siat/__init__.py +0 -75
  149. build/lib/siat/allin.py +0 -137
  150. build/lib/siat/assets_liquidity.py +0 -915
  151. build/lib/siat/beta_adjustment.py +0 -1058
  152. build/lib/siat/beta_adjustment_china.py +0 -548
  153. build/lib/siat/blockchain.py +0 -143
  154. build/lib/siat/bond.py +0 -2900
  155. build/lib/siat/bond_base.py +0 -992
  156. build/lib/siat/bond_china.py +0 -100
  157. build/lib/siat/bond_zh_sina.py +0 -143
  158. build/lib/siat/capm_beta.py +0 -783
  159. build/lib/siat/capm_beta2.py +0 -887
  160. build/lib/siat/common.py +0 -5360
  161. build/lib/siat/compare_cross.py +0 -642
  162. build/lib/siat/copyrights.py +0 -18
  163. build/lib/siat/cryptocurrency.py +0 -667
  164. build/lib/siat/economy.py +0 -1471
  165. build/lib/siat/economy2.py +0 -1853
  166. build/lib/siat/esg.py +0 -536
  167. build/lib/siat/event_study.py +0 -815
  168. build/lib/siat/fama_french.py +0 -1521
  169. build/lib/siat/fin_stmt2_yahoo.py +0 -982
  170. build/lib/siat/financial_base.py +0 -1160
  171. build/lib/siat/financial_statements.py +0 -598
  172. build/lib/siat/financials.py +0 -2339
  173. build/lib/siat/financials2.py +0 -1278
  174. build/lib/siat/financials_china.py +0 -4433
  175. build/lib/siat/financials_china2.py +0 -2212
  176. build/lib/siat/fund.py +0 -629
  177. build/lib/siat/fund_china.py +0 -3307
  178. build/lib/siat/future_china.py +0 -551
  179. build/lib/siat/google_authenticator.py +0 -47
  180. build/lib/siat/grafix.py +0 -3636
  181. build/lib/siat/holding_risk.py +0 -867
  182. build/lib/siat/luchy_draw.py +0 -638
  183. build/lib/siat/market_china.py +0 -1168
  184. build/lib/siat/markowitz.py +0 -2363
  185. build/lib/siat/markowitz2.py +0 -3150
  186. build/lib/siat/markowitz2_20250704.py +0 -2969
  187. build/lib/siat/markowitz2_20250705.py +0 -3158
  188. build/lib/siat/markowitz_simple.py +0 -373
  189. build/lib/siat/ml_cases.py +0 -2291
  190. build/lib/siat/ml_cases_example.py +0 -60
  191. build/lib/siat/option_china.py +0 -3069
  192. build/lib/siat/option_pricing.py +0 -1925
  193. build/lib/siat/other_indexes.py +0 -409
  194. build/lib/siat/risk_adjusted_return.py +0 -1576
  195. build/lib/siat/risk_adjusted_return2.py +0 -1900
  196. build/lib/siat/risk_evaluation.py +0 -2218
  197. build/lib/siat/risk_free_rate.py +0 -351
  198. build/lib/siat/sector_china.py +0 -4140
  199. build/lib/siat/security_price2.py +0 -727
  200. build/lib/siat/security_prices.py +0 -3408
  201. build/lib/siat/security_trend.py +0 -402
  202. build/lib/siat/security_trend2.py +0 -646
  203. build/lib/siat/stock.py +0 -4284
  204. build/lib/siat/stock_advice_linear.py +0 -934
  205. build/lib/siat/stock_base.py +0 -26
  206. build/lib/siat/stock_china.py +0 -2095
  207. build/lib/siat/stock_prices_kneighbors.py +0 -910
  208. build/lib/siat/stock_prices_linear.py +0 -386
  209. build/lib/siat/stock_profile.py +0 -707
  210. build/lib/siat/stock_technical.py +0 -3305
  211. build/lib/siat/stooq.py +0 -74
  212. build/lib/siat/transaction.py +0 -347
  213. build/lib/siat/translate.py +0 -5183
  214. build/lib/siat/valuation.py +0 -1378
  215. build/lib/siat/valuation_china.py +0 -2076
  216. build/lib/siat/var_model_validation.py +0 -444
  217. build/lib/siat/yf_name.py +0 -811
  218. siat-3.10.132.dist-info/RECORD +0 -218
@@ -1,1378 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- 本模块功能:投资组合的风险调整收益率教学插件
4
- 所属工具包:证券投资分析工具SIAT
5
- SIAT:Security Investment Analysis Tool
6
- 创建日期:2023年11月30日
7
- 最新修订日期:2023年11月30日
8
- 作者:王德宏 (WANG Dehong, Peter)
9
- 作者单位:北京外国语大学国际商学院
10
- 作者邮件:wdehong2000@163.com
11
- 版权所有:王德宏
12
- 用途限制:仅限研究与教学使用!
13
- 特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
14
- """
15
-
16
- #==============================================================================
17
- #关闭所有警告
18
- import warnings; warnings.filterwarnings('ignore')
19
- #==============================================================================
20
- from siat.common import *
21
- from siat.translate import *
22
- from siat.stock import *
23
- from siat.security_prices import *
24
- from siat.security_price2 import *
25
- from siat.sector_china import *
26
- from siat.valuation_china import *
27
- from siat.grafix import *
28
-
29
- import pandas as pd
30
- import akshare as ak
31
-
32
- import datetime as dt; todaydt=str(dt.date.today())
33
- #==============================================================================
34
- #==============================================================================
35
- if __name__=='__main__':
36
- ticker='PZU.PL'
37
- ticker='PZU.WA'
38
-
39
- indicators='pe'
40
- indicators=['pe','pb']
41
- indicators=['pe','pb','mv']
42
-
43
- start='2023-1-1'; end='2023-11-30'
44
-
45
- df_pl=get_stock_valuation_pl(ticker,indicators,start,end)
46
-
47
- def get_stock_valuation_pl(ticker,indicators,start,end):
48
- """
49
- 功能:抓取一只波兰股票估值信息pe/pb/mv
50
- """
51
- currency='PLN'
52
- million=1000000
53
- kilo=1000
54
- # 判断是否波兰股票
55
- ticker1=ticker.upper()
56
- result,prefix,suffix=split_prefix_suffix(ticker1)
57
- if (not result) or (suffix not in ['PL','WA']):
58
- return None
59
- iname=ticker_name(ticker)
60
-
61
- if isinstance(indicators,str):
62
- indicators=[indicators]
63
-
64
- indicators1=[]
65
- for i in indicators:
66
- indicators1=indicators1+[i.upper()]
67
-
68
- #屏蔽函数内print信息输出的类
69
- import os, sys
70
- class HiddenPrints:
71
- def __enter__(self):
72
- self._original_stdout = sys.stdout
73
- sys.stdout = open(os.devnull, 'w')
74
-
75
- def __exit__(self, exc_type, exc_val, exc_tb):
76
- sys.stdout.close()
77
- sys.stdout = self._original_stdout
78
-
79
- df=None
80
- for i in indicators1:
81
- t=prefix+'_'+i+'.PL'
82
- with HiddenPrints():
83
- dft=get_price(t,start,end)
84
- if dft is None:
85
- print(" #Warning(get_stock_valuation_pl): failed to retrieve",t)
86
- continue
87
-
88
- dft['ticker']=ticker1
89
- dft['name']=iname
90
- dft['currency']='CNY'
91
-
92
- if i=='MV':
93
- #dft[i]=dft['Close'] * million
94
- dft[i]=dft['Close'] / kilo
95
- else:
96
- dft[i]=dft['Close']
97
-
98
- dft1=dft[[i,'name','currency']]
99
-
100
- if df is None:
101
- df=dft1
102
- else:
103
- #df=pd.merge(df,dft1,how='inner',left_index=True,right_index=True)
104
- df=pd.merge(df,dft1,how='outer',left_index=True,right_index=True)
105
-
106
- # 去掉多余的name/currency重复列
107
- if df is None: return None
108
- collist=list(df)
109
- if not (('name' in collist) and ('currency' in collist)):
110
- df.rename(columns={'name_x':'name','currency_x':'currency'},inplace=True)
111
-
112
- collist=list(df)
113
- collist1=[]
114
- for c in collist:
115
- if "_" not in c:
116
- collist1=collist1+[c]
117
-
118
- df1=df[collist1]
119
-
120
- return df1
121
-
122
-
123
- #==============================================================================
124
- if __name__=='__main__':
125
- ticker='JD'
126
- ticker='NIO'
127
- ticker='XPEV'
128
-
129
- indicators='PE'
130
- indicators=['pe','pb']
131
- indicators=['pe','pb','mv']
132
-
133
- start='2023-1-1'; end='2023-11-30'
134
-
135
- df_us=get_stock_valuation_us(ticker,indicators,start,end)
136
-
137
- def get_stock_valuation_us(ticker,indicators,start,end):
138
- """
139
- 功能:抓取一只美股股票估值信息pe/pb/mv
140
- """
141
- currency='USD'
142
- million=1000000
143
- kilo=1000
144
-
145
- # 判断是否美股股票
146
- ticker1=ticker.upper()
147
- result,prefix,suffix=split_prefix_suffix(ticker1)
148
- if result or suffix != '': # 非美股
149
- return None
150
- iname=ticker_name(ticker)
151
-
152
- if isinstance(indicators,str):
153
- indicators=[indicators]
154
-
155
- indicators1=[]
156
- for i in indicators:
157
- indicators1=indicators1+[i.upper()]
158
-
159
- #屏蔽函数内print信息输出的类
160
- import os, sys
161
- class HiddenPrints:
162
- def __enter__(self):
163
- self._original_stdout = sys.stdout
164
- sys.stdout = open(os.devnull, 'w')
165
-
166
- def __exit__(self, exc_type, exc_val, exc_tb):
167
- sys.stdout.close()
168
- sys.stdout = self._original_stdout
169
-
170
- df=None
171
- for i in indicators1:
172
- t=prefix+'_'+i+'.US'
173
- with HiddenPrints():
174
- dft=get_price_stooq(t,start,end)
175
- if dft is None:
176
- print(" #Warning(get_stock_valuation_us): failed to retrieve",t)
177
- continue
178
-
179
- dft['ticker']=ticker1
180
- dft['name']=iname
181
- dft['currency']='CNY'
182
-
183
- if i=='MV':
184
- #dft[i]=dft['Close'] * million
185
- dft[i]=dft['Close'] / kilo
186
- else:
187
- dft[i]=dft['Close']
188
- dft1=dft[[i,'name','currency']]
189
-
190
- if df is None:
191
- df=dft1
192
- else:
193
- df=pd.merge(df,dft1,how='outer',left_index=True,right_index=True)
194
-
195
- # 去掉多余的name/currency重复列
196
- if df is None: return None
197
- collist=list(df)
198
- if not (('name' in collist) and ('currency' in collist)):
199
- df.rename(columns={'name_x':'name','currency_x':'currency'},inplace=True)
200
-
201
- collist=list(df)
202
- collist1=[]
203
- for c in collist:
204
- if "_" not in c:
205
- collist1=collist1+[c]
206
-
207
- df1=df[collist1]
208
-
209
- return df1
210
-
211
- #==============================================================================
212
- if __name__=='__main__':
213
- ticker='600519.SS'
214
- ticker='002504.SZ'
215
- ticker='835579.BJ'
216
- ticker='00700.HK'
217
-
218
- indicators='pe'
219
- indicators=['pe','pb']
220
- indicators=['pe','pb','mv']
221
-
222
- start='2023-1-1'; end='2023-11-30'
223
-
224
- df_cnhk=get_stock_valuation_cn_hk(ticker,indicators,start,end)
225
-
226
- def get_stock_valuation_cn_hk(ticker,indicators,start,end):
227
- """
228
- 功能:抓取一只A股或港股股票估值信息pe/pb/mv
229
- """
230
- result,startdt,enddt=check_period(start,end)
231
-
232
- yi=100000000
233
- ten=10
234
- # 判断是否A股或港股股票
235
- ticker1=ticker.upper()
236
- result,prefix,suffix=split_prefix_suffix(ticker1)
237
- if (not result) or (suffix not in ['SS','SZ','BJ','HK']):
238
- return None
239
- iname=ticker_name(ticker)
240
-
241
- if suffix in ['SS','SZ','BJ']: currency='CNY'
242
- else: currency='HKD'
243
-
244
- if isinstance(indicators,str):
245
- indicators=[indicators]
246
-
247
- indicators1=[]
248
- for i in indicators:
249
- indicators1=indicators1+[i.upper()]
250
-
251
- #屏蔽函数内print信息输出的类
252
- import os, sys
253
- class HiddenPrints:
254
- def __enter__(self):
255
- self._original_stdout = sys.stdout
256
- sys.stdout = open(os.devnull, 'w')
257
-
258
- def __exit__(self, exc_type, exc_val, exc_tb):
259
- sys.stdout.close()
260
- sys.stdout = self._original_stdout
261
-
262
- # 评估时间间隔: 取样日期间隔长短不同,必须做
263
- delta=date_delta(start,end)
264
- if delta <= 365:
265
- period="近一年"
266
- elif delta <= 365*3:
267
- period="近三年"
268
- elif delta <= 365*5:
269
- period="近五年"
270
- elif delta <= 365*10:
271
- period="近十年"
272
- else:
273
- period="全部"
274
-
275
- indicator_list_en=['PE','PB','MV','PCF']
276
- indicator_list_cn=['市盈率(TTM)','市净率','总市值','市现率']
277
- # 市现率PCF=股价 / 每股现金流
278
- # 市销率PS或PSR=股价 / 每股销售额
279
- df=None
280
- for i in indicators1:
281
- pos=indicator_list_en.index(i)
282
- t=indicator_list_cn[pos]
283
- """
284
- with HiddenPrints():
285
- if suffix in ['SS','SZ','BJ']:
286
- dft=ak.stock_zh_valuation_baidu(symbol=prefix,indicator=t,period=period)
287
- elif suffix in ['HK']:
288
- dft=ak.stock_hk_valuation_baidu(symbol=prefix,indicator=t,period=period)
289
- """
290
- try:
291
- if suffix in ['SS','SZ','BJ']:
292
- dft=ak.stock_zh_valuation_baidu(symbol=prefix,indicator=t,period=period)
293
- elif suffix in ['HK']:
294
- dft=ak.stock_hk_valuation_baidu(symbol=prefix,indicator=t,period=period)
295
- except:
296
- print(" #Warning(get_stock_valuation_cn_hk): failed to retrieve",i,"for",prefix)
297
- continue
298
-
299
- dft['Date']=dft['date'].apply(lambda x: pd.to_datetime(x))
300
- dft.set_index('Date',inplace=True)
301
- dft['ticker']=ticker1
302
- dft['name']=iname
303
- dft['currency']='CNY'
304
- if i=='MV':
305
- #dft[i]=dft['value'] * yi
306
- dft[i]=dft['value'] / ten
307
- else:
308
- dft[i]=dft['value']
309
- dftp=dft[(dft.index >= startdt) & (dft.index <= enddt)]
310
- dft1=dftp[[i,'name','currency']]
311
-
312
- if df is None:
313
- df=dft1
314
- else:
315
- df=pd.merge(df,dft1,how='outer',left_index=True,right_index=True)
316
-
317
- # 去掉多余的name/currency重复列
318
- if df is None: return None
319
- collist=list(df)
320
- if not (('name' in collist) and ('currency' in collist)):
321
- df.rename(columns={'name_x':'name','currency_x':'currency'},inplace=True)
322
-
323
- collist=list(df)
324
- collist1=[]
325
- for c in collist:
326
- if "_" not in c:
327
- collist1=collist1+[c]
328
-
329
- df1=df[collist1]
330
-
331
- return df1
332
-
333
- #==============================================================================
334
- if __name__=='__main__':
335
- ticker='光伏设备(申万)'
336
- ticker='中证500'
337
- ticker='801735.SW'
338
-
339
- ticker='中证红利'
340
- ticker='000922.ZZ'
341
- ticker='中证央企红利'
342
-
343
- indicators='pe'
344
- indicators=['pe','pb','div yield']
345
- indicators=['pe','pb']
346
-
347
- start='2023-1-1'; end='2023-11-30'
348
-
349
- df_index=get_index_valuation_funddb(ticker,indicators,start,end)
350
-
351
- def get_index_valuation_funddb(ticker,indicators,start,end):
352
- """
353
- 功能:抓取一个申万或中证行业估值信息pe/pb/dividend(股息率)
354
- """
355
- result,startdt,enddt=check_period(start,end)
356
-
357
- # 判断是否申万或中证股票
358
- ticker1=ticker.upper()
359
- result,prefix,suffix=split_prefix_suffix(ticker1)
360
- if result and suffix in ['SW']:
361
- iname=industry_sw_name(prefix)+"(申万)"
362
- else:
363
- iname=ticker1
364
-
365
- if isinstance(indicators,str):
366
- indicators=[indicators]
367
-
368
- indicators1=[]
369
- for i in indicators:
370
- indicators1=indicators1+[i.upper()]
371
-
372
- indicator_list_en=['PE','PB','DIV YIELD']
373
- indicator_list_cn=['市盈率','市净率','股息率']
374
- indicators2=[]
375
- for i in indicators1:
376
- if i in indicator_list_en:
377
- indicators2=indicators2+[i]
378
-
379
- #屏蔽函数内print信息输出的类
380
- import os, sys
381
- class HiddenPrints:
382
- def __enter__(self):
383
- self._original_stdout = sys.stdout
384
- sys.stdout = open(os.devnull, 'w')
385
-
386
- def __exit__(self, exc_type, exc_val, exc_tb):
387
- sys.stdout.close()
388
- sys.stdout = self._original_stdout
389
-
390
- # 股息率=每股股利 / 股价
391
- df=None
392
- for i in indicators2:
393
- pos=indicator_list_en.index(i)
394
- t=indicator_list_cn[pos]
395
- try:
396
- with HiddenPrints():
397
- dft=ak.index_value_hist_funddb(symbol=iname,indicator=t)
398
- except:
399
- print(" #Error(get_index_valuation_funddb): failed to retrieve info for industry",ticker)
400
- industry_list=list(ak.index_value_name_funddb()['指数名称'])
401
- industry_sw=[]
402
- industry_zz=[]
403
- industry_gz=[]
404
- industry_others=[]
405
- for i in industry_list:
406
- if '(申万)' in i:
407
- industry_sw=industry_sw+[i]
408
- elif '中证' in i:
409
- industry_zz=industry_zz+[i]
410
- elif '国证' in i:
411
- industry_gz=industry_gz+[i]
412
- else:
413
- industry_others=industry_others+[i]
414
- print(" Supported industry indexes:")
415
- printlist(industry_sw,numperline=5,beforehand=' ',separator=' ')
416
- printlist(industry_zz,numperline=5,beforehand=' ',separator=' ')
417
- printlist(industry_gz,numperline=5,beforehand=' ',separator=' ')
418
- printlist(industry_others,numperline=5,beforehand=' ',separator=' ')
419
-
420
- return None
421
-
422
- if dft is None: continue
423
-
424
- dft['Date']=dft['日期'].apply(lambda x: pd.to_datetime(x))
425
- dft.set_index('Date',inplace=True)
426
- dft['name']=iname
427
- dft['currency']=''
428
- dft[i]=dft[t]
429
- dftp=dft[(dft.index >= startdt) & (dft.index <= enddt)]
430
-
431
- dft1=dftp[[i,'name','currency']]
432
- """
433
- if not (dft1 is None):
434
- columns=create_tuple_for_columns(dft1,iname)
435
- dft1.columns=pd.MultiIndex.from_tuples(columns)
436
- """
437
- if df is None:
438
- df=dft1
439
- else:
440
- df=pd.merge(df,dft1,how='outer',left_index=True,right_index=True)
441
-
442
- # 去掉多余的name/currency重复列
443
- if df is None: return None
444
- collist=list(df)
445
- if not (('name' in collist) and ('currency' in collist)):
446
- df.rename(columns={'name_x':'name','currency_x':'currency'},inplace=True)
447
-
448
- collist=list(df)
449
- collist1=[]
450
- for c in collist:
451
- if "_" not in c:
452
- collist1=collist1+[c]
453
-
454
- df1=df[collist1]
455
-
456
- return df1
457
-
458
- #==============================================================================
459
- if __name__=='__main__':
460
- print(is_alphanumeric("abc123")) # True
461
- print(is_alphanumeric("abcd123!")) # False
462
- print(is_alphanumeric("1234567890")) # True
463
- print(is_alphanumeric("Hello World")) # False
464
- print(is_alphanumeric("中证500"))
465
-
466
- def is_alphanumeric(string):
467
- import re
468
- pattern = r'^[a-zA-Z0-9]+$' # 定义正则表达式模式
469
-
470
- if re.match(pattern, string):
471
- return True
472
- else:
473
- return False
474
-
475
-
476
- #==============================================================================
477
- if __name__=='__main__':
478
- code='H30533.ZZ'
479
- code='801730.SW'
480
-
481
- funddb_name(code)
482
-
483
-
484
- def funddb_name(code):
485
- """
486
- 翻译指数代码为韭圈儿名称。指数估值专用!
487
- 输入:指数代码。输出:韭圈儿指数名称
488
- """
489
- import pandas as pd
490
- ecdict=pd.DataFrame([
491
-
492
- # 申万行业/主题指数
493
- ['801735.SW','光伏设备(申万)'],
494
- ['801730.SW','电力设备(申万)'],
495
- ['801780.SW','银行(申万)'],
496
- ['801740.SW','国防军工(申万)'],
497
- ['801720.SW','建筑装饰(申万)'],
498
- ['801110.SW','家用电器(申万)'],
499
- ['801102.SW','通信设备(申万)'],
500
- ['801194.SW','保险Ⅱ(申万)'],
501
- ['801770.SW','通信(申万)'],
502
- ['801050.SW','有色金属(申万)'],
503
- ['801812.SW','中盘指数(申万)'],
504
- ['801152.SW','生物制品(申万)'],
505
- ['801811.SW','大盘指数(申万)'],
506
- ['801970.SW','环保(申万)'],
507
- ['801120.SW','食品饮料(申万)'],
508
- ['801170.SW','交通运输(申万)'],
509
- ['801150.SW','医药生物(申万)'],
510
- ['801980.SW','美容护理(申万)'],
511
- ['801160.SW','公用事业(申万)'],
512
- ['801950.SW','煤炭(申万)'],
513
- ['801151.SW','化学制药(申万)'],
514
- ['801130.SW','纺织服饰(申万)'],
515
- ['801960.SW','石油石化(申万)'],
516
- ['801890.SW','机械设备(申万)'],
517
- ['801790.SW','非银金融(申万)'],
518
- ['801813.SW','小盘指数(申万)'],
519
- ['801030.SW','基础化工(申万)'],
520
- ['801193.SW','券商Ⅱ(申万)'],
521
- ['801210.SW','社会服务(申万)'],
522
- ['801140.SW','轻工制造(申万)'],
523
- ['801760.SW','传媒(申万)'],
524
- ['801710.SW','建筑材料(申万)'],
525
- ['801080.SW','电子(申万)'],
526
- ['801040.SW','钢铁(申万)'],
527
- ['801200.SW','商贸零售(申万)'],
528
- ['801017.SW','养殖业(申万)'],
529
- ['801180.SW','房地产(申万)'],
530
- ['801230.SW','综合(申万)'],
531
- ['801010.SW','农林牧渔(申万)'],
532
- ['801880.SW','汽车(申万)'],
533
- ['801736.SW','风电设备(申万)'],
534
- ['801750.SW','计算机(申万)'],
535
-
536
- # 沪深交易所行业指数
537
- ['000688.SS','科创50'],#上证科创板50成份指数由上海证券交易所科创板中市值大、流动性好的50只证券组成
538
- ['399976.SZ','CS新能车'],
539
- ['399995.SZ','中证基建工程'],
540
- ['399812.SZ','养老产业'],
541
- ['000986.SS','全指能源'],
542
- ['399986.SZ','中证银行'],
543
- ['000992.SS','全指金融地产'],
544
- ['000991.SS','全指医药'],
545
- ['399285.SZ','物联网50'],
546
- ['399997.SZ','中证白酒'],
547
-
548
- ['000987.SS','全指材料'],
549
- ['000993.SS','全指信息'],
550
- ['399610.SZ','TMT50'],#深证TMT50指数, 科技(Technology)、媒体(Media)和电信(Telecom)类上市公司
551
- ['399975.SZ','证券公司'],
552
- ['399804.SZ','中证体育'],
553
- ['399285.SZ','物联网50'],
554
- ['399998.SZ','中证煤炭'],
555
- ['000932.SS','中证消费'],
556
- ['399970.SZ','中证移动互联'],
557
- ['399971.SZ','中证传媒'],
558
- ['000827.SS','中证环保'],
559
- ['399808.SZ','中证新能'],
560
- ['399967.SZ','中证军工'],
561
- ['000933.SS','中证医药'],
562
- ['000934.SS','中证金融'],
563
- ['399989.SZ','中证医疗'],
564
- ['399441.SZ','国证生物医药'],
565
- ['399707.SZ','CSSW证券'],#中证申万证券行业指数(CSSW证券)和中证全指证券公司指数(证券公司),完全是关于证券行业的指数
566
- ['000057.SS','全指成长'],
567
- ['000058.SS','全指价值'],
568
-
569
- # 中证行业指数
570
- ['930599.ZZ','中证高装'],#中证高端装备制造指数
571
- ['930707.ZZ','中证畜牧'],
572
- ['930606.ZZ','中证钢铁'],
573
- ['931865.ZZ','中证半导'],
574
- ['930743.ZZ','中证生科'],
575
- ['930708.ZZ','中证有色'],
576
- ['930641.ZZ','中证中药'],
577
- ['930771.ZZ','中证新能源'],
578
- ['000949.ZZ','中证农业'],
579
- ['932000.ZZ','中证2000'],#中证规模指数系列
580
-
581
- ['H30533.ZZ','中国互联网50'],#中证海外中国互联网50指数选取海外交易所上市的50家中国互联网企业
582
- ['H30178.ZZ','医疗保健'],
583
- ['H30217.ZZ','医疗器械'],#中证全指医疗保健设备与服务指数
584
- ['H30205.ZZ','饮料指数'],
585
- ['H30199.ZZ','中证全指电力指数'],
586
- ['H30184.ZZ','中证全指半导体'],
587
- ['H30171.ZZ','中证全指运输指数'],
588
- ['H30202.ZZ','软件指数'],
589
- ['H11052.ZZ','智能电车'],
590
-
591
- ['931151.ZZ','光伏产业'],
592
- ['930614.ZZ','环保50'],
593
- ['000812.ZZ','细分机械'],
594
- ['931755.ZZ','SEEE碳中和'],
595
-
596
- ['931719.ZZ','CS电池'],
597
- ['930820.ZZ','CS高端制'],
598
- ['930632.ZZ','CS稀金属'],#中证稀有金属主题指数
599
- ['930716.ZZ','CS物流'],#中证现代物流指数选
600
- ['930726.ZZ','CS生医'],
601
- ['930712.ZZ','CS物联网'],#中证物联网主题指数
602
- ['931484.ZZ','CS医药创新'],
603
- ['930651.ZZ','CS计算机'],
604
- ['930652.ZZ','CS电子'],#中证电子指数
605
- ['930713.ZZ','CS人工智'],
606
- ['930838.ZZ','CS高股息'],
607
- ['931152.ZZ','CS创新药'],
608
- ['930721.ZZ','CS智汽车'],
609
- ['931139.ZZ','CS消费50'],
610
-
611
- ['930697.ZZ','家用电器'],
612
- ['931160.ZZ','通信设备'],
613
-
614
- ['000811.ZZ','细分有色'],
615
- ['000813.ZZ','细分化工'],
616
- ['000815.ZZ','细分食品'],
617
- ['000812.ZZ','细分机械'],
618
-
619
- ['000990.ZZ','全指消费'],
620
- ['000995.ZZ','全指公用'],
621
- ['000988.ZZ','全指工业'],
622
- ['000994.ZZ','全指通信'],
623
-
624
- ['930598.ZZ','稀土产业'],
625
- ['930851.ZZ','云计算'],
626
- ['931079.ZZ','5G通信'],
627
- ['931456.ZZ','中国教育'],
628
- ['931009.ZZ','建筑材料'],
629
- ['931775.ZZ','中证全指房地产'],
630
-
631
- ['931663.ZZ','SHS消费龙头'],#中证沪港深消费龙头企业指数
632
- ['931524.ZZ','SHS科技龙头'],#中证沪港深科技龙头指数
633
- ['930917.ZZ','SHS高股息(CNY)'],#中证沪港深高股息指数
634
- ['930625.ZZ','SHS互联网'],#中证沪港深互联网指数
635
- ['931470.ZZ','SHS云计算'],#中证沪港深云计算指数
636
- ['931409.ZZ','SHS创新药'],#中证沪港深创新药指数
637
-
638
- ['000859.ZZ','国企一带一路'],
639
- ['931165.ZZ','新兴科技100'],#中证新兴科技100策略指数, 沪深A股新兴科技相关产业中选取高盈利能力、高成长且兼具估值水平低的股票
640
-
641
- # 主要市场通用指数
642
- ['399001.SZ','深证成指'],
643
- ['399330.SZ','深证100'],
644
- ['399006.SZ','创业板指'],#创业板指数
645
- ['399102.SZ','创业板综'],#创业板综合指数
646
- ['399303.SZ','国证2000'],
647
-
648
- ['000001.SS','上证指数'],
649
- ['000016.SS','上证50'],
650
- ['000010.SS','上证180'],
651
- ['000009.SS','上证380'],
652
-
653
- ['000300.SS','沪深300'],
654
- ['000903.SS','中证100'],
655
- ['000905.SS','中证500'],
656
- ['000906.SS','中证800'],
657
- ['000852.SS','中证1000'],
658
-
659
- ['899050.BJ','北证50'],
660
-
661
- ['^FTSE','英国富时100'],
662
- ['^HSI','恒生指数'],
663
- ['^CAC','法国CAC40'],['^FCHI','法国CAC40'],
664
- ['^RTS','俄罗斯RTS'],
665
- ['^VN30','胡志明指数'],['VNINDEX','胡志明指数'],
666
- ['^BSESN','印度SENSEX30'],
667
- ['^N225','日经225'],
668
- ['^SPX','标普500'],['^GSPC','标普500'],
669
- ['^KS11','韩国综合指数'],
670
- ['^DJI','道琼斯工业指数'],
671
- ['^NDX','纳斯达克100'],
672
- ['^AXAT','澳洲标普200'],#澳大利亚标普200指数
673
-
674
- # 其他特色指数
675
- ['HSCEI.HK','ESG120策略'],#中证ESG120策略指数从沪深300指数样本股中选取ESG得分较高的120只股票
676
- ['HSCEI.HK','恒生中国企业指数'],#中国企业以H股形式在香港联合交易所(「联交所」)上市
677
- ['930931.ZZ','港股通50(HKD)'],#港股通范围内的最大50家公司
678
- ['HSIII.ZZ','沪港深500'],#中证沪港深500指数, 沪港深交易所上市的互联互通范围内股票
679
- ['HSIII.HK','恒生互联网科技业'],
680
- ['HSTECH.HK','恒生科技指数'],
681
- ['931637.ZZ','HKC互联网'],#中证港股通互联网指数, 港股通内互联网主题上市公司
682
- ['746059.MI','MSCI中国A50互联互通'],#上海和深圳交易所上市的中国A股大盘和中盘股票,且可通过北向交易互联互通
683
- ['S5HLTH','标普500医疗'],#标普500成分股中属于GICS health care sector
684
- ['S5INFT','标普500信息技术'],#标普500成分股中属于GICS information technology sector
685
- ['HSHCI.HK','恒生医疗保健'],#恒生综合指数里主要经营医疗保健业务成份股公司的表现
686
- ['884251.WD','猪产业指数'],#万得指数,包含种猪、肉猪养殖,肉猪屠宰及猪肉销售、猪饲料类公司
687
- ['884252.WD','鸡产业指数'],#万得指数,包含鸡苗、肉鸡养殖,肉鸡屠宰及鸡肉销售类公司
688
- ['^SOX','费城半导体指数'],#费城交易所指数,全球半导体业景气主要指标
689
- ['ERGLU','富时发达市场REITs'],
690
-
691
- ['980032.GZ','新能电池'],#国证新能源电池指数
692
-
693
- ['931468.ZZ','红利质量'],#中证红利质量指数,连续现金分红、股利支付率较高且具备较高盈利能力特征的上市公司股
694
- ['000922.ZZ','中证红利'],#中证红利指数以沪深A股中现金股息率高、分红比较稳定、具有一定规模及流动性的100只股票
695
- ['000825.ZZ','中证央企红利'],#中证中央企业红利指数,中央企业中现金股息率高、分红比较稳定、且有一定规模及流动性的30只股票
696
- ['000969.ZZ','沪深300非周期'],
697
- ['000821.ZZ','沪深300红利'],
698
- ['000968.ZZ','沪深300周期'],
699
-
700
- ], columns=['eword','cword'])
701
-
702
- try:
703
- cword=ecdict[ecdict['eword']==code]['cword'].values[0]
704
- except:
705
- #未查到代码名称,返回原代码
706
- cword=code
707
-
708
- return cword
709
- #==============================================================================
710
-
711
- if __name__=='__main__':
712
- tickers='AAPL'
713
- tickers='PZU.PL'
714
- tickers='JD'
715
- tickers='NIO'
716
- tickers='600519.SS'
717
- tickers='00700.HK'
718
- tickers='光伏设备(申万)'
719
- tickers='中证500'
720
- tickers='801735.SW'
721
- tickers='801853.SW'
722
-
723
- tickers=['PZU.PL','WIG.PL']
724
- tickers=['PZU.PL','JD','600519.SS','00700.HK','801735.SW','光伏设备(申万)','中证500']
725
-
726
- indicators='PE'
727
- indicators='PB'
728
- indicators=['pe','pb']
729
- indicators=['pe','pb','mv']
730
- indicators='ROE'
731
-
732
- start='2023-1-1'; end='2023-11-30'
733
-
734
- df_mix=get_valuation(tickers,indicators,start,end)
735
-
736
- def get_valuation(tickers,indicators,start,end):
737
- """
738
- 功能:获取估值信息pe/pb/mv
739
- 若tickers为多个,则indicators取第一个
740
- 若tickers为单个,则indicators取所有
741
- """
742
-
743
- if isinstance(tickers,str):
744
- tickers=[tickers]
745
-
746
- # 若遇到指数,先转换为韭圈儿的行业名称,以免被误认为股票代码
747
- tickers1=[]
748
- for t in tickers:
749
- t1=funddb_name(t)
750
- tickers1=tickers1+[t1]
751
-
752
- if isinstance(indicators,str):
753
- indicators=[indicators]
754
-
755
- # 若为多个证券代码,则仅取第一个指标
756
- if len(tickers)>1:
757
- indicators1=[indicators[0]]
758
- else:
759
- indicators1=indicators
760
-
761
- #处理ROE,赋值indicators2,保留indicators1
762
- ROE_flag=False
763
- if 'ROE' in indicators1:
764
- ROE_flag=True
765
- indicators2=indicators1.copy() #注意:若不加copy,则仅为指针赋值,两者将联动
766
- indicators2.remove('ROE')
767
- if 'PE' not in indicators2:
768
- indicators2=indicators2+['PE']
769
- if 'PB' not in indicators2:
770
- indicators2=indicators2+['PB']
771
-
772
- # 百度股市百事通不支持指数估值,遇到指数代码需要先转为名称获取韭圈儿估值数据
773
- """
774
- tickers1=[]
775
- for t in tickers:
776
- t1=funddb_name(t)
777
- tickers1=tickers1+[t1]
778
- """
779
- df=None
780
- for t in tickers1:
781
- print(" Searchng valuation info for",t,"......")
782
- t1=t.upper()
783
- result,prefix,suffix=split_prefix_suffix(t1)
784
- iname=ticker_name(t1)
785
-
786
- gotit=False
787
- # A股或港股?
788
- if not gotit and (result and suffix in ['SS','SZ','BJ','HK']):
789
- if ROE_flag:
790
- dft=get_stock_valuation_cn_hk(t1,indicators2,start,end)
791
- dft['ROE']=dft.apply(lambda x: x['PB']/x['PE'],axis=1)
792
- dft=dft[indicators1]
793
- else:
794
- dft=get_stock_valuation_cn_hk(t1,indicators1,start,end)
795
- if dft is not None: gotit=True
796
-
797
- # 波兰股?
798
- if not gotit and (result and suffix in ['PL','WA']):
799
- if ROE_flag:
800
- dft=get_stock_valuation_pl(t1,indicators2,start,end)
801
- dft['ROE']=dft.apply(lambda x: x['PB']/x['PE'],axis=1)
802
- dft=dft[indicators1]
803
- else:
804
- dft=get_stock_valuation_pl(t1,indicators1,start,end)
805
- if dft is not None: gotit=True
806
-
807
- # 行业指数代码?
808
- suffix_list=['SW','SI',#申万行业
809
- 'GI',#谷歌
810
- 'CSI',#中证
811
- 'CNI',#国证
812
- 'SH','SZ','BJ',#沪深京交易所
813
- 'WI',#万得
814
- 'HI',#恒生
815
- 'SPI',#标普
816
- 'MI',#MSCI
817
- 'BO',#孟买
818
- ]
819
- if not gotit and (result and suffix in suffix_list) and not ROE_flag:
820
-
821
- #dft=get_index_valuation_funddb(t1,indicators1,start,end)
822
- indicator1=indicators1[0]
823
- dft0=industry_valuation_history_sw(industry=t1,
824
- start=start,end=end,
825
- vtype=indicator1,
826
- graph=False)
827
- dft0[indicator1]=dft0[list(dft0)[0]]
828
- dft0['name']=industry_sw_name(t1)
829
- dft0['currency']=''
830
- dft=dft0[[indicator1,'name','currency']]
831
-
832
- if dft is not None:
833
- gotit=True
834
- iname=industry_sw_name(t1)
835
-
836
- # 美股?
837
- if not gotit and (not result and (is_alphanumeric(prefix) or '^' in prefix)):
838
- if ROE_flag:
839
- dft=get_stock_valuation_us(t1,indicators2,start,end)
840
- dft['ROE']=dft.apply(lambda x: x['PB']/x['PE'],axis=1)
841
- dft=dft[indicators1]
842
- else:
843
- dft=get_stock_valuation_us(t1,indicators1,start,end)
844
- if dft is not None: gotit=True
845
-
846
- # 行业指数名称?
847
- if not gotit and (not result):
848
- if ROE_flag:
849
- dft=get_index_valuation_funddb(t1,indicators2,start,end)
850
- dft['ROE']=dft.apply(lambda x: x['PB']/x['PE'],axis=1)
851
- dft=dft[indicators1]
852
- else:
853
- dft=get_index_valuation_funddb(t1,indicators1,start,end)
854
- if dft is not None: gotit=True
855
-
856
- if not gotit:
857
- print(" #Warning(get_valuation): failed to retrieve info for",t1)
858
- continue
859
-
860
- if not (dft is None):
861
- columns=create_tuple_for_columns(dft,iname)
862
- dft.columns=pd.MultiIndex.from_tuples(columns)
863
-
864
- # 合成
865
- if df is None:
866
- df=dft
867
- else:
868
- #df=pd.merge(df,dft,how='inner',left_index=True,right_index=True)
869
- df=pd.merge(df,dft,how='outer',left_index=True,right_index=True)
870
-
871
- # 缺失值填充
872
- if not (df is None):
873
- #df.fillna(method='backfill',inplace=True)
874
- df.fillna(method='ffill',inplace=True)
875
- else:
876
- return None
877
-
878
- # 处理字段名称后面的_x/_y/_z
879
- df_collist=list(df)
880
- df1=df
881
- df1_collist=[]
882
-
883
- for c in df_collist:
884
- c1,c2=c
885
- c1x=c1.split('_')[0]
886
- cx=(c1x,c2)
887
- cx=tuple(cx) #必须为元组
888
-
889
- df1_collist=df1_collist+[cx] #列表中必须为元组
890
-
891
- df1.columns=pd.MultiIndex.from_tuples(df1_collist) #统一修改元组型列名
892
- df1.dropna(inplace=True)
893
-
894
- return df1
895
-
896
-
897
- #==============================================================================
898
- if __name__=='__main__':
899
- tickers='PZU.PL'
900
- indicators='PE'
901
- start='2023-1-1'; end='2023-11-30'
902
- loc1='best'
903
-
904
- tickers='PZU.PL'
905
- indicators=['PE','PB']
906
- start='2023-1-1'; end='2023-11-30'
907
- twinx=True
908
- loc1='lower left'; loc2='upper right'
909
-
910
- tickers=['JD','PDD']
911
- indicators='PE'
912
- start='2023-1-1'; end='2023-11-30'
913
- twinx=True
914
- loc1='lower left'; loc2='upper right'
915
-
916
- tickers=['600519.SS','000858.SZ']
917
- indicators='PE'
918
- start='2023-1-1'; end='2023-11-30'
919
- twinx=True
920
- loc1='lower left'; loc2='upper right'
921
-
922
- tickers=['JD','PDD','BABA']
923
- indicators='PE'
924
- start='2023-1-1'; end='2023-11-30'
925
- loc1='best'
926
-
927
- tickers='JD'
928
- indicators=['PE','PB','MV']
929
- start='2023-1-1'; end='2023-11-30'
930
- loc1='best'
931
-
932
- tickers=['AAPL','MSFT']
933
- indicators='ROE'
934
- indicators='PE'
935
- indicators='PB'
936
- start='2023-1-1'; end='2023-12-31'
937
- loc1='best'
938
-
939
- val=security_valuation(tickers,indicators,start,end)
940
-
941
- def security_valuation(tickers,indicators,start,end, \
942
- preprocess='none',scaling_option='start', \
943
- twinx=False,loc1='best',loc2='best', \
944
- graph=True,facecolor='whitesmoke', \
945
- attention_value='',attention_value_area='', \
946
- attention_point='',attention_point_area='', \
947
- band_area='', \
948
- annotate=False,annotate_value=False, \
949
- mark_top=False,mark_bottom=False, \
950
- mark_start=False,mark_end=False):
951
- """
952
- 功能:绘制估值走势
953
- """
954
-
955
- # 获取估值信息
956
- df=get_valuation(tickers,indicators,start,end)
957
- if df is None:
958
- print(" #Warning(security_valuation): retrieved none of",indicators,"for",tickers)
959
- return None
960
-
961
- if not graph: return df
962
-
963
- # 判断估值信息结构
964
- names=[]
965
- indicators=[]
966
-
967
- mcollist=list(df)
968
- for mc in mcollist:
969
- if mc[0] not in ['name','currency']:
970
- indicators=indicators+[mc[0]]
971
- names=names+[mc[1]]
972
-
973
- names1=list(set(names))
974
- indicators1=list(set(indicators))
975
-
976
- name_num=len(names1)
977
- indicator_num=len(indicators1)
978
-
979
-
980
- # 将band_area中的ticker替换为tname
981
- if band_area != '':
982
- if name_num > 1:
983
- # 假定band_area里面的是ticker
984
- for index, item in enumerate(band_area):
985
- tname=ticker_name(item)
986
- if tname in names1:
987
- band_area[index] = tname
988
- else:
989
- band_area.remove(item)
990
-
991
- if name_num == 1 and indicator_num > 1:
992
- # 假定band_area里面的是indicator
993
- for index, item in enumerate(band_area):
994
- if item not in indicators1:
995
- band_area.remove(item)
996
-
997
- if len(band_area) != 2:
998
- band_area=''
999
- print(" #Warning(security_valuation): band_area does not match ticker or indicator")
1000
-
1001
- import datetime
1002
- # 绘制一条线+均值/中位数虚线
1003
- if name_num * indicator_num == 1:
1004
- i=indicators1[0]
1005
- t=names1[0]
1006
- df2=df[i]
1007
- df2.rename(columns={t:i},inplace=True)
1008
-
1009
- df2['平均值']=df2[i].mean()
1010
- df2['中位数']=df2[i].median()
1011
-
1012
- #ylabeltxt=i
1013
- ylabeltxt=ectranslate(i)
1014
- df2.rename(columns={i:ectranslate(i)},inplace=True)
1015
-
1016
- titletxt="证券估值走势:"+t
1017
-
1018
- footnote1=""
1019
- if i=='MV':
1020
- if preprocess=='none':
1021
- footnote1="注:市值金额:十亿,本币单位\n"
1022
-
1023
- todaydt = datetime.date.today()
1024
- footnote9="数据来源: Baidu/Stooq/FundDB/SWHY,"+str(todaydt)
1025
- footnote=footnote1+footnote9
1026
-
1027
- draw_lines(df2,y_label=ylabeltxt,x_label=footnote, \
1028
- axhline_value=0,axhline_label='', \
1029
- title_txt=titletxt,data_label=False, \
1030
- resample_freq='D',loc=loc1,facecolor=facecolor, \
1031
- attention_value=attention_value,attention_value_area=attention_value_area, \
1032
- attention_point=attention_point,attention_point_area=attention_point_area, \
1033
- annotate=annotate,annotate_value=annotate_value, \
1034
- mark_top=mark_top,mark_bottom=mark_bottom, \
1035
- mark_start=mark_start,mark_end=mark_end)
1036
-
1037
- return df
1038
-
1039
- # 绘制双线: 一只证券,两个指标。twinx双轴绘图,注意twinx曲线容易误导走势
1040
- if name_num == 1 and indicator_num == 2 and twinx:
1041
- t=names1[0]
1042
- i1=indicators1[0]; i2=indicators1[1]
1043
- df2_1=df[i1]; df2_2=df[i2]
1044
-
1045
- df2_1.rename(columns={t:i1},inplace=True)
1046
- df2_2.rename(columns={t:i2},inplace=True)
1047
-
1048
- titletxt="证券估值走势:"+t
1049
-
1050
- footnote1=""
1051
- if i1=='MV' or i2=='MV':
1052
- if preprocess=='none':
1053
- footnote1="注:市值金额:十亿,本币单位\n"
1054
-
1055
- todaydt = datetime.date.today()
1056
- footnote9="数据来源: Baidu/Stooq/FundDB/SWHY,"+str(todaydt)
1057
- footnote=footnote1+footnote9
1058
-
1059
- df2_1.rename(columns={i1:ectranslate(i1)},inplace=True)
1060
- df2_2.rename(columns={i2:ectranslate(i2)},inplace=True)
1061
-
1062
- colname1=label1=ectranslate(i1)
1063
- colname2=label2=ectranslate(i2)
1064
-
1065
- plot_line2(df2_1,'',colname1,label1, \
1066
- df2_2,'',colname2,label2, \
1067
- ylabeltxt='',titletxt=titletxt,footnote=footnote, \
1068
- twinx=twinx, \
1069
- resample_freq='D',loc1=loc1,loc2=loc2, \
1070
- color1='red',color2='blue',facecolor=facecolor, \
1071
- yline=attention_value,attention_value_area=attention_value_area, \
1072
- xline=attention_point,attention_point_area=attention_point_area, \
1073
- )
1074
-
1075
- return df
1076
-
1077
- # 绘制双线: 两只证券,一个指标。twinx双轴绘图
1078
- if name_num == 2 and indicator_num == 1 and twinx:
1079
- t1=names1[0]; t2=names1[1]
1080
- i=indicators1[0]
1081
- df2_1=pd.DataFrame(df[i,t1])[i]; df2_2=pd.DataFrame(df[i,t2])[i]
1082
- df2_1.rename(columns={t1:i},inplace=True)
1083
- df2_2.rename(columns={t2:i},inplace=True)
1084
-
1085
- #titletxt="证券估值走势:"+i
1086
- titletxt="证券估值走势:"+ectranslate(i)
1087
-
1088
- footnote1=""
1089
- if i=='MV':
1090
- if preprocess=='none':
1091
- footnote1="注:市值金额:十亿,本币单位\n"
1092
-
1093
- todaydt = datetime.date.today()
1094
- footnote9="数据来源: Baidu/Stooq/FundDB/SWHY,"+str(todaydt)
1095
- footnote=footnote1+footnote9
1096
-
1097
- colname1=i; label1=t1
1098
- colname2=i; label2=t2
1099
-
1100
- if twinx:
1101
- ylabeltxt=''
1102
- else:
1103
- #ylabeltxt=i
1104
- ylabeltxt=ectranslate(i)
1105
-
1106
- plot_line2(df2_1,'',colname1,label1, \
1107
- df2_2,'',colname2,label2, \
1108
- ylabeltxt=ylabeltxt,titletxt=titletxt,footnote=footnote, \
1109
- twinx=twinx, \
1110
- resample_freq='D',loc1=loc1,loc2=loc2, \
1111
- color1='red',color2='blue',facecolor=facecolor, \
1112
- yline=attention_value,attention_value_area=attention_value_area, \
1113
- xline=attention_point,attention_point_area=attention_point_area, \
1114
- )
1115
-
1116
- return df
1117
-
1118
- lang=check_language()
1119
- # 绘制多线:多只证券,一个指标。简单多线绘图
1120
- if name_num >= 2 and indicator_num == 1 and not twinx:
1121
- i=indicators1[0]
1122
- df2=df[i]
1123
-
1124
- titletxt="证券估值走势:"+ectranslate(i)
1125
-
1126
- footnote1=""
1127
- if i=='MV':
1128
- if preprocess=='none':
1129
- footnote1="注:市值金额:十亿,本币单位\n"
1130
-
1131
- todaydt = datetime.date.today()
1132
- footnote9="数据来源: Baidu/Stooq/FundDB/SWHY,"+str(todaydt)
1133
- footnote=footnote1+footnote9
1134
-
1135
- #ylabeltxt=i
1136
- ylabeltxt=ectranslate(i)
1137
-
1138
- # 标准化处理
1139
- dfs2,axhline_label,x_label,y_label,plus_sign=df_preprocess(df2,measure=indicators1, \
1140
- axhline_label='',x_label=footnote,y_label=ylabeltxt, \
1141
- preprocess=preprocess,scaling_option=scaling_option)
1142
-
1143
- draw_lines(dfs2,y_label=y_label,x_label=x_label, \
1144
- axhline_value=0,axhline_label=axhline_label, \
1145
- title_txt=titletxt,data_label=False, \
1146
- resample_freq='D',loc=loc1, \
1147
- annotate=annotate,annotate_value=annotate_value, \
1148
- band_area=band_area, \
1149
- plus_sign=plus_sign, \
1150
- facecolor=facecolor, \
1151
- attention_value=attention_value,attention_value_area=attention_value_area, \
1152
- attention_point=attention_point,attention_point_area=attention_point_area, \
1153
- mark_top=mark_top,mark_bottom=mark_bottom, \
1154
- mark_start=mark_start,mark_end=mark_end)
1155
-
1156
- return df
1157
-
1158
- # 绘制多线:一只证券,多个指标。简单多线绘图。可能数量级差异较大,意义有限
1159
- if name_num == 1 and indicator_num >= 2 and not twinx:
1160
- t=names1[0]
1161
- df2=None
1162
- for i in indicators1:
1163
- dft=pd.DataFrame(df[i,t])[i]
1164
- dft.rename(columns={t:i},inplace=True)
1165
-
1166
- if df2 is None:
1167
- df2=dft
1168
- else:
1169
- df2=pd.merge(df2,dft,left_index=True,right_index=True)
1170
-
1171
- df2.rename(columns={i:ectranslate(i)},inplace=True)
1172
-
1173
- titletxt="证券估值走势:"+t
1174
-
1175
- footnote1=''
1176
- if 'MV' in indicators1:
1177
- if preprocess=='none':
1178
- footnote1="注:市值金额:十亿,本币单位\n"
1179
-
1180
- todaydt = datetime.date.today()
1181
- footnote9="数据来源: Baidu/Stooq/FundDB/SWHY,"+str(todaydt)
1182
- footnote=footnote1+footnote9
1183
-
1184
- #ylabeltxt=''
1185
- ylabeltxt="估值"
1186
-
1187
- # 标准化处理
1188
- dfs2,axhline_label,x_label,y_label,plus_sign=df_preprocess(df2,measure=indicators1, \
1189
- axhline_label='',x_label=footnote,y_label=ylabeltxt, \
1190
- preprocess=preprocess,scaling_option=scaling_option)
1191
-
1192
- draw_lines(dfs2,y_label=y_label,x_label=x_label, \
1193
- axhline_value=0,axhline_label=axhline_label, \
1194
- title_txt=titletxt,data_label=False, \
1195
- resample_freq='D',loc=loc1,plus_sign=plus_sign, \
1196
- annotate=annotate,annotate_value=annotate_value, \
1197
- band_area=band_area, \
1198
- facecolor=facecolor, \
1199
- attention_value=attention_value,attention_value_area=attention_value_area, \
1200
- attention_point=attention_point,attention_point_area=attention_point_area, \
1201
- mark_top=mark_top,mark_bottom=mark_bottom, \
1202
- mark_start=mark_start,mark_end=mark_end)
1203
-
1204
- return df
1205
-
1206
-
1207
- #==============================================================================
1208
- if __name__=='__main__':
1209
- bank_big=find_peers_china('国有大型银行Ⅱ',top=25)
1210
- df=security_trend(bank_big,indicator='PE',start='MRY',graph=False)
1211
- indicator='PE'
1212
- base='601398.SS'
1213
-
1214
-
1215
- def print_valuation(df,indicator='PE',base='',facecolor='whitesmoke'):
1216
- """
1217
- 功能:显示同行估值数字,并进行对比
1218
- """
1219
- try:
1220
- df1=df[indicator]
1221
- except:
1222
- print(f" #Warning(print_valuation): unsupported indicator {indicator} in current dataframe")
1223
- return
1224
-
1225
- collist=list(df1)
1226
- base=base.upper()
1227
- base=ticker_name(base)
1228
- if not (base in collist):
1229
- """
1230
- print(" #Warning(print_valuation): invalid item",base,"for current dataframe")
1231
- print(" Valid items in current dataframe:\n",collist)
1232
- return
1233
- """
1234
- base=collist[0]
1235
-
1236
- df2=df1.T
1237
- latest_date=list(df2)[-1] #最后日期
1238
- col_latest_date=latest_date.strftime('%y-%m-%d')
1239
- start_date=list(df2)[0] #开始日期
1240
- col_start_date=start_date.strftime('%y-%m-%d')
1241
- """
1242
- col_mean="期间内"+indicator+'均值'
1243
- col_mean_rel=indicator+'均值相对倍数'
1244
- col_mean_pct=indicator+'均值分位数'
1245
- """
1246
- col_mean="期间内均值"
1247
- col_mean_rel='均值相对倍数'
1248
-
1249
- df2[col_mean]=df2.mean(axis=1)
1250
-
1251
- df2[col_mean]=df2[col_mean].apply(lambda x: round(x,2))
1252
-
1253
- df2.sort_values(col_mean,ascending=False,inplace=True)
1254
-
1255
- df3=df2[df2[col_mean] > 0]
1256
- diff=len(df2) - len(df3)
1257
- if diff > 0:
1258
- df3t=df2[df2[col_mean] <= 0]
1259
- diff_list=list(df3t.index)
1260
-
1261
- df3['均值排名']=range(len(df3))
1262
- df3['均值排名']=df3['均值排名'] + 1
1263
- df3['证券名称']=df3.index
1264
-
1265
- # 均值基准
1266
- base_value=df3[df3.index == base][col_mean].values[0]
1267
- df3[col_mean_rel]=df3[col_mean].apply(lambda x: round(x / base_value,2))
1268
-
1269
- # 最新值基准
1270
- base_value_latest=df3[df3.index == base][latest_date].values[0]
1271
- df3[col_latest_date]=df3[latest_date]
1272
- col_latest_rel='相对倍数@'+col_latest_date
1273
- df3[col_latest_rel]=df3[col_latest_date].apply(lambda x: round(x / base_value_latest,2))
1274
-
1275
- df3.sort_values(col_latest_date,ascending=False,inplace=True)
1276
- df3['排名@'+col_latest_date]=range(len(df3))
1277
- df3['排名@'+col_latest_date]=df3['排名@'+col_latest_date] + 1
1278
- df3.sort_values(col_mean,ascending=False,inplace=True)
1279
-
1280
- # 变化
1281
- df3['均值对比']=df3[col_mean_rel].apply(lambda x: '0%' if x == 1 else '+'+str(round((x-1)*100,2))+'%' if x >1 else '-'+str(round((1-x)*100,2))+'%')
1282
- df3['对比@'+col_latest_date]=df3[col_latest_rel].apply(lambda x: '0%' if x == 1 else '+'+str(round((x-1)*100,2))+'%' if x >1 else '-'+str(round((1-x)*100,2))+'%')
1283
-
1284
- df3['均值对比']=df3.apply(lambda x: '<---基准' if x['证券名称'] == base else x['均值对比'],axis=1)
1285
- df3['对比@'+col_latest_date]=df3.apply(lambda x: '<---基准' if x['证券名称'] == base else x['对比@'+col_latest_date],axis=1)
1286
-
1287
- #df4=df3[['序号','证券名称',col_mean,col_mean_rel,'均值对比',col_latest_date,col_latest_rel,'对比@'+col_latest_date]]
1288
- df4=df3[['证券名称',col_mean,'均值排名',col_latest_date,'排名@'+col_latest_date,col_mean_rel,col_latest_rel,'均值对比','对比@'+col_latest_date]]
1289
-
1290
- #titletxt="估值对比:"+ectranslate(indicator)+",降序排列"
1291
- titletxt="证券估值对比:{0}({1}),降序排列".format(ectranslate(indicator),indicator)
1292
- """
1293
- print("\n",titletxt,'\n')
1294
- alignlist=['left','right','center','right','center']+['right']*(len(list(df4))-5)
1295
- print(df4.to_markdown(index=False,tablefmt='simple',colalign=alignlist))
1296
- """
1297
- disph=df4.style.hide() #不显示索引列
1298
- dispp=disph.format(precision=2) #设置带有小数点的列精度调整为小数点后2位
1299
- #设置标题/列名
1300
- dispt=dispp.set_caption(titletxt).set_table_styles(
1301
- [{'selector':'caption', #设置标题
1302
- 'props':[('color','black'),('font-size','16px'),('font-weight','bold')]}, \
1303
- {'selector':'th.col_heading', #设置列名
1304
- 'props':[('color','black'),('text-align','center'),('margin','auto')]}])
1305
- #设置列数值对齐
1306
- dispf=dispt.set_properties(**{'text-align':'center'})
1307
- #设置前景背景颜色
1308
- #dispf2=dispf.set_properties(**{'background-color':facecolor,'color':fontcolor})
1309
- dispf2=dispf.set_properties(**{'background-color':facecolor})
1310
-
1311
- from IPython.display import display
1312
- display(dispf2)
1313
-
1314
- #print(" ")
1315
- if diff > 0:
1316
- print("【注】未列出"+str(diff)+"只估值为非正数的证券:"+str(diff_list))
1317
- import datetime; todaydt = datetime.date.today()
1318
- footnote="估值期间:"+col_start_date+"至"+col_latest_date+",数据来源: baidu/stooq/funddb/swhysc,"+str(todaydt)
1319
- print(footnote)
1320
-
1321
- return
1322
-
1323
-
1324
- #==============================================================================
1325
- if __name__=='__main__':
1326
- df=security_trend("00700.HK",start="MRY",power=8)
1327
- valuation_summary(df,column='Close',decimal=1)
1328
-
1329
- def valuation_summary(df,column='Close',decimal=1):
1330
- """
1331
- 功能:快速概括df中某列column的统计特点
1332
- """
1333
- if not (column in list(df)):
1334
- print(" #Warning: "+column+" is not a valid column of the dataframe")
1335
- return
1336
-
1337
- val_min=round(df[column].min(),decimal)
1338
- date_min=df[column].idxmin()
1339
- date_min=pd.to_datetime(date_min).strftime('%Y-%m-%d')
1340
-
1341
- val_max=round(df[column].max(),decimal)
1342
- date_max=df[column].idxmax()
1343
- date_max=pd.to_datetime(date_max).strftime('%Y-%m-%d')
1344
-
1345
- val_mean=df[column].mean()
1346
- val_std_pct=df[column].std() / val_mean
1347
- val_std_pct_str=str(round(val_std_pct*100,1))+'%'
1348
- val_median=round(df[column].median(),decimal)
1349
-
1350
- # 计算分位数
1351
- from scipy.stats import percentileofscore
1352
- sspos=lambda x:percentileofscore(df[column],x,kind='weak')
1353
- df['PCT']=df[column].apply(sspos)
1354
-
1355
- latest=round(df.tail(1)[column].values[0],decimal)
1356
- latest_pct=round(df.tail(1)['PCT'].values[0],1)
1357
- latest_date=pd.to_datetime(df.tail(1).index.values[0])
1358
- latest_date=latest_date.strftime('%Y-%m-%d')
1359
-
1360
- start_date=pd.to_datetime(df.head(1).index.values[0])
1361
- start_date=start_date.strftime('%Y-%m-%d')
1362
-
1363
- print('')
1364
- print("期间:从"+start_date+'至'+latest_date)
1365
- print("\n范围:最低"+str(val_min)+' @'+date_min,'\b,最高'+str(val_max)+' @'+date_max)
1366
- print('均值:',round(val_mean,decimal),'\b, 中位数:',val_median,end=', ')
1367
- print('波动率:',val_std_pct_str)
1368
-
1369
- print("\n末端:",latest,'\b, 分位数:',str(latest_pct)+'%, @'+latest_date)
1370
-
1371
- return
1372
-
1373
- #==============================================================================
1374
- #==============================================================================
1375
- #==============================================================================
1376
- #==============================================================================
1377
- #==============================================================================
1378
-