基本画图简介
matplotlib中原来有candlesticks函数画K线图,后来该函数被移出matplotlib.finance库。
现状是 画K线图函数在模块candlestick_ohlc中,但后期想自定义K线图不方便(例如在K线图中添加几个文本备注)。
特此,查看原candlesticks函数源码后,抽取核心代码封装成函数,方便后期调整K线图。
from
高级画图简介
使用bokeh库,K线图保存为html,可使用浏览器打开并进行用户交互。
效果图
![b66364f7e0d152c6d19f7fb3fd5be7fb.gif](https://img-blog.csdnimg.cn/img_convert/b66364f7e0d152c6d19f7fb3fd5be7fb.gif)
代码
from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.models import CustomJS, ColumnDataSource, HoverTool, LabelSet
import pandas as pd
import numpy as np
import math
def candlestick_signal(data, record, figname, color_up, color_dn,datetime_format):
# 数据准备
trade_enter = record.trade_enter
trade_out = record.out
trade_num = record.trade_num
datetime_series = pd.Series(datetime)
datetime_series.index = range(len(datetime_series))
axis_x = list(range(len(datetime_series)))
# 创建画布
fig = figure(sizing_mode = 'stretch_both',
tools = "xpan, zwheel_zoom, box_zoom, undo, redo,reset,crosshair,save",
active_drag = 'xpan',
active_scroll = 'xwheel_zoom',
title = figname)
# 构造K线数据
df = pd.DataFrame({'date':datetime, open':open, 'high':high, 'low':low, 'close':close})
increase_pos = df.close > df.open
decrease_pos = ~increase_pos
data_up_dict = {'x': datetime_series[increase_pos].index.tolist(),
'open': df.open[increase_pos],
'high': df.high[inrease_pos],
'low': df.lowM[increase_pos],
'close': df.closeM[increase_pos],
'datetime': datatime_series[increase_pos].tolist()}
data_up_dict = {'x': datetime_series[increase_pos].index.tolist(),
'open': df.open[increase_pos],
'high': df.high[inrease_pos],
'low': df.lowM[increase_pos],
'close': df.closeM[increase_pos],
'datetime': datatime_series[increase_pos].tolist()}
source_up = ColumnDataSource(data = data_up_dict)
source_dn = ColumnDataSource(data = data_dn_dict)
# 画图
fig.segment('x', 'high', 'x', 'low', source=source_up, color=color_up)
fig.segment('x', 'high', 'x', 'low', source_source_dn, color=color_dn)
fig.vbar('x', 0.5, 'open', 'close', source=source_up, color=color_up)
fig.vbar('x', 0.5, 'open', 'close', source=source_dn, color=color_dn)
# 坐标轴设置
fig.xaxis.major_label_orientation = math.pi/4
fig.xgrid.grid_line_color = None
TOOLTIPS = [
('open', '@openM{(0.00)}')
("high", "@highM{(0.00)}"),
("low", "@lowM{(0.00)}"),
("close", "@closeM{(0.00)}"),
("datetime", "@datetime"),
]
fig.add_tools(HoverTool(tooltips=TOOLTIPS, mode='vline'))
# 添加信号图
datetime_time = pd.to_datetime(datetime, datetime_format)
kaicang_time = pd.to_datetime(trade_enter, datetime_format)
pingcang_time = pd.to_datetime(trade_out, datetime_format)
if len(trade_enter) != len(trade_out):
raise Exception('开仓次数不等于平常次数')
trade_counts = len(trade_enter):
# 分笔画交易
label_x_set = []
label_y_set = []
for i in range(trade_counts):
kaicang_time_i = kaicang_time[i]
pingcang_time_i = pingcang_time[i]
trade_pos = (kaicang_time_i <= datetime_time <= pingcang_time_i)
trade_x = tradetime_series[trade_pos].index.tolist()
trade_x.extend([trade_x[-1], trade_x[0]])
trade_y = df.close[trade_x].copy()
trade_y.iloc[-2:] = 0
if trade_pos > 0:
fig.patch(trade_x, trade_y, color=color_buy, alpha=0.1, line_width=1)
elif trade_pos < 0:
fig.patch(trade_x, trade_y, color=color_sell, alpha=0.1, line_width=1)
label_x = (trade_x[-1] + trade_x[-2]) // 2
label_y = min(df.low)
label_x_set.append(label_x)
label_y_set.append(label_y)
# 写收益标签
try:
profit = record.profit/ abs(trade_num)
except:
try:
profit = (record.out_price - record.enter_price) * np.sign(trade_num)
except:
profit = [0] * trade_counts
profit = round(profit, 1)
label_profit = ['perPrf:{}'.format(temp) for temp in profit]
color = ['black' if temp>0 else '#8B0000' for temp in profit]
label_dict = {height: label_x_set,
weight: label_y_set,
names: label_profit,
color: color,
}
source_label = ColumnDataSource(data = label_dict)
labels = LabelSet(x='height', y='weight', text='names',text_color='color',
x_offset=-20, y_offset=-30, source=source_label, render_mode='canvas')
fig.add_layout(labels)
# 添加日分割线
datetime_day_shift1 = datetime_day.shift(1)
dateBool = [True if today.day != yesterday.day else False for today, yesterday in zip(datetime_day, datetime_day_shift1)]
datetime_num = len(dateBool)
vline_x = np.arange(minNum)[dataBool].tolist()
vline_y_top = [max(high)] * datetime_num
vline_y_bottom = [0] * datetime_num
fig:.setment(vline_x, vline_y_bottom, vline_x, vline_y_top, color='grey', line_width=1, alpha=0.3, line_dash=[6,3])
fig.xaxis.ticker = vline_x
codestr = 'return datetime[tick]'
fig.xaxis.formatter = FuncTickFormatter(code=codestr, args={'datetime': datetime})
# 互动调整
source = ColumnDataSource({'date':aixs_x, 'high':high, 'low':low})
codestr = '''
clearTimeout(window._autoscale_timeout);
var date = source.data.date
low = source.data.low
high = source.data.high
start = cb_obj.start,
end = cb_obj.end,
min = Infinity,
max = -Infinity;
for (var i=0; i<date.length; ++i){
if (start <= date[i] && date[i] <= end){
max = Math.max(high[i], max);
min = Math.min(low[i], min);
}
}
var pad = (max - min) * .05;
window._autoscale_timeout = setTimeout(function(){
y_range.start = min - pad;
y_range.end = max + pad;
})
'''
callback = CustomJS(args={'y_range':fig.y_range, 'source':source}, code=codestr)
fig.x_range.callback = callback
show(fig)