<本文的原始位置: http://bluegene8210.is-programmer.com/posts/25954.html>
---- 最新的在这里: 用 Python / Matplotlib 画出来的股票 K线图 (四)
---- 下一篇在这里: 用 Python / Matplotlib 画出来的股票 K线图 (三)
---- 上一版的改进,双股同列 + 无数细小改进,如下图。dpi= 300。明的一条是个股走势,暗的是同期的指数走势。这大概是近期最强的一只。
---- 要想培养对走势的感觉,采用固定比例尺的图形是必须的。一般股票软件里的图形都为显示方便而做了变形处理,用处不大。
---- 图形感觉差不多了,告一段落。接下来的目标是 股本结构、历史分配、行业板块、股东研究 这些信息,还包括个股资讯。实时的数据仍然暂时不碰。
---- 源码贴出来。因为 Matplotlib 还不支持 Python3, 所以单写了一个 Python2 脚本。注意绘图数据是用 pickle file 传递的。
[补记:我决定放弃线性坐标了。这个脚本只支持对数坐标。]

1 # -*- coding: utf-8 -*- 2 3 import os 4 import sys 5 import pickle 6 import math 7 import datetime 8 import matplotlib 9 10 matplotlib.use("WXAgg", warn=True) # 这个要紧跟在 import matplotlib 之后,而且必须安装了 wxpython 2.8 才行。 11 12 import matplotlib.pyplot as pyplot 13 import matplotlib.font_manager as font_manager 14 15 import numpy 16 from matplotlib.ticker import FixedLocator, MultipleLocator, FuncFormatter, NullFormatter 17 18 19 20 __font_properties__=font_manager.FontProperties(fname='/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc') 21 __color_lightsalmon__= '#ffa07a' 22 __color_pink__= '#ffc0cb' 23 __color_navy__= '#000080' 24 25 26 27 28 29 30 def Plot(pfile, figpath): 31 ''' 32 pfile 指明存放绘图数据的 pickle file,figpath 指定图片需存放的路径 33 ''' 34 35 fileobj= open(name=pfile, mode='rb') 36 pdata= pickle.load(fileobj) 37 fileobj.close() 38 os.remove(pfile) 39 40 # 计算图片的尺寸(单位英寸) 41 # 注意:Python2 里面, "1 / 10" 结果是 0, 必须写成 "1.0 / 10" 才会得到 0.1 42 #================================================================================================================================================== 43 length= len(pdata[u'日期']) # 所有数据的长度,就是天数 44 45 open_price_pri= pdata[u'开盘'][0] # int 类型 46 open_price_sec= pdata[u'开盘二'][0] # 同上 47 48 highest_price_pri= max( [phigh for phigh in pdata[u'最高'] if phigh != None] ) # 第一个行情的最高价 49 highest_price_sec= max( [phigh for phigh in pdata[u'最高二'] if phigh != None] ) # 第二个行情的最高价 50 highest_price= max(highest_price_pri, highest_price_sec*open_price_pri/open_price_sec) # 以第一个行情为基准修正出的总最高价 51 52 lowest_price_pri= min( [plow for plow in pdata[u'最低'] if plow != None] ) # 最低价 53 lowest_price_sec= min( [plow for plow in pdata[u'最低二'] if plow != None] ) # 最低价 54 lowest_price= min(lowest_price_pri, lowest_price_sec*open_price_pri/open_price_sec) # 以第一个行情为基准修正出的总最低价 55 56 57 58 yhighlim_price= int(highest_price * 1.1) # K线子图 Y 轴最大坐标 59 ylowlim_price= int(lowest_price / 1.1) # K线子图 Y 轴最小坐标 60 61 62 63 xfactor= 10.0/230.0 # 一条 K 线的宽度在 X 轴上所占距离(英寸) 64 yfactor= 0.3 # Y 轴上每一个距离单位的长度(英寸),这个单位距离是线性坐标和对数坐标通用的 65 66 expbase= 1.1 # 底数,取得小一点,比较接近 1。股价 3 元到 4 元之间有大约 3 个单位距离 67 68 # XXX: 价格在 Y 轴上的 “份数”。注意,虽然最高与最低价是以第一个行情为基准修正出来的,但其中包含的倍数因子对结果无影响,即: 69 # log(base, num1) - log(base, num2) == 70 # log(base, num1/num2) == 71 # log(base, k*num1/k*num2) == 72 # log(base, k*num1) - log(base, k*num2) 73 # ,这是对数运算的性质。 74 ymulti_price= math.log(yhighlim_price, expbase) - math.log(ylowlim_price, expbase) 75 76 ymulti_vol= 3.0 # 成交量部分在 Y 轴所占的 “份数” 77 ymulti_top= 1.2 # 顶部空白区域在 Y 轴所占的 “份数” 78 ymulti_bot= 1.2 # 底部空白区域在 Y 轴所占的 “份数” 79 80 xmulti_left= 12.0 # 左侧空白区域所占的 “份数” 81 xmulti_right= 12.0 # 右侧空白区域所占的 “份数” 82 83 xmulti_all= length + xmulti_left + xmulti_right 84 xlen_fig= xmulti_all * xfactor # 整个 Figure 的宽度 85 ymulti_all= ymulti_price + ymulti_vol + ymulti_top + ymulti_bot 86 ylen_fig= ymulti_all * yfactor # 整个 Figure 的高度 87 88 rect_1= (xmulti_left/xmulti_all, (ymulti_bot+ymulti_vol)/ymulti_all, length/xmulti_all, ymulti_price/ymulti_all) # K线图部分 89 rect_2= (xmulti_left/xmulti_all, ymulti_bot/ymulti_all, length/xmulti_all, ymulti_vol/ymulti_all) # 成交量部分 90 91 92 93 # 建立 Figure 对象 94 #================================================================================================================================================== 95 figfacecolor= __color_pink__ 96 figedgecolor= __color_navy__ 97 figdpi= 300 98 figlinewidth= 1.0 99 100 figobj= pyplot.figure(figsize=(xlen_fig, ylen_fig), dpi=figdpi, facecolor=figfacecolor, edgecolor=figedgecolor, linewidth=figlinewidth) # Figure 对象 101 102 # 整个 figure 的标题 103 title_pri= (pdata[u'代码'] + ' ' if u'代码' in pdata else '') + pdata[u'简称'] 104 title_sec= (pdata[u'代码二'] + ' ' if u'代码二' in pdata else '') + pdata[u'简称二'] 105 106 figobj.suptitle(title_pri + ' / ' + title_sec, fontsize=12, fontproperties=__font_properties__) 107 108 109 110 #================================================================================================================================================== 111 #================================================================================================================================================== 112 #======= 113 #======= XXX: 第一只:成交量部分 114 #======= 115 #================================================================================================================================================== 116 #================================================================================================================================================== 117 118 # 第一只:添加 Axes 对象 119 #================================================================================================================================================== 120 axes_2= figobj.add_axes(rect_2, axis_bgcolor='black') 121 axes_2.set_axisbelow(True) # 网格线放在底层 122 123 # 第一只:改变坐标线的颜色 124 #================================================================================================================================================== 125 for child in axes_2.get_children(): 126 if isinstance(child, matplotlib.spines.Spine): 127 child.set_color('lightblue') 128 129 # 第一只:得到 X 轴 和 Y 轴 的两个 Axis 对象 130 #================================================================================================================================================== 131 xaxis_2= axes_2.get_xaxis() 132 yaxis_2= axes_2.get_yaxis() 133 134 # 第一只:设置两个坐标轴上的 grid 135 #================================================================================================================================================== 136 xaxis_2.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2) 137 xaxis_2.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1) 138 139 yaxis_2.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2) 140 yaxis_2.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1) 141 142 143 144 #================================================================================================================================================== 145 #======= 第一只:成交量绘图 146 #================================================================================================================================================== 147 xindex= numpy.arange(length) # X 轴上的 index,一个辅助数据 148 149 zipoc= zip(pdata[u'开盘'], pdata[u'收盘']) 150 up= numpy.array( [ True if po < pc and po != None else False for po, pc in zipoc] ) # 标示出该天股价日内上涨的一个序列 151 down= numpy.array( [ True if po > pc and po != None else False for po, pc in zipoc] ) # 标示出该天股价日内下跌的一个序列 152 side= numpy.array( [ True if po == pc and po != None else False for po, pc in zipoc] ) # 标示出该天股价日内走平的一个序列 153 154 155 156 if u'成交额' in pdata: 157 volume= pdata[u'成交额'] 158 else: 159 volume= pdata[u'成交量'] 160 161 rarray_vol= numpy.array(volume) 162 volzeros= numpy.zeros(length) # 辅助数据 163 164 # XXX: 如果 up/down/side 各项全部为 False,那么 vlines() 会报错。 165 if True in up: 166 axes_2.vlines(xindex[up], volzeros[up], rarray_vol[up], edgecolor='red', linewidth=3.0, label='_nolegend_') 167 if True in down: 168 axes_2.vlines(xindex[down], volzeros[down], rarray_vol[down], edgecolor='green', linewidth=3.0, label='_nolegend_') 169 if True in side: 170 axes_2.vlines(xindex[side], volzeros[side], rarray_vol[side], edgecolor='0.7', linewidth=3.0, label='_nolegend_') 171 172 173 174 # 第一只:设定 X 轴坐标的范围 175 #================================================================================================================================================== 176 axes_2.set_xlim(-1, length) 177 178 179 180 # 第一只:设定 X 轴上的坐标 181 #================================================================================================================================================== 182 datelist= [ datetime.date(int(ys), int(ms), int(ds)) for ys, ms, ds in [ dstr.split('-') for dstr in pdata[u'日期'] ] ] 183 184 # 确定 X 轴的 MajorLocator 185 mdindex= [] # 每个月第一个交易日在所有日期列表中的 index 186 years= set([d.year for d in datelist]) # 所有的交易年份 187 188 for y in sorted(years): 189 months= set([d.month for d in datelist if d.year == y]) # 当年所有的交易月份 190 for m in sorted(months): 191 monthday= min([dt for dt in datelist if dt.year==y and dt.month==m]) # 当月的第一个交易日 192 mdindex.append(datelist.index(monthday)) 193 194 xMajorLocator= FixedLocator(numpy.array(mdindex)) 195 196 # 第一只:确定 X 轴的 MinorLocator 197 wdindex= {} # value: 每周第一个交易日在所有日期列表中的 index; key: 当周的序号 week number(当周是第几周) 198 199 for d in datelist: 200 isoyear, weekno= d.isocalendar()[0:2] 201 dmark= isoyear*100 + weekno 202 if dmark not in wdindex: 203 wdindex[dmark]= datelist.index(d) 204 205 xMinorLocator= FixedLocator(numpy.array( sorted(wdindex.values()) )) 206 207 # 第一只:确定 X 轴的 MajorFormatter 和 MinorFormatter 208 def x_major_formatter_2(idx, pos=None): 209 return datelist[idx].strftime('%Y-%m-%d') 210 211 def x_minor_formatter_2(idx, pos=None): 212 return datelist[idx].strftime('%m-%d') 213 214 xMajorFormatter= FuncFormatter(x_major_formatter_2) 215 xMinorFormatter= FuncFormatter(x_minor_formatter_2) 216 217 # 第一只:设定 X 轴的 Locator 和 Formatter 218 xaxis_2.set_major_locator(xMajorLocator) 219 xaxis_2.set_major_formatter(xMajorFormatter) 220 221 xaxis_2.set_minor_locator(xMinorLocator) 222 xaxis_2.set_minor_formatter(xMinorFormatter) 223 224 # 第一只:设定 X 轴主要坐标点与辅助坐标点的样式 225 for malabel in axes_2.get_xticklabels(minor=False): 226 malabel.set_fontsize(4) 227 malabel.set_horizontalalignment('right') 228 malabel.set_rotation('45') 229 230 for milabel in axes_2.get_xticklabels(minor=True): 231 milabel.set_fontsize(4) 232 milabel.set_color('blue') 233 milabel.set_horizontalalignment('right') 234 milabel.set_rotation('45') 235 236 237 238 # 第一只:设定成交量 Y 轴坐标的范围 239 #================================================================================================================================================== 240 maxvol= max(volume) # 注意是 int 类型 241 axes_2.set_ylim(0, maxvol) 242 243 244 245 # 第一只:设定成交量 Y 轴上的坐标 246 #================================================================================================================================================== 247 vollen= len(str(maxvol)) 248 249 volstep_pri= int(round(maxvol/10.0+5000, -4)) 250 251 yMajorLocator_2= MultipleLocator(volstep_pri) 252 253 254 255 # 第一只:确定 Y 轴的 MajorFormatter 256 dimsuffix= u'元' if u'成交额' in pdata else u'股' 257 def y_major_formatter_2(num, pos=None): 258 if num >= 10**8: # 大于 1 亿 259 return (str(round(num/10.0**8, 2)) + u'亿' + dimsuffix) if num != 0 else '0' 260 else: 261 return (str(num/10.0**4) + u'万' + dimsuffix) if num != 0 else '0' 262 263 # def y_major_formatter_2(num, pos=None): 264 # return int(num) 265 yMajorFormatter_2= FuncFormatter(y_major_formatter_2) 266 267 # 确定 Y 轴的 MinorFormatter 268 # def y_minor_formatter_2(num, pos=None): 269 # return int(num) 270 # yMinorFormatter_2= FuncFormatter(y_minor_formatter_2) 271 yMinorFormatter_2= NullFormatter() 272 273 # 第一只:设定 X 轴的 Locator 和 Formatter 274 yaxis_2.set_major_locator(yMajorLocator_2) 275 yaxis_2.set_major_formatter(yMajorFormatter_2) 276 277 # yaxis_2.set_minor_locator(yMinorLocator_2) 278 yaxis_2.set_minor_formatter(yMinorFormatter_2) 279 280 # 第一只:设定 Y 轴主要坐标点与辅助坐标点的样式 281 for malab in axes_2.get_yticklabels(minor=False): 282 malab.set_font_properties(__font_properties__) 283 malab.set_fontsize(4.5) # 这个必须放在前一句后面,否则作用会被覆盖 284 285 286 287 # 第一只:成交量数值在图中间的显示 288 #================================================================================================================================================== 289 for iy in range(volstep_pri, maxvol, volstep_pri): 290 for ix in mdindex[1:-1:3]: 291 newlab= axes_2.text(ix+8, iy, y_major_formatter_2(iy)) 292 newlab.set_font_properties(__font_properties__) 293 newlab.set_color('0.3') 294 newlab.set_fontsize(3) 295 newlab.set_zorder(0) # XXX: 放在底层 296 # newlab.set_verticalalignment('center') 297 298 299 300 #================================================================================================================================================== 301 #================================================================================================================================================== 302 #======= 303 #======= XXX: 第二条成交量图线 304 #======= 305 #================================================================================================================================================== 306 #================================================================================================================================================== 307 308 # 添加 Axes 对象 309 #================================================================================================================================================== 310 axes_2_sec= axes_2.twinx() 311 # axes_2_sec.set_axisbelow(True) # 网格线放在底层 312 313 axes_2_sec.set_axisbelow(True) # 网格线放在底层 314 315 # 改变坐标线的颜色 316 #================================================================================================================================================== 317 # for child in axes_2_sec.get_children(): 318 # if isinstance(child, matplotlib.spines.Spine): 319 # child.set_color('lightblue') 320 321 # 得到 X 轴 和 Y 轴 的两个 Axis 对象 322 #================================================================================================================================================== 323 xaxis_2_sec= axes_2_sec.get_xaxis() 324 yaxis_2_sec= axes_2_sec.get_yaxis() 325 326 # 设置两个坐标轴上的 grid 327 #================================================================================================================================================== 328 # xaxis_2_sec.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2) 329 # xaxis_2_sec.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1) 330 331 # yaxis_2_sec.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2) 332 # yaxis_2_sec.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1) 333 334 335 336 #================================================================================================================================================== 337 #======= 绘图 338 #================================================================================================================================================== 339 340 if u'成交额二' in pdata: 341 volume_sec= pdata[u'成交额二'] 342 else: 343 volume_sec= pdata[u'成交量二'] 344 345 zipoc_sec= zip(pdata[u'开盘二'], pdata[u'收盘二']) 346 up_sec= numpy.array( [ True if po < pc and po != None else False for po, pc in zipoc_sec] ) # 标示出该天股价日内上涨的一个序列 347 down_sec= numpy.array( [ True if po > pc and po != None else False for po, pc in zipoc_sec] ) # 标示出该天股价日内下跌的一个序列 348 side_sec= numpy.array( [ True if po == pc and po != None else False for po, pc in zipoc_sec] ) # 标示出该天股价日内走平的一个序列 349 350 rarray_vol_sec= numpy.array(volume_sec) 351 volzeros_sec= numpy.zeros(length) # 辅助数据 352 353 # XXX: 如果 up_sec/down_sec/side_sec 各项全部为 False,那么 vlines() 会报错。 354 if True in up_sec: 355 axes_2_sec.vlines(xindex[up_sec], volzeros_sec[up_sec], rarray_vol_sec[up_sec], edgecolor='pink', linewidth=1.0, label='_nolegend_', alpha=0.3) 356 if True in down_sec: 357 axes_2_sec.vlines(xindex[down_sec], volzeros_sec[down_sec], rarray_vol_sec[down_sec], edgecolor='lightgreen', linewidth=1.0, label='_nolegend_', alpha=0.3) 358 if True in side_sec: 359 axes_2_sec.vlines(xindex[side_sec], volzeros_sec[side_sec], rarray_vol_sec[side_sec], edgecolor='0.7', linewidth=1.0, label='_nolegend_', alpha=0.3) 360 361 362 363 # 设定 X 轴坐标的范围 364 #================================================================================================================================================== 365 # XXX: 不用了,与 axes_2 共用。 366 367 368 # 设定 Y 轴坐标的范围 369 #================================================================================================================================================== 370 maxvol_sec= max(volume_sec) # 注意是 int 类型 371 axes_2_sec.set_ylim(0, maxvol_sec) 372 373 374 375 # 设定 Y 轴上的坐标 376 #================================================================================================================================================== 377 378 volstep_sec= volstep_pri*maxvol_sec/float(maxvol) 379 yMajorLocator_2_sec= MultipleLocator(volstep_sec) 380 381 # 确定 Y 轴的 MajorFormatter 382 dimsuffix_sec= u'元' if u'成交额二' in pdata else u'股' 383 def y_major_formatter_2_sec(num, pos=None): 384 if num >= 10**8: # 大于 1 亿 385 print(('num= ' + str(num) + ', result= ' + str(round(num/10.0**8, 3)) + u'亿' + dimsuffix_sec).encode('utf8')) 386 387 return (str(round(num/10.0**8, 3)) + u'亿' + dimsuffix_sec) if num != 0 else '0' 388 else: 389 return (str(round(num/10.0**4, 2)) + u'万' + dimsuffix_sec) if num != 0 else '0' 390 391 # def y_major_formatter_2_sec(num, pos=None): 392 # return int(num) 393 yMajorFormatter_2_sec= FuncFormatter(y_major_formatter_2_sec) 394 395 # 确定 Y 轴的 MinorFormatter 396 # def y_minor_formatter_2(num, pos=None): 397 # return int(num) 398 # yMinorFormatter_2_sec= FuncFormatter(y_minor_formatter_2) 399 yMinorFormatter_2_sec= NullFormatter() 400 401 # 设定 X 轴的 Locator 和 Formatter 402 yaxis_2_sec.set_major_locator(yMajorLocator_2_sec) 403 yaxis_2_sec.set_major_formatter(yMajorFormatter_2_sec) 404 405 # yaxis_2_sec.set_minor_locator(yMinorLocator_2_sec) 406 yaxis_2_sec.set_minor_formatter(yMinorFormatter_2_sec) 407 408 # 设定 Y 轴主要坐标点与辅助坐标点的样式 409 for malab in axes_2_sec.get_yticklabels(minor=False): 410 malab.set_font_properties(__font_properties__) 411 malab.set_fontsize(4.5) # 这个必须放在前一句后面,否则作用会被覆盖 412 413 414 415 416 417 #================================================================================================================================================== 418 #================================================================================================================================================== 419 #======= 420 #======= XXX: K 线图部分 421 #======= 422 #================================================================================================================================================== 423 #================================================================================================================================================== 424 425 # 添加 Axes 对象 426 #================================================================================================================================================== 427 axes_1= figobj.add_axes(rect_1, axis_bgcolor='black', sharex=axes_2) 428 axes_1.set_axisbelow(True) # 网格线放在底层 429 430 axes_1.set_yscale('log', basey=expbase) # 使用对数坐标 431 432 # 改变坐标线的颜色 433 #================================================================================================================================================== 434 for child in axes_1.get_children(): 435 if isinstance(child, matplotlib.spines.Spine): 436 child.set_color('lightblue') 437 438 # 得到 X 轴 和 Y 轴 的两个 Axis 对象 439 #================================================================================================================================================== 440 xaxis_1= axes_1.get_xaxis() 441 yaxis_1= axes_1.get_yaxis() 442 443 # 设置两个坐标轴上的 grid 444 #================================================================================================================================================== 445 xaxis_1.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2) 446 xaxis_1.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1) 447 448 yaxis_1.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2) 449 yaxis_1.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1) 450 451 452 453 #================================================================================================================================================== 454 #======= 绘图 455 #================================================================================================================================================== 456 457 # 绘制 K 线部分 458 #================================================================================================================================================== 459 460 # 对开收盘价进行视觉修正 461 for idx, poc in enumerate( zip(pdata[u'开盘'], pdata[u'收盘']) ): 462 if poc[0] == poc[1] and None not in poc: 463 variant= round((poc[1]+1000)/2000, 0) 464 pdata[u'开盘'][idx]= poc[0] - variant # 稍微偏离一点,使得在图线上不致于完全看不到 465 pdata[u'收盘'][idx]= poc[1] + variant 466 467 rarray_open= numpy.array(pdata[u'开盘']) 468 rarray_close= numpy.array(pdata[u'收盘']) 469 rarray_high= numpy.array(pdata[u'最高']) 470 rarray_low= numpy.array(pdata[u'最低']) 471 472 # XXX: 如果 up, down, side 里有一个全部为 False 组成,那么 vlines() 会报错。 473 # XXX: 可以使用 alpha 参数调节透明度 474 if True in up: 475 axes_1.vlines(xindex[up], rarray_low[up], rarray_high[up], edgecolor='red', linewidth=0.6, label='_nolegend_') 476 axes_1.vlines(xindex[up], rarray_open[up], rarray_close[up], edgecolor='red', linewidth=3.0, label='_nolegend_') 477 478 if True in down: 479 axes_1.vlines(xindex[down], rarray_low[down], rarray_high[down], edgecolor='green', linewidth=0.6, label='_nolegend_') 480 axes_1.vlines(xindex[down], rarray_open[down], rarray_close[down], edgecolor='green', linewidth=3.0, label='_nolegend_') 481 482 if True in side: 483 axes_1.vlines(xindex[side], rarray_low[side], rarray_high[side], edgecolor='0.7', linewidth=0.6, label='_nolegend_') 484 axes_1.vlines(xindex[side], rarray_open[side], rarray_close[side], edgecolor='0.7', linewidth=3.0, label='_nolegend_') 485 486 # 绘制均线部分 487 #================================================================================================================================================== 488 if u'5日均' in pdata: 489 rarray_5dayave= numpy.array(pdata[u'5日均']) 490 axes_1.plot(xindex, rarray_5dayave, 'o-', color='white', linewidth=0.1, label='ave_5', \ 491 markersize=0.7, markeredgecolor='white', markeredgewidth=0.1) # 5日均线 492 493 if u'10日均' in pdata: 494 rarray_10dayave= numpy.array(pdata[u'10日均']) 495 axes_1.plot(xindex, rarray_10dayave, 'o-', color='yellow', linewidth=0.1, label='ave_10', \ 496 markersize=0.7, markeredgecolor='yellow', markeredgewidth=0.1) # 10日均线 497 498 if u'30日均' in pdata: 499 rarray_30dayave= numpy.array(pdata[u'30日均']) 500 axes_1.plot(xindex, rarray_30dayave, 'o-', color='cyan', linewidth=0.1, label='ave_30', \ 501 markersize=0.7, markeredgecolor='cyan', markeredgewidth=0.1) # 30日均线 502 503 504 505 # 绘制 复权提示 506 #================================================================================================================================================== 507 if u'复权' in pdata: 508 adjdict= dict(pdata[u'复权']) 509 510 for idx, dstr in enumerate(pdata[u'日期']): 511 if dstr in adjdict: 512 axes_1.plot([idx, idx], [ylowlim_price, yhighlim_price], '-', color='purple', linewidth=0.3) 513 514 515 516 517 518 # 设定 X 轴坐标的范围 519 #================================================================================================================================================== 520 axes_1.set_xlim(-1, length) 521 522 523 524 # 先设置 label 位置,再将 X 轴上的坐标设为不可见。因为与 成交量子图 共用 X 轴 525 #================================================================================================================================================== 526 527 # 设定 X 轴的 Locator 和 Formatter 528 xaxis_1.set_major_locator(xMajorLocator) 529 xaxis_1.set_major_formatter(xMajorFormatter) 530 531 xaxis_1.set_minor_locator(xMinorLocator) 532 xaxis_1.set_minor_formatter(xMinorFormatter) 533 534 # 将 X 轴上的坐标设为不可见。 535 for malab in axes_1.get_xticklabels(minor=False): 536 malab.set_visible(False) 537 538 for milab in axes_1.get_xticklabels(minor=True): 539 milab.set_visible(False) 540 541 # 用这一段效果也一样 542 # pyplot.setp(axes_1.get_xticklabels(minor=False), visible=False) 543 # pyplot.setp(axes_1.get_xticklabels(minor=True), visible=False) 544 545 546 547 # 设定 Y 轴坐标的范围 548 #================================================================================================================================================== 549 axes_1.set_ylim(ylowlim_price, yhighlim_price) 550 551 552 553 # 设定 Y 轴上的坐标 554 #================================================================================================================================================== 555 556 # XXX: 不用 LogLocator 了,因为不能控制坐标点的位置。 557 558 # 主要坐标点 559 #---------------------------------------------------------------------------- 560 yticks_major_pri= [] 561 for i in range(1, 999): 562 newloc= ylowlim_price * (expbase**i) 563 if newloc <= yhighlim_price: 564 yticks_major_pri.append(newloc) 565 else: 566 break 567 568 yMajorLocator_1= FixedLocator(numpy.array(yticks_major_pri)) 569 570 # 确定 Y 轴的 MajorFormatter 571 def y_major_formatter_1(num, pos=None): 572 return str(round(num/1000.0, 2)) 573 574 yMajorFormatter_1= FuncFormatter(y_major_formatter_1) 575 576 # 设定 X 轴的 Locator 和 Formatter 577 yaxis_1.set_major_locator(yMajorLocator_1) 578 yaxis_1.set_major_formatter(yMajorFormatter_1) 579 580 # 设定 Y 轴主要坐标点与辅助坐标点的样式 581 for mal in axes_1.get_yticklabels(minor=False): 582 mal.set_fontsize(6) 583 584 585 586 # 辅助坐标点 587 #---------------------------------------------------------------------------- 588 yticks_minor_pri= [] 589 mtstart= ylowlim_price * (1.0+(expbase-1.0)/2) 590 for i in range(999): 591 newloc= mtstart * (expbase**i) 592 if newloc <= yhighlim_price: 593 yticks_minor_pri.append(newloc) 594 else: 595 break 596 597 yMinorLocator_1= FixedLocator(numpy.array(yticks_minor_pri)) # XXX minor ticks 已经在上面一并设置,这里不需要了。 598 599 # 确定 Y 轴的 MinorFormatter 600 def y_minor_formatter_1(num, pos=None): 601 return str(round(num/1000.0, 2)) 602 603 yMinorFormatter_1= FuncFormatter(y_minor_formatter_1) 604 605 # 设定 X 轴的 Locator 和 Formatter 606 yaxis_1.set_minor_locator(yMinorLocator_1) 607 yaxis_1.set_minor_formatter(yMinorFormatter_1) 608 # 设定 Y 轴主要坐标点与辅助坐标点的样式 609 for mal in axes_1.get_yticklabels(minor=True): 610 mal.set_fontsize(5) 611 mal.set_color('blue') 612 613 614 615 # 第一只:价格数值在图中间的显示 616 #================================================================================================================================================== 617 for iy in yticks_major_pri: 618 for ix in mdindex[1:-1:3]: 619 newlab= axes_1.text(ix+8, iy*1.001, y_major_formatter_1(iy)) 620 newlab.set_font_properties(__font_properties__) 621 newlab.set_color('0.3') 622 newlab.set_fontsize(3) 623 newlab.set_zorder(0) # XXX: 放在底层 624 # newlab.set_verticalalignment('center') 625 626 627 628 # 第一只:日期在图中间的显示 629 #================================================================================================================================================== 630 for iy in yticks_minor_pri[1:-1:5]: 631 for ix in mdindex: 632 newlab= axes_1.text(ix-1, iy, pdata[u'日期'][ix]) 633 newlab.set_font_properties(__font_properties__) 634 newlab.set_color('0.3') 635 newlab.set_fontsize(4) 636 newlab.set_rotation('vertical') 637 # newlab.set_horizontalalignment('left') 638 # newlab.set_verticalalignment('bottom') 639 newlab.set_zorder(0) # XXX: 放在底层 640 # newlab.set_verticalalignment('center') 641 642 643 644 #================================================================================================================================================== 645 #================================================================================================================================================== 646 #======= 647 #======= XXX: 第二条 K 线图 648 #======= 649 #================================================================================================================================================== 650 #================================================================================================================================================== 651 652 # 添加 Axes 对象 653 #================================================================================================================================================== 654 axes_1_sec= axes_1.twinx() 655 # axes_1_sec.set_axisbelow(True) # 网格线放在底层 656 657 axes_1_sec.set_yscale('log', basey=expbase) # 使用对数坐标 658 659 660 # 得到 X 轴 和 Y 轴 的两个 Axis 对象 661 #================================================================================================================================================== 662 xaxis_1_sec= axes_1_sec.get_xaxis() 663 yaxis_1_sec= axes_1_sec.get_yaxis() 664 665 666 667 #================================================================================================================================================== 668 #======= 绘图 669 #================================================================================================================================================== 670 671 # 绘制 K 线部分 672 #================================================================================================================================================== 673 674 # 对开收盘价进行视觉修正 675 for idx, poc in enumerate( zipoc_sec ): 676 if poc[0] == poc[1] and None not in poc: 677 pdata[u'开盘二'][idx]= poc[0] - 5 # 稍微偏离一点,使得在图线上不致于完全看不到 678 pdata[u'收盘二'][idx]= poc[1] + 5 679 680 rarray_open= numpy.array(pdata[u'开盘二']) 681 rarray_close= numpy.array(pdata[u'收盘二']) 682 rarray_high= numpy.array(pdata[u'最高二']) 683 rarray_low= numpy.array(pdata[u'最低二']) 684 685 # XXX: 如果 up_sec, down_sec, side_sec 里有一个全部为 False 组成,那么 vlines() 会报错。 686 # XXX: 可以使用 alpha 参数调节透明度 687 if True in up_sec: 688 axes_1_sec.vlines(xindex[up_sec], rarray_low[up_sec], rarray_high[up_sec], edgecolor='red', linewidth=0.6, label='_nolegend_', alpha=0.3) 689 axes_1_sec.vlines(xindex[up_sec], rarray_open[up_sec], rarray_close[up_sec], edgecolor='red', linewidth=3.0, label='_nolegend_', alpha=0.3) 690 691 if True in down_sec: 692 axes_1_sec.vlines(xindex[down_sec], rarray_low[down_sec], rarray_high[down_sec], edgecolor='green', linewidth=0.6, label='_nolegend_', alpha=0.3) 693 axes_1_sec.vlines(xindex[down_sec], rarray_open[down_sec], rarray_close[down_sec], edgecolor='green', linewidth=3.0, label='_nolegend_', alpha=0.3) 694 695 if True in side_sec: 696 axes_1_sec.vlines(xindex[side_sec], rarray_low[side_sec], rarray_high[side_sec], edgecolor='0.7', linewidth=0.6, label='_nolegend_', alpha=0.3) 697 axes_1_sec.vlines(xindex[side_sec], rarray_open[side_sec], rarray_close[side_sec], edgecolor='0.7', linewidth=3.0, label='_nolegend_', alpha=0.3) 698 699 700 701 # 设定 X 轴坐标的范围 702 #================================================================================================================================================== 703 axes_1_sec.set_xlim(-1, length) 704 705 706 707 # 先设置 label 位置,再将 X 轴上的坐标设为不可见。因为与 成交量子图 共用 X 轴 708 #================================================================================================================================================== 709 710 # 设定 X 轴的 Locator 和 Formatter 711 xaxis_1_sec.set_major_locator(xMajorLocator) 712 xaxis_1_sec.set_major_formatter(xMajorFormatter) 713 714 xaxis_1_sec.set_minor_locator(xMinorLocator) 715 xaxis_1_sec.set_minor_formatter(xMinorFormatter) 716 717 # 将 X 轴上的坐标设为不可见。 718 for malab in axes_1_sec.get_xticklabels(minor=False): 719 malab.set_visible(False) 720 721 for milab in axes_1_sec.get_xticklabels(minor=True): 722 milab.set_visible(False) 723 724 725 726 # 设定 Y 轴坐标的范围 727 #================================================================================================================================================== 728 axes_1_sec.set_ylim(ylowlim_price*open_price_sec/open_price_pri, yhighlim_price*open_price_sec/open_price_pri) 729 730 731 732 # 设定 Y 轴上的坐标 733 #================================================================================================================================================== 734 735 # 主要坐标点 736 #---------------------------------------------------------------------------- 737 yticks_major_sec= [] 738 ylowlim_price_sec= ylowlim_price*open_price_sec/open_price_pri 739 yhighlim_price_sec= yhighlim_price*open_price_sec/open_price_pri 740 741 for i in range(1, 999): 742 newloc= ylowlim_price_sec * (expbase**i) 743 if newloc <= yhighlim_price_sec: 744 yticks_major_sec.append(newloc) 745 else: 746 break 747 748 yMajorLocator_1_sec= FixedLocator(numpy.array(yticks_major_sec)) 749 750 # 确定 Y 轴的 MajorFormatter 751 def y_major_formatter_1_sec(num, pos=None): 752 return str(round(num/1000.0, 2)) 753 754 yMajorFormatter_1_sec= FuncFormatter(y_major_formatter_1_sec) 755 756 # 设定 X 轴的 Locator 和 Formatter 757 yaxis_1_sec.set_major_locator(yMajorLocator_1_sec) 758 yaxis_1_sec.set_major_formatter(yMajorFormatter_1_sec) 759 760 # 设定 Y 轴主要坐标点与辅助坐标点的样式 761 for mal in axes_1_sec.get_yticklabels(minor=False): 762 mal.set_fontsize(6) 763 764 765 766 # 辅助坐标点 767 #---------------------------------------------------------------------------- 768 yticks_minor_sec= [] 769 mtstart_sec= ylowlim_price_sec * (1.0+(expbase-1.0)/2) 770 for i in range(999): 771 newloc= mtstart_sec * (expbase**i) 772 if newloc <= yhighlim_price_sec: 773 yticks_minor_sec.append(newloc) 774 else: 775 break 776 777 yMinorLocator_1_sec= FixedLocator(numpy.array(yticks_minor_sec)) # XXX minor ticks 已经在上面一并设置,这里不需要了。 778 779 # 确定 Y 轴的 MinorFormatter 780 def y_minor_formatter_1_sec(num, pos=None): 781 return str(round(num/1000.0, 2)) 782 783 yMinorFormatter_1_sec= FuncFormatter(y_minor_formatter_1_sec) 784 785 # 设定 X 轴的 Locator 和 Formatter 786 yaxis_1_sec.set_minor_locator(yMinorLocator_1_sec) 787 yaxis_1_sec.set_minor_formatter(yMinorFormatter_1_sec) 788 # 设定 Y 轴主要坐标点与辅助坐标点的样式 789 for mal in axes_1_sec.get_yticklabels(minor=True): 790 mal.set_fontsize(5) 791 mal.set_color('blue') 792 793 794 795 # 显示图片 796 #================================================================================================================================================== 797 # pyplot.show() 798 799 # 保存图片 800 #================================================================================================================================================== 801 figobj.savefig(figpath, dpi=figdpi, facecolor=figfacecolor, edgecolor=figedgecolor, linewidth=figlinewidth) 802 803 804 805 if __name__ == '__main__': 806 Plot(pfile=sys.argv[1], figpath=sys.argv[2])