Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get an intraday price - volume plot in Pandas?

I have a DataFrame that contains price/volume data on an intraday basis:

time                  price    volume   
2015-04-15 10:10:00   10       500    
2015-04-15 10:20:00   15       100    
2015-04-15 10:30:00   20       70
2015-04-15 10:30:00   etc      etc

I need to get a standard price - volume chart, where the top chart contains the prices (a regular line), and the bottom chart contains the volume (a bar chart).

Both charts should share the same axis, of course.

So far, I have come up with:

plt.figure(figsize=(20,15))          

ax1=plt.subplot2grid((2,2),(0,0),colspan=2)
ax2=plt.subplot2grid((2,2),(1,0),colspan=2)

ax2.xaxis.set_major_locator(HourLocator(interval=3))
ax2.xaxis.set_major_formatter(DateFormatter('%H:%M'))

data.ix['2015-10-01': '2015-10-02','price'].plot(ax=ax1)
data.ix['2015-10-01': '2015-10-02','volume'].plot(ax=ax2, kind='bar')

But I get super-dense tick labels for the bar charts (the chart is unusable).

How can I simply specify to have minor ticks every hours, and major ticks every 3 hours (so that the chart is still readable)?

like image 475
ℕʘʘḆḽḘ Avatar asked Feb 07 '23 01:02

ℕʘʘḆḽḘ


1 Answers

There are some challenges with pandas.plot.bar() and DateTimeIndex that are discussed for instance here. The following:

import matplotlib as mpl
import matplotlib.pyplot as plt

plt.style.use('ggplot')
import pandas as pd
import numpy as np
from datetime import datetime

n = 100
idx = pd.date_range(start=datetime(2016, 1, 1, 10), freq='10Min', periods=n)
data = pd.DataFrame(data={'price': np.cumsum([0.0001] * n + np.random.random(n)),
                          'volume': np.random.randint(low=100, high=10000, size=n)}, index=idx)

fig, ax = plt.subplots(nrows=2, sharex=True, figsize=(15,8))

ax[0].plot(data.index, data.price)
ax[1].bar(data.index, data.volume, width=1/(5*len(data.index)))

xfmt = mpl.dates.DateFormatter('%H:%M')
ax[1].xaxis.set_major_locator(mpl.dates.HourLocator(interval=3))
ax[1].xaxis.set_major_formatter(xfmt)

ax[1].xaxis.set_minor_locator(mpl.dates.HourLocator(interval=1))
ax[1].xaxis.set_minor_formatter(xfmt)

ax[1].get_xaxis().set_tick_params(which='major', pad=25)

fig.autofmt_xdate()
plt.show()

produces the below result. Notice that falling back to matplotlib requires some fiddling with the width parameter in ax[1].bar(). For minorticks, you may want to look here for more detailed formatting options, esp. re skipping intervals to avoid overlap.

enter image description here

like image 157
Stefan Avatar answered Feb 09 '23 13:02

Stefan