Notebook
In [25]:
from pytz import timezone
import matplotlib.pyplot as plt
import pandas as pd
In [26]:
# get minute bar volume data for SPY
# assumption is that empty bars can be filled with zeros, corresponding to no trading volume
data = get_pricing(['SPY'],start_date='2002-01-01',end_date='2015-09-18',fields='volume',frequency='minute').fillna(0)
data.tail(3)
Out[26]:
Equity(8554 [SPY])
2015-09-18 19:58:00+00:00 1352758
2015-09-18 19:59:00+00:00 1587242
2015-09-18 20:00:00+00:00 3342566
In [27]:
# add time & date columns to the data, for pivot table
data['time'] = data.index.tz_convert(timezone('US/Eastern')).time
data['date'] = data.index.date
data.tail(3)
Out[27]:
Equity(8554 [SPY]) time date
2015-09-18 19:58:00+00:00 1352758 15:58:00 2015-09-18
2015-09-18 19:59:00+00:00 1587242 15:59:00 2015-09-18
2015-09-18 20:00:00+00:00 3342566 16:00:00 2015-09-18
In [28]:
# on a rolling basis, compute volume z-scores using a trailing window of width w minutes
# credit to Quantopian user Michael Van Kleeck for this efficient code
# ref.: https://www.quantopian.com/posts/modified-heatmap-based-on-grant-kiehnes-example
w = 390
volumes = data.iloc[:, 0:1]
means = volumes.apply(lambda x: pd.rolling_mean(x, window=w))
sds = volumes.apply(lambda x: pd.rolling_std(x, window=w))
zs = ((volumes - means) / sds)
data['z-score'] = zs
data.tail(3)
Out[28]:
Equity(8554 [SPY]) time date z-score
2015-09-18 19:58:00+00:00 1352758 15:58:00 2015-09-18 1.980082
2015-09-18 19:59:00+00:00 1587242 15:59:00 2015-09-18 2.491620
2015-09-18 20:00:00+00:00 3342566 16:00:00 2015-09-18 6.238266
In [29]:
# apply a pivot table, with trading day along the vertical & trading time along the horizontal
# fill empty minutes with zeros
ht_map = pd.pivot_table(data,'z-score',index=data['date'], columns=data['time'],fill_value=0)
ht_map.tail(3)
Out[29]:
time 09:31:00 09:32:00 09:33:00 09:34:00 09:35:00 09:36:00 09:37:00 09:38:00 09:39:00 09:40:00 ... 15:51:00 15:52:00 15:53:00 15:54:00 15:55:00 15:56:00 15:57:00 15:58:00 15:59:00 16:00:00
date
2015-09-16 2.543713 1.475018 0.478887 2.479433 2.418946 0.955320 1.025321 0.128376 0.438060 0.867887 ... 1.886490 1.729060 1.152875 3.680477 1.976567 1.476489 1.349632 2.649301 2.365451 10.274551
2015-09-17 2.910986 1.903499 1.697658 0.217495 0.136929 1.208661 1.433155 0.579993 0.794222 0.330700 ... 0.525175 1.531511 1.062252 0.960626 1.129707 1.404615 1.743137 1.704468 2.816513 5.174032
2015-09-18 3.986535 1.539162 0.804366 0.697043 0.548146 0.399398 0.798592 0.161119 0.156886 0.177472 ... 1.198675 0.984750 1.541376 0.886846 1.965430 0.993355 0.947574 1.980082 2.491620 6.238266

3 rows × 390 columns

In [34]:
# plot heat map of z-scores 
# see http://matplotlib.org/examples/color/colormaps_reference.html to switch colormap
plt.imshow(ht_map,cmap='jet',aspect=0.1)
plt.grid(False)
plt.colorbar()
plt.clim(ht_map.min().min(),ht_map.max().max())
plt.title('SPY volume z-score, 390-minute rolling window, 2002-present')
plt.xlabel('trading minute')
plt.ylabel('trading day')
Out[34]:
<matplotlib.text.Text at 0x7f3c1323e310>
In [ ]: