Using mplfinance with streamlit?

Hi,

is it possible to use mplfinance with streamlit?

With my code:

fig = mpf.figure(style='yahoo', figsize=(8,6))
mpf.plot(hist)
st.pyplot(fig)

i only see a white window.

Thank you

Can you post a minimal but complete example please so the issue can be tested more easily?

This is my test code:

from datetime import date, timedelta, datetime
import streamlit as st
import pandas as pd
import mplfinance as mpf
import matplotlib.pyplot as plt
from pandas_datareader import data as pdr

def get_historical_data(symbol, start_date = None):
    df = pdr.get_data_yahoo(symbol, start=start_date, end=datetime.now())
    df = df.rename(columns = {'Open': 'open', 'High': 'high', 'Low': 'low', 'Close': 'close', 'Adj Close': 'adj close', 'Volume': 'volume'})
    for i in df.columns:
        df[i] = df[i].astype(float)
    df.index = pd.to_datetime(df.index)
    if start_date:
        df = df[df.index >= start_date]
    return df

hist = get_historical_data('AAPL', '2021-01-01')

fig = mpf.figure(style='yahoo', figsize=(8,6))
mpf.plot(hist)
st.pyplot(fig)

Thanks for posting a more complete example. A couple of things I discovered browsing the mplfinance source code:

  • Streamlit st.pyplot requires a matplotlib fig object (which it can save to disk to render the plot)
  • It’s possible to have mpf.plot return fig and ax, but only if returnfig=True is given
    • See the source code (line 778) here
  • Once you have a handle on fig, you’re in business!

Here’s a fully functioning solution I wrote (since I happen to be doing some financial technical analysis myself at the moment :upside_down_face:):

Demo

Code

from datetime import date, datetime
import streamlit as st
import pandas as pd
import mplfinance as mpf
from pandas_datareader import data as pdr

st.experimental_memo(persist='disk')
def get_historical_data(symbol, start_date = None):
    df = pdr.get_data_yahoo(symbol, start=start_date, end=datetime.now())
    df = df.rename(columns = {'Open': 'open', 'High': 'high', 'Low': 'low', 'Close': 'close', 'Adj Close': 'adj close', 'Volume': 'volume'})
    for i in df.columns:
        df[i] = df[i].astype(float)
    df.index = pd.to_datetime(df.index)
    if start_date:
        df = df[df.index >= start_date]
    return df

st.title('mplfinance demo')

c1, c2, c3 = st.columns([1,1,1])
with c1:
    symbol = st.selectbox('Choose stock symbol', options=['AAPL', 'MSFT', 'GOOG', 'AMZN'], index=1)
with c2:
    date_from = st.date_input('Show data from', date(2021, 10, 1))
with c3:
    st.markdown(' ')
    show_data = st.checkbox('Show data table', False)

st.markdown('---')

st.sidebar.subheader('Settings')
st.sidebar.caption('Adjust charts settings and then press apply')

with st.sidebar.form('settings_form'):
    show_nontrading_days = st.checkbox('Show non-trading days', True)
    # https://github.com/matplotlib/mplfinance/blob/master/examples/styles.ipynb
    chart_styles = [
        'default', 'binance', 'blueskies', 'brasil', 
        'charles', 'checkers', 'classic', 'yahoo',
        'mike', 'nightclouds', 'sas', 'starsandstripes'
    ]
    chart_style = st.selectbox('Chart style', options=chart_styles, index=chart_styles.index('starsandstripes'))
    chart_types = [
        'candle', 'ohlc', 'line', 'renko', 'pnf'
    ]
    chart_type = st.selectbox('Chart type', options=chart_types, index=chart_types.index('candle'))

    mav1 = st.number_input('Mav 1', min_value=3, max_value=30, value=3, step=1)
    mav2 = st.number_input('Mav 2', min_value=3, max_value=30, value=6, step=1)
    mav3 = st.number_input('Mav 3', min_value=3, max_value=30, value=9, step=1)

    st.form_submit_button('Apply')

data = get_historical_data(symbol, str(date_from))

fig, ax = mpf.plot(
    data,
    title=f'{symbol}, {date_from}',
    type=chart_type,
    show_nontrading=show_nontrading_days,
    mav=(int(mav1),int(mav2),int(mav3)),
    volume=True,

    style=chart_style,
    figsize=(15,10),
    
    # Need this setting for Streamlit, see source code (line 778) here:
    # https://github.com/matplotlib/mplfinance/blob/master/src/mplfinance/plotting.py
    returnfig=True
)

st.pyplot(fig)

if show_data:
    st.markdown('---')
    st.dataframe(data)

GitHub gist

Have fun!
Arvindra

1 Like

Thank you very much, it works very well.

1 Like

Great - please mark as solution?

Would st.cache speed up the chart creation?

On the data fetch side it helps. Remove the persist to disk flag and in-memory caching will be used instead, which could be faster. But the overall response time (speed) is going to be overwhelmed by the web request latency. Building an efficient, high speed, etc. data tier is another story, and Streamlit is not designed for that.