siat 3.8.27__py3-none-any.whl → 3.8.30__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/economy2.py CHANGED
@@ -360,6 +360,8 @@ if __name__ =="__main__":
360
360
  indicator="NY.GDP.MKTP.KN"
361
361
  indicator="GC.XPN.TOTL.GD.ZS"
362
362
 
363
+ indicator='GC.GDP.COMP.ZS' # 自制指标
364
+
363
365
  start='2010'; end='2025'; power=3
364
366
 
365
367
  zeroline=False
@@ -380,7 +382,7 @@ def economy_indicator_wb(ticker='CN',indicator='NY.GDP.MKTP.KN', \
380
382
  attention_point='',attention_point_area='', \
381
383
  average_value=False, \
382
384
  datatag=False,power=0,graph=True, \
383
- mark_top=True,mark_bottom=True,mark_end=True, \
385
+ mark_start=False,mark_top=False,mark_bottom=False,mark_end=True, \
384
386
  facecolor='whitesmoke',loc='best',maxticks=30):
385
387
  """
386
388
  ===========================================================================
@@ -406,6 +408,15 @@ def economy_indicator_wb(ticker='CN',indicator='NY.GDP.MKTP.KN', \
406
408
  输出:图形
407
409
  返回值:数据表
408
410
  """
411
+ import pandas as pd
412
+
413
+ # 自制指标
414
+ sm_ind_list=['GC.GDP.COMP.ZS']
415
+ if indicator in sm_ind_list:
416
+ sm_ind_flag=True
417
+ else:
418
+ sm_ind_flag=False
419
+
409
420
  # 检测指标是否存在,并取得指标名称
410
421
  indicator_name=indicator_name_wb(indicator)
411
422
  if indicator_name == indicator:
@@ -416,11 +427,36 @@ def economy_indicator_wb(ticker='CN',indicator='NY.GDP.MKTP.KN', \
416
427
  start,end=start_end_preprocess(start,end)
417
428
 
418
429
  # 下载数据
419
- try:
420
- pricedf=wb.download(indicator=indicator,country=ticker,start=start,end=end)
421
- except:
422
- print(f" #Error(economy_indicator_wb): {indicator} not available for {ticker}")
423
- return None
430
+ if not sm_ind_flag:
431
+ try:
432
+ pricedf=wb.download(indicator=indicator,country=ticker,start=start,end=end)
433
+ except:
434
+ print(f" #Error(economy_indicator_wb): {indicator} not available for {ticker}")
435
+ return None
436
+ elif indicator == 'GC.GDP.COMP.ZS': # 针对自制指标
437
+ indtmp1='NY.GDP.FCST.CN' # Compensation of employees (current LCU),CN无数据!
438
+ indtmp2='NY.GDP.MKTP.CN' # GDP (current LCU)
439
+ try:
440
+ pricetmp1=wb.download(indicator=indtmp1,country=ticker,start=start,end=end)
441
+ except:
442
+ print(f" #Error(economy_indicator_wb): element {indtmp1} not available for {ticker}")
443
+ return None
444
+ try:
445
+ pricetmp2=wb.download(indicator=indtmp2,country=ticker,start=start,end=end)
446
+ except:
447
+ print(f" #Error(economy_indicator_wb): element {indtmp2} not available for {ticker}")
448
+ return None
449
+
450
+ # 算法=indtmp1 / indtmp2 * 100
451
+ pricetmp=pd.merge(pricetmp1,pricetmp2,how='inner',left_on=['country','year'],
452
+ right_on=['country','year'])
453
+ pricetmp[indicator]=pricetmp.apply(lambda x: round(x[indtmp1]/x[indtmp2]*100,2),axis=1)
454
+ pricetmp['country']=pricetmp.index[0][0]
455
+ pricetmp['year']=pricetmp.index
456
+ pricetmp['year']=pricetmp['year'].apply(lambda x: x[1])
457
+
458
+ pricedf=pricetmp[['country','year',indicator]]
459
+ pricedf.reset_index(drop=True,inplace=True)
424
460
 
425
461
  # 是否返回None
426
462
  if pricedf is None:
@@ -432,10 +468,14 @@ def economy_indicator_wb(ticker='CN',indicator='NY.GDP.MKTP.KN', \
432
468
  return None
433
469
  # 是否返回数据表但内容均为NaN
434
470
  if pricedf[indicator].isnull().all():
435
- print(f" #Error(economy_indicator_wb): empty data found on {indicator} in {ticker}")
471
+ print(f" #Error(economy_indicator_wb): all empty data found on {indicator} in {ticker}")
436
472
  return None
437
-
438
- pricedf.reset_index(inplace=True)
473
+ # 判断非空值的个数
474
+ if pricedf[indicator].count() == 1:
475
+ print(f" #Warning(economy_indicator_wb): only 1 non-empty data found on {indicator} in {ticker}")
476
+ #return None
477
+
478
+ pricedf.reset_index(drop=True,inplace=True)
439
479
  pricedf.set_index('year',inplace=True)
440
480
  pricedf.rename(columns={indicator:indicator_name},inplace=True)
441
481
  country=pricedf['country'].values[0]
@@ -475,10 +515,6 @@ def economy_indicator_wb(ticker='CN',indicator='NY.GDP.MKTP.KN', \
475
515
  erdf3[indicator_name]=erdf3[indicator_name].apply(lambda x: round(x/unit_amount,2))
476
516
 
477
517
  # 绘图
478
- """
479
- if not graph:
480
- return erdf3
481
- """
482
518
  # 判断是否绘制零线
483
519
  if ind_max * ind_min <0:
484
520
  zeroline=True
@@ -510,7 +546,8 @@ def economy_indicator_wb(ticker='CN',indicator='NY.GDP.MKTP.KN', \
510
546
  average_value=average_value, \
511
547
  attention_value=attention_value,attention_value_area=attention_value_area, \
512
548
  attention_point=attention_point,attention_point_area=attention_point_area, \
513
- mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end, \
549
+ mark_top=mark_top,mark_bottom=mark_bottom, \
550
+ mark_start=mark_start,mark_end=mark_end, \
514
551
  facecolor=facecolor,loc=loc,maxticks=30,translate=translate)
515
552
  except Exception as e:
516
553
  # 捕获所有异常
@@ -553,7 +590,7 @@ def economy_mindicators_wb(ticker='CN',indicator=['NY.GDP.MKTP.CN','NY.GDP.MKTP.
553
590
  graph=True,smooth=False,loc='best',facecolor='whitesmoke', \
554
591
  date_range=False,date_freq=False, \
555
592
  annotate=False,annotate_value=False, \
556
- mark_top=False,mark_bottom=False,mark_end=False, \
593
+ mark_start=False,mark_top=False,mark_bottom=False,mark_end=False, \
557
594
  maxticks=30,translate=False):
558
595
  """
559
596
  ===========================================================================
@@ -573,7 +610,7 @@ def economy_mindicators_wb(ticker='CN',indicator=['NY.GDP.MKTP.CN','NY.GDP.MKTP.
573
610
  facecolor:画布背景颜色,默认'whitesmoke'
574
611
  annotate:是否在曲线末端标注,默认否False
575
612
  annotate_value:是否标注曲线末端值,默认否False
576
- mark_top, mark_bottom, mark_end:是否标注最大、最小、末端值,默认否
613
+ mark_start, mark_top, mark_bottom, mark_end:是否标注起始值、最大、最小、末端值,默认否
577
614
  maxticks=30:限制横轴刻度最大数量
578
615
 
579
616
  date_range=False:指定开始结束日期绘图
@@ -720,7 +757,8 @@ def economy_mindicators_wb(ticker='CN',indicator=['NY.GDP.MKTP.CN','NY.GDP.MKTP.
720
757
  attention_value=attention_value,attention_value_area=attention_value_area, \
721
758
  attention_point=attention_point,attention_point_area=attention_point_area, \
722
759
  annotate=annotate,annotate_value=annotate_value, \
723
- mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end,facecolor=facecolor, \
760
+ mark_start=mark_start,mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end, \
761
+ facecolor=facecolor, \
724
762
  band_area=band_area,loc=loc,maxticks=maxticks,translate=translate)
725
763
 
726
764
  return pricedf
@@ -758,7 +796,7 @@ def economy_mtickers_wb(ticker=['CN','US','JP'],indicator='NY.GDP.MKTP.PP.CD', \
758
796
  band_area='',loc='best', \
759
797
  annotate=False,annotate_value=False, \
760
798
  smooth=False, \
761
- mark_top=True,mark_bottom=True,mark_end=False, \
799
+ mark_start=False,mark_top=True,mark_bottom=True,mark_end=False, \
762
800
  maxticks=30,translate=False):
763
801
  """
764
802
  ===========================================================================
@@ -969,7 +1007,8 @@ def economy_mtickers_wb(ticker=['CN','US','JP'],indicator='NY.GDP.MKTP.PP.CD', \
969
1007
  attention_value=attention_value,attention_value_area=attention_value_area, \
970
1008
  attention_point=attention_point,attention_point_area=attention_point_area, \
971
1009
  annotate=annotate,annotate_value=annotate_value,plus_sign=plus_sign, \
972
- mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end,facecolor=facecolor, \
1010
+ mark_start=mark_start,mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end, \
1011
+ facecolor=facecolor, \
973
1012
  maxticks_enable=False,maxticks=10, \
974
1013
  translate=translate)
975
1014
 
@@ -982,7 +1021,7 @@ def economy_trend2(ticker='CN',indicator='NY.GDP.MKTP.KN', \
982
1021
  start='L10Y',end='today',translate=False, \
983
1022
  attention_value='',attention_value_area='', \
984
1023
  attention_point='',attention_point_area='', \
985
- mark_top=False,mark_bottom=False,mark_end=False, \
1024
+ mark_start=False,mark_top=False,mark_bottom=False,mark_end=False, \
986
1025
  graph=True,facecolor='whitesmoke',loc='best',maxticks=30, \
987
1026
 
988
1027
  zeroline=False,average_value=False, \
@@ -1009,7 +1048,7 @@ def economy_trend2(ticker='CN',indicator='NY.GDP.MKTP.KN', \
1009
1048
  attention_point:横轴关注值或其列表,默认无''
1010
1049
  attention_point_area:横轴关注值区间强调,默认无''
1011
1050
  graph:是否绘图,默认是True
1012
- mark_top, mark_bottom, mark_end:是否标记最高、最低和末端点:默认是True
1051
+ mark_start, mark_top, mark_bottom, mark_end:是否标记开始点、最高、最低和末端点:默认否False
1013
1052
  facecolor:背景颜色,默认'whitesmoke'
1014
1053
  loc:图例位置,默认自动'best'
1015
1054
 
@@ -1082,7 +1121,8 @@ def economy_trend2(ticker='CN',indicator='NY.GDP.MKTP.KN', \
1082
1121
  attention_value_area=attention_value_area, \
1083
1122
  attention_point=attention_point, \
1084
1123
  attention_point_area=attention_point_area, \
1085
- mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end, \
1124
+ mark_top=mark_top,mark_bottom=mark_bottom, \
1125
+ mark_start=mark_start,mark_end=mark_end, \
1086
1126
  graph=graph,facecolor=facecolor,loc=loc,maxticks=maxticks, \
1087
1127
 
1088
1128
  power=power,average_value=average_value, \
@@ -1097,7 +1137,8 @@ def economy_trend2(ticker='CN',indicator='NY.GDP.MKTP.KN', \
1097
1137
  attention_value_area=attention_value_area, \
1098
1138
  attention_point=attention_point, \
1099
1139
  attention_point_area=attention_point_area, \
1100
- mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end, \
1140
+ mark_top=mark_top,mark_bottom=mark_bottom, \
1141
+ mark_start=mark_start,mark_end=mark_end, \
1101
1142
  graph=graph,loc=loc,facecolor=facecolor,maxticks=maxticks, \
1102
1143
  band_area=band_area, \
1103
1144
  annotate=annotate,annotate_value=annotate_value,smooth=smooth, \
@@ -1115,7 +1156,8 @@ def economy_trend2(ticker='CN',indicator='NY.GDP.MKTP.KN', \
1115
1156
  attention_value_area=attention_value_area, \
1116
1157
  attention_point=attention_point, \
1117
1158
  attention_point_area=attention_point_area, \
1118
- mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end, \
1159
+ mark_top=mark_top,mark_bottom=mark_bottom, \
1160
+ mark_start=mark_start,mark_end=mark_end, \
1119
1161
  graph=graph,facecolor=facecolor,loc=loc,maxticks=maxticks, \
1120
1162
 
1121
1163
  annotate=annotate,annotate_value=annotate_value,smooth=smooth, \
@@ -1505,13 +1547,23 @@ def economic_translate(indicator):
1505
1547
  'Exports of goods and services (% of GDP)',
1506
1548
  'Exports of goods and services (% of GDP)'],
1507
1549
 
1550
+ ['NE.IMP.GNFS.CD','进口商品和服务总金额(美元现价)',
1551
+ 'Imports of goods and services (current US$)',
1552
+ 'Imports of goods and services (current US$)'],
1553
+
1554
+ ['NE.EXP.GNFS.CD','出口商品和服务总金额(美元现价)',
1555
+ 'Exports of goods and services (current US$)',
1556
+ 'Exports of goods and services (current US$)'],
1557
+
1508
1558
  ['NE.IMP.GNFS.ZS','进口商品和服务占GDP%',
1509
1559
  'Imports of goods and services (% of GDP)',
1510
1560
  'Imports of goods and services (% of GDP)'],
1511
1561
 
1512
-
1513
-
1514
-
1562
+ ['NE.TRD.GNFS.ZS','国际贸易占GDP%',
1563
+ 'Trade % of GDP',
1564
+ 'Trade % of GDP'],
1565
+ # 用来分析一个国家对国际贸易的依赖程度。
1566
+ # 高贸易占比通常表明一个国家的经济结构以出口和进口为主,而低贸易占比可能表明经济更依赖国内消费或投资。
1515
1567
 
1516
1568
  # 贫困和贫富分化========================================================
1517
1569
  ['SI.POV.GINI','基尼指数',
@@ -1520,8 +1572,60 @@ def economic_translate(indicator):
1520
1572
  # 基尼指数:0-100,用于衡量收入或财富分配的不平等程度。
1521
1573
  # 0表示完全平等,100表示完全不平等。基尼系数高通常意味着贫富差距较大。
1522
1574
  # 注意不是基尼系数(0-1)。
1575
+
1576
+ # 薪酬=================================================================
1577
+ ['GC.GDP.COMP.ZS','劳动者薪酬占GDP%',
1578
+ 'Compensation of employees (% of GDP)',
1579
+ 'Compensation of employees (% of GDP)'],
1580
+ # 自制指标:= GC.XPN.COMP.ZS: Compensation of employees (% of expense)
1581
+ # x GC.XPN.TOTL.GD.ZS: Expense (% of GDP) / 100。
1582
+ # 或 = GC.XPN.COMP.CN: Compensation of employees (current LCU)
1583
+ # / NY.GDP.MKTP.CN: GDP (current LCU) * 100.
1584
+
1585
+ # 储蓄=================================================================
1586
+ ['NY.GNS.ICTR.ZS','国民储蓄总额占GDP%',
1587
+ 'Gross savings (% of GDP)',
1588
+ 'Gross savings (% of GDP)'],
1589
+ # 国民储蓄:一国居民和政府的总储蓄,包含国内储蓄和来自国外的净收入
1590
+ # 包含国际要素:计入来自国外的净要素收入(如投资收益、侨汇)。
1523
1591
 
1592
+ ['NY.GDS.TOTL.ZS','国内储蓄总额占GDP%',
1593
+ 'Gross Domestic Savings (% of GDP)',
1594
+ 'Gross Domestic Savings (% of GDP)'],
1595
+ # 国内储蓄:仅统计国内经济主体(家庭、企业、政府)的储蓄,不包含国外净收入。
1596
+ # 仅限国内:不涉及国际收入或支出。
1597
+
1598
+ # 投资=================================================================
1599
+ ['NE.GDI.TOTL.ZS','总资本形成占GDP%',
1600
+ 'Gross capital formation (% of GDP)',
1601
+ 'Gross capital formation (% of GDP)'],
1602
+ # 又名Gross domestic investment国内总投资,包括政府、企业和家庭的投资
1603
+
1604
+ ['NE.GDI.FTOT.ZS','总固定资本形成占GDP%',
1605
+ 'Gross fixed capital formation (% of GDP)',
1606
+ 'Gross fixed capital formation (% of GDP)'],
1607
+ # 又名Gross domestic fixed investment国内固定资产总投资,包括政府、企业和家庭的投资
1608
+
1609
+ ['BX.KLT.DINV.WD.GD.ZS','外国直接投资净额占GDP%',
1610
+ 'Foreign direct investment, net inflows (% of GDP)',
1611
+ 'Foreign direct investment, net inflows (% of GDP)'],
1612
+ # 等于FDI流入 - FDI流出
1613
+
1614
+ # 政府财政==============================================================
1615
+ ['GC.REV.XGRT.GD.ZS','政府总收入(不含国际赠款)占GDP%',
1616
+ 'Revenue, excluding grant (% of GDP)',
1617
+ 'Revenue, excluding grant (% of GDP)'],
1618
+ # 包括税收和非税收入
1619
+
1620
+ ['SH.XPD.GHED.GD.ZS','政府卫生支出占GDP%',
1621
+ 'Government health expenditure (% of GDP)',
1622
+ 'Domestic general government health expenditure (% of GDP)'],
1623
+ # 包括税收和非税收入
1524
1624
 
1625
+ ['SH.XPD.GHED.CH.ZS','政府卫生支出占当前卫生支出%',
1626
+ 'Government health expenditure (% of health expenditure)',
1627
+ 'Domestic general government health expenditure (% of current health expenditure)'],
1628
+ # 包括税收和非税收入
1525
1629
 
1526
1630
 
1527
1631
 
@@ -1540,7 +1644,7 @@ def economic_translate(indicator):
1540
1644
 
1541
1645
  found=False; result=indicator
1542
1646
  try:
1543
- dict_word=trans_dict[trans_dict['indicator']==indicator]
1647
+ dict_word=trans_dict[trans_dict['indicator']==indicator.upper()]
1544
1648
  found=True
1545
1649
  except:
1546
1650
  #未查到翻译词汇,返回原词
siat/grafix.py CHANGED
@@ -106,7 +106,7 @@ if __name__ =="__main__":
106
106
  power=0
107
107
  zeroline=False
108
108
  average_value=False
109
- resample_freq='H'
109
+ resample_freq='D'
110
110
  loc='best'
111
111
  date_range=False
112
112
  date_freq=False
@@ -122,9 +122,9 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
122
122
  attention_point='',attention_point_area='', \
123
123
  average_value=False, \
124
124
 
125
- resample_freq='H',loc='best', \
125
+ resample_freq='D',loc='best', \
126
126
  date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
127
- mark_top=True,mark_bottom=True,mark_end=True, \
127
+ mark_start=False,mark_top=True,mark_bottom=True,mark_end=True, \
128
128
  facecolor='whitesmoke',maxticks=15,translate=False):
129
129
  """
130
130
  功能:绘制折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
@@ -203,7 +203,7 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
203
203
 
204
204
  #绘制数据标签
205
205
  if datatag:
206
- mark_top=False; mark_bottom=False; mark_end=False
206
+ mark_start=False; mark_top=False; mark_bottom=False; mark_end=False
207
207
  for x, y in zip(df.index, df[colname]):
208
208
  plt.text(x,y*1.001,'%.2f' % y,ha='center',va='bottom',color='black')
209
209
 
@@ -243,6 +243,19 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
243
243
  plt.text(x,y1,s % y,ha='right',va='bottom',color='seagreen')
244
244
  plt.scatter(x,y, color='seagreen',marker='8',s=70)
245
245
 
246
+ #标记曲线开始数值
247
+ if mark_start:
248
+ df_start=df.head(1)
249
+ y_start = df_start[colname].min() # 开始的y坐标
250
+ x_start = df_start[colname].idxmin() # 开始值的x坐标
251
+
252
+ #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
253
+ y1=str(round(y_start,1)) if abs(y_start) >= 100 else str(round(y_start,2)) if abs(y_start) >= 1 else str(round(y_start,3))
254
+ plt.annotate(text=y1,
255
+ xy=(x_start, y_start),
256
+ xytext=(x_start, y_start*0.998),fontsize=annotate_size,ha='right',va='center')
257
+ # 特别注意:这里的left/right与实际图示的方向正好相反!!!
258
+
246
259
  #标记曲线末端数值
247
260
  if mark_end:
248
261
  df_end=df.tail(1)
@@ -253,7 +266,7 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
253
266
  y1=str(round(y_end,1)) if abs(y_end) >= 100 else str(round(y_end,2)) if abs(y_end) >= 1 else str(round(y_end,3))
254
267
  plt.annotate(text=' '+y1,
255
268
  xy=(x_end, y_end),
256
- xytext=(x_end, y_end),fontsize=annotate_size)
269
+ xytext=(x_end, y_end*0.998),fontsize=annotate_size,ha='left',va='center')
257
270
 
258
271
  #是否绘制水平线
259
272
  if isinstance(zeroline,bool):#若zeroline为True
@@ -340,13 +353,15 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
340
353
  plt.fill_betweenx(yaxis_data,apa_list[0],apa_list[1],color='powderblue',alpha=0.5)
341
354
 
342
355
  if average_value:
343
- av=df[colname].mean()
344
- plt.axhline(y=av,ls="dashed",c="blueviolet",linewidth=2,label=text_lang("均值","Mean"))
345
356
  haveLegend=True
357
+
358
+ av=df[colname].mean()
346
359
  #av=str(round(av,2)) if av < 100 else str(int(av))
347
- av=str(int(av)) if abs(av) >= 100 else str(round(av,2)) if abs(av) >= 10 else str(round(av,3))
360
+ #av=str(int(av)) if abs(av) >= 100 else str(round(av,2)) if abs(av) >= 10 else str(round(av,3))
361
+ avstr=str(int(av)) if abs(av) >= 100 else str(round(av,2)) if abs(av) >= 10 else str(round(av,3))
362
+ plt.axhline(y=av,ls="dashed",c="blueviolet",linewidth=2,label=text_lang("本期间均值","Periodic mean")+avstr)
348
363
  #footnote=footnote + ",均值"+av
349
- footnote=text_lang("注:期间均值","Note: Periodic mean ")+av+"; "+footnote
364
+ #footnote=text_lang("注:期间均值","Note: Periodic mean ")+av+"; "+footnote
350
365
 
351
366
  #绘制趋势线
352
367
  #print("--Debug(plot_line): power=",power)
@@ -412,7 +427,7 @@ if __name__ =="__main__":
412
427
  twinx=False
413
428
  yline=999
414
429
  xline=999
415
- resample_freq='H'
430
+ resample_freq='D'
416
431
 
417
432
  def plot_line2(df1,ticker1,colname1,label1, \
418
433
  df2,ticker2,colname2,label2, \
@@ -421,7 +436,7 @@ def plot_line2(df1,ticker1,colname1,label1, \
421
436
  zeroline=False,twinx=False, \
422
437
  yline=999,attention_value_area='', \
423
438
  xline=999,attention_point_area='', \
424
- resample_freq='H',loc1='best',loc2='best', \
439
+ resample_freq='D',loc1='best',loc2='best', \
425
440
  color1='red',color2='blue',facecolor='whitesmoke', \
426
441
  maxticks=20):
427
442
  """
@@ -480,7 +495,7 @@ def plot2_line2(df1,ticker1,colname1,label1, \
480
495
  zeroline=False,twinx=False, \
481
496
  yline=999,attention_value_area='', \
482
497
  xline=999,attention_point_area='', \
483
- resample_freq='H',loc1='best',loc2='best', \
498
+ resample_freq='D',loc1='best',loc2='best', \
484
499
  date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
485
500
  color1='red',color2='blue',facecolor='whitesmoke', \
486
501
  maxticks=20):
@@ -547,7 +562,7 @@ def plot_line2_coaxial(df01,ticker1,colname1,label1, \
547
562
  power=0,datatag1=False,datatag2=False,zeroline=False, \
548
563
  yline=999,attention_value_area='', \
549
564
  xline=999,attention_point_area='', \
550
- resample_freq='H', \
565
+ resample_freq='D', \
551
566
  loc1='best',loc2='best', \
552
567
  color1='red',color2='blue',facecolor='whitesmoke', \
553
568
  ticker_type='auto',maxticks=15):
@@ -760,7 +775,10 @@ def plot_line2_coaxial(df01,ticker1,colname1,label1, \
760
775
 
761
776
  # 使用 AutoDateLocator 自动选择最佳间隔,目的是显示最后一个日期,亲测有效!!!
762
777
  import matplotlib.dates as mdates
763
- ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
778
+ try:
779
+ ax.xaxis.set_major_locator(mdates.AutoDateLocator(maxticks=maxticks))
780
+ except:
781
+ pass
764
782
 
765
783
  plt.gcf().autofmt_xdate(ha="center") # 优化标注(自动倾斜)
766
784
  try:
@@ -802,7 +820,7 @@ def plot_line2_coaxial2(df01,ticker1,colname1,label1, \
802
820
  power=0,datatag1=False,datatag2=False,zeroline=False, \
803
821
  yline=999,attention_value_area='', \
804
822
  xline=999,attention_point_area='', \
805
- resample_freq='H', \
823
+ resample_freq='D', \
806
824
  loc1='best',loc2='best', \
807
825
  date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
808
826
  color1='red',color2='blue',facecolor='whitesmoke', \
@@ -1060,7 +1078,7 @@ def plot_line2_coaxial2(df01,ticker1,colname1,label1, \
1060
1078
  def plot_line2_twinx(df01,ticker1,colname1,label1, \
1061
1079
  df02,ticker2,colname2,label2, \
1062
1080
  titletxt,footnote,power=0,datatag1=False,datatag2=False, \
1063
- resample_freq='H', \
1081
+ resample_freq='D', \
1064
1082
  xline=999,attention_point_area='', \
1065
1083
  loc1='upper left',loc2='lower left', \
1066
1084
  color1='red',color2='blue',facecolor='whitesmoke', \
@@ -1289,7 +1307,7 @@ def plot_line2_twinx2(df01,ticker1,colname1,label1, \
1289
1307
  df02,ticker2,colname2,label2, \
1290
1308
  titletxt,footnote,power=0,datatag1=False,datatag2=False, \
1291
1309
  xline=999,attention_point_area='', \
1292
- resample_freq='H',loc1='upper left',loc2='lower left', \
1310
+ resample_freq='D',loc1='upper left',loc2='lower left', \
1293
1311
  date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
1294
1312
  color1='red',color2='blue',facecolor='whitesmoke', \
1295
1313
  ticker_type='auto', \
@@ -1532,7 +1550,7 @@ if __name__ =="__main__":
1532
1550
  axhline_value=0; axhline_label=''
1533
1551
  title_txt='Title'
1534
1552
  data_label=False
1535
- resample_freq='H'; smooth=True
1553
+ resample_freq='D'; smooth=True
1536
1554
  linewidth=1.5
1537
1555
  loc='best'
1538
1556
  annotate=True; annotate_value=True
@@ -1545,12 +1563,12 @@ if __name__ =="__main__":
1545
1563
 
1546
1564
 
1547
1565
  def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1548
- data_label=True,resample_freq='H',smooth=True,linewidth=1.5, \
1566
+ data_label=False,resample_freq='D',smooth=False,linewidth=1.5, \
1549
1567
  band_area='',loc='best', \
1550
1568
  annotate=False,annotate_value=False,plus_sign=False, \
1551
1569
  attention_value='',attention_value_area='', \
1552
1570
  attention_point='',attention_point_area='', \
1553
- mark_top=False,mark_bottom=False,mark_end=False, \
1571
+ mark_start=False,mark_top=False,mark_bottom=False,mark_end=False, \
1554
1572
  ticker_type='auto',facecolor='whitesmoke', \
1555
1573
  maxticks_enable=True,maxticks=15, \
1556
1574
  translate=False):
@@ -1738,6 +1756,19 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1738
1756
  plt.text(x,y1,s % y,ha='right',va='bottom',color=last_line_color)
1739
1757
  plt.scatter(x,y, color='seagreen',marker='8',s=70)
1740
1758
 
1759
+ #标记曲线开始数值
1760
+ if mark_start and (c not in ["平均值","中位数"]):
1761
+ df_end=dfg.head(1)
1762
+ y_end = df_end[c].min() # 开始的y坐标
1763
+ x_end = df_end[c].idxmin() # 开始值的x坐标
1764
+
1765
+ #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
1766
+ y1=str(round(y_end,1)) if abs(y_end) >= 100 else str(round(y_end,2)) if abs(y_end) >= 1 else str(round(y_end,3))
1767
+ plt.annotate(text=' '+y1,
1768
+ xy=(x_end, y_end),
1769
+ xytext=(x_end, y_end*0.998),fontsize=annotate_size,
1770
+ color=last_line_color,ha='right',va='center')
1771
+
1741
1772
  #标记曲线末端数值
1742
1773
  if mark_end and (c not in ["平均值","中位数"]):
1743
1774
  df_end=dfg.tail(1)
@@ -1748,8 +1779,8 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1748
1779
  y1=str(round(y_end,1)) if abs(y_end) >= 100 else str(round(y_end,2)) if abs(y_end) >= 1 else str(round(y_end,3))
1749
1780
  plt.annotate(text=' '+y1,
1750
1781
  xy=(x_end, y_end),
1751
- xytext=(x_end, y_end),fontsize=annotate_size,
1752
- color=last_line_color)
1782
+ xytext=(x_end, y_end*0.998),fontsize=annotate_size,
1783
+ color=last_line_color,ha='left',va='center')
1753
1784
 
1754
1785
  #用于关注值的颜色列表
1755
1786
  atv_color_list=["lightgray","paleturquoise","wheat","khaki","lightsage","hotpink","mediumslateblue"]
@@ -1950,7 +1981,7 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1950
1981
  #指定两个横轴之间的区域
1951
1982
  attention_point_area='', \
1952
1983
  annotate=False,annotate_value=False, \
1953
- mark_top=False,mark_bottom=False,mark_end=False, \
1984
+ mark_start=False,mark_top=False,mark_bottom=False,mark_end=False, \
1954
1985
  facecolor='whitesmoke',maxticks=20,translate=False):
1955
1986
  """
1956
1987
  函数功能:根据df的内容绘制折线图
@@ -1973,6 +2004,7 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1973
2004
  band_area='':默认为空,否则为列表,第1个值为带状区域上边沿字段,第2个值为带状区域下边沿字段
1974
2005
  """
1975
2006
  import pandas as pd
2007
+
1976
2008
  DEBUG=False
1977
2009
  if DEBUG:
1978
2010
  print(f"band_area={band_area}")
@@ -2115,6 +2147,19 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
2115
2147
  xy=(x_end, y_end),
2116
2148
  xytext=(x_end, y_end),fontsize=annotate_size,
2117
2149
  color=last_line_color)
2150
+
2151
+ #标记曲线开始数值
2152
+ if mark_start:
2153
+ df_start=df.head(1)
2154
+ y_start = df_start[c].min() # 开始的y坐标
2155
+ x_start = df_start[c].idxmin() # 开始值的x坐标
2156
+
2157
+ #y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
2158
+ y1=str(round(y_start,1)) if abs(y_start) >= 100 else str(round(y_start,2)) if abs(y_start) >= 1 else str(round(y_start,3))
2159
+ plt.annotate(text=y1,
2160
+ xy=(x_start, y_start),
2161
+ xytext=(x_start, y_start*0.998),fontsize=annotate_size,ha='right',va='center')
2162
+ # 特别注意:这里的left/right与实际图示的方向正好相反!!!
2118
2163
 
2119
2164
  #处理布林带的mark_end,仅标记上中下线
2120
2165
  if mark_end & (c in collist3):
@@ -2395,7 +2440,7 @@ if __name__=='__main__':
2395
2440
  #==============================================================================
2396
2441
  def plot_2lines(df01,colname1,label1, \
2397
2442
  df02,colname2,label2, \
2398
- ylabeltxt,titletxt,footnote,hline=0,vline=0,resample_freq='H', \
2443
+ ylabeltxt,titletxt,footnote,hline=0,vline=0,resample_freq='D', \
2399
2444
  date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
2400
2445
  facecolor='whitesmoke', \
2401
2446
  maxticks=15):
@@ -2584,7 +2629,7 @@ def df_smooth(df):
2584
2629
 
2585
2630
 
2586
2631
  #==============================================================================
2587
- def df_smooth_manual(df,method='linear',resample_freq='H',order=3):
2632
+ def df_smooth_manual(df,method='linear',resample_freq='D',order=3):
2588
2633
  """
2589
2634
  功能:对df中的第一个数值列样本进行插值,以便绘制的折线图相对平滑。
2590
2635
  要求:df的索引为pandas的datetime日期型
siat/valuation_china.py CHANGED
@@ -123,7 +123,13 @@ def get_valuation_market_china(start,end,measure='pe',method='lyr',value='value'
123
123
  mp['Date']=mp['date']
124
124
  mp.sort_values(by=['Date'],ascending=True,inplace=True)
125
125
  mp.set_index(['Date'],inplace=True)
126
- mp1=mp[(mp.index >= startpd) & (mp.index <=endpd)]
126
+
127
+ try:
128
+ mp1=mp[(mp.index >= startpd) & (mp.index <=endpd)]
129
+ except:
130
+ startpd=startpd.date()
131
+ endpd=endpd.date()
132
+ mp1=mp[(mp.index >= startpd) & (mp.index <=endpd)]
127
133
 
128
134
  mp9=mp1[['date',field,'close']]
129
135
  mp9['field']=mp9[field]
@@ -149,7 +155,13 @@ def get_valuation_market_china(start,end,measure='pe',method='lyr',value='value'
149
155
  mp['Date']=mp['date']
150
156
  mp.sort_values(by=['Date'],ascending=True,inplace=True)
151
157
  mp.set_index(['Date'],inplace=True)
152
- mp1=mp[(mp.index >= startpd) & (mp.index <=endpd)]
158
+
159
+ try:
160
+ mp1=mp[(mp.index >= startpd) & (mp.index <=endpd)]
161
+ except:
162
+ startpd=startpd.date()
163
+ endpd=endpd.date()
164
+ mp1=mp[(mp.index >= startpd) & (mp.index <=endpd)]
153
165
 
154
166
  mp9=mp1[['date',field,'close']]
155
167
  mp9['field']=mp9[field]
@@ -170,6 +182,293 @@ if __name__ =="__main__":
170
182
  df=get_valuation_market_china(start,end,measure='pe',method='lyr',value='value',statistic='median')
171
183
 
172
184
  #==============================================================================
185
+ if __name__ =="__main__":
186
+ start='2024-1-1'; end='2025-3-31'
187
+ indicator='pe'
188
+ method='ttm'
189
+ value='value'
190
+ statistic='median'
191
+
192
+ indicator=['pb','pe']
193
+ method=['lyr','ttm']
194
+ value=['value','quantile']
195
+ statistic=['median','equal-weighted']
196
+
197
+ twinx=False; loc1='best'; loc2='best'
198
+ power=0; twinx=False; average_value=True
199
+ annotate=False; annotate_value=False; plus_sign=True
200
+ mark_top=False; mark_bottom=False; mark_end=False
201
+
202
+ loc1='upper left'; loc2='lower right'
203
+ facecolor='whitesmoke'; maxticks=20
204
+
205
+
206
+
207
+ def valuation_china(start='MRY',end='today',indicator='pe', \
208
+ method='lyr',value='value',statistic='median', \
209
+ average_value=False,show_index=False, \
210
+ power=0,twinx=False, \
211
+
212
+ band_area='', \
213
+ attention_value='',attention_value_area='', \
214
+ attention_point='',attention_point_area='', \
215
+
216
+ annotate=False,annotate_value=False,plus_sign=True, \
217
+ mark_start=False,mark_top=False,mark_bottom=False,mark_end=False, \
218
+
219
+ loc1='upper left',loc2='lower right', \
220
+ facecolor='whitesmoke', \
221
+ maxticks=20):
222
+ """
223
+ ===========================================================================
224
+ 功能:比较中国全A股市场的估值指标变化趋势
225
+ start: 开始日期,格式YYYY-MM-DD。
226
+ 或者简写版,例如'MRY'近1年、'L3Y'表示近3年等。
227
+ end: 结束日期,默认今天。
228
+
229
+ indicator: 估值指标市盈率'pe'或市净率'pb',或其组合。不支持股息率
230
+ method: 滚动'ttm或静态取样'lyr',或其组合
231
+ value: 直接采用估值指标数值'value'或分位数'quantile',或其组合
232
+ statistic: 采用中位数'median'或等权均值'equal-weighted',或其组合
233
+ twinx:是否使用双轴绘图法,默认否False。
234
+ 如果同时选择了市盈率'pe'或市净率'pb',建议打开该选项True。
235
+ loc1/loc2:图例1/2的位置,默认自动决定'best'。
236
+ 如果自动位置不理想,可以手动设置位置。
237
+ """
238
+ print(" Working on valuating China stock market ... ...")
239
+
240
+ import pandas as pd
241
+ #处理日期
242
+ start,end=start_end_preprocess(start,end)
243
+
244
+ # 情形1:双indicator:双指标,PE+PB
245
+ if isinstance(indicator,list) and len(indicator) >= 2:
246
+ indicator=indicator[:2]
247
+ if isinstance(method,list): method=method[0]
248
+
249
+ if isinstance(value,list): value=value[0]
250
+ if isinstance(statistic,list): statistic=statistic[0]
251
+
252
+ df=None
253
+ for i in indicator:
254
+ if 'pb' != i.lower():
255
+ dftmp=get_valuation_market_china(start,end,measure=i.lower(), \
256
+ method=method, \
257
+ value=value,statistic=statistic)
258
+ else:
259
+ # pb不支持ttm
260
+ dftmp=get_valuation_market_china(start,end,measure=i.lower(), \
261
+ method='lyr', \
262
+ value=value,statistic=statistic)
263
+
264
+ val_desc=dftmp['desc'].values[0]
265
+ method_desc=dftmp['method'].values[0]
266
+ """
267
+ if method_desc == 'lyr': val_desc=val_desc+'静态'
268
+ elif method_desc == 'ttm':
269
+ #val_desc=val_desc+'动态'
270
+ val_desc=val_desc
271
+ if value == 'value': val_desc=val_desc+'数值'
272
+ elif value == 'quantile': val_desc=val_desc+'分位数'
273
+ """
274
+ dftmp[val_desc]=dftmp['field']
275
+ dftmp2=dftmp[[val_desc]]
276
+
277
+ if df is None:
278
+ df=dftmp2
279
+ else:
280
+ df=pd.merge(df,dftmp2,left_index=True,right_index=True)
281
+
282
+ # 情形2:单indicator+双method:ttm+lyr(仅适用于pe;pb仅适用lyr);
283
+ elif isinstance(method,list) and len(method) >= 2:
284
+ method=method[:2]
285
+ if isinstance(indicator,list): indicator=indicator[0]
286
+
287
+ if isinstance(value,list): value=value[0]
288
+ if isinstance(statistic,list): statistic=statistic[0]
289
+
290
+ df=None
291
+ for i in method:
292
+ if (indicator.lower() == 'pe') or \
293
+ (indicator.lower() == 'pb' and i.lower() == 'lyr'):
294
+ dftmp=get_valuation_market_china(start,end,measure=indicator.lower(), \
295
+ method=i.lower(), \
296
+ value=value,statistic=statistic)
297
+
298
+ val_desc=dftmp['desc'].values[0]
299
+ method_desc=dftmp['method'].values[0]
300
+ """
301
+ if method_desc == 'lyr': val_desc=val_desc+'静态'
302
+ elif method_desc == 'ttm':
303
+ #val_desc=val_desc+'动态'
304
+ val_desc=val_desc
305
+ if value == 'value': val_desc=val_desc+'数值'
306
+ elif value == 'quantile': val_desc=val_desc+'分位数'
307
+ """
308
+ dftmp[val_desc]=dftmp['field']
309
+ dftmp2=dftmp[[val_desc]]
310
+
311
+ if df is None:
312
+ df=dftmp2
313
+ else:
314
+ df=pd.merge(df,dftmp2,left_index=True,right_index=True)
315
+
316
+ # 情形3:单indicator+单method+双value;
317
+ elif isinstance(value,list) and len(value) >= 2:
318
+ value=value[:2]
319
+ if isinstance(indicator,list): indicator=indicator[0]
320
+ if isinstance(method,list): method=method[0]
321
+ if indicator == 'pb': method='lyr'
322
+
323
+ if isinstance(statistic,list): statistic=statistic[0]
324
+
325
+ df=None
326
+ for i in value:
327
+ dftmp=get_valuation_market_china(start,end,measure=indicator.lower(), \
328
+ method=method.lower(), \
329
+ value=i.lower(),statistic=statistic)
330
+
331
+ val_desc=dftmp['desc'].values[0]
332
+ method_desc=dftmp['method'].values[0]
333
+ """
334
+ if method_desc == 'lyr': val_desc=val_desc+'静态'
335
+ elif method_desc == 'ttm':
336
+ #val_desc=val_desc+'动态'
337
+ val_desc=val_desc
338
+ if value == 'value': val_desc=val_desc+'数值'
339
+ elif value == 'quantile': val_desc=val_desc+'分位数'
340
+ """
341
+ dftmp[val_desc]=dftmp['field']
342
+ dftmp2=dftmp[[val_desc]]
343
+
344
+ if df is None:
345
+ df=dftmp2
346
+ else:
347
+ df=pd.merge(df,dftmp2,left_index=True,right_index=True)
348
+
349
+ # 数值与分位数差距较大,使用twinx=True
350
+ twinx=True
351
+
352
+ # 情形4:单indicator+单method+单value+双statistic;
353
+ elif isinstance(statistic,list) and len(statistic) >= 2:
354
+ statistic=statistic[:2]
355
+ if isinstance(indicator,list): indicator=indicator[0]
356
+ if isinstance(method,list): method=method[0]
357
+ if indicator == 'pb': method='lyr'
358
+
359
+ df=None
360
+ for i in statistic:
361
+ dftmp=get_valuation_market_china(start,end,measure=indicator.lower(), \
362
+ method=method.lower(), \
363
+ value=value.lower(),statistic=i.lower())
364
+
365
+ val_desc=dftmp['desc'].values[0]
366
+ method_desc=dftmp['method'].values[0]
367
+ """
368
+ if method_desc == 'lyr': val_desc=val_desc+'静态'
369
+ elif method_desc == 'ttm':
370
+ #val_desc=val_desc+'动态'
371
+ val_desc=val_desc
372
+ if value == 'value': val_desc=val_desc+'数值'
373
+ elif value == 'quantile': val_desc=val_desc+'分位数'
374
+ """
375
+ dftmp[val_desc]=dftmp['field']
376
+ dftmp2=dftmp[[val_desc]]
377
+
378
+ if df is None:
379
+ df=dftmp2
380
+ else:
381
+ df=pd.merge(df,dftmp2,left_index=True,right_index=True)
382
+
383
+ # 情形5:单indicator+单method+单value+单statistic;
384
+ else:
385
+ if isinstance(indicator,list): indicator=indicator[0]
386
+ if isinstance(method,list): method=method[0]
387
+ if indicator == 'pb': method='lyr'
388
+
389
+ if isinstance(value,list): value=value[0]
390
+ if isinstance(statistic,list): statistic=statistic[0]
391
+
392
+ dftmp=get_valuation_market_china(start,end,measure=indicator.lower(), \
393
+ method=method.lower(), \
394
+ value=value.lower(),statistic=statistic.lower())
395
+
396
+ val_desc=dftmp['desc'].values[0]
397
+ method_desc=dftmp['method'].values[0]
398
+ """
399
+ if method_desc == 'lyr': val_desc=val_desc+'静态'
400
+ elif method_desc == 'ttm':
401
+ #val_desc=val_desc+'动态'
402
+ val_desc=val_desc
403
+ if value == 'value': val_desc=val_desc+'数值'
404
+ elif value == 'quantile': val_desc=val_desc+'分位数'
405
+ """
406
+ dftmp[val_desc]=dftmp['field']
407
+ if show_index:
408
+ index_desc=dftmp['index name'].values[0]
409
+ dftmp[index_desc]=dftmp['index']
410
+ df=dftmp[[val_desc,index_desc]]
411
+
412
+ # 指数与指标差异大,设定twinx=True
413
+ twinx=True
414
+ else:
415
+ df=dftmp[[val_desc]]
416
+
417
+ # 绘图
418
+ import datetime; todaydt = datetime.date.today()
419
+ sourcetxt=text_lang("数据来源:legulegu","Data source: legulegu")
420
+ footnote=sourcetxt+', '+str(todaydt)
421
+
422
+ if show_index:
423
+ # 显示股票市场指数
424
+ twinx=True
425
+
426
+ titletxt=text_lang("中国A股市场估值趋势","China A-share Market Valuation")
427
+ ylabeltxt=text_lang("估值指标","Valuation Indicator")
428
+
429
+ if len(list(df)) == 1:
430
+ colname=collabel=list(df)[0]
431
+ #titletxt=titletxt+': '+colname
432
+ ylabeltxt=colname
433
+ plot_line(df,colname,collabel,ylabeltxt,titletxt,footnote, \
434
+ power=power, \
435
+ attention_value=attention_value,attention_value_area=attention_value_area, \
436
+ attention_point=attention_point,attention_point_area=attention_point_area, \
437
+ average_value=average_value, \
438
+
439
+ loc=loc1, \
440
+ mark_start=True,mark_top=True,mark_bottom=True,mark_end=mark_end, \
441
+ facecolor=facecolor,maxticks=maxticks)
442
+
443
+ elif twinx and len(list(df)) >= 2:
444
+ ticker1=ticker2=''
445
+ colname1=label1=list(df)[0]; df1=df[[colname1]]
446
+ colname2=label2=list(df)[1]; df2=df[[colname2]]
447
+
448
+ plot_line2(df1,ticker1,colname1,label1, \
449
+ df2,ticker2,colname2,label2, \
450
+ ylabeltxt,titletxt,footnote, \
451
+ power=power,datatag1=False,datatag2=False,yscalemax=5, \
452
+ zeroline=False,twinx=twinx, \
453
+ yline=999,attention_value_area='', \
454
+ xline=999,attention_point_area='', \
455
+ resample_freq='H',loc1=loc1,loc2=loc2, \
456
+ color1='red',color2='blue',facecolor='whitesmoke', \
457
+ maxticks=maxticks)
458
+ else:
459
+ x_label=footnote
460
+ axhline_value=0; axhline_label=''
461
+ draw_lines(df,ylabeltxt,x_label,axhline_value,axhline_label,titletxt, \
462
+ band_area=band_area,loc=loc1, \
463
+ attention_value=attention_value,attention_value_area=attention_value_area, \
464
+ attention_point=attention_point,attention_point_area=attention_point_area, \
465
+ annotate=annotate,annotate_value=annotate_value,plus_sign=False, \
466
+ mark_top=mark_top,mark_bottom=mark_bottom,mark_end=mark_end, \
467
+ facecolor=facecolor,maxticks_enable=True,maxticks=maxticks)
468
+
469
+ return df
470
+
471
+
173
472
  if __name__ =="__main__":
174
473
  start='2020-1-1'; end='2022-10-9'
175
474
  measures=['pb','pe']; methods='lyr'; values='value'; statistics='median'
@@ -177,20 +476,27 @@ if __name__ =="__main__":
177
476
  measures='pe'; methods=['lyr','ttm']; values='value'; statistics='median'
178
477
 
179
478
 
180
- def valuation_market_china(start,end,measures=['pe','pb'], \
479
+ def valuation_market_china(start='MRY',end='today',measures=['pe','pb'], \
181
480
  methods='lyr',values='value',statistics='median', \
182
481
  twinx=False,loc1='best',loc2='best'):
183
482
  """
483
+ ===========================================================================
184
484
  功能:比较中国全A股市场的估值指标变化趋势
185
- ----------
186
- start: 开始日期
187
- end: 结束日期
485
+ start: 开始日期,格式YYYY-MM-DD。
486
+ 或者简写版,例如'MRY'近1年、'L3Y'表示近3年等。
487
+ end: 结束日期,默认今天。
488
+
188
489
  measures: 估值指标市盈率'pe'或市净率'pb',不支持股息率
189
490
  methods: 滚动'ttm/静态取样'lyr'.
190
491
  values: 直接采用估值指标数值'value'或分位数'quantile'
191
492
  statistics: 采用中位数'median'或等权均值'equal-weighted'
192
-
493
+ twinx:是否使用双轴绘图法,默认否False。
494
+ 如果同时选择了市盈率'pe'或市净率'pb',建议打开该选项True。
495
+ loc1/loc2:图例1/2的位置,默认自动决定'best'。
496
+ 如果自动位置不理想,可以手动设置位置。
193
497
  """
498
+ #处理日期
499
+ start,end=start_end_preprocess(start,end)
194
500
 
195
501
  #解析比较的指标,以第一个双指标为准
196
502
  found2=False
@@ -222,7 +528,7 @@ def valuation_market_china(start,end,measures=['pe','pb'], \
222
528
  found2=True
223
529
 
224
530
  if not found2:
225
- print(" #Warning(valuation_market_china):no comparing parameters from either of",parmlist)
531
+ print(" #Warning(valuation_market_china):parameters mismatch among",parmlist)
226
532
  #return None,None
227
533
  """
228
534
  print("measures1=",measures1,"measures2=",measures2)
@@ -235,16 +541,19 @@ def valuation_market_china(start,end,measures=['pe','pb'], \
235
541
  ylabeltxt='估值比率'
236
542
  else:
237
543
  ylabeltxt='分位数'
544
+
545
+ print(" Working on valuating China stock market ... ...")
546
+
238
547
  titletxt='中国全A股市场估值的变化趋势'
239
548
 
240
549
  import datetime
241
550
  today = datetime.date.today()
242
- footnote="数据来源: 乐咕乐股,"+str(today)
551
+ footnote="数据来源: legulegu,"+str(today)
243
552
 
244
553
  #获取指标1
245
554
  df1=get_valuation_market_china(start,end,measure=measures1,method=methods1,value=values1,statistic=statistics1)
246
555
  if df1 is None:
247
- print(" #Error(valuation_market_china):no data available for the combination of",measures1,methods1,values1,statistics1)
556
+ print(" #Error(valuation_market_china):no data available for the combine of",measures1,methods1,values1,statistics1)
248
557
  return None,None
249
558
 
250
559
  ticker1=df1['desc'].values[0]
@@ -260,7 +569,7 @@ def valuation_market_china(start,end,measures=['pe','pb'], \
260
569
  #获取指标2
261
570
  df2=get_valuation_market_china(start,end,measure=measures2,method=methods2,value=values2,statistic=statistics2)
262
571
  if df2 is None:
263
- print(" #Error(valuation_market_china):no data available for the combination of",measures2,methods2,values2,statistics2)
572
+ print(" #Error(valuation_market_china):data unavailable for the combine of",measures2,methods2,values2,statistics2)
264
573
  return None,None
265
574
 
266
575
  ticker2=df2['desc'].values[0]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: siat
3
- Version: 3.8.27
3
+ Version: 3.8.30
4
4
  Summary: Securities Investment Analysis Tools (siat)
5
5
  Home-page: https://pypi.org/project/siat/
6
6
  Author: Prof. WANG Dehong, International Business School, Beijing Foreign Studies University
@@ -30,7 +30,7 @@ siat/cryptocurrency_test.py,sha256=3AikTNJ7j-HwLGLIYEfyXZ3bLVuLeru9mwiwHQi2SdA,2
30
30
  siat/derivative.py,sha256=qV8n09799eqLc26ojR6vN5n_X-xd7rGwdYjgq-wBih8,41483
31
31
  siat/economy-20230125.py,sha256=vxZZlPnLkh7SpGMVEPLwxjt0yYLSVmdZrO-s2NYLyoM,73848
32
32
  siat/economy.py,sha256=BFVQDxOTbuizyumpCgpZIauH6sqnwUXebpqRMmQCzys,84198
33
- siat/economy2.py,sha256=1wEYdfsgTxTy6FtXXOoCfd4v6xWQYUXLDR7GJSOHwGg,75147
33
+ siat/economy2.py,sha256=tdfbDXfv_rI4FjeQEgMwcKnoGNRL_1U2vkrnAPgRmAs,81019
34
34
  siat/economy_test.py,sha256=6vjNlPz7W125pJb7simCddobSEp3jmLIMvVkLRZ7zW8,13339
35
35
  siat/esg.py,sha256=GMhaonIKtvOK83rhpQUH5aJt2OL3HQBSVfD__Yw-0oo,19040
36
36
  siat/esg_test.py,sha256=Z9m6GUt8O7oHZSEG9aDYpGdvvrv2AiRJdHTiU6jqmZ0,2944
@@ -64,7 +64,7 @@ siat/future_china.py,sha256=F-HsIf2Op8Z22RzTjet1g8COzldgnMjFNSXsAkeGyWo,17595
64
64
  siat/future_china_test.py,sha256=BrSzmDVaOHki6rntOtosmRn-6dkfOBuLulJNqh7MOpc,1163
65
65
  siat/global_index_test.py,sha256=hnFp3wqqzzL-kAP8mgxDZ54Bd5Ijf6ENi5YJlGBgcXw,2402
66
66
  siat/google_authenticator.py,sha256=ZUbZR8OW0IAKDbcYtlqGqIpZdERpFor9NccFELxg9yI,1637
67
- siat/grafix.py,sha256=Qw17Gq2jjh8ftWpAM0TfWP7bojGlS48hMpOUSJar5HM,117447
67
+ siat/grafix.py,sha256=MIaNkxxt_n9zoYafsidPhn9xdX0rwjKHbbsNMhkYj0Q,119901
68
68
  siat/grafix_test.py,sha256=kXvcpLgQNO7wd30g_bWljLj5UH7bIVI0_dUtXbfiKR0,3150
69
69
  siat/holding_risk.py,sha256=uWRtMMJqKr-puQn26g6Fq5N3mFB70c0B99zLQug8hAo,30774
70
70
  siat/holding_risk_test.py,sha256=FRlw_9wFG98BYcg_cSj95HX5WZ1TvkGaOUdXD7-V86s,474
@@ -140,12 +140,12 @@ siat/translate_20240606.py,sha256=63IyHWEU3Uz9mjwyuAX3fqY4nUMdwh0ICQAgmgPXP7Y,21
140
140
  siat/translate_241003_keep.py,sha256=un7Fqe1v35MXsja5exZgjmLzrZtt66NARZIGlyFuGGU,218747
141
141
  siat/universal_test.py,sha256=CDAOffW1Rvs-TcNN5giWVvHMlch1w4dp-w5SIV9jXL0,3936
142
142
  siat/valuation.py,sha256=K7epQC_UtELjRR5cyjJp4gskSyJMxXy-jHIAS0SUEj8,51801
143
- siat/valuation_china.py,sha256=CVp1IwIsF3Om0J29RGkyxZLt4n9Ug-ua_RKhLwL9fUQ,69624
143
+ siat/valuation_china.py,sha256=DURa9uplp7B9tgjWvEQVTRQPqFNpRGWnLdTXQHePrB0,83115
144
144
  siat/valuation_market_china_test.py,sha256=gbJ0ioauuo4koTPH6WKUkqcXiQPafnbhU5eKJ6lpdLA,1571
145
145
  siat/var_model_validation.py,sha256=R0caWnuZarrRg9939hxh3vJIIpIyPfvelYmzFNZtPbo,14910
146
146
  siat/yf_name.py,sha256=laNKMTZ9hdenGX3IZ7G0a2RLBKEWtUQJFY9CWuk_fp8,24058
147
- siat-3.8.27.dist-info/LICENSE,sha256=NTEMMROY9_4U1szoKC3N2BLHcDd_o5uTgqdVH8tbApw,1071
148
- siat-3.8.27.dist-info/METADATA,sha256=3SUzT5YcBbrdG3S5mrpUgvkFvBqEZPm2D8fZp9-i7mU,8321
149
- siat-3.8.27.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
150
- siat-3.8.27.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
151
- siat-3.8.27.dist-info/RECORD,,
147
+ siat-3.8.30.dist-info/LICENSE,sha256=NTEMMROY9_4U1szoKC3N2BLHcDd_o5uTgqdVH8tbApw,1071
148
+ siat-3.8.30.dist-info/METADATA,sha256=VTBGp1ahs79HhChoP4vHnzBxdz2PAELL72yzNp4XYI0,8321
149
+ siat-3.8.30.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
150
+ siat-3.8.30.dist-info/top_level.txt,sha256=r1cVyL7AIKqeAmEJjNR8FMT20OmEzufDstC2gv3NvEY,5
151
+ siat-3.8.30.dist-info/RECORD,,
File without changes
File without changes