Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Trading on the RSI of the VIX and SPY

I got this strategy from Simon Thornington, who posted it in the trading strategy ideas thread. The original description can be found here.

It uses the 2 period RSI of the VIX and the asset price (SPY in this case) to determine entry and exit points.

The Rules:
1. Price must be above its 200-day moving average
2. RSI(2) on price must be below 30
3. Buy when RSI(2) of the VIX is above 90
4. Exit when RSI(2) of the price rises above 65

10 responses

Hi David,
Great code. I have added the opposite with short position and a neutral position. This doubles the return. I would like to add a stop loss and a trend indication so that a position is kept longer on a trend.

I also will try to warmup: https://www.quantopian.com/posts/how-to-get-benchmark-and-algorithm-output-in-sync-after-warmup-period.

Last but not least: how to get hold of vix data? The quandl is not up to date for 2014. Calculating it realtime is not possible since option data is needed. Any idea? In a sidewards pattern there is less to trade, so maybe decrease the 200 days dynamically?

J.

J, realtime vix data would be ideal, it might be sort of hack, but one idea is to use the VIX futures ETFs as a proxy for the VIX. Taking the log of the futures price seems to linearize the price nicely. I found a few futures ETFs and scaled the prices to a similar range for plotting, you can see they follow the same general trend of the VIX.

Another source of VIX data is Yahoo. Here's a function to generate the url for their historical csv data. You could try this instead of using Quandl.

def yahoo_history_url(symbol, start_date, end_date, interval='d'):  
    start_date = str(start_date)  
    end_date = str(end_date)  
    url = 'http://ichart.finance.yahoo.com/table.csv?'  
    url += 's={}&a={}&b={}&c={}&d={}&e={}&f={}&g={}'.format(  
        symbol,  
        str(int(start_date[5:7]) - 1),  
        str(int(start_date[8:10])),  
        str(int(start_date[0:4])),  
        str(int(end_date[5:7]) - 1),  
        str(int(end_date[8:10])),  
        str(int(end_date[0:4])),  
        interval,  
    )  
    return url + '&ignore=.csv'

>>> yahoo_history_url('^VIX', '2012-01-01', '2014-07-04')  
'http://ichart.finance.yahoo.com/table.csv?s=^VIX&a=0&b=1&c=2012&d=6&e=4&f=2014&g=d&ignore=.csv'

You can pass datetime objects instead of strings as well. Hopefully this helps.

Hi David,
Thank you. I will try later. I just copy-past my results. I would like to add stop-loss and limit the drawn down..and test for 2014 before running this one.
J.

There seems a huge difference in using daily or minute data. I would say that 'refresh_period=1' would use minute data a daily data. The ETF instead of VIX data does not give similar effect. I used the VXXX price and not the math.log(price). I guess the math.log was only used to indicate a similar delta.

@batch_transform(window_length=200, refresh_period=1)  
def _history(data):  
    return data  

The batch transform function is being depreciated in favor of the history function, so I would start by swapping that out when working in minute mode. I am not positive, but my guess is that you are running into a pretty common problem that comes up when switching from daily to minute mode. When in minute mode, handle_data is called on every bar, that means that you are potentially placing orders every minute.

Also, the 'target' style orders are naive to any pending open orders that you may have. For example, if you use order_target(stock, 10) for two consecutive minutes, and only 5 shares from the first minute filled, you will end up with (5 from bar1 + 5 from bar2 + 5 from bar1 when it fills) = 15. The safest way around that is to not trade when you have open orders, the line below should handle that.

if get_open_orders():  
    return  

As for the trading on every bar, I'm guessing you really only want to trade once per day. I wrote this post a while ago to demo one way to handle switching from daily to minute mode. If you look around at other minute data examples you will find something that works for you.

Also, when switching from daily to minute bars, the results should be in the same ballpark, but don't expect them to be exactly the same. Unless every order fills at the close price of each day, the input data is different, which means the output will also be different. Hopefully I covered the issue you ran into, you can message me from my profile page if you run into any issues, I'd like to see this algo on run minute data too.

Does anyone have the updated version of this code? I tried running but am getting errors.

Here is a pipeline version of the code. It uses the ETF VXX to mimic VIX. However, because VXX only started trading in 2009 the backtest can only be run from that time.

Another pipeline version which uses the Quandl data for VIX (from quantopian.pipeline.data.quandl import cboe_vix). This data goes back to Jan 2004 so can backtest further. Also doesn't have the error that VXX has.

Hello Dan,
I get completely different backtest figures with negative drawdown and sharpe ratio on the same period as yours.
What can be the reason for this?