This algorithm attempts to rebuild an ETF using different positive weights. It's a long only portfolio hedged by ETF. The idea is the excess returns (returns on top of ETF returns) of each stock can be used to run an optimization problem to maximize these returns with a threshold on variance < variance of ETF. I had to put a constraint on minimum weight of each stock else some stocks had zero weight.

Clone Algorithm

588

Loading...

There was an error loading this backtest.

Backtest from
to
with
initial capital

Cumulative performance:

Algorithm
Benchmark

Custom data:

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 math import pandas as pd import statsmodels.api as smapi from sklearn.covariance import OAS from cvxopt import solvers, matrix def initialize(context): set_symbol_lookup_date('2015-08-01') context.XLE = sid(19655) set_slippage(slippage.FixedSlippage(spread=0)) context.stocks = symbols('XOM','CVX','SLB','KMI','EOG','WMB','OXY','VLO','PSX','COP','APC','PXD','TSO','HAL') set_benchmark(context.XLE) schedule_function(myfunc,date_rule=date_rules.every_day(),time_rule=time_rules.market_close(minutes=30)) def handle_data(context, data): record(l=context.account.leverage) pass def myfunc(context, data): prices = history(200, "1d", "price") xle = prices[context.XLE].pct_change().dropna().values xle = np.log1p(xle) prices = prices.dropna(axis=1) prices = prices.drop([context.XLE], axis=1) ret = prices.pct_change().dropna().values ret = np.log1p(ret) s = [] for i, sid in enumerate(prices): X = xle Y = ret[:,i] - xle s.append(mycov(X,Y)) excess = ret - np.tile(xle, (np.shape(ret)[1],1)).T scores = reweight(s, OAS().fit(excess).covariance_, np.std(xle)) scores = np.ravel(scores) wsum = 0 for i, sid in enumerate(prices): val = 150000 * scores[i] / np.sum(np.abs(scores)) order_target_value(sid, val) wsum += val order_target_value(context.XLE, -wsum) def mycov(x, y): xl = pd.ewma(x, span=10) xs = pd.ewma(x, span=5) ys = pd.ewma(y, span=5) yl = pd.ewma(y, span=10) diff = [] for i in range(0, len(xs)): diff = (xs[i] - xl[i]) * (ys[i] - yl[i]) return np.mean(diff) def reweight(ret, cov, xlestd): numPOS = len(ret) pbar = ret U,V = np.linalg.eig(cov) U[U<0] = 0 Usqrt = np.sqrt(U) A = np.dot(np.diag(Usqrt),V.T) G1temp = np.zeros((A.shape[0]+1,A.shape[1])) G1temp[1:,:] = -A h1temp = np.zeros((A.shape[0]+1,1)) h1temp[0] = xlestd for i in np.arange(numPOS): ei = np.zeros((1,numPOS)) ei[0,i] = 1 if i == 0: G2temp = [matrix(-ei)] h2temp = [matrix([[-0.05]])] else: G2temp += [matrix(-ei)] h2temp += [matrix([-0.05])] Ftemp = np.ones((1,numPOS)) F = matrix(Ftemp) g = matrix(np.ones((1,1))) G = [matrix(G1temp)] + G2temp H = [matrix(h1temp)] + h2temp solvers.options['show_progress'] = False sol = solvers.socp(-matrix(pbar),Gq=G,hq=H,A=F,b=g) xsol = np.array(sol['x']) return xsol