# Portfolio Efficient Frontier in Python

Introduction

Investors often aim at maximizing returns on investment for a given level of risk. This can be achieved by selecting a number of assets in which to invest in so as to minimize the risk and at the same time maximize the returns on investment. An efficient frontier represents a set of optimal portfolios that offer the highest expected returns for a defined level of risk (__https://www.investopedia.com/terms/e/efficientfrontier.asp__).

In this tutorial, we will demonstrate how to construct an efficient portfolio of a two-asset portfolio based on the different weight combinations of the assets. The assets we will use for this demonstration are two S&P 500 Exchange Traded Funds (ETFs) of XLE and XLI. . We then proceed to select a suitable portfolio combination on the efficient frontier based on the risk tolerance and the required expected returns.

**Import Required Packages**

```
import numpy as np
import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt
```

**Load the Data**

We will use the daily closing prices for the two assets for a one year period from 27 November, 2017 to 26 November, 2018 . The data is downloaded from Yahoo Finance and loaded into a Data frame.

```
#specifying the assets
tickers = ['XLE','XLI']
#specifying the start and end dates
start = "2017-11-27"
end = "2018-11-27"
#downloading price data for the assets
data = pd.DataFrame()
for ticker in tickers:
data[ticker] = yf.download(ticker, start, end)['Close']
```

**Plot of the Daily Close Prices**

```
plt.figure(figsize=(8,5))
plt.plot(data.index, data['XLE'], label='XLE Close')
plt.plot(data.index, data['XLI'], label='XLI Close')
plt.title('Plot of Close Prices', fontsize=16)
plt.xlabel('Date', fontsize=12)
plt.ylabel('Close Prices', fontsize=12)
plt.legend()
plt.show()
```

## Calculate the Daily Log Returns

The portfolio of the two assets is constructed using the daily returns of each of the assets. We calculate the daily returns of each of the assets using the daily log returns.

```
#create empty Data Frame for returns
returns = pd.DataFrame()
#calculate daily log returns
for ticker in tickers:
returns[ticker] =
np.log(data[ticker]/data[ticker].shift(1))
#drop rows with NaN
returns = returns.dropna()
returns.head()
```

## Daily and Annualized Standard Deviation of Returns

In constructing the portfolio, we will use the annualized standard deviations of each asset returns.

```
#daily standard deviations
daily_std = returns.std()
daily_std
```

```
#annualized standard deviations
annualized_std = daily_std * np.sqrt(252)
annualized_std
```

## Correlation of Returns

We get the correlation of the two asset returns

```
ret_corr = returns[['XLE', 'XLI']].corr()
ret_corr
```

```
corr_value = np.round(ret_corr['XLE'][1],3)
print('The Correlation between the two assets is:', corr_value)
```

The Correlation between the two assets is: 0.66

## Construction of an Efficient Frontier

We construct an efficient frontier of portfolio based on the different weight combinations of the two ETFs. Using these weight combinations, we calculate the portfolio expected returns and volatility for each.

The portfolio expected return is given by the sum of the weighted individual ETF’s returns.

The Portfolio Volatility is computed using the formula for the Two-Asset Portfolio Volatility as shown below:

**Portfolio Weights**

We define the weights for the various portfolio combinations.

```
# define weights for the two ETFs
w1=np.linspace(0,1,11)
w2=np.linspace(1,0,11)
#construct a dataframe of weights
weights_df = pd.DataFrame()
weights_df['XLE Weight'] = w1
weights_df['XLI Weight'] = w2
weights_df
```

### Portfolio Returns and Volatilities

*#volatilities*
xle_vol **=** annualized_std[0]
xli_vol **=** annualized_std[1]
xle_vol, xli_vol

`(0.20335309806894042, 0.1710067876397469)`

*#correlation*
cor**=**corr_value
cor

`0.66`

### Expected Returns using Capital Asset Pricing Model (CAPM)

The Expected return for each asset using the CAPM is calculated as follows:

Where:

*# Define Variables*
beta_xle **=** 1.07 *#Beta Value **of** **XLE*
beta_xli **=** 1.06 *#Beta Value **of** **XLI*
risk_free_rate **=** 0.0225 *# Risk Free Rate*
market_return **=** 0.09 *#Market Return*
market_std **=** 0.15 *#Market Standard Deviation*

*# Expected Return **of** **XLE*
ret_xle **=** risk_free_rate **+** beta_xle ***** (market_return **-** risk_free_rate)
*# Expected Return **of** XLI*ret_xli **=** risk_free_rate **+** beta_xli ***** (market_return **-** risk_free_rate)

`xle_ret`**=**ret_xle
xli_ret**=**ret_xli
xle_ret, xli_ret

`(0.094725, 0.09405)`

*#Compute Returns and Volatility **for** each combination*
portfolio **=** weights_df**.**copy()
*#portfolio Returns*
portfolio['Portfolio Returns'] **=** ((portfolio['XLE Weight']*****xle_ret) **+** (portfolio['XLI Weight']*****xli_ret))
*#portfolio volatility*
portfolio['Volatility'] **=** np**.**sqrt(((portfolio['XLE Weight'])******2 ***** xle_vol******2) **+**((portfolio['XLI Weight'])******2 ***** xli_vol******2) **+**(2 ***** (portfolio['XLE Weight']) ***** xle_vol *****(portfolio['XLI Weight']) ***** xli_vol) ***** cor)
portfolio

## Portfolio Efficient Frontier

From the above table, we construct the Efficient Frontier for each portfolio weights combination. The figure below shows the scatter plot for the constructed Efficient Frontier of the portfolios

*## Plot **of** the Portfolio Efficient Frontier*
plt**.**figure(figsize**=** (8,6))
plt**.**title('Portfolio Efficient Frontier', fontsize**=**16)
plt**.**scatter(portfolio['Volatility'],portfolio['Portfolio Returns'],color**=**'r', alpha**=**0.6)
plt**.**xlabel('Portfolio Volatility', fontsize**=**12)
plt**.**ylabel('Portfolio Returns', fontsize**=**12)
plt**.**show()

## Selecting a Portfolio with Defined Constraints

From the constructed Efficient Frontier above, we choose our portfolio with the following constraints:

The Return greater than 9.43% and

The Volatility not exceeding 16.8%. We achieve this by constructing the threshold lines for returns and volatility on our Efficient Frontier plot as shown below:

*#Define the Portfolio Constraints*
Vol_threshold **=** 0.168
return_threshold **=** 0.0943
n **=** len(portfolio)

*# Data ponts*
points **=** []
**for** i, j **in** zip(portfolio['Volatility'], portfolio['Portfolio Returns']):
points**.**append((i,j))
*# Portfolio Weights**,** **(**xle**,** xli**)*
w **=** []
**for** i, j **in** zip(portfolio['XLE Weight'], portfolio['XLI Weight']):
w**.**append((np**.**round(i,1), np**.**round(j,1)))

*#Plot **of** the Portfolio Efficient Frontier **with** the Constraints*
plt**.**figure(figsize**=** (8,6))
plt**.**title('Portfolio Efficient Frontier', fontsize**=**16)
plt**.**plot(portfolio['Volatility'], portfolio['Portfolio Returns'],'-or',alpha**=**0.6, label**=**'Efficient Frontier')
plt**.**plot(n ***** [Vol_threshold], portfolio['Portfolio Returns'],label **=** 'Volatility Threshold')
plt**.**plot(np**.**linspace(0.165,0.205,11), n ***** [return_threshold],label **=** 'Returns Threshold')
**for** i, j **in** zip(points, w):
plt**.**text(i[0],i[1],j)
plt**.**legend()
plt**.**show()

From the plot above, we want to pick a portfolio with returns greater than 9.43% which lies above the Returns Threshold Line. The portfolio should also have a Volatility not exceeding 16.8% meaning it should lie on the Volatility Threshold line or to the left side of it. We can see from the plot that the only combination which satisfies the above constraints is the portfolio with 40% XLE and 60% XLI.

Github Link

The Notebook for this tutorial can be found on the following Github Link:

__https://github.com/Musonda2day/Portfolio-Efficient-Frontier-.git__