Back to Community
The efficient frontier: Markowitz portfolio optimization using cvxopt (repost; cloning of NB now enabled)

Resharing this post (original here: so that cloning is enabled.

In this post you will learn about the basic idea behind Markowitz portfolio optimization as well as how to do it in Python. We will then show how you can create a simple backtest that rebalances its portfolio in a Markowitz-optimal way. We hope you enjoy it and get a little more enlightened in the process.

Full blog post:

Loading notebook preview...
Notebook previews are currently unavailable.

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.

17 responses


I wonder whether it is possible to cap the weight of a single security within a portfolio, so as not to get portfolios that give almost 100% of the weight to 1 security.

daniel: Yes, that's quite simple to do in cvxpy. Unfortunatley the code still uses cvxopt where this is more difficult, but it shouldn't be too hard to port it (see

Many thanks for the quick reply, Thomas! One more question: Is there any reason that the mean returns are used for the frontier?

It would seem that it would be more accurate to use the following formula:
(Pt/P0)**(1/n) -1 Pt - price at the last date of the time series
P0 - price at the beginning of the time series
n - number of periods

a return series of (10%, -10%, 10%, -10%, 10%, -10%...) would have a mean of 0, but the actual return would be negative.

daniel: I see what you're getting at, but here we care about the expected future return, not historic return. As such, the mean is attempting to estimate that.

Thank you Thomas, it really helped.

I have a couple of points I do not understand:

1) when you compute your portfolio weights parametrically for different mu in mus:
portfolios = [solvers.qp(mu*S, -pbar, G, h, A, b)['x'] for mu in mus] why you use the multiplication mu*S to enforce the condition (using your notation) pbar.T * x == mu ? how does it works?
There is a related question on SO. Some linear algebra trick I'm not seeing now probably here.

Alternatively, would it be equivalent to extend the equality constraint Ax=b to include the mu? Something like here:
A0 = matrix(1.0,(1,n)) A = matrix([A0,ret_mean.T]), b0 = matrix(1.0) b = matrix([b0,matrix(mu)])

2) What sort of return x1 = np.sqrt(m1[2] / m1[0]) is?

Thank you in advance.

Hi Gab,

Please let me answer question 1) first: S is the covariance matrix and mus is simply a non-linear multiplier:

mus = [10**(5.0 * t/N - 1.0) for t in range(N)]

that produces a more even set of points along the efficient frontier. Using linspace, for example, would produce a much more uneven point distribution.

I will answer (2) shortly.


Thank you Tom for the reply. Actually, I do understand what mu in mus represent, that is unevenly spaced portfolio returns levels. What I do not understand is how these enter in the optimization and, specifically, why the optimization problem of "minimum variance given portfolio return == mu" is enforced through mu*S.

Thanks in advance if you want to add also on this.


Hi Gab,

Here's the answer to your second question:

x1 is the multiplier of the covariance matrix for which the portfolio is optimal. For this we calculate the 2nd degree polynomial of the Markowitz bullet and then figure out where the tangent from zero touches the efficient frontier. This is our portfolio with the highest Sharpe ratio. For more information on this please refer to Ernie Chan's blog, who provides an excellent overview of this:

Hi Gab,

As mentioned in the previous post, please have a thorough read of Ernie's blog post on this. The notebook follows this methodology. I hope reading this, will make things much clearer to you.

Hi Gab,

Hope the Ernie blog has helped a bit.

Finally, here is the reference to the first question you've asked. Please have a look at this book:

At page 185-186 you will find a thorough derivation of this expression. The book can be downloaded for free.

Hope that helps.


Thanks Tom Starke and Gabriele - that's very helpful.

You are welcome. This post is quite old so it took me a while to dig out the references. Glad it's helpful.

Hi Tom,

thank you very much, that is exactly what I was looking for!

Correct me if I'm wrong, I would like a very last clarification.

For what I understand also from Boyde and Vandemberghe book's reparametrization of the problem: when you run

portfolios = [solvers.qp(mu*S, -pbar, G, h, A, b)['x']  
                  for mu in mus]  

to get the portfolios on the efficient frontier (that is, the yellow (risks, returns) pairs in the plot), the parameter mu that you make unevenly running in mus seems therefore to be:

  • the tradeoff parameter between the return maximization and the variance minimization objectives ,
  • and not the target mean of the portfolio's returns 𝑅^𝑇𝑀=πœ‡ (as it is seems to be suggested by the introduction above optimal_portfolio function definition).

That is, the loop mu in mus spans the efficient frontier:

  • not by minimizing portfolio's variance given different target portfolio's returns mu;
  • but by running the scalarized minimization of Boyde-Vandenberghe: - 𝑅^𝑇𝑀 + πœ‡ 𝑀^𝑇𝐢𝑀 for different values of the trade-off parameter πœ‡ (mu), which correspond to the range:
    -- from a quasi-maximum mean return portfolio (mus[0] = 0.1)
    -- to a quasi-minimum variance return portfolio (mus[-1] = 8912.51).

Am I right? If so, maybe also other people could have been misleaded by this inconsistency between the introduction above optimal_portfolio function and what the function actually does (and I totally understand that these are things that can happen!). And maybe a reformulation of the introduction might be appropriate. If not, please don't hate me and spend a few more words when you have time to clarify further ;-)

Thank you very much,

You are exactly right, Gab. Sorry, for my short answers, I am in India right now running workshops for Quantopian and it keeps me extremely busy. I agree, the choice of mu was not ideal, when I was engrossed in it I just did not see the ambiguity. It it easy to fix and I will do it when I get some time.

Thanks for your persistence.

Thank you very much Tom. Now everything is clear to me.
Good luck for the workshops!


Hi Gab,

Can you share the fixed notebook for us? Will be very helpful for us.


Note that Q now supports CVXPY, which is easier to use than CVXOPT.

One thing that would be interesting is an example of how to apply mean variance optimization of alpha factors in an algo. The Q former CIO, Jonathan Larkin, alludes to it on in his discussion of Alpha Combination:

For increased complexity, classic portfolio theory can help you; for example, try solving for the weights such that the final combined alpha has the lowest possible variance.