Back to Community
piotroski long/short using pipeline

Hi
i have done my version of the piotroski skore model.
In my code the last year value of fundamental data is 200 bars (days) ago and new shares are calculated with a minus sign (line 65) to check that no new shares has been created from last year.
The stock selection has no filter beside the classic piotroski score an it's limited to 100 stock on the long side and 100 stock on the short side.

So actually the question, is.. why does it perform so bad, do you see some issue in the code or something?...

Clone Algorithm
39
Loading...
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
"""
    Creating an algorithm based off the Piotroski Score index which is based off of a score (0-9)
    Each of the following marks (-) satisfied means one point. And in the end we'll long the stocks with a score of >= 8

    Profitability 
    - Positive ROA
    - Positive Operating Cash Flow
    - Higher ROA in current year versus last year
    - Cash flow from operations > ROA of current year

    Leverage
    - Current ratio of long term debt < last year's ratio of long term debt
    - Current year's current_ratio > last year's current_ratio
    - No new shares issued this year

    Operating Efficiency
    - Higher gross margin compared to previous year
    - Higher asset turnover ratio compared to previous year


    This algorithm demonstrates how to grasp historical fundamental data by storing it in a Pandas Panel similar to how the Quantopian 'data' is currently structured
"""
import numpy as np
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar
            
class Piotroski(CustomFactor):
    def compute(self, today, assets, out, values):
        if self.window_length >1:
            out[:] = values[-1] - values[0]
        else:
            out[:] = values[-1] 

def initialize(context):
    # number of stocks to buy = number of stocks to sell
    context.num_of_stocks = 100
    # approximate last year as 200 bars back
    last_year_length = 200
    pipe = Pipeline()
    attach_pipeline(pipe, name='my_pipeline')
    # ROA this year versus ROA last year
    ROA_current_vs_last = Piotroski(inputs= [morningstar.operation_ratios.roa],window_length = last_year_length )
    # ROA current value
    ROA = Piotroski(inputs= [morningstar.operation_ratios.roa],window_length = 1 )
    # CASH FLOW current value
    cash_flow = Piotroski(inputs = [morningstar.cash_flow_statement.operating_cash_flow],window_length = 1 )
    # R
    ratio_long_term_debt = Piotroski(inputs= [morningstar.operation_ratios.long_term_debt_equity_ratio],window_length = 1 )
    ratio_long_term_debt_current_vs_last = Piotroski(inputs= [morningstar.operation_ratios.long_term_debt_equity_ratio],window_length = last_year_length )
    current_ratio = Piotroski(inputs= [morningstar.operation_ratios.current_ratio],window_length = 1 )
    current_ratio_current_vs_last = Piotroski(inputs= [morningstar.operation_ratios.current_ratio],window_length = last_year_length )
    shares_outstanding_current_vs_last = Piotroski(inputs= [morningstar.valuation.shares_outstanding],window_length = last_year_length )
    gross_margin_current_vs_last = Piotroski(inputs= [morningstar.operation_ratios.gross_margin],window_length = last_year_length )
    asset_turnover_current_vs_last = Piotroski(inputs= [morningstar.operation_ratios.assets_turnover],window_length = last_year_length )
    pipe.add(ROA_current_vs_last, name= 'ROA var')
    pipe.add(ROA, name = 'ROA')
    pipe.add(cash_flow , name= 'cash flow')
    pipe.add(ratio_long_term_debt, name= 'debt ratio')
    pipe.add(ratio_long_term_debt_current_vs_last, name= 'debt ratio var')
    pipe.add(current_ratio, name='Cur Ratio')
    pipe.add(current_ratio_current_vs_last, name= 'Cur ratio var')
    pipe.add(-shares_outstanding_current_vs_last, name= 'New shares')
    pipe.add(gross_margin_current_vs_last, name= 'Gross var')
    pipe.add(asset_turnover_current_vs_last, name= 'Turnover var')
    schedule_function(rebalance, date_rules.month_start(), time_rules.market_close())
def before_trading_start(context, data):
    context.output = pipeline_output('my_pipeline')
    context.scores_df = context.output.applymap(turn_values_into_points)
    context.piotroski_series = context.scores_df.sum(axis=1).sort(inplace=False, ascending=False)
    long_stocks = context.piotroski_series.ix[context.piotroski_series > 7].iloc[:context.num_of_stocks]
    short_stocks = context.piotroski_series.ix[context.piotroski_series < 2].iloc[-context.num_of_stocks:]
    context.long_stocks = long_stocks.index
    context.short_stocks = short_stocks.index
    update_universe(np.union1d(context.long_stocks, context.short_stocks))
def rebalance(context, data):
    #print 'go long on: \n{0}\ngo short on: \n{1}'.format([i.symbol for i in context.long_stocks],[i.symbol for i in context.short_stocks])
    set_long = set(context.long_stocks)
    set_short = set(context.short_stocks)
    set_data = set(data.keys())
    long_list = set.intersection(set_data, set_long)
    short_list = set.intersection(set_data, set_short)
    print 'go long on: \n{0}\ngo short on: \n{1}'.format([i.symbol for i in long_list],[i.symbol for i in short_list])
    long_weight = (.9/len(long_list))/2
    short_weight = -(0.9/len(short_list))/2
    for s in long_list:
        if s not in get_open_orders(): 
            order_target_percent(s, long_weight)
    for s in short_list:
        if s not in get_open_orders(): 
            order_target_percent(s, short_weight)
    for s in context.portfolio.positions.iterkeys():
        if s not in get_open_orders(): 
            if s not in long_list and s not in short_list:
                order_target(s, 0)
    record(leverage = context.account.leverage)
def handle_data(context, data):
    pass
def turn_values_into_points(x):
    if x > 0:
        return 1
    else:
        return 0
There was a runtime error.
7 responses

this is the same thing with different code (cloned) and slightly modified to be long / short

how can i understand from this performance if this is a good starting point to build a market neutral strategy?

Clone Algorithm
16
Loading...
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 numpy as np
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline import CustomFactor, Pipeline
from quantopian.pipeline.factors import SimpleMovingAverage
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.data import morningstar

# Put any initialization logic here.  The context object will be passed to
# the other methods in your algorithm.
class Piotroski(CustomFactor):
    inputs = [
        morningstar.operation_ratios.roa,
        morningstar.cash_flow_statement.operating_cash_flow,
        morningstar.cash_flow_statement.cash_flow_from_continuing_operating_activities,
        
        morningstar.operation_ratios.long_term_debt_equity_ratio,
        morningstar.operation_ratios.current_ratio,
        morningstar.valuation.shares_outstanding,
        
        morningstar.operation_ratios.gross_margin,
        morningstar.operation_ratios.assets_turnover,
    ]
    window_length = 100
    
    def compute(self, today, assets, out,
                roa, cash_flow, cash_flow_from_ops,
                long_term_debt_ratio, current_ratio, shares_outstanding,
                gross_margin, assets_turnover):
        profit = (
            (roa[-1] > 0).astype(int) +
            (cash_flow[-1] > 0).astype(int) +
            (roa[-1] > roa[0]).astype(int) +
            (cash_flow_from_ops[-1] > roa[-1]).astype(int)
        )
        
        leverage = (
            (long_term_debt_ratio[-1] < long_term_debt_ratio[0]).astype(int) +
            (current_ratio[-1] > current_ratio[0]).astype(int) + 
            (shares_outstanding[-1] <= shares_outstanding[0]).astype(int)
        )
        
        operating = (
            (gross_margin[-1] > gross_margin[0]).astype(int) +
            (assets_turnover[-1] > assets_turnover[0]).astype(int)
        )
        
        out[:] = profit + leverage + operating

class ROA(CustomFactor):
    window_length = 1
    inputs = [morningstar.operation_ratios.roa]
    
    def compute(self, today, assets, out, roa):
        out[:] = (roa[-1] > 0).astype(int)
        
class ROAChange(CustomFactor):
    window_length = 100
    inputs = [morningstar.operation_ratios.roa]
    
    def compute(self, today, assets, out, roa):
        out[:] = (roa[-1] > roa[0]).astype(int)
        
class CashFlow(CustomFactor):
    window_length = 1
    inputs = [morningstar.cash_flow_statement.operating_cash_flow]
    
    def compute(self, today, assets, out, cash_flow):
        out[:] = (cash_flow[-1] > 0).astype(int)
        
class CashFlowFromOps(CustomFactor):
    window_length = 1
    inputs = [morningstar.cash_flow_statement.cash_flow_from_continuing_operating_activities, morningstar.operation_ratios.roa]
    
    def compute(self, today, assets, out, cash_flow_from_ops, roa):
        out[:] = (cash_flow_from_ops[-1] > roa[-1]).astype(int)
        
class LongTermDebtRatioChange(CustomFactor):
    window_length = 100
    inputs = [morningstar.operation_ratios.long_term_debt_equity_ratio]
    
    def compute(self, today, assets, out, long_term_debt_ratio):
        out[:] = (long_term_debt_ratio[-1] < long_term_debt_ratio[0]).astype(int)
        
class CurrentDebtRatioChange(CustomFactor):
    window_length = 100
    inputs = [morningstar.operation_ratios.current_ratio]
    
    def compute(self, today, assets, out, current_ratio):
        out[:] = (current_ratio[-1] > current_ratio[0]).astype(int)
        
class SharesOutstandingChange(CustomFactor):
    window_length = 100
    inputs = [morningstar.valuation.shares_outstanding]
    
    def compute(self, today, assets, out, shares_outstanding):
        out[:] = (shares_outstanding[-1] <= shares_outstanding[0]).astype(int)
        
class GrossMarginChange(CustomFactor):
    window_length = 100
    inputs = [morningstar.operation_ratios.gross_margin]
    
    def compute(self, today, assets, out, gross_margin):
        out[:] = (gross_margin[-1] > gross_margin[0]).astype(int)
        
class AssetsTurnoverChange(CustomFactor):
    window_length = 100
    inputs = [morningstar.operation_ratios.assets_turnover]
    
    def compute(self, today, assets, out, assets_turnover):
        out[:] = (assets_turnover[-1] > assets_turnover[0]).astype(int) 
        
class AroonUp(CustomFactor):
    window_length = 100
    inputs = [USEquityPricing.high]
    
    def compute(self, today, assets, out, highs):
        out[:] = (np.argmax(highs, 0).astype(float)/float(self.window_length))*100.0

class AroonDown(CustomFactor):
    window_length = 100
    inputs = [USEquityPricing.low]
    
    def compute(self, today, assets, out, lows):
        out[:] = (np.argmin(lows, 0).astype(float)/float(self.window_length))*100.0
        
def initialize(context):

    pipe = Pipeline()
    pipe = attach_pipeline(pipe, name='piotroski')
    
    profit = ROA() + ROAChange() + CashFlow() + CashFlowFromOps()
    leverage = LongTermDebtRatioChange() + CurrentDebtRatioChange() + SharesOutstandingChange()
    operating = GrossMarginChange() + AssetsTurnoverChange()
    piotroski = profit + leverage + operating

    mc = SimpleMovingAverage(inputs=[morningstar.valuation.market_cap], window_length=10)
    pipe.add(mc, 'mc')
    pipe.add(piotroski, 'piotroski')
    schedule_function(rebalance, date_rules.month_start(), time_rules.market_close())

def before_trading_start(context, data):
    context.results = pipeline_output('piotroski')
    mktCap = context.results.sort('mc', ascending=False).head(400)
    long_stocks = mktCap.ix[mktCap['piotroski']>=7].head(10)
    short_stocks = mktCap.ix[mktCap['piotroski']<=2].head(10)
    context.long_stocks = long_stocks.index  
    context.short_stocks = short_stocks.index
    update_universe(np.union1d(context.long_stocks, context.short_stocks))
def rebalance(context, data):
    
    set_long = set(context.long_stocks)
    set_short = set(context.short_stocks)
    set_data = set(data.keys())
    long_list = set.intersection(set_data, set_long)
    short_list = set.intersection(set_data, set_short)
    print 'go long on: \n{0}\ngo short on: \n{1}'.format([i.symbol for i in long_list],[i.symbol for i in short_list])
    long_weight = (.9/len(long_list))/2
    short_weight = -(0.9/len(short_list))/2
    for s in long_list:
        if s not in get_open_orders(): 
            order_target_percent(s, long_weight)
    for s in short_list:
        if s not in get_open_orders(): 
            order_target_percent(s, short_weight)
    for s in context.portfolio.positions.iterkeys():
        if s not in get_open_orders(): 
            if s not in long_list and s not in short_list:
                order_target(s, 0)
    record(leverage = context.account.leverage)
'''
def trade(context, data):
    num_valid_stocks = 0
    valid_stocks = set(data.keys()).intersection(set(context.long_stocks.index))
    
    for stock in valid_stocks:
        order_target_percent(stock, (context.piotroski_weight[stock] + context.aroon_weight[stock])/2.0)
    
    for stock in context.portfolio.positions:
        if stock not in valid_stocks:
            order_target_percent(stock, 0)
'''
# Will be called on every trade event for the securities you specify. 
def handle_data(context, data):
    pass
    
There was a runtime error.

Thank you very much for putting this up. I have one question

roa[-1] > roa[0])

does this really compare roa from the last year vs roa from the most recent? I thought Piotroski makes you compare roa from the most recent vs 12 months ago roa.

If it is this easy to get historical fundamental, why are staffs in quantopian keep saying that historical fundamental is not there yet, but on the short list.

finally can you get both quarterly as well as annual fundamental from pipline? How can you command it to get each?
Thank you

Hi Ujae,
You can get historical fundamentals. For example, you can get a fundamentals field (lets use shares outstanding for example) in pipeline with a window length of 300, and you will get an array with the last 300 days of shares outstanding. This will reflect what was reported, and then it will be forward filled. That works, and is easy.

What is hard, is if you just want the last 4 quarterly reported values on the day they were reported. This is what is on the short list and we need to make easier to get it.

Hope that makes sense.

KR

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.

Karen,
Thank you for the information. That makes sense. So what we are getting in the fundamental is annual data or quarterly? I am guessing that it is quarterly fundamental data (these quarterly fundamentals are season biased you know). Do you have a sample code what would show how to pull annual data? Or is it not possible.

With Morningstar fundamentals, we currently only surface quarterly metrics or metrics that are updated daily (like market cap, enterprise value and many per-share ratios). Definitely on our roadmap but not an imminent project.

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.

Giuseppe,
Are you still working with this algorithm? I found this post while searching to see if there were any already made pipelines with the Piotroski score.
It doesn't look like any has answered your original question. I would guess the poor performance comes from a misapplication of the principle. Piotroski developed his score to assess the financial strength firms with high book-to-market ratios (Piotroski 2000). It was intended to enhance the already positive performance of value stocks. You might want to try modifying your algorithm to sort on value and see if the results are improved.

Here is a version with a few quick changes I changed market cap from being a sorting factor to a filter and then sorted on price to book ratio instead.

...There is nothing quick about running the backtests, though. It probably needs to be updated to fully take advantage of the new "Q2" features.

Clone Algorithm
38
Loading...
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 numpy as np
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline import CustomFactor, Pipeline
from quantopian.pipeline.factors import SimpleMovingAverage
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.data import morningstar

# Put any initialization logic here.  The context object will be passed to
# the other methods in your algorithm.
class Piotroski(CustomFactor):
    inputs = [
        morningstar.operation_ratios.roa,
        morningstar.cash_flow_statement.operating_cash_flow,
        morningstar.cash_flow_statement.cash_flow_from_continuing_operating_activities,
        
        morningstar.operation_ratios.long_term_debt_equity_ratio,
        morningstar.operation_ratios.current_ratio,
        morningstar.valuation.shares_outstanding,
        
        morningstar.operation_ratios.gross_margin,
        morningstar.operation_ratios.assets_turnover,
    ]
    window_length = 100
    
    def compute(self, today, assets, out,
                roa, cash_flow, cash_flow_from_ops,
                long_term_debt_ratio, current_ratio, shares_outstanding,
                gross_margin, assets_turnover):
        profit = (
            (roa[-1] > 0).astype(int) +
            (cash_flow[-1] > 0).astype(int) +
            (roa[-1] > roa[0]).astype(int) +
            (cash_flow_from_ops[-1] > roa[-1]).astype(int)
        )
        
        leverage = (
            (long_term_debt_ratio[-1] < long_term_debt_ratio[0]).astype(int) +
            (current_ratio[-1] > current_ratio[0]).astype(int) + 
            (shares_outstanding[-1] <= shares_outstanding[0]).astype(int)
        )
        
        operating = (
            (gross_margin[-1] > gross_margin[0]).astype(int) +
            (assets_turnover[-1] > assets_turnover[0]).astype(int)
        )
        
        out[:] = profit + leverage + operating

class ROA(CustomFactor):
    window_length = 1
    inputs = [morningstar.operation_ratios.roa]
    
    def compute(self, today, assets, out, roa):
        out[:] = (roa[-1] > 0).astype(int)
        
class ROAChange(CustomFactor):
    window_length = 100
    inputs = [morningstar.operation_ratios.roa]
    
    def compute(self, today, assets, out, roa):
        out[:] = (roa[-1] > roa[0]).astype(int)
        
class CashFlow(CustomFactor):
    window_length = 1
    inputs = [morningstar.cash_flow_statement.operating_cash_flow]
    
    def compute(self, today, assets, out, cash_flow):
        out[:] = (cash_flow[-1] > 0).astype(int)
        
class CashFlowFromOps(CustomFactor):
    window_length = 1
    inputs = [morningstar.cash_flow_statement.cash_flow_from_continuing_operating_activities, morningstar.operation_ratios.roa]
    
    def compute(self, today, assets, out, cash_flow_from_ops, roa):
        out[:] = (cash_flow_from_ops[-1] > roa[-1]).astype(int)
        
class LongTermDebtRatioChange(CustomFactor):
    window_length = 100
    inputs = [morningstar.operation_ratios.long_term_debt_equity_ratio]
    
    def compute(self, today, assets, out, long_term_debt_ratio):
        out[:] = (long_term_debt_ratio[-1] < long_term_debt_ratio[0]).astype(int)
        
class CurrentDebtRatioChange(CustomFactor):
    window_length = 100
    inputs = [morningstar.operation_ratios.current_ratio]
    
    def compute(self, today, assets, out, current_ratio):
        out[:] = (current_ratio[-1] > current_ratio[0]).astype(int)
        
class SharesOutstandingChange(CustomFactor):
    window_length = 100
    inputs = [morningstar.valuation.shares_outstanding]
    
    def compute(self, today, assets, out, shares_outstanding):
        out[:] = (shares_outstanding[-1] <= shares_outstanding[0]).astype(int)
        
class GrossMarginChange(CustomFactor):
    window_length = 100
    inputs = [morningstar.operation_ratios.gross_margin]
    
    def compute(self, today, assets, out, gross_margin):
        out[:] = (gross_margin[-1] > gross_margin[0]).astype(int)
        
class AssetsTurnoverChange(CustomFactor):
    window_length = 100
    inputs = [morningstar.operation_ratios.assets_turnover]
    
    def compute(self, today, assets, out, assets_turnover):
        out[:] = (assets_turnover[-1] > assets_turnover[0]).astype(int) 
        
class AroonUp(CustomFactor):
    window_length = 100
    inputs = [USEquityPricing.high]
    
    def compute(self, today, assets, out, highs):
        out[:] = (np.argmax(highs, 0).astype(float)/float(self.window_length))*100.0

class AroonDown(CustomFactor):
    window_length = 100
    inputs = [USEquityPricing.low]
    
    def compute(self, today, assets, out, lows):
        out[:] = (np.argmin(lows, 0).astype(float)/float(self.window_length))*100.0
        
def initialize(context):

    pipe = Pipeline()
    pipe = attach_pipeline(pipe, name='piotroski')
    
    profit = ROA() + ROAChange() + CashFlow() + CashFlowFromOps()
    leverage = LongTermDebtRatioChange() + CurrentDebtRatioChange() + SharesOutstandingChange()
    operating = GrossMarginChange() + AssetsTurnoverChange()
    piotroski = profit + leverage + operating
    pipe.add(piotroski, 'piotroski')
    
    # Value metric
    price_to_book = morningstar.valuation_ratios.pb_ratio.latest
    pipe.add(price_to_book, 'price-to-book')
    
    mc = SimpleMovingAverage(inputs=[morningstar.valuation.market_cap], window_length=10)
    top_mc = mc.top(500)
    pipe.set_screen(top_mc)
    
    schedule_function(rebalance, date_rules.month_start(), time_rules.market_close())

def before_trading_start(context, data):
    context.results = pipeline_output('piotroski')
    value_sorted = context.results.sort('price-to-book', ascending=False)
    long_stocks = value_sorted.ix[value_sorted['piotroski']>=7].head(50)
    short_stocks = value_sorted.ix[value_sorted['piotroski']<=2].tail(50)
    context.long_stocks = long_stocks.index  
    context.short_stocks = short_stocks.index
    update_universe(np.union1d(context.long_stocks, context.short_stocks))
def rebalance(context, data):
    
    set_long = set(context.long_stocks)
    set_short = set(context.short_stocks)
    set_data = set(data.keys())
    long_list = set.intersection(set_data, set_long)
    short_list = set.intersection(set_data, set_short)
    print 'go long on: \n{0}\ngo short on: \n{1}'.format([i.symbol for i in long_list],[i.symbol for i in short_list])
    long_weight = (.9/len(long_list))/2
    short_weight = -(0.9/len(short_list))/2
    for s in long_list:
        if s not in get_open_orders() and data.can_trade(s): 
            order_target_percent(s, long_weight)
    for s in short_list:
        if s not in get_open_orders() and data.can_trade(s): 
            order_target_percent(s, short_weight)
    for s in context.portfolio.positions.iterkeys():
        if s not in get_open_orders() and data.can_trade(s): 
            if s not in long_list and s not in short_list:
                order_target(s, 0)
    record(leverage = context.account.leverage)
'''
def trade(context, data):
    num_valid_stocks = 0
    valid_stocks = set(data.keys()).intersection(set(context.long_stocks.index))
    
    for stock in valid_stocks:
        order_target_percent(stock, (context.piotroski_weight[stock] + context.aroon_weight[stock])/2.0)
    
    for stock in context.portfolio.positions:
        if stock not in valid_stocks:
            order_target_percent(stock, 0)
'''
# Will be called on every trade event for the securities you specify. 
def handle_data(context, data):
    pass
    
There was a runtime error.