siat 2.13.43__py3-none-any.whl → 2.14.2__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/grafix.py CHANGED
@@ -30,10 +30,10 @@ plt.rcParams['xtick.labelsize']=11 #横轴字体大小
30
30
  plt.rcParams['ytick.labelsize']=11 #纵轴字体大小
31
31
 
32
32
  title_txt_size=16
33
- ylabel_txt_size=14
34
- xlabel_txt_size=14
35
- legend_txt_size=14
36
- annotate_size=9
33
+ ylabel_txt_size=12
34
+ xlabel_txt_size=12
35
+ legend_txt_size=12
36
+ annotate_size=11
37
37
 
38
38
  #设置绘图风格:网格虚线
39
39
  plt.rcParams['axes.grid']=False
@@ -67,15 +67,39 @@ if czxt in ['linux']: #website Jupyter
67
67
  # 解决保存图像时'-'显示为方块的问题
68
68
  plt.rcParams['axes.unicode_minus'] = False
69
69
  #==============================================================================
70
+ if __name__ =="__main__":
71
+ df0=get_price('000001.SS','2023-1-1','2024-3-22')
72
+
73
+ colname='Close'
74
+ collabel='Close'
75
+ ylabeltxt='Close'
76
+ titletxt='Title'
77
+ footnote='footnote'
78
+ datatag=False
79
+ power=0
80
+ zeroline=False
81
+ average_value=False
82
+ resample_freq='H'
83
+ loc='best'
84
+ date_range=False
85
+ date_freq=False
86
+ date_fmt='%Y-%m-%d'
87
+ mark_top=1
88
+ mark_bottom=1
89
+
90
+ plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,mark_top=1,mark_bottom=1)
91
+
70
92
  def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
71
93
  power=0,zeroline=False,average_value=False, \
72
94
  resample_freq='H',loc='best', \
73
- date_range=False,date_freq=False,date_fmt='%Y-%m-%d'):
95
+ date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
96
+ mark_top=1,mark_bottom=1,mark_end=True):
74
97
  """
75
98
  功能:绘制折线图。如果power=0不绘制趋势图,否则绘制多项式趋势图
76
99
  假定:数据表有索引,且已经按照索引排序
77
100
  输入:数据表df,数据表中的列名colname,列名的标签collabel;y轴标签ylabeltxt;
78
101
  标题titletxt,脚注footnote;是否在图中标记数据datatag;趋势图的多项式次数power
102
+ mark_top,mark_bottom:标记最高最低点的个数
79
103
  输出:折线图
80
104
  返回值:无
81
105
  注意:需要日期类型作为df索引
@@ -118,9 +142,10 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
118
142
  collabel=''
119
143
  if ylabeltxt == "stooq_MB":
120
144
  ylabeltxt=''
121
-
145
+
146
+ lwadjust=linewidth_adjust(df)
122
147
  plt.plot(df.index,df[colname],'-',label=collabel, \
123
- linestyle='-',color='blue', linewidth=2)
148
+ linestyle='-',color='blue', linewidth=lwadjust)
124
149
 
125
150
  haveLegend=True
126
151
  if collabel == '':
@@ -129,22 +154,46 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
129
154
  #绘制数据标签
130
155
  if datatag:
131
156
  for x, y in zip(df.index, df[colname]):
132
- plt.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='black')
157
+ plt.text(x,y*1.001,'%.2f' % y,ha='center',va='bottom',color='black')
158
+
159
+ #标记最高点/最低点
160
+ if mark_top > 0 or mark_bottom > 0:
161
+ df_mark=df[[colname]].copy() #避免影响原df
162
+ df_mark.sort_values(by=colname,ascending=False,inplace=True)
163
+
164
+ high_poit=df_mark[colname].head(1).values[0]
165
+ low_poit=df_mark[colname].tail(1).values[0]
166
+ high_low=high_poit - low_poit
167
+ if mark_top > 0:
168
+ df_mark_top=df_mark[:mark_top]
169
+ for x, y in zip(df_mark_top.index, df_mark_top[colname]):
170
+ #plt.text(x,y+0.1,'%.2f' % y,ha='center',va='bottom',color='red')
171
+ y1=round(y+high_low*0.01,2)
172
+ s='%.0f' if y >= 100 else '%.2f'
173
+ plt.text(x,y1,s % y,ha='center',va='bottom',color='red')
174
+ plt.scatter(x,y, color='red',marker='8',s=70)
175
+
176
+ if mark_bottom > 0:
177
+ df_mark_bottom=df_mark[-mark_bottom:]
178
+ for x, y in zip(df_mark_bottom.index, df_mark_bottom[colname]):
179
+ #plt.text(x,y-0.1,'%.2f' % y,ha='center',va='bottom',color='black')
180
+ y1=round(y-high_low*0.055,2) #标记位置对应y1的底部
181
+ s='%.0f' if y >= 100 else '%.2f'
182
+ plt.text(x,y1,s % y,ha='center',va='bottom',color='seagreen')
183
+ plt.scatter(x,y, color='seagreen',marker='8',s=70)
184
+
185
+ #标记曲线末端数值
186
+ if mark_end:
187
+ df_end=df.tail(1)
188
+ y_end = df_end[colname].min() # 末端的y坐标
189
+ x_end = df_end[colname].idxmin() # 末端值的x坐标
190
+
191
+ y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
192
+ plt.annotate(text=' '+y1,
193
+ xy=(x_end, y_end),
194
+ xytext=(x_end, y_end),fontsize=annotate_size)
133
195
 
134
196
  #是否绘制水平线
135
- #if zeroline and (min(df[colname]) < 0):
136
- """
137
- if zeroline:
138
- if isinstance(zeroline,bool):
139
- hline=0
140
- elif isinstance(zeroline,float):
141
- hline=zeroline
142
- elif isinstance(zeroline,int):
143
- hline=zeroline
144
- else:
145
- hline=0
146
- plt.axhline(y=hline,ls=":",c="black",linewidth=2)
147
- """
148
197
  if isinstance(zeroline,bool):#若zeroline为True
149
198
  if zeroline:
150
199
  hline=0
@@ -161,7 +210,9 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
161
210
  av=df[colname].mean()
162
211
  plt.axhline(y=av,ls="dashed",c="blueviolet",linewidth=2,label="均值")
163
212
  haveLegend=True
164
- footnote=footnote + ",均值"+str(round(av,2))
213
+ av=str(round(av,2)) if av < 100 else str(int(av))
214
+ #footnote=footnote + ",均值"+av
215
+ footnote="注:期间均值"+av+";"+footnote
165
216
 
166
217
  #绘制趋势线
167
218
  #print("--Debug(plot_line): power=",power)
@@ -171,7 +222,6 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
171
222
  #trend_txt=''
172
223
  if lang == 'English':
173
224
  trend_txt='Trend line'
174
-
175
225
  try:
176
226
  #生成行号,借此将横轴的日期数量化,以便拟合
177
227
  df['id']=range(len(df))
@@ -194,7 +244,6 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
194
244
  plt.ylabel(ylabeltxt,fontsize=ylabel_txt_size)
195
245
  plt.xlabel(footnote,fontsize=xlabel_txt_size)
196
246
  plt.title(titletxt,fontweight='bold',fontsize=title_txt_size)
197
-
198
247
 
199
248
  plt.show()
200
249
  plt.close()
@@ -355,8 +404,9 @@ def plot_line2_coaxial(df01,ticker1,colname1,label1, \
355
404
  else:
356
405
  label1txt=codetranslate(ticker1)+'('+label1+')'
357
406
 
407
+ lwadjust=linewidth_adjust(df1)
358
408
  plt.plot(df1.index,df1[colname1],'-',label=label1txt, \
359
- linestyle='-',linewidth=2.5,color=color1)
409
+ linestyle='-',linewidth=lwadjust,color=color1)
360
410
  #证券1:绘制数据标签
361
411
  if datatag1:
362
412
  for x, y in zip(df1.index, df1[colname1]):
@@ -408,8 +458,9 @@ def plot_line2_coaxial(df01,ticker1,colname1,label1, \
408
458
  else:
409
459
  label2txt=codetranslate(ticker2)+'('+label2+')'
410
460
 
461
+ lwadjust=linewidth_adjust(df2)
411
462
  plt.plot(df2.index,df2[colname2],'-',label=label2txt, \
412
- linestyle='-.',linewidth=2.5,color=color2)
463
+ linestyle='-.',linewidth=lwadjust,color=color2)
413
464
  #证券2:绘制数据标签
414
465
  if datatag2:
415
466
  for x, y in zip(df2.index, df2[colname2]):
@@ -526,8 +577,9 @@ def plot_line2_coaxial2(df01,ticker1,colname1,label1, \
526
577
  ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
527
578
  plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
528
579
 
580
+ lwadjust=linewidth_adjust(df1)
529
581
  plt.plot(df1.index,df1[colname1],'-',label=label1txt, \
530
- linestyle='-',linewidth=2.5,color=color1)
582
+ linestyle='-',linewidth=lwadjust,color=color1)
531
583
  #证券1:绘制数据标签
532
584
  if datatag1:
533
585
  for x, y in zip(df1.index, df1[colname1]):
@@ -589,8 +641,9 @@ def plot_line2_coaxial2(df01,ticker1,colname1,label1, \
589
641
  ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
590
642
  plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
591
643
 
644
+ lwadjust=linewidth_adjust(df2)
592
645
  plt.plot(df2.index,df2[colname2],'-',label=label2txt, \
593
- linestyle='-.',linewidth=2.5,color=color2)
646
+ linestyle='-.',linewidth=lwadjust,color=color2)
594
647
  #证券2:绘制数据标签
595
648
  if datatag2:
596
649
  for x, y in zip(df2.index, df2[colname2]):
@@ -673,10 +726,11 @@ def plot_line2_twinx(df01,ticker1,colname1,label1, \
673
726
  if label1 == '':
674
727
  label1txt=codetranslate(ticker1)
675
728
  else:
676
- label1txt=codetranslate(ticker1)+'('+label1+')'
677
-
729
+ label1txt=codetranslate(ticker1)+'('+label1+')'
730
+
731
+ lwadjust=linewidth_adjust(df1)
678
732
  ax.plot(df1.index,df1[colname1],'-',label=label1txt, \
679
- linestyle='-',color=color1,linewidth=2)
733
+ linestyle='-',color=color1,linewidth=lwadjust)
680
734
  #证券1:绘制数据标签
681
735
  if datatag1:
682
736
  for x, y in zip(df1.index, df1[colname1]):
@@ -712,10 +766,11 @@ def plot_line2_twinx(df01,ticker1,colname1,label1, \
712
766
  if label2 == '':
713
767
  label2txt=codetranslate(ticker2)
714
768
  else:
715
- label2txt=codetranslate(ticker2)+'('+label2+')'
716
-
769
+ label2txt=codetranslate(ticker2)+'('+label2+')'
770
+
771
+ lwadjust=linewidth_adjust(df2)
717
772
  ax2.plot(df2.index,df2[colname2],'-',label=label2txt, \
718
- linestyle='-.',color=color2,linewidth=2.5)
773
+ linestyle='-.',color=color2,linewidth=lwadjust)
719
774
  #证券2:绘制数据标签
720
775
  if datatag2:
721
776
  for x, y in zip(df2.index, df2[colname2]):
@@ -844,9 +899,10 @@ def plot_line2_twinx2(df01,ticker1,colname1,label1, \
844
899
  if date_range and date_freq:
845
900
  ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
846
901
  plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
847
-
902
+
903
+ lwadjust=linewidth_adjust(df1)
848
904
  ax.plot(df1.index,df1[colname1],'-',label=label1txt, \
849
- linestyle='-',color=color1,linewidth=2)
905
+ linestyle='-',color=color1,linewidth=lwadjust)
850
906
  #证券1:绘制数据标签
851
907
  if datatag1:
852
908
  for x, y in zip(df1.index, df1[colname1]):
@@ -895,9 +951,10 @@ def plot_line2_twinx2(df01,ticker1,colname1,label1, \
895
951
  if date_range and date_freq:
896
952
  ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
897
953
  plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
898
-
954
+
955
+ lwadjust=linewidth_adjust(df2)
899
956
  ax2.plot(df2.index,df2[colname2],'-',label=label2txt, \
900
- linestyle='-.',color=color2,linewidth=2.5)
957
+ linestyle='-.',color=color2,linewidth=lwadjust)
901
958
  #证券2:绘制数据标签
902
959
  if datatag2:
903
960
  for x, y in zip(df2.index, df2[colname2]):
@@ -922,6 +979,7 @@ def plot_line2_twinx2(df01,ticker1,colname1,label1, \
922
979
  label2txt=''
923
980
  else:
924
981
  label2txt=codetranslate(ticker2)+"("+trend_txt+")"
982
+
925
983
  ax2.plot(df2.index, f(df2.id),"c--", label=label2txt,linewidth=1)
926
984
 
927
985
  ax.set_xlabel(footnote,fontsize=xlabel_txt_size)
@@ -959,7 +1017,8 @@ def plot_line2_twinx2(df01,ticker1,colname1,label1, \
959
1017
  #==============================================================================
960
1018
  def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
961
1019
  data_label=True,resample_freq='H',smooth=True,linewidth=1.5, \
962
- loc='best',annotate=False,annotate_value=False,plus_sign=False):
1020
+ loc='best',annotate=False,annotate_value=False,plus_sign=False, \
1021
+ mark_top=0,mark_bottom=0,mark_end=False):
963
1022
  """
964
1023
  函数功能:根据df的内容绘制折线图
965
1024
  输入参数:
@@ -1003,21 +1062,14 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1003
1062
 
1004
1063
  # 所有字段转换为数值类型,以防万一
1005
1064
  for c in collist:
1006
- df[c]=df[c].astype('float')
1065
+ try:
1066
+ df[c]=df[c].astype('float')
1067
+ except:
1068
+ del df[c]
1007
1069
 
1008
- """
1009
- # 计算所有列中的最大最小差距
1010
- dfmax=0; dfmin=0
1011
- for c in collist:
1012
- cmax=df[c].max()
1013
- if cmax > dfmax:
1014
- dfmax=cmax
1015
-
1016
- cmin=df[c].min()
1017
- if cmin < dfmin:
1018
- dfmin=cmin
1019
- dfspread=(dfmax - dfmin)/10.0
1020
- """
1070
+ # 计算所有列中的最大最小差距,所有列必须为数值型!
1071
+ dfmax=df.max().max(); dfmin=df.min().min()
1072
+ high_low=dfmax - dfmin
1021
1073
 
1022
1074
  # 将末端值最大的排在第一列,优先绘图
1023
1075
  dftt=df.T
@@ -1052,6 +1104,7 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1052
1104
  continue
1053
1105
 
1054
1106
  #plt.plot(dfg,label=c,linewidth=linewidth,ls=lsc,marker=mkc,markersize=3)
1107
+ lwadjust=linewidth_adjust(dfg)
1055
1108
  if not annotate:
1056
1109
  """
1057
1110
  注意:许多传入的df字段名已经不是证券代码,此处调用codetranslate将会导致
@@ -1060,36 +1113,20 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1060
1113
  本函数仅负责绘图,不负责翻译证券名称。
1061
1114
  """
1062
1115
  #plt.plot(dfg,label=codetranslate(c),linewidth=linewidth,ls=lsc,marker=mkc,markersize=3)
1063
- plt.plot(dfg,label=c,linewidth=linewidth,ls=lsc,marker=mkc,markersize=3)
1116
+ plt.plot(dfg,label=c,linewidth=lwadjust,ls=lsc,marker=mkc,markersize=3)
1064
1117
  else:
1065
1118
  #plt.plot(dfg[c],label=codetranslate(c),linewidth=linewidth,ls=lsc,marker=mkc,markersize=3)
1066
1119
  #plt.plot(dfg,label=codetranslate(c),linewidth=linewidth,ls=lsc,marker=mkc,markersize=3)
1067
- plt.plot(dfg,label=c,linewidth=linewidth,ls=lsc,marker=mkc,markersize=3)
1120
+ plt.plot(dfg,label=c,linewidth=lwadjust,ls=lsc,marker=mkc,markersize=3)
1068
1121
 
1069
1122
  df_end=dfg.tail(1)
1070
1123
  # df_end[c]必须为数值类型,否则可能出错
1071
1124
  y_end = df_end[c].min() # 末端的y坐标
1072
1125
  x_end = df_end[c].idxmin() # 末端值的x坐标
1073
1126
 
1074
- """
1075
- if firstline:
1076
- # 直接绘图
1077
- firstline=False
1078
- y_prev=y_end
1079
- else:
1080
- distance=y_prev - y_end
1081
- if distance < dfspread:
1082
- y_end=y_end - dfspread
1083
- y_prev=y_end
1084
- y_end_list=y_end_list+[y_end]
1085
- """
1086
- """
1087
- plt.annotate(text=codetranslate(c)+':'+str(round(y_end,2)),
1088
- xy=(x_end, y_end),
1089
- xytext=(x_end, y_end),fontsize=9)
1090
- """
1091
1127
  if annotate_value: #在标记曲线名称的同时标记其末端数值
1092
- plt.annotate(text=c+':'+str(round(y_end,2)),
1128
+ y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
1129
+ plt.annotate(text=c+':'+y1,
1093
1130
  xy=(x_end, y_end),
1094
1131
  xytext=(x_end, y_end),fontsize=annotate_size)
1095
1132
  else:
@@ -1101,10 +1138,44 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1101
1138
  #plt.plot(df[c],label=c,linewidth=1.5,marker=mkc,markersize=3)
1102
1139
  #为折线加数据标签
1103
1140
  if data_label==True:
1104
- for a,b in zip(df2.index,df2[c]):
1141
+ for a,b in zip(dfg.index,df2[c]):
1105
1142
  plt.text(a,b+0.02,str(round(b,2)), \
1106
1143
  ha='center',va='bottom',fontsize=7)
1107
-
1144
+
1145
+ #标记最高点/最低点
1146
+ if mark_top > 0 or mark_bottom > 0:
1147
+ df_mark=dfg[[c]].copy() #避免影响原df
1148
+ df_mark.dropna(inplace=True)
1149
+ df_mark.sort_values(by=c,ascending=False,inplace=True)
1150
+
1151
+ if mark_top > 0:
1152
+ df_mark_top=df_mark[:mark_top]
1153
+ for x, y in zip(df_mark_top.index, df_mark_top[c]):
1154
+ y1=round(y+high_low*0.01,2)
1155
+ s='%.0f' if y >= 100 else '%.2f'
1156
+ plt.text(x,y1,s % y,ha='center',va='bottom',color='red')
1157
+ plt.scatter(x,y, color='red',marker='8',s=70)
1158
+
1159
+ if mark_bottom > 0:
1160
+ df_mark_bottom=df_mark[-mark_bottom:]
1161
+ for x, y in zip(df_mark_bottom.index, df_mark_bottom[c]):
1162
+ y1=round(y-high_low*0.055,2) #标记位置对应y1的底部
1163
+ s='%.0f' if y >= 100 else '%.2f'
1164
+ plt.text(x,y1,s % y,ha='center',va='bottom',color='seagreen')
1165
+ plt.scatter(x,y, color='seagreen',marker='8',s=70)
1166
+
1167
+ #标记曲线末端数值
1168
+ if mark_end:
1169
+ df_end=dfg.tail(1)
1170
+ y_end = df_end[c].min() # 末端的y坐标
1171
+ x_end = df_end[c].idxmin() # 末端值的x坐标
1172
+
1173
+ y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
1174
+ plt.annotate(text=' '+y1,
1175
+ xy=(x_end, y_end),
1176
+ xytext=(x_end, y_end),fontsize=annotate_size)
1177
+
1178
+
1108
1179
  #绘制水平辅助线
1109
1180
  if axhline_label !="":
1110
1181
  if '零线' in axhline_label:
@@ -1148,7 +1219,8 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1148
1219
  data_label=False,resample_freq='6H',smooth=True, \
1149
1220
  date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
1150
1221
  colorlist=[],lslist=[],lwlist=[], \
1151
- band_area='',loc='best',annotate=False,annotate_value=False):
1222
+ band_area='',loc='best',annotate=False,annotate_value=False, \
1223
+ mark_top=0,mark_bottom=0,mark_end=False):
1152
1224
  """
1153
1225
  函数功能:根据df的内容绘制折线图
1154
1226
  输入参数:
@@ -1184,6 +1256,17 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1184
1256
  else:
1185
1257
  df=df0
1186
1258
 
1259
+ # 所有字段转换为数值类型,以防万一
1260
+ for c in list(df):
1261
+ try:
1262
+ df[c]=df[c].astype('float')
1263
+ except:
1264
+ del df[c]
1265
+
1266
+ # 计算所有列中的最大最小差距,假设所有列均为数值型!
1267
+ dfmax=df.max().max(); dfmin=df.min().min()
1268
+ high_low=dfmax - dfmin
1269
+
1187
1270
  #定义横轴标签:显示完整开始、结束日期
1188
1271
  import matplotlib.dates as mdate
1189
1272
  ax=plt.gca()
@@ -1201,6 +1284,7 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1201
1284
 
1202
1285
  #取得df字段名列表
1203
1286
  collist=df.columns.values.tolist()
1287
+ collist3=collist[:3] #专用于绘制布林带,取前3个字段
1204
1288
 
1205
1289
  #绘制折线图
1206
1290
  for c in collist:
@@ -1210,7 +1294,8 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1210
1294
  lls=lslist[pos]
1211
1295
  llw=lwlist[pos]
1212
1296
  except:
1213
- plt.plot(df[c],label=c,linewidth=2)
1297
+ lwadjust=linewidth_adjust(df)
1298
+ plt.plot(df[c],label=c,linewidth=lwadjust)
1214
1299
  else:
1215
1300
  plt.plot(df[c],label=c,linewidth=llw,ls=lls,color=lcolor)
1216
1301
 
@@ -1219,23 +1304,56 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1219
1304
  for a,b in zip(df.index,df[c]):
1220
1305
  plt.text(a,b+0.02,str(round(b,2)), \
1221
1306
  ha='center',va='bottom',fontsize=7)
1222
-
1223
- #曲线末端标记
1307
+
1308
+ #标记最高点/最低点
1309
+ if mark_top > 0 or mark_bottom > 0:
1310
+ df_mark=df[[c]].copy() #避免影响原df
1311
+ df_mark.dropna(inplace=True)
1312
+ df_mark.sort_values(by=c,ascending=False,inplace=True)
1313
+
1314
+ if mark_top > 0:
1315
+ df_mark_top=df_mark[:mark_top]
1316
+ for x, y in zip(df_mark_top.index, df_mark_top[c]):
1317
+ y1=round(y+high_low*0.01,2)
1318
+ s='%.0f' if y >= 100 else '%.2f'
1319
+ plt.text(x,y1,s % y,ha='center',va='bottom',color='red')
1320
+ plt.scatter(x,y, color='red',marker='8',s=70)
1321
+
1322
+ if mark_bottom > 0:
1323
+ df_mark_bottom=df_mark[-mark_bottom:]
1324
+ for x, y in zip(df_mark_bottom.index, df_mark_bottom[c]):
1325
+ y1=round(y-high_low*0.055,2) #标记位置对应y1的底部
1326
+ s='%.0f' if y >= 100 else '%.2f'
1327
+ plt.text(x,y1,s % y,ha='center',va='bottom',color='seagreen')
1328
+ plt.scatter(x,y, color='seagreen',marker='8',s=70)
1329
+
1330
+ #曲线末端标记:不建议用于布林带
1224
1331
  if annotate:
1225
1332
  df_end=df.tail(1)
1226
1333
  y_end = df_end[c].min() # 末端的y坐标
1227
1334
  x_end = df_end[c].idxmin() # 末端值的x坐标
1228
1335
 
1229
1336
  if annotate_value: #在标记曲线名称的同时标记其末端数值
1230
- plt.annotate(text=c+':'+str(round(y_end,2)),
1337
+ y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
1338
+ plt.annotate(text=c+':'+y1,
1231
1339
  xy=(x_end, y_end),
1232
1340
  xytext=(x_end, y_end),fontsize=annotate_size)
1233
1341
  else:
1234
1342
  plt.annotate(text=c,
1235
1343
  xy=(x_end, y_end),
1236
1344
  xytext=(x_end, y_end),fontsize=annotate_size)
1237
-
1238
1345
 
1346
+ #处理布林带的mark_end,仅标记上中下线
1347
+ if mark_end & (c in collist3):
1348
+ df_end=df.tail(1)
1349
+ y_end = df_end[c].min() # 末端的y坐标
1350
+ x_end = df_end[c].idxmin() # 末端值的x坐标
1351
+
1352
+ y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
1353
+ plt.annotate(text=y1,
1354
+ xy=(x_end, y_end),
1355
+ xytext=(x_end, y_end),fontsize=annotate_size)
1356
+
1239
1357
  #绘制带状区域
1240
1358
  if band_area != '' and isinstance(band_area,list) and len(band_area)>=2:
1241
1359
  plt.fill_between(df.index,df[band_area[0]],df[band_area[1]],alpha=0.5,label='')
@@ -1445,7 +1563,8 @@ def plot_2lines(df01,colname1,label1, \
1445
1563
  ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
1446
1564
  plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
1447
1565
 
1448
- plt.plot(df1.index,df1[colname1],label=label1,linestyle='-',linewidth=2)
1566
+ lwadjust=linewidth_adjust(df1)
1567
+ plt.plot(df1.index,df1[colname1],label=label1,linestyle='-',linewidth=lwadjust)
1449
1568
 
1450
1569
  #证券2:先绘制折线图
1451
1570
  date_start=df2.index[0]
@@ -1462,8 +1581,9 @@ def plot_2lines(df01,colname1,label1, \
1462
1581
  ax=plt.gca()
1463
1582
  ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
1464
1583
  plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
1465
-
1466
- plt.plot(df2.index,df2[colname2],label=label2,linestyle='-.',linewidth=2.5)
1584
+
1585
+ lwadjust=linewidth_adjust(df2)
1586
+ plt.plot(df2.index,df2[colname2],label=label2,linestyle='-.',linewidth=lwadjust)
1467
1587
 
1468
1588
  #是否绘制水平虚线
1469
1589
  if not (hline == 0):
@@ -1535,7 +1655,7 @@ def df_smooth(df):
1535
1655
  #print(' #Warning(df_smooth): resampling failed for frequency',freqlist)
1536
1656
  dfh=df
1537
1657
 
1538
- #插值
1658
+ #重采样后插值
1539
1659
  methodlist=['pchip','nearest','cubic','quadratic','slinear','linear','zero','time','index', \
1540
1660
  'piecewise_polynomial','akima','from_derivatives','spline','polynomial']
1541
1661
  methodlist_order=['spline','polynomial']
@@ -1562,19 +1682,19 @@ def df_smooth(df):
1562
1682
 
1563
1683
 
1564
1684
  #==============================================================================
1565
- def df_smooth_manual(df,method='pchip',resample_freq='H',order=3):
1685
+ def df_smooth_manual(df,method='linear',resample_freq='H',order=3):
1566
1686
  """
1567
1687
  功能:对df中的第一个数值列样本进行插值,以便绘制的折线图相对平滑。
1568
1688
  要求:df的索引为pandas的datetime日期型
1569
1689
  注意1:如果样本数量较多,例如多于100个,平滑效果不明显。
1570
1690
  注意2:order阶数仅对'spline'和'polynomial'方法有效,其中'polynomial'方法的阶数只能为奇数。
1571
- 注意3:pchip方法经常失败,改为cubic
1691
+ 注意3:pchip方法经常失败,可改为cubic
1572
1692
  """
1573
1693
 
1574
1694
  #如果样本个数多于100个,没必要进行平滑,完全看不出效果
1575
1695
  if len(df) >= 100: return df
1576
1696
 
1577
- #检查平滑方法是否支持
1697
+ #检查插值方法是否支持
1578
1698
  methodlist=['quadratic','cubic','slinear','linear','zero','nearest','time','index', \
1579
1699
  'piecewise_polynomial','pchip','akima','from_derivatives','spline','polynomial']
1580
1700
  if not (method in methodlist): return df
@@ -1599,13 +1719,14 @@ def df_smooth_manual(df,method='pchip',resample_freq='H',order=3):
1599
1719
  return df
1600
1720
  df.set_index('date',inplace=True)
1601
1721
 
1722
+ #重新采样
1602
1723
  try:
1603
1724
  dfh=df.resample(resample_freq)
1604
1725
  except:
1605
1726
  print(' #Warning(df_smooth): resampling failed for frequency',resample_freq)
1606
1727
  return df
1607
1728
 
1608
- #重新采样
1729
+ #重采样后插值(不然太多nan):是否methodlist_o里面的特别插值方法
1609
1730
  methodlist_o=['spline','polynomial']
1610
1731
  if method in methodlist_o:
1611
1732
  try:
@@ -1617,6 +1738,7 @@ def df_smooth_manual(df,method='pchip',resample_freq='H',order=3):
1617
1738
  #成功返回经过重采样的df
1618
1739
  return dfm
1619
1740
 
1741
+ #重采样后插值:其他插值方法
1620
1742
  try:
1621
1743
  dfm=dfh.interpolate(method=method)
1622
1744
  except:
@@ -339,7 +339,7 @@ if __name__=='__main__':
339
339
  graph=True
340
340
 
341
341
  def rar_ratio_rolling(portfolio,start,end,ratio_name='treynor',RF=True, \
342
- window=30,graph=True,source='auto'):
342
+ window=21,graph=True,source='auto'):
343
343
  """
344
344
  功能:滚动计算一个投资组合的风险调整后的收益率指数
345
345
  投资组合的结构:{'Market':('US','^GSPC'),'AAPL':0.5,'MSFT':0.3,'IBM':0.2}
@@ -1194,13 +1194,13 @@ if __name__=='__main__':
1194
1194
  trailing=20
1195
1195
 
1196
1196
  def compare_mrar(tickers,rar_name,start,end, \
1197
- market="China",market_index="000300.SS",RF=False,window=60, \
1197
+ market="China",market_index="000300.SS",RF=False,window=63, \
1198
1198
  axhline_value=0,axhline_label='零线',graph=True,printout=True, \
1199
1199
  sortby='tpw_mean',source='auto',trailing=20,trend_threshhold=0.001, \
1200
1200
  annotate=False):
1201
1201
  """
1202
- 功能:计算多只股票的rar比率,并绘图对比
1203
- 比率:支持夏普比率、特雷诺比率、索替诺比率、阿尔法比率等
1202
+ 功能:计算多只股票的rar比率,并绘图对比。多只股票必须处于同一个经济体的证券市场
1203
+ 比率:支持夏普比率、特雷诺比率、索替诺比率、阿尔法比率
1204
1204
 
1205
1205
  sortby:
1206
1206
  tpw_mean(近期优先加权平均值降序排列)
@@ -1364,7 +1364,7 @@ if __name__=='__main__':
1364
1364
  trailing=20
1365
1365
 
1366
1366
  def compare_1security_mrar(ticker,rar_names,start,end, \
1367
- market="China",market_index="000300.SS",RF=False,window=60, \
1367
+ market="China",market_index="000300.SS",RF=False,window=63, \
1368
1368
  axhline_value=0,axhline_label='零线',graph=True,printout=False, \
1369
1369
  sortby='tpw_mean',source='auto',trailing=20,trend_threshhold=0.001, \
1370
1370
  annotate=False):