siat 2.11.13__py3-none-any.whl → 2.11.19__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/market_china.py +19 -18
- siat/translate.py +4 -2
- siat/valuation.py +19 -2
- siat/valuation_china.py +437 -14
- {siat-2.11.13.dist-info → siat-2.11.19.dist-info}/METADATA +2 -1
- {siat-2.11.13.dist-info → siat-2.11.19.dist-info}/RECORD +8 -8
- {siat-2.11.13.dist-info → siat-2.11.19.dist-info}/WHEEL +0 -0
- {siat-2.11.13.dist-info → siat-2.11.19.dist-info}/top_level.txt +0 -0
siat/market_china.py
CHANGED
@@ -773,15 +773,16 @@ def market_detail_china(category='price',prettytab=True,plttab=False, \
|
|
773
773
|
|
774
774
|
print(heading,"信息来源:东方财富,","统计时间:",nowstr)
|
775
775
|
print(heading,"注释:")
|
776
|
+
print(heading,"☆可交易股票数量:将随着股票停复牌情况变化")
|
776
777
|
print(heading,"☆昨日指的是上一个交易日")
|
777
|
-
print(heading,"☆使用实时数据,不同日期/每天不同时刻统计的结果可能不同")
|
778
|
-
print(heading,"☆若在非开市时间或开市前后短期内统计,部分结果数据可能出现空缺")
|
779
778
|
print(heading,"☆涨速:平均每分钟股价变化率,表示股价变化速度")
|
779
|
+
print(heading,"☆5分钟涨跌:最新5分钟内股价的涨跌幅度")
|
780
780
|
print(heading,"☆振幅:最高最低价差绝对值/昨收,表示股价变化活跃程度")
|
781
781
|
print(heading,"☆涨跌幅:(最新价-昨收)/昨收,表示相对昨日的变化程度")
|
782
782
|
print(heading,"☆涨跌额:最新价-昨收,表示相对昨日的变化金额")
|
783
|
-
|
784
|
-
print(heading,"
|
783
|
+
|
784
|
+
print(heading,"☆使用实时数据,不同日期/每天不同时刻统计的结果可能不同")
|
785
|
+
print(heading,"☆若在非开市时间或开市前后短期内统计,部分结果数据可能出现空缺")
|
785
786
|
|
786
787
|
if category1=='VOLUME':
|
787
788
|
titletxt="中国三大股票交易所横向对比:成交状况"
|
@@ -793,14 +794,14 @@ def market_detail_china(category='price',prettytab=True,plttab=False, \
|
|
793
794
|
|
794
795
|
print(heading,"信息来源:东方财富,","统计时间:",nowstr)
|
795
796
|
print(heading,"注:")
|
796
|
-
print(heading,"
|
797
|
-
print(heading,"☆使用实时数据,不同日期/每天不同时刻统计的结果可能不同")
|
798
|
-
print(heading,"☆若在非开市时间或开市前后短期内统计,部分结果数据可能出现空缺")
|
799
|
-
print(heading,"☆量比:当前平均每分钟成交量与过去5个交易日均值之比,表示当前成交量的变化")
|
797
|
+
print(heading,"☆可交易股票数量:将随着股票停复牌情况变化")
|
800
798
|
print(heading,"☆成交量:当前成交股数,表示交易活跃度")
|
801
|
-
print(heading,"☆换手率:成交量/流通股数,表示成交量占比")
|
802
799
|
print(heading,"☆成交额:当前开市后的累计成交金额")
|
803
|
-
print(heading,"
|
800
|
+
print(heading,"☆换手率:成交量/流通股数,表示成交量占比")
|
801
|
+
print(heading,"☆量比:当前平均每分钟成交量与过去5个交易日均值之比,表示当前成交量的变化")
|
802
|
+
|
803
|
+
print(heading,"☆使用实时数据,不同日期/每天不同时刻统计的结果可能不同")
|
804
|
+
print(heading,"☆若在非开市时间或开市前后短期内统计,部分结果数据可能出现空缺")
|
804
805
|
|
805
806
|
if category1=='RETURN':
|
806
807
|
titletxt="中国三大股票交易所横向对比:投资回报"
|
@@ -812,12 +813,12 @@ def market_detail_china(category='price',prettytab=True,plttab=False, \
|
|
812
813
|
|
813
814
|
print(heading,"信息来源:东方财富,","统计时间:",nowstr)
|
814
815
|
print(heading,"注:")
|
815
|
-
print(heading,"
|
816
|
+
print(heading,"☆可交易股票数量:将随着股票停复牌情况变化")
|
817
|
+
print(heading,"☆MRQ:最近一个季度的滚动数据")
|
818
|
+
print(heading,"☆YTD:今年以来的累计情况")
|
819
|
+
|
816
820
|
print(heading,"☆使用实时数据,不同日期/每天不同时刻统计的结果可能不同")
|
817
821
|
print(heading,"☆若在非开市时间或开市前后短期内统计,部分结果数据可能出现空缺")
|
818
|
-
print(heading,"☆MRQ:最近一个季度,即最近60个交易日")
|
819
|
-
print(heading,"☆YTD:今年以来的累计情况")
|
820
|
-
print(heading,"☆可交易股票数量:将随着股票停复牌情况变化")
|
821
822
|
|
822
823
|
if category1=='VALUATION':
|
823
824
|
titletxt="中国三大股票交易所横向对比:市值与估值"
|
@@ -829,13 +830,13 @@ def market_detail_china(category='price',prettytab=True,plttab=False, \
|
|
829
830
|
|
830
831
|
print(heading,"信息来源:东方财富,","统计时间:",nowstr)
|
831
832
|
print(heading,"注:")
|
832
|
-
print(heading,"
|
833
|
+
print(heading,"☆可交易股票数量:将随着股票停复牌情况变化")
|
834
|
+
print(heading,"☆市盈率:这里为动态市盈率,即市盈率TTM,过去12个月的连续变化")
|
835
|
+
print(heading,"☆市净率:这里为静态市净率")
|
836
|
+
|
833
837
|
print(heading,"☆使用实时数据,不同日期/每天不同时刻统计的结果可能不同")
|
834
838
|
print(heading,"☆若在非开市时间或开市前后短期内统计,部分结果数据可能出现空缺")
|
835
839
|
#print(heading,"☆标准差/均值=标准差(数值)/均值,提升可比性")
|
836
|
-
print(heading,"☆市净率:这里为静态市盈率,按季/中/年报计算")
|
837
|
-
print(heading,"☆市盈率:这里为动态市盈率,即市盈率TTM,过去12个月的连续变化")
|
838
|
-
print(heading,"☆可交易股票数量:将随着股票停复牌情况变化")
|
839
840
|
|
840
841
|
return df
|
841
842
|
|
siat/translate.py
CHANGED
@@ -1023,10 +1023,12 @@ def codetranslate0(code):
|
|
1023
1023
|
['000832.SS','中证转债指数'],['399307.SZ','深证转债指数'],
|
1024
1024
|
['000116.SS','上证信用债指数'],['399413.SZ','国证转债综合指数'],
|
1025
1025
|
|
1026
|
-
['^GSPC','标普500指数'],['^
|
1026
|
+
['^GSPC','标普500指数'],['^SPX','标普500指数'],
|
1027
|
+
['^DJI','道琼斯工业指数'],
|
1027
1028
|
['WISGP.SI','富时新加坡指数'], ['^STI','新加坡海峡时报指数'],
|
1028
1029
|
['^IXIC','纳斯达克综合指数'],['^FTSE','英国富时100指数'],
|
1029
|
-
['^
|
1030
|
+
['^NKX','日经225指数'],['^N100','泛欧100指数'],
|
1031
|
+
['^FMIB','富时意大利指数'],
|
1030
1032
|
['^TSX','多伦多综合指数'],['^MXX','墨西哥IPC指数'],
|
1031
1033
|
['^NDX','纳斯达克100指数'],['^BET','罗马尼亚布加勒斯特指数'],
|
1032
1034
|
['^BUX','匈牙利布达佩斯指数'],['^PX','捷克布拉格PX指数'],
|
siat/valuation.py
CHANGED
@@ -22,6 +22,7 @@ from siat.translate import *
|
|
22
22
|
from siat.stock import *
|
23
23
|
from siat.security_prices import *
|
24
24
|
from siat.sector_china import *
|
25
|
+
from siat.valuation_china import *
|
25
26
|
from siat.grafix import *
|
26
27
|
|
27
28
|
import pandas as pd
|
@@ -673,7 +674,7 @@ def funddb_name(code):
|
|
673
674
|
['HSCEI.HK','ESG120策略'],#中证ESG120策略指数从沪深300指数样本股中选取ESG得分较高的120只股票
|
674
675
|
['HSCEI.HK','恒生中国企业指数'],#中国企业以H股形式在香港联合交易所(「联交所」)上市
|
675
676
|
['930931.ZZ','港股通50(HKD)'],#港股通范围内的最大50家公司
|
676
|
-
['HSIII.
|
677
|
+
['HSIII.ZZ','沪港深500'],#中证沪港深500指数, 沪港深交易所上市的互联互通范围内股票
|
677
678
|
['HSIII.HK','恒生互联网科技业'],
|
678
679
|
['HSTECH.HK','恒生科技指数'],
|
679
680
|
['931637.ZZ','HKC互联网'],#中证港股通互联网指数, 港股通内互联网主题上市公司
|
@@ -691,6 +692,9 @@ def funddb_name(code):
|
|
691
692
|
['931468.ZZ','红利质量'],#中证红利质量指数,连续现金分红、股利支付率较高且具备较高盈利能力特征的上市公司股
|
692
693
|
['000922.ZZ','中证红利'],#中证红利指数以沪深A股中现金股息率高、分红比较稳定、具有一定规模及流动性的100只股票
|
693
694
|
['000825.ZZ','中证央企红利'],#中证中央企业红利指数,中央企业中现金股息率高、分红比较稳定、且有一定规模及流动性的30只股票
|
695
|
+
['000969.ZZ','沪深300非周期'],
|
696
|
+
['000821.ZZ','沪深300红利'],
|
697
|
+
['000968.ZZ','沪深300周期'],
|
694
698
|
|
695
699
|
], columns=['eword','cword'])
|
696
700
|
|
@@ -775,7 +779,17 @@ def get_valuation(tickers,indicators,start,end):
|
|
775
779
|
|
776
780
|
# 申万指数代码?
|
777
781
|
if not gotit and (result and suffix in ['SW']):
|
778
|
-
dft=get_index_valuation_funddb(t1,indicators1,start,end)
|
782
|
+
#dft=get_index_valuation_funddb(t1,indicators1,start,end)
|
783
|
+
indicator1=indicators1[0]
|
784
|
+
dft0=industry_valuation_history_sw(industry=t1,
|
785
|
+
start=start,end=end,
|
786
|
+
vtype=indicator1,
|
787
|
+
graph=False)
|
788
|
+
dft0[indicator1]=dft0[list(dft0)[0]]
|
789
|
+
dft0['name']=industry_sw_name(t1)
|
790
|
+
dft0['currency']=''
|
791
|
+
dft=dft0[[indicator1,'name','currency']]
|
792
|
+
|
779
793
|
if dft is not None:
|
780
794
|
gotit=True
|
781
795
|
iname=industry_sw_name(t1)
|
@@ -809,6 +823,8 @@ def get_valuation(tickers,indicators,start,end):
|
|
809
823
|
if not (df is None):
|
810
824
|
#df.fillna(method='backfill',inplace=True)
|
811
825
|
df.fillna(method='ffill',inplace=True)
|
826
|
+
else:
|
827
|
+
return None
|
812
828
|
|
813
829
|
# 处理字段名称后面的_x/_y/_z
|
814
830
|
df_collist=list(df)
|
@@ -824,6 +840,7 @@ def get_valuation(tickers,indicators,start,end):
|
|
824
840
|
df1_collist=df1_collist+[cx] #列表中必须为元组
|
825
841
|
|
826
842
|
df1.columns=pd.MultiIndex.from_tuples(df1_collist) #统一修改元组型列名
|
843
|
+
df1.dropna(inplace=True)
|
827
844
|
|
828
845
|
return df1
|
829
846
|
|
siat/valuation_china.py
CHANGED
@@ -442,24 +442,24 @@ if __name__=='__main__':
|
|
442
442
|
graph=True
|
443
443
|
loc='best'
|
444
444
|
|
445
|
-
def
|
445
|
+
def industry_valuation_history_sw_daily(industry,start,end,vtype='PE', \
|
446
446
|
graph=True,loc='best'):
|
447
447
|
"""
|
448
|
-
|
448
|
+
功能:绘制一个申万行业的日历史估值趋势,不支持二级三级行业分类
|
449
449
|
vtype: PE, PB, dividend
|
450
450
|
|
451
451
|
"""
|
452
452
|
#检查日期期间
|
453
453
|
result,start1,end1=check_period(start,end)
|
454
454
|
if not result:
|
455
|
-
print(" #Warning(
|
455
|
+
print(" #Warning(industry_valuation_history_sw_daily): invalid date period",start,end)
|
456
456
|
return None
|
457
457
|
|
458
458
|
#检查估值类型
|
459
459
|
typelist=['pe','pb','dividend']
|
460
460
|
vtypeu=vtype.lower()
|
461
461
|
if not (vtypeu in typelist):
|
462
|
-
print(" #Warning(
|
462
|
+
print(" #Warning(industry_valuation_history_sw_daily): unsupported valuation type",vtype)
|
463
463
|
print(" Supported types:",typelist)
|
464
464
|
return None
|
465
465
|
|
@@ -475,7 +475,7 @@ def industry_valuation_history_sw(industry,start,end,vtype='PE', \
|
|
475
475
|
# 不支持申万三级行业
|
476
476
|
df = ak.index_value_hist_funddb(symbol=sindustry, indicator=vtypes)
|
477
477
|
except:
|
478
|
-
print(" #Warning(
|
478
|
+
print(" #Warning(industry_valuation_history_sw_daily): failed to fetch industry info for",industry)
|
479
479
|
return None
|
480
480
|
|
481
481
|
import pandas as pd
|
@@ -491,7 +491,7 @@ def industry_valuation_history_sw(industry,start,end,vtype='PE', \
|
|
491
491
|
df2['平均值']=df2[vtypes].mean()
|
492
492
|
df2['中位数']=df2[vtypes].median()
|
493
493
|
|
494
|
-
titletxt="行业估值趋势:"+industry+','+vtypes
|
494
|
+
titletxt="行业估值趋势:"+industry_sw_name(industry)+','+vtypes
|
495
495
|
|
496
496
|
footnote0="注:申万宏源行业指数,"
|
497
497
|
footnote1=''
|
@@ -511,19 +511,372 @@ def industry_valuation_history_sw(industry,start,end,vtype='PE', \
|
|
511
511
|
return df2
|
512
512
|
|
513
513
|
if __name__=='__main__':
|
514
|
-
df=
|
515
|
-
df=
|
516
|
-
df=
|
514
|
+
df=industry_valuation_history_sw_daily(industry,start,end,vtype='PE')
|
515
|
+
df=industry_valuation_history_sw_daily(industry,start,end,vtype='PB')
|
516
|
+
df=industry_valuation_history_sw_daily(industry,start,end,vtype='dividend')
|
517
|
+
|
518
|
+
df=industry_valuation_history_sw_daily(industry='纺织服饰',start=start,end=end,vtype='PE')
|
519
|
+
df=industry_valuation_history_sw_daily(industry='纺织服饰',start=start,end=end,vtype='PB')
|
520
|
+
df=industry_valuation_history_sw_daily(industry='纺织服饰',start=start,end=end,vtype='dividend')
|
521
|
+
|
522
|
+
#==============================================================================
|
523
|
+
#==============================================================================
|
524
|
+
if __name__=='__main__':
|
525
|
+
adate='2023-12-14'
|
526
|
+
|
527
|
+
def get_last_friday(adate):
|
528
|
+
"""
|
529
|
+
功能:给定日期,找出上一个周五的日期,配合申万指数估值函数使用
|
530
|
+
"""
|
531
|
+
|
532
|
+
result,fdate=check_date2(adate)
|
533
|
+
if not result:
|
534
|
+
return None
|
535
|
+
|
536
|
+
import pendulum
|
537
|
+
wrk=pendulum.parse(fdate).day_of_week
|
538
|
+
|
539
|
+
import datetime
|
540
|
+
todaydt = datetime.date.today().strftime('%Y-%m-%d')
|
541
|
+
if fdate > todaydt:
|
542
|
+
fdate=todaydt
|
543
|
+
|
544
|
+
if wrk==5:
|
545
|
+
if fdate != todaydt:
|
546
|
+
adj=-1
|
547
|
+
else:
|
548
|
+
adj=-(2+wrk)
|
549
|
+
elif wrk==6:
|
550
|
+
adj=-1
|
551
|
+
else:
|
552
|
+
adj=-(2+wrk)
|
553
|
+
last_fri=date_adjust(fdate,adjust=adj)
|
554
|
+
|
555
|
+
return last_fri
|
556
|
+
|
557
|
+
if __name__=='__main__':
|
558
|
+
start='2023-1-1'
|
559
|
+
end='2023-12-14'
|
560
|
+
get_all_friday(start,end)
|
561
|
+
|
562
|
+
def get_all_friday(start,end):
|
563
|
+
"""
|
564
|
+
功能:获取start和end之间所有的周五日期,配合申万指数估值函数使用
|
565
|
+
"""
|
566
|
+
#import pandas as pd
|
567
|
+
start_fri=get_last_friday(start)
|
568
|
+
end_fri=get_last_friday(end)
|
569
|
+
|
570
|
+
import akshare as ak
|
571
|
+
wrk_df=ak.index_analysis_week_month_sw("week")
|
572
|
+
wrk_df['Date']=wrk_df['date'].apply(lambda x:x.strftime('%Y-%m-%d'))
|
573
|
+
frilist=list(wrk_df['Date'])
|
574
|
+
|
575
|
+
period_frilist=[]
|
576
|
+
for f in frilist:
|
577
|
+
if (f >= start_fri) and (f <= end_fri):
|
578
|
+
period_frilist=period_frilist+[f]
|
579
|
+
|
580
|
+
return period_frilist
|
581
|
+
|
582
|
+
#==============================================================================
|
583
|
+
|
584
|
+
if __name__=='__main__':
|
585
|
+
industry='食品饮料'
|
586
|
+
industry='白酒Ⅱ'
|
587
|
+
start='2023-10-1'
|
588
|
+
end='2023-12-15'
|
589
|
+
vtype='PE'
|
590
|
+
|
591
|
+
graph=True
|
592
|
+
loc='best'
|
593
|
+
df=industry_valuation_history_sw_weekly(industry,start,end,vtype)
|
594
|
+
|
595
|
+
def industry_valuation_history_sw_weekly(industry,start,end,vtype='PE', \
|
596
|
+
graph=True,loc='best'):
|
597
|
+
"""
|
598
|
+
功能:绘制一个申万行业的周历史估值趋势,支持申万"市场表征", "一级行业", "二级行业", "风格指数"
|
599
|
+
不支持三级行业,若为非二级行业,转为industry_valuation_history_sw_daily函数处理日数据,专注处理二级行业周数据
|
600
|
+
vtype: PE, PB, dividend
|
601
|
+
|
602
|
+
"""
|
603
|
+
#检查日期期间
|
604
|
+
result,start1,end1=check_period(start,end)
|
605
|
+
if not result:
|
606
|
+
print(" #Warning(industry_valuation_history_sw_weekly): invalid date period",start,end)
|
607
|
+
return None
|
608
|
+
fridays=get_all_friday(start,end)
|
609
|
+
|
610
|
+
#检查估值类型
|
611
|
+
typelist=['pe','pb','dividend']
|
612
|
+
vtypeu=vtype.lower()
|
613
|
+
if not (vtypeu in typelist):
|
614
|
+
print(" #Warning(industry_valuation_history_sw_weekly): unsupported valuation type",vtype)
|
615
|
+
print(" Supported types:",typelist)
|
616
|
+
return None
|
617
|
+
|
618
|
+
vtypelist=['pe','pb','dividend']
|
619
|
+
typelist=['市盈率','市净率','股息率']
|
620
|
+
pos=vtypelist.index(vtypeu)
|
621
|
+
vtypes=typelist[pos]
|
622
|
+
|
623
|
+
#分辨申万行业代码类别
|
624
|
+
sw_codes=industry_sw_list()
|
625
|
+
sw_codes['type_name']=''
|
626
|
+
sw_codes['type_name']=sw_codes.apply(lambda x: '市场表征' if x['type']=='F' else x['type_name'],axis=1)
|
627
|
+
sw_codes['type_name']=sw_codes.apply(lambda x: '一级行业' if x['type']=='I' else x['type_name'],axis=1)
|
628
|
+
sw_codes['type_name']=sw_codes.apply(lambda x: '二级行业' if x['type']=='T' else x['type_name'],axis=1)
|
629
|
+
sw_codes['type_name']=sw_codes.apply(lambda x: '风格指数' if x['type']=='S' else x['type_name'],axis=1)
|
630
|
+
sw_codes['type_name']=sw_codes.apply(lambda x: '三级行业' if x['type']=='3' else x['type_name'],axis=1)
|
631
|
+
|
632
|
+
industry1=industry.split('.')[0]
|
633
|
+
industry_name_flag=industry_code_flag=False
|
634
|
+
try:
|
635
|
+
type_name=sw_codes[sw_codes['name']==industry1]['type_name'].values[0]
|
636
|
+
industry_name_flag=True
|
637
|
+
except:
|
638
|
+
try:
|
639
|
+
type_name=sw_codes[sw_codes['code']==industry1]['type_name'].values[0]
|
640
|
+
industry_code_flag=True
|
641
|
+
except:
|
642
|
+
print(" #Error(industry_valuation_history_sw_weekly): Shenwan industry not found for",industry)
|
643
|
+
return None
|
644
|
+
|
645
|
+
if type_name=='三级行业':
|
646
|
+
print(" #Error(industry_valuation_history_sw_weekly): currently does not support Shenwan 3rd_level industry",industry)
|
647
|
+
return None
|
648
|
+
|
649
|
+
if not (type_name=='二级行业'):
|
650
|
+
df=industry_valuation_history_sw_daily(industry=industry,start=start,end=end,vtype=vtype, \
|
651
|
+
graph=graph,loc=loc)
|
652
|
+
return df
|
653
|
+
|
654
|
+
# 获取行业估值历史周数据
|
655
|
+
import pandas as pd
|
656
|
+
import akshare as ak
|
657
|
+
df=None
|
658
|
+
for f in fridays:
|
659
|
+
f1=f[:4]+f[5:7]+f[8:]
|
660
|
+
try:
|
661
|
+
dft=ak.index_analysis_weekly_sw(symbol=type_name, date=f1)
|
662
|
+
except:
|
663
|
+
continue
|
664
|
+
|
665
|
+
"""
|
666
|
+
dft的结构:
|
667
|
+
['指数代码','指数名称','发布日期','收盘指数','成交量','涨跌幅','换手率',
|
668
|
+
'市盈率','市净率','均价','成交额占比','流通市值','平均流通市值','股息率']
|
669
|
+
"""
|
670
|
+
|
671
|
+
if not (dft is None):
|
672
|
+
if industry_name_flag:
|
673
|
+
dft2=dft[dft['指数名称']==industry1]
|
674
|
+
if industry_code_flag:
|
675
|
+
dft2=dft[dft['指数代码']==industry1]
|
676
|
+
|
677
|
+
if df is None:
|
678
|
+
df=dft2
|
679
|
+
else:
|
680
|
+
df=pd.concat([df,dft2])
|
681
|
+
|
682
|
+
df['date']=pd.to_datetime(df['发布日期'])
|
683
|
+
df.set_index('date',inplace=True)
|
684
|
+
df1=df[[vtypes]]
|
517
685
|
|
518
|
-
|
519
|
-
|
520
|
-
|
686
|
+
#筛选期间
|
687
|
+
#df2=df1[(df1.index >= start1) & (df1.index <= end1)]
|
688
|
+
df2=df1.dropna()
|
689
|
+
|
690
|
+
#绘图
|
691
|
+
if graph:
|
692
|
+
df2['平均值']=df2[vtypes].mean()
|
693
|
+
df2['中位数']=df2[vtypes].median()
|
694
|
+
|
695
|
+
titletxt="行业估值趋势:"+industry+','+vtypes
|
696
|
+
|
697
|
+
footnote0="注:申万宏源行业指数,"
|
698
|
+
footnote1=''
|
699
|
+
import datetime
|
700
|
+
today = datetime.date.today()
|
701
|
+
footnote2="数据来源: 申万宏源,"+str(today)
|
702
|
+
footnote=footnote0+footnote1+footnote2
|
703
|
+
|
704
|
+
colname=vtypes
|
705
|
+
collabel=vtypes
|
706
|
+
ylabeltxt=vtypes
|
707
|
+
|
708
|
+
draw_lines(df2,y_label=ylabeltxt,x_label=footnote, \
|
709
|
+
axhline_value=0,axhline_label='', \
|
710
|
+
title_txt=titletxt,data_label=False,resample_freq='D')
|
711
|
+
|
712
|
+
return df2
|
521
713
|
|
522
714
|
#==============================================================================
|
715
|
+
|
716
|
+
if __name__=='__main__':
|
717
|
+
industry='食品饮料'
|
718
|
+
industry='白酒Ⅱ'
|
719
|
+
start='2023-10-1'
|
720
|
+
end='2023-12-15'
|
721
|
+
vtype='PE'
|
722
|
+
|
723
|
+
graph=True
|
724
|
+
loc='best'
|
725
|
+
df=industry_valuation_history_sw(industry,start,end,vtype)
|
726
|
+
|
727
|
+
def industry_valuation_history_sw(industry,start,end,vtype='PE', \
|
728
|
+
graph=True,loc='best'):
|
729
|
+
"""
|
730
|
+
功能:绘制一个申万行业的日历史估值趋势,支持申万"市场表征", "一级行业", "二级行业", "风格指数"
|
731
|
+
不支持三级行业,若为非二级行业,转为industry_valuation_history_sw_daily函数处理日数据,专注处理二级行业日数据
|
732
|
+
vtype: PE, PB, dividend
|
733
|
+
|
734
|
+
"""
|
735
|
+
#检查日期期间
|
736
|
+
result,start1,end1=check_period(start,end)
|
737
|
+
if not result:
|
738
|
+
print(" #Warning(industry_valuation_history_sw): invalid date period",start,end)
|
739
|
+
return None
|
740
|
+
|
741
|
+
#检查估值类型
|
742
|
+
typelist=['pe','pb','dividend']
|
743
|
+
vtypeu=vtype.lower()
|
744
|
+
if not (vtypeu in typelist):
|
745
|
+
print(" #Warning(industry_valuation_history_sw): unsupported valuation type",vtype)
|
746
|
+
print(" Supported types:",typelist)
|
747
|
+
return None
|
748
|
+
|
749
|
+
vtypelist=['pe','pb','dividend']
|
750
|
+
typelist=['市盈率','市净率','股息率']
|
751
|
+
pos=vtypelist.index(vtypeu)
|
752
|
+
vtypes=typelist[pos]
|
753
|
+
|
754
|
+
#分辨申万行业代码类别
|
755
|
+
sw_codes=industry_sw_list()
|
756
|
+
sw_codes['type_name']=''
|
757
|
+
sw_codes['type_name']=sw_codes.apply(lambda x: '市场表征' if x['type']=='F' else x['type_name'],axis=1)
|
758
|
+
sw_codes['type_name']=sw_codes.apply(lambda x: '一级行业' if x['type']=='I' else x['type_name'],axis=1)
|
759
|
+
sw_codes['type_name']=sw_codes.apply(lambda x: '二级行业' if x['type']=='T' else x['type_name'],axis=1)
|
760
|
+
sw_codes['type_name']=sw_codes.apply(lambda x: '风格指数' if x['type']=='S' else x['type_name'],axis=1)
|
761
|
+
sw_codes['type_name']=sw_codes.apply(lambda x: '三级行业' if x['type']=='3' else x['type_name'],axis=1)
|
762
|
+
|
763
|
+
industry1=industry.split('.')[0]
|
764
|
+
industry_name_flag=industry_code_flag=False
|
765
|
+
try:
|
766
|
+
type_name=sw_codes[sw_codes['name']==industry1]['type_name'].values[0]
|
767
|
+
industry_name_flag=True
|
768
|
+
except:
|
769
|
+
try:
|
770
|
+
type_name=sw_codes[sw_codes['code']==industry1]['type_name'].values[0]
|
771
|
+
industry_code_flag=True
|
772
|
+
except:
|
773
|
+
print(" #Error(industry_valuation_history_sw): Shenwan industry not found for",industry)
|
774
|
+
return None
|
775
|
+
|
776
|
+
if type_name=='三级行业':
|
777
|
+
print(" #Error(industry_valuation_history_sw): currently does not support Shenwan 3rd_level industry",industry)
|
778
|
+
return None
|
779
|
+
|
780
|
+
if not (type_name=='二级行业'):
|
781
|
+
df=industry_valuation_history_sw_daily(industry=industry,start=start,end=end,vtype=vtype, \
|
782
|
+
graph=graph,loc=loc)
|
783
|
+
return df
|
784
|
+
|
785
|
+
# 获取行业估值历史周数据
|
786
|
+
import pandas as pd
|
787
|
+
import akshare as ak
|
788
|
+
start2=start1.strftime('%Y-%m-%d')
|
789
|
+
end2 =end1.strftime('%Y-%m-%d')
|
790
|
+
pdate=end2
|
791
|
+
dstep=7
|
792
|
+
df=None
|
793
|
+
while (pdate >= start2) or (abs(date_delta(pdate,start2)) < dstep):
|
794
|
+
if pdate >= start2:
|
795
|
+
enddate=pdate
|
796
|
+
fromdate=date_adjust(pdate,adjust=-dstep)
|
797
|
+
else:
|
798
|
+
enddate=start2
|
799
|
+
fromdate=pdate
|
800
|
+
|
801
|
+
try:
|
802
|
+
fromdate1=fromdate[:4]+fromdate[5:7]+fromdate[8:10]
|
803
|
+
enddate1=enddate[:4]+enddate[5:7]+enddate[8:10]
|
804
|
+
dft=ak.index_analysis_daily_sw(symbol=type_name,start_date=fromdate1,end_date=enddate1)
|
805
|
+
except:
|
806
|
+
dft=None
|
807
|
+
"""
|
808
|
+
try:
|
809
|
+
fromdate1=fromdate[:4]+fromdate[5:7]+fromdate[8:10]
|
810
|
+
enddate1=enddate[:4]+enddate[5:7]+enddate[8:10]
|
811
|
+
dft=ak.index_analysis_daily_sw(symbol=type_name,start_date=fromdate1,end_date=enddate1)
|
812
|
+
except:
|
813
|
+
continue
|
814
|
+
"""
|
815
|
+
"""
|
816
|
+
dft的结构:
|
817
|
+
['指数代码','指数名称','发布日期','收盘指数','成交量','涨跌幅','换手率',
|
818
|
+
'市盈率','市净率','均价','成交额占比','流通市值','平均流通市值','股息率']
|
819
|
+
"""
|
820
|
+
|
821
|
+
if not (dft is None):
|
822
|
+
if industry_name_flag:
|
823
|
+
dft2=dft[dft['指数名称']==industry1]
|
824
|
+
if industry_code_flag:
|
825
|
+
dft2=dft[dft['指数代码']==industry1]
|
826
|
+
|
827
|
+
if df is None:
|
828
|
+
df=dft2
|
829
|
+
else:
|
830
|
+
df=pd.concat([df,dft2])
|
831
|
+
|
832
|
+
# 开始下一轮循环
|
833
|
+
pdate=date_adjust(fromdate,adjust=-1)
|
834
|
+
|
835
|
+
df.sort_values('发布日期',ascending=True,inplace=True)
|
836
|
+
df.drop_duplicates(inplace=True)
|
837
|
+
|
838
|
+
#df=df[df.index >= start1]
|
839
|
+
#df.dropna(inplace=True)
|
840
|
+
|
841
|
+
df['date']=pd.to_datetime(df['发布日期'])
|
842
|
+
df.set_index('date',inplace=True)
|
843
|
+
df1=df[[vtypes]]
|
844
|
+
|
845
|
+
#筛选期间
|
846
|
+
#df2=df1[(df1.index >= start1) & (df1.index <= end1)]
|
847
|
+
df2=df1
|
848
|
+
|
849
|
+
#绘图
|
850
|
+
if graph:
|
851
|
+
df2['平均值']=df2[vtypes].mean()
|
852
|
+
df2['中位数']=df2[vtypes].median()
|
853
|
+
|
854
|
+
titletxt="行业估值趋势:"+industry+','+vtypes
|
855
|
+
|
856
|
+
footnote0="注:申万行业分类指数,"
|
857
|
+
footnote1=''
|
858
|
+
import datetime
|
859
|
+
today = datetime.date.today()
|
860
|
+
footnote2="数据来源: 申万宏源,"+str(today)
|
861
|
+
footnote=footnote0+footnote1+footnote2
|
862
|
+
|
863
|
+
colname=vtypes
|
864
|
+
collabel=vtypes
|
865
|
+
ylabeltxt=vtypes
|
866
|
+
|
867
|
+
draw_lines(df2,y_label=ylabeltxt,x_label=footnote, \
|
868
|
+
axhline_value=0,axhline_label='', \
|
869
|
+
title_txt=titletxt,data_label=False,resample_freq='D')
|
870
|
+
|
871
|
+
return df2
|
872
|
+
|
873
|
+
#==============================================================================
|
874
|
+
#==============================================================================
|
523
875
|
if __name__=='__main__':
|
524
876
|
industries=['食品饮料','纺织服饰']
|
525
|
-
|
526
|
-
|
877
|
+
industries=['银行','国有大型银行Ⅱ','股份制银行Ⅱ','城商行Ⅱ','农商行Ⅱ']
|
878
|
+
start='2023-12-1'
|
879
|
+
end='2023-12-15'
|
527
880
|
vtypes='PE'
|
528
881
|
|
529
882
|
industries='纺织服饰'
|
@@ -532,6 +885,8 @@ if __name__=='__main__':
|
|
532
885
|
graph=True
|
533
886
|
loc1='lower left'
|
534
887
|
loc2='upper right'
|
888
|
+
|
889
|
+
df5=compare_industry_valuation_sw(industries,start,end,vtypes)
|
535
890
|
|
536
891
|
def compare_industry_valuation_sw(industries,start,end,vtypes='PE', \
|
537
892
|
graph=True,loc1='best',loc2='best'):
|
@@ -564,6 +919,8 @@ def compare_industry_valuation_sw(industries,start,end,vtypes='PE', \
|
|
564
919
|
import pandas as pd
|
565
920
|
df=pd.DataFrame()
|
566
921
|
for i in industries:
|
922
|
+
# debug
|
923
|
+
print(" ...Searching valuation info for",i,'\b, which may take time ...')
|
567
924
|
dft=industry_valuation_history_sw(i,start=start,end=end,vtype=vtype,graph=False)
|
568
925
|
if not (dft is None):
|
569
926
|
dft.rename(columns={vtypec:i},inplace=True)
|
@@ -1301,4 +1658,70 @@ def multi_ols(df,xList,y,industryDummies,yearDummies):
|
|
1301
1658
|
|
1302
1659
|
return coefMatrix
|
1303
1660
|
|
1661
|
+
#==============================================================================
|
1662
|
+
#==============================================================================
|
1663
|
+
#==============================================================================
|
1664
|
+
if __name__=='__main__':
|
1665
|
+
sw_code='850831.SW'
|
1666
|
+
sw_code='801193.SW'
|
1667
|
+
indicator='PE'
|
1668
|
+
start='2023-1-1'
|
1669
|
+
end='2023-12-15'
|
1670
|
+
top=10
|
1671
|
+
|
1672
|
+
def valuation_industry_sw_generating(sw_code,indicator,start,end,top=5):
|
1673
|
+
"""
|
1674
|
+
功能:模拟申万行业指数的估值,PE/PB/股息率等
|
1675
|
+
sw_code:申万行业分类指数,各个级别
|
1676
|
+
start/end:开始/结束日期
|
1677
|
+
top:使用前几大成分股的估值进行合成
|
1678
|
+
|
1679
|
+
注意:指数模拟出的估值曲线波动过大,缺乏实用价值!
|
1680
|
+
"""
|
1681
|
+
import pandas as pd
|
1682
|
+
#查找申万行业指数成分股
|
1683
|
+
clist,cdf=industry_stock_sw(industry=sw_code,top=top)
|
1684
|
+
|
1685
|
+
#查找成分股的历史估值
|
1686
|
+
df=None
|
1687
|
+
for t in clist:
|
1688
|
+
dft=get_stock_valuation_cn_hk(ticker=t,indicators=indicator,start=start,end=end)
|
1689
|
+
dft[t]=dft[indicator]
|
1690
|
+
dft2=dft[[t]]
|
1691
|
+
if dft2 is None: continue
|
1692
|
+
|
1693
|
+
#将负数填充为0,不计入估值?整个成分股剔除?
|
1694
|
+
dft2[t]=dft2[t].apply(lambda x: 0 if x<0 else x)
|
1695
|
+
|
1696
|
+
if df is None:
|
1697
|
+
df=dft2
|
1698
|
+
else:
|
1699
|
+
df=pd.merge(df,dft2,how='outer',left_index=True,right_index=True)
|
1700
|
+
|
1701
|
+
#成分股权重
|
1702
|
+
weight=list(cdf['最新权重'])
|
1703
|
+
|
1704
|
+
#各行权重分别求和
|
1705
|
+
dfw=df.copy()
|
1706
|
+
collist=list(dfw)
|
1707
|
+
for c in collist:
|
1708
|
+
dfw[c]=dfw[c].apply(lambda x: 0 if x<=0 else 1)
|
1709
|
+
dfw['weight']=dfw.dot(weight)
|
1710
|
+
dfw2=dfw[['weight']]
|
1711
|
+
|
1712
|
+
#加权平均
|
1713
|
+
df['weighted_total']=df.dot(weight)
|
1714
|
+
df2=pd.merge(df,dfw2,left_index=True,right_index=True)
|
1715
|
+
|
1716
|
+
df2['weighted_avg']=df2['weighted_total']/df2['weight']
|
1717
|
+
df2['code']=sw_code
|
1718
|
+
df3=df2[['code','weighted_avg']]
|
1719
|
+
|
1720
|
+
#因有市盈率负数,不管如何处理都会导致加权平均后数值波动过大,不能实用
|
1721
|
+
return df3
|
1722
|
+
|
1723
|
+
|
1724
|
+
|
1725
|
+
|
1726
|
+
|
1304
1727
|
#==============================================================================
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: siat
|
3
|
-
Version: 2.11.
|
3
|
+
Version: 2.11.19
|
4
4
|
Summary: Securities Investment Analysis Tools (siat)
|
5
5
|
Home-page: https://pypi.org/project/siat/
|
6
6
|
Author: Prof. WANG Dehong, Business School, BFSU
|
@@ -28,6 +28,7 @@ Requires-Dist: ruamel-yaml
|
|
28
28
|
Requires-Dist: prettytable
|
29
29
|
Requires-Dist: graphviz
|
30
30
|
Requires-Dist: luddite
|
31
|
+
Requires-Dist: pendulum
|
31
32
|
|
32
33
|
|
33
34
|
This plug-in is designed to use with the author's textbooks on security investment,
|
@@ -61,7 +61,7 @@ siat/grafix_test.py,sha256=kXvcpLgQNO7wd30g_bWljLj5UH7bIVI0_dUtXbfiKR0,3150
|
|
61
61
|
siat/holding_risk.py,sha256=Dh4zXEw-0hnbMNorbsRS142C8mUzq4NhFjYnauWu5tc,30548
|
62
62
|
siat/holding_risk_test.py,sha256=FRlw_9wFG98BYcg_cSj95HX5WZ1TvkGaOUdXD7-V86s,474
|
63
63
|
siat/local_debug_test.py,sha256=CDAOffW1Rvs-TcNN5giWVvHMlch1w4dp-w5SIV9jXL0,3936
|
64
|
-
siat/market_china.py,sha256=
|
64
|
+
siat/market_china.py,sha256=pwCjEqkNAcOrs4Ba5DIQ5WgyAC73ntOi-d7Cb29wOWk,37849
|
65
65
|
siat/markowitz.py,sha256=gs_R-FiykUMXfTVS0r_HswLC6VFmdmQMcQh7dh285iM,96379
|
66
66
|
siat/markowitz_ccb_test.py,sha256=xBkkoaNHdq9KSUrNuHGgKTdNYUvgi84kNYcf719eoyE,1593
|
67
67
|
siat/markowitz_ef_test.py,sha256=wjNlICkgRIqnonPeSIHo4Mu2GRtb9dr21wDt2kMNEcI,4032
|
@@ -118,13 +118,13 @@ siat/transaction_test.py,sha256=Z8g1LJCN4-mnUByXMUMoFmN0t105cbmsz2QmvSuIkbU,1858
|
|
118
118
|
siat/translate-20230125.py,sha256=NPPSXhT38s5t9fzMvl_fvi4ckSB73ThLmZetVI-xGdU,117953
|
119
119
|
siat/translate-20230206.py,sha256=-vtI125WyaJhmPotOpDAmclt_XnYVaWU9ByLWZ6FyYE,118133
|
120
120
|
siat/translate-20230215.py,sha256=TJgtPE3n8IjljmZ4Pefy8dmHoNdFF-1zpML6BhA9FKE,121657
|
121
|
-
siat/translate.py,sha256=
|
121
|
+
siat/translate.py,sha256=zAemLG2s7wABKhZjM7esMfqH3tKX48O53sTEOLdilZI,142620
|
122
122
|
siat/universal_test.py,sha256=CDAOffW1Rvs-TcNN5giWVvHMlch1w4dp-w5SIV9jXL0,3936
|
123
|
-
siat/valuation.py,sha256=
|
124
|
-
siat/valuation_china.py,sha256=
|
123
|
+
siat/valuation.py,sha256=3VKrO9b9xY9dOJGGuF0ZhytzB5d2pCx3kO3TtMml7mo,44025
|
124
|
+
siat/valuation_china.py,sha256=oEQRrktJNHiOG1mJSQN1aSSQAQrwrg-ppIHyNVjMjNg,67603
|
125
125
|
siat/valuation_market_china_test.py,sha256=gbJ0ioauuo4koTPH6WKUkqcXiQPafnbhU5eKJ6lpdLA,1571
|
126
126
|
siat/var_model_validation.py,sha256=zB_Skk_tmzIR15l6oAW3am4HBGVIG-eZ8gJhCdXZ8Qw,14859
|
127
|
-
siat-2.11.
|
128
|
-
siat-2.11.
|
129
|
-
siat-2.11.
|
130
|
-
siat-2.11.
|
127
|
+
siat-2.11.19.dist-info/METADATA,sha256=Mdm4x2u8FSNCFOkTSMVc-AcohE2iWXihxWC1tKD2vws,1379
|
128
|
+
siat-2.11.19.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
129
|
+
siat-2.11.19.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
|
130
|
+
siat-2.11.19.dist-info/RECORD,,
|
File without changes
|
File without changes
|