Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Simple Mean Reversion Strategy

I'm new to both Quantopian and trading in general, but I attempted to implement a mean reversion strategy. I'm buying the low performing stocks and selling the high performing stocks each day weighting the performance of everything relative to the other stocks in the portfolio.

At this point I'm trying to interpret the results, but I'm not entirely sure how of the results are from the algorithm and how much are simply a consequence of the stocks I selected.

If anyone has any questions, comments, or suggestions please let me know!

I've had a lot of fun learning and working with the platform.

8 responses

nice!

HI Michael,

I am looking at the source code of your algorithm and I am unable to follow the logic of your final for loop. Can you add some explanation/ comments to the code snippet?


    for i in range(len(norm_pct)):  
        stock = context.stocks[i]  
        sell_amount = round(-1 * context.portfolio.positions[stock].amount * norm_pct[i] * norm_pct[i])  
        buy_amount = buy_multiplier * round((context.portfolio.cash / data[stock].price) * norm_pct[i] * norm_pct[i])  
        notional = context.portfolio.positions[stock].amount * data[stock].price  
        if norm_pct[i] > 0 and abs(sell_amount) > 0 and notional > -context.max_notional:  
            if norm_pct[i]**2 > 0.05:  
                order(stock, sell_amount)

        if norm_pct[i] < 0 and buy_amount > 0 and notional < context.max_notional:  
            if abs(norm_pct[i]) > 0.05:  
                order(stock, buy_amount)  

Sure, let me try to explain what I was trying to do.

    for i in range(len(norm_pct)):  
        stock = context.stocks[i]  
        sell_amount = round(-1 * context.portfolio.positions[stock].amount * norm_pct[i] * norm_pct[i])  
        buy_amount = buy_multiplier * round((context.portfolio.cash / data[stock].price) * norm_pct[i] * norm_pct[i])  

I step through each stock that I'm watching, and compute how many of that stock I'd buy or sell given my current position, cash, and its performance. The amount to buy is the maximum number of the stocks I could buy (cash / stock price) weighted by its performance relative to the other stocks in my portfolio. The amount we want to sell is the amount of that stock we own weighted in the same way.

I'm not 100% convinced of the validity of this logic (I feel like I should be weighting the stocks that had gains and losses independently of each other, but I haven't implemented it yet). My reasoning was that if we assume the stock is mean reverting, it makes sense to buy more of the ones that had performed poorly, and quickly sell off more of what had been performing well. The weightings were my way of expressing this idea.

        if norm_pct[i] > 0 and abs(sell_amount) > 0 and notional > -context.max_notional:  
            if norm_pct[i]**2 > 0.05:  
                order(stock, sell_amount)

        if norm_pct[i] < 0 and buy_amount > 0 and notional < context.max_notional:  
            if abs(norm_pct[i]) > 0.05:  
                order(stock, buy_amount)  

The next part implements the buying and selling. We compute how much we would buy or would sell for every stock, but only buy or sell if it's normalized percent change is negative or positive.

We also don't want to submit a buy or sell order unless we have hit some kind of threshold for how much it changed. In cases where the total change was very small we just hold onto the stock. It may be worth considering the stock performance from the point where we bought for the case where we're selling, but I haven't gotten around to testing that.

I hope that's helpful, let me know if you have any other questions.

Thanks so much for that response. This helps a lot

Glad I could help!

I went ahead and implemented the changes I was thinking about, and it does seem to improve the algorithm. Check it out!

Nice improvement!

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.

Interesting.

I thought I'd try backtesting the algorithm against the top ten dividend yielding stocks in the NYSE for the last twelve months, and got this result: considerably worse!

good work!