Insuring tomorrow’s decline, today

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 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:
      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)
      i += 1

After crunching the return data (check the math above, in rtns):

Horizon Avg Std Uncond Std
+1d -0.23% 1.38% 1.22%
+5d -0.11% 2.12% 2.44%
+10d -0.26% 4.44% 3.27%
+20d 0.46% 4.82% 4.53%

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

Enter your email address to follow this blog and receive notifications of new posts by email.



Check out the Beta release of SliceMatrix: a unique tool for visualizing the stock market, including views of filtered correlation networks and minimum spanning trees

Screenshot from SliceMatrix

Screenshot from SliceMatrix


Categories: Quantitative Trading, Volatility

Tagged as: ,

2 replies »

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s