CUATS Workshop

This is a thread we can use to post backtests etc.

5 responses

Workshop pairs trading example, for you to clone and modify.

21
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
"""
This is a basic pairs trading algorithm for use at Quantopian Workshops.
WARNING: THIS IS A LEARNING EXAMPLE ONLY. DO NOT TRY TO TRADE SOMETHING THIS SIMPLE.
https://www.quantopian.com/workshops
https://www.quantopian.com/lectures
By Delaney Granizo-Mackenzie
"""
import numpy as np

def initialize(context):
"""
Called once at the start of the algorithm.
"""
# Check status of the pair every day 2 minutes before we rebalance
# The 2 minutes is just because we want to be safe, and 1 minutes
# is cutting it close
schedule_function(check_pair_status, date_rules.every_day(), time_rules.market_close(minutes=60))

context.stock1 = symbol('ABGB')
context.stock2 = symbol('FSLR')

# Our threshold for trading on the z-score
context.entry_threshold = 0.2
context.exit_threshold = 0.1

# Moving average lengths
context.long_ma_length = 30
context.short_ma_length = 1

# Flags to tell us if we're currently in a trade

def check_pair_status(context, data):

# For notational convenience
s1 = context.stock1
s2 = context.stock2

# Get pricing history
prices = data.history([s1, s2], "price", context.long_ma_length, '1d')

# Try debugging me here to see what the price
# data structure looks like
# To debug, click on the line number to the left of the
# next command. Line numbers on blank lines or comments
# won't work.
short_prices = prices.iloc[-context.short_ma_length:]

# Get the long mavg
long_ma = np.mean(prices[s1] - prices[s2])
# Get the std of the long window
long_std = np.std(prices[s1] - prices[s2])

# Get the short mavg
short_ma = np.mean(short_prices[s1] - short_prices[s2])

# Compute z-score
if long_std > 0:
zscore = (short_ma - long_ma)/long_std

# Our two entry cases
if zscore > context.entry_threshold and \
order_target_percent(s1, -0.5) # short top
order_target_percent(s2, 0.5) # long bottom

elif zscore < -context.entry_threshold and \
order_target_percent(s1, 0.5) # long top
order_target_percent(s2, -0.5) # short bottom

# Our exit case
elif abs(zscore) < context.exit_threshold:
order_target_percent(s1, 0)
order_target_percent(s2, 0)

record('zscore', zscore)
There was a runtime error.

2014 was a bad year :( - joel

2
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
def initialize(context):

context.security_list = [sid(5061), sid(7792), sid(1941), sid(1746),sid(46631)]

schedule_function(rebalance,
date_rules.every_day(),
time_rules.market_open())

#set_slippage(slippage.VolumeShareSlippage(volume_limit=0, price_impact=0))

def Signal(context,data):
hist = data.history(context.security_list, 'price', 60, '1d')

prices_20 = hist[-20:]
prices_60 = hist[-60:]

sma_20 = prices_20.mean()
sma_60 = prices_60.mean()

return sma_20-sma_60

def Signal_yday(context,data):
hist = data.history(context.security_list, 'price', 61, '1d')

prices_20_yday = hist[-21:-1]
prices_60_yday = hist[-61:-1]

sma_20_yday = prices_20_yday.mean()
sma_60_yday = prices_60_yday.mean()

return sma_20_yday-sma_60_yday

def compute_weights(context, data):
"""
Compute weights for each security that we want to order.
"""

# Get the 30-day price history for each security in our list.
hist = data.history(context.security_list, 'price', 200, '1d')

prices_60 = hist[-60:]
prices_200 = hist

sma_60 = prices_60.mean()
sma_200 = prices_200.mean()

# Weights are based on the relative difference between the short and long SMAs
weights = (sma_200-sma_60)/sma_200

# Normalize our weights
normalized_weights = weights / weights.abs().sum()
# Return our normalized weights. These will be used when placing orders later.
return normalized_weights

def rebalance(context, data):
signals_yesterday = Signal_yday(context,data)
signals_today = Signal(context, data)

weights = compute_weights(context, data)

for security in context.security_list:
#record(sma_diff=signals_today[security])

if signals_yesterday[security] <= 0 and signals_today[security] > 0:
order_target_percent(security,weights[security])
print security
elif signals_yesterday[security] >=0 and signals_today[security] < 0:
order_target_percent(security,weights[security])
print 'sell'
print security


There was a runtime error.

Florian Kreyssig

1
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
"""
This is a basic pairs trading algorithm for use at Quantopian Workshops.
WARNING: THIS IS A LEARNING EXAMPLE ONLY. DO NOT TRY TO TRADE SOMETHING THIS SIMPLE.
https://www.quantopian.com/workshops
https://www.quantopian.com/lectures
By Delaney Granizo-Mackenzie
"""
import numpy as np
import math

def initialize(context):
"""
Called once at the start of the algorithm.
"""
# Check status of the pair every day 2 minutes before we rebalance
# The 2 minutes is just because we want to be safe, and 1 minutes
# is cutting it close
schedule_function(check_pair_status, date_rules.every_day(), time_rules.market_close(minutes=60))

s1 = sid(4283) #Coke
s2 = sid(5885) #Pepsi
s3 = sid(25006) #JP morgan
s4 = sid(1335) #Citigroup
s5 = sid(3766) #IBM
s6 = sid(5061) #MSFT
s7 = sid(24) #AAPL
s9 = sid(5938) #Procter and Gamble
s10 = sid(1582) #Colgate Palmolive
context.stocks = []
context.stocks.append(s1)
context.stocks.append(s2)
context.stocks.append(s3)
context.stocks.append(s4)
context.stocks.append(s5)
context.stocks.append(s6)
context.stocks.append(s7)
context.stocks.append(s8)
context.stocks.append(s9)
context.stocks.append(s10)

# Our threshold for trading on the z-score
context.entry_threshold = 0.2
context.exit_threshold = 0.1

# Moving average lengths
context.long_ma_length = 30
context.short_ma_length = 1

# Flags to tell us if we're currently in a trade

def check_pair_status(context, data):

# For notational convenience
stocks = context.stocks
percentage = (1/(float(round(math.floor(len(stocks)/2)))))
# Get pricing history
prices = []
for stockpair in range(0,int(round(math.floor(len(stocks)/2)))):
s1 = stocks[2*stockpair]
s2 = stocks[2*stockpair+1]
prices = data.history([s1, s2], "price", context.long_ma_length, '1d')
short_prices = prices.iloc[-context.short_ma_length:]

# Get the long mavg
long_ma = np.mean(prices[s1] - prices[s2])
# Get the std of the long window
long_std = np.std(prices[s1] - prices[s2])

# Get the short mavg
short_ma = np.mean(short_prices[s1] - short_prices[s2])
print (s1)
print (s2)
print (percentage)
# Compute z-score
if long_std > 0:
zscore = (short_ma - long_ma)/long_std

# Our two entry cases
if zscore > context.entry_threshold and \
order_target_percent(s1, -percentage) # short top
order_target_percent(s2, percentage) # long bottom

elif zscore < -context.entry_threshold and \
order_target_percent(s1, percentage) # long top
order_target_percent(s2, -percentage) # short bottom

# Our exit case
elif abs(zscore) < context.exit_threshold:
order_target_percent(s1, 0)
order_target_percent(s2, 0)
context.currently_long_the_spread = False