Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
error when adding custom factor to pipeline

hi , I am wondering why there is an error for adding a custom factor to pipeline, anyone would give a hand, thanks.
error shows TypeError: unorderable types: ABCMeta() < float()
bias_long = bias < -0.1
bias_short = bias > 0.1

from quantopian.algorithm import order_optimal_portfolio
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import SimpleMovingAverage
from quantopian.pipeline.filters import QTradableStocksUS
import quantopian.optimize as opt
from quantopian.pipeline.data import Fundamentals
from quantopian.pipeline import CustomFactor
import numpy as np
import talib

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()
)

# Create our pipeline and attach it to our algorithm.  
my_pipe = make_pipeline()  
attach_pipeline(my_pipe, 'my_pipeline')

class bias(CustomFactor):
inputs = [USEquityPricing.close]
mean_25 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=25)
def compute(self, today, asset_ids, out, close):
out[:] = (close[0] - mean_25) / mean_25

def make_pipeline():
"""
Create our pipeline.
"""

# Base universe set to the QTradableStocksUS.  
base_universe = QTradableStocksUS()

# 10-day close price average.  
mean_10 = SimpleMovingAverage(  
    inputs=[USEquityPricing.close],  
    window_length=10,  
    mask=base_universe  
)

# 30-day close price average.  
mean_30 = SimpleMovingAverage(  
    inputs=[USEquityPricing.close],  
    window_length=30,  
    mask=base_universe  
)  
percent_difference = (mean_10 - mean_30) / mean_30  

bias_long = bias < -0.1  
bias_short = bias > 0.1  

# Filter to select securities to short.  
shorts = percent_difference.top(75) and bias_short

# Filter to select securities to long.  
longs = percent_difference.bottom(75) and bias_long

# Filter for all securities that we want to trade.  
securities_to_trade = (shorts | longs)

return Pipeline(  
    columns={  
        'longs': longs,  
        'shorts': shorts  
    },  
    screen=(securities_to_trade),  
)

def compute_target_weights(context, data):
"""
Compute ordering weights.
"""

# Initialize empty target weights dictionary.  
# This will map securities to their target weight.  
weights = {}

# If there are securities in our longs and shorts lists,  
# compute even target weights for each security.  
if context.longs and context.shorts:  
    long_weight = 0.5 / len(context.longs)  
    short_weight = -0.5 / len(context.shorts)  
else:  
    return weights

# Exit positions in our portfolio if they are not  
# in our longs or shorts lists.  
for security in context.portfolio.positions:  
    if security not in context.longs and security not in context.shorts and data.can_trade(security):  
        weights[security] = 0

for security in context.longs:  
    weights[security] = long_weight

for security in context.shorts:  
    weights[security] = short_weight

return weights

def before_trading_start(context, data):
"""
Get pipeline results.
"""

# Gets our pipeline output every day.  
pipe_results = pipeline_output('my_pipeline')

# Go long in securities for which the 'longs' value is True,  
# and check if they can be traded.  
context.longs = []  
for sec in pipe_results[pipe_results['longs']].index.tolist():  
    if data.can_trade(sec):  
        context.longs.append(sec)

# Go short in securities for which the 'shorts' value is True,  
# and check if they can be traded.  
context.shorts = []  
for sec in pipe_results[pipe_results['shorts']].index.tolist():  
    if data.can_trade(sec):  
        context.shorts.append(sec)

def my_rebalance(context, data):
"""
Rebalance weekly.
"""

# Calculate target weights to rebalance  
target_weights = compute_target_weights(context, data)

# If we have target weights, rebalance our portfolio  
if target_weights:  
    order_optimal_portfolio(  
        objective=opt.TargetWeights(target_weights),  
        constraints=[],  
    )  
4 responses

Looks like you just missed some parenthesis. The original lines of code shown below

bias_long = bias < -0.1  
bias_short = bias > 0.1  

should be

bias_long = bias() < -0.1  
bias_short = bias() > 0.1  

Note the added parenthesis. Without the parenthesis, python thinks you are comparing a class to a float (hence the error TypeError: unorderable types: ABCMeta() < float()). By adding the parenthesis you are instructing python to instantiate the class and the comparison becomes valid.

That should fix it, however I didn't actually try it. There may still be some other issues. Give that a try. Good luck..

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Hi Dan, thanks for helping.
I've followed your code but it came out another error below:

WindowLengthNotSpecified: bias requires a window_length, but no window_length was passed.
There was a runtime error on line 27.

class bias(CustomFactor):
inputs = [USEquityPricing.close]
mean_25 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=25)
def compute(self, today, asset_ids, out, close):
out[:] = (close[0] - mean_25) / mean_25

why it said there's no window length?
P.S line 27 is >>>> my_pipe = make_pipeline()

All factors need a window_length specified. This can either be within the custom factor definition or supplied when instantiating the factor. Your bias factor doesn't specify a window_length. Your bias factor also probably doesn't work as intended because of the way you are setting mean_25. The SimpleMovingAverage should be added as an input instead. This is probably what you should do

class bias(CustomFactor):  
    inputs = [USEquityPricing.close,  
              SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=25),  
             ]

    # aren't looking at any past data so the window length can be 1  
    window_length = 1

    def compute(self, today, asset_ids, out, close, mean_25):  
        # close and mean_25 are simple 1D arrays since window_length =1  
        # therefore no need to specify a row (eg close[0])  
        out[:] = (close - mean_25) / mean_25

This should work, but I didn't actually try it. Could you attach a backtest of your algo in the future? It makes it much easier to help debug. Even if a backtest generates an error, you should still be able to attach it to a post. Simply click the "Attach" dropdown menu in the upper right corner of the reply text box. Choose "backtest" then choose the desired algo and backtest.

it works , very appreciated, Dan :)