from quantopian.pipeline import Pipeline from quantopian.algorithm import attach_pipeline, pipeline_output from quantopian.pipeline.data.builtin import USEquityPricing from quantopian.pipeline.factors import SimpleMovingAverage, CustomFactor, RSI, Latest from quantopian.pipeline.filters.morningstar import Q1500US, Q500US import quantopian.pipeline.data.morningstar as mstar import math import datetime import numpy as np import talib as ta import pandas as pd quarter_lenght = 65 latest = -1 one_year_ago = -4*quarter_lenght two_year_ago = -8*quarter_lenght ttm = [ -1, -quarter_lenght, -2*quarter_lenght, -3*quarter_lenght] ttm_py = [-4*quarter_lenght, -5*quarter_lenght, -6*quarter_lenght, -7*quarter_lenght] class Sector(CustomFactor): inputs = [mstar.asset_classification.morningstar_sector_code] window_length = 1 def compute(self, today, asset_ids, out, sector): out[:] = sector class Volatility(CustomFactor): inputs = [USEquityPricing.close] window_length = 252 def compute(self, today, assets, out, close): close = pd.DataFrame(data=close, columns=assets) out[:] = np.log(close).diff().std() class Value(CustomFactor): inputs = [mstar.valuation_ratios.fcf_ratio, mstar.valuation_ratios.ps_ratio, mstar.valuation_ratios.pe_ratio, mstar.valuation_ratios.pb_ratio, mstar.valuation_ratios.peg_ratio] window_length = 1 def compute(self, today, assets, out, fcf, ps, pe, pb, peg): value_table = pd.DataFrame(index=assets) value_table["fcf"] = fcf[-1] value_table["ps"] = ps[-1] value_table["pe"] = pe[-1] value_table["pb"] = pb[-1] value_table["peg"] = peg[-1] out[:] = value_table.rank(ascending=True).mean(axis=1) class FinancialStrength(CustomFactor): inputs = [mstar.cash_flow_statement.cash_flowsfromusedin_operating_activities_direct, mstar.balance_sheet.current_liabilities, mstar.cash_flow_statement.free_cash_flow, mstar.balance_sheet.long_term_debt] window_length =1 def compute(self, today, assets, out, cfo, current_liabilities, fcf, lt_debt): value_table = pd.DataFrame(index=assets) value_table["current_liability_coverage"] = (cfo[latest]/current_liabilities[latest]) value_table["fcf_cur_liability_cov"] = (fcf[latest]/current_liabilities[latest]) value_table["cfo_ltdebt"] = cfo[latest]/lt_debt[latest] value_table["fcf_ltdebt"] = fcf[latest]/lt_debt[latest] out[:] = value_table.rank().mean(axis=1) class Quality(CustomFactor): inputs = [mstar.operation_ratios.roe, mstar.operation_ratios.roa, mstar.operation_ratios.roic, mstar.operation_ratios.net_margin, mstar.operation_ratios.operation_margin, mstar.cash_flow_statement.cash_flowsfromusedin_operating_activities_direct, mstar.income_statement.total_revenue] window_length = 1 def compute(self, today, assets, out, roe, roa, roic, net_margin, operation_margin, ocf, sales): value_table = pd.DataFrame(index=assets) value_table["roe"] = roe[-1] value_table["roa"] = roa[-1] value_table["roic"] = roic[-1] value_table["net_margin"] = net_margin[-1] value_table["operation_margin"] = operation_margin[-1] value_table["op_cashflow_ratio"] = ocf[-1] / sales[-1] out[:] = value_table.rank().mean(axis=1) class Growth(CustomFactor): inputs = [mstar.earnings_ratios.diluted_eps_growth, mstar.earnings_ratios.dps_growth, mstar.earnings_ratios.equity_per_share_growth, mstar.operation_ratios.net_income_growth, mstar.operation_ratios.operation_income_growth, mstar.operation_ratios.revenue_growth] window_length = 1 def compute(self, today, assets, out, eps_growth, dps_growth, eqps_growth, net_income_growth, operation_income_growth, revenue_growth): value_table = pd.DataFrame(index=assets) value_table["eps_growth"] = eps_growth[-1] value_table["dps_growth"] = dps_growth[-1] value_table["eqps_growth"] = eqps_growth[-1] value_table["net_income_growth"] = net_income_growth[-1] value_table["operation_income_growth"] = operation_income_growth[-1] value_table["revenue_growth"] = revenue_growth[-1] out[:] = value_table.rank().mean(axis=1) def initialize(context): # Schedule our rebalance function to run at the start of each week. schedule_function(my_rebalance, date_rules.week_start(), time_rules.market_open(hours=1)) # Record variables at the end of each day. schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close()) # Create our pipeline and attach it to our algorithm. pipe = make_pipeline(context) attach_pipeline(pipe, 'pipeline') def make_pipeline(context): """ A function to create our dynamic stock selector (pipeline). Documentation on pipeline can be found here: https://www.quantopian.com/help#pipeline-title """ # Base universe set to the Q500US base_universe = Q1500US() quality = Quality(mask=base_universe) rankedQual = quality.rank(ascending=True) value = Value(mask=base_universe) rankedVal = value.rank(ascending=True) finStrength = FinancialStrength(mask=base_universe) RankedFinStrength = finStrength.rank(ascending=True) growth = Growth(mask=base_universe) rankedGrowth = growth.rank(ascending=True) longs = base_universe & rankedVal.percentile_between(50, 100) & rankedQual.percentile_between(75, 100) & rankedGrowth.percentile_between(50,100) & RankedFinStrength.percentile_between(60,100) & Volatility().rank().percentile_between(0,70) & (mScore < -2.22) & (altmanZ > 2.6) shorts = base_universe & rankedVal.percentile_between(0, 30) & rankedGrowth.percentile_between(0,50) & rankedQual.percentile_between(0,25) & RankedFinStrength.percentile_between(0, 40) #BullCross = SimpleMovingAverage(inputs=[USEquityPricing.close], mask=base_universe, window_length=50) > SimpleMovingAverage(inputs=[USEquityPricing.close], mask=base_universe, window_length=200) #ShortBull = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=10, mask=base_universe) > SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=50, mask=base_universe) #if context.bear == True: # longs = base_universe & rankedQual.percentile_between(90,100) & (ShortBull) #else: # longs = base_universe & rankedQual.percentile_between(95,100) & (BullCross) pipe = Pipeline( screen = base_universe, columns = { 'longs': longs, 'shorts': shorts, } ) return pipe def my_compute_weights(context): """ Compute ordering weights. """ # Compute even target weights for our long positions and short positions. #S&P 500 EMA calculations '''context.bear = False spy = symbol('SPY') historydata = history(bar_count = 201, frequency='1d', field='close_price') moving_average10 = ta.EMA(historydata[spy].values, timeperiod=10)[-1] moving_average50 = ta.EMA(historydata[spy].values, timeperiod=50)[-1] moving_average200 = ta.EMA(historydata[spy].values, timeperiod=200)[-1] ''' if(moving_average10 < moving_average50 < moving_average200): target_long_weight = 0.1 target_short_weight = -0.8 context.bear=True elif(moving_average10 > moving_average50 < moving_average200): target_long_weight = 1.0 target_short_weight = -0.3 elif(moving_average10 > moving_average50 > moving_average200): target_long_weight = 1.4 target_short_weight = -0.3 elif(moving_average10 < moving_average50 > moving_average200): target_long_weight = 1.3 target_short_weight = -0.3 if(len(context.longs) == 0): long_weight = 0 else: long_weight = 1.3 /len(context.longs) if(len(context.shorts) == 0): short_weight = 0 else: short_weight = -0.3 / len(context.shorts) return long_weight, short_weight def before_trading_start(context, data): context.output = pipeline_output('pipeline') # Go long in securities for which the 'longs' value is True. context.longs = context.output[context.output['longs']].index.tolist() # Go short in securities for which the 'shorts' value is True. context.shorts = context.output[context.output['shorts']].index.tolist() context.long_weight, context.short_weight = my_compute_weights(context) def my_rebalance(context, data): """ Rebalance weekly. """ # Gets our pipeline output every day. for security in context.portfolio.positions: if security not in context.longs and security not in context.shorts and data.can_trade(security) and security != symbol('SPY'): order_target_percent(security, 0) for security in context.longs: if data.can_trade(security): order_target_percent(security, context.long_weight) for security in context.shorts: if data.can_trade(security): order_target_percent(security, context.short_weight) def my_record_vars(context, data): """ Record variables at the end of each day. """ longs = shorts = 0 for position in context.portfolio.positions.itervalues(): if position.amount > 0: longs += 1 elif position.amount < 0: shorts += 1 # Record our variables. record(leverage=context.account.net_leverage, long_count=longs, short_count=shorts, target_longs=len(context.longs), target_shorts=len(context.shorts)) def handle_data(context,data): """ Called every minute. """ pass

Hi, so I've been checking out QuantConnect for a bit, and I'm wondering if there's any equivalent of Quantopian's pipeline API? I've been using Quantopian for a little bit but I'm still new to Quant algorithms. I've had some problems with timeouts and wanted to see if they'd run better here. Haven't looked very indepth so forgive me if I missed something. Pipeline let's you easily filter stocks by different factors instead of having to do queries and it simplifies things and takes care of any delistings and a bunch of that basic stuff. So if someone could show how to implement a version of my "Quality" factor, and a buy the top 25% and short the bottom 25%, rebalancing that every week for example? And then I'd probably get it and be able to finish the rest, I don't have much experience with python other than some really basic projects I did 4 years ago so if I'm making any big mistakes or if there are obvious optimizations, let me know too.

Thank you,

Steven

Author