Back to Community
Weekly Rotation S&P 500

Simple momentum algorithm. Got the rules from a book by Laurens Bensdorp.

Objective:
- Trade long only, a big index, mainly blue-chip stocks that rise in value.
- Execute trades once a week. Catch big trending stocks, expecting they will continue to rise.
- Outperform the S&P 500 with lower drawdowns in bear markets.

Trading universe:
- S&P 500. As Quantopian does not provide it directly, found something similar in the forums.

Filters:
- Minimum Average Volume of the last 20 days is above 1.000.000 shares (ensure liquidity).
- Minimum price is 1 USD.

Position Sizing:
- Maximum 10 positions, dividing the equity by 10 to get the position size.

Buys:
1. Trade the first day of the week.
2. Last close of the SPY is above the 200 daily SMA band (with a -2% buffer). In case it goes below, we go back to cash.
3. Filter by the 3 day RSI of the stock. If it's below 50 it's a candidate (ensure not overbought).
4. Select the 10 stocks with the highest ROC-percentage increase over the last two hundred (momentum).

Sells:
1. Trade the first day of the week.
2. We rotate when one of the stocks of our portfolio is not in the top 10 ROC.
3. We exit all positions when the SPY is below the 200 daily SMA band (with a -2% buffer).

Notes:
- The algorithm tracks the available cash trying to avoid spending more than we have.
- The rebalance is split in 2 functions with an hour gap. This is just to "ensure" sell orders are filled before we start buying.
- The results are not as good as the backtests shown in the book, I might be missing something. However it does beat the S&P 500.

Other algorithms:
- Mean-Reversion Long - For Bold Contrarians
- Mean-Reversion Short - Money in bad markets

Clone Algorithm
97
Loading...
Backtest from to with initial capital
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
import quantopian.algorithm as algo
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.filters import QTradableStocksUS, Q1500US
from quantopian.pipeline.factors import SimpleMovingAverage, RSI, CustomFactor, Returns, Latest
from quantopian.algorithm import attach_pipeline, pipeline_output

class roc_200days(CustomFactor):
    inputs = [USEquityPricing.close] 
    window_length = 200+1

    def compute(self, today, assets, out, close):
        out[:] = ((close[-1] - close[0]) / close[0]) * 100


def initialize(context):
    set_commission(commission.PerTrade(cost=0.00))
    set_slippage(slippage.FixedSlippage(spread=0.00))
    set_long_only()
    
    schedule_function(rebalance_sell, date_rules.week_start(), time_rules.market_open(hours=1), half_days=False)
    schedule_function(rebalance_buy, date_rules.week_start(), time_rules.market_open(hours=2), half_days=False)
    schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close(), half_days=False)

    algo.attach_pipeline(make_pipeline(), 'my_pipeline')

    
def make_pipeline():
    TOTAL_STOCKS = 500
    returns_1_yr = Returns(window_length = 252)
    base_universe = returns_1_yr.top(TOTAL_STOCKS, mask = Q1500US())
    
    avg_volume = SimpleMovingAverage(inputs=[USEquityPricing.volume],window_length=20)
    filter_volume = avg_volume > 1000000

    last_price = Latest(inputs=[USEquityPricing.close], window_length=1) 
    filter_price = last_price > 1

    rsi = RSI(inputs=[USEquityPricing.close], window_length=3)
    filter_overbought = rsi < 50

    roc = roc_200days()
    
    stocks_to_trade = base_universe & filter_volume & filter_price & filter_overbought

    return Pipeline(
        columns = {
            'stocks': stocks_to_trade,
            'avg_volume': avg_volume,
            'roc': roc,
        },
        screen = (stocks_to_trade)
    )


def before_trading_start(context, data):
    context.is_trend = is_positive_trend(context, data)
    if context.is_trend == False:
        return
    context.my_output = pipeline_output('my_pipeline')
    context.candidates = context.my_output.sort_values('roc', ascending=False).head(10).index.tolist()
               

def rebalance_sell(context, data):  
    if not context.is_trend:
        empty_bags(context, data)
    else:   
        for security in context.portfolio.positions:
            if security not in context.candidates and data.can_trade(security):
                order_target_percent(security, 0)  

                
def rebalance_buy(context, data): 
    if get_open_orders():
        log.info("Unexpected open orders: " + str(len(context.portfolio.positions)))
        print_orders()

    if context.is_trend is False:
        return

    needed_cash = get_cash_amount(context, data)
    for security in context.candidates:
        if security not in context.portfolio.positions and data.can_trade(security): 
            if(needed_cash < context.portfolio.cash):
                order_value(security, needed_cash)

    
def my_record_vars(context, data):
    record(spy=context.spy_close, sma200=context.sma200, sma200_buffered=context.sma200_buffered)

    
def is_positive_trend(context, data):  
    can_trade = False
    spy = symbol('SPY')
    price_history = data.history(spy, fields='close', bar_count=200, frequency='1d')      
    context.spy_close = data.current(spy,'close')
    context.sma200 = price_history.mean()
    context.sma200_buffered = context.sma200 - context.sma200 * 0.02
    if context.spy_close > context.sma200_buffered:
        can_trade = True 
    return can_trade
    
    
def get_cash_amount(context, data):
    weight = 0
    num_stocks = 0
    for security in context.candidates:
        if security not in context.portfolio.positions and data.can_trade(security):
            if data.can_trade(security):
                num_stocks = num_stocks + 1  

    if num_stocks > 0:
        weight = 1.0 / num_stocks   
    spend = context.portfolio.cash * weight  
    return spend


def empty_bags(context, data):
    for security in context.portfolio.positions:
        if data.can_trade(security):
            order_target_percent(security, 0)

            
def print_orders():
    open_orders = get_open_orders()
    if len(open_orders) == 0:
        return
    for security, orders in open_orders.iteritems():
        for order in orders:
            log.info("Active order for " + str(order.amount) + " shares of " + str(security))
There was a runtime error.
5 responses

Hi Mark,

Thanks for sharing. It is a good simple algorithm.
I have noted that one mistake that spy close is one day delayed.
The is_positive_trend function is delayed.
Better put the global variable spy close in the initialize.
It will have better performance.

Hi Vidal,

Thanks for you feedback. I've scheduled the computation of the trend a minute before start trading and got around 10% performance improvement.

Clone Algorithm
97
Loading...
Backtest from to with initial capital
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
import quantopian.algorithm as algo
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.filters import QTradableStocksUS, Q1500US
from quantopian.pipeline.factors import SimpleMovingAverage, RSI, CustomFactor, Returns, Latest
from quantopian.algorithm import attach_pipeline, pipeline_output

class roc_200days(CustomFactor):
    inputs = [USEquityPricing.close] 
    window_length = 200+1

    def compute(self, today, assets, out, close):
        out[:] = ((close[-1] - close[0]) / close[0]) * 100


def initialize(context):
    set_commission(commission.PerTrade(cost=0.00))
    set_slippage(slippage.FixedSlippage(spread=0.00))
    set_long_only()
 
    schedule_function(is_positive_trend, date_rules.week_start(), time_rules.market_open(hours=0, minutes=59), half_days=False)
    schedule_function(rebalance_sell, date_rules.week_start(), time_rules.market_open(hours=1), half_days=False)
    schedule_function(rebalance_buy, date_rules.week_start(), time_rules.market_open(hours=2), half_days=False)
    schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close(), half_days=False)

    algo.attach_pipeline(make_pipeline(), 'my_pipeline')

    
def make_pipeline():
    TOTAL_STOCKS = 500
    returns_1_yr = Returns(window_length = 252)
    base_universe = returns_1_yr.top(TOTAL_STOCKS, mask = Q1500US())
    
    avg_volume = SimpleMovingAverage(inputs=[USEquityPricing.volume],window_length=20)
    filter_volume = avg_volume > 1000000

    last_price = Latest(inputs=[USEquityPricing.close], window_length=1) 
    filter_price = last_price > 1

    rsi = RSI(inputs=[USEquityPricing.close], window_length=3)
    filter_overbought = rsi < 50

    roc = roc_200days()
    
    stocks_to_trade = base_universe & filter_volume & filter_price & filter_overbought

    return Pipeline(
        columns = {
            'stocks': stocks_to_trade,
            'avg_volume': avg_volume,
            'roc': roc,
        },
        screen = (stocks_to_trade)
    )


def before_trading_start(context, data):
    context.my_output = pipeline_output('my_pipeline')
    context.candidates = context.my_output.sort_values('roc', ascending=False).head(10).index.tolist()
    
    
def is_positive_trend(context, data):  
    can_trade = False
    spy = symbol('SPY')
    price_history = data.history(spy, fields='close', bar_count=200, frequency='1d')      
    context.spy_close = data.current(spy,'close')
    context.sma200 = price_history.mean()
    context.sma200_buffered = context.sma200 * 0.98
    if context.spy_close > context.sma200_buffered:
        can_trade = True 
    context.is_trend = can_trade

    
def rebalance_sell(context, data):  
    if not context.is_trend:
        empty_bags(context, data)
    else:   
        for security in context.portfolio.positions:
            if security not in context.candidates and data.can_trade(security):
                order_target_percent(security, 0)  

                
def rebalance_buy(context, data): 
    if get_open_orders():
        log.info("Unexpected open orders: " + str(len(context.portfolio.positions)))
        print_orders()

    if context.is_trend is False:
        return

    needed_cash = get_cash_amount(context, data)
    for security in context.candidates:
        if security not in context.portfolio.positions and data.can_trade(security): 
            if(needed_cash < context.portfolio.cash):
                order_value(security, needed_cash)

    
def my_record_vars(context, data):
    record(spy=context.spy_close, sma200=context.sma200, sma200_buffered=context.sma200_buffered)

        
def get_cash_amount(context, data):
    weight = 0
    num_stocks = 0
    for security in context.candidates:
        if security not in context.portfolio.positions and data.can_trade(security):
            if data.can_trade(security):
                num_stocks = num_stocks + 1  

    if num_stocks > 0:
        weight = 1.0 / num_stocks   
    spend = context.portfolio.cash * weight  
    return spend


def empty_bags(context, data):
    for security in context.portfolio.positions:
        if data.can_trade(security):
            order_target_percent(security, 0)

            
def print_orders():
    open_orders = get_open_orders()
    if len(open_orders) == 0:
        return
    for security, orders in open_orders.iteritems():
        for order in orders:
            log.info("Active order for " + str(order.amount) + " shares of " + str(security))
There was a runtime error.

Performs better in recent history than I would have expected from a strategy like this. Nearly manages to keep pace with benchmark.

Clone Algorithm
4
Loading...
Backtest from to with initial capital
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
import quantopian.algorithm as algo
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.filters import QTradableStocksUS, Q1500US
from quantopian.pipeline.factors import SimpleMovingAverage, RSI, CustomFactor, Returns, Latest
from quantopian.algorithm import attach_pipeline, pipeline_output

class roc_200days(CustomFactor):
    inputs = [USEquityPricing.close] 
    window_length = 200+1

    def compute(self, today, assets, out, close):
        out[:] = ((close[-1] - close[0]) / close[0]) * 100


def initialize(context):
    set_commission(commission.PerTrade(cost=0.00))
    set_slippage(slippage.FixedSlippage(spread=0.00))
    set_long_only()
 
    schedule_function(is_positive_trend, date_rules.week_start(), time_rules.market_open(hours=0, minutes=59), half_days=False)
    schedule_function(rebalance_sell, date_rules.week_start(), time_rules.market_open(hours=1), half_days=False)
    schedule_function(rebalance_buy, date_rules.week_start(), time_rules.market_open(hours=2), half_days=False)
    schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close(), half_days=False)

    algo.attach_pipeline(make_pipeline(), 'my_pipeline')

    
def make_pipeline():
    TOTAL_STOCKS = 500
    returns_1_yr = Returns(window_length = 252)
    base_universe = returns_1_yr.top(TOTAL_STOCKS, mask = Q1500US())
    
    avg_volume = SimpleMovingAverage(inputs=[USEquityPricing.volume],window_length=20)
    filter_volume = avg_volume > 1000000

    last_price = Latest(inputs=[USEquityPricing.close], window_length=1) 
    filter_price = last_price > 1

    rsi = RSI(inputs=[USEquityPricing.close], window_length=3)
    filter_overbought = rsi < 50

    roc = roc_200days()
    
    stocks_to_trade = base_universe & filter_volume & filter_price & filter_overbought

    return Pipeline(
        columns = {
            'stocks': stocks_to_trade,
            'avg_volume': avg_volume,
            'roc': roc,
        },
        screen = (stocks_to_trade)
    )


def before_trading_start(context, data):
    context.my_output = pipeline_output('my_pipeline')
    context.candidates = context.my_output.sort_values('roc', ascending=False).head(10).index.tolist()
    
    
def is_positive_trend(context, data):  
    can_trade = False
    spy = symbol('SPY')
    price_history = data.history(spy, fields='close', bar_count=200, frequency='1d')      
    context.spy_close = data.current(spy,'close')
    context.sma200 = price_history.mean()
    context.sma200_buffered = context.sma200 * 0.98
    if context.spy_close > context.sma200_buffered:
        can_trade = True 
    context.is_trend = can_trade

    
def rebalance_sell(context, data):  
    if not context.is_trend:
        empty_bags(context, data)
    else:   
        for security in context.portfolio.positions:
            if security not in context.candidates and data.can_trade(security):
                order_target_percent(security, 0)  

                
def rebalance_buy(context, data): 
    if get_open_orders():
        log.info("Unexpected open orders: " + str(len(context.portfolio.positions)))
        print_orders()

    if context.is_trend is False:
        return

    needed_cash = get_cash_amount(context, data)
    for security in context.candidates:
        if security not in context.portfolio.positions and data.can_trade(security): 
            if(needed_cash < context.portfolio.cash):
                order_value(security, needed_cash)

    
def my_record_vars(context, data):
    record(spy=context.spy_close, sma200=context.sma200, sma200_buffered=context.sma200_buffered)
    record(l=context.account.leverage)
        
def get_cash_amount(context, data):
    weight = 0
    num_stocks = 0
    for security in context.candidates:
        if security not in context.portfolio.positions and data.can_trade(security):
            if data.can_trade(security):
                num_stocks = num_stocks + 1  

    if num_stocks > 0:
        weight = 1.0 / num_stocks   
    spend = context.portfolio.cash * weight  
    return spend


def empty_bags(context, data):
    for security in context.portfolio.positions:
        if data.can_trade(security):
            order_target_percent(security, 0)

            
def print_orders():
    open_orders = get_open_orders()
    if len(open_orders) == 0:
        return
    for security, orders in open_orders.iteritems():
        for order in orders:
            log.info("Active order for " + str(order.amount) + " shares of " + str(security))
There was a runtime error.

Mark, I saw you posted another new algo to the public. Really amazed that you could get some solid trade ideas from that book that could have quite good performance, I think I should check that book too.
My small change to your algo: sell all positions when spy close below ma100 in daily basis

Clone Algorithm
60
Loading...
Backtest from to with initial capital
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
import quantopian.algorithm as algo
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.filters import QTradableStocksUS, Q1500US
from quantopian.pipeline.factors import SimpleMovingAverage, RSI, CustomFactor, Returns, Latest
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.classifiers.morningstar import Sector

MAX_LEVERAGE = 1

class roc_200days(CustomFactor):
    inputs = [USEquityPricing.close] 
    window_length = 200+1

    def compute(self, today, assets, out, close):
        out[:] = ((close[-1] - close[0]) / close[0]) * 100


def initialize(context):
    set_commission(commission.PerTrade(cost=0.00))
    set_slippage(slippage.FixedSlippage(spread=0.00))
    set_long_only()
    
    schedule_function(rebalance_sell, date_rules.week_start(), time_rules.market_open(hours=1), half_days=False)
    schedule_function(rebalance_buy, date_rules.week_start(), time_rules.market_open(hours=2), half_days=False)
    schedule_function(daily_sell, date_rules.every_day(), time_rules.market_close(minutes=10))
    schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close(), half_days=False)

    algo.attach_pipeline(make_pipeline(), 'my_pipeline')
    context.spy = sid(8554)
    
def make_pipeline():
    TOTAL_STOCKS = 500
    returns_1_yr = Returns(window_length = 252)
    base_universe = returns_1_yr.top(TOTAL_STOCKS, mask = Q1500US())
    
    avg_volume = SimpleMovingAverage(inputs=[USEquityPricing.volume],window_length=20)
    filter_volume = avg_volume > 1000000

    last_price = Latest(inputs=[USEquityPricing.close], window_length=1) 
    filter_price = last_price > 1

    rsi = RSI(inputs=[USEquityPricing.close], window_length=3)
    filter_overbought = rsi < 60

    roc = roc_200days()
    
    #sector = Sector()
    #sector_filter = (sector.eq(206) and sector.eq(311))
    
    stocks_to_trade = base_universe & filter_volume & filter_price & filter_overbought 
    pipe = Pipeline(
        columns = {
            'stocks': stocks_to_trade,
            'avg_volume': avg_volume,
            'roc': roc,
        },
        screen = (stocks_to_trade)
    )

    return pipe


def before_trading_start(context, data):
    context.my_output = pipeline_output('my_pipeline')
    print len(context.my_output)
    context.candidates = context.my_output.sort_values('roc', ascending=False).head(10).index.tolist()
               

def rebalance_sell(context, data):  
        for security in context.portfolio.positions:
            if security not in context.candidates and data.can_trade(security):
                order_target_percent(security, 0)  

def daily_sell(context,data):
    spyclose = data.current(context.spy,'price')
    ma100 = data.history(context.spy,'price', 100,'1d').mean()
    if spyclose < ma100:
        empty_bags(context, data)
        
    else:
        pass
                
def rebalance_buy(context, data): 
    if get_open_orders():
        log.info("Unexpected open orders: " + str(len(context.portfolio.positions)))
        print_orders()

    spyclose = data.current(context.spy,'price')
    ma100 = data.history(context.spy,'price', 100,'1d').mean()
    if spyclose < ma100:
        return

    needed_cash = get_cash_amount(context, data)
    for security in context.candidates:
        if security not in context.portfolio.positions and data.can_trade(security): 
            if(needed_cash < context.portfolio.cash):
                order_value(security, needed_cash)

    
def my_record_vars(context, data):    
    #spyclose = data.current(context.spy,'price')
    #ma100 = data.history(context.spy,'price', 100,'1d').mean()
    #record(spy=spyclose, sma100=ma100)
    record(Leverage = context.account.leverage)
    record(Stock = len(context.portfolio.positions))
    
def get_cash_amount(context, data):
    weight = 0
    num_stocks = 0
    for security in context.candidates:
        if security not in context.portfolio.positions and data.can_trade(security):
            if data.can_trade(security):
                num_stocks = num_stocks + 1  

    if num_stocks > 0:
        weight = 1.0 / num_stocks   
    spend = context.portfolio.cash * weight  
    return spend


def empty_bags(context, data):
    for security in context.portfolio.positions:
        if data.can_trade(security):
            order_target_percent(security, 0)

      
def print_orders():
    open_orders = get_open_orders()
    if len(open_orders) == 0:
        return
    for security, orders in open_orders.iteritems():
        for order in orders:
            log.info("Active order for " + str(order.amount) + " shares of " + str(security))
There was a runtime error.

and another one:

Clone Algorithm
60
Loading...
Backtest from to with initial capital
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
import quantopian.algorithm as algo
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data import Fundamentals
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.filters import QTradableStocksUS, Q1500US
from quantopian.pipeline.factors import SimpleMovingAverage, RSI, CustomFactor, Returns, Latest, AnnualizedVolatility
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.classifiers.morningstar import Sector
import quantopian.optimize as opt
import numpy as np  
import math

MAX_LEVERAGE = 1

class roc_200days(CustomFactor):
    inputs = [USEquityPricing.close] 
    window_length = 200+1

    def compute(self, today, assets, out, close):
        out[:] = ((close[-1] - close[0]) / close[0]) * 100


def initialize(context):
    set_commission(commission.PerTrade(cost=0.00))
    set_slippage(slippage.FixedSlippage(spread=0.00))
    set_long_only()
    
    schedule_function(rebalance_sell, date_rules.week_start(), time_rules.market_open(hours=1), half_days=False)
    schedule_function(rebalance_buy, date_rules.week_start(), time_rules.market_open(hours=2), half_days=False)
    schedule_function(daily_sell, date_rules.every_day(), time_rules.market_close(minutes=10))
    schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close(), half_days=False)

    algo.attach_pipeline(make_pipeline(), 'my_pipeline')
    context.spy = sid(8554)
    
def make_pipeline():

    avg_volume = SimpleMovingAverage(inputs=[USEquityPricing.volume],window_length=20)
    filter_volume = avg_volume > 1000000
    
    last_price = Latest(inputs=[USEquityPricing.close], window_length=1) 
    filter_price = last_price > 1
    
    rsi = RSI(inputs=[USEquityPricing.close], window_length=3)
    filter_overbought = rsi < 60

    average = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length = 200)
    sma_filter = (last_price > average)
    
    #TOTAL_STOCKS = 500
    #returns_1_yr = Returns(window_length = 252)
    #base_universe = returns_1_yr.top(TOTAL_STOCKS, mask = Q1500US())
    
    booktomarket = Fundamentals.book_value_yield.latest
    profitability = Fundamentals.ebit.latest / Fundamentals.enterprise_value.latest

    booktomarket_adj = booktomarket.winsorize(min_percentile=0.02, max_percentile=0.98)
    profitability_adj = profitability.winsorize(min_percentile=0.02, max_percentile=0.98)
    
    ranking = (   
        booktomarket_adj.zscore() + profitability_adj.zscore()
    )
    
    universe = Q1500US()
    
    trading_base = ranking.top(500, mask = universe)
    
    momentum = Returns(
        inputs=[USEquityPricing.close],
        window_length= 201,
        mask = trading_base
      )
    
    # Calculate volatility of returns
    momentum_vol = AnnualizedVolatility(
        inputs=[USEquityPricing.close],
        window_length= 201,
        mask = trading_base
      )
    
    beta = 3
    momentum_rank = ( 
        (beta**2 + 1)*(momentum.zscore() * ( 1 - momentum_vol.zscore())) 
        / (momentum.zscore() + ( 1 - momentum_vol.zscore()) * beta)
        )
    
    
    #roc = roc_200days()
    
    stocks_to_trade = filter_volume & filter_price & filter_overbought & sma_filter
    pipe = Pipeline(
        columns = {
            'stocks': stocks_to_trade,
            'avg_volume': avg_volume,
            'roc': momentum_rank,
        },
        screen = (stocks_to_trade)
    )

    return pipe


def before_trading_start(context, data):
    context.my_output = pipeline_output('my_pipeline')
    print len(context.my_output)
    context.candidates = context.my_output.sort_values('roc', ascending=False).head(10).index.tolist()
               

def rebalance_sell(context, data):  
        for security in context.portfolio.positions:
            if security not in context.candidates and data.can_trade(security):
                order_target_percent(security, 0)  

def daily_sell(context,data):
    spyclose = data.current(context.spy,'price')
    ma100 = data.history(context.spy,'price', 100,'1d').mean()
    if spyclose < ma100:
        empty_bags(context, data)
        
    else:
        pass
                
def rebalance_buy(context, data): 
    if get_open_orders():
        log.info("Unexpected open orders: " + str(len(context.portfolio.positions)))
        print_orders()

    spyclose = data.current(context.spy,'price')
    ma100 = data.history(context.spy,'price', 100,'1d').mean()
    if spyclose < ma100:
        return

    needed_cash = get_cash_amount(context, data)
    for security in context.candidates:
        if security not in context.portfolio.positions and data.can_trade(security): 
            if(needed_cash < context.portfolio.cash):
                order_value(security, needed_cash)

    
def my_record_vars(context, data):    
    #spyclose = data.current(context.spy,'price')
    #ma100 = data.history(context.spy,'price', 100,'1d').mean()
    #record(spy=spyclose, sma100=ma100)
    record(Leverage = context.account.leverage)
    record(Stock = len(context.portfolio.positions))
    
def get_cash_amount(context, data):
    weight = 0
    num_stocks = 0
    for security in context.candidates:
        if security not in context.portfolio.positions and data.can_trade(security):
            if data.can_trade(security):
                num_stocks = num_stocks + 1  

    if num_stocks > 0:
        weight = 1.0 / num_stocks   
    spend = context.portfolio.cash * weight  
    return spend


def empty_bags(context, data):
    for security in context.portfolio.positions:
        if data.can_trade(security):
            order_target_percent(security, 0)

      
def print_orders():
    open_orders = get_open_orders()
    if len(open_orders) == 0:
        return
    for security, orders in open_orders.iteritems():
        for order in orders:
            log.info("Active order for " + str(order.amount) + " shares of " + str(security))
There was a runtime error.