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

Excuse the novice question, I am new to coding.
I'm trying to create an algo that only trades when both the $SPY and the $IWM are uptrending.
I'm assigning a binary variable to define the trends using SMA's
I keep getting an undbloundlocalerror

UnboundLocalError: local variable 'iwmbull' referenced before assignment
USER ALGORITHM:35, in handle_data
if spybull == iwmbull:

def initialize(context):  
    context.spy = sid(8554)  
    context.iwm = sid(21519)  
    context.aapl = sid(24)  
def handle_data(context, data):  
    histspy = data.history(context.spy, 'price', 20, '1d')  
    log.info(histspy.head())  
    sma_20spy = histspy.mean()  
    sma_9spy = histspy[-9:].mean()  
    if sma_9spy > sma_20spy:  
        spybull = 1  
    elif sma_9spy < sma_20spy:  
        spybear = 1

    histiwm = data.history(context.iwm, 'price', 20, '1m')  
    log.info(histiwm.head())  
    sma_20iwm = histiwm.mean()  
    sma_9iwm = histiwm[-9:].mean()  
    if sma_9iwm > sma_20iwm:  
        iwmbull = 1  
    elif sma_9iwm < sma_20iwm:  
        iwmbear = 1  
    if spybull == iwmbull:  
        order_target_percent(context.aapl, 1.0)  
    elif spybear == iwmbear:  
        order_target_percent(context.aapl, -1.0)  
6 responses

A couple of ideas...

Assign boolean values (ie True and False) instead of assigning and comparing to 1. This generally makes your logic cleaner. So instead of

    if sma_9spy > sma_20spy:  
        spybull = 1  
    elif sma_9spy < sma_20spy:  
        spybear = 1  

Simply set the values directly (without the if statement)

    # Use boolean types to store True/False values  
    # Eliminate the if statement so these always get defined  
    spybull = sma_9spy > sma_20spy  
    spybear = sma_9spy < sma_20spy  

Do the same for setting the values of 'iwmbull' and 'iwmbear'. This will also eliminate the error you are seeing " local variable 'iwmbull' referenced before assignment". That error happens because, if the 'if' statement isn't executed, then iwmbull is never set. Python is picky about that. One always needs to set (define) a variable before it is used.

Another comment I would make is to NOT put this logic into the 'handle_data' method where it will get automatically executed every minute. Place it into a scheduled function instead. Since you are really just looking at daily data then consider trading daily. As a practical matter, using the 'order_target_percent' method doesn't account for any open orders. There is a high likelihood that ones order may not fill within a minute. Therefore, before placing more orders, one should check if there's already any outstanding orders open. This precaution isn't necessary if only trading once a day (using a scheduled function) since all orders are cancelled at the end of day so there will never be any outstanding open orders.

Attached is some updated code. Good luck.

Ahh, this is huge. Thanks for the help Dan.
I will play with this for a minute and attempt to build on this info.
If I get stuck I may reach out again

After reverse engineering this, it all makes sense now. Thanks Vlad. This is amazing.
However, i have one question. when schedule function is set to run once a day and close all positions at end of the day....what if I set schedule function to run every hour, how could I get it to close positions if the trend changes intraday (if that makes sense)?
EX: let's say MKT1 and MKT2 are both uptrending from 9:30 to 11:00, then at 11:10 MKT2 start downtrending....How do I get it to close all positions at 11:10

I think a lot of people would be pleasantly surprised like I was, how much headroom became available on Quantopian after they doubled the RAM awhile ago. So you can do a lot every minute, scheduling like this every minute or every 2 or 5 or whatever. The rest of this is mainly just to give schedule_function something to be doing and in case it might spark an idea or be useful to someone in the future arriving here. I have not thought about your code, only a narrow band, suggesting that you can be checking a condition even every minute if you want to. Could be (100, 391 to be starting at 11:10 ... but then also watching that condition all day.

import pandas as pd

def initialize(context):  
    context.pnls = pd.Series({})

    for i in range(1, 391, 1):  # start, end + 1, every i minutes and in this case simply 1  
        schedule_function(mkt_check, date_rules.every_day(), time_rules.market_open(minutes=i))

def mkt_check(context,data):  
    ''' Placeholder ... and might as well toss some ideas out there while at it.  
    I think you'll want to do something more specific to your algorithm.  
    To have something in place here generically that might benefit others,  
      this is checking PnL (Profit-n-Loss) on every position, both long and short.  
    '''  
    c = context   # brevity, easier reading  
    # Lowest 9 pnl  
    lows = c.pnls.sort_values(ascending=False)[-9:].index if len(c.pnls) else []

    pos = c.portfolio.positions  
    for s in pos:  
        if not data.can_trade(s): continue  
        pnl = pos[s].amount * (data.current(s, 'price') - pos[s].cost_basis)

        if s in c.pnls and pnl < .95 * c.pnls[s]:   # close if way down  
            if get_open_order(s): continue  
            order_target(s, 0)

        # I haven't thought this thru, you can do something that'll actually make good sense  
        if MKT1_bear and MKT2_bear and s in lows:  
            if get_open_order(s): continue  
            order_target(s, 0)

        c.pnls[s] = pnl     # replace with latest  

I figured out how to close positions if the trend becomes mixed (mkt1 is bullish and mk2 is bearish).
however, the mkt_check maybe a little over my head at my novice state. I will reverse engineer that tomorrow

andre,

The strategy I created based on yours idea is not HFT or daytrading.
It makes every day some minor re balancing trades but major switches happens in average once a month.
You may try to trade it more frequently as Blue recommending.