This is an INDIVIDUAL workshop. In this workshop we review the basics of portfolio theory and portfolio optimization. We learn how to program estimations for portfolio return and risk, and portfolio optimization.
A portfolio is a set of 2 or more financial assets. A financial asset of any type such as stock, bond, risk-free instrument, derivative, commodity. The portfolio owner needs to decide how much money allocate to each individual asset. The main advantage of financial portfolios is the possibility to diversify risk, while maintaining an expected rate of return.
In this workshop we review practical easy examples of 2-asset and 3-asset portfolios with the purpose to illustrate portfolio theory and portfolio optimization.
It is recommended that you review the lecture notes posted in the course site where portfolio theory, matrix algebra, and portfolio optimization are explain in more detail.
Let’s start with an example of calculating historical returns of a 2-asset portfolio. Imagine that we want to calculate how much return you would have realized if you had invested in the following portfolio between January 2019 to December 2020:
Wal Mart: 70% Tesla: 30%
We start downloading historical monthly prices from Yahoo Finance:
library(quantmod)
## Loading required package: xts
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
## Loading required package: TTR
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
tickers = c("WMT","TSLA")
getSymbols(Symbols = tickers, periodicity="monthly",from="2018-01-01", to="2021-10-01")
## 'getSymbols' currently uses auto.assign=TRUE by default, but will
## use auto.assign=FALSE in 0.5-0. You will still be able to use
## 'loadSymbols' to automatically load data. getOption("getSymbols.env")
## and getOption("getSymbols.auto.assign") will still be checked for
## alternate defaults.
##
## This message is shown once per session and may be disabled by setting
## options("getSymbols.warning4.0"=FALSE). See ?getSymbols for details.
## [1] "WMT" "TSLA"
datasets_list <- lapply(tickers, get)
Now we merge all datasets using the function call. I do this to generalize our program for any number of tickers:
prices <- do.call(merge, datasets_list)
# We select only Adjusted prices:
prices <- Ad(prices)
# We change the name of the columns to be equal to the tickers vector:
names(prices) = tickers
We calculate holding period returns for both stocks. We can divide the price of each stock by its own price in the first month and then subtract 1:
firstprices = as.vector(prices[1,])
HPR = prices / firstprices - 1
As you can see, when R divides a dataset (or matrix) by a vector R divides each row of the dataset by the vector. We set the weight for each stock to form a portfolio:
w1 = 0.70
w2 = 0.30
The holding period return for each month of this portfolio would be the weighted average of the holding period stock returns:
\[PortfolioHPRt=0.7∗HPR1t+0.3∗HPR2t\] At the end of the first month the weights assigned to each stock will change depending on the return of each stock. For example, if stock 1 had a much higher return than stock 2, then the weight w1 will increase to more than 70% and weight w2 will be less than 30%.
We can calculate the holding portfolio return as follows:
HPR$Port = w1 * HPR$WMT + w2 * HPR$TSLA
The historical holding portfolio monthly return would look like:
plot(HPR$Port)
We can calculate how much $1 invested in our portfolio would have grew over time. We can use the HPR of the portfolio and add 1 to get a growth factor for each month:
HPR$invport = 1 * (1+HPR$Port)
plot(HPR$invport)
We can do the previous portfolio return calculations and the same plot using the PerformanceAnalytics package:
library(PerformanceAnalytics)
##
## Attaching package: 'PerformanceAnalytics'
## The following object is masked _by_ '.GlobalEnv':
##
## prices
## The following object is masked from 'package:graphics':
##
## legend
# I create a vector with the portfolio weights:
w = c(w1,w2)
# I create the monthly return for each stock:
R = prices / lag(prices,1) - 1
# I calculate the portfolio historical returns using the weight vector and the stock historical returns:
PR <- Return.portfolio(R,weights=w)
## Warning in Return.portfolio(R, weights = w): NA's detected: filling NA's with
## zeros
# The charts.PerformanceSummary function calculates and plots the $1.0 performance invested in the portfolio:
charts.PerformanceSummary(PR,
main = "Performance of $1.00 over time",
wealth.index = TRUE)
This plot shows the same portfolio performance than the previous one, but with this we can also see the monthly return and the drowdowns, which are the negative % declines over time.
The historical risk of a portfolio can be measured with the standard deviation of the portfolio historical period returns. Another important measure for portfolio risk is Value at Risk, but we will not cover that measure in this workshop.
I recommend to use the continuously compounded (cc) returns to calculate the standard deviation of returns. The main reason is that cc returns behave more like a normal distribution, and also because cc returns are more conservative measure than simple returns: for negative returns, cc returns have higher magnitude, and for positive returns, cc returns are less than simple returns.
Then, we can calculate the cc returns of the monthly portfolio returns as follows. We can use the monthly returns calculated by the Return.Portfolio function and convert it to continuously compounded returns:
pr = log(1+PR$portfolio.returns)
Now we can use the table.Stats from PeformanceAnalytics to quickly calculate the standard deviation and also other important descriptive statistics of returns:
returns_statistics = table.Stats(pr)
returns_statistics
returns_statistics["Stdev",]
## [1] 0.1018
Also we can use the sd and the mean function:
portfolio_volatility = sd(pr,na.rm = TRUE)
portfolio_volatility
## [1] 0.1018379
portfolio_mean_return = mean(pr,na.rm=TRUE)
portfolio_mean_return
## [1] 0.03223968
Remember that in Finance, the standard deviation of returns is usually called volatility.
We can say that the monthly volatility of this portfolio composed of 70% of Wal Mart and 30% of Tesla calculated from 2018 up to Oct 2021 was 10.1837901%.
We can complement this including the mean historical return of the portfolio. We can say that this portfolio had an average monthly return of 3.2239679%, and a monthly volatility of 10.1837901%.
It is very important to be aware of the granularity of the historical data used to calculate volatility and mean returns. Granularity of a dataset refers to the frequency of periods. In this case, we are using monthly returns, so the granularity is monthly.
Then, we can have a better interpretation of portfolio volatility and portfolio return if we convert both values from monthly to annual. It is very common to report annual mean portfolio return and annual portfolio volatility based on monthly data.
To convert monthly portfolio mean return to annual portfolio mean return, we just multiply the monthly average return times 12:
annual_portfolio_mean_return = 12 * portfolio_mean_return
annual_portfolio_mean_return
## [1] 0.3868761
However, to convert from monthly to annual volatility, we need to multiply by the square root of the numbers of the periods in the year, in this case, 12:
annual_portfolio_volatility = sqrt(12) * portfolio_volatility
annual_portfolio_volatility
## [1] 0.3527769
Now we can do a better interpretation using these annual figures:
We can say that this portfolio had an average annual return of 38.6876146%, and an annual volatility of 35.2776838%.
In the following sections we review what is variance and standard deviation of returns, and how they are calculated (without using a function)
Variance of any variable is actually the arithmetic mean of squared deviations. A squared deviation is the value resulting from subtracting the value of the variable minus its mean, and the square the value.
Variance is a measure of dispersion. The higher the variance, the more dispersed the values from its mean. It is hard to interpret the magnitude of variance. That is the reason why we need to calculate standard deviation, which is basically the squared root of the variance.
Standard deviation of a variable is the squared root of the variance of the variable: \[SD(r)=√VAR(r)\] Then, the standard deviation of returns can be interpreted as a standardized average distance from each value of the variable from its mean.
The standard deviation of returns is called volatility. Then, volatility of returns tells us an idea of how much on average (above or below) the period returns move from its mean.
We can calculate volatility of a single stock, or volatility of a portfolio composed of 2 or more stocks.
The Sharpe ratio is a standardized measure of portfolio premium return after considering its volatility.
A premium return is the return above the risk-free rate. In Mexico the risk-free rate is the CETES; in the US, the risk-free rate is the Treasury Bills.
Then, the Sharpe ratio tells us how much portfolio returns (above the risk free rate) we can expect for each percent point of volatility. Let’s see the formula:
\[SharpeRatio=(PortfolioReturn−riskfreeRate)/PortfolioVolatility\] # Calculating expected portfolio return
Up to now we have calculated historical portfolio returns and risk. Here we review how to estimate future expected portfolio returns and risk based on Portfolio Theory developed by Harry Markowitz.
We will use the simpler method to estimate the expected return of each stock, which is the geometric mean of historical returns. Other methods to estimate expected stock return are a) the CAPM regression model, b) ARIMA models.
The geometric mean of historical returns is the average period return needed so that holding an investment at that geometric mean return per period, we will get the final holding return of the stock.
An easier way to calculate geometric mean of returns is to calculate the arithmetic mean of continuously compounded returns, and then convert the result to simple return by applying the exponential function.
Let’s do an example. Calculate the expected monthly return of Wal Mart and Tesla using the same historical data from 2018 to Oct 2021.
We need to calculate the continuously compounded returns of each stock:
#Calculating continuously compounded returns:
r = diff(log(prices))
Now we get the expected return for each stock as the geometric mean of their historical returns:
ccmean_returns = colMeans(r,na.rm=TRUE)
colMeans calculate the arithmetic mean of 1 or more columns of a dataset.
Once we have the arithmetic mean cc returns, we convert them to simple returns:
ER = exp(ccmean_returns) - 1
ER
## WMT TSLA
## 0.007755907 0.055886431
Now that we have individual expected returns we can estimate the expected return of a portfolio composed of the stocks.
The expected portfolio returns is the weighted average of the individual expected return of the stocks of the portfolio.
Imagine we have a 2-stock portfolio composed as follows:
WalMart: 70%
Tesla: 30%
We use the weights (%) allocated for each asset to calculate the weighted average as the portfolio expected return:
w1 = 0.7
w2 = 0.3
ER_Portfolio = w1 * ER[1] + w2 * ER[2]
# ER is a vector of 2 numbers: the expected return of stock 1 and the expected return of stock 2
names(ER_Portfolio)=c("ER_Portfolio")
ER_Portfolio
## ER_Portfolio
## 0.02219506
Then, the expected return of this portfolio for the future month is 2.2195064%.
Another way to calculate the expected return of a portfolio is using matrix algebra. This is a very useful method when we have many assets in the portfolio since it is very easy to compute.
If you do not remember how to multiply matrices, it is strongly recommended to review this (you can read Note 2 of Portfolio Theory).
Matrix multiplication is used to compute sum of products or sum of multiplications.
We compute this in R as follows:
# We set a vector composed of the asset weights:
W = c(w1,w2)
# We multiply the transpose of the weight vector times the vector of expected returns
ER_portfolio = t(W) %*% ER
ER_portfolio
## [,1]
## [1,] 0.02219506
The transposed of a matrix or a vector is the conversion of the rows by columns and columns by rows. Transposing is like rotating a vector or a matrix 90 degrees.
Before we calculate the expected portfolio risk we need to understand what is the expected portfolio variance.
The covariance of 2 stock returns is the arithmetic mean of the product return deviations. A deviation is the difference between the stock return in a period t and its mean.
The covariance is a measure of linear relationship between 2 variables. If covariance between stock return 1 and stock return 2 is positive this means that both stock returns are positively related. In other words, when stock 1 return moves up it is likely that stock 2 return moves up and vice versa; both returns move in the same direction (not always, but mostly).
If covariance is negative that means that stock 1 return is negatively related to stock 2 return; when stock 1 return moves up it is likely that stock 2 return moves down.
Covariance can be a negative or positive number (it is not limited to any number). It is very difficult to interpret the magnitude of covariance. It is much more intuitive if we standardize covariance.
The standardization of the covariance is called correlation.
Correlation of 2 stock returns is also a measure of linear relationship between both returns. The difference compared to covariance is that the possible values of correlation is between -1 and +1, and the correlation gives us a percentage of linear relationship.
Correlation between 2 returns is the covariance between the 2 returns divided by the product of standard deviation of return 1 and standard deviation of return 2.
VAR1 = var(r$WMT,na.rm=TRUE)
VAR2 = var(r$TSLA,na.rm=TRUE)
COV = var(x=r$WMT,y=r$TSLA,na.rm=TRUE)
VarPortfolio = w1^2 * VAR1 + w2^2 * VAR2 + 2*w1*w2*COV
VarPortfolio
## WMT
## WMT 0.005651936
# We calculate the Variance-Covariance matrix with the var function:
COV =var(r,na.rm=TRUE)
# Note var function calculates the variance-covariance matrix if r has more than 1 column.
# If r has only 1 column, then var calculates only the variance of that column.
COV
## WMT TSLA
## WMT 0.002734706 0.002553678
## TSLA 0.002553678 0.035993165
VarPortfolio = t(W) %*% COV %*% W
VarPortfolio
## [,1]
## [1,] 0.005651936
It is always good to review the correlation matrix of the asset returns of a portfolios. We can get the correlation matrix from the covariance matrix as follows:
CORR = cov2cor(COV)
CORR
## WMT TSLA
## WMT 1.0000000 0.2573954
## TSLA 0.2573954 1.0000000
In this case we see 1’s in the diagonal since the correlation of an asset return with itself will always be equal to 1. In the diagonal we see the level of correlation between both asset returns.
We got the same result as above, but the result now is a matrix of 1 row and 1 element.
To get the expected risk of a portfolio, we simply get the squared root of the expected variance
PortRisk = sqrt(VarPortfolio[1,1])
PortRisk
## [1] 0.07517936
The expected portfolio monthly risk is 7.5179331%. Remember that portfolio risk is also called portfolio volatility. We can annualize portfolio volatility:
AnnualPortRisk = sqrt(12) * PortRisk
AnnualPortRisk
## [1] 0.2604289
The expected portfolio annual risk is 26.0428843%.
Financial portfolios allow an investor to diversify the risk. The main drivers of portfolio diversification are:
N - the number of financial assets. The more the financial assets, the higher the expected diversification.
Combination of pair of correlations between asset returns. The less the correlation of the pair of assets, the more the diversification.
The first driver is just given by N, the number of assets.
The second driver can actually be manipulated by changing the weights allocated for each asset.
In the following section we illustrate how changing asset weights actually change both, the expected return of the portfolio and the expected portfolio volatility.
Weight combination determines both expected risk and expected return of a portfolio. Let’s do an example with the same 2-asset portfolio:
Let’s create a set of 11 portfolios where we change the weight assigned to the first stock from 0 to 1 changing by 0.10. We can create a matrix of weights, where each column represents one portfolio.
# I first create a vector for the weights of the first stock:
w1= seq(from=0,to=1,by=0.1)
w1
## [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
# The weight vector for stock 2 is just the complement of w1:
w2 = 1 - w1
w2
## [1] 1.0 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1 0.0
# I construct the weight matrix with the cbind function:
W = rbind(w1,w2)
W
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11]
## w1 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
## w2 1 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1 0
# I compute the expected return of the 11 portfolios:
ERPortfolios = t(W) %*% ER
We see that the portfolios with higher expected returns are the first, which are the portfolios with higher weight in stock 2. Now we can compute the expected risk of the 11 portfolio as follows:
VARPortfolios = t(W) %*% COV %*% W
When we have more than 1 portfolio in the weight matrix, the result of the previous matrix multiplication will be a matrix of 11 rows and 11 columns. The expected variance of the 11 portfolio result in the diagonal of the previous multiplication:
VARPortfolios = diag(VARPortfolios)
VARPortfolios
## [1] 0.035993165 0.029641473 0.023962191 0.018955319 0.014620858 0.010958807
## [7] 0.007969166 0.005651936 0.004007115 0.003034706 0.002734706
Finally, the expected portfolio volatility is the squared root of these 11 expected variances:
RISKPortfolios = sqrt(VARPortfolios)
RISKPortfolios
## [1] 0.18971865 0.17216699 0.15479726 0.13767832 0.12091674 0.10468432
## [7] 0.08927019 0.07517936 0.06330178 0.05508816 0.05229442
Now that we have the 11 portfolio risk and 11 portfolio returns we can plot the 11 portfolios in the risk-return space:
plot(x=RISKPortfolios,y= ERPortfolios,
xlabel="Portfolio Expected Risk", ylabel="Portfolio Expected Return")
## Warning in plot.window(...): "xlabel" is not a graphical parameter
## Warning in plot.window(...): "ylabel" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "xlabel" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "ylabel" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "xlabel" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "ylabel" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "xlabel" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "ylabel" is not a
## graphical parameter
## Warning in box(...): "xlabel" is not a graphical parameter
## Warning in box(...): "ylabel" is not a graphical parameter
## Warning in title(...): "xlabel" is not a graphical parameter
## Warning in title(...): "ylabel" is not a graphical parameter
text(x=RISKPortfolios,y= ERPortfolios,
labels=w1, cex=0.7, pos=3)
Weights of stock 1 (WMT) are shown in each portfolio. We see that less the w1, the less the expected portfolio risk, but the less the expected portfolio return.
With this illustration we can see how asset weight combination in a portfolio actually change the expected return and risk of a portfolio!
This plot is called the frontier of feasible portfolios of 2 assets. Interestingly, for portfolios with 3 or more assets, the possibilities of feasible portfolios become will not be a nice frontier like this. The feasible portfolios will be in between a frontier. In other words, for these portfolios some feasible portfolios will not be efficient since there will be other feasible portfolios with the same level of expected risk, but with higher expected return.
Let’s do an example of 4-asset portfolios.
We will add 2 stocks to our portfolio: Oracle (ORCL) and Freeport-McMoran, Inc (FCX). This last firm is a mining company. I will collect the data for the 4 assets using the same code we used above:
tickers = c("WMT","TSLA","ORCL","FCX")
getSymbols(Symbols = tickers, periodicity="monthly",from="2018-01-01", to="2021-10-01")
## [1] "WMT" "TSLA" "ORCL" "FCX"
datasets_list <- lapply(tickers, get)
# Merging the datasets:
prices <- do.call(merge, datasets_list)
# We select only Adjusted prices:
prices <- Ad(prices)
# We change the name of the columns to be equal to the tickers vector:
names(prices) = tickers
#Calculating continuously compounded returns:
r = diff(log(prices))
Since we have now 4 assets, let’s create many feasible portfolios with random weights, but with the condition that the sum of the weights must be 1 (100%). Let’s create 1,000 random portfolios:
# Initialize the Weight matrix
W = c()
# Create 4 vectors of 1000 random values from 0 to 1:
for(i in 1:4) {
W = rbind(W,runif(1000))
}
# The problem I have now is that some of the 1,000 portfolios
# might end up having a sum of weights higher than one.
# I can do a simple "trick" by
# dividing each of the 4 weights by the sum of these 4
# weights. And I can do this # for all 1000 portfolios:
# I first create a vector with the sum of weights for all portfolios:
sumw <- colSums(W)
# I do another loop to divide each weight by the sum of weights:
for(i in 1:4) {
W[i,]<-W[i,]/sumw
# In each iteration I divide one raw of W2 by the vector sumw,
# which is the sum of the weights of all 1000 portfolios
}
# I check that the sum of weights is 1 (I do this for 5 portfolios)
W[,1:5]
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0.35272345 0.34358126 0.2502573 0.323109189 0.3210056
## [2,] 0.17923775 0.04188508 0.2030668 0.001548318 0.1088672
## [3,] 0.08637235 0.14273666 0.3581600 0.598043845 0.3289920
## [4,] 0.38166645 0.47179699 0.1885160 0.077298648 0.2411352
colSums(W[,1:5])
## [1] 1 1 1 1 1
# All sums are equal to 1, as expected
# Then each column of this matrix represents a random portfolio without allowing for short sales.
#I calculate the expected return of each asset:
ER = exp(colMeans(r,na.rm=TRUE)) - 1
ER
## WMT TSLA ORCL FCX
## 0.007755905 0.055886431 0.013411716 0.012518412
I calculate the variance-covariance matrix:
COV = var(r,na.rm=TRUE)
COV
## WMT TSLA ORCL FCX
## WMT 0.0027347067 0.002553673 0.0007634576 0.0009250762
## TSLA 0.0025536731 0.035993165 0.0013659571 0.0113606709
## ORCL 0.0007634576 0.001365957 0.0034419189 0.0043780298
## FCX 0.0009250762 0.011360671 0.0043780298 0.0212865605
I calculate the correlation matrix to review the correlation levels of pair of assets:
CORR = cov2cor(COV)
CORR
## WMT TSLA ORCL FCX
## WMT 1.0000000 0.2573949 0.2488452 0.1212466
## TSLA 0.2573949 1.0000000 0.1227232 0.4104320
## ORCL 0.2488452 0.1227232 1.0000000 0.5114765
## FCX 0.1212466 0.4104320 0.5114765 1.0000000
The lowest correlations are the one between ORCL and TSLA and the correlation between WMT and FCX (around 0.12).
We can calculate the expected return of the 1,000 portfolios:
ERPortfolios = t(W) %*% ER
We can calculate the expected risk of the 1,000 portfolios:
VARPortfolios = diag(t(W) %*% COV %*% W)
RISKPortfolios = sqrt(VARPortfolios)
Now we can visualize the feasible portfolios in the risk-return space:
plot(x=RISKPortfolios,y= ERPortfolios,
xlabel="Portfolio Expected Risk", ylabel="Portfolio Expected Return")
## Warning in plot.window(...): "xlabel" is not a graphical parameter
## Warning in plot.window(...): "ylabel" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "xlabel" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "ylabel" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "xlabel" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "ylabel" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "xlabel" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "ylabel" is not a
## graphical parameter
## Warning in box(...): "xlabel" is not a graphical parameter
## Warning in box(...): "ylabel" is not a graphical parameter
## Warning in title(...): "xlabel" is not a graphical parameter
## Warning in title(...): "ylabel" is not a graphical parameter
We can see that for each level of expected risk there are many possible portfolios. The best portfolios will be those that lie in the frontier of this feasible portfolios.
The problem we have when we have 3 or more assets in a portfolio is that we need to find the efficient frontier to get only those portfolios that maximize the expected return for each level of expected risk.
Here is where we need to find optimization algorithms to do this.
In the lecture note Basics of Portfolio Theory - Part III I explain what type of optimization methods can be used.
Fortunately, we can use R packages that already do these complicated optimization algorithms.
Out of all feasible portfolios we might be interested in the following:
The portfolio with the lest expected risk of all - The Global Minimum Variance Portfolio (GMV)
The efficient frontier - all portfolios that offer the highest expected return for any level of expected risk
The tangent/optimal portfolio - The portfolio with the highest Sharpe Ratio
We need to install the IntroCompFinR package. This package must be installed using the following code:
install.packages("IntroCompFinR", repos="http://R-Forge.R-project.org")
## Warning: unable to access index for repository http://R-Forge.R-project.org/bin/macosx/contrib/4.0:
## cannot open URL 'http://R-Forge.R-project.org/bin/macosx/contrib/4.0/PACKAGES'
## installing the source package 'IntroCompFinR'
We can easily get the GMV portfolio as follows:
library(IntroCompFinR)
GMVPort = globalMin.portfolio(ER,COV)
GMVPort
## Call:
## globalMin.portfolio(er = ER, cov.mat = COV)
##
## Portfolio expected return: 0.01047156
## Portfolio standard deviation: 0.04339397
## Portfolio weights:
## WMT TSLA ORCL FCX
## 0.5659 0.0054 0.4630 -0.0342
Allowing for short-sales, the portfolio with the minimum variance has an expected return of 0.0104715, and expected risk of 0.043394. We see that FCX has a negative weight, meaning that we need to short FCX with 3.4%.
We can estimate the GMV portfolio without allowing for short sales:
GMVPort = globalMin.portfolio(ER,COV, shorts = FALSE)
GMVPort
## Call:
## globalMin.portfolio(er = ER, cov.mat = COV, shorts = FALSE)
##
## Portfolio expected return: 0.01015369
## Portfolio standard deviation: 0.04357745
## Portfolio weights:
## WMT TSLA ORCL FCX
## 0.576 0.000 0.424 0.000
Now the GMV assigned 0% to FCX and 0% to TSLA. This makes sense since both stocks are very volatile. We can check the volatility of each of the stock returns:
table.Stats(r)
We can see that the historical volatility (Stdev) of Tesla and FCX are much higher than the volatility of ORCL and WMT.
efrontier <- efficient.frontier(ER, COV, nport = 100,
alpha.min = -0.5,
alpha.max = 1.5, shorts = FALSE)
plot(efrontier, plot.assets=TRUE, col="blue")
rfree = 0
tangentPort = tangency.portfolio(ER, COV,rfree, shorts=FALSE)
tangentPort
## Call:
## tangency.portfolio(er = ER, cov.mat = COV, risk.free = rfree,
## shorts = FALSE)
##
## Portfolio expected return: 0.02394625
## Portfolio standard deviation: 0.06762273
## Portfolio weights:
## WMT TSLA ORCL FCX
## 0.1238 0.2645 0.6117 0.0000
tangentPortWeights = getPortfolio(ER, COV, weights=tangentPort$weights)
plot(tangentPortWeights, col="blue")
Finally, we can plot the efficient frontier, the tangent portfolio and the Capital Market Line:
plot(efrontier, plot.assets=TRUE, col="blue", pch=16)
points(GMVPort$sd, GMVPort$er, col="green", pch=16, cex=2)
points(tangentPort$sd, tangentPort$er, col="red", pch=16, cex=2)
text(GMVPort$sd, GMVPort$er, labels="GLOBAL MIN", pos=2)
text(tangentPort$sd, tangentPort$er, labels="TANGENCY", pos=2)
SharpeRatio = (tangentPort$er - rfree)/tangentPort$sd
abline(a=rfree, b=SharpeRatio, col="green", lwd=2)
The Capital Market Line (CML) is the green line that goes from the risk-free rate to the tangent portfolio. One of the main findings of portfolio theory is that when we add 1 risk-free instrument to a portfolio composed of stocks, the new efficient frontier becomes the Capital Market Line (instead of the hyperbola), which is more efficient that the previous efficient frontier (the hyperbola).
Then, an investor can play between the tanget portfolio and the risk-free rate to move in the CML. If an investor has a middle-level aversion to risk, he/she might select to allocate 50% to the risk-free asset and the rest 50% in the tangent portfolio, locating the portfolio in a mid-point in the CML between the risk-free rate and the tangent portfolio.
The main assumption of portfolio theory is that all investors behave as rational participants all the time. In other words, they always maximize return and minimize risk using the available information disclosed to the market in a rational way. In other words, they act with no emotions, no fear and they always understand what happen in the market.
If most of the investors are not rational all the time, how can you take advantage of this and define a disruptive portfolio? Which trends, beliefs, fears, regulations, opportunities do you think that few investors are looking for, so that you can beat the rational optimized portfolio?
Partiendo de la premisa de que somos seres emocionales, al momento de escuchar noticias (manipuladas) solemos entrar en pánico y vender nuestras posiciones. No obstante, es justamente cuando las personas están apanicadas cuando hay que comprar y vender cuando entran en FOMO; en palabras de Warren Buffet: compra cuando todos tengan miedo, vende cuando todos se sean dominados por su avaricia.
Based on your own set of beliefs and your understanding of portfolio risk-return trade-off, propose weights for a “disruptive” portfolio that might beat most of the optimized portfolios in the market?
25% Stocks 25% Cryptocurrencies 25% Etfs 25% Reits
Based on the list of 10 assets generated from previous Challenge (w2):
“BRK-B”, “COHN”, “CPSS”, “CYH”, “GHLD”, “GNK”, “HCHC”, “IBEX”, “MTEX”, “NMRK”, “GSPC”
1.- Generate the Global Minimum Variance Portfolio 2.- Generate 10,000 portfolios with random weights for each asset.
library(quantmod)
tickers_W3 = c("BRK-B", "WMT", "CPSS", "CYH", "GHLD", "GNK", "TSLA", "IBEX", "MTEX", "NMRK")
getSymbols(Symbols = tickers_W3, periodicity="monthly",from="2018-01-01", to="2021-10-01")
## pausing 1 second between requests for more than 5 symbols
## pausing 1 second between requests for more than 5 symbols
## pausing 1 second between requests for more than 5 symbols
## pausing 1 second between requests for more than 5 symbols
## pausing 1 second between requests for more than 5 symbols
## pausing 1 second between requests for more than 5 symbols
## [1] "BRK-B" "WMT" "CPSS" "CYH" "GHLD" "GNK" "TSLA" "IBEX" "MTEX"
## [10] "NMRK"
datasets_list_W3 <- lapply(tickers_W3, get)
# Merging the datasets:
prices_W3 <- do.call(merge, datasets_list_W3)
# We select only Adjusted prices:
prices_W3 <- Ad(prices_W3)
# We change the name of the columns to be equal to the tickers vector:
names(prices_W3) = tickers_W3
#Calculating continuously compounded returns:
r_W3 = diff(log(prices_W3))
# Initialize the Weight matrix
W_W3 = c()
# Create 10 vectors of 10000 random values from 0 to 1:
for(i in 1:10) {
W_W3 = rbind(W_W3,runif(10000))
}
# I first create a vector with the sum of weights for all portfolios:
sumw_W3 <- colSums(W_W3)
# I do another loop to divide each weight by the sum of weights:
for(i in 1:10) {
W_W3[i,]<-W_W3[i,]/sumw_W3
# In each iteration I divide one raw of W2 by the vector sumw,
# which is the sum of the weights of all 10000 portfolios
}
W_W3[,1:5]
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0.12612575 0.188864450 0.227303677 0.1191404024 0.08622785
## [2,] 0.06168701 0.001774618 0.019833517 0.1510441559 0.13825679
## [3,] 0.07586569 0.173056127 0.079070173 0.1160817804 0.04673590
## [4,] 0.13506826 0.070134669 0.097488233 0.1062137736 0.12646505
## [5,] 0.12351727 0.106494235 0.105606185 0.1297131138 0.02302330
## [6,] 0.10014125 0.156384283 0.030835376 0.1362680997 0.18282603
## [7,] 0.13502634 0.014492828 0.004098438 0.0005253803 0.03702602
## [8,] 0.08207463 0.089363768 0.237018248 0.1484836014 0.17290132
## [9,] 0.11245526 0.088823012 0.043536166 0.0706980475 0.04821964
## [10,] 0.04803854 0.110612010 0.155209987 0.0218316449 0.13831809
colSums(W_W3[,1:5])
## [1] 1 1 1 1 1
#I calculate the expected return of each asset:
ER_W3 = exp(colMeans(r_W3,na.rm=TRUE)) - 1
ER_W3
## BRK-B WMT CPSS CYH GHLD GNK
## 0.005503768 0.007755907 0.005886231 0.016681547 0.001468838 0.012112841
## TSLA IBEX MTEX NMRK
## 0.055886431 0.008380369 0.023275734 -0.001506726
#I calculate the variance-covariance matrix:
COV_W3 = var(r_W3,na.rm=TRUE)
COV_W3
## BRK-B WMT CPSS CYH GHLD
## BRK-B 0.0018257075 0.0007192293 0.0005795471 0.0007631006 0.0003221720
## WMT 0.0007192293 0.0019544205 0.0009603432 0.0028400445 -0.0018213741
## CPSS 0.0005795471 0.0009603432 0.0036229407 -0.0066461977 0.0008946484
## CYH 0.0007631006 0.0028400445 -0.0066461977 0.0443102306 -0.0105419342
## GHLD 0.0003221720 -0.0018213741 0.0008946484 -0.0105419342 0.0087396401
## GNK 0.0022074314 -0.0001732778 -0.0006900538 -0.0132307897 0.0027602416
## TSLA -0.0022394494 -0.0001325984 0.0009694549 -0.0047617816 0.0004437602
## IBEX 0.0017405468 -0.0012862664 -0.0013447383 -0.0038328381 0.0017406158
## MTEX 0.0008445698 0.0027602979 0.0014172563 0.0135839124 -0.0037967236
## NMRK 0.0030251618 -0.0022821203 0.0005922601 -0.0080638376 0.0048337444
## GNK TSLA IBEX MTEX NMRK
## BRK-B 0.0022074314 -0.0022394494 0.001740547 0.0008445698 0.0030251618
## WMT -0.0001732778 -0.0001325984 -0.001286266 0.0027602979 -0.0022821203
## CPSS -0.0006900538 0.0009694549 -0.001344738 0.0014172563 0.0005922601
## CYH -0.0132307897 -0.0047617816 -0.003832838 0.0135839124 -0.0080638376
## GHLD 0.0027602416 0.0004437602 0.001740616 -0.0037967236 0.0048337444
## GNK 0.0241942842 -0.0030236833 0.005003789 -0.0045428084 0.0066521197
## TSLA -0.0030236833 0.0124031865 -0.005464309 -0.0020604150 -0.0114854833
## IBEX 0.0050037890 -0.0054643089 0.008454217 -0.0067361167 0.0081706929
## MTEX -0.0045428084 -0.0020604150 -0.006736117 0.0131802091 -0.0022983666
## NMRK 0.0066521197 -0.0114854833 0.008170693 -0.0022983666 0.0183228200
#I calculate the correlation matrix to review the correlation levels of pair of assets:
CORR_W3 = cov2cor(COV_W3)
CORR_W3
## BRK-B WMT CPSS CYH GHLD GNK
## BRK-B 1.00000000 0.38075249 0.22534221 0.08484265 0.08065391 0.33213544
## WMT 0.38075249 1.00000000 0.36089998 0.30518567 -0.44070034 -0.02519867
## CPSS 0.22534221 0.36089998 1.00000000 -0.52455452 0.15899190 -0.07370483
## CYH 0.08484265 0.30518567 -0.52455452 1.00000000 -0.53569985 -0.40408932
## GHLD 0.08065391 -0.44070034 0.15899190 -0.53569985 1.00000000 0.18982086
## GNK 0.33213544 -0.02519867 -0.07370483 -0.40408932 0.18982086 1.00000000
## TSLA -0.47060768 -0.02693164 0.14462066 -0.20311913 0.04262211 -0.17454735
## IBEX 0.44303027 -0.31643553 -0.24297997 -0.19803036 0.20249740 0.34986936
## MTEX 0.17217052 0.54385834 0.20509573 0.56209758 -0.35375376 -0.25439401
## NMRK 0.52304235 -0.38135844 0.07269185 -0.28300467 0.38198012 0.31594210
## TSLA IBEX MTEX NMRK
## BRK-B -0.47060768 0.4430303 0.1721705 0.52304235
## WMT -0.02693164 -0.3164355 0.5438583 -0.38135844
## CPSS 0.14462066 -0.2429800 0.2050957 0.07269185
## CYH -0.20311913 -0.1980304 0.5620976 -0.28300467
## GHLD 0.04262211 0.2024974 -0.3537538 0.38198012
## GNK -0.17454735 0.3498694 -0.2543940 0.31594210
## TSLA 1.00000000 -0.5336198 -0.1611487 -0.76187984
## IBEX -0.53361978 1.0000000 -0.6381338 0.65648686
## MTEX -0.16114874 -0.6381338 1.0000000 -0.14789790
## NMRK -0.76187984 0.6564869 -0.1478979 1.00000000
#We can calculate the expected return of the 10,000 portfolios:
ERPortfolios_W3 = t(W_W3) %*% ER_W3
#We can calculate the expected risk of the 10,000 portfolios:
VARPortfolios_W3 = diag(t(W_W3) %*% COV_W3 %*% W_W3)
RISKPortfolios_W3 = sqrt(VARPortfolios_W3)
#Now we can visualize the feasible portfolios in the risk-return space:
plot(x=RISKPortfolios_W3,y= ERPortfolios_W3,
xlabel="Portfolio Expected Risk", ylabel="Portfolio Expected Return")
## Warning in plot.window(...): "xlabel" is not a graphical parameter
## Warning in plot.window(...): "ylabel" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "xlabel" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "ylabel" is not a graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "xlabel" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "ylabel" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "xlabel" is not a
## graphical parameter
## Warning in axis(side = side, at = at, labels = labels, ...): "ylabel" is not a
## graphical parameter
## Warning in box(...): "xlabel" is not a graphical parameter
## Warning in box(...): "ylabel" is not a graphical parameter
## Warning in title(...): "xlabel" is not a graphical parameter
## Warning in title(...): "ylabel" is not a graphical parameter
#Estimating the global minimum variance portfolio
#library(IntroCompFinR)
#GMVPort_W3 = globalMin.portfolio(ER_W3,COV_W3)
#GMVPort_W3
#We can estimate the GMV portfolio without allowing for short sales:
#GMVPort_W3 = globalMin.portfolio(ER_W3,COV_W3, shorts = FALSE)
#GMVPort_W3
#table.Stats(r_W3)
ESTOY CONVENCIDO DE QUE EL CÓDIGO ESTÁ BIEN ELABORADO, SIN EMBARGO, NO LOGRO IDENTIFICAR EL ERROR MARCADO: “Error in solve.default(cov.mat) : system is computationally singular: reciprocal condition number = 4.89308e-18”
*PREGUNTAR EN CLASE
#Estimating the efficient frontier
#efrontier_W3 <- efficient.frontier(ER_W3, COV_W3, nport = 100,
# alpha.min = -0.5,
# alpha.max = 1.5, shorts = FALSE)
#plot(efrontier_W3, plot.assets=TRUE, col="blue")
#Estimating the optimal/tangent portfolio
#rfree_W3 = 0
#tangentPort_W3 = tangency.portfolio(ER_W3, COV_W3, rfree_W3, shorts=FALSE)
#tangentPort_W3
#tangentPortWeights_W3 = getPortfolio(ER_W3, COV_W3, weights=tangentPort_W3$weights)
#plot(tangentPortWeights_W3, col="blue")
#Finally, we can plot the efficient frontier, the tangent portfolio and the Capital Market Line:
#plot(efrontier_W3, plot.assets=TRUE, col="blue", pch=16)
#points(GMVPort_W3$sd, GMVPort_W3$er, col="green", pch=16, cex=2)
#points(tangentPort_W3$sd, tangentPort_W3$er, col="red", pch=16, cex=2)
#text(GMVPort_W3$sd, GMVPort_W3$er, labels="GLOBAL MIN", pos=2)
#text(tangentPort_W3$sd, tangentPort_W3$er, labels="TANGENCY", pos=2)
#SharpeRatio_W3 = (tangentPort_W3$er - rfree_W3)/tangentPort_W3$sd
#abline(a=rfree_W3, b=SharpeRatio_W3, col="green", lwd=2)
3.- Propose your 3 portfolios: Conservative, Aggressive, and Disruptive. Include the description of each portfolio, expected return and volatility.
CONSERVADOR:
25% Renta variable (Acciones, ETF’s, REITS) 75% Renta fija (Bonos)
AGRESIVO
75% Renta variable (Acciones, ETF’s, REITS, IPO, Small caps) 25% Criptoactivos (Protocolos sólidos, Staking, Farming, DeFi)
DISRUPTIVO
50% Renta variable (Acciones, ETF’s, REITS, IPO, Small caps) 50% Criptoactivos (Protocolos sólidos, Staking, Farming, DeFi)