Search code examples
pythonbokeh

bokeh candlestick create small gap between candles


I have a candlestick chart that works nicely with bokeh. The only issue I have is the data is 1 minute data and chart can look a little squashed together. Is there anyway to create a small gap between the candlestick bars?

update - code

import pandas as pd

from datetime import timedelta

from bokeh.plotting import figure, ColumnDataSource
from bokeh.models.widgets import Dropdown
from bokeh.io import curdoc
from bokeh.layouts import column

from bokeh.models import BooleanFilter, CDSView, Select, Range1d, HoverTool
from bokeh.palettes import Category20
from bokeh.models.formatters import NumeralTickFormatter
from bokeh.io import output_file, show

# Define constants
W_PLOT = 1700
H_PLOT = 600
TOOLS = "pan,box_zoom,zoom_in,zoom_out,redo,undo,reset,save,crosshair"

VBAR_WIDTH = 60*60*10000
# VBAR_WIDTH =  12*60*60*1000 # half day in ms
# VBAR_WIDTH =  24*60*60*1000 # day in ms

RED = Category20[7][6]
GREEN = Category20[5][4]

def plot_test(df: pd.DataFrame,
          name: str) -> None:

inc = df.price_close > df.price_open
dec = ~inc

cds = ColumnDataSource(data=df)   
view_inc = CDSView(source=cds, filters=[BooleanFilter(inc)])
view_dec = CDSView(source=cds, filters=[BooleanFilter(dec)])    

fig = figure(plot_width=W_PLOT, plot_height=H_PLOT, 
             tools=TOOLS,
             x_axis_type="datetime",
             title=name,
             toolbar_location='above')

# Plot candles
# High and low
fig.segment(x0='time_stamp', y0='price_high', 
            x1='time_stamp', y1='price_low', 
            source=cds, view=view_inc, 
            color='black')
fig.segment(x0='time_stamp', y0='price_high', 
            x1='time_stamp', y1='price_low', 
            source=cds, view=view_dec,
            color='black')

# Open and close
r1 = fig.vbar(x='time_stamp', width=timedelta(minutes=1), 
         top='price_open', bottom='price_close', 
              source=cds, view=view_inc,
              fill_color=GREEN, line_color="black")
r2 = fig.vbar(x='time_stamp', width=timedelta(minutes=1), 
         top='price_open', bottom='price_close', 
              source=cds, view=view_dec,
              fill_color=RED, line_color="black")

# let add a moving average
fig.line(x='time_stamp', y='ma_20', source=cds, legend_label='MA 20')

# entry signals
fig.triangle(x='time_stamp', y='buy', source=cds, fill_color=GREEN,
             size=10)
fig.inverted_triangle(x='time_stamp', y='sell', source=cds, 
                      fill_color=RED, size=10)

# Set up the hover tooltip to display some useful data
fig.add_tools(HoverTool(
    renderers=[r1],
    tooltips=[
        ("Open", "@price_open{0.0000}"),
        ("High", "@price_high{0.0000}"),
        ("Low", "@price_low{0.0000}"),
        ("Close", "@price_close{0.0000}"),
        ("Date", "@time_stamp{%Y-%m-%d %H:%M}"),
    ],
    formatters={
        '@time_stamp': 'datetime'
        }))

fig.add_tools(HoverTool(
    renderers=[r2],
    tooltips=[
        ("Open", "@price_open{0.0000}"),
        ("High", "@price_high{0.0000}"),
        ("Low", "@price_low{0.0000}"),
        ("Close", "@price_close{0.0000}"),
        ("Date", "@time_stamp{%Y-%m-%d %H:%M}"),
    ],
    formatters={
        '@time_stamp': 'datetime'
        }))

elements = list()
elements.append(fig)

curdoc().add_root(column(elements))
curdoc.title = 'Blah'

show(fig)

Solution

  • As pointed out my bigredot, in order to change the width of the candlestick it is done by setting the width parameter of the vbar method.

    The number below is good for daily data. For higher frequency data I would reduce the '12'

    VBAR_WIDTH = 126060*1000 # half day in ms