Hi all,

I attached a backtest of a simple fundamental analysis using the pipeline. I used P/B, P/E, Roa, Roe and Roic and some filters like market cap, momentum and volatility.

I think the result is good but maybe it might be maximized grouping the stocks by sector before rank them but I don't know exactly how to do it.

For example technology Sector has very high P/E compared to consumer defensive one so I think technology stock should be ranked within their Sector and so on for all other Sector and ratio.

Thanks

Michele

Clone Algorithm

119

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 |

"""" scoring based on valuation ratio filtered on mkt cap, momentum and volatility different weight for different ratio """ from quantopian.algorithm import attach_pipeline, pipeline_output from quantopian.pipeline import Pipeline from quantopian.pipeline import CustomFactor from quantopian.pipeline.data.builtin import USEquityPricing from quantopian.pipeline.data import morningstar import pandas as pd import numpy as np class Sector(CustomFactor): inputs = [morningstar.asset_classification. morningstar_sector_code] window_length = 1 def compute(self, today, assets, out, sector): table = pd.DataFrame(index=assets) table ["sector"] = sector[-1] out[:] = table.fillna(0).mean(axis=1) # Create custom factor #2 Price of 10 days ago.y / Price of 30 days ago. class Momentum(CustomFactor): # Pre-declare inputs and window_length inputs = [USEquityPricing.close] window_length = 30 def compute(self, today, assets, out, close): out[:] = close[-10]/close[0] class Pricetobook(CustomFactor): # Pre-declare inputs and window_length inputs = [morningstar.valuation_ratios.pb_ratio] window_length = 1 def compute(self, today, assets, out, pb): table = pd.DataFrame(index=assets) table ["pb"] = pb[-1] out[:] = table.fillna(table.max()).mean(axis=1) class Pricetoearnings(CustomFactor): # Pre-declare inputs and window_length inputs = [morningstar.valuation_ratios.pe_ratio] window_length = 1 def compute(self, today, assets, out, pe): table = pd.DataFrame(index=assets) table ["pe"] = pe[-1] out[:] = table.fillna(table.max()).mean(axis=1) class Roa(CustomFactor): # Pre-declare inputs and window_length inputs = [morningstar.operation_ratios.roa] window_length = 1 def compute(self, today, assets, out, roa): table = pd.DataFrame(index=assets) table ["roa"] = roa[-1] out[:] = table.fillna(table.min()).mean(axis=1) class Roe(CustomFactor): # Pre-declare inputs and window_length inputs = [morningstar.operation_ratios.roe] window_length = 1 def compute(self, today, assets, out, roe): table = pd.DataFrame(index=assets) table ["roe"] = roe[-1] out[:] = table.fillna(table.min()).mean(axis=1) class Roic(CustomFactor): # Pre-declare inputs and window_length inputs = [morningstar.operation_ratios.roic] window_length = 1 def compute(self, today, assets, out, roic): table = pd.DataFrame(index=assets) table ["roic"] = roic[-1] out[:] = table.fillna(table.min()).mean(axis=1) class Volatility(CustomFactor): # pre-declared inputs and window length inputs = [USEquityPricing.close] window_length = 15 # compute standard deviation def compute(self, today, assets, out, close): out[:] = np.std(close, axis=0) # Create custom factor to calculate a market cap based on yesterday's close # We'll use this to get the top 2000 stocks by market cap class MarketCap(CustomFactor): # Pre-declare inputs and window_length inputs = [USEquityPricing.close, morningstar.valuation.shares_outstanding] window_length = 1 # Compute market cap value def compute(self, today, assets, out, close, shares): out[:] = close[-1] * shares[-1] def initialize(context): pipe = Pipeline() attach_pipeline(pipe, 'ranked_2000') sector = Sector() pipe.add(sector, 'sector') momentum = Momentum() pipe.add(momentum, 'momentum') pb = Pricetobook() pipe.add(pb, 'pb') pe = Pricetoearnings() pipe.add(pe, 'pe') roa = Roa() pipe.add(roa, 'roa') roe = Roe() pipe.add(roe, 'roe') roic = Roic() pipe.add(roic, 'roic') vol = Volatility() pipe.add(vol, 'vol') # Create and apply a filter representing the top 2000 equities by MarketCap every day mkt_cap = MarketCap() top_2000 = mkt_cap.top(2000) #lower is better vol_rank = vol.rank(mask=top_2000, ascending=True) pipe.add(vol_rank, 'vol_rank') pb_rank = pb.rank(mask=top_2000, ascending=True) pipe.add(pb_rank, 'pb_rank') pe_rank = pe.rank(mask=top_2000, ascending=True) pipe.add(pe_rank, 'pe_rank') #higher is better roa_rank = roa.rank(mask=top_2000, ascending=False) pipe.add(roa_rank, 'roa_rank') roe_rank = roe.rank(mask=top_2000, ascending=False) pipe.add(roe_rank, 'roe_rank') roic_rank = roic.rank(mask=top_2000, ascending=False) pipe.add(roic_rank, 'roic_rank') #different weight per different ratio combo_raw = (1*pb_rank+1*pe_rank+3*roa_rank+3*roe_rank+3*roic_rank)/10 pipe.add(combo_raw, 'combo_raw') # Rank the combo_raw and add that to the pipeline pipe.add(combo_raw.rank(mask=top_2000), 'combo_rank') #market cap, momentum and volarility filter pipe.set_screen(top_2000 & (momentum>1) & (vol_rank.top(400))) # Scedule my rebalance function schedule_function(func=rebalance, date_rule=date_rules.month_start(days_offset=0), time_rule=time_rules.market_open(hours=0,minutes=30), half_days=True) # Schedule my plotting function schedule_function(func=record_vars, date_rule=date_rules.every_day(), time_rule=time_rules.market_close(), half_days=True) # set my leverage context.long_leverage = 0.95 def before_trading_start(context, data): # Call pipelive_output to get the output context.output = pipeline_output('ranked_2000') # Narrow down the securities to only the top 20 & update my universe context.long_list = context.output.sort_values(['combo_rank'], ascending=True).iloc[:20] def record_vars(context, data): # Record and plot the leverage of our portfolio over time. record(leverage = context.account.leverage) print "Long List" log.info("\n" + str(context.long_list.sort_values(['combo_rank'], ascending=True).head(3))) # This rebalancing is called according to our schedule_function settings. def rebalance(context,data): try: long_weight = context.long_leverage / float(len(context.long_list)) except ZeroDivisionError: long_weight = 0 #maximum weight per single stock if long_weight > 0.054 : long_weight = 0.05 for long_stock in context.long_list.index: log.info("ordering longs") log.info("weight is %s" % (long_weight)) order_target_percent(long_stock, long_weight) for stock in context.portfolio.positions.iterkeys(): if stock not in context.long_list.index: order_target(stock, 0)