Search code examples
pythonmplfinance

mplfinance stacked plots with common, time-aligned shared axis


I am plotting stacked graphs of 5, 15, 30 and 60 minute candles on top of one another.

I would like to please:

  1. Have all charts with price right aligned (y_on_right=True seems not be used)
  2. For the times/grid on the 5 minute graph to be every 60 mins on the hour
  3. For all the other graphs to use the same as the above, every 60 mins, all aligned
  4. Optionally if possible, to remove the space on the left and the right (so the first bar is up against the left edge, and last bar up against the right edge)

This is my output so far:

plot

And code is below:

import mplfinance as mpf
import pandas as pd
from polygon import RESTClient

def main():
    key = "key"

    with RESTClient(key) as client:
        start = "2019-02-01"
        end = "2019-02-02"
        ticker = "TVIX"
        resp5 = client.stocks_equities_aggregates(ticker, 5, "minute", start, end, unadjusted=False)
        resp15 = client.stocks_equities_aggregates(ticker, 15, "minute", start, end, unadjusted=False)
        resp30 = client.stocks_equities_aggregates(ticker, 30, "minute", start, end, unadjusted=False)
        resp60 = client.stocks_equities_aggregates(ticker, 60, "minute", start, end, unadjusted=False)
        print(f'5 min data is {len(resp5.results)} long')
        print(f'15 min data is {len(resp15.results)} long')
        print(f'30 min data is {len(resp30.results)} long')
        print(f'60 min data is {len(resp60.results)} long')
        
        df5 = pd.DataFrame(resp5.results)
        df5.index = pd.DatetimeIndex( pd.to_datetime(df5['t']/1000, unit='s') )

        df15 = pd.DataFrame(resp15.results)
        df15.index = pd.DatetimeIndex( pd.to_datetime(df15['t']/1000, unit='s') )

        df30 = pd.DataFrame(resp30.results)
        df30.index = pd.DatetimeIndex( pd.to_datetime(df30['t']/1000, unit='s') )

        df60 = pd.DataFrame(resp60.results)
        df60.index = pd.DatetimeIndex( pd.to_datetime(df60['t']/1000, unit='s') )
        
        df60.index.name = df30.index.name = df15.index.name = df5.index.name = 'Timestamp'   
        # mpf expects a dataframe containing Open, High, Low, and Close data with a Pandas TimetimeIndex
        df60.columns = df30.columns = df15.columns = df5.columns = ['Volume', 'Volume Weighted', 'Open', 'Close', 'High', 'Low', 'Time', 'Num Items']
        
        fig = mpf.figure(figsize=(32, 32))
        ax1 = fig.add_subplot(4, 1, 1)
        ax2 = fig.add_subplot(4, 1, 2)
        ax3 = fig.add_subplot(4, 1, 3)
        ax4 = fig.add_subplot(4, 1, 4)
        
        ap = [
                mpf.make_addplot(df15, type='candle', ax=ax2, y_on_right=True),
                mpf.make_addplot(df30, type='candle', ax=ax3, y_on_right=True),
                mpf.make_addplot(df60, type='candle', ax=ax4, y_on_right=True)
            ]
        
        s = mpf.make_mpf_style(base_mpf_style='default',y_on_right=True)
        mpf.plot(df5, style=s, ax=ax1, addplot=ap, xrotation=0, datetime_format='%H:%M', type='candlestick')              

if __name__ == '__main__':
    main()

Solution

  • I don't have the corresponding API key, so I used Yahoo Finance's stock price instead. As for the issue of placing the price on the right side, you can change the style to achieve this. Also, it seems that y_on_right is only valid for the first graph. From this information. To remove the first and last margins, use tight_layout=True, and to align the x-axis to the hour, you need to check how far the mpl time series formatter can go.

    import yfinance as yf
    import pandas as pd
    import mplfinance as mpf
    import numpy as np
    import datetime
    import matplotlib.dates as mdates
    
    start = '2021-12-22'
    end = '2021-12-23'
    intervals = [5,15,30,60]
    
    for i in intervals:
        vars()[f'df{i}'] = yf.download("AAPL", start=start, end=end, period='1d', interval=str(i)+'m')
    
    for df in [df5,df15,df30,df60]:    
        df.index = pd.to_datetime(df.index)
        df.index = df.index.tz_localize(None)
    
    df5 = df5[df5.index.date == datetime.date(2021,12,21)]
    df15 = df15[df15.index.date == datetime.date(2021,12,21)]
    df30 = df30[df30.index.date == datetime.date(2021,12,21)]
    df60 = df60[df60.index.date == datetime.date(2021,12,21)]
    
    fig = mpf.figure(style='yahoo', figsize=(12,9))
    ax1 = fig.add_subplot(4,1,1)
    ax2 = fig.add_subplot(4,1,2)
    ax3 = fig.add_subplot(4,1,3)
    ax4 = fig.add_subplot(4,1,4)
    
    mpf.plot(df5, type='candle', ax=ax1, xrotation=0, datetime_format='%H:%M', tight_layout=True)
    mpf.plot(df15, type='candle', ax=ax2, xrotation=0, datetime_format='%H:%M', tight_layout=True)
    mpf.plot(df30, type='candle', ax=ax3, xrotation=0, datetime_format='%H:%M', tight_layout=True)
    mpf.plot(df60, type='candle', ax=ax4, xrotation=0, datetime_format='%H:%M', tight_layout=True)
    
    ax3_ticks = ax3.get_xticks()
    print(ax3_ticks)
    

    enter image description here