Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Momentum: Stock splits causing issues with overlapping portfolios

Hi,
I am trying to write a proper momentum portfolio simulation, rather than the simple examples on Quantopian.
For those who aren't up with it, the correct use of momentum involves a set of overlapping sub-portfolios. I have implemented this using python classes where each class represents one of the overlapping sub-portfolios.
The same security could be held in more than 1 subportfolio. I resolve this by allowing each subportfolio to store an internal object containing all the orderids it has issued.
This all works fine until there is a stock split. When I want to liquidate a subportfolio, I get back all the orders it has placed, and for each one, obtain the quantity (stored in amount), and sell that amount. Unfortunately, when there is a stock split, it appears the actual portfolio gets correctly adjusted by quantopian, but the order amounts are not adjusted.
Example: If I bought 1000 of XYZ into subportfolio 1, then that orderid for XYZ shows amount of 1000. If 6 months later, I want to liquidate portfolio 1, I get_order that orderid, and it correctly shows 1000. If in the meantime there was a 2:1 share split, then my actual portfolio only contains 500 XYZ. Selling the original 1000 then makes me short 500.
Essentially, the order amount hasn't been adjusted, but the portfolio quantity has. In the overlapping portfolio structure, orders could have been issued for XYZ from several different subportfolios (subportfolio1, subportfolio2 and subportfolio3 for example), so there appears to be no way to identify how many XYZ should be sold when closing a specific subportfolio - each subportfolio has correctly stored its orderids, but they do not contain the updated quantity after the split, only the original quantity)
I would appreciate any thoughts on how I can resolve this problem.
Cheers,
Bruce

4 responses

The zipline backtester isn't well set up to track 'lots' or sub-portfolios. Certainly saving the order objects isn't a good practice. As noted, the amounts and prices won't be adjusted for any splits or dividends.

One solution may be to track the 'weights' of each holding within each sub-portfolio. Maybe a dataframe with securities as the index and columns representing the percentage of the total holdings associated with each portfolio. The sum of the columns for a given row should always equal 1 (or maybe zero if no positions are held). Whenever a new position is opened, find the row associated with the security and update all the column values to the new percentages. Use the dollar value of the position and not the shares.

When one wants to close out a sub-portfolio, simply go to the associated column. Loop through all the securities with non-zero weights and close out the associated percentage of total holdings for each security. This can actually be done in one step by creating a series from the column and then using order_optimal_portfolio with a target weight of 1-my_series.

There is another "oh by the way". The above method won't account for any added shares for spinoffs or for dividends. Consider the case where a company spins off a subsidiary. For example SHLD spun off Lands End in 2014 (https://www.forbes.com/sites/samanthasharf/2014/04/07/sears-completes-lands-end-spinoff/#3fcd2eae1efc). The backtester will magically add new shares of Lands End to the total portfolio to reflect this spin off (similar to what a real broker would do). It will be difficult to go back and equate those new shares with the shares of SHLD. There's no good way to proportion those new shares between the portfolios. A similar issue happens with dividends. Dividends will be deposited into the total portfolio and will be difficult to proportion to the proper sub-portfolio.

Hope that helps a bit.

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.

Hi Dan,

thanks for your reply.

I don't think that will work for me... the percentage weight that each security represents in a subportfolio will change as the price evolves. Probably best for me is to use backadjusted data, so I will need to step outside quantopian for this. Backadjusted data is readily available and already adjusted for the effects of splits, dividends etc for exactly this purpose.

Just to be clear though, my problem is not related to subportfolios... that is just how I came across the problem. Subportfolios work fine within the quantopian and python class structure.

The problem is that the initial order quantity is not updated after a stock split, but the portfolio position size is. That means that if I buy 1000 XYZ today, my portfolio will show a position size of 1000. If there is a 2:1 stock split tomorrow, my order will still show 1000, but the portfolio will show 500. The current quantopian practice does not keep the two things in sync.

This means that it is very risky to use the amount returned by the get_order function... the amount you get back represents the state at which the order was placed, not the current state. I understand why you have done that, but it essentially means that it is not possible to manually control your own orders in an algorithm... (the functions are provided to allow you to do that, but if a stock split occurs, then the results are wrong).

I think it would be wise to put a note to this effect into the documentation... I can't imagine any other use case which involves the get_order function which isn't affected by this

Cheers,
Bruce

You are correct that order info isn't updated for corporate actions. This is actually one of the reasons why all orders are 'Good-Till-Day' (GTD). If an order were allowed to span multiple days then it would need to be adjusted for corporate actions such as splits. As a rule of thumb, just like prices and volumes, don't save order values from day to day.

What I had suggested was not to save the percentage weight of a stock in a sub-portfolio. I'd suggest saving the percentage of each stock across the sub-portfolios. As an example, consider the case of three sub-portfolios and a single stock IBM, and a 'context.weights' dataframe. Let's also assume that all orders fill complete. Before, any positions are opened 'context.weights' will be empty.

Now, one orders 100 shares of IBM for portfolio1. The 'context.weights' dataframe would look like this

stock    port1    port2    port3  
IBM       1.0      0.0      0.0  

What this means is 100% of the shares of IBM are allocated to port1.

Now, on the following day, one orders 100 shares of IBM for port2. The 'context.weights' dataframe should be updated to look like this

stock    port1    port2    port3  
IBM       0.5      0.5      0.0  

There are now 200 shares total across all portfolios with 50% allocated to port1 and 50% port2.

Now, on the following days, one sells 50 shares of IBM from port1 and buys 50 shares for port 2. The 'context.weights' dataframe should be updated to look like this

stock    port1    port2    port3  
IBM       0.25     0.5      0.25 

This will track how the total shares of each security are allocated across each portfolio. It's not the percentage of weight within the portfolio. Before updating the dataframe, simply check the total shares held using 'context.portfolio.positions'. Use that share quantity to base the updated percentages on. The share quantity in 'context.portfolio.positions' is updated before trading each day to reflect any corporate actions. That will ensure the percentages are always correct. Note too, that the percentages for each row should always total 1.0.

This doesn't solve all the issues as mentioned above, but will track the current percent of shares to be allocated to each portfolio for each security.

Hi Dan,
thanks for this excellent reply.
Unfortunately I don't think it will work in my specific case. I need to keep each portfolio's $ separate. Each is initially seeded with the same amount of money, but the portfolio values will diverge over time as the simulation unfolds.
As an example of the problem this would cause, imagine in your example when I come to sell the percentage held by IBM in any given portfolio. A specific portfolio may hold 25% of the IBM stocks, but the actual return for the portfolio will depend on which 25% are sold... ie there will be repeated buys at different dates across each portfolio. If I sell the first 25% bought, the $ result would be very different to selling the last 25% bought.
Cheers,
Bruce