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

Please see the attached algorithm for an implementation of a Black-Litterman model for equity portfolio construction. Black-Litterman extends the classical mean-variance approach to portfolio construction by allowing the investor to specify views on the absolute or relative over-/under- performance of various assets in the universe.

Please see the following paper for more information:

http://bfi.cl/papers/He%20Litterman%201999%20-%20The%20intuition%20behind%20the%20Black-Litterman%20model%20portfolios.pdf

30 responses

Nice! Black-Litterman would make a decent platform to combine multiple trading systems into a single portfolio and risk management layer.

I was able to understand this explanation of Black-Litterman a bit easier.

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.

Okay super annoying, I can't copy and paste two articles into a single reply on the ipad, the text I write gets lost. Anyway, I implemented from Meucci's formulation and then added the Idzorek extension for specifying omega without getting caught up with tau, here: http://corporate.morningstar.com/ib/documents/MethodologyDocuments/IBBAssociates/BlackLitterman.pdf

It worked well, though prior to the Idzorek bootstrapped omega matrix, I was finding it very difficult to get the weight of the views to make sense.

http://mikespivey.wordpress.com/2012/07/20/tauidzorek/

And an interesting blog post about the relevance of tau in the Idzorek method.

Very cool algorithm. Thanks for posting.

I found a bug... right now you are computing daily_returns as follows:

daily_returns = np.zeros((len(context.securities),window))  
  # Compute daily returns  
  security_index = 0;  
  for security in context.securities:  
      if data.has_key(security):  
          for day in range(0,window):  
              day_of = all_prices[security][day]  
              day_before = all_prices[security][day-1]  
              daily_returns[security_index][day] = (day_of-day_before)/day_before  
          security_index = security_index + 1  

The bug happens when day = 0 and we try to get day_before = all_prices[security][day-1]. The day - 1 wraps around and pulls out the data item at the very end of the all_prices window. I would suggest doing it this way:

all_prices = all_prices[context.securities]  
daily_returns = all_prices.pct_change().dropna().values.T  

The first line makes sure the columns of all_prices matches the order of the securities in context.securities. This may not be necessary, but I don't know the quantopian internals well enough to say. It would be easy enough to verify, but I haven't done it yet.

The second line produces an array that is (len(context.securities), window-1) because the first row is all NaN because we don't have a day_before to get data from. The transpose is so it matches the shape of the original daily_returns array (not sure if this is necessary, but I did it anyway).

You can verify that this gives the same array as before (except for the first, incorrect row), by doing np.allclose(original[:, 1:], new[:, 1;]), where original and new are the daily_returns arrays computed how they were and using my suggested method.

Spencer - thank you for the catch! I implemented the your suggestion to the code. See the new attached backtest for an updated version.

Went to a presentation by Richard Michaud, who was pretty hard on BL, tau and omega - of course, his firm markets a Monte-Carlo resampled efficient frontier. The allocations do look much more reasonable with his method though...

I only have one question for you: What time period are the market caps inside of context.market_cap from?

I hard-coded the market caps from the market caps on the day I built the model, which is early January of this year. While Quantopian does not currently support fundamental data (such as P/E ratio, market cap, etc.), there are plans to support fundamental data in the near future. The model I posted used a few simplifications for explanatory purposes, but a more robust model would certainly include a real-time updating of market capitalizations.

Please don't take this the wrong way, but do you see the inherent problem with that which makes the backtest completely useless? There's no way you could have known 2014 market caps in 2008 (i.e. lookahead bias). To keep things simple, I suggest simply changing your market caps to 2008 values.

I don't think this was an implementation for trading, just a demonstration of BL for the benefit of quantopian students. I assumed the little red [] by Ryan's name meant he works for the company to implement examples! Is this not the case? (whoops)

That said, extending the set_universe function or creating something else that seamlessly provides historical as-of index constituents and weights would help everyone from making this mistake over and over.

Hi, yes, Simon is right, I do work at Quantopian and the goal was to show a well-known and established method for portfolio selection (Black-Litterman) within the Quantopian platform. The demonstration is for educational purposes and is not intended to be implemented for trading (not yet, at least!). I will work on making the calculation of market caps more robust.

I added functionality to more accurately describe the market capitalizations at different points in time. I downloaded data from Quandl, which has yearly data on market caps (horribly coarse), to correct the look-ahead bias. An improvement to the algorithm that would be desirable in the future is daily market cap numbers (I have not yet found this available online).

Here is a more detailed illustration on how to import market cap data from Quandl.

@Ryan Could you describe how you overcame the look ahead bias as mentioned by @al t ?

Hey Adam, Black-Litterman uses relative market capitalizations of securities as a proxy for a "market portfolio" and then computes returns that are "implied" by the market portfolio. The first algorithm hard-coded the current market caps for the duration of the algorithm (back to 2008). This demonstrates look-ahead bias because the algorithm is acting on information from a future time (i.e. 2014 market caps in 2008). In the most recent iteration of the algorithm, the market caps are updated every year. For every trading day in 2008, the algorithm uses market caps from January 1, 2008 (for 2009, from Jan 1, 2009, etc.). This corrects the look-ahead bias but may suffer from outdated information as the market caps will change over the course of the year.

Latest iteration of Black-Litterman with more robust importing of market cap data. Please note the use of the functools Python library to add a column of tickers to a Quandl .csv file.

@Ryan Could you rebalance say every quarter based on market cap to alleviate the issue of outdated info during the year? This is more of a general question.

Hey Adam, you can change the rebalancing dates by changing refresh_rate in the algo. I'm not sure this would alleviate the problem, as you would be making investment decisions based on the same market cap information, just rebalancing less often. The best solution would be to supply more granular market cap data.

I am just starting to use Quantopian and have been exploring the algorithms others have built. It is great to see someone building something like the B-L model. If I can add my two cents' worth on why this model may be useful. It is mainly useful for someone running a strategy that enhances the benchmark. This is primarily because you are setting up to deviate from benchmark weightings. Also, another cool thing I have found with B-L is to base your views on some quantitative process. For example, rather than having a fixed relative performance and conviction, you could trade on analyst recommendations by trying to first estimate how a buy recommendation is expected to outperform a sell recommendation. (Not saying this is necessarily profitable, just for illustration.) This may work for more than one factor as well. Anyway, thanks for coding this and I hope to get some use out of it.

Hey Joel - I'm glad you have found the Black-Litterman model useful thus far! Please feel free to give suggestions on additional features, etc. you would like to see implemented in the model.

Please see the attached improvement of the Black-Litterman model. The algorithm now imports yield data from US Treasuries as a proxy for the risk free rate at different times, rather than hard-coding the risk-free rate for the duration of the simulation.

I am sorry , could someone help change the algorithm let could backtest on minute time frame.

Hey Ting-Jung,

Try running the algorithm given in the backtest below. It worked for me in minute mode. It looked like the Quandl links to market capitalization data were broken.

Ryan

Hey Ryan,

Do you plan on updating this model now that pipeline allows for custom market cap filters? It wouldn't be hard to import that data from morningstar using morningstar.valuation.market_cap.

Also correct me if I'm wrong but it looks like line 199 of your latest version would error if both new_position and current_position are negative. I don't see that it limits the weights to positive values so I assume there would be a problem if the model was adjusting a short position.

Thanks for the model by the way. Very interesting.

Luther

Hi Ryan
Thanks for your program,after I run your program I found some question about the '@batch_transform'. Could you help me to explain the meaning of program sentence "batch_transform(refresh_period=refresh_rate, window_length=window) "?

can you explain about context