Investing: Minimum Variance Portfolio and the Efficient Frontiers

How should you invest your wealth? This simple question does not have a simple answer. In 1952, Harry Markowitz introduced the Modern Portfolio Theory (MPT) as the answer to this question.

The MPT is a mathematical framework for estimating the maximum expected return of a portfolio of assets for a given level of risk. If we have two assets - A and B - the return of the portfolio is mathematically represented as:

While the risk - or variance - of the portfolio is given by:

The weights wa, wb are the percentage of wealth that one would invest in both asset classes. And their sum is:

wa + wb = 1

The weight of an asset can be a negative number. For example, when an investor shorts a stock. However, we are only interested in the long position for this article.

The mathematical equations get more cumbersome when there are more than two stocks in the portfolio. This article will describe how to create a minimum variance portfolio when there are two stocks in the portfolio and when there are more than two stocks in the portfolio.

Two Assets Portfolio

    import yfinance as yf
    import pandas as pd

    # Investigating Two Assets: TSLA and Bitcoin
    TSLA ="TSLA", "2020-01-02", "2021-01-01")
    BTC ="BTC-USD", "2020-01-02", "2021-01-01")

    # Cryptocurrencies are traded 24/7 and more than 360 days in a year
    # On the other hand, stock are traded about 250 days in a year
    # We therefore need to adjust the length of the dataframes

    dfBTC = BTC[BTC.index.isin(TSLA.index)]
    dfTSLA = TSLA[TSLA.index.isin(dfBTC.index)]

    # Concatenate both dataframes, take the Adjusted Close price and
    # rename the columns

    df = pd.concat([dfTSLA[['Adj Close']], dfBTC[['Adj Close']]], axis=1)
    df.columns = ['TSLA', 'BTC']

In the above block of code, we have imported Tesla and Bitcoin, and have selected their Adjusted closing prices. We will calculate return using the formula:

rt = InPtPt-1

    # Calculate the return of the stock and drop NA cells
    df = df.pct_change().dropna()

    # Get the Expected return (mean) and variance from both stocks
    summary = df.describe()

    ETSLA = summary.loc['mean', 'TSLA']
    EBTC = summary.loc['mean', 'BTC']

    stdTSLA = summary.loc['std', 'TSLA']
    varTSLA = stdTSLA**2
    stdBTC = summary.loc['std', 'BTC']
    varBTC = stdBTC**2

    # Get the covariance
    cov = df.cov().loc['TSLA', 'BTC']

We have all the parameters that we need aside from the weights. We will define the portfolio variance and portfolio return function according to the MPT and apply several combinations of weights in the following block of code.

    # Define the portfolio variance and portfolio return functions

    def portfolio_variance(w1):
        return w1**2 * varTSLA + (1-w1)**2 * varBTC + 2*w1*(1-w1)*cov

    def portfolio_return(w1):
        return w1 * ETSLA + (1 - w1) * EBTC

    # Generate weights for w1 which is the TSLA stock

    import numpy as np
    wTSLA = np.arange(0,1.1,0.1)

    # Put weights in dataframe
    dff = pd.DataFrame(wTSLA, columns=['w1'])

    # Calculate the portfolio returns and variance

    dff['PortfolioReturn'] = dff['w1'].apply(portfolio_return)
    dff['PortfolioVar'] = dff['w1'].apply(portfolio_variance)

    # Plot Efficient Frontiers

    import plotly.graph_objects as go

    fig = go.Figure(data=go.Scatter(x=dff['PortfolioVar'], y=dff['PortfolioReturn']))
    fig.update_layout(title='Efficient Frontiers for a Portfolio with Two Assets: BTC and TSLA',
    xaxis_title='Portfolio Variance',
    yaxis_title='Portfolio Expected Return')

Quite straightforward. We have been able to make an efficient frontier plot using two asset classes. But why is the above graph important? We can invest our wealth in either asset class in many different combinations. However, we want the combination that gives us the maximum return given our risk appetite. With the help of the efficient frontier plot, given the risk we are willing to take, we get the portfolio expected return and the weight combinations associated with the return - we interpolate if necessary.

Four Assets Portfolio

The idea behind estimating the Efficient Frontiers is the same but the mathematics becomes more involved when the number of assets are more than two. Usually, there are more than two assets in a portfolio. In this section, we will extend the MPT to estimate the risks and returns for a four assets portfolio.

    # Investigating the following assets: TSLA, AAPL, BITCOIN, ETHEREUM

    TSLA ="TSLA", "2020-01-02", "2021-01-01")
    BTC ="BTC-USD", "2020-01-02", "2021-01-01")
    AAPL ="AAPL", "2020-01-02", "2021-01-01")
    ETH ="ETH-USD", "2020-01-02", "2021-01-01")

    # Adjust length of the dataframes

    dfAAPL = AAPL[AAPL.index.isin(dfBTC.index)]
    dfETH = ETH[ETH.index.isin(dfBTC.index)]
    dfBTC = BTC[BTC.index.isin(TSLA.index)]
    dfTSLA = TSLA[TSLA.index.isin(dfBTC.index)]

    # Concatenate the dataframes, take the Adj Close Prices

    df = pd.concat([dfTSLA[['Adj Close']], dfAAPL[['Adj Close']], dfBTC[['Adj Close']], dfETH[['Adj Close']]], axis=1)
    df.columns = ['TSLA', 'AAPL', 'BTC', 'ETH']

    # Calculate the return
    df = df.pct_change().dropna()

    # Get descriptive statistics
    summary = df.describe()

    # Get the Expected return for each asset

    ETSLA = summary.loc['mean', 'TSLA']
    EAAPL = summary.loc['mean', 'AAPL']
    EBTC = summary.loc['mean', 'BTC']
    EETH = summary.loc['mean', 'ETH']

    # Get the assets variance and covariance
    dfCov = df.cov()
    varTSLA = dfCov.loc['TSLA', 'TSLA']
    varAAPL = dfCov.loc['AAPL', 'AAPL']
    varBTC = dfCov.loc['BTC', 'BTC']
    varETH = dfCov.loc['ETH', 'ETH']

    covTSLA_AAPL = dfCov.loc['TSLA', 'AAPL']
    covTSLA_BTC = dfCov.loc['TSLA', 'BTC']
    covTSLA_ETH = dfCov.loc['TSLA', 'ETH']

    covAAPL_BTC = dfCov.loc['AAPL', 'BTC']
    covAAPL_ETH = dfCov.loc['AAPL', 'ETH']

    covBTC_ETH = dfCov.loc['BTC','ETH']

We have gotten most of the parameters to calculate the portfolio’s estimated return and variance. We will now extend the portfolio expected return and portfolio variance functions that we used previously. In addition, we have to also generate weights for the four asset classes that sums to one. The itertools library will help us generate the weights.

    # Extended portfolio variance and portfolio return functions

    portfolio_return = lambda w: w[0] * ETSLA + w[1] * EAAPL + w[2] * EBTC + w[3] * EETH

    portfolio_variance = lambda w: w[0]**2 * varTSLA + w[1]**2 * varAAPL + w[2]**2 * varBTC + w[3]**2 * varETH + \
    2*w[0]*w[1]*covTSLA_AAPL + 2*w[0]*w[2]*covTSLA_BTC + 2*w[0]*w[3]*covTSLA_ETH + \
    2*w[1]*w[2]*covAAPL_BTC + 2*w[1]*w[3]*covAAPL_ETH + 2*w[2]*w[3]*covBTC_ETH

    # Generate weights w1, w2, w3, w4
    from itertools import product

    iterable = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]

    my_iter = product(iterable, iterable, iterable, iterable)

    weights = [(a, b, c, d) for a, b, c, d in my_iter if sum([a, b, c, d]) == 1]

    # Put weights in a dataframe
    dff = pd.DataFrame(weights, columns=['w1', 'w2', 'w3', 'w4'])

    # Calculate the Portfolio expected return and the variance

    returns = pd.Series(dff[['w1', 'w2', 'w3', 'w4']].values.tolist()).apply(portfolio_return)

    variances = pd.Series(dff[['w1', 'w2', 'w3', 'w4']].values.tolist()).apply(portfolio_variance)

    dff['PortfolioReturn'] = returns
    dff['PortfolioVar'] = variances

    # Plot the Efficient Frontier

    import as px
    fig = px.scatter(x=dff['PortfolioVar'], y=dff['PortfolioReturn'])
    fig.update_layout(title='Efficient Frontiers for a Portfolio with Four Assets: TSLA, AAPL, BTC, ETH',
    xaxis_title='Portfolio Variance',
    yaxis_title='Portfolio Expected Return')

Similarly, we can estimate the percentage of our assets that should be invested in each asset class given our risk appetite. Points below the efficient frontiers are suboptimal investments and positions above the efficient frontiers are impossible positions.


In this article, we looked at how we can invest our wealth to get the maximum possible returns. We discussed the Modern Portfolio Theory and showed how it helps us answer the question, “How should we invest our wealth?”, by estimating the maximum return for each risk profile. We showed how the MPT is applied to two asset classes and extended to a portfolio with more than two assets. And we concluded that investments below the efficient frontiers give suboptimal returns. One area we did not discuss is shorting of a stock. This analysis can be extended to investigate the efficient frontiers for stocks with one or more negative weight - shorting.