Back to Community
Is this worth investing?

Hi Q,

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

Best regards,
Pravin

Clone Algorithm
65
Loading...
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 = symbols('XLE','AAPL','AAP','ABC','ADS','AGN','ALXN','AMG','AMGN','AMP','AMZN','ANTM','APD','AVB','AZO','BA','BCR','BDX','BIIB','BLK','BMRN','BXP','CB','CELG','CF','CHTR','CI','CLX','CMG','CMI','COST','CVS','CVX','CXO','DIS','ECL','EQIX','ESS','EW','FDX','FLT','GD','GILD','GMCR','GS','GWW','GOOG','HBI','HD','HON','HSIC','HSY','HUM','IBM','ICE','IEP','ILMN','ISRG','IVV','KMB','KSU','LLL','LMT','LNKD','MCK','MHFI','MHK','MJN','MKL','MMM','MNST','MON','MPC','MTB','NEE','NFLX','NOC','NSC','ORLY','PANW','PCLN','PCP','PCYC','PH','PII','PLL','PPG','PSA','PX','PXD','REGN','RL','ROK','ROP','RTN','SBAC','SHW','SIAL','SJM','SLG','SPG','SRCL','SRE','STZ','TDG','TMO','TRV','TRW','TSLA','TWC','UHS','UNH','UNP','UPS','UTX','V','VNO','VRTX','WDC','WHR','WYNN')
        
    context.first = True
    context.days = 9
    set_slippage(slippage.FixedSlippage(spread=0.00))
    schedule_function(trade,date_rules.every_day(),time_rules.market_open(minutes=15))
    
def handle_data(context, data):
    record(leverage=context.account.leverage)
    
def trade(context, data):
    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.

Loading notebook preview...

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.

Clone Algorithm
0
Loading...
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
    set_slippage(slippage.FixedSlippage(spread=0.00))
    schedule_function(trade,date_rules.every_day(),time_rules.market_open(minutes=15))
    
def handle_data(context, data):
    record(leverage=context.account.leverage)
    
def trade(context, data):
    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.

Clone Algorithm
4
Loading...
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
    set_slippage(slippage.FixedSlippage(spread=0.00))
    schedule_function(trade,date_rules.every_day(),time_rules.market_open(minutes=15))
    
def handle_data(context, data):
    record(leverage=context.account.leverage)
    
def trade(context, data):
    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
Clone Algorithm
2
Loading...
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
    #set_slippage(slippage.FixedSlippage(spread=0.00))
    schedule_function(trade,date_rules.every_day(),time_rules.market_open(minutes=15))
    
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  
    
def trade(context, data):
    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