This algorithm performs a standard mean-variance optimization over a group of large cap US stocks. The algorithm constructs an efficient frontier of allocations and allows the user to choose an allocation based on risk preference.

Ryan

Clone Algorithm

485

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 |

from numpy import matrix, array, zeros, empty, sqrt, ones, dot, append, mean, cov, transpose, linspace import numpy as np import scipy.optimize import math import random # This algorithm performs a Markowitz-style mean-variance optimization with a # universe of the 14 highest market capitalization stocks in the S&P 500. The # algorithm constructs an efficient frontier and then selects a weighting from # the efficient frontier. Uses ideas from the Global Minimum Variance Portfolio # algorithm posted on Quantopian. # This is the lwindow that governs the pulling of historical data and # portfolio rebalancing. window = 100 refresh_rate = 10 # Compute the expected return of the portfolio. def compute_mean(W,R): return sum(R*W) # Compute the variance of the portfolio. def compute_var(W,C): return dot(dot(W, C), W) # Combination of the two functions above - mean and variance of returns calculation. def compute_mean_var(W, R, C): return compute_mean(W, R), compute_var(W, C) def fitness(W, R, C, r): # For given level of return r, find weights which minimizes portfolio variance. mean, var = compute_mean_var(W, R, C) # Penalty for not meeting stated portfolio return effectively serves as optimization constraint # Here, r is the 'target' return penalty = 0.1*abs(mean-r) return var + penalty # Given risk-free rate, asset returns, and covariances, this function # calculates the weights of the tangency portfolio with regard to Sharpe # ratio maximization. def fitness_sharpe(W, R, C, rf): mean, var = compute_mean_var(W, R, C) utility = (mean - rf)/sqrt(var) return 1/utility # Solves for the optimal portfolio weights using the Sharpe ratio # maximization objective function. def solve_weights(R, C, rf): n = len(R) W = ones([n])/n # Start optimization with equal weights b_ = [(0.,1.) for i in range(n)] # Bounds for decision variables c_ = ({'type':'eq', 'fun': lambda W: sum(W)-1. }) # Constraints - weights must sum to 1 optimized = scipy.optimize.minimize(fitness, W, (R, C, rf), method='SLSQP', constraints=c_, bounds=b_) if not optimized.success: raise BaseException(optimized.message) return optimized.x # Solve for the efficient frontier using the variance + penalty minimization # function fitness. def solve_frontier(R, C, rf): frontier_mean, frontier_var, frontier_weights = [], [], [] n = len(R) # Number of assets in the portfolio for r in linspace(min(R), max(R), num=20): # Iterate through the range of returns on Y axis W = ones([n])/n # Set initial guess for weights b_ = [(0,1) for i in range(n)] # Set bounds on weights c_ = ({'type':'eq', 'fun': lambda W: sum(W)-1. }) # Set constraints optimized = scipy.optimize.minimize(fitness, W, (R, C, r), method='SLSQP', constraints=c_, bounds=b_) #if not optimized.success: # raise BaseException(optimized.message) # Add point to the efficient frontier frontier_mean.append(r) frontier_var.append(compute_var(optimized.x, C)) # Min-variance based on optimized weights frontier_weights.append(optimized.x) return array(frontier_mean), array(frontier_var), frontier_weights # Weights - array of asset weights (derived from market capitalizations) # Expreturns - expected returns based on historical data # Covars - covariance matrix of asset returns based on historical data def assets_meanvar(daily_returns): # Calculate expected returns expreturns = array([]) (rows, cols) = daily_returns.shape for r in range(rows): expreturns = append(expreturns, mean(daily_returns[r])) # Compute covariance matrix covars = cov(daily_returns) # Annualize expected returns and covariances # Assumes 255 trading days per year expreturns = (1+expreturns)**255-1 covars = covars * 255 return expreturns, covars def initialize(context): # Set day context.day = 0 # Set risk-free rate # 14 largest stocks by market cap in S&P in 2010 context.securities = [sid(24),sid(26578),sid(3149), sid(5061), sid(3766),sid(23112),sid(4151),sid(5938),sid(5923),sid(6653),sid(700), sid(1900), sid(8347), sid(8229)] # Set Max and Min positions in security context.max_notional = 1000000.1 context.min_notional = -1000000.0 # Set commission def handle_data(context, data): # Get 40 days of prices for each security all_prices = get_past_prices(data) # Circuit breaker in case transform returns none if all_prices is None: return # Circuit breaker, only calculate every 20 days if context.day%refresh_rate is not 0: context.day = context.day+1 return daily_returns = np.zeros((len(context.securities),window)) # Calculate daily returns into daily_returns security_index = 0; for security in context.securities: if data.has_key(security): for day in range(0,window): day_of = all_prices[security][day] day_before = all_prices[security][day-1] daily_returns[security_index][day] = (day_of-day_before)/day_before security_index = security_index + 1 expreturns, covars = assets_meanvar(daily_returns) R = expreturns C = covars rf = 0.015 frontier_mean, frontier_var, frontier_weights = solve_frontier(R, C, rf) f_w = array(frontier_weights) (row_1, col_1) = f_w.shape log.info(row_1) log.info(col_1) wts = frontier_weights[5] new_weights = wts #log.info(new_weights) #set leverage to 1 leverage = sum(abs(new_weights)) portfolio_value = (context.portfolio.positions_value + context.portfolio.cash)/leverage #reweight portfolio security_index = 0 for security in context.securities: current_position = context.portfolio.positions[security].amount new_position = (portfolio_value*new_weights[security_index])/all_prices[security][window-1] order(security,new_position-current_position) security_index = security_index+1 context.day = context.day+1 @batch_transform(refresh_period=refresh_rate, window_length=window) def get_past_prices(data): prices = data['price'] return prices

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.