Back to Community
Earnings Drift with Accern Data - Collaboration Request

Hi

This was created off Seong's Earnings Drift algo and I added Accern data and changed quite a bit of things. I can only test until Aug 2015 due to a data issue with the earning release data-set that they are looking into but here are some results.

Please help improve it, this is set to only Long, not a contest algo, just personal use. Would love to see what others can do with this.

Maybe some others that know how to incorporate more advanced things like machine learning can get better returns while maximizing draw down.

The reason I set Sell and Stop Limits is because I don't really trust putting any algo in without them to an extend just in case things went sideways.

Clone Algorithm
15
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
"""
This is a PEAD strategy based off Estimize's earnings estimates. Estimize
is a service that aggregate financial estimates from independent, buy-side,
sell-side analysts as well as students and professors. You can run this
algorithm yourself by geting the free sample version of Estimize's consensus
dataset and EventVestor's Earnings Calendar Dataset at:

- https://www.quantopian.com/data/eventvestor/earnings_calendar
- https://www.quantopian.com/data/estimize/revisions

Much of the variables are meant for you to be able to play around with them:
1. context.days_to_hold: defines the number of days you want to hold before exiting a position
2. context.min/max_surprise: defines the min/max % surprise you want before trading on a signal
"""
import pandas as pd
import numpy as np

from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.classifiers.morningstar import Sector
from quantopian.pipeline.factors import AverageDollarVolume
from quantopian.pipeline.data.estimize import consensus_estimize_eps as estimize
from quantopian.pipeline.data.eventvestor import EarningsCalendar
from quantopian.pipeline.factors.eventvestor import (BusinessDaysUntilNextEarnings, BusinessDaysSincePreviousEarnings)
from quantopian.pipeline.data.accern import alphaone as alphaone

# Create custom factor subclass to calculate a market cap based on yesterday's
# close
class PercentSurprise(CustomFactor):
    window_length = 1
    inputs = [estimize.eps, estimize.estimize_eps_final]

    # Compute market cap value
    def compute(self, today, assets, out, actual_eps, estimize_eps):
        out[:] = (actual_eps[-1] - estimize_eps[-1])/(estimize_eps[-1] + 0)
        

class WeightedSentimentByVolatility(CustomFactor):
    # Economic Hypothesis: Sentiment volatility can be an indicator that
    # public news is changing rapidly about a given security. So securities
    # with a high level of sentiment volatility may indicate a change in
    # momentum for that stock's price.
    inputs = [alphaone.article_sentiment]
    window_length = 2
    
    def compute(self, today, assets, out, sentiment):
        out[:] = np.nanstd(sentiment, axis=0) * np.nanmean(sentiment, axis=0)

def make_pipeline(context):
    # Create our pipeline
    pipe = Pipeline()

    # Get our Estimize Factors
    estimize_eps = estimize.estimize_eps_final
    actual_eps = estimize.eps
    num_estimates = estimize.count
    percent_surprise = PercentSurprise()
    
    # Screen out penny stocks and low liquidity securities.
    dollar_volume = AverageDollarVolume(window_length=20)
    is_liquid = dollar_volume.rank(ascending=False) < 1000
    
    # Create the mask that we will use for our percentile methods.
    base_universe = (is_liquid)

    # Filter down to stocks in the top/bottom 10% by sentiment rank
    factor = WeightedSentimentByVolatility()

    #pipe.add(factor, 'factor')
    longs = factor.percentile_between(85, 100, mask=base_universe)
    
    
    #shorts = factor.percentile_between(0, 10, mask=base_universe)

    # Add Accern to the Pipeline
    pipe.add(longs, "longs")
    #pipe.add(shorts, "shorts")

    # Add Factors to Pipeline
    pipe.add(estimize_eps.latest, 'estimize_eps')
    pipe.add(actual_eps.latest, 'actual_eps')
    pipe.add(num_estimates.latest, 'num_estimates')
    pipe.add(percent_surprise, 'percent_surprise')
    pipe.add(BusinessDaysUntilNextEarnings(), 'ne')
    pipe.add(BusinessDaysSincePreviousEarnings(), 'pe')
    pipe.add(EarningsCalendar.next_announcement.latest, 'next')
 
    # Set our screen
    pipe.set_screen(
        actual_eps.latest.notnan() & longs & (factor != 0) & 
        ((percent_surprise >= context.min_surprise) &
         (percent_surprise <= context.max_surprise))
         & (num_estimates >= 20))

    return pipe
        
def initialize(context):
    #: Set commissions and slippage to 0 to determine pure alpha
    set_commission(commission.PerShare(cost=0, min_trade_cost=0))
    set_slippage(slippage.FixedSlippage(spread=0))
    
    #: Declaring the days to hold, change this to what you want)))
    context.days_to_hold = 5
    #: Declares which stocks we currently held and how many days we've held them dict[stock:days_held]
    context.stocks_held = {}
    #: Declares the minimum magnitude of percent surprise
    context.min_surprise = .00
    context.max_surprise = .04
   
    #: OPTIONAL - Initialize our Hedge
    # See order_positions for hedging logic
    context.spy = sid(8554)
    
    # Make our pipeline
    attach_pipeline(make_pipeline(context), 'estimize')

    
    # Log our positions at 10:00AM
    schedule_function(func=log_positions,
                      date_rule=date_rules.every_day(),
                      time_rule=time_rules.market_open(minutes=30))
    # Order our positions
    schedule_function(func=order_positions,
                      date_rule=date_rules.every_day(),
                      time_rule=time_rules.market_open())
    # Exit our positions
    schedule_function(func=exit_positions,
                      date_rule=date_rules.every_day(),
                      time_rule=time_rules.market_close(minutes=30))



def before_trading_start(context, data):
    # Screen for securities that only have an earnings release
    # 1 business day previous and separate out the earnings surprises into
    # positive and negative 
    results = pipeline_output('estimize')
    results = results[results['pe'] == 1]
    #log.info(results)
    context.positive_surprise = results[results['percent_surprise'] > 0]
    #context.negative_surprise = results[results['percent_surprise'] < 0]
    #log.info(results.iloc[:5])
    #log.info("There are %s positive surprises today " % 
     #        (len(context.positive_surprise.index)))
    update_universe(context.positive_surprise.index)
    #print context.positive_surprise.index

def log_positions(context, data):
    #: Get all positions
    all_positions = "Current positions for %s : " % (str(get_datetime()))
    for pos in context.portfolio.positions:
        if context.portfolio.positions[pos].amount != 0:
            all_positions += "%s at %s shares, " % (pos.symbol, context.portfolio.positions[pos].amount)
    log.info(all_positions)
        
def order_positions(context, data):
    """
    Main ordering conditions to always order an equal percentage in each position
    so it does a rolling rebalance by looking at the stocks to order today and the stocks
    we currently hold in our portfolio.
    """
    port = context.portfolio.positions
    current_positive_pos = [pos for pos in port if (port[pos].amount > 0 and pos in context.stocks_held)]
    positive_stocks = context.positive_surprise.index.tolist() + current_positive_pos

    #Rebalance our positive surprise securities (existing + new)                
    for security in positive_stocks:
        if get_open_orders(security):
            continue
        if security in data:
            order_target_percent(security, 1.0 / len(positive_stocks))
            if context.stocks_held.get(security) is None:
                context.stocks_held[security] = 0

    #: Get the total amount ordered for the day
    amount_ordered = 0 
    for order in get_open_orders():
        for oo in get_open_orders()[order]:
            amount_ordered += oo.amount * data[oo.sid].price

        
def exit_positions(context, data):        
    """
    Exit position/days held update logic
    """
    #: Go through each held stock and update the number of days held and close out any positions
    #: that have been held past context.days_to_hold        
    for security in context.portfolio.positions:
        
        #: If we don't currently hold the stock or there are open orders, don't try and exit
        if context.stocks_held.get(security) is None:
            log.info("Cannot exit %s" % security.symbol)
            continue

        # Make sure that our days held are incremented
        context.stocks_held[security] += 1     

        # Exit our position and delete it from our list of securities currently held
        if context.stocks_held[security] >= context.days_to_hold:
            order_target_percent(security, 0)
            del context.stocks_held[security]
        
def handle_data(context, data):      
    
    
    for security in context.portfolio.positions:
        if security in data:
            price = data[security].price
            cost = context.portfolio.positions[security].cost_basis
            limit = cost*1.05
            stop = cost*0.95
            current_position = context.portfolio.positions[security].amount
            #if price > limit and current_position > 0:
            #    order_target_percent(security, 0.0)
            #    del context.stocks_held[security]
            #    log.info(str(security) + ' Sold For Gain')
            if price <= stop and current_position > 0:
                order_target_percent(security, 0.0)
                del context.stocks_held[security]
                log.info(str(security) + ' Sold For Loss')
        #        
    record(leverage=context.account.leverage)
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
There was a runtime error.
3 responses

Steven,

I really like your algo. I've been updating it to run in Q2 so I can paper trade it soon after I pay for the data. I'm not positive why but after updating it to Q2, two things are different. 1) The performance isn't as good and 2) leverage can spike. I'll keep working on it but I thought I would post my changes so far.

John

Clone Algorithm
16
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
"""
This is a PEAD strategy based off Estimize's earnings estimates. Estimize
is a service that aggregate financial estimates from independent, buy-side,
sell-side analysts as well as students and professors. You can run this
algorithm yourself by geting the free sample version of Estimize's consensus
dataset and EventVestor's Earnings Calendar Dataset at:

- https://www.quantopian.com/data/eventvestor/earnings_calendar
- https://www.quantopian.com/data/estimize/revisions

Much of the variables are meant for you to be able to play around with them:
1. context.days_to_hold: defines the number of days you want to hold before exiting a position
2. context.min/max_surprise: defines the min/max % surprise you want before trading on a signal
"""
import pandas as pd
import numpy as np

from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.classifiers.morningstar import Sector
from quantopian.pipeline.factors import AverageDollarVolume
from quantopian.pipeline.data.estimize import consensus_estimize_eps_free as estimize
from quantopian.pipeline.data.eventvestor import EarningsCalendar
from quantopian.pipeline.factors.eventvestor import (BusinessDaysUntilNextEarnings, BusinessDaysSincePreviousEarnings)
from quantopian.pipeline.data.accern import alphaone_free as alphaone

# Create custom factor subclass to calculate a market cap based on yesterday's
# close
class PercentSurprise(CustomFactor):
    window_length = 1
    inputs = [estimize.eps, estimize.estimize_eps_final]

    # Compute market cap value
    def compute(self, today, assets, out, actual_eps, estimize_eps):
        out[:] = (actual_eps[-1] - estimize_eps[-1])/(estimize_eps[-1] + 0)
        

class WeightedSentimentByVolatility(CustomFactor):
    # Economic Hypothesis: Sentiment volatility can be an indicator that
    # public news is changing rapidly about a given security. So securities
    # with a high level of sentiment volatility may indicate a change in
    # momentum for that stock's price.
    inputs = [alphaone.article_sentiment]
    window_length = 2
    
    def compute(self, today, assets, out, sentiment):
        out[:] = np.nanstd(sentiment, axis=0) * np.nanmean(sentiment, axis=0)

def make_pipeline(context):
    # Create our pipeline
    pipe = Pipeline()

    # Get our Estimize Factors
    estimize_eps = estimize.estimize_eps_final
    actual_eps = estimize.eps
    num_estimates = estimize.count
    percent_surprise = PercentSurprise()
    
    # Screen out penny stocks and low liquidity securities.
    dollar_volume = AverageDollarVolume(window_length=20)
    is_liquid = dollar_volume.rank(ascending=False) < 1000
    
    # Create the mask that we will use for our percentile methods.
    base_universe = (is_liquid)

    # Filter down to stocks in the top/bottom 10% by sentiment rank
    factor = WeightedSentimentByVolatility()

    #pipe.add(factor, 'factor')
    longs = factor.percentile_between(85, 100, mask=base_universe)
    
    
    #shorts = factor.percentile_between(0, 10, mask=base_universe)

    # Add Accern to the Pipeline
    pipe.add(longs, "longs")
    #pipe.add(shorts, "shorts")

    # Add Factors to Pipeline
    pipe.add(estimize_eps.latest, 'estimize_eps')
    pipe.add(actual_eps.latest, 'actual_eps')
    pipe.add(num_estimates.latest, 'num_estimates')
    pipe.add(percent_surprise, 'percent_surprise')
    pipe.add(BusinessDaysUntilNextEarnings(), 'ne')
    pipe.add(BusinessDaysSincePreviousEarnings(), 'pe')
    pipe.add(EarningsCalendar.next_announcement.latest, 'next')
 
    # Set our screen
    pipe.set_screen(
        actual_eps.latest.notnan() & longs & (factor != 0) & 
        ((percent_surprise >= context.min_surprise) &
         (percent_surprise <= context.max_surprise))
         & (num_estimates >= 20))

    return pipe
        
def initialize(context):
    #: Set commissions and slippage to 0 to determine pure alpha
    set_commission(commission.PerShare(cost=0, min_trade_cost=0))
    set_slippage(slippage.FixedSlippage(spread=0))
    
    #: Declaring the days to hold, change this to what you want)))
    context.days_to_hold = 5
    #: Declares which stocks we currently held and how many days we've held them dict[stock:days_held]
    context.stocks_held = {}
    #: Declares the minimum magnitude of percent surprise
    context.min_surprise = .00
    context.max_surprise = .04
   
    #: OPTIONAL - Initialize our Hedge
    # See order_positions for hedging logic
    context.spy = sid(8554)
    
    # Make our pipeline
    attach_pipeline(make_pipeline(context), 'estimize')

    
    # Log our positions at 10:00AM
    schedule_function(func=log_positions,
                      date_rule=date_rules.every_day(),
                      time_rule=time_rules.market_open(minutes=30))
    # Order our positions
    schedule_function(func=order_positions,
                      date_rule=date_rules.every_day(),
                      time_rule=time_rules.market_open())
    # Exit our positions
    schedule_function(func=exit_positions,
                      date_rule=date_rules.every_day(),
                      time_rule=time_rules.market_close(minutes=30))



def before_trading_start(context, data):
    # Screen for securities that only have an earnings release
    # 1 business day previous and separate out the earnings surprises into
    # positive and negative 
    results = pipeline_output('estimize')
    results = results[results['pe'] == 1]
    #log.info(results)
    context.positive_surprise = results[results['percent_surprise'] > 0]
    #context.negative_surprise = results[results['percent_surprise'] < 0]
    #log.info(results.iloc[:5])
    #log.info("There are %s positive surprises today " % 
     #        (len(context.positive_surprise.index)))
    context.assets = context.positive_surprise.index
    #print context.positive_surprise.index

def log_positions(context, data):
    #: Get all positions
    all_positions = "Current positions for %s : " % (str(get_datetime()))
    for pos in context.portfolio.positions:
        if context.portfolio.positions[pos].amount != 0:
            all_positions += "%s at %s shares, " % (pos.symbol, context.portfolio.positions[pos].amount)
    log.info(all_positions)
        
def order_positions(context, data):
    """
    Main ordering conditions to always order an equal percentage in each position
    so it does a rolling rebalance by looking at the stocks to order today and the stocks
    we currently hold in our portfolio.
    """
    port = context.portfolio.positions
    current_positive_pos = [pos for pos in port if (port[pos].amount > 0 and pos in context.stocks_held)]
    positive_stocks = context.positive_surprise.index.tolist() + current_positive_pos

    #Rebalance our positive surprise securities (existing + new)                
    for security in positive_stocks:
        if get_open_orders(security):
            continue
        if security in context.assets:
            order_target_percent(security, 1.0 / len(positive_stocks))
            if context.stocks_held.get(security) is None:
                context.stocks_held[security] = 0

    #: Get the total amount ordered for the day
    amount_ordered = 0 
    for order in get_open_orders():
        for oo in get_open_orders()[order]:
            amount_ordered += oo.amount * data.current(oo.sid, 'price')

        
def exit_positions(context, data):        
    """
    Exit position/days held update logic
    """
    #: Go through each held stock and update the number of days held and close out any positions
    #: that have been held past context.days_to_hold        
    for security in context.portfolio.positions:
        
        #: If we don't currently hold the stock or there are open orders, don't try and exit
        if context.stocks_held.get(security) is None:
            log.info("Cannot exit %s" % security.symbol)
            continue

        # Make sure that our days held are incremented
        context.stocks_held[security] += 1     

        # Exit our position and delete it from our list of securities currently held
        if context.stocks_held[security] >= context.days_to_hold:
            order_target_percent(security, 0)
            del context.stocks_held[security]
        
def handle_data(context, data):      
    for security in context.portfolio.positions:
        if security in context.assets:
            price = data.current(security, 'price')
            cost = context.portfolio.positions[security].cost_basis
            limit = cost*1.05
            stop = cost*0.95
            current_position = context.portfolio.positions[security].amount
            #if price > limit and current_position > 0:
            #    order_target_percent(security, 0.0)
            #    del context.stocks_held[security]
            #    log.info(str(security) + ' Sold For Gain')
            if price <= stop and current_position > 0:
                order_target_percent(security, 0.0)
                del context.stocks_held[security]
                log.info(str(security) + ' Sold For Loss')
        #        
    record(leverage=context.account.leverage)
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
There was a runtime error.

I figured out what was wrong with the leverage. I also removed the stop and move the leverage recording to when logging the position.

Clone Algorithm
16
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
"""
This is a PEAD strategy based off Estimize's earnings estimates. Estimize
is a service that aggregate financial estimates from independent, buy-side,
sell-side analysts as well as students and professors. You can run this
algorithm yourself by geting the free sample version of Estimize's consensus
dataset and EventVestor's Earnings Calendar Dataset at:

- https://www.quantopian.com/data/eventvestor/earnings_calendar
- https://www.quantopian.com/data/estimize/revisions

Much of the variables are meant for you to be able to play around with them:
1. context.days_to_hold: defines the number of days you want to hold before exiting a position
2. context.min/max_surprise: defines the min/max % surprise you want before trading on a signal
"""
import pandas as pd
import numpy as np

from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.classifiers.morningstar import Sector
from quantopian.pipeline.factors import AverageDollarVolume
from quantopian.pipeline.data.estimize import consensus_estimize_eps_free as estimize
from quantopian.pipeline.data.eventvestor import EarningsCalendar
from quantopian.pipeline.factors.eventvestor import (BusinessDaysUntilNextEarnings, BusinessDaysSincePreviousEarnings)
from quantopian.pipeline.data.accern import alphaone_free as alphaone

# Create custom factor subclass to calculate a market cap based on yesterday's
# close
class PercentSurprise(CustomFactor):
    window_length = 1
    inputs = [estimize.eps, estimize.estimize_eps_final]

    # Compute market cap value
    def compute(self, today, assets, out, actual_eps, estimize_eps):
        out[:] = (actual_eps[-1] - estimize_eps[-1])/estimize_eps[-1]
        

class WeightedSentimentByVolatility(CustomFactor):
    # Economic Hypothesis: Sentiment volatility can be an indicator that
    # public news is changing rapidly about a given security. So securities
    # with a high level of sentiment volatility may indicate a change in
    # momentum for that stock's price.
    inputs = [alphaone.article_sentiment]
    window_length = 2
    
    def compute(self, today, assets, out, sentiment):
        out[:] = np.nanstd(sentiment, axis=0) * np.nanmean(sentiment, axis=0)

def make_pipeline(context):
    # Create our pipeline
    pipe = Pipeline()

    # Get our Estimize Factors
    estimize_eps = estimize.estimize_eps_final
    actual_eps = estimize.eps
    num_estimates = estimize.count
    percent_surprise = PercentSurprise()
    
    # Screen out penny stocks and low liquidity securities.
    dollar_volume = AverageDollarVolume(window_length=20)
    is_liquid = dollar_volume.rank(ascending=False) < 1000
    
    # Create the mask that we will use for our percentile methods.
    base_universe = (is_liquid)

    # Filter down to stocks in the top/bottom 10% by sentiment rank
    factor = WeightedSentimentByVolatility()

    #pipe.add(factor, 'factor')
    longs = factor.percentile_between(85, 100, mask=base_universe)
    
    
    #shorts = factor.percentile_between(0, 10, mask=base_universe)

    # Add Accern to the Pipeline
    pipe.add(longs, "longs")
    #pipe.add(shorts, "shorts")

    # Add Factors to Pipeline
    pipe.add(estimize_eps.latest, 'estimize_eps')
    pipe.add(actual_eps.latest, 'actual_eps')
    pipe.add(num_estimates.latest, 'num_estimates')
    pipe.add(percent_surprise, 'percent_surprise')
    pipe.add(BusinessDaysUntilNextEarnings(), 'ne')
    pipe.add(BusinessDaysSincePreviousEarnings(), 'pe')
    pipe.add(EarningsCalendar.next_announcement.latest, 'next')
 
    # Set our screen
    pipe.set_screen(
        actual_eps.latest.notnan() & longs & (factor != 0) & 
        ((percent_surprise >= context.min_surprise) &
         (percent_surprise <= context.max_surprise))
         & (num_estimates >= 20))

    return pipe
        
def initialize(context):
    #: Set commissions and slippage to 0 to determine pure alpha
    # set_commission(commission.PerShare(cost=0, min_trade_cost=0))
    # set_slippage(slippage.FixedSlippage(spread=0))
    
    #: Declaring the days to hold, change this to what you want)))
    context.days_to_hold = 5
    #: Declares which stocks we currently held and how many days we've held them dict[stock:days_held]
    context.stocks_held = {}
    #: Declares the minimum magnitude of percent surprise
    context.min_surprise = .00
    context.max_surprise = .05
   
    #: OPTIONAL - Initialize our Hedge
    # See order_positions for hedging logic
    context.spy = sid(8554)
    
    # Make our pipeline
    attach_pipeline(make_pipeline(context), 'estimize')

    
    # Log our positions at 10:00AM
    schedule_function(func=log_positions,
                      date_rule=date_rules.every_day(),
                      time_rule=time_rules.market_open(minutes=30))
    # Order our positions
    schedule_function(func=order_positions,
                      date_rule=date_rules.every_day(),
                      time_rule=time_rules.market_open(minutes=1))
    # Exit our positions
    schedule_function(func=exit_positions,
                      date_rule=date_rules.every_day(),
                      time_rule=time_rules.market_close(minutes=30))



def before_trading_start(context, data):
    # Screen for securities that only have an earnings release
    # 1 business day previous and separate out the earnings surprises into
    # positive and negative 
    results = pipeline_output('estimize')
    results = results[results['pe'] == 1]
    #log.info(results)
    context.positive_surprise = results[results['percent_surprise'] > 0]
    #context.negative_surprise = results[results['percent_surprise'] < 0]
    #log.info(results.iloc[:5])
    #log.info("There are %s positive surprises today " % 
     #        (len(context.positive_surprise.index)))
    context.assets = context.positive_surprise.index
    #print context.positive_surprise.index

def log_positions(context, data):
    record(leverage=context.account.leverage)
    #: Get all positions
    all_positions = "Current positions for %s : " % (str(get_datetime()))
    for pos in context.portfolio.positions:
        if context.portfolio.positions[pos].amount != 0:
            all_positions += "%s at %s shares, " % (pos.symbol, context.portfolio.positions[pos].amount)
    log.info(all_positions)
        
def order_positions(context, data):
    """
    Main ordering conditions to always order an equal percentage in each position
    so it does a rolling rebalance by looking at the stocks to order today and the stocks
    we currently hold in our portfolio.
    """
    port = context.portfolio.positions
    current_positive_pos = [pos for pos in port if (port[pos].amount > 0 and pos in context.stocks_held)]
    positive_stocks = context.positive_surprise.index.tolist() + current_positive_pos
    target_percent = 0.0
    
    if (len(positive_stocks) > 0):
        target_percent = 1.0 / len(positive_stocks)
        
    print "curent set is {0} the number of stocks is {1} and the target percent is {2}".format(len(current_positive_pos), len(positive_stocks), target_percent)
    #Rebalance our positive surprise securities (existing + new)                
    for security in positive_stocks:
        if get_open_orders(security):
            continue
        order_target_percent(security, target_percent)
        if context.stocks_held.get(security) is None:
            context.stocks_held[security] = 0
        
def exit_positions(context, data):    
    """
    Exit position/days held update logic
    """
    #: Go through each held stock and update the number of days held and close out any positions
    #: that have been held past context.days_to_hold        
    for security in context.portfolio.positions:
        
        #: If we don't currently hold the stock or there are open orders, don't try and exit
        if context.stocks_held.get(security) is None:
            log.info("Cannot exit %s" % security.symbol)
            continue

        # Make sure that our days held are incremented
        context.stocks_held[security] += 1     

        # Exit our position and delete it from our list of securities currently held
        if context.stocks_held[security] >= context.days_to_hold:
            order_target_percent(security, 0)
            del context.stocks_held[security]

# def handle_data(context, data):      
#     for security in context.portfolio.positions:
#         if security in context.assets:
#             price = data.current(security, 'price')
#             cost = context.portfolio.positions[security].cost_basis
#             limit = cost*1.05
#             stop = cost*0.95
#             current_position = context.portfolio.positions[security].amount
#             #if price > limit and current_position > 0:
#             #    order_target_percent(security, 0.0)
#             #    del context.stocks_held[security]
#             #    log.info(str(security) + ' Sold For Gain')
#             if price <= stop and current_position > 0:
#                 order_target_percent(security, 0.0)
#                 del context.stocks_held[security]
#                 log.info(str(security) + ' Sold For Loss')
There was a runtime error.

Hi Stephen,

I believe we've resolved the issue you were experiencing a few weeks back. If you're still having problems please let me know.

Seong

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.