Method:

1. Take related stocks (use clustering or simply use a sector)

2. Remove PC 1 factor

3. Sum the residuals and build 2 signals.

4. Trade portfolio

Clone Algorithm

646

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 math import numpy as np import pandas as pd import scipy as sp import cvxpy as cvx from sklearn.covariance import OAS from sklearn.decomposition import PCA import statsmodels.api as smapi from quantopian.pipeline import Pipeline from quantopian.pipeline.data.builtin import USEquityPricing from quantopian.algorithm import attach_pipeline, pipeline_output from quantopian.pipeline.filters.morningstar import Q500US from quantopian.pipeline.classifiers.morningstar import Sector from quantopian.pipeline.factors.morningstar import MarketCap from quantopian.pipeline.data import morningstar as mstar def make_pipeline(): price_filter = USEquityPricing.close.latest >= 15 pipe = Pipeline(screen=Q500US() & price_filter & Sector().eq(309)) pipe.add(mstar.asset_classification.morningstar_industry_group_code.latest, 'ind') return pipe def initialize(context): context.Hedge = sid(8554) context.counter = 90 set_commission(commission.PerShare(cost=0.001, min_trade_cost=0)) schedule_function(trade, date_rules.every_day(), time_rules.market_open(minutes=10)) schedule_function(update_chart, date_rules.every_day(), time_rules.market_close(minutes=1)) attach_pipeline(make_pipeline(), "Q500") def handle_data(context, data): pass def before_trading_start(context, data): if context.counter < 90: context.counter += 1 return context.counter = 0 context.output = pipeline_output("Q500") context.indices = context.output.index def trade(context, data): prices = data.history(context.indices, "price", 90, "1d").dropna(axis=1) logP = np.log(prices.values) diff = np.diff(logP, axis=0) factors = PCA(1).fit_transform(diff) model = smapi.OLS(diff, smapi.add_constant(factors)).fit() betas = model.params.T[:, 1:] R = sp.stats.zscore(model.resid[-2:, :].sum(axis=0)) - sp.stats.zscore(model.resid[-20:, :].sum(axis=0)) weights = getW(R, betas) denom = np.sum(np.abs(weights)) if denom == 0: denom = 1. weights = weights / denom for sid in context.portfolio.positions: if sid not in prices.columns: order_target(sid, 0) for i, sid in enumerate(prices.columns): if data.can_trade(sid): order_target_percent(sid, weights[i]) def getW(signal, betas): (m, n) = betas.shape x = cvx.Variable(m) objective = cvx.Maximize(signal.T * x) constraints = [cvx.abs(sum(x)) < 0.001, sum(cvx.abs(x)) <= 1, x <= 3.5 / m, -x <= 3.5 / m] for i in range(0, n): constraints.append(cvx.abs(betas[:, i].T * x) < 0.001) prob = cvx.Problem(objective, constraints) prob.solve(solver=cvx.CVXOPT) if prob.status <> 'optimal': print prob.status return np.asarray([0.] * m) return np.asarray(x.value).flatten() def update_chart(context,data): record(leverage = context.account.leverage) longs = shorts = 0 for position in context.portfolio.positions.itervalues(): if position.amount > 0: longs += 1 if position.amount < 0: shorts += 1 record(l=longs,s=shorts)