Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Plot candlesticks with automatic Y zoom

I am looking for a Python plotting library that allows me to plot candlesticks (preferably the OHLC bars variant) with X zoom via mousewheel scrolling (or similar) and an automatically scaled Y axis when zooming.

As an example of what I am looking for, tradingview.com does this perfectly. See https://uk.tradingview.com/chart/?symbol=NASDAQ:NDX. OHLC bars can be seen by clicking the candlestick icon near the top left and selecting 'Bars'.

Plotly is almost able to do this. The Ohlc class in plotly.graph_objs give the OHLC bars, and the default rangeslider is a nice feature for X zoom (mousewheel scrolling can also be easily enabled). However automatic Y scaling is not available in Python as far as I can see (Y-axis autoscaling with x-range sliders in plotly), thus zooming in on a section of data makes it appear flat. Example code - https://plot.ly/python/ohlc-charts/

Another option I am familiar with is PyQtGraph, which has nice zoom features but does not have support for candlestick plots. Using this would involve coding my own candlestick object.

There are a wide range of Python plotting libraries out there that I don't know. Is there anything out there that has out of the box support for this? Can anyone provide example code to do this cleanly?

like image 815
Graeme Avatar asked Jul 03 '18 19:07

Graeme


3 Answers

This is how to do it in finplot:

import yfinance as yf
import finplot as fplt

df = yf.download('^NDX', start='2018-01-01', end='2020-04-29')
print(df)
fplt.candlestick_ochl(df[['Open','Close','High','Low']])
fplt.show()

Disclaimer: I am the author. Finplot has auto-Y-scaling, is fast and opinionated with a clean api. See examples here.

like image 141
Jonas Byström Avatar answered Oct 15 '22 19:10

Jonas Byström


The best solution I have found is to use Bokeh. There is a related question here - Bokeh, zoom only on single axis, adjust another axis accordingly. One answer links a gist which gives an example of setting up candlesticks with automatic Y zoom.

Unfortunately this is far from an 'out of the box' solution as it involves coding a custom JavaScript callback. However, the solution is still fairly simple. I couldn't get the code on the gist to run, mainly due to issues with the Pandas DataReader. Here is an updated version of the code which uses the example data Bokeh provides (as per the Bokeh Candlesicks example), adds more similarities with TradingView and irons out a few other issues I found:

import pandas as pd

from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.models import CustomJS, ColumnDataSource
from bokeh.sampledata.stocks import MSFT


def candlestick_plot(df):
    fig = figure(sizing_mode='stretch_both',
                 tools="xpan,xwheel_zoom,undo,redo,reset,crosshair,save",
                 active_drag='xpan',
                 active_scroll='xwheel_zoom',
                 x_axis_type='datetime')

    inc = df.close > df.open
    dec = ~inc

    fig.segment(df.date[inc], df.high[inc], df.date[inc], df.low[inc], color="green")
    fig.segment(df.date[dec], df.high[dec], df.date[dec], df.low[dec], color="red")
    width_ms = 12*60*60*1000 # half day in ms
    fig.vbar(df.date[inc], width_ms, df.open[inc], df.close[inc], color="green")
    fig.vbar(df.date[dec], width_ms, df.open[dec], df.close[dec], color="red")

    source = ColumnDataSource({'date': df.date, 'high': df.high, 'low': df.low})
    callback = CustomJS(args={'y_range': fig.y_range, 'source': source}, code='''
        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;
        });
    ''')

    fig.x_range.callback = callback
    show(fig)

df = pd.DataFrame(MSFT)
df["date"] = pd.to_datetime(df["date"])
output_file("candlestick.html")
candlestick_plot(df)
like image 6
Graeme Avatar answered Oct 15 '22 18:10

Graeme


I struggled with getting the plotly candlestick chart to work the way I wanted to work so I developed a code example to share.

This does not depend on any additional javascript or other libraries except Dash, Plotly, and a date library called pytz. Example code provides automatic updates to the yaxis range when and x range slider is updated. Y axis is set to show only price range of bars that are in the chart with a two tick padding.

This worked well for me and I can potentially add any number of trace overlays that I want on top of the chart. Plus, I can run it locally without having to use plotly services. See gitub repo here:

https://github.com/gersteing/DashCandlestickCharting/blob/master/README.md

For whom ever wants to try it out. Runs locally using Flask. Enjoy!

like image 5
user3930061 Avatar answered Oct 15 '22 19:10

user3930061