Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
rebalance - sell only when a stock goes below its moving average

I'm having trouble with coding something that I think should be easy.

When I run my_rebalance, I want to first check the stocks I already own. And if the price is lower than the 50 day moving average, I want to sell it down to 0.

When I try it like I have pasted at the bottom, I get this error:

There was a runtime error.
AttributeError: 'zipline.assets._assets.Equity' object has no attribute 'USEquityPricing'
USER ALGORITHM:26, in my_rebalance
if security.USEquityPricing.price.latest < sma_50:

My code:

def my_rebalance(context,data):
for security in context.portfolio.positions:
# check to see if our longs have broken down. otherwise, do nothing.
sma_50 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=50)
if security.USEquityPricing.price.latest < sma_50:
order_target_percent(security,0)

5 responses

The error is saying the 'security' object doesn't have a method or attribute named USEquityPricing. The exact error is in this line:

if security.USEquityPricing.price.latest < sma_50:

However, there is another issue with the way 'SimpleMovingAverage' is being used. That needs to be put into the pipeline definition. Take a look at the tutorials if you haven't already (https://www.quantopian.com/tutorials/getting-started). Lessons 5-7 demonstrate how to create the pipeline definition, get the results in a dataframe, and then use those results in logic. I've also attached a simple algo with these steps which may get you moving forward.

Hope that helps. Good luck.

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.

Dan,

Thanks for the help.

I have moved the calculation of moving average down to pipeline. Now it's a matter of checking the condition on securities that are already in the portfolio.

I'm getting this error now:

TypeError: 'zipline.assets.assets.Equity' object has no attribute 'getitem_'
USER ALGORITHM:26, in my_rebalance
if security['latest price'] < security['50D MA']:

Are you trying to run an algo within a notebook or did you just copy your algo code into a notebook for demonstration? Algos don't run in notebooks and it would be helpful if you attached the actual algo. That said, a couple of things.

Looking at this statement

    for security in context.portfolio.positions:  
        # check to see if our longs have broken down. otherwise, do nothing.  
        if security['latest price'] < security['50D MA']:  
            order_target_percent(security,0)  
        else:  
            continue

'security' is an equity object. It only has a limited number of attributes (see https://www.quantopian.com/help#api-sidinfo). The fields you're trying to reference ('latest price' and '50D MA') are columns in the pipeline output (ie context.output) which is a pandas dataframe. The best way to fetch single values from a dataframe is to use the .at method (https://pandas.pydata.org/pandas-docs/version/0.18/generated/pandas.DataFrame.at.html). So maybe the code could be something like this:

    for stock in context.portfolio.positions:  
        yesterday_close = context.output.at[stock, 'latest price']  
        sma_50 = context.output.at[stock, '50D MA']  
        if yesterday_close < sma_50 and  data.can_trade(stock):  
                order_target_percent(stock, 0)

That fetches 'latest price' and '50D MA' for that specific security from the context.output dataframe. It then compares those values. BTW it's always a good idea to check if 'data.can_trade' in case a security became delisted. Doesn't happen often but the algo will error if it does.

While the above should work, some may consider it not very 'pythonic'. Generally, python (and especially pandas) is better at doing things across entire groups of data in a parallel manner and then working with those groups. Additionally, it's often very advantageous to NOT use spaces in dataframe column names. Best to use an underscore instead. So this would be another way to do the same thing:

    # Select all the stocks meeting the query criteria then turn that into a list  
    close_these = context.output.query('latest_price < 50D_MA').index.tolist()

    for stock in context.portfolio.positions:  
        if stock in close_these and data.can_trade(stock):  
            order_target_percent(stock, 0)

Part of the benefit of this approach is by using the query method the logic can be as involved and complex as one wishes and still remain very readable. See https://pandas.pydata.org/pandas-docs/version/0.18/generated/pandas.DataFrame.query.html and https://pandas.pydata.org/pandas-docs/version/0.18/indexing.html#indexing-query for some good examples.

Hope that get's the error resolved.

Dan,

Thanks so much. I was able to get it working using this:
close_these = context.output.query('latest_price < 50D_MA').index.tolist()

I just put it in a notebook since it wouldn't run a backtest because of the errors.

I've attached one now. More work to be done!

Thanks,
Andrew

Andrew, glad to help. Looks good.