siat 2.13.43__py3-none-any.whl → 2.14.1__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=0,mark_bottom=0,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
@@ -171,7 +220,6 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
171
220
  #trend_txt=''
172
221
  if lang == 'English':
173
222
  trend_txt='Trend line'
174
-
175
223
  try:
176
224
  #生成行号,借此将横轴的日期数量化,以便拟合
177
225
  df['id']=range(len(df))
@@ -194,7 +242,6 @@ def plot_line(df0,colname,collabel,ylabeltxt,titletxt,footnote,datatag=False, \
194
242
  plt.ylabel(ylabeltxt,fontsize=ylabel_txt_size)
195
243
  plt.xlabel(footnote,fontsize=xlabel_txt_size)
196
244
  plt.title(titletxt,fontweight='bold',fontsize=title_txt_size)
197
-
198
245
 
199
246
  plt.show()
200
247
  plt.close()
@@ -355,8 +402,9 @@ def plot_line2_coaxial(df01,ticker1,colname1,label1, \
355
402
  else:
356
403
  label1txt=codetranslate(ticker1)+'('+label1+')'
357
404
 
405
+ lwadjust=linewidth_adjust(df1)
358
406
  plt.plot(df1.index,df1[colname1],'-',label=label1txt, \
359
- linestyle='-',linewidth=2.5,color=color1)
407
+ linestyle='-',linewidth=lwadjust,color=color1)
360
408
  #证券1:绘制数据标签
361
409
  if datatag1:
362
410
  for x, y in zip(df1.index, df1[colname1]):
@@ -408,8 +456,9 @@ def plot_line2_coaxial(df01,ticker1,colname1,label1, \
408
456
  else:
409
457
  label2txt=codetranslate(ticker2)+'('+label2+')'
410
458
 
459
+ lwadjust=linewidth_adjust(df2)
411
460
  plt.plot(df2.index,df2[colname2],'-',label=label2txt, \
412
- linestyle='-.',linewidth=2.5,color=color2)
461
+ linestyle='-.',linewidth=lwadjust,color=color2)
413
462
  #证券2:绘制数据标签
414
463
  if datatag2:
415
464
  for x, y in zip(df2.index, df2[colname2]):
@@ -526,8 +575,9 @@ def plot_line2_coaxial2(df01,ticker1,colname1,label1, \
526
575
  ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
527
576
  plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
528
577
 
578
+ lwadjust=linewidth_adjust(df1)
529
579
  plt.plot(df1.index,df1[colname1],'-',label=label1txt, \
530
- linestyle='-',linewidth=2.5,color=color1)
580
+ linestyle='-',linewidth=lwadjust,color=color1)
531
581
  #证券1:绘制数据标签
532
582
  if datatag1:
533
583
  for x, y in zip(df1.index, df1[colname1]):
@@ -589,8 +639,9 @@ def plot_line2_coaxial2(df01,ticker1,colname1,label1, \
589
639
  ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
590
640
  plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
591
641
 
642
+ lwadjust=linewidth_adjust(df2)
592
643
  plt.plot(df2.index,df2[colname2],'-',label=label2txt, \
593
- linestyle='-.',linewidth=2.5,color=color2)
644
+ linestyle='-.',linewidth=lwadjust,color=color2)
594
645
  #证券2:绘制数据标签
595
646
  if datatag2:
596
647
  for x, y in zip(df2.index, df2[colname2]):
@@ -673,10 +724,11 @@ def plot_line2_twinx(df01,ticker1,colname1,label1, \
673
724
  if label1 == '':
674
725
  label1txt=codetranslate(ticker1)
675
726
  else:
676
- label1txt=codetranslate(ticker1)+'('+label1+')'
677
-
727
+ label1txt=codetranslate(ticker1)+'('+label1+')'
728
+
729
+ lwadjust=linewidth_adjust(df1)
678
730
  ax.plot(df1.index,df1[colname1],'-',label=label1txt, \
679
- linestyle='-',color=color1,linewidth=2)
731
+ linestyle='-',color=color1,linewidth=lwadjust)
680
732
  #证券1:绘制数据标签
681
733
  if datatag1:
682
734
  for x, y in zip(df1.index, df1[colname1]):
@@ -712,10 +764,11 @@ def plot_line2_twinx(df01,ticker1,colname1,label1, \
712
764
  if label2 == '':
713
765
  label2txt=codetranslate(ticker2)
714
766
  else:
715
- label2txt=codetranslate(ticker2)+'('+label2+')'
716
-
767
+ label2txt=codetranslate(ticker2)+'('+label2+')'
768
+
769
+ lwadjust=linewidth_adjust(df2)
717
770
  ax2.plot(df2.index,df2[colname2],'-',label=label2txt, \
718
- linestyle='-.',color=color2,linewidth=2.5)
771
+ linestyle='-.',color=color2,linewidth=lwadjust)
719
772
  #证券2:绘制数据标签
720
773
  if datatag2:
721
774
  for x, y in zip(df2.index, df2[colname2]):
@@ -844,9 +897,10 @@ def plot_line2_twinx2(df01,ticker1,colname1,label1, \
844
897
  if date_range and date_freq:
845
898
  ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
846
899
  plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
847
-
900
+
901
+ lwadjust=linewidth_adjust(df1)
848
902
  ax.plot(df1.index,df1[colname1],'-',label=label1txt, \
849
- linestyle='-',color=color1,linewidth=2)
903
+ linestyle='-',color=color1,linewidth=lwadjust)
850
904
  #证券1:绘制数据标签
851
905
  if datatag1:
852
906
  for x, y in zip(df1.index, df1[colname1]):
@@ -895,9 +949,10 @@ def plot_line2_twinx2(df01,ticker1,colname1,label1, \
895
949
  if date_range and date_freq:
896
950
  ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
897
951
  plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
898
-
952
+
953
+ lwadjust=linewidth_adjust(df2)
899
954
  ax2.plot(df2.index,df2[colname2],'-',label=label2txt, \
900
- linestyle='-.',color=color2,linewidth=2.5)
955
+ linestyle='-.',color=color2,linewidth=lwadjust)
901
956
  #证券2:绘制数据标签
902
957
  if datatag2:
903
958
  for x, y in zip(df2.index, df2[colname2]):
@@ -922,6 +977,7 @@ def plot_line2_twinx2(df01,ticker1,colname1,label1, \
922
977
  label2txt=''
923
978
  else:
924
979
  label2txt=codetranslate(ticker2)+"("+trend_txt+")"
980
+
925
981
  ax2.plot(df2.index, f(df2.id),"c--", label=label2txt,linewidth=1)
926
982
 
927
983
  ax.set_xlabel(footnote,fontsize=xlabel_txt_size)
@@ -959,7 +1015,8 @@ def plot_line2_twinx2(df01,ticker1,colname1,label1, \
959
1015
  #==============================================================================
960
1016
  def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
961
1017
  data_label=True,resample_freq='H',smooth=True,linewidth=1.5, \
962
- loc='best',annotate=False,annotate_value=False,plus_sign=False):
1018
+ loc='best',annotate=False,annotate_value=False,plus_sign=False, \
1019
+ mark_top=0,mark_bottom=0,mark_end=False):
963
1020
  """
964
1021
  函数功能:根据df的内容绘制折线图
965
1022
  输入参数:
@@ -1003,21 +1060,14 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1003
1060
 
1004
1061
  # 所有字段转换为数值类型,以防万一
1005
1062
  for c in collist:
1006
- df[c]=df[c].astype('float')
1063
+ try:
1064
+ df[c]=df[c].astype('float')
1065
+ except:
1066
+ del df[c]
1007
1067
 
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
- """
1068
+ # 计算所有列中的最大最小差距,所有列必须为数值型!
1069
+ dfmax=df.max().max(); dfmin=df.min().min()
1070
+ high_low=dfmax - dfmin
1021
1071
 
1022
1072
  # 将末端值最大的排在第一列,优先绘图
1023
1073
  dftt=df.T
@@ -1052,6 +1102,7 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1052
1102
  continue
1053
1103
 
1054
1104
  #plt.plot(dfg,label=c,linewidth=linewidth,ls=lsc,marker=mkc,markersize=3)
1105
+ lwadjust=linewidth_adjust(dfg)
1055
1106
  if not annotate:
1056
1107
  """
1057
1108
  注意:许多传入的df字段名已经不是证券代码,此处调用codetranslate将会导致
@@ -1060,36 +1111,20 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1060
1111
  本函数仅负责绘图,不负责翻译证券名称。
1061
1112
  """
1062
1113
  #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)
1114
+ plt.plot(dfg,label=c,linewidth=lwadjust,ls=lsc,marker=mkc,markersize=3)
1064
1115
  else:
1065
1116
  #plt.plot(dfg[c],label=codetranslate(c),linewidth=linewidth,ls=lsc,marker=mkc,markersize=3)
1066
1117
  #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)
1118
+ plt.plot(dfg,label=c,linewidth=lwadjust,ls=lsc,marker=mkc,markersize=3)
1068
1119
 
1069
1120
  df_end=dfg.tail(1)
1070
1121
  # df_end[c]必须为数值类型,否则可能出错
1071
1122
  y_end = df_end[c].min() # 末端的y坐标
1072
1123
  x_end = df_end[c].idxmin() # 末端值的x坐标
1073
1124
 
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
1125
  if annotate_value: #在标记曲线名称的同时标记其末端数值
1092
- plt.annotate(text=c+':'+str(round(y_end,2)),
1126
+ y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
1127
+ plt.annotate(text=c+':'+y1,
1093
1128
  xy=(x_end, y_end),
1094
1129
  xytext=(x_end, y_end),fontsize=annotate_size)
1095
1130
  else:
@@ -1101,10 +1136,44 @@ def draw_lines(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1101
1136
  #plt.plot(df[c],label=c,linewidth=1.5,marker=mkc,markersize=3)
1102
1137
  #为折线加数据标签
1103
1138
  if data_label==True:
1104
- for a,b in zip(df2.index,df2[c]):
1139
+ for a,b in zip(dfg.index,df2[c]):
1105
1140
  plt.text(a,b+0.02,str(round(b,2)), \
1106
1141
  ha='center',va='bottom',fontsize=7)
1107
-
1142
+
1143
+ #标记最高点/最低点
1144
+ if mark_top > 0 or mark_bottom > 0:
1145
+ df_mark=dfg[[c]].copy() #避免影响原df
1146
+ df_mark.dropna(inplace=True)
1147
+ df_mark.sort_values(by=c,ascending=False,inplace=True)
1148
+
1149
+ if mark_top > 0:
1150
+ df_mark_top=df_mark[:mark_top]
1151
+ for x, y in zip(df_mark_top.index, df_mark_top[c]):
1152
+ y1=round(y+high_low*0.01,2)
1153
+ s='%.0f' if y >= 100 else '%.2f'
1154
+ plt.text(x,y1,s % y,ha='center',va='bottom',color='red')
1155
+ plt.scatter(x,y, color='red',marker='8',s=70)
1156
+
1157
+ if mark_bottom > 0:
1158
+ df_mark_bottom=df_mark[-mark_bottom:]
1159
+ for x, y in zip(df_mark_bottom.index, df_mark_bottom[c]):
1160
+ y1=round(y-high_low*0.055,2) #标记位置对应y1的底部
1161
+ s='%.0f' if y >= 100 else '%.2f'
1162
+ plt.text(x,y1,s % y,ha='center',va='bottom',color='seagreen')
1163
+ plt.scatter(x,y, color='seagreen',marker='8',s=70)
1164
+
1165
+ #标记曲线末端数值
1166
+ if mark_end:
1167
+ df_end=dfg.tail(1)
1168
+ y_end = df_end[c].min() # 末端的y坐标
1169
+ x_end = df_end[c].idxmin() # 末端值的x坐标
1170
+
1171
+ y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
1172
+ plt.annotate(text=' '+y1,
1173
+ xy=(x_end, y_end),
1174
+ xytext=(x_end, y_end),fontsize=annotate_size)
1175
+
1176
+
1108
1177
  #绘制水平辅助线
1109
1178
  if axhline_label !="":
1110
1179
  if '零线' in axhline_label:
@@ -1148,7 +1217,8 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1148
1217
  data_label=False,resample_freq='6H',smooth=True, \
1149
1218
  date_range=False,date_freq=False,date_fmt='%Y-%m-%d', \
1150
1219
  colorlist=[],lslist=[],lwlist=[], \
1151
- band_area='',loc='best',annotate=False,annotate_value=False):
1220
+ band_area='',loc='best',annotate=False,annotate_value=False, \
1221
+ mark_top=0,mark_bottom=0,mark_end=False):
1152
1222
  """
1153
1223
  函数功能:根据df的内容绘制折线图
1154
1224
  输入参数:
@@ -1184,6 +1254,17 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1184
1254
  else:
1185
1255
  df=df0
1186
1256
 
1257
+ # 所有字段转换为数值类型,以防万一
1258
+ for c in list(df):
1259
+ try:
1260
+ df[c]=df[c].astype('float')
1261
+ except:
1262
+ del df[c]
1263
+
1264
+ # 计算所有列中的最大最小差距,假设所有列均为数值型!
1265
+ dfmax=df.max().max(); dfmin=df.min().min()
1266
+ high_low=dfmax - dfmin
1267
+
1187
1268
  #定义横轴标签:显示完整开始、结束日期
1188
1269
  import matplotlib.dates as mdate
1189
1270
  ax=plt.gca()
@@ -1201,6 +1282,7 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1201
1282
 
1202
1283
  #取得df字段名列表
1203
1284
  collist=df.columns.values.tolist()
1285
+ collist3=collist[:3] #专用于绘制布林带,取前3个字段
1204
1286
 
1205
1287
  #绘制折线图
1206
1288
  for c in collist:
@@ -1210,7 +1292,8 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1210
1292
  lls=lslist[pos]
1211
1293
  llw=lwlist[pos]
1212
1294
  except:
1213
- plt.plot(df[c],label=c,linewidth=2)
1295
+ lwadjust=linewidth_adjust(df)
1296
+ plt.plot(df[c],label=c,linewidth=lwadjust)
1214
1297
  else:
1215
1298
  plt.plot(df[c],label=c,linewidth=llw,ls=lls,color=lcolor)
1216
1299
 
@@ -1219,23 +1302,56 @@ def draw_lines2(df0,y_label,x_label,axhline_value,axhline_label,title_txt, \
1219
1302
  for a,b in zip(df.index,df[c]):
1220
1303
  plt.text(a,b+0.02,str(round(b,2)), \
1221
1304
  ha='center',va='bottom',fontsize=7)
1222
-
1223
- #曲线末端标记
1305
+
1306
+ #标记最高点/最低点
1307
+ if mark_top > 0 or mark_bottom > 0:
1308
+ df_mark=df[[c]].copy() #避免影响原df
1309
+ df_mark.dropna(inplace=True)
1310
+ df_mark.sort_values(by=c,ascending=False,inplace=True)
1311
+
1312
+ if mark_top > 0:
1313
+ df_mark_top=df_mark[:mark_top]
1314
+ for x, y in zip(df_mark_top.index, df_mark_top[c]):
1315
+ y1=round(y+high_low*0.01,2)
1316
+ s='%.0f' if y >= 100 else '%.2f'
1317
+ plt.text(x,y1,s % y,ha='center',va='bottom',color='red')
1318
+ plt.scatter(x,y, color='red',marker='8',s=70)
1319
+
1320
+ if mark_bottom > 0:
1321
+ df_mark_bottom=df_mark[-mark_bottom:]
1322
+ for x, y in zip(df_mark_bottom.index, df_mark_bottom[c]):
1323
+ y1=round(y-high_low*0.055,2) #标记位置对应y1的底部
1324
+ s='%.0f' if y >= 100 else '%.2f'
1325
+ plt.text(x,y1,s % y,ha='center',va='bottom',color='seagreen')
1326
+ plt.scatter(x,y, color='seagreen',marker='8',s=70)
1327
+
1328
+ #曲线末端标记:不建议用于布林带
1224
1329
  if annotate:
1225
1330
  df_end=df.tail(1)
1226
1331
  y_end = df_end[c].min() # 末端的y坐标
1227
1332
  x_end = df_end[c].idxmin() # 末端值的x坐标
1228
1333
 
1229
1334
  if annotate_value: #在标记曲线名称的同时标记其末端数值
1230
- plt.annotate(text=c+':'+str(round(y_end,2)),
1335
+ y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
1336
+ plt.annotate(text=c+':'+y1,
1231
1337
  xy=(x_end, y_end),
1232
1338
  xytext=(x_end, y_end),fontsize=annotate_size)
1233
1339
  else:
1234
1340
  plt.annotate(text=c,
1235
1341
  xy=(x_end, y_end),
1236
1342
  xytext=(x_end, y_end),fontsize=annotate_size)
1237
-
1238
1343
 
1344
+ #处理布林带的mark_end,仅标记上中下线
1345
+ if mark_end & (c in collist3):
1346
+ df_end=df.tail(1)
1347
+ y_end = df_end[c].min() # 末端的y坐标
1348
+ x_end = df_end[c].idxmin() # 末端值的x坐标
1349
+
1350
+ y1=str(int(y_end)) if y_end >= 100 else str(round(y_end,2))
1351
+ plt.annotate(text=y1,
1352
+ xy=(x_end, y_end),
1353
+ xytext=(x_end, y_end),fontsize=annotate_size)
1354
+
1239
1355
  #绘制带状区域
1240
1356
  if band_area != '' and isinstance(band_area,list) and len(band_area)>=2:
1241
1357
  plt.fill_between(df.index,df[band_area[0]],df[band_area[1]],alpha=0.5,label='')
@@ -1445,7 +1561,8 @@ def plot_2lines(df01,colname1,label1, \
1445
1561
  ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
1446
1562
  plt.xticks(pd.date_range(date_start,date_end,freq=date_freq))
1447
1563
 
1448
- plt.plot(df1.index,df1[colname1],label=label1,linestyle='-',linewidth=2)
1564
+ lwadjust=linewidth_adjust(df1)
1565
+ plt.plot(df1.index,df1[colname1],label=label1,linestyle='-',linewidth=lwadjust)
1449
1566
 
1450
1567
  #证券2:先绘制折线图
1451
1568
  date_start=df2.index[0]
@@ -1462,8 +1579,9 @@ def plot_2lines(df01,colname1,label1, \
1462
1579
  ax=plt.gca()
1463
1580
  ax.xaxis.set_major_formatter(mdate.DateFormatter(date_fmt))
1464
1581
  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)
1582
+
1583
+ lwadjust=linewidth_adjust(df2)
1584
+ plt.plot(df2.index,df2[colname2],label=label2,linestyle='-.',linewidth=lwadjust)
1467
1585
 
1468
1586
  #是否绘制水平虚线
1469
1587
  if not (hline == 0):
@@ -1535,7 +1653,7 @@ def df_smooth(df):
1535
1653
  #print(' #Warning(df_smooth): resampling failed for frequency',freqlist)
1536
1654
  dfh=df
1537
1655
 
1538
- #插值
1656
+ #重采样后插值
1539
1657
  methodlist=['pchip','nearest','cubic','quadratic','slinear','linear','zero','time','index', \
1540
1658
  'piecewise_polynomial','akima','from_derivatives','spline','polynomial']
1541
1659
  methodlist_order=['spline','polynomial']
@@ -1562,19 +1680,19 @@ def df_smooth(df):
1562
1680
 
1563
1681
 
1564
1682
  #==============================================================================
1565
- def df_smooth_manual(df,method='pchip',resample_freq='H',order=3):
1683
+ def df_smooth_manual(df,method='linear',resample_freq='H',order=3):
1566
1684
  """
1567
1685
  功能:对df中的第一个数值列样本进行插值,以便绘制的折线图相对平滑。
1568
1686
  要求:df的索引为pandas的datetime日期型
1569
1687
  注意1:如果样本数量较多,例如多于100个,平滑效果不明显。
1570
1688
  注意2:order阶数仅对'spline'和'polynomial'方法有效,其中'polynomial'方法的阶数只能为奇数。
1571
- 注意3:pchip方法经常失败,改为cubic
1689
+ 注意3:pchip方法经常失败,可改为cubic
1572
1690
  """
1573
1691
 
1574
1692
  #如果样本个数多于100个,没必要进行平滑,完全看不出效果
1575
1693
  if len(df) >= 100: return df
1576
1694
 
1577
- #检查平滑方法是否支持
1695
+ #检查插值方法是否支持
1578
1696
  methodlist=['quadratic','cubic','slinear','linear','zero','nearest','time','index', \
1579
1697
  'piecewise_polynomial','pchip','akima','from_derivatives','spline','polynomial']
1580
1698
  if not (method in methodlist): return df
@@ -1599,13 +1717,14 @@ def df_smooth_manual(df,method='pchip',resample_freq='H',order=3):
1599
1717
  return df
1600
1718
  df.set_index('date',inplace=True)
1601
1719
 
1720
+ #重新采样
1602
1721
  try:
1603
1722
  dfh=df.resample(resample_freq)
1604
1723
  except:
1605
1724
  print(' #Warning(df_smooth): resampling failed for frequency',resample_freq)
1606
1725
  return df
1607
1726
 
1608
- #重新采样
1727
+ #重采样后插值(不然太多nan):是否methodlist_o里面的特别插值方法
1609
1728
  methodlist_o=['spline','polynomial']
1610
1729
  if method in methodlist_o:
1611
1730
  try:
@@ -1617,6 +1736,7 @@ def df_smooth_manual(df,method='pchip',resample_freq='H',order=3):
1617
1736
  #成功返回经过重采样的df
1618
1737
  return dfm
1619
1738
 
1739
+ #重采样后插值:其他插值方法
1620
1740
  try:
1621
1741
  dfm=dfh.interpolate(method=method)
1622
1742
  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):