Back to Community
Top and bottom filter error!!

Hello,
I have tried to select top 10 long companies and top 5 short companies. However, when I write :

n_longs = (base_universe & ROA_long & ROE_long & PE_long & EPS_Growth_long & Current_R_long & debt_to_marketcap_long) | (base_universe & sector & dividentyield_long)
longs = n_longs.top(10)

I recieve the following error: AttributeError: 'NumExprFilter' object has no attribute 'top'
Please help.

Clone Algorithm
12
Loading...
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
from quantopian.pipeline import Pipeline
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.filters import QTradableStocksUS
import quantopian.optimize as opt
from quantopian.pipeline.data import morningstar
#from quantopian.pipeline.data.psychsignal import #aggregated_twitter_withretweets_stocktwits_free as psychsignal
#import pandas as pd
#import numpy as np

def initialize(context):
    # Schedule our rebalance function to run at the start of 
    # each week, when the market opens. 
    schedule_function(
        my_rebalance,
        date_rules.week_start(),
        time_rules.market_open()
    )

    # 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.
    my_pipe = make_pipeline()
    attach_pipeline(my_pipe, 'my_pipeline')


def make_pipeline():
    sector_universe = morningstar.asset_classification.morningstar_sector_code.latest
    sector = sector_universe.element_of([311, 103, 309, 206, 310, 102, 205 ])
    base_universe = QTradableStocksUS()
    ROA_long= morningstar.operation_ratios.roa.latest > 0.15
    ROA_short = morningstar.operation_ratios.roa.latest < 0.08
    ROE_long = morningstar.operation_ratios.roe.latest > 0.2
    ROE_short = morningstar.operation_ratios.roe.latest > 0.12   
    PE_long = morningstar.valuation_ratios.pe_ratio.latest < 30
    PE_short = morningstar.valuation_ratios.pe_ratio.latest > 60
    EPS_Growth_long = morningstar.earnings_ratios.diluted_eps_growth.latest > 0.3
    EPS_Growth_short = morningstar.earnings_ratios.diluted_eps_growth.latest < 0.1
    debt_to_marketcap_long = morningstar.balance_sheet.current_debt.latest / morningstar.valuation.market_cap.latest < 0.5
    debt_to_marketcap_short = morningstar.balance_sheet.current_debt.latest / morningstar.valuation.market_cap.latest > 1.5
    Current_R_long = morningstar.operation_ratios.current_ratio.latest > 1.2
    Current_R_short = morningstar.operation_ratios.current_ratio.latest < 1    
    #bullish_intensity = psychsignal.bullish_intensity.latest > 1.5
    dividentyield_long = morningstar.valuation_ratios.dividend_yield.latest > 0.004
    dividentyield_short = morningstar.valuation_ratios.dividend_yield.latest < 0.002
    
    n_longs = (base_universe & ROA_long & ROE_long & PE_long & EPS_Growth_long & Current_R_long & debt_to_marketcap_long) | (base_universe & sector & dividentyield_long) #& bullish_intensity
    
    n_shorts = (base_universe & sector & ROA_short & ROE_short & PE_short & EPS_Growth_short & debt_to_marketcap_short & Current_R_short ) | ( dividentyield_short & sector & base_universe)
    longs = n_longs.top(10)
    shorts = n_shorts.bottom(5)
    picks = longs | shorts
    
    pipe_columns={
          'longs': longs,
          'shorts': shorts

        }
        
    pipe_screen = (picks)
    pipe = Pipeline(columns=pipe_columns,screen=pipe_screen)
    return pipe


def compute_target_weights(context, data):
    longs_qty = len(context.longs)
    longs_weight = 0.7/ longs_qty if longs_qty>0 else 0.0
    shorts_qty = len(context.shorts)
    shorts_weight = -0.3/ shorts_qty if shorts_qty>0 else 0.0
    
    return longs_weight, shorts_weight

def before_trading_start(context, data):

    context.output = pipeline_output('my_pipeline')
    context.longs = context.output[context.output['longs']]
    context.shorts = context.output[context.output['shorts']]
    context.my_stocks = context.longs.index.union(context.shorts.index).tolist()
    context.stock_set = set(context.my_stocks)
    pass

def my_rebalance(context, data):

    longs_weight, shorts_weight = compute_target_weights(context, data)
    for stock in context.my_stocks:
        stock_price = data.current(stock, "price")
        if data.can_trade(stock):
            if stock in context.longs.index:
                order_target_percent(stock, longs_weight, style=StopOrder(stock_price - (stock_price * 0.10)))
            elif stock in context.shorts.index:
                order_target_percent(stock, shorts_weight, style=StopOrder(stock_price + (stock_price * 0.10)))
  
    for stock in context.portfolio.positions:
        if stock not in context.stock_set and data.can_trade(stock):
            order_target_percent(stock, 0)
    
 

def my_record_vars(context, data):
    """
    Record variables at the end of each day.
    """
    record(
        leverage = context.account.leverage,
        longs = len(context.longs),
        shorts = len(context.shorts),
        held = len(context.portfolio.positions)
    )

    log.info(context.my_stocks)
    
#help for sector clasification : https://www.quantopian.com/posts/how-to-filter-out-the-stocks-from-a-sector-in-building-customer-factor
There was a runtime error.
3 responses

The error is an indication of what the problem is. 'NumExprFilter' object has no attribute 'top' means that a filter object doesn't have a 'top' method. The problem is in the two lines

longs = n_longs.top(10)  
shorts = n_shorts.bottom(5)

Both 'n_longs' and 'n_shorts' are filters. Basically they are collections of securities which pass all the constraints. They don't have any intrinsic order so the concept of 'top' or 'bottom' doesn't mean anything. One can only apply 'top' and 'bottom' to factors. Factors have values and therefore can be ordered by that value and return the highest (ie top) and lowest (ie bottom) securities. The result is a filter or collection of securities and NOT a factor.

So, the first step is to determine what factor one wishes to rank the results by. Does one want the highest and lowest ROE? ROA? PE_RATIO? Simply use that factor with a mask. Something like this (I randomly chose the latest close price)

    ranking_factor = USEquityPricing.close.latest  
    longs = ranking_factor.top(10, mask=n_longs)  
    shorts = ranking_factor.bottom(5, mask=n_shorts)

Note that the ranking_factor could also be a calculated value based upon several other factors.

    ranking_factor = factor1 + factor2 + (2*factor3)

Good luck.

Thank you for advice Dan,
But in my algo I'm trying to select, lets say top 10 companies that have a ROA > 0.15, not the top 10 companies with the biggest roa. How can I create a factor that does this?

Hi Daniel,
What do you mean by top 10 in this case?
Let's assume you've selected the companies with ROA > 0.15 and there are 25 such companies.
["Stock 1", "Stock 2", "Stock 3", ..., "Stock 25"] Which 10 should the algorithm pick?