Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
TimeoutException Help

I seem to be running into a TimeoutException in my code below. I am still learning python so I suspect I am doing something inefficiently that is causing the timeout but I can't identify what it is. My before_trading_start method gets a set of 50 stocks based on some fundamentals. If I lower this number to say 5 then I don't run into the TimeoutException, but 50 equities does not see like that large of a number.

I have two methods scheduled to run daily. The first looks at the set of stocks generated from before_trading_start and filters this list down some based on volume criteria. The second method then determines moving average and %R for each stock in the set, based on these numbers it will decide where to buy or sell.

The TimeoutException is thrown from line 123, but using the debugger I found the timeout must really be occurring around line 143 where moving average is calculated. The full code is below with comments on what I believe are the problem areas.

Is there any optimization I can make to avoid this error? Or have I done something else wrong that is causing this?

# 

# 03/28/2014 - 08/18/2015  $10,000 Minute

# TimeoutException: Too much time spent in handle_data call  
# There was a runtime error on line 123.


import numpy as np  
import math  
import operator

# Set up Williams %R by ta lib  
willer = ta.WILLR(timeperiod=30)

# Put any initialization logic here.  The context object will be passed to  
# the other methods in your algorithm.  
def initialize(context):

    # Max shares to buy in a day  
    # TODO: move this down to day constants  
    context.max_shares_buy = 5

    ###  
    # Daily Constants  
    ###  
    # Define Daily Trades  
    context.daily_stocks = []

    # Set high loss tolerance since these are volatile stocks  
    context.d_stop_loss_perc = 0.50  
    # Buy stock at -1% current price  
    context.d_limit_buy_perc = 0.99  
    context.d_percent_of_portfolio = .40  
    context.d_budget = 0  
    context.d_min_profit = 2.25  
    ###  
    # Recommender Constants  
    ###  
    # Define WILLER Constants  
    context.LOW_W = -85  
    context.HIGH_W = -15  
    context.willer_recommendation_weight = 1  
    # Define MA Constants  
    context.fma_days = 50  
    context.sma_days = 200  
    context.ma_recommendation_weight = 1  
    ###  
    # Scheduling Functions  
    ### 

    # Schedule daily sorting  
    # Executes every day one minute after open  
    schedule_function(daily_stocks, date_rule=date_rules.every_day(), time_rule=time_rules.market_open(hours=0, minutes=1))  
    # Schedule daily buys  
    # Executes every day 10min after market open  
    schedule_function(daily_trades_buy, date_rule=date_rules.every_day(), time_rule=time_rules.market_open(hours=0, minutes=10))

# Executed every day before trade start, divvy out cash for the day  
def before_trading_start(context):  
    cash = context.portfolio.cash  
    context.d_budget = context.d_percent_of_portfolio * cash

    # Query for securities based on market_cap size  
    context.fundamental_df = get_fundamentals(  
        query(  
            # market cap  
            fundamentals.valuation.market_cap,  
        )

        # Filter where market_cap > 10billion == large cap  
        .filter(fundamentals.valuation.market_cap > 10000000000)  
        .order_by(fundamentals.valuation.market_cap.desc())

        .limit(50)  
        )  

    # Set stock results into context  
    context.fundamental_stocks = context.fundamental_df.columns.values  
    # Update universe  
    update_universe(context.fundamental_df.columns.values)


# Will be called on every trade event for the securities you specify.  
def handle_data(context, data):  
    pass

"""
Sorts most recent stocks from fundmaentals and gets the ones with the highest average trading volume in the past 90 days.  
"""
def daily_stocks(context, data):  
    # Filter by Volume past 90 days 1M < stock  
    avg_vol_stocks = get_avg_volume(90, 1000000)  
    # Converge  
    context.daily_stocks = []  
    for equity in context.fundamental_stocks:  
        if equity in avg_vol_stocks:  
            context.daily_stocks.append(equity)  
    for equity in context.daily_stocks:  
        print(equity.symbol)  
# DAILY  
# Daily trades are made every day soon after market open.  The trades are made over a  
# predefined set of stocks.  We will first rank these stocks by WILLER and MA Recommenders.  
def daily_trades_buy(context, data):  
    cash = context.d_budget  
    # fails here occasionally with a Timeout error  
    # Go to method below for more info, line 195  
    sorted_stocks = sort_stocks_by_ma_willer(context, data, context.daily_stocks)  
    for stockTuple in sorted_stocks:  
        # do stuff  
        recommendation = stockTuple[1]  
        stock = stockTuple[0]  
        print(stock)


###  
# Recommenders  
###

"""
Determine if the moving average recommends a buy or a sell for a given stock.

Requires: context, data, and stock  
Returns: 1 for a buy and -1 for a sell, 0 for neutral  
"""
def determine_ma_recommendation(context, data, stock):  
    if stock in data:  
        # calculate fast moving average  
        # I think it is failing in the mavg method  
        fast_moving_average = data[stock].mavg(context.fma_days)  
        # calculate slow moving average  
        slow_moving_average = data[stock].mavg(context.sma_days)  
        if (fast_moving_average > slow_moving_average):  
            return 1  
        elif (fast_moving_average < slow_moving_average):  
            return -1  
        else:  
            return 0  
    else: # stock may no longer be selling, recommend sell  
        return -1


"""
Determine if the Willer %R recommends a buy or a sell.

Requires: context, data, stock  
Returns: 1 fora  buy and -1 for a sell, 0 for neutral  
"""
def determine_willer_recommendation(context, data, stock):  
    if stock in data:  
        willer_data = willer(data)  
        stock_willer = willer_data[stock]  
         # first 14 days, the william value will be numpy.nan  
        if not np.isnan(stock_willer):  
            if stock_willer > context.HIGH_W:  
                return -1  
            elif stock_willer < context.LOW_W:  
                return 1  
            else:  
                return 0  
        else:  
            return 0  
    else: # stock is not in data, may no longer be trading, recommend a sell  
        return -1

###  
# Helpers  
###

"""
Sorts stocks by best MA and WIlLER recommendations first.

Requires: context, data, list of stocks to sort  
Returns: the sorted stocks dictionary, key = stock, value = recommendation  
"""
def sort_stocks_by_ma_willer(context, data, stocks):  
    sorted_stocks = {}  
    for stock in stocks:  
        if stock in data:  
            # MA Recommendation  
            # Seems to fail inside this method. line 139  
            ma_recommendation = determine_ma_recommendation(context, data, stock)  
            # WILLER Recommendation  
            willer_recommendation = determine_willer_recommendation(context, data, stock)  
            # Determine Recommendation  
            recommendation = (ma_recommendation * context.ma_recommendation_weight) + (willer_recommendation * context.willer_recommendation_weight)  
            sorted_stocks[stock] = recommendation  
    sorted_stocks = sorted(sorted_stocks.items(), key = operator.itemgetter(1))  
    return sorted_stocks

"""
Gets the average volume for all stocks in universe of the past x days.  Filters out any stocks that do not have an average volume above minsize.

Requires: days, minsize  
Returns: list of Equities  
"""
def get_avg_volume(days, minsize):  
    # Gets history for all stocks in universe of past 90 days  
    volume_history_df = history(bar_count=days, frequency='1d', field='volume')  
    average_volume_series = volume_history_df.mean()  
    # Descending sort  
    average_volume_series.sort(axis=0, ascending=False)  
    # Get largest  
    avg_vol_stocks = []  
    for s, v in average_volume_series.iteritems():  
        if v > minsize:  
            avg_vol_stocks.append(s)  
    return avg_vol_stocks