Is this worth investing?

Hi Q,

Is this strategy worth investing? If yes, what is the process to get it funded?

Best regards,
Pravin

65
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
import scipy.stats as st
from scipy.optimize import minimize

def initialize(context):
context.SPY = sid(8554)
set_symbol_lookup_date('2015-01-01')

context.first = True
context.days = 9

def handle_data(context, data):
record(leverage=context.account.leverage)

if context.days < 5:
context.days += 1
return

context.days = 0
prices = history(600, "1d", "price")

prices = prices.dropna(axis=1)
prices = prices.drop([context.SPY], axis=1)
copy = prices.copy(True)

for sid in copy:
if sid not in data:
prices = prices.drop([sid], axis=1)

context.prices = prices.values
x0 = [1. / np.shape(context.prices)[1]] * np.shape(context.prices)[1]
b = tuple((0, None) for x in x0)
res = minimize(variance_ratio, x0, args=(context), bounds=b)

p = np.dot(context.prices, res.x)
sign = np.sign(p[-1] - p[0])

wsum = 0
for i, sid in enumerate(prices):
val = sign * res.x[i] / np.sum(np.abs(res.x)) * context.portfolio.portfolio_value
if sid in data:
order_target_value(sid, val)
wsum += val
order_target_value(context.SPY, -wsum)

def variance_ratio(X, context):
P = np.dot(context.prices, X)

r = 0
ratio = []
for i in range(1,5):
r += np.corrcoef(P[:-i], P[i:])[0,1] * (1 - i / 5.)
ratio.append(r)

total = 0
for i in range(1, len(ratio)):
total += ratio[i] - ratio[i-1]
s,i,r,p,e = st.linregress(range(0, len(P)), P)
return -total * r

There was a runtime error.
15 responses

No b/c leverage so high means the great looking curve is an illusion. Return on the amount spent is 59%, lower than the benchmark.

This is a minimal version for keeping an eye on PvR that will usually work by just pasting this at the end of initialize() [or depending on how ordering is being done, sometimes you might need to call info() more often, like from from handle_data()]

    schedule_function(info, time_rules.market_close())

def info(context, data):
c = context                           # For brevity

shorts = 0                            # Shorts value
for p in c.portfolio.positions:       # Total up shorting, because it is risk
shrs = c.portfolio.positions[p].amount
if shrs < 0:
shorts += int(abs(shrs * data[p].price))

if 'risk_hi' not in c: c.risk_hi = 0  # Init this in initialize for better efficiency
cash_dip  = int(max(0, c.portfolio.starting_cash - c.portfolio.cash)) # all of these as positives
risk      = int(max(cash_dip, shorts))
c.risk_hi = max(risk, c.risk_hi)

# Profit_vs_Risk returns based on max amount actually put into play (risk high)
if c.risk_hi != 0:  # Avoid zero-divide
pvr_rtrn = 100 * (c.portfolio.portfolio_value - c.portfolio.starting_cash) / c.risk_hi
record(PvR = pvr_rtrn)  # Profit_vs_Risk returns


In this backtest I just remove 'HBI', as it has wrong split adjustment.

1

If the performance holds up using a dynamic universe, it might be on to something? Backtests with fixed lists of assets, if they aren't an unbiased set of ETFs (like all the sector ETFs, or all the country ETFs) make me pretty skeptical. But I am not Quantopian!

Pravin,

How you pick up instruments?

@Vladimir, I had this list for a while now. Don't remember anymore how I obtained it.

(deleted previous post, fixed the error) Backtesting very slowly on dynamic universe...

@James Miller, since the algo longs stocks and shorts SPY, you might want to try and pick winning stocks from dynamic universe. Alternatively you could remove the bounds in minimize method to find a long short portfolio.

Best regards,
Pravin

Heres the test without Pravins suggestions.

0
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
import scipy.stats as st
from scipy.optimize import minimize

def initialize(context):
context.SPY = sid(8554)
set_symbol_lookup_date('2015-01-01')
context.stocks = []
set_universe(universe.DollarVolumeUniverse(floor_percentile=95.0, ceiling_percentile=100.0))
context.first = True
context.days = 9

def handle_data(context, data):
record(leverage=context.account.leverage)

if context.days < 5:
context.days += 1
return

context.days = 0
prices = history(600, "1d", "price")

prices = prices.dropna(axis=1)
prices = prices.drop([context.SPY], axis=1)
copy = prices.copy(True)

for sid in copy:
if sid not in data:
prices = prices.drop([sid], axis=1)

context.prices = prices.values
x0 = [1. / np.shape(context.prices)[1]] * np.shape(context.prices)[1]
b = tuple((0, None) for x in x0)
res = minimize(variance_ratio, x0, args=(context), bounds=b)

p = np.dot(context.prices, res.x)
sign = np.sign(p[-1] - p[0])

wsum = 0
for i, sid in enumerate(prices):
val = sign * res.x[i] / np.sum(np.abs(res.x)) * context.portfolio.portfolio_value
if sid in data:
order_target_value(sid, val)
wsum += val
order_target_value(context.SPY, -wsum)

def variance_ratio(X, context):
P = np.dot(context.prices, X)

r = 0
ratio = []
for i in range(1,5):
r += np.corrcoef(P[:-i], P[i:])[0,1] * (1 - i / 5.)
ratio.append(r)

total = 0
for i in range(1, len(ratio)):
total += ratio[i] - ratio[i-1]
s,i,r,p,e = st.linregress(range(0, len(P)), P)
return -total * r

There was a runtime error.

And with more acceptable leverage.

4
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
import scipy.stats as st
from scipy.optimize import minimize

def initialize(context):
context.SPY = sid(8554)
set_symbol_lookup_date('2015-01-01')
context.stocks = []
set_universe(universe.DollarVolumeUniverse(floor_percentile=95.0, ceiling_percentile=100.0))
context.first = True
context.days = 9

def handle_data(context, data):
record(leverage=context.account.leverage)

if context.days < 5:
context.days += 1
return

context.days = 0
prices = history(600, "1d", "price")

prices = prices.dropna(axis=1)
prices = prices.drop([context.SPY], axis=1)
copy = prices.copy(True)

for sid in copy:
if sid not in data:
prices = prices.drop([sid], axis=1)

context.prices = prices.values
x0 = [1. / np.shape(context.prices)[1]] * np.shape(context.prices)[1]
b = tuple((0, None) for x in x0)
res = minimize(variance_ratio, x0, args=(context), bounds=b)

p = np.dot(context.prices, res.x)
sign = np.sign(p[-1] - p[0])

wsum = 0
for i, sid in enumerate(prices):
val = sign * res.x[i] / np.sum(np.abs(res.x)) * context.portfolio.portfolio_value
if sid in data:
order_target_value(sid, val / 2)
wsum += val
order_target_value(context.SPY, -wsum / 2)

def variance_ratio(X, context):
P = np.dot(context.prices, X)

r = 0
ratio = []
for i in range(1,5):
r += np.corrcoef(P[:-i], P[i:])[0,1] * (1 - i / 5.)
ratio.append(r)

total = 0
for i in range(1, len(ratio)):
total += ratio[i] - ratio[i-1]
s,i,r,p,e = st.linregress(range(0, len(P)), P)
return -total * r

There was a runtime error.

how does the dynamic universe make such a difference?
Best,
Andrew

Selection bias.

I changed James' version slightly:

• Universe consists of 9 out of 11 SPDR sector ETFs (per Simon's suggestion. Note: I couldn't find XLFS and XLRE in SID)
• Tracking Max Leverage
• Turned simulated slippage back on
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
import numpy as np
import pandas as pd
import scipy.stats as st
from scipy.optimize import minimize

def initialize(context):

# Used to track max-leverage
context.mx_lvrg = 0

context.SPY = sid(8554)
set_symbol_lookup_date('2015-01-01')
# Define the stocks in your target portfolio:
context.stocks =   [ sid(19662),  # XLY Consumer Discrectionary SPDR Fund
sid(19656),  # XLF Financial SPDR Fund
sid(19658),  # XLK Technology SPDR Fund
sid(19655),  # XLE Energy SPDR Fund
sid(19661),  # XLV Health Care SPRD Fund
sid(19657),  # XLI Industrial SPDR Fund
sid(19659),  # XLP Consumer Staples SPDR Fund
sid(19654),  # XLB Materials SPDR Fund
sid(19660) ] # XLU Utilities SPRD Fund

#set_universe(universe.DollarVolumeUniverse(floor_percentile=95.0, ceiling_percentile=100.0))
context.first = True
context.days = 9

def handle_data(context, data):
if context.account.leverage > context.mx_lvrg:
context.mx_lvrg = context.account.leverage
record(mx_lvrg = context.mx_lvrg)    # Record maximum leverage encountered

if context.days < 5:
context.days += 1
return

context.days = 0
prices = history(600, "1d", "price")

prices = prices.dropna(axis=1)
prices = prices.drop([context.SPY], axis=1)
copy = prices.copy(True)

for sid in copy:
if sid not in data:
prices = prices.drop([sid], axis=1)

context.prices = prices.values
x0 = [1. / np.shape(context.prices)[1]] * np.shape(context.prices)[1]
b = tuple((0, None) for x in x0)
res = minimize(variance_ratio, x0, args=(context), bounds=b)

p = np.dot(context.prices, res.x)
sign = np.sign(p[-1] - p[0])

wsum = 0
for i, sid in enumerate(prices):
val = sign * res.x[i] / np.sum(np.abs(res.x)) * context.portfolio.portfolio_value
if sid in data:
order_target_value(sid, val / 2)
wsum += val
order_target_value(context.SPY, -wsum / 2)

def variance_ratio(X, context):
P = np.dot(context.prices, X)

r = 0
ratio = []
for i in range(1,5):
r += np.corrcoef(P[:-i], P[i:])[0,1] * (1 - i / 5.)
ratio.append(r)

total = 0
for i in range(1, len(ratio)):
total += ratio[i] - ratio[i-1]
s,i,r,p,e = st.linregress(range(0, len(P)), P)
return -total * r

There was a runtime error.

Hi Pravin,

Could you please explain a little bit your idea behind this algo?

Many thanks!

Hi Thomas,

Thanks for bringing my attention this algorithm. It has some obvious errors. I will post a new back test with dynamic universe and an explanation today or tomorrow once I fix the errors.

Best regards,
Pravin

Hi Pravin,

have you fixed the error already? :-)

Thomas