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,3307 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- 本模块功能:中国基金市场案例分析
4
- 所属工具包:证券投资分析工具SIAT
5
- SIAT:Security Investment Analysis Tool
6
- 创建日期:2020年10月17日
7
- 最新修订日期:2025年3月28日
8
- 作者:王德宏 (WANG Dehong, Peter)
9
- 作者单位:北京外国语大学国际商学院
10
- 版权所有:王德宏
11
- 用途限制:仅限研究与教学使用,不可商用!商用需要额外授权。
12
- 特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
13
- """
14
-
15
- #==============================================================================
16
- #关闭所有警告
17
- import warnings; warnings.filterwarnings('ignore')
18
- from siat.common import *
19
- from siat.translate import *
20
- from siat.grafix import *
21
- from siat.bond_base import *
22
- from siat.security_trend2 import *
23
- #==============================================================================
24
- def compare_fund_holding_china(ticker,quarters,rank=10,font_size='14px'):
25
- """
26
- 功能:套壳函数fund_stock_holding_compare_china
27
- """
28
- if len(quarters) < 2:
29
- print(" #Warning(compare_fund_holding_china): need 2 quarters to compare at",quarters)
30
- return None
31
- """
32
- if quarters[0] >= quarters[1]:
33
- print(" #Warning(compare_fund_holding_china):",quarters[0],"is supposed to be earlier than",quarters[1])
34
- return None
35
- """
36
- #保证较早的季度排在前面
37
- quarters.sort()
38
-
39
- df=fund_stock_holding_compare_china(fund=ticker,quarter1=quarters[0],quarter2=quarters[1], \
40
- rank=rank,font_size=font_size)
41
-
42
- return df
43
-
44
- if __name__=='__main__':
45
- fund='000592.SS'
46
- quarter1='2023Q4'
47
- quarter2='2024Q1'
48
-
49
- df=fund_stock_holding_compare_china(fund,quarter1,quarter2,rank=10)
50
-
51
- #比较两个季度之间的基金持仓变化
52
- def fund_stock_holding_compare_china(fund,quarter1,quarter2,rank=10, \
53
- font_size='14px'):
54
- """
55
- 功能:基金fund在两个季度quarter1和quarter2的持仓股票对比(股数和金额),前rank名股票
56
- 参数:
57
- fund,str,基金代码;
58
- quarter1,str,靠前的季度, 格式为 'YYYYQ1',例如: '2021Q2';
59
- quarter2,str,靠后的季度, 格式为 'YYYYQ1',例如: '2021Q2';
60
-
61
- 注意:监管仅要求基金披露前十大重仓股,因此其持仓比例之和一般小于100%;若大于100%,
62
- 则为基金以其净资产作为抵押加了杠杆融资,买进更多成份股,导致成份股总价值(基金总资产)超过了基金的净资产。
63
- 基金总资产 = 基金负债 + 基金净资产
64
- """
65
- print("Searching fund holding info, which may take time, please wait ...\n")
66
-
67
- import akshare as ak
68
- import pandas as pd
69
-
70
- code=fund[:6]
71
- s1=quarter1.upper()
72
- s2=quarter2.upper()
73
- years=[s1[0:4],s2[0:4]]
74
-
75
- s1_share = s1+'持股数'
76
- s2_share = s2+'持股数'
77
- s1_value = s1+'持仓市值'
78
- s2_value = s2+'持仓市值'
79
- s1_ratio = s1+'持仓比例'
80
- s2_ratio = s2+'持仓比例'
81
-
82
- """
83
- try:
84
- data = ak.fund_portfolio_hold_em(symbol=fund,date=years[0])
85
- except:
86
- print(" #Error(fund_stock_holding_compare_china): stock fund",fund,"not found or wrong year",years[0])
87
- return
88
- if len(data)==0:
89
- print(" #Error(fund_stock_holding_compare_china): stock fund",fund,"not found or wrong year",years[0])
90
- return
91
- """
92
-
93
- data=pd.DataFrame()
94
- for yr in years:
95
- try:
96
- df_tmp = ak.fund_portfolio_hold_em(symbol=code,date=yr)
97
- except:
98
- print(" #Error(fund_stock_holding_compare_china): wrong year",yr)
99
- break
100
-
101
- if len(df_tmp)==0:
102
- print(" #Error(fund_stock_holding_compare_china): stock fund",fund,"not found or wrong year",years[0])
103
- break
104
-
105
- if len(data)==0:
106
- data=df_tmp
107
- else:
108
- try:
109
- data = data.append(df_tmp)
110
- except:
111
- data = data._append(df_tmp)
112
-
113
- data.drop_duplicates(keep='first', inplace=True)
114
-
115
- data['季度']=data['季度'].apply(lambda x:x[:6])
116
- data['季度'] = data['季度'].str.replace('年','Q')
117
- data['占净值比例'] = pd.to_numeric(data['占净值比例'])
118
-
119
- df1 =data[data['季度']==s1]
120
- if len(df1)==0:
121
- print(" #Error(fund_stock_holding_compare_china): no data available for",s1)
122
- return
123
-
124
- df1 = df1[['股票代码', '股票名称','持股数','持仓市值','占净值比例']]
125
- df1 = df1.rename(columns={'持股数':s1_share,'持仓市值':s1_value,'占净值比例':s1_ratio})
126
- num1=len(df1)
127
-
128
- df2 =data[data['季度']==s2]
129
- if len(df2)==0:
130
- print(" #Error(fund_stock_holding_compare_china): no data available for",s2)
131
- return
132
-
133
- df2 = df2[['股票代码', '股票名称','持股数','持仓市值','占净值比例']]
134
- df2 = df2.rename(columns={'持股数':s2_share,'持仓市值':s2_value,'占净值比例':s2_ratio})
135
- num2=len(df2)
136
-
137
- df_merge = pd.merge(df1,df2,on=['股票代码','股票名称'],how='outer')
138
-
139
- # Q2 和 Q4,即半年度和年度报告,是需要披露全部持仓的
140
- # 合并后,在dataframe 中 NaN 的数据应为 0
141
-
142
- if s1.endswith('Q2') or s1.endswith('Q4'):
143
- df_merge[s1_share] = df_merge[s1_share].fillna(0)
144
- df_merge[s1_value] = df_merge[s1_value].fillna(0)
145
- df_merge[s1_ratio] = df_merge[s1_ratio].fillna(0)
146
-
147
- if s2.endswith('Q2') or s2.endswith('Q4'):
148
- df_merge[s2_share] = df_merge[s2_share].fillna(0)
149
- df_merge[s2_value] = df_merge[s2_value].fillna(0)
150
- df_merge[s2_ratio] = df_merge[s2_ratio].fillna(0)
151
-
152
- df_merge.fillna(0,inplace=True)
153
-
154
- df_merge['持股数变化'] = df_merge[s2_share] - df_merge[s1_share]
155
- df_merge['持仓比例变化'] = df_merge[s2_ratio] - df_merge[s1_ratio]
156
- df_merge['持仓市值变化'] = df_merge[s2_value] - df_merge[s1_value]
157
- df_merge = df_merge.sort_values(s2_value,ascending=False)
158
-
159
- #df_merge['股票名称'] = df_merge['股票名称_y']
160
- #df_merge.loc[df_merge['股票名称'].isna(),'股票名称'] = df_merge.loc[df_merge['股票名称'].isna(),'股票名称_x']
161
- df_merge = df_merge[['股票名称','股票代码',s1_share,s2_share,'持股数变化',s1_ratio,s2_ratio,'持仓比例变化',s1_value,s2_value,'持仓市值变化']]
162
-
163
- df_merge.reset_index(drop=True,inplace=True)
164
- if rank>0:
165
- df=df_merge.head(rank)
166
- else:
167
- df=df_merge.tail(-rank)
168
- """
169
- #持股数和持仓比例取整数
170
- df.fillna(0)
171
- try:
172
- df[s1_share]=df[s1_share].astype('int')
173
- except: pass
174
- try:
175
- df[s2_share]=df[s2_share].astype('int')
176
- except: pass
177
- try:
178
- df[s1_value]=df[s1_value].astype('int')
179
- except: pass
180
- try:
181
- df[s2_value]=df[s2_value].astype('int')
182
- except: pass
183
- df['持股数变化'] = df[s2_share] - df[s1_share]
184
- """
185
- #设置打印对齐
186
- pd.set_option('display.max_columns', 1000)
187
- pd.set_option('display.width', 1000)
188
- pd.set_option('display.max_colwidth', 1000)
189
- pd.set_option('display.unicode.ambiguous_as_wide', True)
190
- pd.set_option('display.unicode.east_asian_width', True)
191
-
192
- #获取基金名称
193
- """
194
- #names = ak.fund_em_fund_name()
195
- names = ak.fund_name_em()
196
- namedf=names[names['基金代码']==code]
197
- if len(namedf)==0:
198
- name=fund
199
- else:
200
- name=namedf['基金简称'].values[0]
201
- """
202
- name=get_fund_name_china2(fund)
203
-
204
- order='前'
205
- if rank <0:
206
- order='后'
207
- rank=-rank
208
-
209
- # 替换空值
210
- df.fillna('---')
211
- """
212
- print("===== 中国基金持仓股票分析:"+name+','+s1+"对比"+s2,"(按后者持仓比例高低排列,"+order+str(rank)+"名重仓股) =====\n")
213
- print(df.to_string(index=False))
214
- import datetime; today = datetime.date.today()
215
- print("\n*** 注:持股数为万股,持仓市值为万元,持仓比例为占基金资产净值比例%,包括A股与非A股")
216
- print(" 数据来源:天天基金/东方财富, 期间持仓股票总计"+str(len(df_merge))+"只,",today)
217
- """
218
- titletxt="基金持仓转移明细:"+name+'基金,'+s1+"对比"+s2+"(按后者持仓比例降序排列,"+order+str(rank)+"名重仓股)"
219
-
220
- footnote1="【注】持仓数单位为万股,持仓市值单位为万元,持仓比例为成份股价值为占基金资产净值%(以最新期间为准列示)\n"
221
- #footnote2=s1+'/'+s2+"期末持仓证券数"+str(num1)+'/'+str(num2)+"只"+'\n'
222
- footnote2='监管仅要求披露前十大重仓股,其持仓比例之和一般小于100%;若大于100%则为基金加了杠杆,总资产多于净资产\n'
223
- import datetime; todaydt = datetime.date.today()
224
- footnote9="数据来源:天天基金/东方财富,"+str(todaydt)+"统计"
225
- footnote=footnote1+footnote2+footnote9
226
-
227
- #调整字段顺序
228
- collist=list(df)
229
- df['序号']=df.index + 1
230
- df=df[['序号']+collist]
231
- """
232
- shares=[]; ratios=[]; values=[]
233
- for c in collist:
234
- if "持股数" in c:
235
- shares=shares+[c]
236
- if "持仓比例" in c:
237
- ratios=ratios+[c]
238
- if "持仓市值" in c:
239
- values=values+[c]
240
- collist1=['序号','股票名称','股票代码']+shares+ratios+values
241
- df=df[collist1]
242
- """
243
- df.replace(0,'---',inplace=True); df.replace('0','---',inplace=True)
244
-
245
- #确定表格字体大小
246
- titile_font_size=font_size
247
- heading_font_size=data_font_size=str(int(font_size.replace('px',''))-2)+'px'
248
-
249
- df_display_CSS(df,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=2, \
250
- first_col_align='center',second_col_align='left', \
251
- last_col_align='right',other_col_align='right', \
252
- titile_font_size=titile_font_size, \
253
- heading_font_size=heading_font_size, \
254
- data_font_size=data_font_size)
255
-
256
- return df_merge
257
-
258
- #==============================================================================
259
- def fund_holding_china(ticker,rank=10,pastyears=2,reverse=False,font_size='16px'):
260
- """
261
- 功能:套壳函数fund_stock_holding_rank_china
262
- """
263
- df,data=fund_stock_holding_rank_china(fund=ticker,rank=rank,year_num=pastyears, \
264
- reverse=reverse,font_size=font_size)
265
-
266
- return df,data
267
-
268
- if __name__=='__main__':
269
- fund='000592.SS'
270
- year_num=2
271
- rank=10
272
-
273
- df=fund_stock_holding_rank_china(fund,year_num=2)
274
-
275
- # 获取单只基金的十大股票名称信息
276
- def fund_stock_holding_rank_china(fund,rank=10,year_num=2, \
277
- reverse=False,font_size='16px'):
278
- """
279
- 基金的成份股持仓转移矩阵
280
- 比较股票型基金fund近year_num年持仓的前10大股票排名变化
281
- """
282
- print("Searching fund stock holding info, which takes time, please wait ...\n")
283
- code=fund[:6]
284
-
285
- import akshare as ak
286
- import pandas as pd
287
-
288
- import datetime; today = datetime.date.today()
289
- year_0_num=int(str(today)[0:4])
290
- years=[]
291
- for yr in range(0,year_num):
292
- yri=str(year_0_num - yr)
293
- years=years+[yri]
294
- years.sort(reverse=False)
295
- """
296
- #抓取第一年的信息
297
- data = ak.fund_portfolio_hold_em(symbol=fund,date=years[0])
298
- if len(data)==0:
299
- print(" #Error(fund_stock_holding_rank_china): stock fund",fund,"not found")
300
- return
301
- """
302
- data=pd.DataFrame()
303
- try:
304
- for yr in years:
305
- df_tmp = ak.fund_portfolio_hold_em(symbol=code,date=yr)
306
- try:
307
- data = data.append(df_tmp)
308
- except:
309
- data = data._append(df_tmp)
310
- except:
311
- years_1=[]
312
- for yr in years:
313
- yr_1=str(int(yr)-1)
314
- years_1=years_1+[yr_1]
315
-
316
- for yr in years_1:
317
- df_tmp = ak.fund_portfolio_hold_em(symbol=code,date=yr)
318
- try:
319
- data = data.append(df_tmp)
320
- except:
321
- data = data._append(df_tmp)
322
-
323
- data.drop_duplicates(keep='first', inplace=True)
324
-
325
- # data['季度']=data['季度'].apply(lambda x:x[:8])
326
- data['季度']=data['季度'].apply(lambda x:x[:6])
327
- data['季度'] = data['季度'].str.replace('年','Q')
328
- #data['占净值比例'] = pd.to_numeric(data['占净值比例'])
329
- #data.fillna(0,inplace=True)
330
- #data=data.replace('',0)
331
- data['占净值比例'] = pd.to_numeric(data['占净值比例'])
332
-
333
- # 序号中,有些是字符串,并且包含字符 “*”,需要替换,最后转换为数字
334
- data['序号'] = data['序号'].astype(str)
335
- data['序号'] = data['序号'].str.replace('\*','',regex=True)
336
- data['序号'] = pd.to_numeric(data['序号'])
337
-
338
- data = data.sort_values(['季度','持仓市值'],ascending=[True,False])
339
- #data.drop_duplicates(keep='first',inplace=True)
340
-
341
- yqlist=list(set(list(data['季度'])))
342
- yqlist.sort(reverse=False)
343
- import pandas as pd
344
- data2=pd.DataFrame()
345
-
346
- for yq in yqlist:
347
- dft=data[data['季度']==yq]
348
- dft.sort_values(by='占净值比例',ascending=False,inplace=True)
349
- dft.reset_index(drop=True,inplace=True)
350
- dft['序号']=dft.index + 1
351
- dft2=dft.head(rank)
352
-
353
- if len(data2)==0:
354
- data2=dft2
355
- else:
356
- try:
357
- data2=data2.append(dft2)
358
- except:
359
- data2=data2._append(dft2)
360
-
361
- # 合成信息
362
- data2['持股状况']=data2.apply(lambda x: x['股票名称']+'('+str(x['占净值比例'])+','+str(x['持股数'])+')',axis=1)
363
-
364
- df = data2.set_index(['序号','季度']).stack().unstack([1,2]).head(rank)
365
-
366
- #df = df.loc[:,(slice(None), '股票名称')] # 只选取 股票名称
367
- df = df.loc[:,(slice(None), '持股状况')] # 只选取 持股状况
368
-
369
- df = df.droplevel(None,axis=1)
370
- df.columns.name=None
371
- df.reset_index(inplace=True)
372
- """
373
- df['基金代码']=code
374
- cols = df.columns.tolist()
375
- cols = cols[:1] + cols[-1:] + cols[1:-1] # 将基金代码列名放前面
376
- df = df[cols]
377
- """
378
- #设置打印对齐
379
- pd.set_option('display.max_columns', 1000)
380
- pd.set_option('display.width', 1000)
381
- pd.set_option('display.max_colwidth', 1000)
382
- pd.set_option('display.unicode.ambiguous_as_wide', True)
383
- pd.set_option('display.unicode.east_asian_width', True)
384
-
385
- #获取基金名称
386
- """
387
- #names = ak.fund_em_fund_name()
388
- names = ak.fund_name_em()
389
- namedf=names[names['基金代码']==fund]
390
- if len(namedf)==0:
391
- name=fund
392
- else:
393
- name=namedf['基金简称'].values[0]
394
- """
395
- name=get_fund_name_china2(fund)
396
-
397
- #print("=== 基金持仓股票排行分析:"+name+",按照占净值比例高低排列 ===\n")
398
- titletxt="基金持仓转移矩阵:"+name+"基金,按照占净值比例降序排列,前"+str(rank)+"名重仓股"
399
- import datetime; todaydt = datetime.date.today()
400
- #print("\n*** 注:包括A股与非A股。持股结构:股票简称(占净值比例%,持股数万股),",str(todaydt))
401
- footnote="【注】持仓结构:证券简称(占净值比例%,持仓数万股),"+str(todaydt)+"统计"
402
-
403
- if reverse:
404
- #最新的日期放前面
405
- collist=list(df)
406
- collist.sort(reverse=True)
407
- df=df[collist]
408
-
409
- #确定表格字体大小
410
- titile_font_size=font_size
411
- heading_font_size=data_font_size=str(int(font_size.replace('px',''))-1)+'px'
412
-
413
- df_display_CSS(df,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=3, \
414
- first_col_align='center',second_col_align='left', \
415
- last_col_align='left',other_col_align='left', \
416
- titile_font_size=titile_font_size, \
417
- heading_font_size=heading_font_size, \
418
- data_font_size=data_font_size)
419
-
420
- """
421
- alignlist=['center']+['left']*(len(list(df))-1)
422
- print(df.to_markdown(index=False,tablefmt='plain',colalign=alignlist))
423
- #print(df.to_string(index=False))
424
- """
425
-
426
- return df,data
427
-
428
- #==============================================================================
429
- if __name__=='__main__':
430
- fund='180801'
431
- rank=10
432
-
433
- def reits_jsl_china(fund='',rank=10):
434
- """
435
- 功能:REITs基金信息概述和列表
436
- 目前不能正常工作,因为集思录数据源现在需要会员登陆才能显示和下载信息
437
- """
438
- import akshare as ak
439
- try:
440
- df1 = ak.reits_info_jsl()
441
- df2 = ak.reits_realtime_em()
442
- except:
443
- print("Sorry, data source rejected access")
444
- return None
445
-
446
- #合成基金类型信息
447
- import pandas as pd
448
- df = pd.merge(df1,df2,on = ['代码'],how='left')
449
- df.rename(columns={'涨幅':'涨幅%','成交额_x':'成交额(万元)','折价率':'折价率%','规模':'规模(亿元)','剩余年限':'剩余年限(年)','涨跌幅':'涨跌幅%'}, inplace=True)
450
- num=len(df)
451
-
452
- df.sort_values(by=['昨收'],ascending=False,inplace=True)
453
- df.reset_index(drop=True,inplace=True)
454
- import datetime
455
- today = datetime.date.today()
456
-
457
- dfa=df[df['代码']==fund]
458
- # 未找到
459
- if len(dfa)==0:
460
- if rank > 0:
461
- dfa=df.head(rank)
462
- else:
463
- dfa=df.tail(-rank)
464
- dfb=dfa[['代码','名称','昨收','规模(亿元)','到期日']]
465
-
466
- #设置打印对齐
467
- pd.set_option('display.max_columns', 1000)
468
- pd.set_option('display.width', 1000)
469
- pd.set_option('display.max_colwidth', 1000)
470
- pd.set_option('display.unicode.ambiguous_as_wide', True)
471
- pd.set_option('display.unicode.east_asian_width', True)
472
-
473
- order='前'
474
- if rank <0:
475
- order='后'
476
- rank=-rank
477
- print("\n===== 中国REITs基金列表(按最新价高低排列,"+order+str(rank)+"名) =====\n")
478
- print(dfb)
479
-
480
- print("*** 数据来源:东方财富/集思录, 总计"+str(num)+"只REITs基金,",today)
481
- return dfb
482
-
483
- #单列一只基金的具体信息
484
- collist=['代码','简称','名称','全称','项目类型','基金公司','规模(亿元)','到期日','剩余年限(年)','净值','净值日期','现价','涨幅%','开盘价','最高价','最低价','昨收','成交额(万元)']
485
- maxcollen=0
486
- for i in collist:
487
- ilen=hzlen(i)
488
- if maxcollen < ilen:
489
- maxcollen=ilen
490
-
491
- dfb=dfa[collist]
492
- print("\n===== 中国REITs基金详情(代码"+fund+") =====\n")
493
- for i in collist:
494
- print(i,' '*(maxcollen-hzlen(i))+':',dfb[i].values[0])
495
-
496
- print("*** 数据来源:东方财富/集思录,",today)
497
- return dfb
498
-
499
- #==============================================================================
500
- def reit_rank_china(indicator='最新价',rank=5):
501
- """
502
- 功能:套壳函数reits_list_china
503
- """
504
-
505
- df=reits_list_china(indicator=indicator,rank=rank)
506
-
507
- return df
508
-
509
-
510
- if __name__=='__main__':
511
- rank=10
512
-
513
- df=reits_list_china(rank=10)
514
-
515
- def reits_list_china(indicator='最新价',rank=5):
516
- """
517
- 功能:REITs基金信息概述和列表
518
- 目前能正常工作
519
- """
520
- import akshare as ak
521
- import math
522
- try:
523
- df2 = ak.reits_realtime_em()
524
- except:
525
- print(" #Error(reits_profile_china): akshare does not work properly now")
526
- return None
527
- df2.drop('序号', axis=1, inplace=True)
528
- #使用-999标记空缺值,避免后续处理出错,同时避免与真正的0混淆
529
- df2.fillna(-999,inplace=True)
530
- #df2['成交额']=df2['成交额'].apply(lambda x: int(x) if not math.isnan(x) else x)
531
- df2['成交额']=df2['成交额'].apply(lambda x: int(x))
532
- df2['成交量']=df2['成交量'].apply(lambda x: int(x))
533
-
534
- df2=df_swap_columns(df2, col1='代码', col2='名称')
535
- num=len(df2)
536
-
537
- indicatorlist=list(df2)
538
- if indicator not in indicatorlist:
539
- print(" #Error(reits_list_china):",indicator,"is not supported")
540
- print(" Supported indicators:",indicatorlist)
541
- return None
542
-
543
- #df2.indicator_values(by=['昨收'],ascending=False,inplace=True)
544
- df2.sort_values(by=[indicator],ascending=False,inplace=True)
545
- df2.replace(-999,"---",inplace=True)
546
-
547
- df2.reset_index(drop=True,inplace=True)
548
- df2=df2[df2[indicator] != "---"]
549
- num1=len(df2)
550
-
551
- collist=list(df2)
552
-
553
- for i in ['名称','代码',indicator]:
554
- collist.remove(i)
555
- collist1=['名称','代码',indicator]+collist
556
-
557
- df2['序号']=df2.index + 1
558
- df2=df2[['序号']+collist1]
559
- """
560
- #设置打印对齐
561
- pd.set_option('display.max_columns', 1000)
562
- pd.set_option('display.width', 1000)
563
- pd.set_option('display.max_colwidth', 1000)
564
- pd.set_option('display.unicode.ambiguous_as_wide', True)
565
- pd.set_option('display.unicode.east_asian_width', True)
566
- """
567
- if rank > 0:
568
- order='前'
569
- dfb=df2.head(rank)
570
- else:
571
- order='后'
572
- rank=-rank
573
- dfb=df2.tail(rank)
574
-
575
- #print("\n===== 中国REITs基金列表(按最新价高低排列,"+order+str(rank)+"名) =====\n")
576
- titletxt="中国REITs基金列表(按"+indicator+"降序排列,"+order+str(rank)+"名)"
577
- """
578
- print(dfb.to_string(index=False))
579
- """
580
- #print('') #在标题与表格之间空一行
581
- """
582
- alignlist=['right','center','left']+['right']*9
583
- try:
584
- print(dfb.to_markdown(index=False,tablefmt='plain',colalign=alignlist))
585
- except:
586
- #解决汉字编码gbk出错问题
587
- print_df=dfb.to_markdown(index=False,tablefmt='plain',colalign=alignlist)
588
- print_df2=print_df.encode("utf-8",errors="strict")
589
- print(print_df2)
590
- """
591
- import datetime; todaydt = datetime.date.today()
592
- #print("\n*** 数据来源:东方财富, 总计"+str(num)+"只REITs基金,",today)
593
- if num == num1 or order=='前':
594
- footnote="数据来源:新浪财经/天天基金,共找到"+str(num)+"只REITs基金,"+str(todaydt)
595
- else:
596
- footnote="数据来源:新浪财经/天天基金,共找到"+str(num)+"只REITs基金(其中"+str(num-num1)+"只没有"+indicator+"信息),"+str(todaydt)
597
-
598
- df_display_CSS(dfb,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=3, \
599
- first_col_align='center',second_col_align='left', \
600
- last_col_align='right',other_col_align='right', \
601
- titile_font_size='16px',heading_font_size='15px', \
602
- data_font_size='15px')
603
-
604
- return df2
605
-
606
- #==============================================================================
607
-
608
- if __name__=='__main__':
609
- fund_type='全部类型'
610
- fund_type='债券型'
611
- printout=True
612
-
613
- def pof_list_china(rank=10,fund_type='全部类型',printout=True):
614
- """
615
- 功能:抓取公募基金列表,按照基金类型列表,按照基金名称拼音排序
616
- """
617
- print("Searching for publicly offering fund (POF) information in China ...")
618
- import akshare as ak
619
-
620
- #基金基本信息:基金代码,基金简称,基金类型
621
- #df = ak.fund_em_fund_name()
622
- df = ak.fund_name_em()
623
-
624
- df.sort_values(by=['拼音全称'],na_position='first',inplace=True)
625
- df.drop_duplicates(subset=['基金代码','基金类型'], keep='first',inplace=True)
626
- df=df[df['基金类型'] != '']
627
- df['基金类型']=df['基金类型'].apply(lambda x: x.upper())
628
-
629
- #获取基金类型列表,并去掉重复项
630
- typelist=list(set(list(df['基金类型'])))
631
- #判断类型是否支持
632
- matchtype=False
633
- for t in typelist+['全部类型']:
634
- if fund_type in t:
635
- matchtype=True
636
- break
637
-
638
- if not matchtype:
639
- print(" #Error(fund_list_china): unsupported fund type:",fund_type)
640
- print(" Supported fund_type:",typelist+['全部类型'])
641
- return None
642
-
643
- #摘取选定的基金类型
644
- if fund_type != '全部类型':
645
- #df2=df[df['基金类型']==fund_type]
646
- df2=df[df['基金类型'].apply(lambda x: fund_type in x)]
647
- else:
648
- df2=df
649
-
650
- df3=df2[['基金简称','基金代码','基金类型']]
651
- df3.reset_index(drop=True,inplace=True)
652
-
653
- #打印种类数量信息
654
- if printout:
655
- num=len(df3)
656
- if fund_type != '全部类型':
657
- print(texttranslate("共找到")+str(num)+texttranslate("支基金, 类型为")+fund_type)
658
- return df3
659
-
660
- titletxt="中国公募基金的类型与分布(前"+str(rank)+"名)"
661
- footnote1="共有"+str(len(typelist))+"种类型,"+str("{:,}".format(num))+'支基金\n'
662
-
663
- maxlen=0
664
- for t in typelist:
665
- tlen=hzlen(t)
666
- if tlen > maxlen: maxlen=tlen
667
- maxlen=maxlen+1
668
-
669
- #排序
670
- dfg0=pd.DataFrame(df.groupby("基金类型").size())
671
- dfg0.sort_values(by=[0], ascending=False, inplace=True)
672
- dfg=dfg0.head(rank)
673
-
674
- typelist2=list(dfg.index)
675
- try:
676
- typelist2.remove('')
677
- except:
678
- pass
679
-
680
- dfg.rename(columns={0:'基金数量'}, inplace=True)
681
- dfg['数量占比']=dfg['基金数量'].apply(lambda x: str(round(x/num*100,3))+'%')
682
- dfg.reset_index(inplace=True)
683
-
684
- collist=list(dfg)
685
- dfg['序号']=dfg.index+1
686
- dfg=dfg[['序号']+collist]
687
-
688
- footnote2="表中类型的数量占比为"+str(round(dfg['基金数量'].sum()/num*100,2))+"%\n"
689
- import datetime; todaydt = datetime.date.today()
690
- footnote9="数据来源:东方财富/天天基金,"+str(todaydt)
691
- footnote=footnote1+footnote2+footnote9
692
-
693
- df_display_CSS(dfg,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=3, \
694
- first_col_align='center',second_col_align='left', \
695
- last_col_align='right',other_col_align='right', \
696
- titile_font_size='16px',heading_font_size='15px', \
697
- data_font_size='15px')
698
-
699
- return df3
700
-
701
- if __name__=='__main__':
702
- df=pof_list_china()
703
-
704
- #==============================================================================
705
- if __name__=='__main__':
706
- df=get_oef_rank_china()
707
-
708
- def get_oef_rank_china():
709
- """
710
- 功能:中国开放式基金排名,单位净值,累计净值,手续费
711
- 不分类
712
- """
713
-
714
- print("Searching for open-ended fund (OEF) information in China ...")
715
-
716
- import pandas as pd
717
- import akshare as ak
718
-
719
- #获取开放式基金实时信息
720
- try:
721
- print(" Looking for OEF net value information ...")
722
- df1 = ak.fund_open_fund_daily_em()
723
- except:
724
- print(" #Error(oef_rank_china): data source tentatively busy or unavailable, try later")
725
- return None
726
-
727
- collist=list(df1)
728
- nvname1=collist[2]
729
- nvname1_num_all=len(df1)
730
- nvname1_num_eq=len(df1[df1[nvname1]==''])
731
- nvname1_ratio_eq=nvname1_num_eq / nvname1_num_all
732
-
733
- nvname2=collist[3]
734
- #if df1[nvname1].eq('').all():
735
- if nvname1_ratio_eq > 0.5: #空缺率超过50%?
736
- nvname1=collist[4]
737
- nvname2=collist[5]
738
- nvdate=nvname1[:10]
739
-
740
- df1x=df1[df1[nvname1] != '']
741
-
742
- #修改列名
743
- df1x.rename(columns={nvname1:'单位净值',nvname2:'累计净值'}, inplace=True)
744
- df1c=df1x[['基金代码','基金简称','单位净值','累计净值','日增长率','申购状态','赎回状态','手续费']]
745
-
746
- #获取所有公募基金类型信息
747
- print(" Looking for OEF category information ...")
748
- df2 = ak.fund_name_em()
749
-
750
- print(" Analyzing OEF query requests ...")
751
- df2a=df2[['基金代码','基金类型']]
752
-
753
- #合成基金类型信息
754
- df3 = pd.merge(df1c,df2a,on = ['基金代码'],how='left')
755
-
756
- df3.fillna(0,inplace=True)
757
- df3=df3.replace('',0)
758
- df3['单位净值']=df3['单位净值'].astype('float')
759
- df3['累计净值']=df3['累计净值'].astype('float')
760
- df3['日增长率']=df3['日增长率'].astype('float')
761
-
762
- # 避免该字段出现非字符串类型引起后续出错
763
- df3['基金类型']=df3['基金类型'].astype(str)
764
- df3['净值日期']=nvdate
765
-
766
- print("Successfully retrieved",len(df3),"OEF products on",nvdate)
767
-
768
- return df3
769
-
770
- #==============================================================================
771
- if __name__=='__main__':
772
- fund_type='全部类型'
773
- fund_type='QDII'
774
- fund_type='REIT'
775
- fund_type='FOF'
776
- fund_type='LOF'
777
- fund_type='FOF-LOF'
778
- fund_type='MOM'
779
-
780
- rank=5
781
- indicator='单位净值'
782
-
783
- qdii=oef_rank_china2(df,fund_type='QDII',rank=5)
784
-
785
- def oef_rank_china2(df,fund_type='全部类型',rank=5,indicator='单位净值'):
786
- """
787
- 功能:中国开放式基金排名,单位净值,累计净值,手续费
788
- 仅分类用
789
- """
790
-
791
- typelist=['单位净值','累计净值','手续费','增长率']
792
- if indicator not in typelist:
793
- print(" #Error(oef_rank_china2): unsupported indicator",indicator)
794
- print(" Supported indicators:",typelist)
795
- return None
796
-
797
- nvdate=df['净值日期'].values[0]
798
-
799
- #过滤基金类型
800
- if fund_type not in ['全部类型','','all']:
801
- fundtypelist=list(set(list(df['基金类型'])))
802
- try: fundtypelist.remove('0')
803
- except: pass
804
-
805
- fundtypelist=fundtypelist+['LOF','FOF-LOF','REITs','REIT','MOM']
806
- #检查基金类型是否存在
807
- found=False
808
- for ft in fundtypelist:
809
- if ft==0: continue
810
- if fund_type in ft:
811
- found=True
812
- break
813
-
814
- #未找到基金类型
815
- if not found:
816
- print(" Notice: unpredefined fund type",fund_type)
817
- print(" Predefined fund types:")
818
- fundtypelist.sort(reverse=True)
819
- printlist(fundtypelist,numperline=5,beforehand=' '*4,separator=' ')
820
- print(" Continue to search key word",fund_type,"among fund type and fund name ...")
821
- #return None
822
-
823
- df.dropna(inplace=True)
824
-
825
- df['基金类型s']=False
826
- df['基金类型s']=df.apply(lambda x: True if fund_type in x['基金类型'] else x['基金类型s'],axis=1)
827
- df['基金类型s']=df.apply(lambda x: True if fund_type in x['基金简称'] else x['基金类型s'],axis=1)
828
-
829
- if fund_type == 'QDII':
830
- df['基金类型s']=df.apply(lambda x: False if '不含' in x['基金类型'] else x['基金类型s'],axis=1)
831
-
832
- if fund_type == 'FOF':
833
- df['基金类型s']=df.apply(lambda x: True if (fund_type in x['基金类型'] or fund_type in x['基金简称']) else x['基金类型s'],axis=1)
834
- #df['基金类型s']=df.apply(lambda x: False if ('LOF' in x['基金类型'] or 'LOF' in x['基金简称']) else x['基金类型s'],axis=1)
835
-
836
- if fund_type == 'LOF':
837
- df['基金类型s']=df.apply(lambda x: True if (fund_type in x['基金类型'] or fund_type in x['基金简称']) else x['基金类型s'],axis=1)
838
- #df['基金类型s']=df.apply(lambda x: False if ('FOF' in x['基金类型'] or 'FOF' in x['基金简称']) else x['基金类型s'],axis=1)
839
-
840
- if fund_type == 'FOF-LOF':
841
- df['基金类型s']=df.apply(lambda x: True if (fund_type in x['基金类型'] or fund_type in x['基金简称']) else x['基金类型s'],axis=1)
842
-
843
-
844
- df=df[df['基金类型s']==True]
845
-
846
- num=len(df)
847
- if num==0:
848
- print("Sorry, no OEF products found in China with key word",fund_type)
849
- return None
850
-
851
- if indicator == '单位净值':
852
- df['单位净值']=df['单位净值'].apply(lambda x: round(x,2))
853
- df.sort_values(by=['单位净值'],ascending=False,inplace=True)
854
- #dfprint=df[['基金简称','基金代码','基金类型','单位净值','申购状态','赎回状态']]
855
- dfprint=df[['基金简称','基金代码','基金类型','单位净值','累计净值']]
856
- #print(texttranslate("\n===== 中国开放式基金排名:单位净值 ====="))
857
- titletxt="中国开放式基金排名:单位净值"
858
-
859
- if indicator == '累计净值':
860
- df['累计净值']=df['累计净值'].apply(lambda x: round(x,2))
861
- df.sort_values(by=['累计净值'],ascending=False,inplace=True)
862
- #dfprint=df[['基金简称','基金代码','基金类型','累计净值','申购状态','赎回状态']]
863
- dfprint=df[['基金简称','基金代码','基金类型','累计净值','单位净值']]
864
- #print(texttranslate("\n===== 中国开放式基金排名:累计净值 ====="))
865
- titletxt="中国开放式基金排名:累计净值"
866
-
867
- if indicator == '手续费':
868
- try:
869
- df['手续费'] = df['手续费'].astype(str)
870
- df.sort_values(by=['手续费'],ascending=False,inplace=True)
871
- except: pass
872
- #dfprint=df[['基金简称','基金代码','基金类型','手续费','申购状态','赎回状态']]
873
- dfprint=df[['基金简称','基金代码','基金类型','手续费','单位净值']]
874
- #print(texttranslate("\n===== 中国开放式基金排名:手续费 ====="))
875
- titletxt="中国开放式基金排名:手续费"
876
-
877
- if indicator == '增长率':
878
- df.sort_values(by=['日增长率'],ascending=False,inplace=True)
879
- #dfprint=df[['基金简称','基金代码','基金类型','日增长率','申购状态','赎回状态']]
880
- dfprint=df[['基金简称','基金代码','基金类型','日增长率','单位净值']]
881
- #print(texttranslate("\n===== 中国开放式基金排名:增长率% ====="))
882
- titletxt="中国开放式基金排名:增长率%"
883
-
884
- df=df.replace(0,'--')
885
-
886
- #重新设置序号
887
- dfprint.dropna(inplace=True)
888
- dfprint.reset_index(drop=True,inplace=True)
889
- dfprint.index=dfprint.index + 1
890
-
891
- collist=list(dfprint)
892
- dfprint['序号']=dfprint.index
893
- dfprint=dfprint[['序号']+collist]
894
-
895
- if rank >= 0:
896
- dfprint10=dfprint.head(rank)
897
- order="前"
898
- else:
899
- dfprint10=dfprint.tail(-rank)
900
- order="后"
901
- titletxt=titletxt+"("+order+str(abs(rank))+"名,降序排列)"
902
- footnote1="披露净值的开放式基金数量:"+str(num)+','
903
- footnote2="基金类型:"+str(fund_type)+'\n'
904
-
905
- footnote3="净值日期:"+str(nvdate)+','
906
-
907
- import datetime; todaydt = datetime.date.today()
908
- #footnote4="数据来源:东方财富/天天基金,"+str(todaydt)
909
- footnote4="数据来源:新浪财经/天天基金\n"
910
-
911
- import time; current_time = time.localtime()
912
- formatted_hour = time.strftime("%H", current_time)
913
- footnote5=''
914
- if (formatted_hour >= '18' or formatted_hour <= '06') and not is_weekend(todaydt):
915
- footnote5="注意:此时若为数据源更新时段,获取的信息可能不全\n"
916
-
917
- footnote=footnote1+footnote2+footnote3+footnote4+footnote5
918
-
919
- df_display_CSS(dfprint10,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=4, \
920
- first_col_align='center',second_col_align='left', \
921
- last_col_align='right',other_col_align='right', \
922
- titile_font_size='16px',heading_font_size='15px', \
923
- data_font_size='15px')
924
-
925
- return df
926
- #==============================================================================
927
-
928
- if __name__=='__main__':
929
- indicator='单位净值'
930
-
931
- fund_type='股票型'
932
- fund_type='FOF'
933
- fund_type='LOF'
934
- fund_type='FOF-LOF'
935
- fund_type='QDII'
936
-
937
- rank=10
938
-
939
-
940
- def oef_rank_china(indicator='单位净值',fund_type='全部类型',rank=5):
941
- """
942
- 功能:中国开放式基金排名,单位净值,累计净值,手续费
943
- """
944
- info_type=indicator
945
-
946
- typelist=['单位净值','累计净值','手续费','增长率']
947
- if info_type not in typelist:
948
- print(" #Error(oef_rank_china): unsupported indicator",info_type)
949
- print(" Supported indicators:",typelist)
950
- return None
951
-
952
- print("Searching for open-ended fund (OEF) information in China ...")
953
- import akshare as ak
954
-
955
- #获取开放式基金实时信息
956
- try:
957
- print(" Looking for OEF net value information ...")
958
- df1 = ak.fund_open_fund_daily_em()
959
- except:
960
- print(" #Error(oef_rank_china): data source tentatively busy or unavailable, try later")
961
- return None
962
-
963
- collist=list(df1)
964
- nvname1=collist[2]
965
- nvname1_num_all=len(df1)
966
- nvname1_num_eq=len(df1[df1[nvname1]==''])
967
- nvname1_ratio_eq=nvname1_num_eq / nvname1_num_all
968
-
969
- nvname2=collist[3]
970
- #if df1[nvname1].eq('').all():
971
- if nvname1_ratio_eq > 0.5: #空缺率超过50%?
972
- nvname1=collist[4]
973
- nvname2=collist[5]
974
- nvdate=nvname1[:10]
975
-
976
- df1x=df1[df1[nvname1] != '']
977
-
978
- #修改列名
979
- df1x.rename(columns={nvname1:'单位净值',nvname2:'累计净值'}, inplace=True)
980
- #df1a=df1.drop(df1[df1['单位净值']==''].index)
981
- #df1b=df1a.drop(df1a[df1a['累计净值']==''].index)
982
- df1c=df1x[['基金代码','基金简称','单位净值','累计净值','日增长率','申购状态','赎回状态','手续费']]
983
-
984
-
985
- #获取所有公募基金类型信息
986
- #df2 = ak.fund_em_fund_name()
987
- print(" Looking for OEF category information ...")
988
- df2 = ak.fund_name_em()
989
-
990
- print(" Analyzing OEF query requests ...")
991
- df2a=df2[['基金代码','基金类型']]
992
-
993
- #合成基金类型信息
994
- import pandas as pd
995
- import numpy as np
996
- df3 = pd.merge(df1c,df2a,on = ['基金代码'],how='left')
997
-
998
- df3.fillna(0,inplace=True)
999
- df3=df3.replace('',0)
1000
- df3['单位净值']=df3['单位净值'].astype('float')
1001
- df3['累计净值']=df3['累计净值'].astype('float')
1002
- df3['日增长率']=df3['日增长率'].astype('float')
1003
-
1004
- """
1005
- df=df3[(df3['基金类型'] is not np.nan) and (df3['基金类型'] != 0)]
1006
- """
1007
- # 避免该字段出现非字符串类型引起后续出错
1008
- df3['基金类型']=df3['基金类型'].astype(str)
1009
- df=df3
1010
-
1011
- #过滤基金类型
1012
- if fund_type != '全部类型':
1013
- fundtypelist=list(set(list(df['基金类型'])))
1014
- try: fundtypelist.remove('0')
1015
- except: pass
1016
-
1017
- fundtypelist=fundtypelist+['LOF','FOF-LOF','REITs','REIT','MOM']
1018
- """
1019
- while np.nan in fundtypelist:
1020
- fundtypelist.remove(np.nan)
1021
- while 0 in fundtypelist:
1022
- fundtypelist.remove(0)
1023
- """
1024
- #检查基金类型是否存在
1025
- found=False
1026
- for ft in fundtypelist:
1027
- if ft==0: continue
1028
- if fund_type in ft:
1029
- found=True
1030
- break
1031
-
1032
- #未找到基金类型
1033
- if not found:
1034
- print(" #Error(oef_rank_china): unsupported fund type",fund_type)
1035
- print(" Supported fund types:",fundtypelist)
1036
- return None
1037
-
1038
- #df.dropna(inplace=True)
1039
- fund_filter=lambda x: fund_type in x
1040
- df['基金类型s']=df['基金类型'].apply(fund_filter)
1041
- df['基金类型s']=df['基金简称'].apply(fund_filter)
1042
-
1043
- if fund_type == 'QDII':
1044
- df['基金类型s']=df.apply(lambda x: False if '不含' in x['基金类型'] else x['基金类型s'],axis=1)
1045
-
1046
- if fund_type == 'FOF':
1047
- df['基金类型s']=df.apply(lambda x: True if (fund_type in x['基金类型'] or fund_type in x['基金简称']) else x['基金类型s'],axis=1)
1048
- #df['基金类型s']=df.apply(lambda x: False if ('LOF' in x['基金类型'] or 'LOF' in x['基金简称']) else x['基金类型s'],axis=1)
1049
-
1050
- if fund_type == 'LOF':
1051
- df['基金类型s']=df.apply(lambda x: True if (fund_type in x['基金类型'] or fund_type in x['基金简称']) else x['基金类型s'],axis=1)
1052
- #df['基金类型s']=df.apply(lambda x: False if ('FOF' in x['基金类型'] or 'FOF' in x['基金简称']) else x['基金类型s'],axis=1)
1053
-
1054
- if fund_type == 'FOF-LOF':
1055
- df['基金类型s']=df.apply(lambda x: True if (fund_type in x['基金类型'] or fund_type in x['基金简称']) else x['基金类型s'],axis=1)
1056
-
1057
-
1058
- df=df[df['基金类型s']==True]
1059
-
1060
- num=len(df)
1061
-
1062
- if info_type == '单位净值':
1063
- df['单位净值']=df['单位净值'].apply(lambda x: round(x,2))
1064
- df.sort_values(by=['单位净值'],ascending=False,inplace=True)
1065
- #dfprint=df[['基金简称','基金代码','基金类型','单位净值','申购状态','赎回状态']]
1066
- dfprint=df[['基金简称','基金代码','基金类型','单位净值','累计净值']]
1067
- #print(texttranslate("\n===== 中国开放式基金排名:单位净值 ====="))
1068
- titletxt="中国开放式基金排名:单位净值"
1069
-
1070
- if info_type == '累计净值':
1071
- df['累计净值']=df['累计净值'].apply(lambda x: round(x,2))
1072
- df.sort_values(by=['累计净值'],ascending=False,inplace=True)
1073
- #dfprint=df[['基金简称','基金代码','基金类型','累计净值','申购状态','赎回状态']]
1074
- dfprint=df[['基金简称','基金代码','基金类型','累计净值','单位净值']]
1075
- #print(texttranslate("\n===== 中国开放式基金排名:累计净值 ====="))
1076
- titletxt="中国开放式基金排名:累计净值"
1077
-
1078
- if info_type == '手续费':
1079
- df.sort_values(by=['手续费'],ascending=False,inplace=True)
1080
- #dfprint=df[['基金简称','基金代码','基金类型','手续费','申购状态','赎回状态']]
1081
- dfprint=df[['基金简称','基金代码','基金类型','手续费','单位净值']]
1082
- #print(texttranslate("\n===== 中国开放式基金排名:手续费 ====="))
1083
- titletxt="中国开放式基金排名:手续费"
1084
-
1085
- if info_type == '增长率':
1086
- df.sort_values(by=['日增长率'],ascending=False,inplace=True)
1087
- #dfprint=df[['基金简称','基金代码','基金类型','日增长率','申购状态','赎回状态']]
1088
- dfprint=df[['基金简称','基金代码','基金类型','日增长率','单位净值']]
1089
- #print(texttranslate("\n===== 中国开放式基金排名:增长率% ====="))
1090
- titletxt="中国开放式基金排名:增长率%"
1091
-
1092
- df=df.replace(0,'--')
1093
-
1094
- #设置打印对齐
1095
- pd.set_option('display.max_columns', 1000)
1096
- pd.set_option('display.width', 1000)
1097
- pd.set_option('display.max_colwidth', 1000)
1098
- pd.set_option('display.unicode.ambiguous_as_wide', True)
1099
- pd.set_option('display.unicode.east_asian_width', True)
1100
-
1101
- dfprint.dropna(inplace=True)
1102
- dfprint.reset_index(drop=True,inplace=True)
1103
- dfprint.index=dfprint.index + 1
1104
-
1105
- collist=list(dfprint)
1106
- dfprint['序号']=dfprint.index
1107
- dfprint=dfprint[['序号']+collist]
1108
-
1109
- if rank >= 0:
1110
- dfprint10=dfprint.head(rank)
1111
- order="前"
1112
- else:
1113
- dfprint10=dfprint.tail(-rank)
1114
- order="后"
1115
- titletxt=titletxt+"("+order+str(abs(rank))+"名,降序排列)"
1116
- #print(dfprint10.to_string(index=False))
1117
- """
1118
- print(dfprint10)
1119
- """
1120
- """
1121
- alignlist=['left','left']+['center']*(len(list(amac_sum_df.head(10)))-3)+['right']
1122
- """
1123
- """
1124
- print('') #在标题与表格之间空一行
1125
- alignlist=['right','left','center','center','right','center','center']
1126
- try:
1127
- print(dfprint10.to_markdown(index=True,tablefmt='plain',colalign=alignlist))
1128
- except:
1129
- #解决汉字编码gbk出错问题
1130
- print_df=dfprint10.to_markdown(index=True,tablefmt='plain',colalign=alignlist)
1131
- print_df2=print_df.encode("utf-8",errors="strict")
1132
- print(print_df2)
1133
-
1134
- print('\n'+texttranslate("共找到披露净值信息的开放式基金数量:"),len(dfprint),'\b,',end='')
1135
- print(texttranslate("基金类型:"),fund_type)
1136
-
1137
- print(texttranslate("净值日期:"),nvdate,'\b. ',end='')
1138
- import datetime
1139
- today = datetime.date.today()
1140
- print(texttranslate("数据来源:东方财富/天天基金,"),today)
1141
- """
1142
- footnote1="披露净值的开放式基金数量:"+str(num)+','
1143
- footnote2="基金类型:"+str(fund_type)+'\n'
1144
- footnote3="净值日期:"+str(nvdate)+','
1145
-
1146
- import datetime; todaydt = datetime.date.today()
1147
- #footnote4="数据来源:东方财富/天天基金,"+str(todaydt)
1148
-
1149
- import time; current_time = time.localtime()
1150
- formatted_hour = time.strftime("%H", current_time)
1151
- footnote4=''
1152
- if formatted_hour > '17':
1153
- footnote4="此时若为数据源更新时段,获取的信息可能不全\n"
1154
-
1155
- footnote5="数据来源:新浪财经/天天基金"
1156
- footnote=footnote1+footnote2+footnote3+footnote4+footnote5
1157
-
1158
- df_display_CSS(dfprint10,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=4, \
1159
- first_col_align='center',second_col_align='left', \
1160
- last_col_align='right',other_col_align='right', \
1161
- titile_font_size='16px',heading_font_size='15px', \
1162
- data_font_size='15px')
1163
-
1164
- return df
1165
-
1166
- if __name__=='__main__':
1167
- df=oef_rank_china(info_type='单位净值')
1168
- df=oef_rank_china(info_type='累计净值')
1169
- df=oef_rank_china(info_type='手续费')
1170
-
1171
- #==============================================================================
1172
- if __name__=='__main__':
1173
- fund_code='000009'
1174
- fund_code='0000XX'
1175
- fund_name,fund_type=get_oef_name_china(fund_code)
1176
-
1177
- def get_oef_name_china(fund_code):
1178
- """
1179
- 功能:获得基金的名称和类型
1180
- """
1181
-
1182
- import akshare as ak
1183
- try:
1184
- names=ak.fund_name_em()
1185
- except:
1186
- return fund_code,'未知类型'
1187
-
1188
- dft=names[names['基金代码']==fund_code]
1189
- if len(dft) != 0:
1190
- fund_name=dft['基金简称'].values[0]
1191
- fund_type=dft['基金类型'].values[0]
1192
- else:
1193
- return fund_code,'未知类型'
1194
-
1195
- return fund_name,fund_type
1196
-
1197
- #==============================================================================
1198
- if __name__=='__main__':
1199
- fund='050111.SS'
1200
- fund='000592.SS'
1201
- start='MRM'
1202
- end='today'
1203
- trend_type='净值'
1204
- power=0
1205
- twinx=False
1206
- zeroline=False
1207
-
1208
- def oef_trend_china(ticker,start,end='today',indicator='净值', \
1209
- power=0,twinx=False, \
1210
- average_value=True,facecolor='whitesmoke',
1211
- loc1='best',loc2='best'):
1212
- """
1213
- 功能:开放式基金业绩趋势,单位净值,累计净值,近三个月收益率,同类排名,总排名
1214
- """
1215
- fund=ticker
1216
- fromdate,todate=start_end_preprocess(start,end)
1217
- trend_type=indicator
1218
-
1219
- #检查走势类型
1220
- trendlist=["净值","单位净值","累计净值","收益率","排名"]
1221
- if trend_type not in trendlist:
1222
- print(" #Error(oef_trend_china): unsupported trend type:",trend_type)
1223
- print(" Supported trend types:",trendlist)
1224
- return None
1225
-
1226
- #检查日期
1227
- result,start,end=check_period(fromdate,todate)
1228
- if not result:
1229
- print(" #Error(oef_trend_china): invalid date period:",fromdate,todate)
1230
- return None
1231
- """
1232
- #转换日期格式
1233
- import datetime
1234
- startdate=datetime.datetime.strftime(start,"%Y-%m-%d")
1235
- enddate=str(datetime.datetime.strftime(end,"%Y-%m-%d"))
1236
- """
1237
- print("Searching for open-ended fund (OEF) trend info in China ...")
1238
- import akshare as ak
1239
- import pandas as pd
1240
-
1241
- #开放式基金-历史数据
1242
- import datetime; today = datetime.date.today()
1243
- source=texttranslate("数据来源:东方财富/天天基金")
1244
-
1245
- fund1=fund[:6]
1246
- fund_name=ticker_name(fund1,'fund')
1247
-
1248
- #绘制单位/累计净值对比图
1249
- if trend_type == '净值':
1250
- df1 = ak.fund_open_fund_info_em(fund1, indicator="单位净值走势")
1251
- df1.rename(columns={'净值日期':'date','单位净值':'单位净值'}, inplace=True)
1252
- df1['日期']=df1['date']
1253
- df1.set_index(['date'],inplace=True)
1254
-
1255
- df2 = ak.fund_open_fund_info_em(fund1, indicator="累计净值走势")
1256
- df2.rename(columns={'净值日期':'date','累计净值':'累计净值'}, inplace=True)
1257
- df2.set_index(['date'],inplace=True)
1258
-
1259
- #合并
1260
- df = pd.merge(df1,df2,left_index=True,right_index=True,how='inner')
1261
- df['日期']=df['日期'].apply(lambda x: pd.to_datetime(x))
1262
-
1263
- dfp=df[(df['日期'] >= start)]
1264
- dfp=dfp[(dfp['日期'] <= end)]
1265
- if len(dfp) == 0:
1266
- print(" #Error(oef_trend_china): no info found for",fund,"in the period:",fromdate,todate)
1267
- return
1268
-
1269
- #绘制双线图
1270
- ticker1=fund1; colname1='单位净值';label1=texttranslate('单位净值')
1271
- ticker2=fund1; colname2='累计净值';label2=texttranslate('累计净值')
1272
- #ylabeltxt='人民币元'
1273
- ylabeltxt=texttranslate('净值')
1274
-
1275
- titletxt=texttranslate("开放式基金的净值趋势:")+fund_name
1276
-
1277
- #footnote=source+', '+str(today)
1278
- footnote='注意:图中为交易市场数据,存在溢价或折价,可能与基金公司公布的净值存在差异\n'+source+', '+str(today)
1279
-
1280
- plot_line2(dfp,ticker1,colname1,label1, \
1281
- dfp,ticker2,colname2,label2, \
1282
- ylabeltxt,titletxt,footnote,power=power,twinx=twinx, \
1283
- facecolor=facecolor, \
1284
- loc1=loc1,loc2=loc2)
1285
- return df
1286
-
1287
- #绘制单位净值图
1288
- if trend_type == '单位净值':
1289
- df1 = ak.fund_open_fund_info_em(fund1, indicator="单位净值走势")
1290
- df1.rename(columns={'净值日期':'date','单位净值':'单位净值'}, inplace=True)
1291
- df1['日期']=df1['date']
1292
- df1.set_index(['date'],inplace=True)
1293
- """
1294
- df2 = ak.fund_open_fund_info_em(fund1, indicator="累计净值走势")
1295
- df2.rename(columns={'净值日期':'date','累计净值':'累计净值'}, inplace=True)
1296
- df2.set_index(['date'],inplace=True)
1297
- """
1298
- #合并
1299
- #df = pd.merge(df1,df2,left_index=True,right_index=True,how='inner')
1300
- df = df1
1301
- df['日期']=df['日期'].apply(lambda x: pd.to_datetime(x))
1302
-
1303
- dfp=df[(df['日期'] >= start)]
1304
- dfp=dfp[(dfp['日期'] <= end)]
1305
- if len(dfp) == 0:
1306
- print(" #Error(oef_trend_china): no info found for",fund,"in the period:",fromdate,todate)
1307
- return
1308
-
1309
- #绘图
1310
- ticker1=fund1; colname1='单位净值';label1=texttranslate('单位净值')
1311
- #ticker2=fund1; colname2='累计净值';label2=texttranslate('累计净值')
1312
- #ylabeltxt='人民币元'
1313
- ylabeltxt=texttranslate('单位净值')
1314
-
1315
- titletxt=texttranslate("开放式基金的净值趋势:")+fund_name
1316
-
1317
- #footnote=source+', '+str(today)
1318
- footnote='图中为交易市场数据,存在溢价或折价,可能与基金公司公布的净值存在差异\n'+source+', '+str(today)
1319
-
1320
- plot_line(dfp,colname1,label1,ylabeltxt,titletxt,footnote,power=power,loc=loc1, \
1321
- average_value=average_value,facecolor=facecolor)
1322
- """
1323
- plot_line2(dfp,ticker1,colname1,label1, \
1324
- dfp,ticker2,colname2,label2, \
1325
- ylabeltxt,titletxt,footnote,power=power,twinx=twinx, \
1326
- facecolor=facecolor, \
1327
- loc1=loc1,loc2=loc2)
1328
- """
1329
- return df
1330
-
1331
- #绘制累计净值图
1332
- if trend_type == '累计净值':
1333
- df2 = ak.fund_open_fund_info_em(fund1, indicator="累计净值走势")
1334
- df2.rename(columns={'净值日期':'date','累计净值':'累计净值'}, inplace=True)
1335
- df2['日期']=df2['date']
1336
- df2.set_index(['date'],inplace=True)
1337
-
1338
- #合并
1339
- df = df2
1340
- df['日期']=df['日期'].apply(lambda x: pd.to_datetime(x))
1341
-
1342
- dfp=df[(df['日期'] >= start)]
1343
- dfp=dfp[(dfp['日期'] <= end)]
1344
- if len(dfp) == 0:
1345
- print(" #Error(oef_trend_china): no info found for",fund,"in the period:",fromdate,todate)
1346
- return
1347
-
1348
- #绘图
1349
- ticker2=fund1; colname2='累计净值';label2=texttranslate('累计净值')
1350
- #ylabeltxt='人民币元'
1351
- ylabeltxt=texttranslate('累计净值')
1352
-
1353
- titletxt=texttranslate("开放式基金的净值趋势:")+fund_name
1354
-
1355
- #footnote=source+', '+str(today)
1356
- footnote='图中为交易市场数据,存在溢价或折价,可能与基金公司公布的净值存在差异\n'+source+', '+str(today)
1357
-
1358
- plot_line(dfp,colname2,label2,ylabeltxt,titletxt,footnote,power=power,loc=loc1, \
1359
- average_value=average_value,facecolor=facecolor)
1360
-
1361
- return df
1362
-
1363
-
1364
- #绘制累计收益率单线图
1365
- if trend_type == '收益率':
1366
- df = ak.fund_open_fund_info_em(fund1, indicator="累计收益率走势")
1367
- #df.rename(columns={'净值日期':'date','累计收益率':'累计收益率'}, inplace=True)
1368
- df['date']=df['日期']
1369
- df.set_index(['date'],inplace=True)
1370
- df['日期']=df['日期'].apply(lambda x: pd.to_datetime(x))
1371
- dfp=df[(df['日期'] >= start)]
1372
- dfp=dfp[(dfp['日期'] <= end)]
1373
- if len(dfp) == 0:
1374
- print(" #Error(oef_trend_china): no info found for",fund,"in the period:",fromdate,todate)
1375
- return
1376
-
1377
- colname='累计收益率'; collabel=texttranslate('累计收益率%')
1378
- ylabeltxt=texttranslate('累计收益率%')
1379
- titletxt=texttranslate("开放式基金的累计收益率趋势:")+fund_name
1380
- footnote=source+','+str(today)
1381
- plot_line(dfp,colname,collabel,ylabeltxt,titletxt,footnote,power=power,loc=loc1, \
1382
- average_value=average_value,facecolor=facecolor)
1383
- return df
1384
-
1385
- #绘制同类排名图:近三个月收益率
1386
- if trend_type == '排名':
1387
- df1 = ak.fund_open_fund_info_em(fund1, indicator="同类排名走势")
1388
- df1.rename(columns={'报告日期':'date','同类型排名-每日近三月排名':'同类排名','总排名-每日近三月排名':'总排名'}, inplace=True)
1389
- df1['日期']=df1['date']
1390
- df1['总排名']=df1['总排名'].astype('int64')
1391
- df1.set_index(['date'],inplace=True)
1392
-
1393
- df2 = ak.fund_open_fund_info_em(fund1, indicator="同类排名百分比")
1394
- df2.rename(columns={'报告日期':'date','同类型排名-每日近3月收益排名百分比':'同类排名百分比'}, inplace=True)
1395
- df2.set_index(['date'],inplace=True)
1396
-
1397
- #合并
1398
- df = pd.merge(df1,df2,left_index=True,right_index=True,how='inner')
1399
- df['日期']=df['日期'].apply(lambda x: pd.to_datetime(x))
1400
- dfp=df[(df['日期'] >= start)]
1401
- dfp=dfp[(dfp['日期'] <= end)]
1402
- if len(dfp) == 0:
1403
- print(" #Error(oef_trend_china): no info found for",fund,"in the period:",fromdate,todate)
1404
- return
1405
-
1406
- #绘制双线图:同类排名,总排名
1407
- ylabeltxt=''
1408
- titletxt=texttranslate("开放式基金的近三个月收益率排名趋势:")+fund_name
1409
-
1410
- footnote=source+', '+str(today)
1411
-
1412
- ticker1=fund1; colname1='同类排名';label1=texttranslate('同类排名')
1413
- """
1414
- ticker2=fund1; colname2='同类排名百分比';label2=texttranslate('同类排名百分比')
1415
- dfp1=pd.DataFrame(dfp[colname1])
1416
- dfp2=pd.DataFrame(dfp[colname2])
1417
- plot_line2(dfp1,ticker1,colname1,label1, \
1418
- dfp2,ticker2,colname2,label2, \
1419
- ylabeltxt,titletxt,footnote,power=power,twinx=True)
1420
- """
1421
- #
1422
- ticker2=fund1; colname2='总排名';label2=texttranslate('开放式基金总排名')
1423
- dfp1=pd.DataFrame(dfp[colname1])
1424
- dfp2=pd.DataFrame(dfp[colname2])
1425
- plot_line2(dfp1,ticker1,colname1,label1, \
1426
- dfp2,ticker2,colname2,label2, \
1427
- ylabeltxt,titletxt,footnote,power=power,twinx=twinx, \
1428
- facecolor=facecolor, \
1429
- loc1=loc1,loc2=loc2)
1430
-
1431
- return df
1432
-
1433
- #==============================================================================
1434
- if __name__=='__main__':
1435
- indicator="万份收益"
1436
- rank=5
1437
-
1438
- def mmf_rank_china(indicator="7日年化%",rank=5):
1439
- """
1440
- 功能:中国货币型基金排名,7日年化收益率%
1441
- 货币基金的万份收益指的是基金公司每日公布的当日每万份基金单位产生的收益金额,即万份基金单位收益。
1442
- 注意:万份基金单位收益与万份基金累计收益是不一样的,投资者想要买货币基金应改看基金的万份基金单位收益。
1443
- 货币基金具体的收益计算方式是:
1444
- 货币基金收益=已确认金额/10000*当日万分收益。
1445
- 另外,货币基金每日公布一次收益,周末及节假日,通常在节后首个交易日公布周末或这节假日期间的累计收益。
1446
- """
1447
- indicator_list=["万份收益","7日年化%"]
1448
- if indicator not in indicator_list:
1449
- print(" #Warning(mmf_rank_china): unsupported indicator",indicator)
1450
- print(" Supported indicators:",indicator_list)
1451
- #indicator="7日年化%"
1452
- return None
1453
-
1454
- print("Searching for money market fund (OEF) information in China ...")
1455
- import akshare as ak
1456
- import pandas as pd
1457
-
1458
- #获取货币型基金实时信息
1459
- df = ak.fund_money_fund_daily_em()
1460
- collist=list(df)
1461
- nvname1=collist[2]
1462
- nvname2=collist[3]
1463
- if df[nvname1].eq('').all() or df[nvname1].eq('---').all():
1464
- nvname1=collist[5]
1465
- nvname2=collist[6]
1466
-
1467
- nvdate=nvname1[:10]
1468
-
1469
- #修改列名
1470
- df.rename(columns={nvname1:'万份收益',nvname2:'7日年化%'}, inplace=True)
1471
- #dfa=df.drop(df[df['7日年化%']==''].index)
1472
- dfb=df[['基金代码','基金简称','万份收益','7日年化%','成立日期','基金经理','手续费']].copy()
1473
- dfb=dfb[dfb['7日年化%'] != '---']
1474
-
1475
- if indicator=='7日年化%':
1476
- dfb.sort_values(by=['7日年化%'],ascending=False,inplace=True)
1477
- dfprint=dfb[['基金简称','基金代码','7日年化%','万份收益']].copy()
1478
- titletxt="中国货币型基金排名:7日年化收益率"
1479
- if indicator=='万份收益':
1480
- dfb.sort_values(by=['万份收益'],ascending=False,inplace=True)
1481
- dfprint=dfb[['基金简称','基金代码','万份收益','7日年化%']].copy()
1482
- titletxt="中国货币型基金排名:万份收益金额(元)"
1483
-
1484
- if len(dfprint)==0:
1485
- print(" #Warning(mmf_rank_china): zero records found for",indicator)
1486
- return None
1487
-
1488
- #设置打印
1489
- dfprint.dropna(inplace=True)
1490
- dfprint.reset_index(drop=True,inplace=True)
1491
- dfprint.index=dfprint.index + 1
1492
-
1493
- collist=list(dfprint)
1494
- dfprint['序号']=dfprint.index
1495
- dfprint=dfprint[['序号']+collist]
1496
-
1497
- if rank >0:
1498
- dfprint10=dfprint.head(rank)
1499
- order="前"
1500
- else:
1501
- dfprint10=dfprint.tail(-rank)
1502
- order="后"
1503
- titletxt=titletxt+"("+order+str(abs(rank))+"名,降序)"
1504
-
1505
- footnote1="披露信息的货币型基金数量:"+str(len(dfprint))+','
1506
- footnote2=str(nvdate)+'\n'
1507
- import datetime; todaydt = datetime.date.today()
1508
- footnote3="数据来源:新浪财经/天天基金,"+str(todaydt)+"统计"
1509
- footnote=footnote1+footnote2+footnote3
1510
-
1511
- df_display_CSS(dfprint10,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=4, \
1512
- first_col_align='center',second_col_align='left', \
1513
- last_col_align='right',other_col_align='right', \
1514
- titile_font_size='16px',heading_font_size='15px', \
1515
- data_font_size='15px')
1516
-
1517
- return df
1518
-
1519
- if __name__=='__main__':
1520
- df=mmf_rank_china()
1521
-
1522
- #==============================================================================
1523
- if __name__=='__main__':
1524
- fund='320019.SS'
1525
- fromdate='2020-1-1'
1526
- todate='2020-10-16'
1527
- power=0
1528
-
1529
- def mmf_trend_china(ticker,start,end='today',indicator='7日年化%',power=0, \
1530
- average_value=True,facecolor='whitesmoke'):
1531
- """
1532
- 功能:货币型基金业绩趋势,7日年化收益率
1533
- """
1534
- fund=ticker
1535
-
1536
- fromdate,todate=start_end_preprocess(start,end)
1537
- #检查日期
1538
- result,start,end=check_period(fromdate,todate)
1539
- if not result:
1540
- print(" #Error(mmf_trend_china): invalid date period:",fromdate,todate)
1541
- return None
1542
- import datetime; todaydt = datetime.date.today()
1543
- startdate=datetime.datetime.strftime(start,"%Y-%m-%d")
1544
- enddate=str(datetime.datetime.strftime(end,"%Y-%m-%d"))
1545
-
1546
- print("Searching for money market fund (MMF) info in China ...")
1547
- import akshare as ak
1548
- import pandas as pd
1549
-
1550
- #基金历史数据
1551
- source=texttranslate("数据来源:东方财富/天天基金")
1552
-
1553
- #绘制收益率单线图
1554
- fund1=fund[:6]
1555
- df = ak.fund_money_fund_info_em(fund1)
1556
- df['7日年化%']=df['7日年化收益率'].astype("float")
1557
- df['万份收益']=df['每万份收益'].astype("float")
1558
-
1559
- df.sort_values(by=['净值日期'],ascending=True,inplace=True)
1560
-
1561
- df['date']=pd.to_datetime(df['净值日期'])
1562
- df.set_index(['date'],inplace=True)
1563
-
1564
- dfp = df[(df.index >= startdate)]
1565
- dfp = dfp[(dfp.index <= enddate)]
1566
- if len(dfp) == 0:
1567
- print(" #Error(mmf_trend_china): no info found for",fund,"in the period:",fromdate,todate)
1568
- return
1569
-
1570
- if indicator=='7日年化%':
1571
- colname='7日年化%'; collabel='7日年化%'
1572
- else:
1573
- colname='万份收益'; collabel="万份收益(元)"
1574
-
1575
- ylabeltxt=''
1576
- titletxt="货币型基金的收益趋势:"+get_fund_name_china2(fund)+","+collabel
1577
- footnote=source+', '+str(todaydt)
1578
- plot_line(dfp,colname,collabel,ylabeltxt,titletxt,footnote,power=power, \
1579
- average_value=average_value,facecolor=facecolor)
1580
-
1581
- return df
1582
-
1583
- #==============================================================================
1584
- if __name__=='__main__':
1585
- info_type='单位净值'
1586
- fund_type='全部类型'
1587
- fund_type='增长率'
1588
- rank=10
1589
-
1590
- def etf_rank_china(indicator='单位净值',fund_type='全部类型',rank=5):
1591
- """
1592
- 功能:中国ETF基金排名,单位净值,累计净值,手续费
1593
- """
1594
- info_type=indicator
1595
-
1596
- typelist=['单位净值','累计净值','市价','增长率']
1597
- if info_type not in typelist:
1598
- print(" #Error(etf_rank_china): unsupported indicator",info_type)
1599
- print(" Supported indicators:",typelist)
1600
- return None
1601
-
1602
- print("Searching for exchange traded fund (ETF) information in China ...")
1603
- import akshare as ak
1604
-
1605
- #获取ETF基金实时信息
1606
- df1 = ak.fund_etf_fund_daily_em()
1607
- #删除全部为空值'---'的列
1608
- df1t=df1.T
1609
- df1t['idx']=df1t.index
1610
- df1t.drop_duplicates(subset=['idx'],keep='last',inplace=True)
1611
- df2=df1t.T
1612
- #删除空值'---'的列
1613
-
1614
- #提取净值日期
1615
- collist=list(df2)
1616
- nvname1=collist[3]
1617
- nvname2=collist[4]
1618
- if df2[nvname1].eq('').all() or df2[nvname1].eq('---').all():
1619
- nvname1=collist[5]
1620
- nvname2=collist[6]
1621
- nvdate=nvname1[:10]
1622
-
1623
- #修改列名
1624
- df3=df2.rename(columns={nvname1:'单位净值',nvname2:'累计净值'})
1625
- df=df3[['基金简称','基金代码','类型','单位净值','累计净值','增长率','市价']].copy()
1626
-
1627
- # 过滤idx行
1628
- df=df[df.index != 'idx']
1629
-
1630
- #过滤基金类型
1631
- if fund_type != '全部类型':
1632
- fundtypelist=list(set(list(df['类型'])))
1633
- found=False
1634
- for ft in fundtypelist:
1635
- if fund_type in ft:
1636
- found=True
1637
- break
1638
- if not found:
1639
- print(" #Error(etf_rank_china): unsupported fund type",fund_type)
1640
- print(" Supported fund types:",fundtypelist)
1641
- return None
1642
- fund_filter=lambda x: fund_type in x
1643
- df['基金类型s']=df['类型'].apply(fund_filter)
1644
-
1645
- if fund_type == 'QDII':
1646
- df['基金类型s']=df.apply(lambda x: False if '不含' in x['类型'] else x['基金类型s'],axis=1)
1647
-
1648
- df=df[df['基金类型s']==True]
1649
-
1650
-
1651
- #df=df.replace('---',0)
1652
- if info_type == '单位净值':
1653
- df=df.replace('---',0)
1654
- df['单位净值']=df['单位净值'].astype(float)
1655
- df.sort_values(by=['单位净值'],ascending=False,inplace=True)
1656
- dfprint=df[['基金简称','基金代码','类型','单位净值','市价']].copy()
1657
- #print(texttranslate("\n===== 中国ETF基金排名:单位净值 ====="))
1658
- titletxt="中国ETF基金排名:单位净值"
1659
- dfprint=dfprint[dfprint['单位净值'] != 0]
1660
-
1661
- if info_type == '累计净值':
1662
- df=df.replace('---',0)
1663
- df['累计净值']=df['累计净值'].astype(float)
1664
- df.sort_values(by=['累计净值'],ascending=False,inplace=True)
1665
- dfprint=df[['基金简称','基金代码','类型','累计净值','单位净值']].copy()
1666
- #print(texttranslate("\n===== 中国ETF基金排名:累计净值 ====="))
1667
- titletxt="中国ETF基金排名:累计净值"
1668
- dfprint=dfprint[dfprint['累计净值'] != 0]
1669
-
1670
- if info_type == '市价':
1671
- df=df.replace('---',0)
1672
- df['市价']=df['市价'].astype(float)
1673
- df.sort_values(by=['市价'],ascending=False,inplace=True)
1674
- dfprint=df[['基金简称','基金代码','类型','市价','单位净值']].copy()
1675
- #print(texttranslate("\n===== 中国ETF基金排名:市价 ====="))
1676
- titletxt="中国ETF基金排名:市价"
1677
- dfprint=dfprint[dfprint['市价'] != 0]
1678
-
1679
- if info_type == '增长率':
1680
- df['增长率']=df['增长率'].astype(str)
1681
- df.sort_values(by=['增长率'],ascending=False,inplace=True)
1682
- dfprint=df[['基金简称','基金代码','类型','增长率','市价','单位净值']].copy()
1683
- #print(texttranslate("\n===== 中国ETF基金排名:增长率 ====="))
1684
- titletxt="中国ETF基金排名:增长率"
1685
- dfprint=dfprint[dfprint['增长率'] != 0]
1686
-
1687
- #设置打印对齐
1688
- import pandas as pd
1689
- pd.set_option('display.max_columns', 1000)
1690
- pd.set_option('display.width', 1000)
1691
- pd.set_option('display.max_colwidth', 1000)
1692
- pd.set_option('display.unicode.ambiguous_as_wide', True)
1693
- pd.set_option('display.unicode.east_asian_width', True)
1694
-
1695
- dfprint.dropna(inplace=True)
1696
- dfprint.reset_index(drop=True,inplace=True)
1697
- dfprint.index=dfprint.index + 1
1698
-
1699
- collist=list(dfprint)
1700
- dfprint['序号']=dfprint.index
1701
- dfprint=dfprint[['序号']+collist]
1702
-
1703
- if rank >=0:
1704
- dfprint10=dfprint.head(rank)
1705
- order="前"
1706
- else:
1707
- dfprint10=dfprint.tail(-rank)
1708
- order="后"
1709
- titletxt=titletxt+"("+order+str(abs(rank))+"名,降序排列)"
1710
-
1711
- #print(dfprint10.to_string(index=False))
1712
- """
1713
- print(dfprint10)
1714
- """
1715
- """
1716
- print('') #在标题与表格之间空一行
1717
- alignlist=['right','left','center','center','right','right']
1718
- try:
1719
- print(dfprint10.to_markdown(index=True,tablefmt='plain',colalign=alignlist))
1720
- except:
1721
- #解决汉字编码gbk出错问题
1722
- print_df=dfprint10.to_markdown(index=True,tablefmt='plain',colalign=alignlist)
1723
- print_df2=print_df.encode("utf-8",errors="strict")
1724
- print(print_df2)
1725
-
1726
- print('') #空一行
1727
- print(texttranslate("共找到披露净值信息的ETF基金数量:"),len(dfprint),'\b. ',end='')
1728
- print(texttranslate("基金类型:"),fund_type)
1729
-
1730
- print(texttranslate("净值日期:"),nvdate,'\b. ',end='')
1731
- import datetime
1732
- today = datetime.date.today()
1733
- print(texttranslate("数据来源:东方财富/天天基金,"),today)
1734
- """
1735
- footnote1="披露净值信息的ETF基金数量:"+str(len(dfprint))+','
1736
- footnote2="基金类型:"+str(fund_type)+'\n'
1737
- footnote3="披露日期:"+str(nvdate)+','
1738
- import datetime; todaydt = datetime.date.today()
1739
- footnote4="数据来源:东方财富/天天基金,"+str(todaydt)
1740
- footnote=footnote1+footnote2+footnote3+footnote4
1741
-
1742
- df_display_CSS(dfprint10,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=3, \
1743
- first_col_align='center',second_col_align='left', \
1744
- last_col_align='right',other_col_align='right', \
1745
- titile_font_size='16px',heading_font_size='15px', \
1746
- data_font_size='15px')
1747
-
1748
- return df
1749
-
1750
- if __name__=='__main__':
1751
- df=etf_rank_china(info_type='单位净值',fund_type='全部类型')
1752
- df=etf_rank_china(info_type='累计净值')
1753
- df=etf_rank_china(info_type='市价')
1754
-
1755
- #==============================================================================
1756
- if __name__=='__main__':
1757
- ticker='159922.SS'
1758
- ticker='510580'
1759
- start='2025-1-1'
1760
- end='2025-5-30'
1761
-
1762
- def etf_trend_china(ticker,start,end='today',indicator='净值',power=0, \
1763
- average_value=True,facecolor='whitesmoke', \
1764
- loc1='best',loc2='best',twinx=False,graph=True):
1765
- """
1766
- 功能:ETF基金业绩趋势,单位净值,累计净值
1767
- """
1768
- fund=ticker
1769
- fromdate,todate=start_end_preprocess(start,end)
1770
-
1771
- indicator_list=['净值','单位净值','累计净值']
1772
- if indicator not in indicator_list:
1773
- indicator='净值'
1774
-
1775
- #检查日期
1776
- result,start,end=check_period(fromdate,todate)
1777
- if not result:
1778
- print(" #Error(oef_trend_china): invalid date period:",fromdate,todate)
1779
- return None
1780
- #转换日期格式
1781
- import datetime; todaydt = datetime.date.today()
1782
- startdate=str(datetime.datetime.strftime(start,"%Y-%m-%d"))
1783
- enddate=str(datetime.datetime.strftime(end,"%Y-%m-%d"))
1784
-
1785
- print("Searching for exchange traded fund (ETF) trend info in China ...")
1786
- import akshare as ak
1787
- import pandas as pd
1788
-
1789
- source=texttranslate("数据来源:东方财富/天天基金")
1790
-
1791
- #获取基金数据
1792
- fund1=fund[:6]
1793
- df = ak.fund_etf_fund_info_em(fund1)
1794
- df['date']=pd.to_datetime(df['净值日期'])
1795
- df.set_index(['date'],inplace=True)
1796
- df['单位净值']=df['单位净值'].astype("float")
1797
- df['累计净值']=df['累计净值'].astype("float")
1798
-
1799
- df['净值日期']=df['净值日期'].apply(lambda x: pd.to_datetime(x))
1800
- dfp=df[(df['净值日期'] >= start)]
1801
- dfp=dfp[(dfp['净值日期'] <= end)]
1802
- if len(dfp) == 0:
1803
- print(" #Error(etf_trend_china): no info found for",fund,"in the period:",fromdate,todate)
1804
- return
1805
-
1806
- #绘制双线图
1807
- if graph:
1808
- ticker1=fund1; colname1='单位净值';label1=texttranslate('单位净值')
1809
- ticker2=fund1; colname2='累计净值';label2=texttranslate('累计净值')
1810
- titletxt=texttranslate("ETF基金的净值趋势:")+get_fund_name_china2(fund)
1811
- footnote=source+', '+str(todaydt)
1812
-
1813
- if indicator=='净值':
1814
- ylabeltxt=texttranslate('净值(元)')
1815
- plot_line2(dfp,ticker1,colname1,label1, \
1816
- dfp,ticker2,colname2,label2, \
1817
- ylabeltxt,titletxt,footnote, twinx=twinx, \
1818
- facecolor=facecolor,loc1=loc1,loc2=loc2)
1819
-
1820
- if indicator=='单位净值':
1821
- ylabeltxt=texttranslate('单位净值(元)')
1822
- plot_line(dfp,colname1,label1,ylabeltxt,titletxt,footnote,power=power,loc=loc1, \
1823
- average_value=average_value,facecolor=facecolor)
1824
-
1825
- if indicator=='累计净值':
1826
- ylabeltxt=texttranslate('累计净值(元)')
1827
- plot_line(dfp,colname2,label2,ylabeltxt,titletxt,footnote,power=power,loc=loc1, \
1828
- average_value=average_value,facecolor=facecolor)
1829
-
1830
- return dfp
1831
-
1832
- if __name__=='__main__':
1833
- df=etf_trend_china('510580','2019-1-1','2020-9-30')
1834
-
1835
- #==============================================================================
1836
-
1837
- def fund_summary_china(rank=10):
1838
- """
1839
- 功能:中国基金投资机构概况
1840
- 爬虫来源地址:https://zhuanlan.zhihu.com/p/97487003
1841
- """
1842
- print("Searching for investment fund institutions in China ...")
1843
- import akshare as ak
1844
-
1845
- #会员机构综合查询:
1846
- #机构类型:'商业银行','支付结算机构','证券公司资管子公司','会计师事务所',
1847
- #'保险公司子公司','独立服务机构','证券投资咨询机构','证券公司私募基金子公司',
1848
- #'私募基金管理人','公募基金管理公司','地方自律组织','境外机构','期货公司',
1849
- #'独立第三方销售机构','律师事务所','证券公司','其他机构','公募基金管理公司子公司',
1850
- #'期货公司资管子公司','保险公司'
1851
- try:
1852
- amac_df = ak.amac_member_info()
1853
- except:
1854
- print(" #Error(fund_summary_china): data source tentatively inaccessible, try later")
1855
- return None
1856
-
1857
- """
1858
- typelist=['公募基金管理公司','公募基金管理公司子公司','私募基金管理人', \
1859
- '期货公司','期货公司资管子公司','证券公司', \
1860
- '证券公司私募基金子公司','证券公司资管子公司','境外机构']
1861
- """
1862
- typelist=list(set(list(amac_df["机构类型"])))
1863
-
1864
- import pandas as pd
1865
- titletxt="中国基金机构类型与分布(前"+str(rank)+"名)"
1866
-
1867
- amac_sum_df=pd.DataFrame(columns=['机构类型','机构数量','数量占比%'])
1868
- totalnum=0
1869
- for t in typelist:
1870
- df_sub=amac_df[amac_df['机构类型']==t]
1871
- n=len(list(set(list(df_sub['机构(会员)名称']))))
1872
- if n==0: continue
1873
- totalnum=totalnum+n
1874
-
1875
- s=pd.Series({'机构类型':t,'机构数量':n})
1876
- try:
1877
- amac_sum_df=amac_sum_df.append(s,ignore_index=True)
1878
- except:
1879
- amac_sum_df=amac_sum_df._append(s,ignore_index=True)
1880
-
1881
- amac_sum_df['数量占比%']=amac_sum_df['机构数量'].apply(lambda x: round(x/totalnum*100,2))
1882
-
1883
- amac_sum_df.sort_values(by=['机构数量'],ascending=False,inplace=True)
1884
- amac_sum_df.reset_index(drop=True,inplace=True)
1885
- amac_sum_df.index=amac_sum_df.index + 1
1886
-
1887
- collist=list(amac_sum_df)
1888
- amac_sum_df['序号']=amac_sum_df.index
1889
- amac_sum_df=amac_sum_df[['序号']+collist]
1890
-
1891
- df10=amac_sum_df.head(rank)
1892
-
1893
- footnote1="共有"+str(len(typelist))+'个类型,'
1894
- footnote2=str(totalnum)+'家机构;'
1895
- footnote3="表中类型数量占比"+str(round(df10['机构数量'].sum()/totalnum*100,2))+'%\n'
1896
-
1897
- import datetime; todaydt = datetime.date.today()
1898
- footnote9="数据来源:中国证券投资基金业协会,"+str(todaydt)
1899
- footnote=footnote1+footnote2+footnote3+footnote9
1900
-
1901
- df_display_CSS(df10,titletxt=titletxt,footnote=footnote,facecolor='papayawhip',decimals=2, \
1902
- first_col_align='center',second_col_align='left', \
1903
- last_col_align='right',other_col_align='right', \
1904
- titile_font_size='16px',heading_font_size='15px', \
1905
- data_font_size='15px')
1906
-
1907
- return amac_df
1908
-
1909
-
1910
- #==============================================================================
1911
- if __name__=='__main__':
1912
- location='全国'
1913
- df=pef_manager_china(location='全国')
1914
-
1915
- def pef_manager_china(location='全国'):
1916
- """
1917
- 功能:中国私募基金管理人地域分布概况
1918
- 爬虫来源地址:https://zhuanlan.zhihu.com/p/97487003
1919
- """
1920
-
1921
- print("Searching for private equity fund (PEF) managers info in China ...")
1922
- import akshare as ak
1923
- import pandas as pd
1924
-
1925
- #私募基金管理人综合查询
1926
- manager_df = ak.amac_manager_info()
1927
- num=len(list(manager_df["法定代表人/执行事务合伙人(委派代表)姓名"]))
1928
-
1929
- #注册地检查
1930
- if location != '全国':
1931
- typelist=sort_pinyin(list(set(list(manager_df['注册地']))))
1932
- typelist.remove('')
1933
- if location not in typelist:
1934
- print(" #Error(pef_manager_china): failed to find registration place-"+location)
1935
- print(" Supported registration place:",typelist+['全国'])
1936
- return
1937
-
1938
- #设置打印对齐
1939
- pd.set_option('display.max_columns', 1000)
1940
- pd.set_option('display.width', 1000)
1941
- pd.set_option('display.max_colwidth', 1000)
1942
- pd.set_option('display.unicode.ambiguous_as_wide', True)
1943
- pd.set_option('display.unicode.east_asian_width', True)
1944
-
1945
- import datetime; today = datetime.date.today()
1946
- source=texttranslate("数据来源:中国证券投资基金业协会")
1947
- footnote=source+', '+str(today)
1948
-
1949
- if location != '全国':
1950
- manager_df=manager_df[manager_df['注册地']==location]
1951
- print(texttranslate("\n===== 中国私募基金管理人角色分布 ====="))
1952
- print(texttranslate("地域:")+location)
1953
- print(texttranslate("法定代表人/执行合伙人数量:"),end='')
1954
- num1=len(list(manager_df["法定代表人/执行事务合伙人(委派代表)姓名"]))
1955
- print("{:,}".format(num1),texttranslate('\b, 占比全国'),round(num1/num*100.0,2),'\b%')
1956
-
1957
- print(texttranslate("其中, 角色分布:"))
1958
- #instlist=list(set(list(manager_df['机构类型'])))
1959
- instlist=['私募股权、创业投资基金管理人','私募证券投资基金管理人','私募资产配置类管理人','其他私募投资基金管理人']
1960
- mtype=pd.DataFrame(columns=['管理人类型','人数','占比%'])
1961
- for t in instlist:
1962
- df_sub=manager_df[manager_df['机构类型']==t]
1963
- n=len(list(df_sub['法定代表人/执行事务合伙人(委派代表)姓名']))
1964
- pct=round(n/num1*100,2)
1965
- s=pd.Series({'管理人类型':t,'人数':n,'占比%':pct})
1966
- try:
1967
- mtype=mtype.append(s,ignore_index=True)
1968
- except:
1969
- mtype=mtype._append(s,ignore_index=True)
1970
- mtype.sort_values(by=['人数'],ascending=False,inplace=True)
1971
- mtype.reset_index(drop=True,inplace=True)
1972
- mtype.index=mtype.index + 1
1973
-
1974
- print(mtype)
1975
- print(footnote)
1976
- return manager_df
1977
-
1978
- print(texttranslate("\n===== 中国私募基金管理人地域分布概况 ====="))
1979
- print(texttranslate("法定代表人/执行合伙人数量:"),end='')
1980
- num=len(list(manager_df["法定代表人/执行事务合伙人(委派代表)姓名"]))
1981
- print("{:,}".format(num))
1982
-
1983
- typelist=sort_pinyin(list(set(list(manager_df['注册地']))))
1984
- typelist.remove('')
1985
-
1986
- print(texttranslate("其中分布在:"))
1987
- location=pd.DataFrame(columns=['注册地','人数','占比%'])
1988
- for t in typelist:
1989
- df_sub=manager_df[manager_df['注册地']==t]
1990
- n=len(list(df_sub['法定代表人/执行事务合伙人(委派代表)姓名']))
1991
- pct=round(n/num*100,2)
1992
- s=pd.Series({'注册地':t,'人数':n,'占比%':pct})
1993
- try:
1994
- location=location.append(s,ignore_index=True)
1995
- except:
1996
- location=location._append(s,ignore_index=True)
1997
- location.sort_values(by=['人数'],ascending=False,inplace=True)
1998
-
1999
- location.reset_index(drop=True,inplace=True)
2000
- location.index=location.index + 1
2001
-
2002
- location10=location.head(10)
2003
- pctsum=round(location10['占比%'].sum(),2)
2004
-
2005
- print(location10)
2006
- print(texttranslate("上述地区总计占比:"),pctsum,'\b%')
2007
- print(footnote)
2008
-
2009
- """
2010
- print("\n===== 中国私募基金管理人角色分布 =====")
2011
- print("地域:"+location)
2012
- print("法定代表人/执行合伙人数量:",end='')
2013
- num1=len(list(manager_df["法定代表人/执行事务合伙人(委派代表)姓名"]))
2014
- print("{:,}".format(num1),'\b, 占比全国',round(num1/num*100.0,2),'\b%')
2015
-
2016
- print("其中, 角色分布:")
2017
- #instlist=list(set(list(manager_df['机构类型'])))
2018
- instlist=['私募股权、创业投资基金管理人','私募证券投资基金管理人','私募资产配置类管理人','其他私募投资基金管理人']
2019
- mtype=pd.DataFrame(columns=['管理人类型','人数','占比%'])
2020
- for t in instlist:
2021
- df_sub=manager_df[manager_df['机构类型']==t]
2022
- n=len(list(df_sub['法定代表人/执行事务合伙人(委派代表)姓名']))
2023
- pct=round(n/num1*100,2)
2024
- s=pd.Series({'管理人类型':t,'人数':n,'占比%':pct})
2025
- mtype=mtype.append(s,ignore_index=True)
2026
- mtype.sort_values(by=['人数'],ascending=False,inplace=True)
2027
- mtype.reset_index(drop=True,inplace=True)
2028
-
2029
- print(mtype)
2030
- print(footnote)
2031
- """
2032
-
2033
- return manager_df
2034
-
2035
-
2036
- #==============================================================================
2037
- if __name__=='__main__':
2038
- start_page=1
2039
- end_page=10
2040
- step_pages=5
2041
- DEBUG=True
2042
-
2043
- df,failedpages=get_pef_product_china_pages(start_page,end_page,step_pages)
2044
-
2045
- def get_pef_product_china_pages(start_page,end_page,step_pages,DEBUG=True):
2046
- """
2047
- 功能:获取中国私募基金产品运营方式和状态信息,指定页数范围和页数跨度
2048
- 返回:获取的数据,失败的页数范围列表。
2049
- """
2050
- DEBUG=DEBUG
2051
- if DEBUG:
2052
- print(" Starting to retrieve pef info from",start_page,"to",end_page,"by every",step_pages,"pages ...")
2053
-
2054
- import akshare as ak
2055
- import pandas as pd
2056
-
2057
- df=pd.DataFrame()
2058
- pg=start_page
2059
- failedpages=[]
2060
- while pg <= end_page:
2061
- pg_end=pg+step_pages-1
2062
- try:
2063
- if DEBUG:
2064
- print(" Getting pef info from page",pg,"to",pg_end)
2065
- dft = ak.amac_fund_info(start_page=str(pg),end_page=str(pg_end))
2066
-
2067
- if len(df)==0:
2068
- df=dft
2069
- else:
2070
- #df=df.append(dft)
2071
- df=pd.concat([df,dft],ignore_index=True)
2072
- except:
2073
- if DEBUG:
2074
- print(" Warning: failed to get pef pages from",pg,'to',pg_end)
2075
- failedpages=failedpages+[[pg,pg_end]]
2076
-
2077
- pg=pg_end + 1
2078
-
2079
- if DEBUG:
2080
- print('\n',end='')
2081
- print(" Successfully retrieved pef info",len(df),"records, with failed page range",len(failedpages),'pairs')
2082
-
2083
- return df,failedpages
2084
-
2085
- #==============================================================================
2086
- if __name__=='__main__':
2087
- max_pages=2000
2088
- step_page_list=[100,10,1]
2089
- DEBUG=True
2090
-
2091
- def get_pef_product_china(max_pages=2000,step_page_list=[100,20,1],DEBUG=True):
2092
- """
2093
- 功能:获取中国私募基金产品运营方式和状态信息,耗时较长
2094
- 注意:由于获取过程极易失败,因此分割为三个阶段进行下载,然后合成。
2095
- """
2096
- print(" Downloading in pages, which takes long time upon network stability and speed")
2097
- print(" If a download is stuck, RESTART Python kernel or even Jupyter, then run again")
2098
- import pandas as pd
2099
-
2100
- # 第1步:页数跨度最大
2101
- per_step=1
2102
- step_pages=step_page_list[per_step-1]
2103
- df1,failedpages1=get_pef_product_china_pages(start_page=1,end_page=max_pages,step_pages=step_pages,DEBUG=DEBUG)
2104
-
2105
- # 第2步:页数跨度第二大
2106
- per_step=2
2107
- df2=df1.copy(deep=True)
2108
- failedpages2=[]
2109
-
2110
- if len(failedpages1) > 0:
2111
-
2112
- step_pages=step_page_list[per_step-1]
2113
-
2114
- for fp in failedpages1:
2115
- start_page=fp[0]
2116
- end_page=fp[1]
2117
-
2118
- dft,failedpagest=get_pef_product_china_pages(start_page=start_page,end_page=end_page,step_pages=step_pages,DEBUG=DEBUG)
2119
- if len(dft) > 0:
2120
- #df1=df1.append(dft)
2121
- df2=pd.concat([df2,dft],ignore_index=True)
2122
-
2123
- if len(failedpagest) > 0:
2124
- failedpages2=failedpages2+failedpagest
2125
-
2126
- # 第3步:页数跨度小
2127
- per_step=3
2128
- df3=df2.copy(deep=True)
2129
- failedpages3=[]
2130
-
2131
- if len(failedpages2) > 0:
2132
-
2133
- step_pages=step_page_list[per_step-1]
2134
-
2135
- for fp in failedpages2:
2136
- start_page=fp[0]
2137
- end_page=fp[1]
2138
-
2139
- dft,failedpagest=get_pef_product_china_pages(start_page=start_page,end_page=end_page,step_pages=step_pages,DEBUG=DEBUG)
2140
- if len(dft) > 0:
2141
- #df1=df1.append(dft)
2142
- df3=pd.concat([df3,dft],ignore_index=True)
2143
-
2144
- if len(failedpagest) > 0:
2145
- failedpages3=failedpages3+failedpagest
2146
-
2147
- if DEBUG:
2148
- print(" Finally retrieved pef info",len(df3),"records, with failed pages",failedpages3)
2149
-
2150
- return df3
2151
-
2152
-
2153
- #==============================================================================
2154
-
2155
-
2156
- def pef_product_china(rank=20,facecolor='papayawhip',DEBUG=False):
2157
-
2158
- """
2159
- 功能:中国私募基金管理人的产品管理概况
2160
- 爬虫来源地址:https://zhuanlan.zhihu.com/p/97487003
2161
- 注意:下载数据需要极长时间,极少完全成功,谨慎运行!
2162
- """
2163
- print("Searching for private equity fund (PEF) info in China ...")
2164
- import akshare as ak
2165
- import pandas as pd
2166
-
2167
- #私募基金管理人基金产品
2168
- product_df = get_pef_product_china(max_pages=2200,step_page_list=[100,22,1],DEBUG=False)
2169
- product_df['私募基金管理人类型']=product_df['私募基金管理人类型'].apply(lambda x: '方式不明' if x=='' or x is None else x)
2170
- product_df['运行状态']=product_df['运行状态'].apply(lambda x: '状态不明' if x=='' or x is None else x)
2171
-
2172
- #num=len(list(product_df["基金名称"])) #统计可能有问题,原因不明
2173
- #footnote1="找到产品数量:"+str("{:,}".format(num))+'\n'
2174
- import datetime; todaydt = datetime.date.today()
2175
- footnote9="数据来源:中国证券投资基金业协会,"+str(todaydt)
2176
-
2177
- # 产品运营方式==============================================================
2178
- titletxt="中国私募基金管理人的产品运营方式"
2179
-
2180
- #typelist=['受托管理','顾问管理','自我管理']
2181
- typelist=list(set(list(product_df['私募基金管理人类型'])))
2182
- dfprint=pd.DataFrame(columns=['运营方式','产品数量','数量占比%'])
2183
- totalnum=0
2184
- for t in typelist:
2185
- df_sub=product_df[product_df['私募基金管理人类型']==t]
2186
- n=len(list(set(list(df_sub['基金名称']))))
2187
- totalnum=totalnum+n
2188
-
2189
- s=pd.Series({'运营方式':t,'产品数量':n})
2190
- try:
2191
- dfprint=dfprint.append(s,ignore_index=True)
2192
- except:
2193
- dfprint=dfprint._append(s,ignore_index=True)
2194
-
2195
- dfprint['数量占比%']=dfprint['产品数量'].apply(lambda x: round(x/totalnum*100,3))
2196
- dfprint['产品数量']=dfprint['产品数量'].apply(lambda x: str("{:,}".format(x)))
2197
-
2198
- dfprint.sort_values(by=['数量占比%'],ascending=False,inplace=True)
2199
- dfprint.reset_index(drop=True,inplace=True)
2200
- dfprint.index=dfprint.index + 1
2201
- collist=list(dfprint)
2202
- dfprint['序号']=dfprint.index
2203
- dfprint=dfprint[['序号']+collist]
2204
-
2205
- footnote1="找到管理产品"+str("{:,}".format(totalnum))+'个\n'
2206
- footnote=footnote1+footnote9
2207
-
2208
- df_display_CSS(dfprint,titletxt=titletxt,footnote=footnote,facecolor=facecolor,decimals=3, \
2209
- first_col_align='center',second_col_align='left', \
2210
- last_col_align='right',other_col_align='right', \
2211
- titile_font_size='16px',heading_font_size='15px', \
2212
- data_font_size='15px')
2213
-
2214
- #运营状态===================================================================
2215
- titletxt="中国私募基金管理人的产品运营状态"
2216
- typelist=list(set(list(product_df['运行状态'])))
2217
- dfprint=pd.DataFrame(columns=['运营状态','产品数量','数量占比%'])
2218
- #totalnum=0
2219
- for t in typelist:
2220
- df_sub=product_df[product_df['运行状态']==t]
2221
- n=len(list(set(list(df_sub['基金名称']))))
2222
- if n==0: continue
2223
- #totalnum=totalnum+n
2224
-
2225
- s=pd.Series({'运营状态':t,'产品数量':n})
2226
- try:
2227
- dfprint=dfprint.append(s,ignore_index=True)
2228
- except:
2229
- dfprint=dfprint._append(s,ignore_index=True)
2230
-
2231
- dfprint['数量占比%']=dfprint['产品数量'].apply(lambda x: round(x/totalnum*100,3))
2232
- dfprint['产品数量']=dfprint['产品数量'].apply(lambda x: str("{:,}".format(x)))
2233
-
2234
- dfprint.sort_values(by=['数量占比%'],ascending=False,inplace=True)
2235
- dfprint.reset_index(drop=True,inplace=True)
2236
- dfprint.index=dfprint.index + 1
2237
- collist=list(dfprint)
2238
- dfprint['序号']=dfprint.index
2239
- dfprint=dfprint[['序号']+collist]
2240
-
2241
- footnote1="找到运营产品"+str("{:,}".format(totalnum))+'个\n'
2242
- footnote=footnote1+footnote9
2243
-
2244
- df_display_CSS(dfprint,titletxt=titletxt,footnote=footnote,facecolor=facecolor,decimals=3, \
2245
- first_col_align='center',second_col_align='left', \
2246
- last_col_align='right',other_col_align='right', \
2247
- titile_font_size='16px',heading_font_size='15px', \
2248
- data_font_size='15px')
2249
-
2250
- #推出产品数量排行===========================================================
2251
- titletxt="中国推出产品数量最多的私募基金管理人(前"+str(rank)+"名)"
2252
- subttl=pd.DataFrame(product_df.groupby(by=['私募基金管理人名称'])['基金名称'].count())
2253
- subttl.rename(columns={'基金名称':'产品数量'}, inplace=True)
2254
- subttl['数量占比‰']=round(subttl['产品数量']/totalnum*1000.0,2)
2255
- subttl.sort_values(by=['产品数量'],ascending=False,inplace=True)
2256
- subttl.reset_index(inplace=True)
2257
-
2258
- subttl.index=subttl.index + 1
2259
- subttl10=subttl.head(rank)
2260
-
2261
- dfprint=subttl10
2262
- dfprint.sort_values(by=['数量占比‰'],ascending=False,inplace=True)
2263
- dfprint.reset_index(drop=True,inplace=True)
2264
- dfprint.index=dfprint.index + 1
2265
- collist=list(dfprint)
2266
- dfprint['序号']=dfprint.index
2267
- dfprint=dfprint[['序号']+collist]
2268
-
2269
- pctsum=round(subttl10['数量占比‰'].sum(),2)
2270
- footnote1="找到产品"+str("{:,}".format(totalnum))+"个,上述产品合计占比"+str(pctsum)+'‰'+'\n'
2271
- footnote=footnote1+footnote9
2272
-
2273
- df_display_CSS(dfprint,titletxt=titletxt,footnote=footnote,facecolor=facecolor,decimals=2, \
2274
- first_col_align='center',second_col_align='left', \
2275
- last_col_align='right',other_col_align='right', \
2276
- titile_font_size='16px',heading_font_size='15px', \
2277
- data_font_size='15px')
2278
-
2279
-
2280
- # 托管产品==================================================================
2281
- titletxt="中国私募基金管理人的产品托管概况(前"+str(rank)+"名)"
2282
- tnum=len(list(set(list(product_df['托管人名称']))))
2283
- footnote1="找到产品"+str("{:,}".format(totalnum))+"个,托管机构"+str("{:,}".format(tnum))+'家\n'
2284
-
2285
- subttl=pd.DataFrame(product_df.groupby(by=['托管人名称'])['基金名称'].count())
2286
- subttl.rename(columns={'基金名称':'产品数量'}, inplace=True)
2287
- subttl.sort_values(by=['产品数量'],ascending=False,inplace=True)
2288
- subttl.reset_index(inplace=True)
2289
-
2290
- subttl=subttl[subttl['托管人名称']!='']
2291
- #subttl.drop(subttl.index[0], inplace=True) # 删除第1行
2292
- subttl.reset_index(drop=True,inplace=True)
2293
- subttl['数量占比%']=round(subttl['产品数量']/totalnum*100.0,3)
2294
-
2295
- subttl.index=subttl.index + 1
2296
- subttl10=subttl.head(rank)
2297
-
2298
- pctsum=round(subttl10['数量占比%'].sum(),2)
2299
- #print(subttl10)
2300
- #print(texttranslate("上述金融机构托管产品总计占比:"),pctsum,'\b%')
2301
- footnote2="上述机构托管产品合计占比:"+str(pctsum)+'%\n'
2302
- footnote=footnote1+footnote2+footnote9
2303
-
2304
- dfprint=subttl10
2305
- dfprint.sort_values(by=['数量占比%'],ascending=False,inplace=True)
2306
- dfprint.reset_index(drop=True,inplace=True)
2307
- dfprint.index=dfprint.index + 1
2308
- collist=list(dfprint)
2309
- dfprint['序号']=dfprint.index
2310
- dfprint=dfprint[['序号']+collist]
2311
-
2312
- df_display_CSS(dfprint,titletxt=titletxt,footnote=footnote,facecolor=facecolor,decimals=3, \
2313
- first_col_align='center',second_col_align='left', \
2314
- last_col_align='right',other_col_align='right', \
2315
- titile_font_size='16px',heading_font_size='15px', \
2316
- data_font_size='15px')
2317
-
2318
- return product_df
2319
-
2320
-
2321
- #==============================================================================
2322
- #==============================================================================
2323
- if __name__=='__main__':
2324
- fund_list=['510050.SS','510210.SS']
2325
- start='2022-1-1'
2326
- end='2022-10-31'
2327
- ftype='单位净值'
2328
- loc1='best'
2329
- loc2='best'
2330
- graph=True
2331
-
2332
- def compare_metf_china(fund_list,start,end,ftype='单位净值',graph=True):
2333
- """
2334
- 功能:比较多只交易所基金的单位净值或累计净值,仅限中国内地
2335
- """
2336
-
2337
- #检查日期期间的合理性
2338
- result,startpd,endpd=check_period(start,end)
2339
- if not result:
2340
- print(" #Error(compare_metf): invalid date period",start,end)
2341
- return None
2342
-
2343
- #检查净值类型
2344
- typelist=['单位净值','累计净值']
2345
- if not (ftype in typelist):
2346
- print(" #Error(compare_metf): invalid fund value type",ftype)
2347
- print(" Supported fund value type:",typelist)
2348
- return None
2349
-
2350
- import os, sys
2351
- class HiddenPrints:
2352
- def __enter__(self):
2353
- self._original_stdout = sys.stdout
2354
- sys.stdout = open(os.devnull, 'w')
2355
-
2356
- def __exit__(self, exc_type, exc_val, exc_tb):
2357
- sys.stdout.close()
2358
- sys.stdout = self._original_stdout
2359
-
2360
- #循环获取基金净值
2361
- import pandas as pd
2362
- fdf=pd.DataFrame()
2363
- print("Searching for ETF fund information, please wait ...")
2364
- for f in fund_list:
2365
-
2366
- f6=f[:6]
2367
- try:
2368
- with HiddenPrints():
2369
- dft=etf_trend_china(f6,start,end,graph=False)
2370
- except:
2371
- print(" #Error(compare_metf): ETF fund not found for",f)
2372
- return None
2373
-
2374
- dft2=pd.DataFrame(dft[ftype])
2375
- dft2.rename(columns={ftype:get_fund_name_china2(f)}, inplace=True)
2376
- if len(fdf)==0:
2377
- fdf=dft2
2378
- else:
2379
- fdf=pd.merge(fdf,dft2,how='outer',left_index=True,right_index=True)
2380
-
2381
- #绘图
2382
- y_label=ftype
2383
- import datetime; todaydt = datetime.date.today()
2384
-
2385
- lang=check_language()
2386
- if lang == 'English':
2387
- x_label="Source: eastmoney/tiantian funds, "+str(todaydt)
2388
- title_txt="Compare Multiple ETF Fund Performance"
2389
- else:
2390
- x_label="数据来源: 东方财富/天天基金,"+str(todaydt)
2391
- title_txt="比较多只ETF基金的净值指标"
2392
-
2393
- draw_lines(fdf,y_label,x_label,axhline_value=0,axhline_label='',title_txt=title_txt, \
2394
- data_label=False,resample_freq='H',smooth=True)
2395
-
2396
- return fdf
2397
-
2398
- if __name__=='__main__':
2399
- fund_list=['510050.SS','510210.SS','510880.SS','510180.SS']
2400
- fdf=compare_metf_china(fund_list,start,end,ftype='单位净值',graph=True)
2401
-
2402
- #==============================================================================
2403
- #==============================================================================
2404
- #==============================================================================
2405
- #以下信息专注于中国内地基金信息,来源于akshare,尚未利用
2406
- #==============================================================================
2407
- def fund_info_china0():
2408
-
2409
- #证券公司集合资管产品
2410
- cam_df = ak.amac_securities_info()
2411
-
2412
- #证券公司直投基金:
2413
- #中国证券投资基金业协会-信息公示-私募基金管理人公示-基金产品公示-证券公司直投基金
2414
- sdif_df = ak.amac_aoin_info()
2415
-
2416
- #证券公司私募投资基金
2417
- speif_df = ak.amac_fund_sub_info()
2418
-
2419
- #证券公司私募基金子公司管理人信息
2420
- spesub_manager_df = ak.amac_member_sub_info()
2421
-
2422
- #基金公司及子公司集合资管产品
2423
- #中国证券投资基金业协会-信息公示-私募基金管理人公示-基金产品公示-基金公司及子公司集合资管产品
2424
- sscam_df = ak.amac_fund_account_info()
2425
-
2426
- #期货公司集合资管产品
2427
- #中国证券投资基金业协会-信息公示-私募基金管理人公示-基金产品公示-期货公司集合资管产品
2428
- fccam_df = ak.amac_futures_info()
2429
-
2430
- #==========================================================================
2431
- #以下为公募数据:
2432
-
2433
- #基金净值估算数据,当前获取在交易日的所有基金的净值估算数据
2434
- #爬虫来源:https://zhuanlan.zhihu.com/p/140478554?from_voters_page=true
2435
- #信息内容:基金代码,基金类型,单位净值,基金名称
2436
- fnve_df = ak.fund_value_estimation_em()
2437
-
2438
- #挑选QDII产品
2439
- fnve_list=list(set(list(fnve_df['基金类型'])))
2440
- qdii=lambda x: True if 'QDII' in x else False
2441
- fnve_df['is_QDII']=fnve_df['基金类型'].apply(qdii)
2442
- fnve_qdii_df=fnve_df[fnve_df['is_QDII']==True]
2443
-
2444
- #基金持股:获取个股的基金持股数据
2445
- #爬虫来源:https://my.oschina.net/akshare/blog/4428824
2446
- #持股的基金类型:symbol="基金持仓"; choice of {"基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"}
2447
- #返回:单次返回指定 symbol 和 date 的所有历史数据
2448
- df = ak.stock_report_fund_hold(symbol="基金持仓", date="20200630")
2449
-
2450
- ###Fama-French三因子回归A股实证(附源码)
2451
- #代码来源:https://mp.weixin.qq.com/s?__biz=MzU5NDY0NDM2NA==&mid=2247486057&idx=1&sn=0fb3f8558da4e55789ce340c03b648cc&chksm=fe7f568ac908df9c22bae8b52207633984ec91ef7b2728eea8c6a75089b8f2db284e3d611775&scene=21#wechat_redirect
2452
-
2453
- ###Carhart四因子模型A股实证(附源码)
2454
- #代码来源:https://my.oschina.net/akshare/blog/4340998
2455
-
2456
- #==========================================================================
2457
- ###其他公募基金实时/历史行情
2458
- #爬虫来源:https://cloud.tencent.com/developer/article/1624480
2459
-
2460
- ###########XXX理财型基金-实时数据
2461
- #基金代码,基金简称,当前交易日-7日年化收益率,封闭期,申购状态
2462
- wmf_df = ak.fund_financial_fund_daily_em()
2463
- #理财型基金-历史数据
2464
- #净值日期,7日年化收益率,申购状态,赎回状态
2465
- wmf_hist_df = ak.fund_financial_fund_info_em("000134")
2466
-
2467
- ###########分级基金(结构化基金)-实时数据
2468
- #基金代码,基金简称,单位净值,累计净值,市价,折价率,手续费
2469
- gsf_df = ak.fund_graded_fund_daily_em()
2470
- #分级基金-历史数据
2471
- #净值日期,7日年化收益率,申购状态,赎回状态
2472
- gsf_hist_df = ak.fund_graded_fund_info_em("150232")
2473
-
2474
- ###抓取沪深股市所有指数关联的公募基金列表(含ETF、增强、分级等)
2475
- #代码来源:https://blog.csdn.net/leeleilei/article/details/106124894
2476
-
2477
- ###pyecharts绘制可伸缩蜡烛图
2478
- #代码地址:https://segmentfault.com/a/1190000021999451?utm_source=sf-related
2479
-
2480
- #==============================================================================
2481
- if __name__=='__main__':
2482
- etflist=choose_etf_china(etf_type='股票型',startpos=0,endpos=10,printout=True)
2483
-
2484
- def choose_etf_china(etf_type='股票型',startpos=0,endpos=10,printout=True):
2485
- """
2486
- 功能:从数据库中挑选中国ETF基金
2487
- 输入:
2488
- startpos=0,endpos=10:同型ETF列表的起始终止位置,同型ETF内部按照基金简称顺序排列
2489
- 输出:基金代码列表
2490
- """
2491
-
2492
- # 检查ETF类型
2493
- etf_types=['股票型','债券型','商品型','货币型','QDII','全部']
2494
- etf_type1=etf_type.upper()
2495
- if not (etf_type1 in etf_types):
2496
- print(" #Error(choose_etf_china): unsupported ETF type:",etf_type)
2497
- print(" Supported ETF types:",etf_types)
2498
- return None
2499
-
2500
- # 搜索处理ETF类型
2501
- import akshare as ak
2502
- names = ak.fund_name_em()
2503
-
2504
- names['ETF']=names['基金简称'].apply(lambda x: 1 if 'ETF' in x else 0)
2505
- names_etf=names[names['ETF']==1]
2506
-
2507
- if etf_type != '全部':
2508
- ftypea=['QDII','债券型-中短债','债券型-可转债','债券型-长债','商品(不含QDII)','指数型-股票','货币型']
2509
- ftypes=['QDII','债券型','债券型','债券型','商品型','股票型','货币型']
2510
- names_etf['基金分类']=names_etf['基金类型'].apply(lambda x:ftypes[ftypea.index(x)])
2511
- names_etf2=names_etf[names_etf['基金分类']==etf_type]
2512
- else:
2513
- names_etf2=names_etf
2514
-
2515
- names_etf2.sort_values(by=['基金分类','基金代码'],ascending=[True,True],inplace=True)
2516
- etfcols=['基金代码','基金简称','基金分类','基金类型']
2517
- names_etf2=names_etf2[etfcols]
2518
-
2519
- names_etf3=names_etf2[startpos:endpos]
2520
- if len(names_etf3)==0:
2521
- print(" #Error(choose_etf_china): no records of ETF selected")
2522
- print(" Parameter startpos",startpos,'should be smaller than endpos',endpos)
2523
- return None
2524
-
2525
- names_etf4=names_etf3[etfcols]
2526
- names_etf4.reset_index(drop=True,inplace=True)
2527
- names_etf4.index=names_etf4.index+1
2528
-
2529
- print("\n")
2530
- alignlist=['right','center','left']+['center']*(len(list(names_etf4))-2)
2531
- print(names_etf4.to_markdown(index=True,tablefmt='plain',colalign=alignlist))
2532
- print("\n*** ETF基金("+etf_type+")总数:",len(names_etf2),"\b。",end='')
2533
-
2534
- import datetime; today = datetime.date.today().strftime("%Y-%m-%d")
2535
- footnote=texttranslate("数据来源:新浪财经,")+today
2536
- print(footnote)
2537
-
2538
-
2539
- return list(names_etf4['基金代码']),names_etf2
2540
-
2541
- #==============================================================================
2542
- #==============================================================================
2543
- if __name__=='__main__':
2544
- fund='sh510170'
2545
- fund='sh000311'
2546
-
2547
- info=fund_info_china('sh510170')
2548
- info=fund_info_china('510170.SS')
2549
-
2550
- fund='510170.SS'
2551
-
2552
- def fund_info_china(fund):
2553
- """
2554
- 功能:查询中国基金代码和类型
2555
- 注意:实际仅需6位数字代码
2556
-
2557
- 数据来源:东方财富,天天基金网
2558
- """
2559
- print("Searching for fund info, it may take a long time, please wait ...")
2560
-
2561
- # 代码中提取6位数字
2562
- fund1=fund.upper()
2563
- exchlist=['SH','SZ','.SS','.SZ']
2564
- for exch in exchlist:
2565
- fund1=fund1.replace(exch,'')
2566
-
2567
- import pandas as pd
2568
- import akshare as ak
2569
-
2570
- # 检查基金是否存在
2571
- try:
2572
- names = ak.fund_name_em()
2573
- namedf=names[names['基金代码']==fund1]
2574
-
2575
- if len(namedf) >= 1:
2576
- df1=namedf[['基金代码','基金简称','基金类型']]
2577
- fname=namedf['基金简称'].values[0]
2578
- ftype=namedf['基金类型'].values[0]
2579
- else:
2580
- print(" #Warning(fund_info_china): info not found for fund",fund)
2581
- return None
2582
- except:
2583
- print(" #Warning(fund_info_china): info source inaccessible for now, try later")
2584
- return None
2585
-
2586
- # 基金评级
2587
- df6=pd.DataFrame()
2588
- titletxt6="基金概况与评级"
2589
- footnote6="注:评级机构为上海证券、招商证券和济安金信,数字表示星星个数,在同类基金中通常越高越好"
2590
- try:
2591
- dft6 = ak.fund_rating_all()
2592
- dft6t=dft6[dft6['代码']==fund1]
2593
- dft6t.fillna('---',inplace=True)
2594
- fmanager=dft6t['基金经理'].values[0]
2595
-
2596
- if len(dft6t) >= 1:
2597
- df6=dft6t
2598
- #printInMarkdown(df6,titletxt=titletxt6,footnote=footnote6)
2599
- df_display_CSS(df6,titletxt=titletxt6,footnote=footnote6,facecolor='papayawhip', \
2600
- first_col_align='left',second_col_align='left', \
2601
- last_col_align='center',other_col_align='center')
2602
-
2603
- except:
2604
- pass
2605
-
2606
- # 指数型基金信息
2607
- df2=pd.DataFrame()
2608
- titletxt2="指数型基金的相关信息"
2609
- footnote2="注:单位净值元,日/今年来/今年来的增长率及手续费为百分比"
2610
- try:
2611
- dft2 = ak.fund_info_index_em(symbol="全部", indicator="全部")
2612
- dft2.sort_values('基金代码',inplace=True)
2613
- dft2t=dft2[dft2['基金代码']==fund1]
2614
-
2615
- if len(dft2t) >= 1:
2616
- df2=dft2t[['基金代码','单位净值','日期','日增长率','今年来','手续费']]
2617
- #printInMarkdown(df2,titletxt=titletxt2,footnote=footnote2)
2618
- df_display_CSS(df2,titletxt=titletxt2,footnote=footnote2,facecolor='papayawhip', \
2619
- first_col_align='left',second_col_align='left', \
2620
- last_col_align='center',other_col_align='center')
2621
-
2622
- except:
2623
- pass
2624
-
2625
- # 基金持仓:股票
2626
- titletxt3="基金持仓情况:股票"
2627
- footnote3="注:占净值比例为百分比,持股数为万股,(持仓)市值为万元"
2628
- df3=pd.DataFrame()
2629
- import datetime; today = datetime.date.today()
2630
- thisYear=str(today)[:4]
2631
- try:
2632
- dft3 = ak.fund_portfolio_hold_em(symbol=fund1,date=thisYear)
2633
- dft3.sort_values(by=['季度','占净值比例'],ascending=[False,False],inplace=True)
2634
-
2635
- if len(dft3) >= 1:
2636
- df3=dft3
2637
- df3['持仓类型']='股票'
2638
- #printInMarkdown(df3,titletxt=titletxt3,footnote=footnote3)
2639
- df_display_CSS(df3,titletxt=titletxt3,footnote=footnote3,facecolor='papayawhip', \
2640
- first_col_align='left',second_col_align='left', \
2641
- last_col_align='center',other_col_align='center')
2642
-
2643
- except:
2644
- pass
2645
-
2646
- # 基金持仓:债券
2647
- titletxt4="基金持仓情况:债券"
2648
- df4=pd.DataFrame()
2649
- try:
2650
- dft4 = ak.fund_portfolio_bond_hold_em(symbol=fund1,date=thisYear)
2651
- dft4.sort_values(by=['季度','占净值比例'],ascending=[False,False],inplace=True)
2652
-
2653
- if len(dft4) >= 1:
2654
- df4=dft4
2655
- df4['持仓类型']='债券'
2656
- #printInMarkdown(df4,titletxt=titletxt4)
2657
- df_display_CSS(df4,titletxt=titletxt4,footnote='',facecolor='papayawhip', \
2658
- first_col_align='left',second_col_align='left', \
2659
- last_col_align='center',other_col_align='center')
2660
-
2661
- except:
2662
- print('')
2663
- print(titletxt4)
2664
- print("\n #Warning(fund_info_china): unable to retrieve bond holding info for",fund,"@",thisYear)
2665
-
2666
-
2667
- # 基金持仓:行业配置
2668
- titletxt5="基金的行业配置情况"
2669
- footnote5="注:占净值比例为百分比,市值为万元"
2670
- df5=pd.DataFrame()
2671
- try:
2672
- dft5 = ak.fund_portfolio_industry_allocation_em(symbol=fund1,date=thisYear)
2673
- dft5.sort_values(by=['截止时间','占净值比例'],ascending=[False,False],inplace=True)
2674
-
2675
- if len(dft5) >= 1:
2676
- df5=dft5
2677
- df5['持仓类型']='行业配置'
2678
- #printInMarkdown(df5,titletxt=titletxt5,footnote=footnote5)
2679
- df_display_CSS(df5,titletxt=titletxt5,footnote=footnote5,facecolor='papayawhip', \
2680
- first_col_align='left',second_col_align='left', \
2681
- last_col_align='center',other_col_align='center')
2682
-
2683
- except:
2684
- pass
2685
-
2686
- # 基金经理
2687
- titletxt7="基金经理的相关情况"
2688
- source="数据来源:东方财富/天天基金"
2689
- footnote7="注:从业时间为天数,现任基金资产总规模为该基金经理管辖所有基金的总规模(亿元),最佳回报为历史业绩(百分比)\n"+source+","+str(today)
2690
-
2691
- df7=pd.DataFrame()
2692
- try:
2693
- dft7 = ak.fund_manager(adjust='0')
2694
- dft7t=dft7[dft7['姓名']==fmanager]
2695
-
2696
- if len(dft7t) >= 1:
2697
- current=dft7t['现任基金'].values[0]
2698
- df7=dft7t[['姓名','所属公司','累计从业时间','现任基金资产总规模','现任基金最佳回报']]
2699
-
2700
- #printInMarkdown(df7,titletxt=titletxt7)
2701
- df_display_CSS(df7,titletxt=titletxt7,footnote='',facecolor='papayawhip', \
2702
- first_col_align='left',second_col_align='left', \
2703
- last_col_align='center',other_col_align='center')
2704
-
2705
-
2706
- print(' ')
2707
- print("基金经理当前兼任情况:")
2708
- num=print_long_text(current)
2709
- print(' ')
2710
- print(footnote7)
2711
- except:
2712
- print('')
2713
- print(titletxt7)
2714
- print("\n #Warning(fund_info_china): unable to retrieve job info for",fmanager)
2715
-
2716
- return
2717
-
2718
- #==============================================================================
2719
- #==============================================================================
2720
- #==============================================================================
2721
- if __name__=='__main__':
2722
- num_quarters=8
2723
-
2724
- get_past_quarters()
2725
-
2726
-
2727
- def get_past_quarters(num_quarters=8,date_format="%Y%m%d",date_reverse=False):
2728
- """
2729
- 功能:生成最近多个季度结束日期列表
2730
- 参数:
2731
- num_quarters:最近的季度个数,默认8.
2732
-
2733
- 返回值:列表,日期格式为YYYYMMDD,适合akshare的要求
2734
- """
2735
-
2736
- from datetime import datetime, date
2737
- from dateutil.relativedelta import relativedelta
2738
-
2739
- # 获取当前日期
2740
- today = date.today()
2741
- # 确定当前季度的结束日期
2742
- current_year = today.year
2743
- current_month = today.month
2744
- current_quarter = (current_month - 1) // 3 + 1 # 计算当前季度
2745
- quarter_end_month = current_quarter * 3 # 当前季度的结束月份
2746
- quarter_end_day = 31 if quarter_end_month in [3, 12] else 30 # 3月和12月是31天,其他季度末月份是30天
2747
- current_quarter_end_date = date(current_year, quarter_end_month, quarter_end_day)
2748
-
2749
- # 如果今天还没到季度末,需要调整为上一个季度的结束日期
2750
- if today < current_quarter_end_date:
2751
- current_quarter_end_date -= relativedelta(months=3)
2752
- quarter_end_month = current_quarter_end_date.month
2753
- quarter_end_day = 31 if quarter_end_month in [3, 12] else 30
2754
- current_quarter_end_date = date(current_quarter_end_date.year, quarter_end_month, quarter_end_day)
2755
-
2756
- # 生成过去连续的 num_quarters 个季度结束日期
2757
- quarter_dates = []
2758
- for _ in range(num_quarters):
2759
- quarter_dates.append(current_quarter_end_date)
2760
- current_quarter_end_date -= relativedelta(months=3)
2761
-
2762
- current_year = current_quarter_end_date.year
2763
- current_month = current_quarter_end_date.month
2764
- quarter_end_day = 31 if current_month in [3, 12] else 30 # 3月和12月是31天,其他季度末月份是30天
2765
- current_quarter_end_date = date(current_year, current_month, quarter_end_day)
2766
-
2767
-
2768
- # 格式化日期为 YYYY-MM-DD
2769
- quarter_dates = [date.strftime(date_format) for date in quarter_dates]
2770
-
2771
- if not date_reverse:
2772
- quarter_dates.reverse()
2773
-
2774
- return quarter_dates
2775
-
2776
-
2777
- #==============================================================================
2778
- if __name__=='__main__':
2779
- date_str='20241231'
2780
- from_format="%Y%m%d"; to_format="%Y-%m-%d"
2781
-
2782
- format_date(date_str,from_format="%Y%m%d",to_format="%Y-%m-%d")
2783
-
2784
- def format_date(date_str,from_format="%Y%m%d",to_format="%Y-%m-%d"):
2785
- # 将 YYYYMMDD 格式的字符串解析为日期对象
2786
-
2787
- from datetime import datetime
2788
-
2789
- date_obj = datetime.strptime(date_str, "%Y%m%d")
2790
- # 将日期对象格式化为 YYYY-MM-DD 格式
2791
- formatted_date = date_obj.strftime("%Y-%m-%d")
2792
-
2793
- return formatted_date
2794
-
2795
- #==============================================================================
2796
- if __name__=='__main__':
2797
- top=10
2798
- sortby='持有基金家数'
2799
- sortby='持股变动数值'
2800
- holder_type="基金持仓"
2801
-
2802
- def fund_holding_stock_rank_china(ticker='',top=5,sortby='持有基金家数',holder_type="基金持仓"):
2803
- """
2804
- ===========================================================================
2805
- 功能:列出基金持股比例最高的股票及其持股信息
2806
- 参数:
2807
- ticker:股票代码,默认空'',对全市场股票进行排行;若指定股票代码,则着重显示该股票的排行。
2808
- top=5:若不指定股票代码,列出基金持股比例最高的股票个数,默认10;
2809
- 若指定股票代码,则列示该股票及其前后的排行。
2810
- sortby:排行指标,默认'持有基金家数'。
2811
- 支持指标:'持有基金家数','持股总数','持股市值','持股变动数值','持股变动比例'(百分比)
2812
-
2813
- holder_type:持仓基金类别,默认"基金持仓"。
2814
- 支持类别:"基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"
2815
- 1. 基金持仓:主要反映公募基金和私募基金的持仓情况。
2816
- 2. QFII持仓:反映合格境外机构投资者(QFII)的持仓情况。
2817
- 3. 社保持仓:反映社保基金的持仓情况。
2818
- 4. 券商持仓:反映证券公司的自营业务持仓情况。
2819
- 5. 保险持仓:反映保险资金的持仓情况。
2820
- 6. 信托持仓:反映信托公司的持仓情况。
2821
- 在东方财富网中,“基金持仓”不包括QFII持仓、社保持仓、券商持仓、保险持仓或信托持仓。
2822
-
2823
- • 基金持仓:多样化投资策略,专业管理,透明度高,追求相对收益。
2824
- 公募基金通常具有较高的流动性,投资者可以方便地申购和赎回。
2825
- 公募基金通常追求超越基准指数的收益,注重长期业绩表现。
2826
- • QFII持仓:注重基本面和估值,长期投资,偏好高ROE和成长股,行业集中度较高。
2827
- QFII倾向于选择基本面良好、估值合理的股票,偏好行业龙头。
2828
- QFII的投资策略较为长期,持股时间较长,注重公司的长期增长潜力。
2829
- QFII偏好高净资产收益率(ROE)的个股,近年来也逐渐增加对成长股的投资。
2830
- 重仓行业通常集中在相对安全、稳健的行业,如银行、食品饮料、医药等。
2831
- QFII在市场趋势判断方面表现出色,能够在市场高点前加仓,在低点前减仓。
2832
- • 社保持仓:长期价值投资,稳健投资,风险控制严格,市场风向标。
2833
- 社保基金注重长期投资,追求稳定收益,通常持有股票的时间较长。
2834
- 偏好稳健的股票,注重公司的基本面和盈利能力。
2835
- 社保基金对风险控制要求高,投资决策较为谨慎。
2836
- 社保基金的持仓变化被视为市场的风向标,其增仓或减仓行为可能预示市场趋势。
2837
- • 券商持仓:灵活性高,信息优势,强周期性,注重短期收益。
2838
- 券商可能更注重短期的市场波动和交易机会,追求短期收益。
2839
- • 保险持仓:稳健保守,长期投资,资产配置多元化,风险控制严格。
2840
- 保险资金注重资产的安全性和流动性,追求稳健收益。
2841
- 保险资金的投资期限较长,通常进行长期投资。
2842
- 对风险控制要求高,注重资产负债匹配管理。
2843
- • 信托持仓:灵活性高,定制化服务,风险与收益平衡,专业管理。
2844
- 信托可以根据委托人的需求提供定制化的投资方案。
2845
-
2846
-
2847
- 返回值:df
2848
- """
2849
- holder_type_list=["基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"]
2850
- if not (holder_type in holder_type_list):
2851
- print(f" #Warning(fund_holding_stock_rank): {holder_type} not supported")
2852
- print(f" Supported types: {holder_type_list}")
2853
- holder_type="基金持仓"
2854
-
2855
- import akshare as ak
2856
-
2857
- quarter_dates=get_past_quarters(num_quarters=4,date_format="%Y%m%d",date_reverse=False)
2858
- recent_quarter_date=quarter_dates[-1]
2859
- recent_quarter_date2=format_date(recent_quarter_date,from_format="%Y%m%d",to_format="%Y-%m-%d")
2860
-
2861
- # symbol="基金持仓"; choice of {"基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"}
2862
- df = ak.stock_report_fund_hold(symbol=holder_type, date=recent_quarter_date)
2863
-
2864
- sortby_list=['持有基金家数','持股总数','持股市值','持股变化','持股变动数值','持股变动比例']
2865
- if sortby not in sortby_list:
2866
- print(" #Warning: sortby option only supports the following:")
2867
- print(f" {sortby_list}")
2868
- sortby=sortby_list[0]
2869
-
2870
- if sortby != '持有基金家数':
2871
- df.sort_values(sortby,ascending=False,inplace=True)
2872
- else:
2873
- df = df.sort_values(by=[sortby, '持股总数'], ascending=[False, False])
2874
-
2875
- df.reset_index(drop=True,inplace=True)
2876
- df['序号']=df.index+1
2877
-
2878
- # 挪动排名项目
2879
- df=shift_column_position(df,sortby,position=3)
2880
-
2881
- df2=df.copy()
2882
-
2883
- wan=10000; yiyuan=100000000
2884
- df2['持股总数'] =df2['持股总数']/wan
2885
- df2['持股总数'] =df2['持股总数'].apply(lambda x: round(x,2))
2886
-
2887
- df2['持股变动数值'] =df2['持股变动数值']/wan
2888
- df2['持股变动数值'] =df2['持股变动数值'].apply(lambda x: round(x,2))
2889
-
2890
- df2['持股市值'] =df2['持股市值']/yiyuan
2891
- df2['持股市值'] =df2['持股市值'].apply(lambda x: round(x,2))
2892
-
2893
- if top > 0:
2894
- df3=df2.head(top)
2895
- elif top < 0:
2896
- df3=df2.tail(-top)
2897
- else:
2898
- df3=df2.head(5)
2899
-
2900
- #强制显示所选股票
2901
- #if force_show_stock and rank != 10:
2902
- if ticker != '':
2903
- #所选股票是否在其中?
2904
- if not ticker[:6] in list(df3["股票代码"]):
2905
- try:
2906
- ticker_seq=df2[df2["股票代码"]==ticker[:6]]["序号"].values[0]
2907
- except:
2908
- print(f" #Error(fund_holding_stock_rank): {ticker} not found in {holder_type}")
2909
- return None
2910
-
2911
- num_before=int(top/2)
2912
- if num_before * 2 == top: num_before=num_before-1
2913
- num_after=top-num_before-1
2914
-
2915
- #seq1=ticker_seq-4; seq2=ticker_seq+5
2916
- seq1=ticker_seq-num_before; seq2=ticker_seq+num_after
2917
- #如果超出开头
2918
- if seq1 <=0:
2919
- seq1=1; seq2=top
2920
- #如果超出结尾
2921
- if seq2 > len(df2):
2922
- seq2=len(df2); seq1=len(df2)-(top-1)
2923
-
2924
- #注意:此处的&不能换为and
2925
- df3=df2[(df2["序号"]>=seq1) & (df2["序号"]<=seq2)]
2926
-
2927
- titletxt=holder_type+'排名:基于'+sortby
2928
- import datetime
2929
- todaydt = datetime.date.today()
2930
- #footnote0="【注释】排名方法:"+sortby
2931
- footnote0="【注释】数据截至"+recent_quarter_date2
2932
- footnote1=';持股总数/持股变动数值:万股,持股市值:亿元'
2933
- footnote2='。数据来源:东方财富/天天基金,'+str(todaydt)
2934
- footnote=footnote0+footnote1+footnote2
2935
-
2936
- df_display_CSS(df3,titletxt=titletxt,footnote=footnote, \
2937
- facecolor='papayawhip',decimals=2, \
2938
- first_col_align='left',second_col_align='left', \
2939
- last_col_align='right',other_col_align='right', \
2940
- titile_font_size='16px',heading_font_size='15px', \
2941
- data_font_size='14px',footnote_font_size='13px')
2942
-
2943
- return df
2944
-
2945
- #==============================================================================
2946
- if __name__=='__main__':
2947
- ticker='689009.SS'
2948
- num_quarters=8
2949
-
2950
-
2951
- def fund_holding_stock_trend_china(ticker,num_quarters=8,holder_type="基金持仓", \
2952
- close_price=False):
2953
- """
2954
- ===========================================================================
2955
- 功能:列出一只股票被基金持股的变动趋势
2956
- 参数:
2957
- ticker:股票代码
2958
- num_quarters:最近基金持股的季度个数,默认8。
2959
- holder_type:持仓基金类别,默认"基金持仓";若为'ALL'则扫描所有机构持股信息,时间较长。
2960
-
2961
- 返回值:df
2962
- """
2963
- holder_type_list=["基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"]
2964
- if not (holder_type in holder_type_list):
2965
- print(f" #Warning(fund_holding_stock_trend): {holder_type} not supported")
2966
- print(f" Supported types: {holder_type_list}")
2967
- holder_type="基金持仓"
2968
-
2969
- import akshare as ak
2970
- import pandas as pd
2971
-
2972
- quarter_dates=get_past_quarters(num_quarters=num_quarters,date_format="%Y%m%d",date_reverse=False)
2973
-
2974
-
2975
- df=pd.DataFrame()
2976
- for d in quarter_dates:
2977
- print(f" Searching {holder_type} info on {ticker} in {d} ...")
2978
-
2979
- # symbol="基金持仓"; choice of {"基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"}
2980
- try:
2981
- dftmp = ak.stock_report_fund_hold(symbol=holder_type, date=d)
2982
- except:
2983
- continue
2984
-
2985
- try:
2986
- dftmp2=dftmp[dftmp['股票代码']==ticker[:6]]
2987
- except:
2988
- break
2989
-
2990
- d2=format_date(d,from_format="%Y%m%d",to_format="%Y-%m-%d")
2991
- dftmp2['季度']=d2
2992
- #dftmp2['机构类别']=holder_type
2993
-
2994
-
2995
- if len(df)==0:
2996
- df=dftmp2
2997
- else:
2998
- df=pd.concat([df, dftmp2], axis=0, ignore_index=True)
2999
-
3000
- # 未找到股票
3001
- if len(df)==0:
3002
- print(f" #Error(fund_holding_stock_trend): stock {ticker} not found or not holded by fund")
3003
- return None
3004
-
3005
- # 重排字段
3006
- stock_name=df['股票简称'].values[0]
3007
- col_list=['季度','持股变化','持股变动数值','持股变动比例','持有基金家数','持股总数','持股市值']
3008
- df2=df[col_list]
3009
-
3010
-
3011
- wan=10000; yiyuan=100000000
3012
- df2['持股总数'] =df2['持股总数']/wan
3013
- df2['持股总数'] =df2['持股总数'].apply(lambda x: round(x,2))
3014
-
3015
- df2['持股变动数值'] =df2['持股变动数值']/wan
3016
- df2['持股变动数值'] =df2['持股变动数值'].apply(lambda x: round(x,2))
3017
-
3018
- df2['持股市值'] =df2['持股市值']/yiyuan
3019
- df2['持股市值'] =df2['持股市值'].apply(lambda x: round(x,2))
3020
-
3021
- if not close_price:
3022
- df4=df2
3023
- else:
3024
- ticker2=tickers_cvt2ak(ticker)
3025
- fromdate=df2['季度'].values[0]; fromdate=date_adjust(fromdate, adjust=-30)
3026
- todate=df2['季度'].values[-1]; todate=date_adjust(todate, adjust=30)
3027
- result,start,end=check_period(fromdate,todate)
3028
- start1=start.strftime('%Y%m%d'); end1=end.strftime('%Y%m%d')
3029
- prices=security_trend(ticker,start=fromdate,end=todate,graph=False)
3030
- prices.index = pd.to_datetime(prices.index, format='%Y-%m-%d')
3031
- prices['收盘价']=prices['Close']
3032
- prices['季度']=prices.index.strftime('%Y-%m-%d')
3033
- prices2=prices[['季度','收盘价']]
3034
-
3035
-
3036
- df3=pd.merge(df2,prices2,on='季度',how='outer')
3037
- # 使用前一个非空值填充某一列的空缺值
3038
- df3['收盘价'] = df3['收盘价'].fillna(method='ffill')
3039
- # 使用后一个非空值填充某一列的空缺值
3040
- df3['收盘价'] = df3['收盘价'].fillna(method='bfill')
3041
- # 删除列 'A' 中包含空缺值的所有行
3042
- df4 = df3.dropna(subset=['持有基金家数'])
3043
-
3044
- titletxt=holder_type+'变动趋势:'+stock_name
3045
- import datetime
3046
- todaydt = datetime.date.today()
3047
- #footnote0="【注释】排名方法:"+sortby
3048
- footnote0="【注释】"
3049
- footnote1='持股总数/持股变动数值:万股,持股市值:亿元'
3050
- footnote2='。数据来源:东方财富/天天基金,'+str(todaydt)
3051
- footnote=footnote0+footnote1+footnote2
3052
-
3053
- df_display_CSS(df4,titletxt=titletxt,footnote=footnote, \
3054
- facecolor='papayawhip',decimals=2, \
3055
- first_col_align='left',second_col_align='left', \
3056
- last_col_align='right',other_col_align='right', \
3057
- titile_font_size='16px',heading_font_size='15px', \
3058
- data_font_size='14px',footnote_font_size='13px')
3059
-
3060
- return df
3061
-
3062
- #==============================================================================
3063
- if __name__=='__main__':
3064
- ticker='689009.SS'
3065
- ticker='600519.SS'
3066
- num_quarters=8
3067
-
3068
-
3069
- def fund_holding_stock_trend_all_china(ticker,num_quarters=4):
3070
- """
3071
- ===========================================================================
3072
- 功能:列出一只股票被所有机构类别持股的变动趋势
3073
- 参数:
3074
- ticker:股票代码
3075
- num_quarters:最近基金持股的季度个数,默认8。
3076
-
3077
- 返回值:df
3078
- """
3079
- holder_type_list=["基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"]
3080
-
3081
- import akshare as ak
3082
- import pandas as pd
3083
-
3084
- quarter_dates=get_past_quarters(num_quarters=num_quarters,date_format="%Y%m%d",date_reverse=False)
3085
-
3086
-
3087
- df=pd.DataFrame()
3088
- for ht in holder_type_list:
3089
- print(f" Searching {ht} info on {ticker} ...")
3090
-
3091
- for d in quarter_dates:
3092
-
3093
- try:
3094
- dftmp = ak.stock_report_fund_hold(symbol=ht, date=d)
3095
- except:
3096
- continue
3097
-
3098
- try:
3099
- dftmp2=dftmp[dftmp['股票代码']==ticker[:6]]
3100
- except:
3101
- break
3102
-
3103
- d2=format_date(d,from_format="%Y%m%d",to_format="%Y-%m-%d")
3104
- dftmp2['季度']=d2
3105
- dftmp2['机构类别']=ht
3106
-
3107
-
3108
- if len(df)==0:
3109
- df=dftmp2
3110
- else:
3111
- df=pd.concat([df, dftmp2], axis=0, ignore_index=True)
3112
-
3113
- # 未找到股票
3114
- if len(df)==0:
3115
- print(f" #Error(fund_holding_stock_trend): stock {ticker} not found or not holded by fund")
3116
- return None
3117
-
3118
- # 重排字段
3119
- stock_name=df['股票简称'].values[0]
3120
- col_list=['季度','机构类别','持股变化','持股变动数值','持股变动比例','持有基金家数','持股总数','持股市值']
3121
- df2=df[col_list]
3122
- df2= df2.sort_values(['季度'],ascending=[True])
3123
-
3124
-
3125
- wan=10000; yiyuan=100000000
3126
- df2['持股总数'] =df2['持股总数']/wan
3127
- df2['持股总数'] =df2['持股总数'].apply(lambda x: round(x,2))
3128
-
3129
- df2['持股变动数值'] =df2['持股变动数值']/wan
3130
- df2['持股变动数值'] =df2['持股变动数值'].apply(lambda x: round(x,2))
3131
-
3132
- df2['持股市值'] =df2['持股市值']/yiyuan
3133
- df2['持股市值'] =df2['持股市值'].apply(lambda x: round(x,2))
3134
-
3135
- titletxt='机构持仓变动趋势:'+stock_name
3136
- import datetime
3137
- todaydt = datetime.date.today()
3138
- #footnote0="【注释】排名方法:"+sortby
3139
- footnote0="【注释】"
3140
- footnote1='持股总数/持股变动数值:万股,持股市值:亿元'
3141
- footnote2='。数据来源:东方财富/天天基金,'+str(todaydt)
3142
- footnote=footnote0+footnote1+footnote2
3143
-
3144
- df_display_CSS(df2,titletxt=titletxt,footnote=footnote, \
3145
- facecolor='papayawhip',decimals=2, \
3146
- first_col_align='left',second_col_align='left', \
3147
- last_col_align='right',other_col_align='right', \
3148
- titile_font_size='16px',heading_font_size='15px', \
3149
- data_font_size='14px',footnote_font_size='13px')
3150
-
3151
- return df
3152
-
3153
-
3154
- #==============================================================================
3155
- if __name__=='__main__':
3156
- ticker='600519.SS'
3157
- ticker='600305.SS'
3158
- top=3
3159
-
3160
- def stock_heldby_fund_detail_china(ticker,top=5):
3161
- """
3162
- ===========================================================================
3163
- 功能:列示持有一只股票最多的前几名基金列表。
3164
- 参数:
3165
- ticker:股票代码
3166
- top:列示前几名,默认5
3167
-
3168
- 返回值:数据表
3169
- """
3170
-
3171
- import akshare as ak
3172
-
3173
- # 获取某只股票被基金持股的数据
3174
- try:
3175
- df = ak.stock_fund_stock_holder(symbol=ticker[:6])
3176
- except:
3177
- print(f"Sorry, no fund holding details found for {ticker} in data source")
3178
- return None
3179
-
3180
- df2=df.copy()
3181
-
3182
- wan=10000; yiyuan=100000000
3183
- df2['持仓数量'] =df2['持仓数量']/wan
3184
- df2['持仓数量'] =df2['持仓数量'].apply(lambda x: round(x,2))
3185
-
3186
- df2['持股市值'] =df2['持股市值']/yiyuan
3187
- df2['持股市值'] =df2['持股市值'].apply(lambda x: round(x,2))
3188
-
3189
- # 按持股比例降序排列
3190
- df3 = df2.sort_values(by='占流通股比例', ascending=False)
3191
-
3192
- # 取前五名基金
3193
- df4 = df3.head(top)
3194
- df4['序号']=df4.index+1
3195
- df4=shift_column_position(df4,col_name='序号',position=0)
3196
-
3197
- ddl_date=df4['截止日期'].values[0]
3198
- del df4['截止日期']
3199
-
3200
- quarter_dates=get_past_quarters(num_quarters=8,date_format="%Y%m%d",date_reverse=False)
3201
- recent_quarter_date=quarter_dates[-1]
3202
- recent_quarter_date2=format_date(recent_quarter_date,from_format="%Y%m%d",to_format="%Y-%m-%d")
3203
- if str(ddl_date) < str(recent_quarter_date2):
3204
- print("Pity, fund holding stock info may be far out of date:-(")
3205
-
3206
- titletxt=ticker_name(ticker)+':机构持仓情况,截至'+str(ddl_date)
3207
- import datetime
3208
- todaydt = datetime.date.today()
3209
- #footnote0="【注释】排名方法:"+sortby
3210
- footnote0="【注释】"
3211
- footnote1='持仓数量:万股,持股市值:亿元'
3212
- footnote2='。数据来源:新浪财经,'+str(todaydt)
3213
- footnote=footnote0+footnote1+footnote2
3214
-
3215
- df_display_CSS(df4,titletxt=titletxt,footnote=footnote, \
3216
- facecolor='papayawhip',decimals=2, \
3217
- first_col_align='center',second_col_align='left', \
3218
- last_col_align='right',other_col_align='right', \
3219
- titile_font_size='16px',heading_font_size='15px', \
3220
- data_font_size='14px',footnote_font_size='13px')
3221
-
3222
- return df
3223
- #==============================================================================
3224
-
3225
-
3226
-
3227
- def fund_holding_stock_china(ticker='',top=5,sortby='持有基金家数', \
3228
- holder_type="基金持仓",quarter='recent', \
3229
- detail=False, \
3230
- close_price=False):
3231
- """
3232
- ===========================================================================
3233
- 功能:列示中国内地机构持股情况。
3234
- 参数:
3235
- ticker:股票代码,默认'',列示最受机构追捧的股票排行及其被机构持仓情况。
3236
- 若为一个股票代码,则列示该股票的排行情况及其被机构持仓情况。
3237
- top:列示排行时的个数,默认5。
3238
- sortby:当列示排行时标示排行的指标,默认'持有基金家数'。
3239
- holder_type:机构持仓的类别,默认"基金持仓"。
3240
- 当为ALL时列示所有机构类别的持仓情况。
3241
- 仅有少数热门股票在除“基金持仓”以外的类别有数据,数据亦可能较久远。
3242
- quarter:指示列示数据的季度,默认'recent'仅列示最近一个季度末的披露数据。
3243
- 若为数字则列示近若干个季度的机构持仓变动趋势。
3244
- 与holder_type='ALL'配合时列示近若干个季度的所有机构类别的持仓变动趋势。
3245
- detail:是否列示持有一只股票的机构持仓情况,仅当ticker不为空时有效,默认False。
3246
- close_price:当列示持有一只股票的机构持仓情况是否同时列示股价,默认False。
3247
-
3248
- 返回值:数据表,无数据时返回空。
3249
- """
3250
-
3251
- if quarter=='recent' and holder_type.upper() != 'ALL' and not detail:
3252
- df=fund_holding_stock_rank_china(ticker=ticker,top=top, \
3253
- sortby=sortby,holder_type=holder_type)
3254
-
3255
- elif ticker != '' and isinstance(quarter,int) and holder_type.upper() != 'ALL' and not detail:
3256
- df=fund_holding_stock_trend_china(ticker=ticker,num_quarters=quarter, \
3257
- holder_type=holder_type, \
3258
- close_price=close_price)
3259
-
3260
- elif ticker != '' and isinstance(quarter,int) and holder_type.upper() == 'ALL' and not detail:
3261
- df=fund_holding_stock_trend_all_china(ticker=ticker,num_quarters=quarter)
3262
-
3263
- elif ticker != '' and detail:
3264
- df=stock_heldby_fund_detail_china(ticker=ticker,top=top)
3265
-
3266
- else:
3267
- print("Sorry, no idea on what you expect to do:-(")
3268
-
3269
- return df
3270
-
3271
-
3272
- #==============================================================================
3273
- #==============================================================================
3274
- #==============================================================================
3275
- #==============================================================================
3276
- #==============================================================================
3277
- #==============================================================================
3278
- #==============================================================================
3279
- #==============================================================================
3280
-
3281
-
3282
-
3283
-
3284
-
3285
-
3286
-
3287
-
3288
-
3289
-
3290
-
3291
-
3292
-
3293
-
3294
-
3295
-
3296
-
3297
-
3298
-
3299
-
3300
-
3301
-
3302
-
3303
-
3304
-
3305
-
3306
-
3307
-