Back to Community
The classic GLD and GDX pair trading

used Bollinger band as the criteria. This results is much more reasonable than the KO and PEP pair.

Clone Algorithm
1585
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
import numpy as np
import pandas as pd
from collections import deque

R_P = 1 # refresh period in days
W_L = 11 # window length in days
lookback=22
def initialize(context):
    context.nobs = 10
    context.max_notional = 100000
    context.min_notional = -100000
    
    context.stocks = [sid(26807), sid(32133)]
    context.ratio = deque([])
    context.strategy = 0
    context.daysToRecalibration = 0
    context.beta = 0

       
def handle_data(context, data):
    price0 = data[context.stocks[0]].price
    price1 = data[context.stocks[1]].price
    shares0 = context.portfolio.positions[context.stocks[0]].amount
    shares1 = context.portfolio.positions[context.stocks[1]].amount
    
    if len(context.ratio)<context.nobs or context.daysToRecalibration > 0:
        temp = price0/price1
        context.ratio.append(temp)
        log.info("ratio: {ratio}".format(ratio = sum(context.ratio)))
    #else:
        notional0 = (context.portfolio.positions[context.stocks[0]].amount*data[context.stocks[0]].price)/context.portfolio.starting_cash
        notional1 = (context.portfolio.positions[context.stocks[1]].amount*data[context.stocks[1]].price)/context.portfolio.starting_cash
        if context.daysToRecalibration == 0:
            context.beta=sum(context.ratio)/context.nobs
            context.daysToRecalibration = context.nobs
            context.ratio = deque([])
        log.info("beta = {beta}, price0 = {p0}, price1 = {p1}, diff = {diff}, notional0 = {not0}, notional1 = {not1}".format(beta = context.beta, p0 = price0, p1 = price1, diff = price0 - context.beta*price1, not0 = notional0, not1 = notional1))    
        context.daysToRecalibration -= 1
        rVal=getMeanStd(data, context.beta, context.stocks[0], context.stocks[1])
        if rVal is None:
            return  
        meanPrice,stdPrice = rVal
        h = ((price0 - context.beta*price1) - meanPrice)/stdPrice
        if h>2 and context.strategy != 1:
            order(context.stocks[0], -shares0)
            order(context.stocks[1], -shares1)
            num_shares = int(context.max_notional / price1)
            order(context.stocks[1], num_shares)
            order(context.stocks[0], -1 * num_shares/context.beta )
            context.strategy = 1

        elif h<-2 and context.strategy != 2 :
            order(context.stocks[0], -shares0)
            order(context.stocks[1], -shares1)
            num_shares = int(context.max_notional / price0)
            order(context.stocks[0], num_shares)
            order(context.stocks[1], -1 * num_shares*context.beta )
            context.strategy = 2
        
    record(strategy = context.strategy)
    record(diff = price0 - price1*context.beta, h = h)
        #record(port = context.portfolio.positions_value, cash = context.portfolio.cash)
    record(notional0 = notional0,
           notional1 = notional1)            

@batch_transform(window_length=W_L, refresh_period=R_P) 
def getMeanStd(datapanel, beta, sid0, sid1):
    prices = datapanel['price']
    meanPrice = np.mean(prices[sid0] - beta*prices[sid1])
    stdPrice=np.std(prices[sid0] - beta*prices[sid1])
    if meanPrice is not None and stdPrice is not None :
        return (meanPrice, stdPrice)
    else:
        return None
                
   
We have migrated this algorithm to work with a new version of the Quantopian API. The code is different than the original version, but the investment rationale of the algorithm has not changed. We've put everything you need to know here on one page.
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.
1 response

Very nice pick! Huapu

I cannot believe that the result is so pretty, even their correlation is only 0.4822 based on the data of 2006 to 2013. Anyway, good job!