Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Taking forever in backtest! Need some help

I am brand new to Quantopian, my teammate and I at the ChiPy Hackathon came up with this strategy and it is running really really slow. We cloned one of the lecture series code and added our factors to it and did a small regression. Can someone look into it and tell me what could be changed to make it work faster? I am pasting the code here for you guys to view. Appreciate any help!!


from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.factors import CustomFactor, SimpleMovingAverage
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar
from sklearn import linear_model

mstar = morningstar

import numpy as np
import pandas as pd
from datetime import datetime

class Value(CustomFactor):
inputs = [morningstar.income_statement.ebit,
morningstar.valuation.enterprise_value]
window_length = 1

def compute(self, today, assets, out, ebit, ev):  
    out[:] = ebit[-1] / ev[-1]

class MACD(CustomFactor):
inputs=[USEquityPricing.close]
window_length = 35

def compute(self, today, assets, out, close):  
    ema12 = pd.stats.moments.ewma(close, span=12)  
    ema26 = pd.stats.moments.ewma(close, span=26)  
    signal = pd.stats.moments.ewma(ema12[-10:] - ema26[-10:], span=9)  
    out[:] = (ema12[-1] - ema26[-1]) - signal[-1]

class Quality(CustomFactor):

# Pre-declare inputs and window_length  
inputs = [morningstar.operation_ratios.roe,]  
window_length = 1

def compute(self, today, assets, out, roe):  
    out[:] = roe[-1]

class AvgDailyDollarVolumeTraded(CustomFactor):
inputs = [USEquityPricing.close, USEquityPricing.volume]

def compute(self, today, assets, out, close_price, volume):  
    out[:] = np.mean(close_price * volume, axis=0)

class Magic_Formula(CustomFactor):
inputs = [mstar.income_statement.ebit, mstar.valuation.enterprise_value,
mstar.operation_ratios.roic]
# outputs = ['result','earnings_yield','roic']
window_length = 1

def compute(self, today, assets, out, ebit, ev, roic):  
    a = ebit[-1] / ev[-1]  
    b = roic[-1]  
    out[:] = a + b

def trange_helper(high, low, close):
"""
Returns true range

http://www.macroption.com/true-range/

Parameters  
----------  
high : np.array  
    matrix of high prices  
low : np.array  
    matrix of low prices  
close: np.array  
    matrix of close prices

Returns  
-------  
np.array : matrix of true range

"""  
# define matrices to be compared  
close = close[:-1]  
high = high[1:]  
low = low[1:]  
# matrices for comparison  
high_less_close = high - close  
close_less_low = close - low  
high_less_low = high - low

# return maximum value for each cel  
return np.maximum(high_less_close, close_less_low, high_less_low)

class ATR(CustomFactor):
"""
Average True Range

Momentum indicator

**Default Inputs:** USEquityPricing.high, USEquityPricing.low, USEquityPricing.close

**Default Window Length:** 15 (14+1)

https://en.wikipedia.org/wiki/Average_true_range  
"""  
inputs=[USEquityPricing.high, USEquityPricing.low, USEquityPricing.close]  
window_length = 15

def compute(self, today, assets, out, high, low, close):

    tr_frame = trange_helper(high, low, close)  
    decay_rate= 2./(len(tr_frame) + 1.)  
    weights = np.full(len(tr_frame), decay_rate, float) ** np.arange(len(tr_frame) + 1, 1, -1)  
    out[:] = np.average(tr_frame, axis=0, weights=weights)

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.  
"""  
pipe = Pipeline()



 # We only want to trade relatively liquid stocks.  
# Build a filter that only passes stocks that have $10,000,000 average  
# daily dollar volume over the last 20 days.  
dollar_volume = AvgDailyDollarVolumeTraded(window_length=20)  
is_liquid = dollar_volume.top(700)

# We also don't want to trade penny stocks, which we define as any stock with an  
# average price of less than $5.00 over the last 200 days.  
sma_200 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=200)  
not_a_penny_stock = (sma_200 > 5)

# Before we do any other ranking, we want to throw away these assets.  
initial_screen = (is_liquid & not_a_penny_stock)

# Basic value and quality metrics.  
value = Value(mask=initial_screen)  
pipe.add(value, "value")  
quality = Quality(mask=initial_screen)  
pipe.add(quality, "quality")  
macd = MACD(mask=initial_screen)  
pipe.add(macd, 'macd')  
atr = ATR(mask=initial_screen)  
pipe.add(atr, 'atr')  
magic_formula = Magic_Formula(mask=initial_screen)  
pipe.add(magic_formula, 'magic_formula')  
# Construct and add a Factor representing the average rank of each asset by our  
# value and quality metrics.  
# By applying a mask to the rank computations, we remove any stocks that failed  
# to meet our initial criteria **before** computing ranks.  This means that the  
# stock with rank 10.0 is the 10th-lowest stock that passed `initial_screen`.  
# combined_rank = (  
#     value.rank(mask=initial_screen) +  
#     quality.rank(mask=initial_screen)  
# )  
# pipe.add(combined_rank, 'combined_rank')

# Build Filters representing the top and bottom 200 stocks by our combined ranking system.  
# We'll use these as our tradeable universe each day.  
# longs = combined_rank.top(200)  
# shorts = combined_rank.bottom(200)

# # The final output of our pipeline should only include  
# # the top/bottom 200 stocks by our criteria.  
# pipe.set_screen(longs | shorts)

# pipe.add(longs, 'longs')  
# pipe.add(shorts, 'shorts')

return pipe

def initialize(context):

context.long_leverage = 0.50  
context.short_leverage = -0.50  
context.spy = sid(8554)  
context.yesterday = None  
context._start_date = datetime(year=2014, month=6, day=1).date()


context._factors = ['atr', 'magic_formula', 'quality', 'value', 'macd']  
context.hist = pd.DataFrame(columns= context._factors + ['date', 'pct_change'])  
attach_pipeline(make_pipeline(), 'ranking_example')

# Used to avoid purchasing any leveraged ETFs  
context.dont_buys = security_lists.leveraged_etf_list

# Schedule my rebalance function  
schedule_function(func=rebalance,  
                  date_rule=date_rules.every_day(),  
                  time_rule=time_rules.market_open(hours=0,minutes=30),  
                  half_days=True)

# Schedule a function to plot leverage and position count  
schedule_function(func=record_vars,  
                  date_rule=date_rules.every_day(),  
                  time_rule=time_rules.market_close(),  
                  half_days=True)

def before_trading_start(context, data):
# Call pipeline_output to get the output
# Note this is a dataframe where the index is the SIDs for all
# securities to pass my screen and the columns are the factors which
output = pipeline_output('ranking_example')
yesterday = context.yesterday
today_date = get_datetime().date()

# get pct_change for assets tracked yesterday  
if yesterday is not None:  
    pct_change = data.history(yesterday.keys(), 'price', 2, '1d').pct_change()[1:]

# add data to our history  
    for stock in yesterday:  
        yesterday[stock]['date'] = today_date  
        yesterday[stock]['pct_change'] = pct_change[stock]  
        context.hist.append(yesterday[stock])

# filter history for last 50 days  
filter_date = today_date - pd.Timedelta(days=50)  
context.hist = context.hist[context.hist['date'] >= filter_date]

X = context.hist[context._factors]  
y = context.hist['pct_change']

# don't start trading until the start date  
if today_date >= context._start_date:  
    clf = linear_model.Ridge()  
    clf.fit(X,y)  
    scores = clf.predict(output[context._factors])  
    scores = scores.sort(ascending=False)  
    context.longs = scores.index[0:50]  
    context.shorts = scores.index[-20:]

context.yesterday = {stock: output.loc[stock][context._factors] for stock in output.index}  
# long_ranks = ranks[output['longs']]  
# short_ranks = ranks[output['shorts']]

context.long_weights = 1./70 #(long_ranks / long_ranks.sum())  
# log.info("Long Weights:")  
# log.info(context.long_weights)

context.short_weights = 1./70 #(short_ranks / short_ranks.sum())  
# log.info("Short Weights:")  
# log.info(context.short_weights)

context.active_portfolio = output.index

def record_vars(context, data):

# Record and plot the leverage, number of positions, and expsoure of our portfolio over time.  
record(num_positions=len(context.portfolio.positions),  
       exposure=context.account.net_leverage,  
       leverage=context.account.leverage)

This function is scheduled to run at the start of each month.

def rebalance(context, data):
"""
Allocate our long/short portfolio based on the weights supplied by
context.long_weights and context.short_weights.
"""
# Order our longs.
log.info("ordering longs")
for long_stock, long_weight in context.long_weights.iterkv():
if data.can_trade(long_stock):
if get_open_orders(long_stock):
continue
if long_stock in context.dont_buys:
continue
order_target_percent(long_stock, context.long_leverage * long_weight)

# Order our shorts.  
log.info("ordering shorts")  
for short_stock, short_weight in context.short_weights.iterkv():  
    if data.can_trade(short_stock):  
        if get_open_orders(short_stock):  
            continue  
        if short_stock in context.dont_buys:  
            continue  
        order_target_percent(short_stock, context.short_leverage * short_weight)

# Sell any positions in assets that are no longer in our target portfolio.  
for security in context.portfolio.positions:  
    if get_open_orders(security):  
        continue  
    if data.can_trade(security):  # Work around inability to sell de-listed stocks.  
        if security not in context.active_portfolio:  
            order_target_percent(security, 0)  
1 response

You should post the notebook or algorithm. Use the "Attach" button in the top right-hand corner of the reply box.