Sure…
The CSV files are attached.
import pandas as pd
from bokeh.io import show
from bokeh.plotting import figure
from bokeh.transform import factor_cmap
from bokeh.models import ColumnDataSource, \
FuncTickFormatter, \
DatetimeTickFormatter
#from bokeh.sampledata.stocks import GOOG
read a CSV file
def read_csv(filename):
dataframes have an datetime index: “DateTimeSecs”
date_column = [“DateTimeSecs”]
index_column = “DateTimeSecs”
df = pd.read_csv(filename, parse_dates = date_column).set_index(index_column)
return df
plot candlestick chart
def plot_ohlcv(df):
df[‘inc’] = (df.open < df.close).astype(int).astype(str)
df[‘date’] = pd.to_datetime(df[‘date’]) # Have real dates in ‘date’ column
df[‘date’] = df.index # only assing the index to new column: “date”
df.reset_index(drop=True, inplace=True) # And a simple range(0,n) index
source = ColumnDataSource(df)
Axis type must be linear and df.index a simple range index
p = figure(x_axis_type=‘linear’,
plot_width=1000,
tools=‘pan,wheel_zoom’,
active_scroll=‘wheel_zoom’,
active_drag=‘pan’)
Plot high-low segment and candles, colored appropriately
p.segment(‘index’, ‘high’, ‘index’, ‘low’, source=source, color=“black”)
p.vbar(‘index’, .7, ‘open’, ‘close’, source=source, line_color=‘black’,
fill_color=factor_cmap(‘inc’, [‘tomato’, ‘lime’], [‘0’, ‘1’]))
Override x axis formatter with a custom JS function formatter
Could avoid using FuncTickFormatter if GH-4272 were available
p.xaxis.formatter = FuncTickFormatter(
args=dict(
We pass in the x axis itself, so we can access its
ticks values
axis=p.xaxis[0],
An instance of DatetimeTickFormatter to nicely format
arbitrary precision datetimes
formatter=DatetimeTickFormatter(days=[‘%d %b’, ‘%a %d’],
months=[‘%m/%Y’, “%b %y”]),
Our column data source with ‘date’ column we will
map indexes through
source=source,
),
code=“”"
// We override this axis’ formatter’s doFormat
method
// with one that maps index ticks to dates. Some of those dates
// are undefined (e.g. those whose ticks fall out of defined data
// range) and we must filter out and account for those, otherwise
// the formatter computes invalid visible span and returns some
// labels as ‘ERR’.
// Note, after this assignment statement, on next plot redrawing,
// our override doFormat
will be called directly
// – FunctionTickFormatter.doFormat(), i.e. this code, no longer
// executes.
axis.formatter.doFormat = function (ticks) {
const dates = ticks.map(i => source.data.date[i]),
valid = t => t !== undefined,
labels = formatter.doFormat(dates.filter(valid));
let i = 0;
return dates.map(t => valid(t) ? labels[i++] : ‘’);
};
// Before the second redrawing when above doFormat will be called,
// we are still within this current labels formatting.
// FuncTickFormatter gets passed a single tick
at a time, but
// DatetimeTickFormatter requires all ticks at once to work.
// We handle that by formatting all axis’ ticks with the function
// we constructed above and then just taking out the current tick.
// Note: .tick_coords probably not public API
const ticks = axis.tick_coords.major[0],
labels = axis.formatter.doFormat(ticks);
return labels[ticks.indexOf(tick)];
“”")
return p
Plot a glyph (small vbar) in EVERY CANDLE.
It marks the price where the maximum volume is traded.
def plot_candle_vpoc(df, p):
df[‘date’] = df.index # Have real dates in ‘date’ column
df.reset_index(drop=True, inplace=True) # And a simple range(0,n) index
create a small vbar
size = 0.00001
df[“vpoc_max_top”] = df[“vpoc_max”] + size
df[“vpoc_max_bottom”] = df[“vpoc_max”] - size
source = ColumnDataSource(df)
p.vbar(‘index’, .7, ‘vpoc_max_bottom’, ‘vpoc_max_top’, source=source, line_color=‘black’,fill_color=“black”)
return p
Plot a small glyph (small vbar, but MORE GREATER THAN glyphs in previous function)
Similar to candle VPOC, but only marks ONE CANDLE EVERY DAY:
the price where the maximum volume is traded in that day.
def plot_cluster(df, p):
df[‘date’] = df.index # Have real dates in ‘date’ column
df.reset_index(drop=True, inplace=True) # And a simple range(0,n) index
create a small vbar
size = 0.00001
df[“vpoc_max_top”] = df[“vpoc_max”] + size
df[“vpoc_max_bottom”] = df[“vpoc_max”] - size
source = ColumnDataSource(df)
p.vbar(‘index’, 2, ‘vpoc_max_bottom’, ‘vpoc_max_top’, source=source, fill_color=“red”, line_color=“green”)
return p
read the CSV’s
df_ohlcv = read_csv(“df_ohlcv.csv”)
df_candle_vpoc = read_csv(“df_candle_vpoc.csv”)
df_max_cluster_volume = read_csv(“df_max_cluster_volume.csv”)
p = plot_ohlcv(df_ohlcv) # OK, no problem
p = plot_candle_vpoc(df_candle_vpoc, p) # OK, no problem, EVERY CANDLE has a VPOC
p = plot_cluster(df_max_cluster_volume, p) # PROBLEM: every day only ONE CANDLE has the maximum volume
show(p)
``
The OHLC plot is OK.
The Candle VPOC plot is OK (every candle has a small glyph, a black vbar).
The maximum cluster of volume plot is wrong. Only one candle a day needs to be marked. The glyph is plotted in the left side of the chart
Thanks in advance.
df_candle_vpoc.csv (78.1 KB)
df_max_cluster_volume.csv (1.16 KB)
df_ohlcv.csv (141 KB)
···
El lunes, 5 de febrero de 2018, 22:22:51 (UTC+1), Kernc escribió:
Can you share a minimal (non-)working example?