I have done this algo and it works well until 2009, but after that it stops making orders.
I have checked in the debugger and in this code the variables context.long_list and context.weigths are correctly populated.
So i cannot understand why it stops working.
for long_stock in context.long_list:
if long_stock in data:
if long_stock in context.dont_buys:
continue
order_target_percent(long_stock, context.weigths.loc[long_stock])
Clone Algorithm
4
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 quantopian.algorithm import attach_pipeline, pipeline_output from quantopian.pipeline import Pipeline from quantopian.pipeline.factors import CustomFactor, SimpleMovingAverage from quantopian.pipeline.data.builtin import USEquityPricing from quantopian.pipeline.data import morningstar import datetime import statsmodels.api as sm import numpy as np import pandas as pd ''' Algo Logic: 1) define market uptrend and downtrend by the 252 days slope. 2) Group all stocks by sectors 3) Filter all the stocks of each sector by a combination of these factors: growth, value, roic, quality and 1/volatility 4) if the market is uptrend buy cyclical and sensitive stocks 5) if the market is downtrend buy sensitive and defensive stocks ''' def initialize(context): context.num_stocks = 3 context.defensive_sectors = [205,206,207] #Consumer_defensive, HealthCare, Utilities context.cyclical_sectors = [101,102,103,104] # Basic Materials, Consumer Cyclical, Financials, Real Estate context.sensitive_sectors = [308,309,310,311] # Communication, Energy, Industrials, Technology context.sectors = context.defensive_sectors + context.cyclical_sectors + context.sensitive_sectors context.fundamental_factors = ['growth', 'value','quality','roic', 'volatility'] context.weigth = 0.95/(11*context.num_stocks) set_commission(commission.PerShare(cost=0, min_trade_cost=0)) set_slippage(slippage.FixedSlippage(spread=0)) create_pipeline(context) schedule_function(func=rebalance, date_rule=date_rules.month_end(days_offset=0), time_rule=time_rules.market_open(hours=0,minutes=30), half_days=True) schedule_function(func = cancel_open_orders, date_rule = date_rules.every_day(), time_rule = time_rules.market_close(minutes=5),half_days=True ) def handle_data(context, data): # Record and plot the leverage, number of positions, and expsoure of our portfolio over time. record( exposure=context.account.net_leverage, longs = len([s for s in data if context.portfolio.positions[s].amount > 0]), shorts = len([s for s in data if context.portfolio.positions[s].amount < 0]), leverage=context.account.leverage) def before_trading_start(context, data): context.output = pipeline_output('ranking_example') #~~~~~~ RESET DICTS AND LISTS ~~~~~~# context.long_list=[] weigths = {} #~~~~~~ FILTER OUT DELISTED STOCKS ~~~~~~# context.output['end_date'] = [stock.end_date for stock in context.output.index] context.output = context.output[(context.output['end_date'] > (get_datetime()+datetime.timedelta(days=10)))] df = context.output #~~~~~~ SECOND FILTERING: RANKING EACH SECTORS STOCKS ~~~~~~# grouped = df.groupby('sector') for sector, group in grouped: if group['slope'].mean() > 0.0: #trend up: buy it --> select good stocks roic = group['roic'] > 0.0 growth = group['growth'] > 0.0 value = group['value'] > group['value'] .mean() quality = group['quality'] > group['quality'].mean() group = group[roic & growth & value & quality] group = group[context.fundamental_factors] normalized = group.apply(normalize) fund = normalized.sum(axis=1) selected = fund.order(ascending=False).iloc[:context.num_stocks] long_stocks = selected.index.tolist() volatility = group['volatility'].loc[long_stocks] weigths[sector] = volatility if len(long_stocks) > 0: for stock in long_stocks: context.long_list.append(stock) else: pass # No good stocks for this sector else: pass # Sector has negative slope long_weigths = pd.DataFrame(weigths) long_weigths = long_weigths.sum(axis=1) context.weigths = long_weigths/long_weigths.sum() update_universe(context.long_list) def rebalance(context,data): # Order our longs log.info("ordering longs") for long_stock in context.long_list: if long_stock in data: if long_stock in context.dont_buys: continue order_target_percent(long_stock, context.weigths.loc[long_stock]) # Get rid of any stocks incorrectly held for security in context.portfolio.positions: if get_open_orders(security): continue if security in data: if security in context.dont_buys: continue if security not in context.long_list: order_target_percent(security, 0) def create_pipeline(context): pipe_columns = {'roic': Value(), 'growth': Quality(), 'sector':Sector(), 'quality':Quality(), 'value':Value(), 'slope': Slope(window_length=252), 'volatility': Volatility()} pipe = Pipeline(columns=pipe_columns) attach_pipeline(pipe, 'ranking_example') # We'll use this to screen out illiquid stocks... dollar_volume = AvgDailyDollarVolumeTraded() high_dollar_volume = dollar_volume > 10**7 # ...and this to screen out penny stocks. sma_200 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=200) price = USEquityPricing.close.latest not_a_penny_stock = sma_200 > 5.0 # Implement both of our screens. pipe.set_screen(high_dollar_volume & not_a_penny_stock) # Used to avoid purchasing any leveraged ETFs context.dont_buys = [sec for sec in security_lists.leveraged_etf_list] def cancel_open_orders(context, data): for security in get_open_orders(): for order in get_open_orders(security): cancel_order(order) class Value(CustomFactor): # Pre-declare inputs and window_length inputs = [morningstar.income_statement.ebit, morningstar.valuation.enterprise_value] window_length = 1 def compute(self, today, assets, out, ebit, ev): out[:] = ebit[-1] / ev[-1] # Create a fundamental based custom "Quality" (profitability) factor class Quality(CustomFactor): inputs = [morningstar.operation_ratios.roe] window_length = 1 def compute(self, today, assets, out, roe): out[:] = roe[-1] class Roic(CustomFactor): inputs = [morningstar.operation_ratios.roic] window_length = 1 def compute(self, today, assets, out, roic): out[:] = roic[-1] class Growth(CustomFactor): inputs = [morningstar.operation_ratios.revenue_growth] window_length = 1 def compute(self, today, assets, out, growth): out[:] = growth[-1] class Sector(CustomFactor): inputs = [morningstar.asset_classification.morningstar_sector_code] window_length= 1 def compute(self, today, assets, out, sector): out[:] = sector[-1] class PEG(CustomFactor): inputs = [morningstar.valuation_ratios.peg_ratio] window_length = 1 def compute(self, today, assets, out, peg): out[:] = peg[-1] class AvgDailyDollarVolumeTraded(CustomFactor): inputs = [USEquityPricing.close, USEquityPricing.volume] window_length = 20 def compute(self, today, assets, out, close_price, volume): out[:] = np.mean(close_price * volume, axis=0) class Slope(CustomFactor): inputs = [USEquityPricing.close] def compute(self, today, assets, out, prices): Y = prices X = range(len(prices)) A = sm.add_constant(X) results = sm.OLS(Y,A).fit() (b, a) =results.params slope = a / b * 252.0 out[:] = slope class PE_ratio(CustomFactor): inputs = [morningstar.valuation_ratios.pe_ratio] window_length= 1 def compute(self, today, assets, out, pe): out[:] = pe[-1] class Volatility(CustomFactor): inputs = [USEquityPricing.close] window_length = 252 def compute(self, today, assets, out, close): close = pd.DataFrame(data=close, columns=assets) # Since we are going to rank largest is best we need to invert the sdev. out[:] = 1 / np.log(close).diff().std() normalize = lambda x : (x-x.mean())/x.std()