I'm plotting a candlestick chart for stock price analysis and I want to make the chart auto-scale / auto-resize when I zoom-in or zoom-out of the chart.
You can use any stock price data, below is the python code (which is working properly, main issue is in the CustomJS code):
new_bokeh_figure = partial(
figure,
x_axis_type='linear',
height = 500,
sizing_mode = "stretch_width",
# title = f'{stock}',
tools="pan,wheel_zoom,box_zoom,reset,save",
active_drag='pan',
active_scroll='wheel_zoom'
)
pad = (index[-1] - index[0]) / 20
fig_ohlc = new_bokeh_figure(
x_range=Range1d(index[0], index[-1],
min_interval=10,
bounds=(index[0] - pad,
index[-1] + pad)) if index.size > 1 else None
)
ohlc_extreme_values = dfpl[['high', 'low']].copy(deep=False)
source.add(ohlc_extreme_values.min(1), 'ohlc_low')
source.add(ohlc_extreme_values.max(1), 'ohlc_high')
custom_js_args = dict(ohlc_range=fig_ohlc.y_range,
source=source)
if plot_volume:
custom_js_args.update(volume_range=fig_volume.y_range)
Here is the CustomJS code I'm using:
fig_ohlc.x_range.js_on_change('end', CustomJS(args=custom_js_args,
code="""
if (!window._bt_scale_range) {
window._bt_scale_range = function (range, min, max, pad) {
"use strict";
if (min !== Infinity && max !== -Infinity) {
pad = pad ? (max - min) * .05 : 0;
range.start = min - pad;
range.end = max + pad;
} else console.error('backtesting: scale range error:', min, max, range);
};
}
clearTimeout(window._bt_autoscale_timeout);
window._bt_autoscale_timeout = setTimeout(function () {
/**
* @variable cb_obj `fig_ohlc.x_range`.
* @variable source `ColumnDataSource`
* @variable ohlc_range `fig_ohlc.y_range`.
* @variable volume_range `fig_volume.y_range`.
*/
"use strict";
let i = Math.max(Math.floor(cb_obj.start), 0),
j = Math.min(Math.ceil(cb_obj.end), source.data['ohlc_high'].length);
let max = Math.max.apply(null, source.data['ohlc_high'].slice(i, j)),
min = Math.min.apply(null, source.data['ohlc_low'].slice(i, j));
_bt_scale_range(ohlc_range, min, max, true);
if (volume_range) {
max = Math.max.apply(null, source.data['Volume'].slice(i, j));
_bt_scale_range(volume_range, 0, max * 1.03, false);
}
}, 50);
"""))
I got it working half-way correct, however as you can see if you run the code, it's far from perfect. I've uploaded a video to show what's not working: video_url It does not auto-scale correctly if I zoom-in or zoom-out then pan the chart. How to make it auto-scale properly?