Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Backtesting error in Lecture 46: Example: Pairs Trading Algorithm

I'm running a full backtest on the algorithm given in Lecture 46. I get a Tradable Universe error:

To be eligible for the contest, algorithms must trade within the
Quantopian Tradable Universe.

So I change my code to this

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  
    """

    # Factor of yesterday's close price.  
    yesterday_close = USEquityPricing.close.latest

    pipe = Pipeline(  
        columns={  
            'close': yesterday_close,  
        },  
        screen=QTradableStocksUS()  
    )  
    return pipe

However, I still get the same error. How do I fix this?

Below is the complete algorithm:

"""
This is a template algorithm on Quantopian for you to adapt and fill in.  
"""
import quantopian.algorithm as algo  
from quantopian.pipeline import Pipeline  
from quantopian.pipeline.data.builtin import USEquityPricing  
from quantopian.pipeline.filters import QTradableStocksUS  
import pandas as pd  
import numpy as np  
import statsmodels.api as sm  
import quantopian.optimize as opt  
from quantopian.algorithm import attach_pipeline


def initialize(context):  
    """  
    Called once at the start of the algorithm.  
    """  
    # Quantopian backtester specific variables  
    set_slippage(slippage.FixedSlippage(spread=0))  
    set_commission(commission.PerTrade(cost=1))  
    set_symbol_lookup_date('2014-01-01')

    context.stock_pairs = [(symbol('ABGB'), symbol('FSLR')),  
                           (symbol('CSUN'), symbol('ASTI'))]

    context.stocks = symbols('ABGB', 'FSLR', 'CSUN', 'ASTI')

    context.num_pairs = len(context.stock_pairs)  
    # strategy specific variables  
    context.lookback = 20  # used for regression  
    context.z_window = 20  # used for zscore calculation, must be <= lookback

    context.target_weights = pd.Series(index=context.stocks, data=0.25)

    context.spread = np.ndarray((context.num_pairs, 0))  
    context.inLong = [False] * context.num_pairs  
    context.inShort = [False] * context.num_pairs

    # Only do work 30 minutes before close  
    schedule_function(func=check_pair_status, date_rule=date_rules.every_day(),  
                      time_rule=time_rules.market_close(minutes=30))  
    # Create our pipeline and attach it to our algorithm.  
    my_pipe = make_pipeline()  
    attach_pipeline(my_pipe, 'pipeline')


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  
    """

    # Factor of yesterday's close price.  
    yesterday_close = USEquityPricing.close.latest

    pipe = Pipeline(  
        columns={  
            'close': yesterday_close,  
        },  
        screen=QTradableStocksUS()  
    )  
    return pipe


def before_trading_start(context, data):  
    """  
    Called every day before market open.  
    """  
    context.output = algo.pipeline_output('pipeline')

    # These are the securities that we are interested in trading each day.  
    context.security_list = context.output.index


def rebalance(context, data):  
    """  
    Execute orders according to our schedule_function() timing.  
    """  
    pass


def record_vars(context, data):  
    """  
    Plot variables at the end of each day.  
    """  
    pass


# Will be called on every trade event for the securities you specify.  
def handle_data(context, data):  
    """  
    Called every minute.  
    """  
    # Our work is now scheduled in check_pair_status  
    pass


def check_pair_status(context, data):  
    prices = data.history(context.stocks, 'price', 35, '1d').iloc[-context.lookback::]

    new_spreads = np.ndarray((context.num_pairs, 1))

    for i in range(context.num_pairs):

        (stock_y, stock_x) = context.stock_pairs[i]

        Y = prices[stock_y]  
        X = prices[stock_x]

        # Comment explaining try block  
        try:  
            hedge = hedge_ratio(Y, X, add_const=True)  
        except ValueError as e:  
            log.debug(e)  
            return

        context.target_weights = get_current_portfolio_weights(context, data)

        new_spreads[i, :] = Y[-1] - hedge * X[-1]

        if context.spread.shape[1] > context.z_window:  
            # Keep only the z-score lookback period  
            spreads = context.spread[i, -context.z_window:]

            zscore = (spreads[-1] - spreads.mean()) / spreads.std()

            if context.inShort[i] and zscore < 0.0:  
                context.target_weights[stock_y] = 0  
                context.target_weights[stock_x] = 0

                context.inShort[i] = False  
                context.inLong[i] = False

                record(X_pct=0, Y_pct=0)  
                allocate(context, data)  
                return

            if context.inLong[i] and zscore > 0.0:  
                context.target_weights[stock_y] = 0  
                context.target_weights[stock_x] = 0

                context.inShort[i] = False  
                context.inLong[i] = False

                record(X_pct=0, Y_pct=0)  
                allocate(context, data)  
                return

            if zscore < -1.0 and (not context.inLong[i]):  
                # Only trade if NOT already in a trade  
                y_target_shares = 1  
                X_target_shares = -hedge  
                context.inLong[i] = True  
                context.inShort[i] = False

                (y_target_pct, x_target_pct) = computeHoldingsPct(y_target_shares, X_target_shares, Y[-1], X[-1])

                context.target_weights[stock_y] = y_target_pct * (1.0 / context.num_pairs)  
                context.target_weights[stock_x] = x_target_pct * (1.0 / context.num_pairs)

                record(Y_pct=y_target_pct, X_pct=x_target_pct)  
                allocate(context, data)  
                return

            if zscore > 1.0 and (not context.inShort[i]):  
                # Only trade if NOT already in a trade  
                y_target_shares = -1  
                X_target_shares = hedge  
                context.inShort[i] = True  
                context.inLong[i] = False

                (y_target_pct, x_target_pct) = computeHoldingsPct(y_target_shares, X_target_shares, Y[-1], X[-1])

                context.target_weights[stock_y] = y_target_pct * (1.0 / context.num_pairs)  
                context.target_weights[stock_x] = x_target_pct * (1.0 / context.num_pairs)

                record(Y_pct=y_target_pct, X_pct=x_target_pct)  
                allocate(context, data)  
                return

    context.spread = np.hstack([context.spread, new_spreads])


def hedge_ratio(Y, X, add_const=True):  
    if add_const:  
        X = sm.add_constant(X)  
        model = sm.OLS(Y, X).fit()  
        return model.params[1]  
    model = sm.OLS(Y, X).fit()  
    return model.params.values


def computeHoldingsPct(yShares, xShares, yPrice, xPrice):  
    yDol = yShares * yPrice  
    xDol = xShares * xPrice  
    notionalDol = abs(yDol) + abs(xDol)  
    y_target_pct = yDol / notionalDol  
    x_target_pct = xDol / notionalDol  
    return (y_target_pct, x_target_pct)


def get_current_portfolio_weights(context, data):  
    positions = context.portfolio.positions  
    positions_index = pd.Index(positions)  
    share_counts = pd.Series(  
        index=positions_index,  
        data=[positions[asset].amount for asset in positions]  
    )

    current_prices = data.current(positions_index, 'price')  
    current_weights = share_counts * current_prices / context.portfolio.portfolio_value  
    return current_weights.reindex(positions_index.union(context.stocks), fill_value=0.0)


def allocate(context, data):  
    # Set objective to match target weights as closely as possible, given constraints  
    objective = opt.TargetWeights(context.target_weights)

    # Define constraints  
    constraints = []  
    constraints.append(opt.MaxGrossExposure(1.0))

    algo.order_optimal_portfolio(  
        objective=objective,  
        constraints=constraints,  
    )