Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
spread trading GLD and SLV etf's

I'm a trader with 30 years experience but no programming background. I used to trade Asian Index options (volatility arbitrage). It was very profitable and fairly low risk for a decade.....now I'm looking for a new trade and I'd prefer to trade spreads for small edge....rather than try to predict direction.

I recently read this article http://www.futuresmag.com/2014/12/15/shadow-pricing-futures-and-etfs?page=2, which shows spread the author was looking at between two ETF's GLD and SLV . He looks at day over day volatility in each and sees that while silver is usually more volatile than gold....the vols tend to mean revert back to point where their vols are similar.

I'd like to trade this spread , or another mean reverting type spread intraday for small consistent profits. My question is...."Is there a way to predict when the spread is going to continue going in one direction for an extended period?"

thanks

6 responses

@Mitch, I've got a question about pairs trades that go directional against you. I've built quite a few pairs trading algos over the years and although, yes, many of them exhibited the wished for oscillation in the spread between them (sell spread at the top of the ~sine wave, buy it at the bottom), undoubtedly, every pair would eventually go directional against you. And these directional trades would ultimately erase much or most of the profits.

Gold/Silver ETF spread

In that image the green arrows are where one would think to buy the spread, and you get a bit of profit going your way, but a reversal occurs and the spread goes directional the other way. Red arrows are selling the spread.

Of course trading trading a spread is probably no different than trading a single instrument: enter the signals, set stops, trail the profit, exit as the market indicates. But pairs trading doubles your trouble. What with double commissions, borrowing the short, paying spreads in both, I've yet to find a pair strat that was ever consistent. Do you have a secret or technique you could share?

It would seem that in your above post you say to use the volatility of each leg, and when they increase (and peak?) this is the time to enter into the pairs trade. So, volatility up + trigger signal for trade?

Market Tech,

I guess I wasn't very clear....I have the same problem you have....how do you anticipate when the spread is going to start trending and stop mean reverting?
The spread I'm watching is simply the % change of SLV on the day vs the % change of GLD on the day .I'd like to attach a picture of the chart I'm looking at but not sure how to attach a file here.

@Mitch, single security trading is, in my book, never going to make money. 100 million investor/traders out there all beating the same equity bush all thinking they can flush a rabbit or two. Not gonna happen. But multiple security trading, pairs, triangulation, quad-pairs, syndexes (synthetic indexes) all improve the information content and all can give an intelligent quant an edge most others cannot discover or leverage.

So you're trying to use PoP (period over period) returns (either % or log) in a ratio to determine when the primary leg has temporarily exhausted its buyers or sellers and the secondary leg must either catch up or the primary leg falter and revert to mean. Then maybe ratios of ROC or RSI or RSI of STO, or CCI may all give you some flavor of limited run/fade exhaustion. Simple research tests like this are easy to do here. Let's see what some of these ratios look like...

Here's a small playground for fiddling with pairs.

There are three (four now) different comparison calculations you can use, price returns, RSI and ROC (and linreg). You'll have to uncomment the one you want to test.
I tested on daily only and the performance is poor. No doubt due to the poor executions available on daily. It uses schedule_function at the open but who knows if this actually applies on daily or not. You'd have to run this on minutely to test - and I don't have the patience.

What I was seeing was that this treatment looks to be finding the divergences in the spread -- not the maximum peaks of the spread. Which means that it works better buying the momentum leg and fading the lagging leg. Exactly opposite what a mean reverting pairs strat should do.

It's a place to start.

[Edit: Added a version of linear regression comparison (slope of returns)]

import numpy  
import talib  
import collections

# Price return settings  
#periodsToConsider = 2  
#minimumPercentDeltaThreshold = .03

# RSI settings  
#periodsToConsider = 11  
#minimumPercentDeltaThreshold = 11

# ROC settings  
#periodsToConsider = 3  
#minimumPercentDeltaThreshold = 1

# Linear Regression  
periodsToConsider = 11  
minimumPercentDeltaThreshold = 200

def initialize(context):  
    context.stocks = symbols('GLD', 'SLV')  
    context.spreadDirection = 0  
    set_benchmark(symbol('GLD'))  
    set_commission(commission.PerTrade(cost=2))  
    schedule_function(func=HandleDataScheduled,  
                      date_rule=date_rules.every_day(),  
                      time_rule=time_rules.market_open(hours=0, minutes=1))

def handle_data(context, data):  
    pass

def HandleDataScheduled(context, data):  
    prices = history(periodsToConsider+1, '1d', 'price')  
    ### Price returns calc ###  
    #returns = (prices.iloc[-1] - prices.iloc[0]) / prices.iloc[0]  
    #returns.sort()  
    #returnsSpread = returns[-1] - returns[0]  
    ###

    ### RSI calc ###  
    #returns = prices.apply(talib.RSI, timeperiod=periodsToConsider).iloc[-1]  
    #returns = returns.dropna()  
    #returns = returns.order()  
    #returnsSpread = returns[-1] - returns[0]  
    ###    

    ### ROC calc ###  
    #returns = prices.apply(talib.ROC, timeperiod=periodsToConsider).iloc[-1]  
    #returns = returns.dropna()  
    #returns = returns.order()  
    #returnsSpread = returns[-1] - returns[0]  
    ###

    ### Linear regression calc ###  
    leg0Stock = context.stocks[0]  
    leg1Stock = context.stocks[-1]  
    leg0Returns = numpy.asarray(prices[leg0Stock]) / prices[leg0Stock][0]  
    leg1Returns = numpy.asarray(prices[leg1Stock]) / prices[leg1Stock][0]  
    returns = prices.iloc[-1] / prices.iloc[0] # a place to store the results  
    # Perform linear regression of these two stock returns  
    returns[leg0Stock] = numpy.polyfit(leg0Returns, range(0, periodsToConsider + 1), 1)[0]  
    returns[leg1Stock] = numpy.polyfit(leg1Returns, range(0, periodsToConsider + 1), 1)[0]  
    returns.sort()  
    returnsSpread = returns[-1] - returns[0]  
    ###

    ### General logic below  
    requestedSpreadDirection = 1 if context.stocks[0] == returns.index[0] else -1  
    # Buy/Sell the spread?  
    if (returnsSpread >= minimumPercentDeltaThreshold):  
        if (context.portfolio.positions_value == 0 and context.spreadDirection != requestedSpreadDirection):  
            context.spreadDirection = requestedSpreadDirection  
            # Buy smallest return  
            # Sell greatest return  
            order_target_percent(returns.index[0], 1)  
            order_target_percent(returns.index[-1], -1)  
            print("     Buy: {0} @ {1:<7.2f}  Sell: {2} @ {3:<7.2F} >>>").format(  
                returns.index[0].symbol,  
                prices[returns.index[0]][-1],  
                returns.index[-1].symbol,  
                prices[returns.index[-1]][-1])

    # Close any open position if we cross the spread  
    elif (context.portfolio.positions_value > 0 and context.spreadDirection != requestedSpreadDirection):  
        order_target_percent(returns.index[0], 0)  
        order_target_percent(returns.index[-1], 0)  
        print("<<< Exit: {0} @ {1:<7.2f}  Exit: {2} @ {3:<7.2F}").format(  
            returns.index[0].symbol,  
            prices[returns.index[0]][-1],  
            returns.index[-1].symbol,  
            prices[returns.index[-1]][-1])

    record(Leg1=prices[context.stocks[0]][-1],  
           Leg2=prices[context.stocks[-1]][-1],  
           Leg1Return=returns[context.stocks[0]],  
           Leg2Return=returns[context.stocks[-1]])

Thank you for the work on my behalf. I am not a coder...so I am waiting to hire a coder for another project so he/she can explain this to me.
Meanwhile...my reading on this site tells me I need to figure out if the pair I am looking at is cointegrated before I start.

Simplistic pairs trading, as illustrated above, may be difficult to near impossible to trade profitably. Dynamic discovery of cointegrated pairs seems like it would help find those sets of securities that are dancing well together. Yet there is a host of high end quant shops that strive to perfect this exact technique. Competing with those is an uphill battle. Alternatively, trading a basket of behaviorally linked securities, whether conjoined by fundamental metrics, sector similarities, or resource dependencies, can give you a smoother return and more confidence in your strategy. Trading such a basket is effectively trading many simultaneous pairs. If your strategy picks the right time to catch a mean reversion move for more than half of your virtual trading pairs -- you're in the money.

For instance, what companies are inexorably linked to the price of crude oil? Airline and plastic mfg. companies? Parcel delivery and fertilizer companies? Drill rig/explorers and refineries? Build baskets of 1/2 and 1/2 of each variety and test them as a group. Buy the laggards and sell the leaders at high inflection points in crude oil. The opposite for low inflection points. You'd at least be trading something non-standard than few would be mimicking.