Beispiel #1
0
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():
    """
    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.
    """

    # The factors we create here are based on broker recommendations data and a moving
    # average of sentiment data
    diff = (broker_ratings.rating_cnt_strong_buys.latest +
            broker_ratings.rating_cnt_mod_buys.latest -
            (broker_ratings.rating_cnt_strong_sells.latest +
             broker_ratings.rating_cnt_mod_sells.latest))
    # Here we temper the diff between recommended buys and sells with a ratio of what
    # percentage of brokers actually rated a given security
    rat = broker_ratings.rating_cnt_with.latest/ \
        (broker_ratings.rating_cnt_with.latest+broker_ratings.rating_cnt_without.latest)
    alpha_signal = diff * rat

    sentiment_score = SimpleMovingAverage(
        inputs=[stocktwits.bull_minus_bear],
        window_length=3,
    )

    universe = QTradableStocksUS()

    # 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_factor = (alpha_signal.zscore() + sentiment_score.zscore())

    # Build Filters representing the top and bottom NUM_POSITIONS stocks by our combined ranking system.
    # We'll use these as our tradeable universe each day.
    longs = combined_factor.top(NUM_LONG_POSITIONS, mask=universe)
    shorts = combined_factor.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_factor': combined_factor
    },
                    screen=long_short_screen)
    return pipe
def make_pipeline():
    """
    A function that creates and returns 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.

    Returns
    -------
    pipe : Pipeline
        Represents computation we would like to perform on the assets that make
        it through the pipeline screen.
    """
    # The factors we create here are based on fundamentals data and a moving
    # average of sentiment data
    value = Fundamentals.ebit.latest / Fundamentals.enterprise_value.latest
    quality = Fundamentals.roe.latest
    sentiment_score = SimpleMovingAverage(
        inputs=[stocktwits.bull_minus_bear],
        window_length=3,
    )

    universe = QTradableStocksUS()
    sGrowRate = Fundamentals.sustainable_growth_rate.latest
    dividendYield = Fundamentals.forward_dividend_yield.latest

    # We winsorize our factor values in order to lessen the impact of outliers
    # For more information on winsorization, please see
    # https://en.wikipedia.org/wiki/Winsorizing
    value_winsorized = value.winsorize(min_percentile=0.05,
                                       max_percentile=0.95)
    quality_winsorized = quality.winsorize(min_percentile=0.05,
                                           max_percentile=0.95)
    sentiment_score_winsorized = sentiment_score.winsorize(min_percentile=0.05,
                                                           max_percentile=0.95)
    positive_sentiment_pct = (twitter_sentiment.bull_scored_messages.latest /
                              twitter_sentiment.total_scanned_messages.latest)
    mean_sentiment_5day = SimpleMovingAverage(
        inputs=[sentiment.sentiment_signal], window_length=5)
    total_revenue = Fundamentals.total_revenue.latest
    sGrowRate_winsorized = sGrowRate.winsorize(min_percentile=0.05,
                                               max_percentile=0.95)
    dividendYield_winsorized = dividendYield.winsorize(min_percentile=0.05,
                                                       max_percentile=0.95)

    # Here we combine our winsorized factors, z-scoring them to equalize their influence
    combined_factor = (value_winsorized.zscore() +
                       quality_winsorized.zscore() +
                       sentiment_score_winsorized.zscore() +
                       positive_sentiment_pct.zscore() +
                       mean_sentiment_5day.zscore() + total_revenue.zscore() +
                       sGrowRate_winsorized.zscore())

    # Build Filters representing the top and bottom baskets of stocks by our
    # combined ranking system. We'll use these as our tradeable universe each
    # day.
    longs = combined_factor.top(TOTAL_POSITIONS // 2, mask=universe)
    shorts = combined_factor.bottom(TOTAL_POSITIONS // 2, 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_factor': combined_factor
    },
                    screen=long_short_screen)
    return pipe