Here's a long-short algo with CVXPY, perhaps of interest. Nothing too sexy, but it shows that CVXPY can be used.

Note that although the long-term beta is low, there is nothing forcing a market neutral portfolio on a week-by-week basis, so a contest entry might not satisfy the abs(beta) < 0.3 rule.

Clone Algorithm

74

Loading...

There was an error loading this backtest.
Retry

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 cvxpy as cvx import numpy as np from quantopian.algorithm import attach_pipeline, pipeline_output from quantopian.pipeline import Pipeline from quantopian.pipeline.data import morningstar as mstar from quantopian.pipeline.filters import Q1500US np.random.seed(seed=31415927) def initialize(context): schedule_function(rebalance, date_rules.week_start(days_offset=1),time_rules.market_open(hours=1)) attach_pipeline(make_pipeline(context), 'my_pipe') def make_pipeline(context): profitable = mstar.valuation_ratios.ev_to_ebitda.latest > 0 market_cap = mstar.valuation.market_cap.latest top_market_cap = market_cap.top(50, mask = Q1500US() & profitable) return Pipeline(screen = top_market_cap) def before_trading_start(context,data): output = pipeline_output('my_pipe') context.stocks = output.index.tolist() record(leverage = context.account.leverage) num_secs = 0 for stock in context.portfolio.positions.keys(): if context.portfolio.positions[stock].amount != 0: num_secs += 1 record(num_secs = num_secs) def rebalance(context,data): m = len(context.stocks) prices = data.history(context.stocks, 'price', 390*5, '1m').dropna(axis=1) context.stocks = list(prices.columns.values) prices = prices.ewm(com=30).mean().as_matrix(context.stocks) x_tilde = np.mean(prices,axis=0)/prices[-1,:] d = np.ones(m) x_tilde = np.mean(prices,axis=0)/prices[-1,:] y_tilde = 1.0/x_tilde d[x_tilde < 1] = -1 x_tilde[x_tilde < 1] = 0 y_tilde[x_tilde != 0] = 0 x_tilde = x_tilde + y_tilde b_t = np.zeros(m) for i, stock in enumerate(context.stocks): b_t[i] = abs(context.portfolio.positions[stock].amount*data.current(stock,'price')) denom = np.sum(b_t) # test for divide-by-zero case if denom > 0: b_t = b_t/denom else: b_t = np.random.random_sample((m,)) b_t = b_t/np.sum(b_t) x = cvx.Variable(m) objective = cvx.Minimize(cvx.sum_entries(cvx.square(x-b_t))) constraints = [cvx.sum_entries(x) == 1, cvx.sum_entries(x_tilde*x) >= 1, x >= 0.2/m] prob = cvx.Problem(objective, constraints) prob.solve() weight = np.squeeze(np.asarray(x.value)) if prob.status != 'optimal': return weight = d*weight denom = np.sum(np.absolute(weight)) # test for divide-by-zero case if denom > 0: weight = weight/denom else: return for i,stock in enumerate(context.stocks): if data.can_trade(stock): order_target_percent(stock, weight[i]) for stock in context.portfolio.positions.keys(): if stock not in context.stocks: if data.can_trade(stock): order_target_percent(stock,0)