def initialize(context): universe = QTradableStocksUS() sector = Sector() momentum = Momentum() pipe = Pipeline() pipe.add(sector, 'sector') # ALPHA asset_turnover = Fundamentals.assets_turnover.latest.winsorize(.05, .95).zscore() ciwc = Fundamentals.change_in_working_capital.latest.winsorize(.05, .95).zscore() alpha = (asset_turnover + ciwc).rank().demean() pipe.add(alpha, 'alpha') # BETA beta = RollingLinearRegressionOfReturns(target=sid(8554), returns_length=5, regression_length=252, mask=alpha.notnull() & Sector().notnull() ).beta pipe.add(beta, 'beta') # REGISTER PIPELINES # ------------------ attach_pipeline(pipe, 'pipe') attach_pipeline(risk_loading_pipeline(), 'risk_loading_pipeline') pipe.set_screen(alpha.notnull() & Sector().notnull() & beta.notnull() & universe & (momentum>0)) # SCHEDULE FUNCTIONS # ------------------ schedule_function(rebalance, date_rule=date_rules.every_day(), time_rule=time_rules.market_open(minutes=10))
def initialize(context): # DEFINE UNIVERSE # ------------------ universe = QTradableStocksUS() # ALPHA GENERATION # ---------------- # COMPUTE Z SCORES: ASSET TURNOVER AND CHANGE IN WORKING CAPITAL # BOTH ARE FUNDAMENTAL VALUE MEASURES asset_turnover = Fundamentals.assets_turnover.latest.winsorize( .05, .95).zscore() ciwc = Fundamentals.change_in_working_capital.latest.winsorize( .05, .95).zscore() # ALPHA COMBINATION # ----------------- # ASSIGN EVERY ASSET AN ALPHA RANK AND CENTER VALUES AT 0 (DEMEAN). alpha = (asset_turnover + 2 * ciwc).rank().demean() # BETA DEFINITION beta = 0.66 * RollingLinearRegressionOfReturns( target=sid(8554), returns_length=5, regression_length=252, mask=alpha.notnull() & Sector().notnull()).beta + 0.33 * 1.0 # CREATE AND REGISTER PIPELINE #------------------------------- # COMPUTES COMBINES ALPHA AND SECTOR CODE FOR UNIVERSE OF STOCKS TO BE USED IN OPTIMIZATION pipe = Pipeline( columns={ 'alpha': alpha, 'sector': Sector(), 'beta': beta, }, # RETURN ONLY "NOT NULL" VALUES IN OUR PIPELINE screen=alpha.notnull() & Sector().notnull() & beta.notnull() & universe, ) # LOAD ALL PIPELINES algo.attach_pipeline(pipe, 'pipe') algo.attach_pipeline(risk_loading_pipeline(), 'risk_loading_pipeline') # SCHEDULE FUNCTIONS #-------------------- algo.schedule_function( do_portfolio_construction, date_rule=algo.date_rules.week_start(), time_rule=algo.time_rules.market_open(minutes=10), half_days=False, )
def make_pipeline(): # Set the universe to the QTradableStocksUS & stocks with Sector defined universe = QTradableStocksUS() & Sector().notnull() # A Filterfor market cap greater than 1 billion medium_cap = Fundamentals.market_cap.latest > 1000000000 # We don't choose from Financial and Ultility Sector not_Finan_and_Ulti = ((Sector != 103) & (Sector != 207)) # the final universe universe = universe & medium_cap & not_Finan_and_Ulti #Create an object of Earnings_Yield and rank them in descending order earnings_yield = Earnings_Yield() EY_rank = earnings_yield.rank(ascending=False, mask=universe) #Create an object of Return on invested Capital and rank them in descending order roic= Return_on_Invested_Capital() roic_rank = roic.rank(ascending=False, mask=universe) # the rank of magic formula is equal to the sum of rank of Earning Yields and Return on invested capital Magic_Formula_rank = EY_rank + roic_rank pipe = Pipeline(columns = { 'earnings_yield': earnings_yield, 'Earnings_yield_rank':EY_rank, 'roic' : roic, 'Roic_rank': roic_rank, 'MagicFormula_rank': Magic_Formula_rank, }, screen = universe ) return pipe
def make_pipeline2(): pipe = Pipeline() '''standards''' book_to_price = 1 / Latest([Fundamentals.pb_ratio]) PE = Latest([Fundamentals.pe_ratio]) #research_and_development = Latest([Fundamentals.research_and_development]) gross_dividend_payment = Latest([Fundamentals.gross_dividend_payment]) value_score = Latest([Fundamentals.value_score]) returns = Returns(inputs=[USEquityPricing.close], window_length=2) growth_score = Latest([Fundamentals.growth_score]) profit_grade = Fundamentals.profitability_grade.latest financial_health_grade = Fundamentals.financial_health_grade.latest '''filter''' #profit_requirement = (profit_grade=='A') | (profit_grade=='B') mask = QTradableStocksUS() mask &= Sector().eq(sector) #mask &= value_score > 30 mask &= PE < 35 mask &= USEquityPricing.volume.latest > 10000 '''pipeline''' pipe = Pipeline(columns={ 'Returns': returns, 'B/P': book_to_price, 'P/E': PE, 'Dividends': gross_dividend_payment, 'Value Score': value_score, 'Growth_Score': growth_score, 'Profit_Grade': profit_grade, 'Financial_Health': financial_health_grade }, screen=mask) return pipe
def make_pipeline(context): # Use a universe of just the top 500 US stocks universe = Q500US() sector = Sector() # Determine if the market is trending up or down. If the market is trending down then just buy bonds. If it is trending up then buy stocks # This is not an optimal solution and will obviously not work in all future market crashes spy_ma_fast_slice = SMA( inputs=[USEquityPricing.close], window_length=context.TF_FAST_LOOKBACK)[context.SPY] spy_ma_slow_slice = SMA( inputs=[USEquityPricing.close], window_length=context.TF_SLOW_LOOKBACK)[context.SPY] spy_ma_fast = SMA(inputs=[spy_ma_fast_slice], window_length=1) spy_ma_slow = SMA(inputs=[spy_ma_slow_slice], window_length=1) # If the 100 moving average crosses the 10 then alter the trend up variable trend_up = spy_ma_fast > spy_ma_slow # Get simple factors to determine "quality" companies cash_return = ms.cash_return.latest.rank(mask=universe) fcf_yield = ms.fcf_yield.latest.rank(mask=universe) roic = ms.roic.latest.rank(mask=universe) rev_growth = ms.revenue_growth.latest.rank(mask=universe) value = (cash_return + fcf_yield).rank(mask=universe) # Find sentiment rank using https://www.quantopian.com/posts/sentiment-as-a-factor sentiment_score = SMA( inputs=[sentiment.sentiment_signal], window_length=30, ) sentiment_score_zscore = sentiment_score.zscore() sentiment_overall_rank = sentiment_score_zscore.rank( mask=universe, groupby=sector).demean() # Combine factors to create one single ranking system quality = roic + rev_growth + value + sentiment_overall_rank # Create a 'momentum' factor by looking back over the last 140 days (20 weeks). momentum = Returns(window_length=context.MOMENTUM_LOOKBACK_DAYS) # Filters for top quality and momentum to use in the selection criteria top_quality = quality.top(context.TOP_ROE_QTY, mask=universe) top_quality_momentum = momentum.top(context.TARGET_SECURITIES, mask=top_quality) # Only return values to be used in the selection criteria by using the screen parameter pipe = Pipeline(columns={ 'trend_up': trend_up, 'top_quality_momentum': top_quality_momentum, }, screen=top_quality_momentum) return pipe
def make_pipeline(): base_universe = QTradableStocksUS() sector = Sector() sector2 = morningstar.asset_classification.morningstar_sector_code.latest healthcare_sector = sector.eq(206) airline_sector = sector2.eq(31053108) sent = sentiment.sentiment_signal.latest longs = healthcare_sector and (sent > 3) shorts = airline_sector and (sent < 1) tradable_securities = (longs | shorts) and base_universe return Pipeline(columns={ 'longs': longs, 'shorts': shorts }, screen=tradable_securities)
def make_pipeline(context): """ A function to build out filtered stock list by sectors. """ # Hold sector object, which will be used as a column in the pipeline, identifying # each stock's sector. stocks_sector = Sector() # Possible short version of a pipeline without filters return Pipeline( columns={ 'sector_code': stocks_sector } )
def make_pipeline(): """ Create and return our pipeline. We break this piece of logic out into its own function to make it easier to test and modify in isolation. In particular, this function can be copy/pasted into research and run by itself. """ # By appending .latest to the imported morningstar data, we get builtin Factors # so there's no need to define a CustomFactor value = Fundamentals.ebit.latest / Fundamentals.enterprise_value.latest quality = Fundamentals.roe.latest # Classify all securities by sector so that we can enforce sector neutrality later sector = Sector() # Screen out non-desirable securities by defining our universe. # Removes ADRs, OTCs, non-primary shares, LP, etc. # Also sets a minimum $500MM market cap filter and $5 price filter mkt_cap_filter = Fundamentals.market_cap.latest >= 500000000 price_filter = USEquityPricing.close.latest >= 5 universe = QTradableStocksUS() & price_filter & mkt_cap_filter # Construct a Factor representing the rank of each asset by our value # quality metrics. We aggregate them together here using simple addition # after zscore-ing them combined_rank = (value.zscore() + quality.zscore()) # Build Filters representing the top and bottom 150 stocks by our combined ranking system. # We'll use these as our tradeable universe each day. longs = combined_rank.top(NUM_LONG_POSITIONS, mask=universe) shorts = combined_rank.bottom(NUM_SHORT_POSITIONS, mask=universe) # The final output of our pipeline should only include # the top/bottom 300 stocks by our criteria long_short_screen = (longs | shorts) # Create pipeline pipe = Pipeline(columns={ 'longs': longs, 'shorts': shorts, 'combined_rank': combined_rank, 'quality': quality, 'value': value, 'sector': sector }, screen=long_short_screen) return pipe
def make_pipeline(): exchange = Fundamentals.exchange_id.latest nyse_filter = exchange.eq('NYS') morningstar_sector = Sector() dollar_volume_decile = AverageDollarVolume(window_length=10).deciles() top_decile = (dollar_volume_decile.eq(9)) return Pipeline(columns={ 'exchange': exchange, 'sector_code': morningstar_sector, 'dollar_volume_decile': dollar_volume_decile }, screen=(nyse_filter & top_decile))
def make_pipeline(): # Define universe # =============================================== base_universe = QTradableStocksUS() value = morningstar.valuation_ratios.ev_to_ebitda.latest market_cap = morningstar.valuation.market_cap.latest > 2e9 #Screen Value universe1 = value.bottom(2 * (NUM_LONG_POSITIONS + NUM_SHORT_POSITIONS), mask=(QTradableStocksUS() & market_cap)) universe2 = value.top(2 * (NUM_LONG_POSITIONS + NUM_SHORT_POSITIONS), mask=(QTradableStocksUS() & market_cap)) #Screen Quality #universe3 = #universe4 = universe = base_universe & (universe1 | universe2) sector = Sector(mask=universe) # sector needed to construct portfolio # =============================================== factors = make_factors() combined_alpha = None for name, f in factors.iteritems(): if combined_alpha == None: combined_alpha = f(mask=universe) else: combined_alpha = combined_alpha + f(mask=universe) longs = combined_alpha.top(NUM_LONG_POSITIONS) shorts = combined_alpha.bottom(NUM_SHORT_POSITIONS) long_short_screen = (longs | shorts) beta = 0.66 * RollingLinearRegressionOfReturns( target=sid(8554), returns_length=5, regression_length=260, mask=long_short_screen).beta + 0.33 * 1.0 # Create pipeline pipe = Pipeline(columns={ 'combined_alpha': combined_alpha, 'sector': sector, 'market_beta': beta }, screen=long_short_screen) return pipe
def make_pipeline(): # Define universe # =============================================== base_universe = QTradableStocksUS() value = morningstar.valuation_ratios.ev_to_ebitda.latest market_cap = morningstar.valuation.market_cap.latest > 2e9 Long_universe = value.bottom(5*(NUM_LONG_POSITIONS), mask = (QTradableStocksUS() & market_cap)) Short_universe = value.top(5*(NUM_LONG_POSITIONS), mask = (QTradableStocksUS() & market_cap)) sector_code = morningstar.asset_classification.morningstar_sector_code.latest sector_screen = (~sector_code.eq(103) and ~sector_code.eq(104) ) universe = QTradableStocksUS() & market_cap & sector_screen & (Long_universe | Short_universe) sector = Sector(mask=universe) # sector needed to construct portfolio # =============================================== factors = make_factors() combined_alpha = None for name, f in factors.iteritems(): if combined_alpha == None: combined_alpha = f(mask=universe) else: combined_alpha = combined_alpha + f(mask=universe) longs = combined_alpha.top(NUM_LONG_POSITIONS) #longs = (Long_universe & Quality) shorts = combined_alpha.bottom(NUM_SHORT_POSITIONS) #shorts = (Short_universe & bad_quality) long_short_screen = (longs | shorts) beta = 0.66*RollingLinearRegressionOfReturns( target=sid(8554), returns_length=5, regression_length=260, mask=long_short_screen ).beta + 0.33*1.0 # Create pipeline pipe = Pipeline(columns = { 'combined_alpha':combined_alpha, 'sector':sector, 'market_beta':beta }, screen = long_short_screen) return pipe
def make_pipeline(): """ Create our pipeline. """ # Base universe set to the Q1500US. base_universe = Q1500US() # 30-day close price average. mean_30 = ExponentialWeightedMovingAverage(inputs=[USEquityPricing.close], window_length=30, mask=base_universe, decay_rate=0.9) # 120-day close price average. mean_120 = ExponentialWeightedMovingAverage(inputs=[USEquityPricing.close], window_length=120, mask=base_universe, decay_rate=0.9) percent_difference = (mean_30 - mean_120) / mean_120 # Filter to select securities to long. longs = percent_difference.top(50) long_value = percent_difference # sector attribution sector = Sector() #pipeline construction return Pipeline( columns={ 'long value': long_value, 'sector': sector }, screen=longs, )
def make_pipeline(): pipe = Pipeline() '''standards''' book_to_price = 1 / Latest([Fundamentals.pb_ratio]) earning_to_price = 1 / Latest([Fundamentals.pe_ratio]) #research_and_development = Latest([Fundamentals.research_and_development]) gross_dividend_payment = Latest([Fundamentals.gross_dividend_payment]) value_score = Latest([Fundamentals.value_score]) returns = Returns(inputs=[USEquityPricing.close], window_length=2) '''filter''' mask = QTradableStocksUS() mask &= Sector().eq(sector) #mask &= value_score > 70 mask &= USEquityPricing.volume.latest > 10000 '''pipeline''' pipe = Pipeline(columns={ 'Returns': returns, 'B/P': book_to_price, 'E/P': earning_to_price, 'Dividends': gross_dividend_payment, 'Value_score': value_score }, screen=mask) return pipe
def make_pipeline(): """ 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 QTradableStocksUS mask = QTradableStocksUS() & Sector().notnull() mask &= (Fundamentals.market_cap.latest > 1000000000) mask &= ( (Fundamentals.morningstar_sector_code.latest != 103) & (Fundamentals.morningstar_sector_code.latest != 207) & (Fundamentals.morningstar_sector_code.latest != 206) & (Fundamentals.morningstar_sector_code.latest != 309) & (Fundamentals.morningstar_industry_code.latest != 20533080) & (Fundamentals.morningstar_industry_code.latest != 10217033) & (Fundamentals.morningstar_industry_group_code != 10106) & (Fundamentals.morningstar_industry_group_code != 10104) ) #mask &= (Fundamentals.total_debt_equity_ratio.latest < 1.0) earnings_yield = Fundamentals.ebit.latest/Fundamentals.enterprise_value.latest EY_rank = earnings_yield.rank(ascending=False, mask=mask) roic = Fundamentals.roic.latest roic_rank = roic .rank(ascending=False, mask=mask) debt_equity = Fundamentals.total_debt_equity_ratio.latest debt_equity_rank = debt_equity.rank(ascending=True, mask=mask) # lower is better div_yield = Fundamentals.trailing_dividend_yield.latest div_rank = div_yield.rank(ascending=False, mask=mask) # higher is better gross_margin = Fundamentals.gross_margin.latest gross_margin_rank = gross_margin.rank(ascending=False, mask=mask) rnd_ocf = Fundamentals.research_and_development.latest / Fundamentals.operating_cash_flow.latest rnd_ocf_rank = rnd_ocf.rank(ascending=False, mask=mask) total_yield = Fundamentals.total_yield.latest total_yield_rank = total_yield.rank(ascending=False, mask=mask) ma50 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=50, mask=mask) ma200 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=200, mask=mask) mv_yield = ma50 / ma200 mv_yield_rank = mv_yield.rank(ascending=False, mask=mask) revenue_growth = Fundamentals.revenue_growth.latest revenue_growth_rank = revenue_growth.rank(ascending=False, mask=mask) mf_rank = np.sum([ EY_rank, roic_rank, # returns = 24.12%, alpha = -.09, beta = 1.3, sharpe = .47, drawdown = -27.95% debt_equity_rank, # returns = 35.45%, alpha = -.04, beta = 1.18, sharpe = .65, drawdown = -30.26% #div_rank, # returns = 30.44%, alpha = -.05, beta = 1.07, sharpe = .65, drawdown = -22.73% gross_margin_rank, rnd_ocf_rank, total_yield_rank, revenue_growth_rank, # ]) # Factor of yesterday's close price. yesterday_close = USEquityPricing.close.latest pipe = Pipeline( columns={ 'mf_rank' : mf_rank, }, screen=mask ) return pipe
def make_pipeline(): # Windows used for moving averages windows = [10, 20, 50] price = USEquityPricing.close.latest # Let's calculate moving averages based on our windows price_ma_10 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=windows[0]) price_ma_20 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=windows[1]) price_ma_50 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=windows[2]) # Score the divergence momentum_score = .67 * ( (price_ma_10 - price_ma_20) / price_ma_20) + .33 * ( (price_ma_20 - price_ma_50) / price_ma_50) momentum_abs = momentum_score.abs() # Top decile of momentum_scores are our longs and bottom ten are shorts score_deciles = momentum_score.deciles() bottom_ten = score_deciles.eq(0) top_ten = score_deciles.eq(9) ################################################ # Now let's filter out all stocks we don't want: ################################################ # Screening for short positions shorts = bottom_ten # Screening for long positions longs = top_ten # Let's get dollar volume moving averages for each stock dv_ma_20 = AverageDollarVolume(window_length=20) dv_ma_5 = AverageDollarVolume(window_length=5) # We only want stocks with notable trade volume >$5,000,000 dv_min = dv_ma_20 > 5e6 # We want technology sector stocks sector = Sector().eq(Sector.TECHNOLOGY) # We don't want super cheap stocks not_cheap_stock = (price_ma_10 > 5) # Check for increasing trade volume inc_volume = dv_ma_5 > dv_ma_20 # Universe of stocks we want to trade that fit all our criteria universe = sector & not_cheap_stock & dv_min & inc_volume & (shorts | longs) return Pipeline( columns={ 'price': price, 'price_ma_10': price_ma_10, 'price_ma_20': price_ma_20, 'price_ma_50': price_ma_50, 'dollar_volume': dv_ma_5, 'momentum_score': momentum_score, 'momentum_abs': momentum_abs, 'long_bets': longs, 'short_bets': shorts, }, screen=universe, domain=US_EQUITIES, )
def initialize(context): # Universe Selection # ------------------ base_universe = QTradableStocksUS() # From what remains, each month, take the top UNIVERSE_SIZE stocks by average dollar # volume traded. monthly_top_volume = (AverageDollarVolume( window_length=LIQUIDITY_LOOKBACK_LENGTH).top( UNIVERSE_SIZE, mask=base_universe).downsample('week_start')) # The final universe is the monthly top volume &-ed with the original base universe. # &-ing these is necessary because the top volume universe is calculated at the start # of each month, and an asset might fall out of the base universe during that month. universe = monthly_top_volume & base_universe # Alpha Generation # ---------------- # Compute Z-scores of free cash flow yield and earnings yield. # Both of these are fundamental value measures. fcf_zscore = Fundamentals.fcf_yield.latest.zscore(mask=universe) yield_zscore = Fundamentals.earning_yield.latest.zscore(mask=universe) sentiment_zscore = psychsignal.stocktwits.bull_minus_bear.latest.zscore( mask=universe) # Alpha Combination # ----------------- # Assign every asset a combined rank and center the values at 0. # For UNIVERSE_SIZE=500, the range of values should be roughly -250 to 250. combined_alpha = (fcf_zscore + yield_zscore + sentiment_zscore).rank().demean() beta = 0.66 * RollingLinearRegressionOfReturns( target=sid(8554), returns_length=5, regression_length=260, mask=combined_alpha.notnull() & Sector().notnull()).beta + 0.33 * 1.0 # Schedule Tasks # -------------- # Create and register a pipeline computing our combined alpha and a sector # code for every stock in our universe. We'll use these values in our # optimization below. pipe = Pipeline( columns={ 'alpha': combined_alpha, 'sector': Sector(), 'sentiment': sentiment_zscore, 'beta': beta, }, # combined_alpha will be NaN for all stocks not in our universe, # but we also want to make sure that we have a sector code for everything # we trade. screen=combined_alpha.notnull() & Sector().notnull() & beta.notnull(), ) # Multiple pipelines can be used in a single algorithm. algo.attach_pipeline(pipe, 'pipe') algo.attach_pipeline(risk_loading_pipeline(), 'risk_loading_pipeline') # Schedule a function, 'do_portfolio_construction', to run twice a week # ten minutes after market open. algo.schedule_function( do_portfolio_construction, date_rule=algo.date_rules.week_start(), time_rule=algo.time_rules.market_open( minutes=MINUTES_AFTER_OPEN_TO_TRADE), half_days=False, )
print 'Number of securities that passed the filter: %d' % len(result) ''' 8. Classifiers ''' ''' Classifiers ''' # A classifier is a function from an asset and a moment in time to a categorical output # such as a string or integer label. from quantopian.pipeline.data import Fundamentals # Since the underlying data of Fundamentals.exchange_id # is of type string, .latest returns a Classifier exchange = Fundamentals.exchange_id.latest # Using Sector is equivalent to Fundamentals.morningstar_sector_code.latest from quantopian.pipeline.classifiers.fundamentals import Sector morningstar_sector = Sector() ''' Building Filters From Classifiers ''' # Classifier Methods: # https://www.quantopian.com/help#quantopian_pipeline_classifiers_Classifier # If we wanted a filter to select securities trading on the New York Stock Exchange, # we can use the eq method of our exchange classifier. nyse_filter = exchange.eq('NYS') ''' Quantiles ''' # Classifiers can also be produced from various Factor methods. # The most general of these is the quantiles method, # which accepts a bin count as an argument. # The quantiles classifier assigns a label from 0 to (bins - 1) to # every non-NaN data point in the factor output. NaNs are labeled with -1. # Aliases are available for quartiles (quantiles(4)), quintiles (quantiles(5)), # and deciles (quantiles(10)). As an example, this is what a filter for the
def make_pipeline(): """ Create and return our pipeline. We break this piece of logic out into its own function to make it easier to test and modify in isolation. In particular, this function can be copy/pasted into research and run by itself. """ # Create our momentum, value, and quality factors momentum = Momentum() # By appending .latest to the imported morningstar data, we get builtin Factors # so there's no need to define a CustomFactor value = Fundamentals.ebit.latest / Fundamentals.enterprise_value.latest quality = Fundamentals.roe.latest # Classify all securities by sector so that we can enforce sector neutrality later sector = Sector() # Screen out non-desirable securities by defining our universe. # Removes ADRs, OTCs, non-primary shares, LP, etc. # Also sets a minimum $500MM market cap filter and $5 price filter mkt_cap_filter = Fundamentals.market_cap.latest >= 500000000 price_filter = USEquityPricing.close.latest >= 5 universe = Q1500US() & price_filter & mkt_cap_filter # Construct a Factor representing the rank of each asset by our momentum, # value, and quality metrics. We aggregate them together here using simple # addition. # # By applying a mask to the rank computations, we remove any stocks that failed # to meet our initial criteria **before** computing ranks. This means that the # stock with rank 10.0 is the 10th-lowest stock that was included in the Q1500US. combined_rank = (momentum.rank(mask=universe).zscore() + value.rank(mask=universe).zscore() + quality.rank(mask=universe).zscore()) # Build Filters representing the top and bottom 150 stocks by our combined ranking system. # We'll use these as our tradeable universe each day. longs = combined_rank.top(NUM_LONG_POSITIONS) shorts = combined_rank.bottom(NUM_SHORT_POSITIONS) # The final output of our pipeline should only include # the top/bottom 300 stocks by our criteria long_short_screen = (longs | shorts) # Define any risk factors that we will want to neutralize # We are chiefly interested in market beta as a risk factor so we define it using # Bloomberg's beta calculation # Ref: https://www.lib.uwo.ca/business/betasbydatabasebloombergdefinitionofbeta.html beta = 0.66 * RollingLinearRegressionOfReturns( target=sid(8554), returns_length=5, regression_length=260, mask=long_short_screen).beta + 0.33 * 1.0 # Create pipeline pipe = Pipeline(columns={ 'longs': longs, 'shorts': shorts, 'combined_rank': combined_rank, 'quality': quality, 'value': value, 'momentum': momentum, 'sector': sector, 'market_beta': beta }, screen=long_short_screen) return pipe
def make_pipeline(): """ 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 QTradableStocksUS # Base universe set to the QTradableStocksUS mask = QTradableStocksUS() & Sector().notnull() mask &= (F.market_cap.latest > 1000000000) mask &= ((F.morningstar_sector_code.latest != 103) & (F.morningstar_sector_code.latest != 207) & (F.morningstar_sector_code.latest != 206) & (F.morningstar_sector_code.latest != 309) & (F.morningstar_industry_code.latest != 20533080) & (F.morningstar_industry_code.latest != 10217033) & (F.morningstar_industry_group_code != 10106) & (F.morningstar_industry_group_code != 10104)) mask &= (F.morningstar_sector_code.latest == 311) revenue_growth = F.revenue_growth.latest revenue_growth_rank = revenue_growth.rank(ascending=False, mask=mask) # higher is better rule_40 = F.revenue_growth.latest + F.net_margin.latest rule_40_rank = rule_40.rank(ascending=False, mask=mask) # higher is better ps_ratio = F.ps_ratio.latest ps_ratio_rank = ps_ratio.rank(ascending=True, mask=mask) # lower is better # relative historical self price to sales mean_ps = MeanPS() rel_ps = F.ps_ratio.latest / mean_ps rel_ps_rank = rel_ps.rank(ascending=True, mask=mask) # lower is better # run rate := cash on hand / operating expense run_rate = F.cash_and_cash_equivalents.latest / F.operating_expense run_rate_rank = run_rate.rank(ascending=False, mask=mask) # higher is better gross_margin = F.gross_margin.latest gross_margin_rank = gross_margin.rank(ascending=False, mask=mask) # Factor of yesterday's close price. yesterday_close = USEquityPricing.close.latest rank = np.sum([ #rule_40_rank, #rel_ps_rank, #run_rate_rank, #revenue_growth_rank, ps_ratio_rank, gross_margin_rank, ]) pipe = Pipeline(columns={ 'close': yesterday_close, 'rank': rank, }, screen=mask) return pipe
def make_pipeline(): base_universe = QTradableStocksUS() latest_close = USEquityPricing.close.latest latest_volume = USEquityPricing.volume.latest latest_close = USEquityPricing.close.latest mkt_cap = morningstar.valuation.market_cap.latest symbol_float1 = morningstar.Fundamentals.shares_outstanding.latest symbol_float2 = morningstar.Fundamentals.ordinary_shares_number.latest morningstar_sector = Sector() volume_3_months = AverageDollarVolume( window_length=66, mask=base_universe & (mkt_cap < 5000000000) #masking ) volume_1_day = AverageDollarVolume( window_length=1, mask=base_universe & (mkt_cap < 5000000000) #masking ) mean_close_30 = SimpleMovingAverage( inputs=[USEquityPricing.close], window_length=30, mask=base_universe & (mkt_cap < 5000000000) #masking ) rv = volume_1_day / volume_3_months high_52_w = High252() high_3_m = High66() low_52_w = Low252() # price at 30%, 50%, 60% and 90% respectively of the yearly price range third_range = (high_52_w - low_52_w) * (1 / 3) + low_52_w half_range = (high_52_w - low_52_w) * 0.5 + low_52_w sixty_range = (high_52_w - low_52_w) * 0.6 + low_52_w ninty_range = (high_52_w - low_52_w) * 0.9 + low_52_w fifteen_range = (high_52_w - low_52_w) * 0.15 + low_52_w #create the price range for potential longs long_range = (latest_close <= sixty_range) & (latest_close >= third_range) #take profit range tp_range = latest_close >= ninty_range #stop loss range sl_range = latest_close <= fifteen_range valid_open_position_range = (latest_close <= ninty_range) & (latest_close >= fifteen_range) #filters (the data type is a zipline pipeline filter not a df) # returns True or False per row (per symbol): close_price_filter = (latest_close < 15) price_under_30mva = latest_close < mean_close_30 #price under 30 mva #create a list of stocks for potential longs universe = close_price_filter & base_universe & (mkt_cap < 5000000000) # create the "go long" critera longs = price_under_30mva & long_range return Pipeline(columns={ 'latest_close': latest_close, 'rv': rv, 'stop_loss': sl_range, 'take_profit': tp_range, 'valid_open_position': valid_open_position_range, 'longs': longs }, screen=universe)