Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Position weights significantly different from target weights.

To compare the target weights of the algo with the real weights of the positions in the portfolio,
I used my old "All-weather trio", switched it to daily trading 5 minutes before close,
added record_vars on market close, and wrote a simple code similar to the one that Thomas Wiecki used
in recent challenges to find EOD portfolio positions.

def record_vars(context, data):  
    pos_wt = pd.Series()  
    for sec in context.portfolio.positions.values():  
        pos_wt.loc[sec.sid] = sec.amount  
    pos_wt /= pos_wt.abs().sum()  
    print("------- pos_wt --------")  
    print(pos_wt)  

You can see the results are significantly different.

2007-06-01 12:55 PRINT ------- target_wt --------
2007-06-01 12:55 PRINT {'QQQ': 0.5}
2007-06-01 12:55 PRINT {'TLT': 0.4}
2007-06-01 12:55 PRINT {'EFA': -0.1}

2007-06-01 12:59 PRINT ------- pos_wt --------
2007-06-01 12:59 PRINT
Equity(19920 [QQQ]) 0.641291
Equity(23921 [TLT]) 0.284409
Equity(22972 [EFA]) -0.074300

dtype: float64
2007-06-04 12:55 PRINT ------- target_wt --------
2007-06-04 12:55 PRINT {'QQQ': 0.5}
2007-06-04 12:55 PRINT {'TLT': 0.4}
2007-06-04 12:55 PRINT {'EFA': -0.1}

2007-06-04 12:59 PRINT ------- pos_wt --------
2007-06-04 12:59 PRINT
Equity(19920 [QQQ]) 0.641291
Equity(23921 [TLT]) 0.284409
Equity(22972 [EFA]) -0.074300

Please correct me if I am wrong, otherwise correct the error.

BTW I have not published this post yet and Algo has already been cloned 124 times, how can this be?

7 responses

It appears that 'amount' is the number of shares. If you multiply it by the price you get weights very close to the ones you ordered.
I added a limit to the order to make sure to get the current price which in turn can lead to orders not being (completely) filled.

2007-06-01 21:55 PRINT ------- target_wt --------
2007-06-01 21:55 PRINT {'QQQ': 0.5}
2007-06-01 21:55 PRINT {'TLT': 0.4}
2007-06-01 21:55 PRINT {'EFA': -0.1}
2007-06-01 21:59 PRINT ------- real_wt --------
2007-06-01 21:59 PRINT Equity(19920 [QQQ]) 0.834126
Equity(22972 [EFA]) -0.165874
dtype: float64
2007-06-01 22:00 WARN Your order for 467 shares of TLT failed to fill by the end of day and was canceled.
2007-06-04 21:55 PRINT ------- target_wt --------
2007-06-04 21:55 PRINT {'QQQ': 0.5}
2007-06-04 21:55 PRINT {'TLT': 0.4}
2007-06-04 21:55 PRINT {'EFA': -0.1}
2007-06-04 21:59 PRINT ------- real_wt --------
2007-06-04 21:59 PRINT Equity(19920 [QQQ]) 0.500586
Equity(23921 [TLT]) 0.399751
Equity(22972 [EFA]) -0.099663
dtype: float64
2007-06-05 21:55 PRINT ------- target_wt --------
2007-06-05 21:55 PRINT {'QQQ': 0.5}
2007-06-05 21:55 PRINT {'TLT': 0.4}
2007-06-05 21:55 PRINT {'EFA': -0.1}
2007-06-05 21:59 PRINT ------- real_wt --------
2007-06-05 21:59 PRINT Equity(19920 [QQQ]) 0.500664
Equity(23921 [TLT]) 0.399865
Equity(22972 [EFA]) -0.099471
dtype: float64
2007-06-06 21:55 PRINT ------- target_wt --------
2007-06-06 21:55 PRINT {'QQQ': 0.5}
2007-06-06 21:55 PRINT {'TLT': 0.4}
2007-06-06 21:55 PRINT {'EFA': -0.1}
2007-06-06 21:59 PRINT ------- real_wt --------
2007-06-06 21:59 PRINT Equity(19920 [QQQ]) 0.500182
Equity(23921 [TLT]) 0.400562
Equity(22972 [EFA]) -0.099257
dtype: float64

@Tentor Testivis,

Thanks a lot. You're right.

So the error came from the "Algorithm template" published March 16, 2020.

def record_positions(context, data):  
    pos = pd.Series()  
    for position in context.portfolio.positions.values():  
        pos.loc[position.sid] = position.amount  
    pos /= pos.abs().sum()  
    record(max_conc_perc=np.max(np.abs(pos)) * 100)  
    record(pos_count_div_100=len(pos) / 100)

Trust but verify.

Q,

Can you comment on this:

I have not published this post yet and Algo has already been cloned 124 times, how can this be?

@ Vladimir. Regarding the algo having already been cloned 124 times. That count is a little misleading. It's based on the algo ID and not the backtest ID. So, if that algo was already shared in another post, even though it was a different backtest, it will have the same count info. The count is the total clones, from all backtests having a common algo ID, shared in the forums.

I didn't check if that algo had been previously shared, but does that seem to be the case?

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,
Thank you for your prompt reply and explanation.
This algorithm has already been published in another post.

Please respond to this my request.

@Tentor Testivis,

Here is my solution of the problem:

    real_pos_wt = pd.Series()  
    for sec in context.portfolio.positions.values():  
        real_pos_wt.loc[sec.sid] = sec.amount*sec.last_sale_price  
    real_pos_wt /= real_pos_wt.abs().sum()  

Now you can print or record on daily basis real positions weights of the securities you rebalance monthly or quarterly.
Thanks a lot.
Problem solved.

There is actually a (not well documented) method of the portfolio object current_portfolio_weights which one can also use. See https://github.com/quantopian/zipline/blob/bf2be9afc1e536bd75afb4b0c6d11e797b52b834/zipline/protocol.py#L228

    portfolio_weights = context.portfolio.current_portfolio_weights():  

@Vladimir
You're welcome.

@Dan
Thanks, this can be very useful. One question though:
What purpose has the asset.price_multiplier in that function? For the positions I checked it's always 1, under what circumstances would it have a different value?
Edit: I think I found it - that's for future contracts, right?