siat 3.7.28__py3-none-any.whl → 3.8.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- siat/__init__.py +27 -5
- siat/allin.py +2 -0
- siat/beta_adjustment.py +1 -1
- siat/beta_adjustment_china.py +1 -1
- siat/bond.py +4 -2
- siat/bond_base.py +2 -1
- siat/bond_china.py +2 -1
- siat/capm_beta2.py +57 -14
- siat/common.py +57 -12
- siat/cryptocurrency.py +6 -3
- siat/economy2.py +977 -0
- siat/financials.py +4 -2
- siat/financials2.py +4 -2
- siat/financials_china.py +2 -1
- siat/fund.py +12 -12
- siat/fund_china.py +561 -2
- siat/grafix.py +185 -50
- siat/holding_risk.py +4 -2
- siat/market_china.py +4 -1
- siat/markowitz.py +7 -7
- siat/markowitz2.py +6 -5
- siat/option_china.py +3 -2
- siat/risk_adjusted_return.py +2 -2
- siat/risk_evaluation.py +10 -6
- siat/sector_china.py +62 -28
- siat/security_trend2.py +10 -2
- siat/stock.py +18 -5
- siat/stock_profile.py +2 -1
- siat/stock_technical.py +2 -1
- siat/translate.py +280 -5
- {siat-3.7.28.dist-info → siat-3.8.10.dist-info}/METADATA +2 -10
- {siat-3.7.28.dist-info → siat-3.8.10.dist-info}/RECORD +35 -34
- {siat-3.7.28.dist-info → siat-3.8.10.dist-info}/WHEEL +1 -1
- {siat-3.7.28.dist-info → siat-3.8.10.dist-info}/LICENSE +0 -0
- {siat-3.7.28.dist-info → siat-3.8.10.dist-info}/top_level.txt +0 -0
siat/fund_china.py
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
所属工具包:证券投资分析工具SIAT
|
5
5
|
SIAT:Security Investment Analysis Tool
|
6
6
|
创建日期:2020年10月17日
|
7
|
-
最新修订日期:
|
7
|
+
最新修订日期:2025年3月28日
|
8
8
|
作者:王德宏 (WANG Dehong, Peter)
|
9
9
|
作者单位:北京外国语大学国际商学院
|
10
10
|
版权所有:王德宏
|
@@ -19,6 +19,7 @@ from siat.common import *
|
|
19
19
|
from siat.translate import *
|
20
20
|
from siat.grafix import *
|
21
21
|
from siat.bond_base import *
|
22
|
+
from siat.security_trend2 import *
|
22
23
|
#==============================================================================
|
23
24
|
def compare_fund_holding_china(ticker,quarters,rank=10,font_size='14px'):
|
24
25
|
"""
|
@@ -439,7 +440,7 @@ def reits_jsl_china(fund='',rank=10):
|
|
439
440
|
df1 = ak.reits_info_jsl()
|
440
441
|
df2 = ak.reits_realtime_em()
|
441
442
|
except:
|
442
|
-
print("
|
443
|
+
print("Sorry, data source rejected access")
|
443
444
|
return None
|
444
445
|
|
445
446
|
#合成基金类型信息
|
@@ -2687,8 +2688,566 @@ def fund_info_china(fund):
|
|
2687
2688
|
#==============================================================================
|
2688
2689
|
#==============================================================================
|
2689
2690
|
#==============================================================================
|
2691
|
+
if __name__=='__main__':
|
2692
|
+
num_quarters=8
|
2693
|
+
|
2694
|
+
get_past_quarters()
|
2695
|
+
|
2696
|
+
|
2697
|
+
def get_past_quarters(num_quarters=8,date_format="%Y%m%d",date_reverse=False):
|
2698
|
+
"""
|
2699
|
+
功能:生成最近多个季度结束日期列表
|
2700
|
+
参数:
|
2701
|
+
num_quarters:最近的季度个数,默认8.
|
2702
|
+
|
2703
|
+
返回值:列表,日期格式为YYYYMMDD,适合akshare的要求
|
2704
|
+
"""
|
2705
|
+
|
2706
|
+
from datetime import datetime, date
|
2707
|
+
from dateutil.relativedelta import relativedelta
|
2708
|
+
|
2709
|
+
# 获取当前日期
|
2710
|
+
today = date.today()
|
2711
|
+
# 确定当前季度的结束日期
|
2712
|
+
current_year = today.year
|
2713
|
+
current_month = today.month
|
2714
|
+
current_quarter = (current_month - 1) // 3 + 1 # 计算当前季度
|
2715
|
+
quarter_end_month = current_quarter * 3 # 当前季度的结束月份
|
2716
|
+
quarter_end_day = 31 if quarter_end_month in [3, 12] else 30 # 3月和12月是31天,其他季度末月份是30天
|
2717
|
+
current_quarter_end_date = date(current_year, quarter_end_month, quarter_end_day)
|
2718
|
+
|
2719
|
+
# 如果今天还没到季度末,需要调整为上一个季度的结束日期
|
2720
|
+
if today < current_quarter_end_date:
|
2721
|
+
current_quarter_end_date -= relativedelta(months=3)
|
2722
|
+
quarter_end_month = current_quarter_end_date.month
|
2723
|
+
quarter_end_day = 31 if quarter_end_month in [3, 12] else 30
|
2724
|
+
current_quarter_end_date = date(current_quarter_end_date.year, quarter_end_month, quarter_end_day)
|
2725
|
+
|
2726
|
+
# 生成过去连续的 num_quarters 个季度结束日期
|
2727
|
+
quarter_dates = []
|
2728
|
+
for _ in range(num_quarters):
|
2729
|
+
quarter_dates.append(current_quarter_end_date)
|
2730
|
+
current_quarter_end_date -= relativedelta(months=3)
|
2731
|
+
|
2732
|
+
current_year = current_quarter_end_date.year
|
2733
|
+
current_month = current_quarter_end_date.month
|
2734
|
+
quarter_end_day = 31 if current_month in [3, 12] else 30 # 3月和12月是31天,其他季度末月份是30天
|
2735
|
+
current_quarter_end_date = date(current_year, current_month, quarter_end_day)
|
2736
|
+
|
2737
|
+
|
2738
|
+
# 格式化日期为 YYYY-MM-DD
|
2739
|
+
quarter_dates = [date.strftime(date_format) for date in quarter_dates]
|
2740
|
+
|
2741
|
+
if not date_reverse:
|
2742
|
+
quarter_dates.reverse()
|
2743
|
+
|
2744
|
+
return quarter_dates
|
2745
|
+
|
2746
|
+
|
2690
2747
|
#==============================================================================
|
2748
|
+
if __name__=='__main__':
|
2749
|
+
date_str='20241231'
|
2750
|
+
from_format="%Y%m%d"; to_format="%Y-%m-%d"
|
2751
|
+
|
2752
|
+
format_date(date_str,from_format="%Y%m%d",to_format="%Y-%m-%d")
|
2753
|
+
|
2754
|
+
def format_date(date_str,from_format="%Y%m%d",to_format="%Y-%m-%d"):
|
2755
|
+
# 将 YYYYMMDD 格式的字符串解析为日期对象
|
2756
|
+
|
2757
|
+
from datetime import datetime
|
2758
|
+
|
2759
|
+
date_obj = datetime.strptime(date_str, "%Y%m%d")
|
2760
|
+
# 将日期对象格式化为 YYYY-MM-DD 格式
|
2761
|
+
formatted_date = date_obj.strftime("%Y-%m-%d")
|
2762
|
+
|
2763
|
+
return formatted_date
|
2764
|
+
|
2691
2765
|
#==============================================================================
|
2766
|
+
if __name__=='__main__':
|
2767
|
+
top=10
|
2768
|
+
sortby='持有基金家数'
|
2769
|
+
sortby='持股变动数值'
|
2770
|
+
holder_type="基金持仓"
|
2771
|
+
|
2772
|
+
def fund_holding_stock_rank_china(ticker='',top=5,sortby='持有基金家数',holder_type="基金持仓"):
|
2773
|
+
"""
|
2774
|
+
===========================================================================
|
2775
|
+
功能:列出基金持股比例最高的股票及其持股信息
|
2776
|
+
参数:
|
2777
|
+
ticker:股票代码,默认空'',对全市场股票进行排行;若指定股票代码,则着重显示该股票的排行。
|
2778
|
+
top=5:若不指定股票代码,列出基金持股比例最高的股票个数,默认10;
|
2779
|
+
若指定股票代码,则列示该股票及其前后的排行。
|
2780
|
+
sortby:排行指标,默认'持有基金家数'。
|
2781
|
+
支持指标:'持有基金家数','持股总数','持股市值','持股变动数值','持股变动比例'(百分比)
|
2782
|
+
|
2783
|
+
holder_type:持仓基金类别,默认"基金持仓"。
|
2784
|
+
支持类别:"基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"
|
2785
|
+
1. 基金持仓:主要反映公募基金和私募基金的持仓情况。
|
2786
|
+
2. QFII持仓:反映合格境外机构投资者(QFII)的持仓情况。
|
2787
|
+
3. 社保持仓:反映社保基金的持仓情况。
|
2788
|
+
4. 券商持仓:反映证券公司的自营业务持仓情况。
|
2789
|
+
5. 保险持仓:反映保险资金的持仓情况。
|
2790
|
+
6. 信托持仓:反映信托公司的持仓情况。
|
2791
|
+
在东方财富网中,“基金持仓”不包括QFII持仓、社保持仓、券商持仓、保险持仓或信托持仓。
|
2792
|
+
|
2793
|
+
• 基金持仓:多样化投资策略,专业管理,透明度高,追求相对收益。
|
2794
|
+
公募基金通常具有较高的流动性,投资者可以方便地申购和赎回。
|
2795
|
+
公募基金通常追求超越基准指数的收益,注重长期业绩表现。
|
2796
|
+
• QFII持仓:注重基本面和估值,长期投资,偏好高ROE和成长股,行业集中度较高。
|
2797
|
+
QFII倾向于选择基本面良好、估值合理的股票,偏好行业龙头。
|
2798
|
+
QFII的投资策略较为长期,持股时间较长,注重公司的长期增长潜力。
|
2799
|
+
QFII偏好高净资产收益率(ROE)的个股,近年来也逐渐增加对成长股的投资。
|
2800
|
+
重仓行业通常集中在相对安全、稳健的行业,如银行、食品饮料、医药等。
|
2801
|
+
QFII在市场趋势判断方面表现出色,能够在市场高点前加仓,在低点前减仓。
|
2802
|
+
• 社保持仓:长期价值投资,稳健投资,风险控制严格,市场风向标。
|
2803
|
+
社保基金注重长期投资,追求稳定收益,通常持有股票的时间较长。
|
2804
|
+
偏好稳健的股票,注重公司的基本面和盈利能力。
|
2805
|
+
社保基金对风险控制要求高,投资决策较为谨慎。
|
2806
|
+
社保基金的持仓变化被视为市场的风向标,其增仓或减仓行为可能预示市场趋势。
|
2807
|
+
• 券商持仓:灵活性高,信息优势,强周期性,注重短期收益。
|
2808
|
+
券商可能更注重短期的市场波动和交易机会,追求短期收益。
|
2809
|
+
• 保险持仓:稳健保守,长期投资,资产配置多元化,风险控制严格。
|
2810
|
+
保险资金注重资产的安全性和流动性,追求稳健收益。
|
2811
|
+
保险资金的投资期限较长,通常进行长期投资。
|
2812
|
+
对风险控制要求高,注重资产负债匹配管理。
|
2813
|
+
• 信托持仓:灵活性高,定制化服务,风险与收益平衡,专业管理。
|
2814
|
+
信托可以根据委托人的需求提供定制化的投资方案。
|
2815
|
+
|
2816
|
+
|
2817
|
+
返回值:df
|
2818
|
+
"""
|
2819
|
+
holder_type_list=["基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"]
|
2820
|
+
if not (holder_type in holder_type_list):
|
2821
|
+
print(f" #Warning(fund_holding_stock_rank): {holder_type} not supported")
|
2822
|
+
print(f" Supported types: {holder_type_list}")
|
2823
|
+
holder_type="基金持仓"
|
2824
|
+
|
2825
|
+
import akshare as ak
|
2826
|
+
|
2827
|
+
quarter_dates=get_past_quarters(num_quarters=4,date_format="%Y%m%d",date_reverse=False)
|
2828
|
+
recent_quarter_date=quarter_dates[-1]
|
2829
|
+
recent_quarter_date2=format_date(recent_quarter_date,from_format="%Y%m%d",to_format="%Y-%m-%d")
|
2830
|
+
|
2831
|
+
# symbol="基金持仓"; choice of {"基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"}
|
2832
|
+
df = ak.stock_report_fund_hold(symbol=holder_type, date=recent_quarter_date)
|
2833
|
+
|
2834
|
+
sortby_list=['持有基金家数','持股总数','持股市值','持股变化','持股变动数值','持股变动比例']
|
2835
|
+
if sortby not in sortby_list:
|
2836
|
+
print(" #Warning: sortby option only supports the following:")
|
2837
|
+
print(f" {sortby_list}")
|
2838
|
+
sortby=sortby_list[0]
|
2839
|
+
|
2840
|
+
if sortby != '持有基金家数':
|
2841
|
+
df.sort_values(sortby,ascending=False,inplace=True)
|
2842
|
+
else:
|
2843
|
+
df = df.sort_values(by=[sortby, '持股总数'], ascending=[False, False])
|
2844
|
+
|
2845
|
+
df.reset_index(drop=True,inplace=True)
|
2846
|
+
df['序号']=df.index+1
|
2847
|
+
|
2848
|
+
# 挪动排名项目
|
2849
|
+
df=shift_column_position(df,sortby,position=3)
|
2850
|
+
|
2851
|
+
df2=df.copy()
|
2852
|
+
|
2853
|
+
wan=10000; yiyuan=100000000
|
2854
|
+
df2['持股总数'] =df2['持股总数']/wan
|
2855
|
+
df2['持股总数'] =df2['持股总数'].apply(lambda x: round(x,2))
|
2856
|
+
|
2857
|
+
df2['持股变动数值'] =df2['持股变动数值']/wan
|
2858
|
+
df2['持股变动数值'] =df2['持股变动数值'].apply(lambda x: round(x,2))
|
2859
|
+
|
2860
|
+
df2['持股市值'] =df2['持股市值']/yiyuan
|
2861
|
+
df2['持股市值'] =df2['持股市值'].apply(lambda x: round(x,2))
|
2862
|
+
|
2863
|
+
if top > 0:
|
2864
|
+
df3=df2.head(top)
|
2865
|
+
elif top < 0:
|
2866
|
+
df3=df2.tail(-top)
|
2867
|
+
else:
|
2868
|
+
df3=df2.head(5)
|
2869
|
+
|
2870
|
+
#强制显示所选股票
|
2871
|
+
#if force_show_stock and rank != 10:
|
2872
|
+
if ticker != '':
|
2873
|
+
#所选股票是否在其中?
|
2874
|
+
if not ticker[:6] in list(df3["股票代码"]):
|
2875
|
+
try:
|
2876
|
+
ticker_seq=df2[df2["股票代码"]==ticker[:6]]["序号"].values[0]
|
2877
|
+
except:
|
2878
|
+
print(f" #Error(fund_holding_stock_rank): {ticker} not found in {holder_type}")
|
2879
|
+
return None
|
2880
|
+
|
2881
|
+
num_before=int(top/2)
|
2882
|
+
if num_before * 2 == top: num_before=num_before-1
|
2883
|
+
num_after=top-num_before-1
|
2884
|
+
|
2885
|
+
#seq1=ticker_seq-4; seq2=ticker_seq+5
|
2886
|
+
seq1=ticker_seq-num_before; seq2=ticker_seq+num_after
|
2887
|
+
#如果超出开头
|
2888
|
+
if seq1 <=0:
|
2889
|
+
seq1=1; seq2=top
|
2890
|
+
#如果超出结尾
|
2891
|
+
if seq2 > len(df2):
|
2892
|
+
seq2=len(df2); seq1=len(df2)-(top-1)
|
2893
|
+
|
2894
|
+
#注意:此处的&不能换为and
|
2895
|
+
df3=df2[(df2["序号"]>=seq1) & (df2["序号"]<=seq2)]
|
2896
|
+
|
2897
|
+
titletxt=holder_type+'排名:基于'+sortby
|
2898
|
+
import datetime
|
2899
|
+
todaydt = datetime.date.today()
|
2900
|
+
#footnote0="【注释】排名方法:"+sortby
|
2901
|
+
footnote0="【注释】数据截至"+recent_quarter_date2
|
2902
|
+
footnote1=';持股总数/持股变动数值:万股,持股市值:亿元'
|
2903
|
+
footnote2='。数据来源:东方财富/天天基金,'+str(todaydt)
|
2904
|
+
footnote=footnote0+footnote1+footnote2
|
2905
|
+
|
2906
|
+
df_display_CSS(df3,titletxt=titletxt,footnote=footnote, \
|
2907
|
+
facecolor='papayawhip',decimals=2, \
|
2908
|
+
first_col_align='left',second_col_align='left', \
|
2909
|
+
last_col_align='right',other_col_align='right', \
|
2910
|
+
titile_font_size='16px',heading_font_size='15px', \
|
2911
|
+
data_font_size='14px',footnote_font_size='13px')
|
2912
|
+
|
2913
|
+
return df
|
2914
|
+
|
2915
|
+
#==============================================================================
|
2916
|
+
if __name__=='__main__':
|
2917
|
+
ticker='689009.SS'
|
2918
|
+
num_quarters=8
|
2919
|
+
|
2920
|
+
|
2921
|
+
def fund_holding_stock_trend_china(ticker,num_quarters=8,holder_type="基金持仓", \
|
2922
|
+
close_price=False):
|
2923
|
+
"""
|
2924
|
+
===========================================================================
|
2925
|
+
功能:列出一只股票被基金持股的变动趋势
|
2926
|
+
参数:
|
2927
|
+
ticker:股票代码
|
2928
|
+
num_quarters:最近基金持股的季度个数,默认8。
|
2929
|
+
holder_type:持仓基金类别,默认"基金持仓";若为'ALL'则扫描所有机构持股信息,时间较长。
|
2930
|
+
|
2931
|
+
返回值:df
|
2932
|
+
"""
|
2933
|
+
holder_type_list=["基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"]
|
2934
|
+
if not (holder_type in holder_type_list):
|
2935
|
+
print(f" #Warning(fund_holding_stock_trend): {holder_type} not supported")
|
2936
|
+
print(f" Supported types: {holder_type_list}")
|
2937
|
+
holder_type="基金持仓"
|
2938
|
+
|
2939
|
+
import akshare as ak
|
2940
|
+
import pandas as pd
|
2941
|
+
|
2942
|
+
quarter_dates=get_past_quarters(num_quarters=num_quarters,date_format="%Y%m%d",date_reverse=False)
|
2943
|
+
|
2944
|
+
|
2945
|
+
df=pd.DataFrame()
|
2946
|
+
for d in quarter_dates:
|
2947
|
+
print(f" Searching {holder_type} info on {ticker} in {d} ...")
|
2948
|
+
|
2949
|
+
# symbol="基金持仓"; choice of {"基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"}
|
2950
|
+
try:
|
2951
|
+
dftmp = ak.stock_report_fund_hold(symbol=holder_type, date=d)
|
2952
|
+
except:
|
2953
|
+
continue
|
2954
|
+
|
2955
|
+
try:
|
2956
|
+
dftmp2=dftmp[dftmp['股票代码']==ticker[:6]]
|
2957
|
+
except:
|
2958
|
+
break
|
2959
|
+
|
2960
|
+
d2=format_date(d,from_format="%Y%m%d",to_format="%Y-%m-%d")
|
2961
|
+
dftmp2['季度']=d2
|
2962
|
+
#dftmp2['机构类别']=holder_type
|
2963
|
+
|
2964
|
+
|
2965
|
+
if len(df)==0:
|
2966
|
+
df=dftmp2
|
2967
|
+
else:
|
2968
|
+
df=pd.concat([df, dftmp2], axis=0, ignore_index=True)
|
2969
|
+
|
2970
|
+
# 未找到股票
|
2971
|
+
if len(df)==0:
|
2972
|
+
print(f" #Error(fund_holding_stock_trend): stock {ticker} not found or not holded by fund")
|
2973
|
+
return None
|
2974
|
+
|
2975
|
+
# 重排字段
|
2976
|
+
stock_name=df['股票简称'].values[0]
|
2977
|
+
col_list=['季度','持股变化','持股变动数值','持股变动比例','持有基金家数','持股总数','持股市值']
|
2978
|
+
df2=df[col_list]
|
2979
|
+
|
2980
|
+
|
2981
|
+
wan=10000; yiyuan=100000000
|
2982
|
+
df2['持股总数'] =df2['持股总数']/wan
|
2983
|
+
df2['持股总数'] =df2['持股总数'].apply(lambda x: round(x,2))
|
2984
|
+
|
2985
|
+
df2['持股变动数值'] =df2['持股变动数值']/wan
|
2986
|
+
df2['持股变动数值'] =df2['持股变动数值'].apply(lambda x: round(x,2))
|
2987
|
+
|
2988
|
+
df2['持股市值'] =df2['持股市值']/yiyuan
|
2989
|
+
df2['持股市值'] =df2['持股市值'].apply(lambda x: round(x,2))
|
2990
|
+
|
2991
|
+
if not close_price:
|
2992
|
+
df4=df2
|
2993
|
+
else:
|
2994
|
+
ticker2=tickers_cvt2ak(ticker)
|
2995
|
+
fromdate=df2['季度'].values[0]; fromdate=date_adjust(fromdate, adjust=-30)
|
2996
|
+
todate=df2['季度'].values[-1]; todate=date_adjust(todate, adjust=30)
|
2997
|
+
result,start,end=check_period(fromdate,todate)
|
2998
|
+
start1=start.strftime('%Y%m%d'); end1=end.strftime('%Y%m%d')
|
2999
|
+
prices=security_trend(ticker,start=fromdate,end=todate,graph=False)
|
3000
|
+
prices.index = pd.to_datetime(prices.index, format='%Y-%m-%d')
|
3001
|
+
prices['收盘价']=prices['Close']
|
3002
|
+
prices['季度']=prices.index.strftime('%Y-%m-%d')
|
3003
|
+
prices2=prices[['季度','收盘价']]
|
3004
|
+
|
3005
|
+
|
3006
|
+
df3=pd.merge(df2,prices2,on='季度',how='outer')
|
3007
|
+
# 使用前一个非空值填充某一列的空缺值
|
3008
|
+
df3['收盘价'] = df3['收盘价'].fillna(method='ffill')
|
3009
|
+
# 使用后一个非空值填充某一列的空缺值
|
3010
|
+
df3['收盘价'] = df3['收盘价'].fillna(method='bfill')
|
3011
|
+
# 删除列 'A' 中包含空缺值的所有行
|
3012
|
+
df4 = df3.dropna(subset=['持有基金家数'])
|
3013
|
+
|
3014
|
+
titletxt=holder_type+'变动趋势:'+stock_name
|
3015
|
+
import datetime
|
3016
|
+
todaydt = datetime.date.today()
|
3017
|
+
#footnote0="【注释】排名方法:"+sortby
|
3018
|
+
footnote0="【注释】"
|
3019
|
+
footnote1='持股总数/持股变动数值:万股,持股市值:亿元'
|
3020
|
+
footnote2='。数据来源:东方财富/天天基金,'+str(todaydt)
|
3021
|
+
footnote=footnote0+footnote1+footnote2
|
3022
|
+
|
3023
|
+
df_display_CSS(df4,titletxt=titletxt,footnote=footnote, \
|
3024
|
+
facecolor='papayawhip',decimals=2, \
|
3025
|
+
first_col_align='left',second_col_align='left', \
|
3026
|
+
last_col_align='right',other_col_align='right', \
|
3027
|
+
titile_font_size='16px',heading_font_size='15px', \
|
3028
|
+
data_font_size='14px',footnote_font_size='13px')
|
3029
|
+
|
3030
|
+
return df
|
3031
|
+
|
3032
|
+
#==============================================================================
|
3033
|
+
if __name__=='__main__':
|
3034
|
+
ticker='689009.SS'
|
3035
|
+
ticker='600519.SS'
|
3036
|
+
num_quarters=8
|
3037
|
+
|
3038
|
+
|
3039
|
+
def fund_holding_stock_trend_all_china(ticker,num_quarters=4):
|
3040
|
+
"""
|
3041
|
+
===========================================================================
|
3042
|
+
功能:列出一只股票被所有机构类别持股的变动趋势
|
3043
|
+
参数:
|
3044
|
+
ticker:股票代码
|
3045
|
+
num_quarters:最近基金持股的季度个数,默认8。
|
3046
|
+
|
3047
|
+
返回值:df
|
3048
|
+
"""
|
3049
|
+
holder_type_list=["基金持仓", "QFII持仓", "社保持仓", "券商持仓", "保险持仓", "信托持仓"]
|
3050
|
+
|
3051
|
+
import akshare as ak
|
3052
|
+
import pandas as pd
|
3053
|
+
|
3054
|
+
quarter_dates=get_past_quarters(num_quarters=num_quarters,date_format="%Y%m%d",date_reverse=False)
|
3055
|
+
|
3056
|
+
|
3057
|
+
df=pd.DataFrame()
|
3058
|
+
for ht in holder_type_list:
|
3059
|
+
print(f" Searching {ht} info on {ticker} ...")
|
3060
|
+
|
3061
|
+
for d in quarter_dates:
|
3062
|
+
|
3063
|
+
try:
|
3064
|
+
dftmp = ak.stock_report_fund_hold(symbol=ht, date=d)
|
3065
|
+
except:
|
3066
|
+
continue
|
3067
|
+
|
3068
|
+
try:
|
3069
|
+
dftmp2=dftmp[dftmp['股票代码']==ticker[:6]]
|
3070
|
+
except:
|
3071
|
+
break
|
3072
|
+
|
3073
|
+
d2=format_date(d,from_format="%Y%m%d",to_format="%Y-%m-%d")
|
3074
|
+
dftmp2['季度']=d2
|
3075
|
+
dftmp2['机构类别']=ht
|
3076
|
+
|
3077
|
+
|
3078
|
+
if len(df)==0:
|
3079
|
+
df=dftmp2
|
3080
|
+
else:
|
3081
|
+
df=pd.concat([df, dftmp2], axis=0, ignore_index=True)
|
3082
|
+
|
3083
|
+
# 未找到股票
|
3084
|
+
if len(df)==0:
|
3085
|
+
print(f" #Error(fund_holding_stock_trend): stock {ticker} not found or not holded by fund")
|
3086
|
+
return None
|
3087
|
+
|
3088
|
+
# 重排字段
|
3089
|
+
stock_name=df['股票简称'].values[0]
|
3090
|
+
col_list=['季度','机构类别','持股变化','持股变动数值','持股变动比例','持有基金家数','持股总数','持股市值']
|
3091
|
+
df2=df[col_list]
|
3092
|
+
df2= df2.sort_values(['季度'],ascending=[True])
|
3093
|
+
|
3094
|
+
|
3095
|
+
wan=10000; yiyuan=100000000
|
3096
|
+
df2['持股总数'] =df2['持股总数']/wan
|
3097
|
+
df2['持股总数'] =df2['持股总数'].apply(lambda x: round(x,2))
|
3098
|
+
|
3099
|
+
df2['持股变动数值'] =df2['持股变动数值']/wan
|
3100
|
+
df2['持股变动数值'] =df2['持股变动数值'].apply(lambda x: round(x,2))
|
3101
|
+
|
3102
|
+
df2['持股市值'] =df2['持股市值']/yiyuan
|
3103
|
+
df2['持股市值'] =df2['持股市值'].apply(lambda x: round(x,2))
|
3104
|
+
|
3105
|
+
titletxt='机构持仓变动趋势:'+stock_name
|
3106
|
+
import datetime
|
3107
|
+
todaydt = datetime.date.today()
|
3108
|
+
#footnote0="【注释】排名方法:"+sortby
|
3109
|
+
footnote0="【注释】"
|
3110
|
+
footnote1='持股总数/持股变动数值:万股,持股市值:亿元'
|
3111
|
+
footnote2='。数据来源:东方财富/天天基金,'+str(todaydt)
|
3112
|
+
footnote=footnote0+footnote1+footnote2
|
3113
|
+
|
3114
|
+
df_display_CSS(df2,titletxt=titletxt,footnote=footnote, \
|
3115
|
+
facecolor='papayawhip',decimals=2, \
|
3116
|
+
first_col_align='left',second_col_align='left', \
|
3117
|
+
last_col_align='right',other_col_align='right', \
|
3118
|
+
titile_font_size='16px',heading_font_size='15px', \
|
3119
|
+
data_font_size='14px',footnote_font_size='13px')
|
3120
|
+
|
3121
|
+
return df
|
3122
|
+
|
3123
|
+
|
3124
|
+
#==============================================================================
|
3125
|
+
if __name__=='__main__':
|
3126
|
+
ticker='600519.SS'
|
3127
|
+
ticker='600305.SS'
|
3128
|
+
top=3
|
3129
|
+
|
3130
|
+
def stock_heldby_fund_detail_china(ticker,top=5):
|
3131
|
+
"""
|
3132
|
+
===========================================================================
|
3133
|
+
功能:列示持有一只股票最多的前几名基金列表。
|
3134
|
+
参数:
|
3135
|
+
ticker:股票代码
|
3136
|
+
top:列示前几名,默认5
|
3137
|
+
|
3138
|
+
返回值:数据表
|
3139
|
+
"""
|
3140
|
+
|
3141
|
+
import akshare as ak
|
3142
|
+
|
3143
|
+
# 获取某只股票被基金持股的数据
|
3144
|
+
try:
|
3145
|
+
df = ak.stock_fund_stock_holder(symbol=ticker[:6])
|
3146
|
+
except:
|
3147
|
+
print(f"Sorry, no fund holding details found for {ticker} in data source")
|
3148
|
+
return None
|
3149
|
+
|
3150
|
+
df2=df.copy()
|
3151
|
+
|
3152
|
+
wan=10000; yiyuan=100000000
|
3153
|
+
df2['持仓数量'] =df2['持仓数量']/wan
|
3154
|
+
df2['持仓数量'] =df2['持仓数量'].apply(lambda x: round(x,2))
|
3155
|
+
|
3156
|
+
df2['持股市值'] =df2['持股市值']/yiyuan
|
3157
|
+
df2['持股市值'] =df2['持股市值'].apply(lambda x: round(x,2))
|
3158
|
+
|
3159
|
+
# 按持股比例降序排列
|
3160
|
+
df3 = df2.sort_values(by='占流通股比例', ascending=False)
|
3161
|
+
|
3162
|
+
# 取前五名基金
|
3163
|
+
df4 = df3.head(top)
|
3164
|
+
df4['序号']=df4.index+1
|
3165
|
+
df4=shift_column_position(df4,col_name='序号',position=0)
|
3166
|
+
|
3167
|
+
ddl_date=df4['截止日期'].values[0]
|
3168
|
+
del df4['截止日期']
|
3169
|
+
|
3170
|
+
quarter_dates=get_past_quarters(num_quarters=8,date_format="%Y%m%d",date_reverse=False)
|
3171
|
+
recent_quarter_date=quarter_dates[-1]
|
3172
|
+
recent_quarter_date2=format_date(recent_quarter_date,from_format="%Y%m%d",to_format="%Y-%m-%d")
|
3173
|
+
if str(ddl_date) < str(recent_quarter_date2):
|
3174
|
+
print("Pity, fund holding stock info may be far out of date:-(")
|
3175
|
+
|
3176
|
+
titletxt=ticker_name(ticker)+':机构持仓情况,截至'+str(ddl_date)
|
3177
|
+
import datetime
|
3178
|
+
todaydt = datetime.date.today()
|
3179
|
+
#footnote0="【注释】排名方法:"+sortby
|
3180
|
+
footnote0="【注释】"
|
3181
|
+
footnote1='持仓数量:万股,持股市值:亿元'
|
3182
|
+
footnote2='。数据来源:新浪财经,'+str(todaydt)
|
3183
|
+
footnote=footnote0+footnote1+footnote2
|
3184
|
+
|
3185
|
+
df_display_CSS(df4,titletxt=titletxt,footnote=footnote, \
|
3186
|
+
facecolor='papayawhip',decimals=2, \
|
3187
|
+
first_col_align='center',second_col_align='left', \
|
3188
|
+
last_col_align='right',other_col_align='right', \
|
3189
|
+
titile_font_size='16px',heading_font_size='15px', \
|
3190
|
+
data_font_size='14px',footnote_font_size='13px')
|
3191
|
+
|
3192
|
+
return df
|
3193
|
+
#==============================================================================
|
3194
|
+
|
3195
|
+
|
3196
|
+
|
3197
|
+
def fund_holding_stock_china(ticker='',top=5,sortby='持有基金家数', \
|
3198
|
+
holder_type="基金持仓",quarter='recent', \
|
3199
|
+
detail=False, \
|
3200
|
+
close_price=False):
|
3201
|
+
"""
|
3202
|
+
===========================================================================
|
3203
|
+
功能:列示中国内地机构持股情况。
|
3204
|
+
参数:
|
3205
|
+
ticker:股票代码,默认'',列示最受机构追捧的股票排行及其被机构持仓情况。
|
3206
|
+
若为一个股票代码,则列示该股票的排行情况及其被机构持仓情况。
|
3207
|
+
top:列示排行时的个数,默认5。
|
3208
|
+
sortby:当列示排行时标示排行的指标,默认'持有基金家数'。
|
3209
|
+
holder_type:机构持仓的类别,默认"基金持仓"。
|
3210
|
+
当为ALL时列示所有机构类别的持仓情况。
|
3211
|
+
仅有少数热门股票在除“基金持仓”以外的类别有数据,数据亦可能较久远。
|
3212
|
+
quarter:指示列示数据的季度,默认'recent'仅列示最近一个季度末的披露数据。
|
3213
|
+
若为数字则列示近若干个季度的机构持仓变动趋势。
|
3214
|
+
与holder_type='ALL'配合时列示近若干个季度的所有机构类别的持仓变动趋势。
|
3215
|
+
detail:是否列示持有一只股票的机构持仓情况,仅当ticker不为空时有效,默认False。
|
3216
|
+
close_price:当列示持有一只股票的机构持仓情况是否同时列示股价,默认False。
|
3217
|
+
|
3218
|
+
返回值:数据表,无数据时返回空。
|
3219
|
+
"""
|
3220
|
+
|
3221
|
+
if quarter=='recent' and holder_type.upper() != 'ALL' and not detail:
|
3222
|
+
df=fund_holding_stock_rank_china(ticker=ticker,top=top, \
|
3223
|
+
sortby=sortby,holder_type=holder_type)
|
3224
|
+
|
3225
|
+
elif ticker != '' and isinstance(quarter,int) and holder_type.upper() != 'ALL' and not detail:
|
3226
|
+
df=fund_holding_stock_trend_china(ticker=ticker,num_quarters=quarter, \
|
3227
|
+
holder_type=holder_type, \
|
3228
|
+
close_price=close_price)
|
3229
|
+
|
3230
|
+
elif ticker != '' and isinstance(quarter,int) and holder_type.upper() == 'ALL' and not detail:
|
3231
|
+
df=fund_holding_stock_trend_all_china(ticker=ticker,num_quarters=quarter)
|
3232
|
+
|
3233
|
+
elif ticker != '' and detail:
|
3234
|
+
df=stock_heldby_fund_detail_china(ticker=ticker,top=top)
|
3235
|
+
|
3236
|
+
else:
|
3237
|
+
print("Sorry, no idea on what you expect to do:-(")
|
3238
|
+
|
3239
|
+
return df
|
3240
|
+
|
3241
|
+
|
3242
|
+
#==============================================================================
|
3243
|
+
#==============================================================================
|
3244
|
+
#==============================================================================
|
3245
|
+
#==============================================================================
|
3246
|
+
#==============================================================================
|
3247
|
+
#==============================================================================
|
3248
|
+
#==============================================================================
|
3249
|
+
#==============================================================================
|
3250
|
+
|
2692
3251
|
|
2693
3252
|
|
2694
3253
|
|