python用mpl_finance中的candlestick_ohlc画分时图

matplotlib.finance独立出来成为mpl_finance,而mpl_finance中的candlestick_ochl和candlestick_ohlc一般用来画股票的K线图。我需要分析分时图,也就是一分钟的行情,这个时候就不能直接用candlestick_ochl函数,因为candlestick_ochl中x轴最小的单位是日期,不是分钟。

经过对mpl_finance的源代码进行分析,问题在于matplotlib的date2num将日期转换为浮点数,浮点数的整数部分表示日期,小数部分代表小时和分钟。比如下面4个时间段是连续的分钟。

时间 date2num之后 乘以1440
2018/09/17-21:34 736954.8986 1061215054
2018/09/17-21:35 736954.8993 1061215055
2018/09/17-21:36 736954.9000 1061215056
2018/09/17-21:37 736954.9007 1061215057

可以看出date2num函数计算之后,4个时间的整数部分都是736954,导致在X轴上这4个时间段都重叠在一起,无法区分了。要达到的效果是每一个分钟也能成为一个整数,这样就可以显示出来了。那么一天是24小时,每小时60分钟,那么一天就是1440分钟,将date2num计算的浮点数乘以1440就可以将每一分钟转为整数,那么就可以在x轴上。

最后还需要对x轴格式化,因为自己对x轴进行了处理(乘以1440),采用默认的格式化是乱码。需要自定义x轴的格式化函数。

完整例子如下:

import pandas as pd
from pandas import DataFrame
import matplotlib.pyplot as plt
import matplotlib.dates as dates
import mpl_finance as mpf
from matplotlib.ticker import Formatter
import numpy as np


dfcvs = DataFrame([
    ["2018/09/17-21:34", 3646, 3650,3644,3650],
    ["2018/09/17-21:35", 3650, 3650,3648,3648],
    ["2018/09/17-21:36", 3650, 3650,3648,3650],
    ["2018/09/17-21:37", 3652, 3654,3648,3652]
])

dfcvs.columns = ['时间','开盘','最高','最低','收盘']
dfcvs['时间']=pd.to_datetime(dfcvs['时间'],format="%Y/%m/%d-%H:%M")

#matplotlib的date2num将日期转换为浮点数,整数部分区分日期,小数区分小时和分钟
#因为小数太小了,需要将小时和分钟变成整数,需要乘以24(小时)×60(分钟)=1440,这样小时和分钟也能成为整数
#这样就可以一分钟就占一个位置

 

dfcvs['时间']=dfcvs['时间'].apply(lambda x:dates.date2num(x)*1440)
data_mat=dfcvs.as_matrix()
    
fig,ax=plt.subplots(figsize=(1200/72,480/72))
 
fig.subplots_adjust(bottom=0.1)   
mpf.candlestick_ohlc(ax,data_mat,colordown='#53c156', colorup='#ff1717',width=0.2,alpha=1)

#将x轴的浮点数格式化成日期小时分钟
#默认的x轴格式化是日期被dates.date2num之后的浮点数,因为在上面乘以了1440,所以默认是错误的
#只能自己将浮点数格式化为日期时间分钟
#参考https://matplotlib.org/examples/pylab_examples/date_index_formatter.html
class MyFormatter(Formatter):
            def __init__(self, dates, fmt='%Y%m%d %H:%M'):
                self.dates = dates
                self.fmt = fmt
    
            def __call__(self, x, pos=0):
                'Return the label for time x at position pos'
                ind = int(np.round(x))
                #ind就是x轴的刻度数值,不是日期的下标

                return dates.num2date( ind/1440).strftime(self.fmt)
        
formatter = MyFormatter(data_mat[:,0])
ax.xaxis.set_major_formatter(formatter)

for label in ax.get_xticklabels():
            label.set_rotation(90)
            label.set_horizontalalignment('right')
           
plt.show()

 

展开阅读全文

没有更多推荐了,返回首页