As of pixel time the VIX is up over 7% and the S&P 500 is basically unchanged; we feel this situation arises when traders desire protection today for the possibility of danger tomorrow. In other words, the price of risk is rising and markets are stabilizing. Intuitively (i.e. the feeling our rat brains get from too many years spent scurrying around the markets) we feel this sets the stage for a sideways trading range, but as with all things it must be tested quantitatively to ensure the hedging of certain human frailties (although we all know unfortunately some human qualities are impossible to hedge away).
The basic idea here is that when volatility spikes in the absence of a large decline, it becomes attractive to marginally sell volatility. Think of the market selling an option straddle, in aggregate. If the intuition is correct, then looking at average returns over subsequent return windows will show compressed distributions.
First let’s explicitly define the event we are using to test: i.e. what happens to stock market returns when the S&P 500 is up/down less than 0.25% and the VIX is up over 5%? To test this we will make use of Python’s Pandas package to download daily stock return data:
import pandas as pd import pandas.io.data as web import datetime as dt import numpy as np start = dt.datetime(2004, 1, 1) end = dt.datetime(2015, 7, 2) SPY = web.DataReader("SPY", 'yahoo', start, end) VIX = web.DataReader("^VIX", 'yahoo', start, end) combo1 = pd.merge(SPY[['Adj Close']], VIX[['Adj Close']], left_index = True, right_index = True, how = "inner") combo1.columns = ["SPY", "VIX"] spy = SPY[['Adj Close']] vix = VIX[['Adj Close']] d_spy = pd.DataFrame(np.log(spy).diff().dropna()) d_vix = pd.DataFrame(np.log(vix).diff().dropna()) combo = pd.merge(d_spy, d_vix, left_index = True, right_index = True, how = "inner") combo.columns = ["SPY", "VIX"] combo2 = combo[(np.abs(combo.SPY) < 0.0025) & (combo.VIX > 0.05)] horizons = [-1, -5, -10, -20, -50, -100, -250] rtns = [ for thing in horizons] for date in combo2.index: print date # grab returns for +1, +5, +10, +20 days beg = combo1.loc[date] i = 0 for horizon in horizons: try: end = combo1.shift(horizons[i]).loc[date] print beg print end rtns[i].append((end.SPY - beg.SPY) / beg.SPY) except Exception,e: print str(e) finally: i += 1
After crunching the return data (check the math above, in rtns):
The numbers seem to show a trend towards sideways movement. There were 49 events like this since 2004 when we started looking at the data. The standard deviation of returns after this event are comparable to the unconditional results. Looking at times that this happens over a weekend might be interesting as well.
Want to learn how to mine social data sources like Google Trends, StockTwits, Twitter, and Estimize? Make sure to download our book Intro to Social Data for Traders