Stock Portfolio Optimization using Efficient Frontier

Stock portfolios are a collection of investments, typically stocks, bonds, and other assets, owned by an individual or an entity. The goal of a stock portfolio is to generate returns while minimizing risks.

Portfolio Optimization is the process of selecting the best combination of assets to invest in, given a specific set of investment objectives and constraints. The objective of portfolio optimization is to achieve the highest possible returns with the lowest possible risk.

Portfolio optimization is essential because it helps investors to minimize the risk of losses, maximize the return on investment, and achieve a balance between risk and return.

In this article, we will explore how to optimize stock portfolios using Efficient Frontier. We will explain the concept of stock portfolios, their benefits, and the importance of portfolio optimization. We will also delve into the theoretical aspects of Efficient Frontier, and the role it plays in portfolio optimization. Finally, we will discuss the limitations and challenges associated with portfolio optimization using Efficient Frontier. The article concludes with an implementation of the optimization using Python.

Stock Portfolios

A stock portfolio refers to a collection of securities owned by an individual or an entity, including stocks, bonds, and other financial assets. The goal of investing in a stock portfolio is to diversify risk and maximize returns.

Stock portfolios have been around for centuries. The Dutch East India Company issued the first recorded shares of stock in 1602, marking the beginning of the modern stock market. Since then, stock portfolios have become a popular way for individuals and institutions to invest in the stock market.

Investing in stock portfolios offers several benefits, including:

  • Diversification: Investing in a portfolio of stocks reduces risk by spreading out investments across different sectors and asset classes.
  • Higher returns: Stock portfolios have the potential for higher returns than individual stocks, as a diversified portfolio can capture returns from different sectors and asset classes.
  • Professional management: Many stock portfolios are managed by professional fund managers, who use their expertise to select stocks and create diversified portfolios.
  • Access to different asset classes: Investing in a stock portfolio allows investors to gain exposure to different asset classes, such as domestic and international stocks, bonds, and commodities.

There are several types of stock portfolios, including:

  • Diversified portfolio: A portfolio that includes stocks from different sectors and asset classes.
  • Sector-specific portfolio: A portfolio that focuses on stocks from a particular industry or sector, such as technology or healthcare.
  • Index-based portfolio: A portfolio that tracks a particular stock market index, such as the S&P 500 or the Dow Jones Industrial Average.
  • Active portfolio: A portfolio that is actively managed by a fund manager, who selects stocks based on market research and analysis.

Understanding the definition, benefits, and types of stock portfolios is essential for investors looking to optimize their portfolios. Diversifying investments and maximizing returns while minimizing risks are key goals in portfolio optimization. 

Portfolio Optimization Using Efficient Frontier

The stock market can be volatile, and investors can experience significant gains or losses. Portfolio optimization is essential because it helps investors minimize the risk of losses and maximize the return on investment. Optimization allows investors to strike a balance between risk and return, which is critical to long-term investment success.

Efficient Frontier is a concept in finance that represents the set of optimal portfolios that offer the highest expected return for a given level of risk. It is a graphical representation of the relationship between risk and expected returns for a portfolio of securities.

The Efficient Frontier concept was introduced by Harry Markowitz in 1952. Markowitz‘s Modern Portfolio Theory (MPT) is based on the idea of diversification and optimal portfolio construction. He argued that investors can reduce their risk by creating a portfolio of assets with a low correlation of returns.

Efficient Frontier is widely used in portfolio optimization to construct portfolios that offer the highest expected returns for a given level of risk. It is also used in risk management, asset allocation, and portfolio performance evaluation. 

Portfolio optimization using Efficient Frontier involves the following steps:

  • Identify the universe of assets to be included in the portfolio.
  • Estimate the expected returns and volatility.
  • Determine the correlation matrix between assets.
  • Construct a set of efficient portfolios using different combinations of assets.
  • Identify the optimal portfolio that offers the highest expected return for a given level of risk.
  • Rebalance the portfolio periodically to maintain the optimal risk-return trade-off.

Efficient Frontier is a critical tool in portfolio optimization, enabling investors to construct portfolios that offer the best risk-return trade-off. By understanding the concept of Efficient Frontier, investors can create diversified portfolios that maximize returns while minimizing risks.

Challenges in Portfolio Optimization Using Efficient Frontier

While Efficient Frontier is a useful tool in portfolio optimization, it has some limitations. For example, Efficient Frontier assumes that historical returns and volatilities are good predictors of future returns and volatilities. However, this assumption may not always hold true, as market conditions can change unpredictably. Efficient Frontier also assumes that investors are risk-averse and prefer portfolios with lower risk, which may not be true for all investors.

Selecting optimal portfolios using Efficient Frontier can be challenging. Investors need to consider various factors, such as risk tolerance, investment goals, and time horizon, to select the optimal portfolio that meets their needs. The process can also be time-consuming and requires extensive market research and analysis.

To overcome the limitations and challenges of Efficient Frontier, investors can consider the following solutions:

  • Regularly update the portfolio: Investors should regularly update their portfolio to reflect changes in market conditions and adjust their portfolio’s risk-return trade-off.
  • Incorporate alternative data: Investors can incorporate alternative data, such as social media sentiment, into their analysis to better predict future market trends.
  • Use multiple optimization techniques: Investors can use multiple optimization techniques, such as Monte Carlo simulations or Black-Litterman models, to create more robust portfolios.
  • Work with a professional: Investors can work with a professional financial advisor or fund manager, who can provide expert guidance and help them navigate the complexities of portfolio optimization.

Implementation of Efficient Frontier Optimization

This section will cover the implementation of Efficient Frontier Optimization using Python. It’s important to note that the code provided is intended solely for educational purposes, and it aims to illustrate how to optimize a random portfolio.

To begin, let’s import the necessary libraries needed to construct the portfolio:

import numpy as np
import pandas as pd
import yfinance as yf

Next, we will select the stocks to be included in our portfolio. For this particular example, we will be using five well-known US stocks: Meta, Amazon, Apple, Netflix, and Google. Each of these stocks will be assigned a weight.

tickers = [‘META’,‘AMZN’,‘AAPL’,‘NFLX’,‘GOOG’]
tickers_share = np.array([0.2,0.2,0.2,0.2,0.2])

Initially, we are dividing the investing money equally between the stocks. We are investing 20 percent of our money in each stock. These values may differ while optimizing the portfolio later in the code.

Next, we will download the historical data of the stocks to utilize in our optimization process.

Typically, when optimizing a portfolio, we use the “Adjusted Close price” of the stocks over the last few years. For this example, we will be working with static data and therefore we will use the historical data of the stocks between the years 2015 and 2022.

It is worth noting that “Adjusted Close price” is commonly used in portfolio optimization instead of “Close Price” because it takes into account corporate actions such as stock splits, dividends, and other events that affect the value of the underlying asset.

dataa = []
starting_date = ‘2015-01-01’
ending_date = ‘2022-01-01’
for i in tickers:
adj = yf.download(tickers=i, start=starting_date, end=ending_date, interval=“1d”)
adj = adj.rename(columns={‘Adj Close’: i})
adj=adj[i]
dataa.append(adj)
data = pd.concat([dataa[0], dataa[1], dataa[2], dataa[3], dataa[4]], axis=1, join=‘outer’)
print(data.head())

                META     AMZN       AAPL       NFLX       GOOG

Date                                                           

2015-01-02  78.449997  15.4260  24.565695  49.848572  26.168653

2015-01-05  77.190002  15.1095  23.873644  47.311428  25.623152

2015-01-06  76.150002  14.7645  23.875887  46.501431  25.029282

2015-01-07  76.150002  14.9210  24.210682  46.742859  24.986401

2015-01-08  78.180000  15.0230  25.140911  47.779999  25.065184

The adjusted close price of the stocks between the years 2015 and 2022 is now stored in a dataframe named “data”.

data.info()

<class ‘pandas.core.frame.DataFrame’>

DatetimeIndex: 1763 entries, 2015-01-02 to 2021-12-31

Data columns (total 5 columns):

 #   Column  Non-Null Count  Dtype  

—  ——  ————–  —–  

 0   META    1763 non-null   float64

 1   AMZN    1763 non-null   float64

 2   AAPL    1763 non-null   float64

 3   NFLX    1763 non-null   float64

 4   GOOG    1763 non-null   float64

dtypes: float64(5)

memory usage: 82.6 KB

Displaying the dataframe’s information. We have 1763 rows with no null values.

Now, we calculate the daily percentage change for each stock in a portfolio:

daily = data.pct_change()
print(daily.tail())

              META      AMZN      AAPL      NFLX      GOOG

Date                                                        

2021-12-27  0.032633 -0.008178  0.022975 -0.001580  0.006263

2021-12-28  0.000116  0.005844 -0.005767 -0.003931 -0.010914

2021-12-29 -0.009474 -0.008555  0.000502 -0.000278  0.000386

2021-12-30  0.004141 -0.003289 -0.006578  0.002539 -0.003427

2021-12-31 -0.023260 -0.011429 -0.003535 -0.015766 -0.009061

The “pct_change()” function is a pandas function that calculates the percentage change between the current and a prior element in a DataFrame. Each element in “daily” is the percentage change between the corresponding element in “data” and the element before it.

By calculating the daily percentage change, we can better understand the volatility and performance of each stock in the portfolio.

Continuing, we calculate the annualized covariance matrix:

annualized = daily.cov()*252 #252 is the number of trading days in a year, in average
print(annualized)

        META      AMZN      AAPL      NFLX      GOOG

META  0.099412  0.056018  0.051893  0.057043  0.054892

AMZN  0.056018  0.090622  0.048638  0.064303  0.051237

AAPL  0.051893  0.048638  0.084223  0.049051  0.046089

NFLX  0.057043  0.064303  0.049051  0.169120  0.051616

GOOG  0.054892  0.051237  0.046089  0.051616  0.070176

The “cov()” function is a pandas function that calculates the covariance between columns in a DataFrame. In this case, the function is applied to the “daily” DataFrame to calculate the covariance between each pair of stocks in the portfolio.

Multiplying the result of the “cov()” function by 252, which is the number of trading days in a year, annualizes the covariance matrix. This is because the daily covariance values are based on daily returns. By annualizing the covariance matrix, we can better compare the risk and return of their portfolio to other investment opportunities that are based on annual returns.

Now, we will calculate both the variance, the volatility, and the annual return of the portfolio:

var = np.dot(tickers_share.T, np.dot(annualized, tickers_share))
var

0.06300444359133407

vol = np.sqrt(var)
vol

0.2510068596499587

annual_return = np.sum(daily.mean()*tickers_share)*252
annual_return

0.33753146537326517

We have found that:
Expected Annual Return = 34%
Annual Volatility = 25%
Annual Variance = 6%

These are the portfolio’s parameters before optimizing it. We now will apply Efficient Frontier on the portfolio aiming for less volatility and higher expected annual return.

To use apply Efficient Frontier, we will use “pypfopt” library.

from pypfopt.efficient_frontier import EfficientFrontier
from pypfopt import risk_models
from pypfopt import expected_returns

Now, we will perform portfolio optimization using the Maximum Sharpe Ratio objective function. By maximizing the Sharpe ratio, the optimized portfolio seeks to balance risk and return to achieve the highest possible risk-adjusted return.

The maximum Sharpe ratio objective function is a method used in portfolio optimization to find the optimal weights for a portfolio that balances risk and return to achieve the highest possible risk-adjusted return. The objective function maximizes the Sharpe ratio by finding the portfolio weights that produce the highest expected return for a given level of risk or the lowest risk for a given level of expected return. The result is a set of portfolio weights that balances risk and return in a way that is optimal for the investor’s specific goals and constraints.

mean = expected_returns.mean_historical_return(data)
risk = risk_models.sample_cov(data)

ef = EfficientFrontier(mean, risk)
weights = ef.max_sharpe()
cleaned_weights = ef.clean_weights()
print(cleaned_weights)
ef.portfolio_performance(verbose = True)

OrderedDict([(‘META’, 0.0), (‘AMZN’, 0.54137), (‘AAPL’, 0.28227), (‘NFLX’, 0.17636), (‘GOOG’, 0.0)])

Expected annual return: 38.7%

Annual volatility: 26.6%

Sharpe Ratio: 1.38

(0.38696227617970946, 0.265626783483469, 1.381495763971207)

This block of code performs portfolio optimization using the maximum Sharpe ratio objective function. Here’s what each line does:

  • The “mean” variable calculates the mean historical return for each stock in the portfolio using the “mean_historical_return” function from the “expected_returns” module.
  • The “risk” variable calculates the sample covariance matrix for the stocks in the portfolio using the “sample_cov” function from the “risk_models” module.
  • The “ef” variable creates an instance of the “EfficientFrontier” class, which represents the efficient frontier of the portfolio. The mean and risk variables are passed to the constructor to initialize the efficient frontier object.
  • The “weights” variable uses the “max_sharpe” method of the ef object to calculate the weights for the portfolio that maximize the Sharpe ratio.
  • The “cleaned_weights” variable is a dictionary that contains the cleaned weights for the portfolio, which are the weights rounded to 6 decimal places and with any near-zero weights removed.
  • The “ef.portfolio_performance(verbose=True)” method prints out the portfolio performance metrics, including the expected return, volatility, Sharpe ratio, and other measures. This method takes an optional “verbose” parameter, which controls whether additional performance metrics are printed.

After applying the optimization, the algorithm found that we have to ignore the Meta and Google stocks. Instead, our money will be divided in the following way:
Amazon: 54.1% of our money.
Apple: 28.2% of our money.
Netflix: 17.6% of our money.

Following this partition, the new parameters of the portfolio are:
Expected Annual Return = 38.7%
Annual Volatility = 26.6%

Although the new volatility (risk) of the portfolio is 1.6% more than the risk before, the expected return is up 4.7%.

Now, we will give an example of investing 10.000 USD in this portfolio, and check out how many stocks of each company we can buy:

from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices

latest_prices = get_latest_prices(data)
weights = cleaned_weights
da =  DiscreteAllocation(weights, latest_prices,  total_portfolio_value=10000)
allocation, leftover = da.lp_portfolio()
print(“Discrete Allocation: “,allocation)
print(“Funds remaining: ${:.2f}”.format(leftover))

Discrete Allocation:  {‘AMZN’: 32, ‘AAPL’: 16, ‘NFLX’: 3}

Funds remaining: $37.32

By investing 10.000 USD in the portfolio, we buy 32 Amazon stocks, 16 Apple stocks, and 3 Netflix stocks. These stocks combined cost 9963 USD, so there will be 37 USD leftover.

Final Words

In summary, stock portfolio optimization using the Efficient Frontier is an essential tool for investors looking to balance risk and return and achieve the highest possible risk-adjusted return.

By diversifying across assets and optimizing for the maximum Sharpe ratio, investors can build a portfolio that is customized to their specific goals and constraints while minimizing risk.

In this article, we provided an overview of stock portfolios and their benefits, explained the concept of Efficient Frontier, and walked through the steps involved in portfolio optimization using Efficient Frontier. We also highlighted some of the challenges involved in the optimization process and possible solutions to overcome them.

Key takeaways from this article include the importance of diversification in portfolio construction, the significance of the Efficient Frontier in portfolio optimization, and the need for careful consideration of risk and return in portfolio design.

Similar Posts