python金融数据分析和可视化--06_03用mplfinance金融数据可视化(下)

05_02用mplfinance金融数据可视化(下)

用mplfinance实现全功能K线图

目标
在开始实际工作之前,需要确定我们需要达到的目标,以便一步步实现:

  • 符合中国习惯的配色风格——红涨绿跌自然是必须实现的第一步
  • 图表上要能显示股票代码和股票名称、以及价格信息
  • 图表上要显示完整的移动平均线
  • 在交易量的下方显示第三张图表,同步显示相关指标如MACD等

下面我们就来一一实现上面的功能,随着本文的逐步完善。

实现自定义风格和颜色

这肯定是上面的所有功能中最容易实现的一个。mplfinance提供了两个相关的函数:make_mpf_style 以及make_marketcolors。示例如下:

import mplfinance as mpf
# 设置mplfinance的蜡烛颜色,up为阳线颜色,down为阴线颜色
my_color = mpf.make_marketcolors(up='r',
                                 down='g',
                                 edge='inherit',
                                 wick='inherit',
                                 volume='inherit')
# 设置图表的背景色
my_style = mpf.make_mpf_style(marketcolors=my_color,
                              figcolor='(0.82, 0.83, 0.85)',
                              gridcolor='(0.82, 0.83, 0.85)')

在make_marketcolors函数中,几个不同的参数主要用于设置K线的颜色,up 和down都很明显,用于分别指定上涨K线和下跌K线的颜色。因此根据国内习惯自然应该设置up=‘r'也就是red红色,down自然就是’g'也就是‘green’绿色。不过需要注意的是这里仅仅设置K线的柱子的内部填充色,如果不指定边框、上下影线的颜色,他们都会是黑色,显示的效果就是黑色的边框、黑色的上下影线,挺难看的,因此还需要设置边框"edge"的颜色。此处设置为“in”或“inherit”代表“使用主配色“。也就是说,阳线(上涨)的柱子外框线跟阳线的内部填充色一致,那么如果阳线的颜色为红色,边框的颜色也是红色,如果阳线是绿色,则边框也是绿色。阴线也一样。
wick设置的就是上下影线的颜色,这里为了显眼,同样设置为”in“。
类似的,volume设置的是交易量柱子的颜色,也设置为”in“就可以了。

有朋友可能想问,如果我不喜欢标准的红绿色配色,觉得太鲜艳了,想改成自定义的RGB配色可不可以,当然可以,不过需要注意的是,在标准的matplotlib中,可以传入一个元组表示RGB配色,例如(0.5, 0.8, 0.6)然而mpf不能直接传递元组作为颜色代码,但可以接受一个表示元组的字符串,如上面代码中的figcolor='(0.82, 0.83, 0.85)'。

make_mpf_style()函数接受上面的参数,将所有的配置都存储在一个字典中,然后使用mpf的基本绘图方法,就可以生成一张符合中国股市习惯的K线图了。

准备数据:

import pandas as pd
import os
import numpy as np
import matplotlib # 注意这个也要import一次
import matplotlib.pyplot as plt
import talib


# 文件路径和名称
file_name = os.path.join(os.path.join(os.getcwd(), "datas/days"), "000012.SZ.csv")
# 读取CSV文件
df = pd.read_csv(file_name)
# 取需要的数据
df = df[['trade_date', 'open', 'close', 'high', 'low', 'vol', 'amount', 'pre_close', 'change', 'pct_chg']]
# 重命名
df.columns = ['date', 'open', 'close', 'high', 'low', 'volume', 'amount', 'pre_close', 'change', 'pct_chg']
# 涨停价
df['upper_lim'] = np.round(df['close'] * 1.10)
# 跌停价
df['lower_lim'] = np.round(df['close'] * 0.90)
df['average'] = np.round((df['high']+df['low']) / 2)
# 用talib计算MACD
df['macd_dif'], df['macd_dea'], df['macd_m'] = np.round(talib.MACD(df['close'], fastperiod=12,
                                                               slowperiod=26, signalperiod=9), 
                                                        2)
df['macd_macd'] = 2 * df['macd_m']
# 分别计算5日、10日、20日、60日的移动平均线
ma_list = [5, 10, 20, 60]
# 计算简单算术移动平均线MA
for ma in ma_list:
    df['MA' + str(ma)] = np.round(talib.SMA(df['close'], ma),2)
# 转换Date为日期格式
df['date'] = pd.to_datetime(df['date'])
# 设置Date为索引
df.set_index('date', inplace=True)
out_file_name = os.path.join(os.path.join(os.getcwd(), "datas/days"), "000012.csv")
df.to_csv(out_file_name)
# 文件路径和名称
file_name = os.path.join(os.path.join(os.getcwd(), "datas/days"), "000012.csv")
# 读取CSV文件
data = pd.read_csv(file_name)
# 转换Date为日期格式
data['date'] = pd.to_datetime(data['date'])
# 设置Date为索引
data.set_index('date', inplace=True)

绘制K线图

mpf.plot(data.iloc[100:200], style=my_style, type='candle', volume=True)

输出结果:

上面的代码从本地读取测试数据后,将其中一部分显示在K线图中,如上图所示,红涨绿跌。这就是符合国内习惯的K线图了。

图表尺寸调整、相关信息的显示

有了符合中国股市习惯配色风格的K线图,接下来需要调整图表尺寸,同时显示价格信息。
在mplfinance的默认设置下,K线图会显示两张图表,K线图在上,交易量柱状图在下。实际上在大多数情况下,还需要第三张图表以显示一些相关的指标如KDJ,MACD等等,另外,图表的顶部应该预留出一些区域用于显示价格。
因此我们必须对图表的尺寸和位置进行精确控制,然而mplfinance的基础用法是不允许我们控制每一个图表的位置的,因此就必须使用mplfinance提供的另一种用法“External Axes Mode“,在这种模式下,我们可以像使用matplotlib一样直接控制画布上的每一个图标元素和文字元素,获得更大的操作自由。
为了实现自由控制,需要获取图表的figure对象,然后手动在figure上放置图表Axes和文字Text,文字和图表的位置、大小、格式完全自定义,下面是代码:

# data是测试数据,可以直接下载后读取,在下例中只显示其中100个交易日的数据
plot_data = data.iloc[-100:]
# 读取显示区间最后一个交易日的数据
last_data = plot_data.iloc[-1]
# 使用mpf.figure()函数可以返回一个figure对象,从而进入External Axes Mode,从而实现对Axes对象和figure对象的自由控制
fig = mpf.figure(style=my_style, figsize=(12, 8), facecolor=(0.82, 0.83, 0.85))
# 添加三个图表,四个数字分别代表图表左下角在figure中的坐标,以及图表的宽(0.88)、高(0.60)
ax1 = fig.add_axes([0.06, 0.25, 0.88, 0.60])
# 添加第二、三张图表时,使用sharex关键字指明与ax1在x轴上对齐,且共用x轴
ax2 = fig.add_axes([0.06, 0.15, 0.88, 0.10], sharex=ax1)
ax3 = fig.add_axes([0.06, 0.05, 0.88, 0.10], sharex=ax1)
# 设置三张图表的Y轴标签
ax1.set_ylabel('price')
ax2.set_ylabel('volume')
ax3.set_ylabel('macd')
# 在figure对象上添加文本对象,用于显示各种价格和标题
fig.text(0.50, 0.94, '513100.SH - 纳指ETF:')
fig.text(0.12, 0.90, '开/收: ')
fig.text(0.14, 0.89, f'{np.round(last_data["open"], 3)} / {np.round(last_data["close"], 3)}')
fig.text(0.14, 0.86, f'{last_data["change"]}')
fig.text(0.22, 0.86, f'[{np.round(last_data["pct_chg"], 2)}%]')
fig.text(0.12, 0.86, f'{last_data.name.date()}')
fig.text(0.40, 0.90, '高: ')
fig.text(0.40, 0.90, f'{last_data["high"]}')
fig.text(0.40, 0.86, '低: ')
fig.text(0.40, 0.86, f'{last_data["low"]}')
fig.text(0.55, 0.90, '量(万手): ')
fig.text(0.55, 0.90, f'{np.round(last_data["volume"] / 10000, 3)}')
fig.text(0.55, 0.86, '额(亿元): ')
# fig.text(0.55, 0.86, f'{last_data["Value"]}')
# fig.text(0.70, 0.90, '涨停: ')
# fig.text(0.70, 0.90, f'{last_data["upper_lim"]}')
# fig.text(0.70, 0.86, '跌停: ')
# fig.text(0.70, 0.86, f'{last_data["lower_lim"]}')
# fig.text(0.85, 0.90, '均价: ')
# fig.text(0.85, 0.90, f'{np.round(last_data["average"], 3)}')
# fig.text(0.85, 0.86, '昨收: ')
# fig.text(0.85, 0.86, f'{last_data["last_close"]}')
# 调用mpf.plot()函数,注意调用的方式跟上一节不同,这里需要指定ax=ax1,volume=ax2,将K线图显示在ax1中,交易量显示在ax2中
mpf.plot(plot_data,
         ax=ax1,
         volume=ax2,
         type='candle',
         style=my_style)
plt.show()

输出结果:

在External Axes Mode模式下,由于我们手动创建了几个Axes对象(这也就是External Axes Mode的由来),调用mpf.plot()函数,注意调用的方式跟上一节不同,这里需要指定ax=ax1, volume=ax2,将K线图显示在ax1中,交易量显示在ax2中。
通过运行上面的代码得到上面的图表:

可以看到,图表的格式和数量都正确了,三个Axes分别用于显示K线图、交易量以及指标(暂时还未显示),最后一个交易日的价格显示在顶部区域,但是有两个问题:

数字的格式和颜色不对,应该用红绿色区分不同的价格,字体大小也需要设置正确的格式
中文显示为乱码,需要设法使mplfinance支持utf-8编码格式的字符串

为了解决第一个问题,我们可以预设几种不同的格式备用,而第二个问题的原因在于使用的字体不支持中文,只要使用支持中文的字体就可以了。因此,可以分别定义下面几种字体,分别用于标题(黑色大字),开盘价/收盘价(大字体数字)和普通字体,每种字体都有红色和绿色两个版本:

# 标题格式,字体为中文字体,颜色为黑色,粗体,水平中心对齐
title_font = {'fontname': 'SimHei', 
              'size':     '16',
              'color':    'black',
              'weight':   'bold',
              'va':       'bottom',
              'ha':       'center'}
# 红色数字格式(显示开盘收盘价)粗体红色24号字
large_red_font = {'fontname': 'Arial',
                  'size':     '24',
                  'color':    'red',
                  'weight':   'bold',
                  'va':       'bottom'}
# 绿色数字格式(显示开盘收盘价)粗体绿色24号字
large_green_font = {'fontname': 'Arial',
                    'size':     '24',
                    'color':    'green',
                    'weight':   'bold',
                    'va':       'bottom'}
# 小数字格式(显示其他价格信息)粗体红色12号字
small_red_font = {'fontname': 'Arial',
                  'size':     '12',
                  'color':    'red',
                  'weight':   'bold',
                  'va':       'bottom'}
# 小数字格式(显示其他价格信息)粗体绿色12号字
small_green_font = {'fontname': 'Arial',
                    'size':     '12',
                    'color':    'green',
                    'weight':   'bold',
                    'va':       'bottom'}
# 标签格式,可以显示中文,普通黑色12号字
normal_label_font = {'fontname': 'SimHei',
                     'size':     '12',
                     'color':    'black',
                     'va':       'bottom',
                     'ha':       'right'}
# 普通文本格式,普通黑色12号字
normal_font = {'fontname': 'Arial',
               'size':     '12',
               'color':    'black',
               'va':       'bottom',
               'ha':       'left'}
#内嵌画图
%matplotlib inline
# data是测试数据,可以直接下载后读取,在下例中只显示其中100个交易日的数据
plot_data = data.iloc[-120:]
# 读取显示区间最后一个交易日的数据
last_data = plot_data.iloc[-1]
# 使用mpf.figure()函数可以返回一个figure对象,从而进入External Axes Mode,从而实现对Axes对象和figure对象的自由控制
fig = mpf.figure(style=my_style, figsize=(16, 10), facecolor=(0.82, 0.83, 0.85))
ax1 = fig.add_axes([0.06, 0.25, 0.88, 0.60])
ax2 = fig.add_axes([0.06, 0.15, 0.88, 0.10], sharex=ax1)
ax3 = fig.add_axes([0.06, 0.05, 0.88, 0.10], sharex=ax1)
ax1.set_ylabel('price')
ax2.set_ylabel('volume')
ax3.set_ylabel('macd')
# 设置显示文本的时候,返回文本对象
# 对不同的文本采用不同的格式
t1 = fig.text(0.50, 0.94, '513100.SH - 纳指ETF:', **title_font)
t2 = fig.text(0.12, 0.90, '开/收: ', **normal_label_font)
t3 = fig.text(0.14, 0.89, f'{np.round(last_data["open"], 3)} / {np.round(last_data["close"], 3)}', **large_red_font)
t4 = fig.text(0.14, 0.86, f'{last_data["change"]}', **small_red_font)
t5 = fig.text(0.22, 0.86, f'[{np.round(last_data["pct_chg"], 2)}%]', **small_red_font)
t6 = fig.text(0.12, 0.86, f'{last_data.name.date()}', **normal_label_font)
t7 = fig.text(0.40, 0.90, '高: ', **normal_label_font)
t8 = fig.text(0.40, 0.90, f'{last_data["high"]}', **small_red_font)
t9 = fig.text(0.40, 0.86, '低: ', **normal_label_font)
t10 = fig.text(0.40, 0.86, f'{last_data["low"]}', **small_green_font)
t11 = fig.text(0.55, 0.90, '量(万手): ', **normal_label_font)
t12 = fig.text(0.55, 0.90, f'{np.round(last_data["volume"] / 10000, 3)}', **normal_font)
t13 = fig.text(0.55, 0.86, '额(亿元): ', **normal_label_font)
t14 = fig.text(0.55, 0.86, f'{last_data["amount"]}', **normal_font)
t15 = fig.text(0.70, 0.90, '涨停: ', **normal_label_font)
t16 = fig.text(0.70, 0.90, f'{last_data["upper_lim"]}', **small_red_font)
t17 = fig.text(0.70, 0.86, '跌停: ', **normal_label_font)
t18 = fig.text(0.70, 0.86, f'{last_data["lower_lim"]}', **small_green_font)
t19 = fig.text(0.85, 0.90, '均价: ', **normal_label_font)
t20 = fig.text(0.85, 0.90, f'{np.round(last_data["average"], 3)}', **normal_font)
t21 = fig.text(0.85, 0.86, '昨收: ', **normal_label_font)
t22 = fig.text(0.85, 0.86, f'{last_data["pre_close"]}', **normal_font)

mpf.plot(plot_data,
         ax=ax1,
         volume=ax2,
         type='candle',
         style=my_style)
plt.show()

输出结果:

有的朋友在运行上述代码时,可能会遇到错误说使用的中文字体不存在,因而还是显示乱码,这里给出一个解决方案供大家参考:

为了显示系统中有哪些中文字体,可以先导入matplotlib的FontManager类,调用这个类的ttflist属性,就可以看到系统中已经存在的所有可以被matplotlib使用的字体了,选择其中的中文字体即可(中文字体名称中一般都带有拼音,或者含有TC、SC之类的关键字):

from matplotlib.font_manager import FontManager
fm = FontManager()
fm.ttflist

输出结果:

添加完整移动平均线

在mplfinance的标准plot()方法中,有一个mav参数,接受一个整数元组或列表,代表不同的移动平均线的天数,如[5, 20, 60]代表绘制三条均线,分别为5日、20日和60日均线。

然而,直接传入mav参数后绘制的移动平均线是不完整的,在图表的最初一段时间内没有均线,因为mplfinance没有足够的数据计算完整均线。如果要显示完整的均线,就必须提前计算好均线数据,然后再添加到K线图中。

在mplfinance中,添加更多的数据和均线到K线图中,不管是移动平均线,指标、买卖点、还是布林带线等等信息,都需要用到addplot。

通过data[['MA5', 'MA10', 'MA20', 'MA60']]就可以访问了,我们现在通过make_addplot()方法把这几条均线添加到ax1中:

# data是测试数据,可以直接下载后读取,在下例中只显示其中100个交易日的数据
plot_data = data.iloc[-120:]
# 读取显示区间最后一个交易日的数据
last_data = plot_data.iloc[-1]
# 使用mpf.figure()函数可以返回一个figure对象,从而进入External Axes Mode,从而实现对Axes对象和figure对象的自由控制
fig = mpf.figure(style=my_style, figsize=(16, 10), facecolor=(0.82, 0.83, 0.85))
ax1 = fig.add_axes([0.06, 0.25, 0.88, 0.60])
ax2 = fig.add_axes([0.06, 0.15, 0.88, 0.10], sharex=ax1)
ax3 = fig.add_axes([0.06, 0.05, 0.88, 0.10], sharex=ax1)
ax1.set_ylabel('price')
ax2.set_ylabel('volume')
ax3.set_ylabel('macd')
# 设置显示文本的时候,返回文本对象
# 对不同的文本采用不同的格式
t1 = fig.text(0.50, 0.94, '513100.SH - 纳指ETF:', **title_font)
t2 = fig.text(0.12, 0.90, '开/收: ', **normal_label_font)
t3 = fig.text(0.14, 0.89, f'{np.round(last_data["open"], 3)} / {np.round(last_data["close"], 3)}', **large_red_font)
t4 = fig.text(0.14, 0.86, f'{last_data["change"]}', **small_red_font)
t5 = fig.text(0.22, 0.86, f'[{np.round(last_data["pct_chg"], 2)}%]', **small_red_font)
t6 = fig.text(0.12, 0.86, f'{last_data.name.date()}', **normal_label_font)
t7 = fig.text(0.40, 0.90, '高: ', **normal_label_font)
t8 = fig.text(0.40, 0.90, f'{last_data["high"]}', **small_red_font)
t9 = fig.text(0.40, 0.86, '低: ', **normal_label_font)
t10 = fig.text(0.40, 0.86, f'{last_data["low"]}', **small_green_font)
t11 = fig.text(0.55, 0.90, '量(万手): ', **normal_label_font)
t12 = fig.text(0.55, 0.90, f'{np.round(last_data["volume"] / 10000, 3)}', **normal_font)
t13 = fig.text(0.55, 0.86, '额(亿元): ', **normal_label_font)
t14 = fig.text(0.55, 0.86, f'{last_data["amount"]}', **normal_font)
t15 = fig.text(0.70, 0.90, '涨停: ', **normal_label_font)
t16 = fig.text(0.70, 0.90, f'{last_data["upper_lim"]}', **small_red_font)
t17 = fig.text(0.70, 0.86, '跌停: ', **normal_label_font)
t18 = fig.text(0.70, 0.86, f'{last_data["lower_lim"]}', **small_green_font)
t19 = fig.text(0.85, 0.90, '均价: ', **normal_label_font)
t20 = fig.text(0.85, 0.90, f'{np.round(last_data["average"], 3)}', **normal_font)
t21 = fig.text(0.85, 0.86, '昨收: ', **normal_label_font)
t22 = fig.text(0.85, 0.86, f'{last_data["pre_close"]}', **normal_font)
# 通过ax=ax1参数指定把新的线条添加到ax1中,与K线图重叠
ap = mpf.make_addplot(plot_data[['MA5', 'MA10', 'MA20', 'MA60']], ax=ax1)
# 调用plot()方法,注意传递addplot=ap参数,以添加均线
mpf.plot(plot_data,
         ax=ax1,
         volume=ax2,
         addplot=ap,
         type='candle',
         style=my_style)
plt.show()

输出结果:

添加指标MACD

至此,一个静态的实用K线图已经初具雏形了,不过,ax3还是空的,这里本来应该显示MACD指标的,那么如何实现呢?自然还是需要addplot()! 不过,在开始之前,我们要知道,MACD指标包含两条线,还有一组柱状图,而且柱状图还分红绿两色,不是一个简单的图形,需要分别绘制。在mplfinance中,addplot可以是一个字典,也可以是一个列表,列表中包含多组不同的addplot,这样在调用mpf.plot()的时候,可以传入任意多个addplot,从而实现复杂的图表形式。

在本文的测试数据中,已经计算好了用于MACD的数据,分别存放在data[['macd_m', 'macd_h', 'macd_s']]中,addplot应该按照以下方法设置:

# data是测试数据,可以直接下载后读取,在下例中只显示其中100个交易日的数据
plot_data = data.iloc[-120:]
# print(plot_data.head())>
# 读取显示区间最后一个交易日的数据
last_data = plot_data.iloc[-1]
# 使用mpf.figure()函数可以返回一个figure对象,从而进入External Axes Mode,从而实现对Axes对象和figure对象的自由控制
fig = mpf.figure(style=my_style, figsize=(16, 10), facecolor=(0.82, 0.83, 0.85))
ax1 = fig.add_axes([0.06, 0.25, 0.88, 0.60])
ax2 = fig.add_axes([0.06, 0.15, 0.88, 0.10], sharex=ax1)
ax3 = fig.add_axes([0.06, 0.05, 0.88, 0.10], sharex=ax1)
ax1.set_ylabel('price')
ax2.set_ylabel('volume')
ax3.set_ylabel('macd')
# 设置显示文本的时候,返回文本对象
# 对不同的文本采用不同的格式
t1 = fig.text(0.50, 0.94, '513100.SH - 纳指ETF:', **title_font)
t2 = fig.text(0.12, 0.90, '开/收: ', **normal_label_font)
t3 = fig.text(0.14, 0.89, f'{np.round(last_data["open"], 3)} / {np.round(last_data["close"], 3)}', **large_red_font)
t4 = fig.text(0.14, 0.86, f'{last_data["change"]}', **small_red_font)
t5 = fig.text(0.22, 0.86, f'[{np.round(last_data["pct_chg"], 2)}%]', **small_red_font)
t6 = fig.text(0.12, 0.86, f'{last_data.name.date()}', **normal_label_font)
t7 = fig.text(0.40, 0.90, '高: ', **normal_label_font)
t8 = fig.text(0.40, 0.90, f'{last_data["high"]}', **small_red_font)
t9 = fig.text(0.40, 0.86, '低: ', **normal_label_font)
t10 = fig.text(0.40, 0.86, f'{last_data["low"]}', **small_green_font)
t11 = fig.text(0.55, 0.90, '量(万手): ', **normal_label_font)
t12 = fig.text(0.55, 0.90, f'{np.round(last_data["volume"] / 10000, 3)}', **normal_font)
t13 = fig.text(0.55, 0.86, '额(亿元): ', **normal_label_font)
t14 = fig.text(0.55, 0.86, f'{last_data["amount"]}', **normal_font)
t15 = fig.text(0.70, 0.90, '涨停: ', **normal_label_font)
t16 = fig.text(0.70, 0.90, f'{last_data["upper_lim"]}', **small_red_font)
t17 = fig.text(0.70, 0.86, '跌停: ', **normal_label_font)
t18 = fig.text(0.70, 0.86, f'{last_data["lower_lim"]}', **small_green_font)
t19 = fig.text(0.85, 0.90, '均价: ', **normal_label_font)
t20 = fig.text(0.85, 0.90, f'{np.round(last_data["average"], 3)}', **normal_font)
t21 = fig.text(0.85, 0.86, '昨收: ', **normal_label_font)
t22 = fig.text(0.85, 0.86, f'{last_data["pre_close"]}', **normal_font)
# 生成一个空列表用于存储多个addplot
ap = []
# 在ax3图表中绘制 MACD指标中的快线和慢线
ap.append(mpf.make_addplot(plot_data[['MA5', 'MA10', 'MA20', 'MA60']], ax=ax1))
# 通过ax=ax1参数指定把新的线条添加到ax1中,与K线图重叠
ap.append(mpf.make_addplot(plot_data[['macd_dif', 'macd_dea']], ax=ax3))
# 使用柱状图绘制快线和慢线的差值,根据差值的数值大小,分别用红色和绿色填充
# 红色和绿色部分需要分别填充,因此先生成两组数据,分别包含大于零和小于等于零的数据
bar_r = np.where(plot_data['macd_macd'] > 0, plot_data['macd_macd'], 0)
bar_g = np.where(plot_data['macd_macd'] <= 0, plot_data['macd_macd'], 0)
# 使用柱状图填充(type='bar'),设置颜色分别为红色和绿色
ap.append(mpf.make_addplot(bar_r, type='bar', color='red', ax=ax3))
ap.append(mpf.make_addplot(bar_g, type='bar', color='green', ax=ax3))
# 调用plot()方法,注意传递addplot=ap参数,以添加均线
mpf.plot(plot_data,
         ax=ax1,
         volume=ax2,
         addplot=ap,
         type='candle',
         style=my_style)
plt.show()

输出结果:

完整代码

import matplotlib.pyplot as plt
import pandas as pd
import os
import talib
import mplfinance as mpf
import numpy as np


class DataFinanceDraw(object):
    """
    获取数据,并按照 mplfinanace 需求的格式格式化,然后绘图
    """

    def __init__(self):
        self.data = pd.DataFrame()

    def my_data(self, file_name='002624.SZ.csv'):
        """
        获取数据,把数据格式化成mplfinance的标准格式
        """
        data = pd.read_csv(os.getcwd() + '\\datas\\days\\' + file_name)
        # 取需要的数据
        data = data[['trade_date', 'open', 'close', 'high', 'low', 'vol', 'amount', 'pre_close', 'change', 'pct_chg']]
        # 重命名
        data.columns = ['date', 'open', 'close', 'high', 'low', 'volume', 'amount', 'pre_close', 'change', 'pct_chg']
        data['upper_lim'] = np.round(data['pre_close'] * 1.10)
        data['lower_lim'] = np.round(data['pre_close'] * 0.90)
        data['average'] = np.round((data['high'] + data['low']) / 2)
        data['macd_dif'], data['macd_dea'], data['macd_m'] = np.round(talib.MACD(data['close'], fastperiod=12,
                                                                             slowperiod=26, signalperiod=9),
                                                                  2)
        data['macd_macd'] = 2 * data['macd_m']
        # 分别计算5日、10日、20日、60日的移动平均线
        ma_list = [5, 10, 20, 60]
        # 计算简单算术移动平均线MA
        for ma in ma_list:
            data['MA' + str(ma)] = np.round(talib.SMA(data['close'], ma), 2)
        # 转换Date为日期格式
        data['date'] = pd.to_datetime(data['date'])
        # 设置Date为索引
        data.set_index('date', inplace=True)
        # out_file_name = os.path.join(os.path.join(os.getcwd(), "datas/days"), "000012.csv")
        # data.to_csv(out_file_name)
        self.data = data
        return data

    def panel_draw(self):
        # 设置mplfinance的蜡烛颜色,up为阳线颜色,down为阴线颜色
        my_color = mpf.make_marketcolors(up='r',
                                         down='g',
                                         edge='inherit',
                                         wick='inherit',
                                         volume='inherit')
        # 设置图表的背景色
        my_style = mpf.make_mpf_style(marketcolors=my_color,
                                      figcolor='(0.82, 0.83, 0.85)',
                                      gridcolor='(0.82, 0.83, 0.85)')
        # 标题格式,字体为中文字体,颜色为黑色,粗体,水平中心对齐
        title_font = {'fontname': 'SimHei',
                      'size': '16',
                      'color': 'black',
                      'weight': 'bold',
                      'va': 'bottom',
                      'ha': 'center'}
        # 红色数字格式(显示开盘收盘价)粗体红色24号字
        large_red_font = {'fontname': 'Arial',
                          'size': '24',
                          'color': 'red',
                          'weight': 'bold',
                          'va': 'bottom'}
        # 绿色数字格式(显示开盘收盘价)粗体绿色24号字
        large_green_font = {'fontname': 'Arial',
                            'size': '24',
                            'color': 'green',
                            'weight': 'bold',
                            'va': 'bottom'}
        # 小数字格式(显示其他价格信息)粗体红色12号字
        small_red_font = {'fontname': 'Arial',
                          'size': '12',
                          'color': 'red',
                          'weight': 'bold',
                          'va': 'bottom'}
        # 小数字格式(显示其他价格信息)粗体绿色12号字
        small_green_font = {'fontname': 'Arial',
                            'size': '12',
                            'color': 'green',
                            'weight': 'bold',
                            'va': 'bottom'}
        # 标签格式,可以显示中文,普通黑色12号字
        normal_label_font = {'fontname': 'SimHei',
                             'size': '12',
                             'color': 'black',
                             'va': 'bottom',
                             'ha': 'right'}
        # 普通文本格式,普通黑色12号字
        normal_font = {'fontname': 'Arial',
                       'size': '12',
                       'color': 'black',
                       'va': 'bottom',
                       'ha': 'left'}

        data = self.data.iloc[-120:]
        plot_data = data
        # print(plot_data.head())>
        # 读取显示区间最后一个交易日的数据
        last_data = plot_data.iloc[-2]
        # 使用mpf.figure()函数可以返回一个figure对象,从而进入External Axes Mode,从而实现对Axes对象和figure对象的自由控制
        fig = mpf.figure(style=my_style, figsize=(16, 10), facecolor=(0.82, 0.83, 0.85))
        ax1 = fig.add_axes([0.06, 0.25, 0.88, 0.60])
        ax2 = fig.add_axes([0.06, 0.15, 0.88, 0.10], sharex=ax1)
        ax3 = fig.add_axes([0.06, 0.05, 0.88, 0.10], sharex=ax1)
        ax1.set_ylabel('price')
        ax2.set_ylabel('volume')
        ax3.set_ylabel('macd')
        # 设置显示文本的时候,返回文本对象
        # 对不同的文本采用不同的格式
        t1 = fig.text(0.50, 0.94, '002624.SZ - 完美世界', **title_font)
        t2 = fig.text(0.12, 0.90, '开/收: ', **normal_label_font)
        t3 = fig.text(0.14, 0.89, f'{np.round(last_data["open"], 3)} / {np.round(last_data["close"], 3)}',
                      **large_red_font)
        t4 = fig.text(0.14, 0.86, f'{last_data["change"]}', **small_red_font)
        t5 = fig.text(0.22, 0.86, f'[{np.round(last_data["pct_chg"], 2)}%]', **small_red_font)
        t6 = fig.text(0.12, 0.86, f'{last_data.name.date()}', **normal_label_font)
        t7 = fig.text(0.40, 0.90, '高: ', **normal_label_font)
        t8 = fig.text(0.40, 0.90, f'{last_data["high"]}', **small_red_font)
        t9 = fig.text(0.40, 0.86, '低: ', **normal_label_font)
        t10 = fig.text(0.40, 0.86, f'{last_data["low"]}', **small_green_font)
        t11 = fig.text(0.55, 0.90, '量(万手): ', **normal_label_font)
        t12 = fig.text(0.55, 0.90, f'{np.round(last_data["volume"] / 10000, 3)}', **normal_font)
        t13 = fig.text(0.55, 0.86, '额(亿元): ', **normal_label_font)
        t14 = fig.text(0.55, 0.86, f'{last_data["amount"]}', **normal_font)
        t15 = fig.text(0.70, 0.90, '涨停: ', **normal_label_font)
        t16 = fig.text(0.70, 0.90, f'{last_data["upper_lim"]}', **small_red_font)
        t17 = fig.text(0.70, 0.86, '跌停: ', **normal_label_font)
        t18 = fig.text(0.70, 0.86, f'{last_data["lower_lim"]}', **small_green_font)
        t19 = fig.text(0.85, 0.90, '均价: ', **normal_label_font)
        t20 = fig.text(0.85, 0.90, f'{np.round(last_data["average"], 3)}', **normal_font)
        t21 = fig.text(0.85, 0.86, '昨收: ', **normal_label_font)
        t22 = fig.text(0.85, 0.86, f'{last_data["pre_close"]}', **normal_font)
        # 生成一个空列表用于存储多个addplot
        ap = [mpf.make_addplot(plot_data[['MA5', 'MA10', 'MA20', 'MA60']], ax=ax1),
              mpf.make_addplot(plot_data[['macd_dif', 'macd_dea']], ax=ax3)]
        # 在ax3图表中绘制 MACD指标中的快线和慢线
        # 通过ax=ax1参数指定把新的线条添加到ax1中,与K线图重叠
        # 使用柱状图绘制快线和慢线的差值,根据差值的数值大小,分别用红色和绿色填充
        # 红色和绿色部分需要分别填充,因此先生成两组数据,分别包含大于零和小于等于零的数据
        bar_r = np.where(plot_data['macd_macd'] > 0, plot_data['macd_macd'], 0)
        bar_g = np.where(plot_data['macd_macd'] <= 0, plot_data['macd_macd'], 0)
        # 使用柱状图填充(type='bar'),设置颜色分别为红色和绿色
        ap.append(mpf.make_addplot(bar_r, type='bar', color='red', ax=ax3))
        ap.append(mpf.make_addplot(bar_g, type='bar', color='green', ax=ax3))
        # 调用plot()方法,注意传递addplot=ap参数,以添加均线
        mpf.plot(plot_data,
                 ax=ax1,
                 volume=ax2,
                 addplot=ap,
                 type='candle',
                 datetime_format='%Y-%m-%d',
                 style=my_style)
        plt.show()


if __name__ == "__main__":
    candle = DataFinanceDraw()
    candle.my_data('002624.SZ.csv')
    candle.panel_draw()
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值