def make_pipeline(): # Sector sector = Sector() # Equity Filters mkt_cap_filter = morningstar.valuation.market_cap.latest >= 500000000 price_filter = USEquityPricing.close.latest >= 5 nan_filter = sentiment_free.sentiment_signal.latest.notnull() # Universe universe = Q1500US() & price_filter & mkt_cap_filter & nan_filter # Rank sentiment_signal = sentiment_free.sentiment_signal.latest sma_30 = SimpleMovingAverage(inputs=[sentiment_free.sentiment_signal], window_length=30, mask=universe) combined_rank = (sentiment_signal + sma_30.rank(mask=universe).zscore()) # Long and Short Positions longs = combined_rank.top(NUM_LONG_POSITIONS) shorts = combined_rank.bottom(NUM_SHORT_POSITIONS) long_short_screen = (longs | shorts) # Bloomberg Beta Implementation beta = 0.66 * RollingLinearRegressionOfReturns( target=sid(8554), returns_length=5, regression_length=260, mask=long_short_screen).beta + 0.33 * 1.0 pipe = Pipeline() pipe.add(longs, 'longs') pipe.add(shorts, 'shorts') pipe.add(combined_rank, 'combined_rank') pipe.add(sentiment_free.sentiment_signal.latest, 'sentiment_signal') pipe.add(sma_30, 'sma_30') pipe.add(sector, 'sector') pipe.add(beta, 'market_beta') pipe.set_screen(universe) return pipe
def make_pipeline(): # 5-day sentiment moving average factor. sentiment_factor = SimpleMovingAverage(inputs=[sentiment.sentiment_signal], window_length=5) # Filter for stocks that are not within 2 days of an earnings announcement. not_near_earnings_announcement = ~( (BusinessDaysUntilNextEarnings() <= 2) | (BusinessDaysSincePreviousEarnings() <= 2)) # Filter for stocks that are announced acquisition target. not_announced_acq_target = ~IsAnnouncedAcqTarget() # Filter for stocks that had their sentiment signal updated in the last day. new_info = (BusinessDaysSincePreviousEvent( inputs=[sentiment.asof_date.latest]) <= 1) # Our universe is made up of stocks that have a non-null sentiment signal that was updated in # the last day, are not within 2 days of an earnings announcement, are not announced acquisition # targets, and are in the Q1500US. universe = (Q1500US() & sentiment_factor.notnull() & not_near_earnings_announcement & not_announced_acq_target & new_info) # A classifier to separate the stocks into quantiles based on sentiment rank. sentiment_quantiles = sentiment_factor.rank(mask=universe, method='average').quantiles(3) # Go short the stocks in the 0th quantile, and long the stocks in the 2nd quantile. pipe = Pipeline(columns={ 'sentiment': sentiment_quantiles, 'shorts': sentiment_quantiles.eq(0), 'longs': sentiment_quantiles.eq(2), }, screen=universe) return pipe