1 Data management

1.1 Data collection

#install.packages("IntroCompFinR", repos = "http://R-Forge.R-project.org")
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
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:xts':
## 
##     first, last
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(PerformanceAnalytics)
## 
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
## 
##     legend
library(IntroCompFinR)
library(readxl)
setwd("D:/tec/7mo sem/Computational Finance")
input.df<-read_excel("InputW6.xlsx",sheet = "ticklist")
tickers.list<-input.df$ticker
getSymbols(tickers.list,
           from = "2016-01-01", to = "2021-03-23",
           periodicity = "monthly",
           src = "yahoo")
## '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] "AMZN" "JPM"  "WMT"  "TSLA"
p1<-get(tickers.list[1])
p2<-get(tickers.list[2])
p3<-get(tickers.list[3])
p4<-get(tickers.list[4])

prices.zoo <- merge(p1, p2, p3, p4)
rm(p1, p2, p3, p4) 
objList <- lapply(tickers.list, get)
class(objList)
## [1] "list"
head(objList[[1]])
##            AMZN.Open AMZN.High AMZN.Low AMZN.Close AMZN.Volume AMZN.Adjusted
## 2016-01-01    656.29    657.72   547.18     587.00   130200900        587.00
## 2016-02-01    578.15    581.80   474.00     552.52   124144800        552.52
## 2016-03-01    556.29    603.24   538.58     593.64    94009500        593.64
## 2016-04-01    590.49    669.98   585.25     659.59    78464200        659.59
## 2016-05-01    663.92    724.23   656.00     722.79    90614500        722.79
## 2016-06-01    720.90    731.50   682.12     715.62    74540900        715.62
prices.zoo <- merge(objList[[1]], objList[[2]], objList[[3]], objList[[4]])
prices.zoo <- do.call(merge, objList)
prices.df <- as.data.frame(na.omit(Ad(prices.zoo)))

1.2 Return calculation

returns.df <- diff(log(as.zoo(prices.df)))
## 
## NOTE: quantmod::as.zoo.data.frame() is deprecated
##   Use as.zoo(x, order.by = as.Date(rownames(x))) instead.
##   This note is printed once. To see it for every call, set
##   options(quantmod.deprecate.as.zoo.data.frame = TRUE)

1.3 Descriptive statistics and visualization

head(returns.df)
##            AMZN.Adjusted JPM.Adjusted  WMT.Adjusted TSLA.Adjusted
## 2016-02-01   -0.06053515  -0.04859566 -0.0003013322   0.003810721
## 2016-03-01    0.07178343   0.05056473  0.0318948643   0.179948013
## 2016-04-01    0.10534537   0.06504490 -0.0165615355   0.046721800
## 2016-05-01    0.09150022   0.03960472  0.0568256359  -0.075597957
## 2016-06-01   -0.00996940  -0.04914263  0.0384522019  -0.050296449
## 2016-07-01    0.05860212   0.02902439 -0.0006851690   0.100785316
tail(returns.df)
##            AMZN.Adjusted JPM.Adjusted WMT.Adjusted TSLA.Adjusted
## 2020-10-01 -0.0364089574   0.01821884 -0.008325563   -0.10037180
## 2020-11-01  0.0425228793   0.19352809  0.096390579    0.38030845
## 2020-12-01  0.0276719006   0.07507106 -0.058210060    0.21773078
## 2021-01-01 -0.0156985930   0.01251284 -0.022069153    0.11734370
## 2021-02-01 -0.0359675803   0.14151335 -0.078217603   -0.16103823
## 2021-03-01  0.0003717938   0.03380409  0.044485239   -0.01126979
#To avoid scientific notations for outputs, I define the following:
options(scipen=100)
options(digits=2)
returns.zoo<-as.zoo(returns.df)
table.Stats(returns.df) 
chart.Boxplot(returns.zoo)

INTERPRETATION

BY LOOKING AT THE GRAPGH, I CAN SEE THAT TSLA IS THE RISKIEST DUE TO THE EXTREME CALUES IT HAS, EVENTHOUG ITS RESULTS ARE USUALLY POSITIVE, IT CAN VARIATE SINCE LESS THAN -0.2 TO 0.35 APROXIMATELY. ALSO WE CAN SAY THAT THE MORE SECURE IS WALMART BECAUSE ITS VALUES ARE MORE NEAR TO 0 AND HAS LESS VARIATIONS.

1.4 Simulating portfolios of 4 assets

Using these 4 assets you have to simulate 1000 portfolios with random weights for each asset, but the sum of the 4 random weights must be equal to 1.

# I create an empty vector 
W<-c()
# I do a loop from 1 to 3 to create 1,000 columns of 4 random weights following
#   the uniform probability distribution:
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 only for 10 portfolios)
colSums(W[,1:10])
##  [1] 1 1 1 1 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.

Then each of the 1,000 columns of W represent one random portfolio of 4 assets. I can calculate the expected return and expected risk of each of these portfolios according to Markowitz portfolio theory.

# I create a matrix for the historical returns of the assets:
ret.mat <- as.matrix(returns.df)
# I generate the expected returns of the assets as their geometric means:
exp.rets<-exp(colMeans(ret.mat)) - 1
# I generate the variance-covariance matrix:
COV<-var(ret.mat)
# I estimate the expected returns of all 1,000 portfolios using matrix algebra:
ERP<-t(W)%*%exp.rets
# I estimate the expected variance and risk of the portfolios using matrix algebra:
VARP<-t(W)%*%COV%*%W
# I get the diagonal of this matrix and take square root to get the expected risk
#   of the 1,000 portfolios:
RISKP<-sqrt(diag(VARP))
# I remove the VARP object since it has 1,000 times 1,000 cels! 1 million cells!
rm(VARP)

I plot the expected risk vs return of 1,000 portfolios

plot(RISKP,ERP[,1], main="Random portfolios of 4 assets",xlab="Volatility",ylab="Exp Return")

2 CHALLENGE 1- Calculate the portfolio of minimum variance

Write code to identify which of the 1,000 portfolios is the portfolio with the lowest expected variance. You have to show the weights of each asset and its corresponding expected risk and expected variance. Hint: you can use sub-setting of data frames.

2.1 Function

PORT <- as.data.frame(cbind(ERP,RISKP, t(W)))
colnames(PORT) <- c("ER", "RISK", tickers.list)
MIN_VAR_PORT <- PORT[order(PORT$RISK)[1],]
MIN_VAR_PORT

2.2 Global Minimum Portfolio

gmvportws = globalMin.portfolio(exp.rets, COV) 
gmvportws
## Call:
## globalMin.portfolio(er = exp.rets, cov.mat = COV)
## 
## Portfolio expected return:     0.016 
## Portfolio standard deviation:  0.043 
## Portfolio weights:
## AMZN.Adjusted  JPM.Adjusted  WMT.Adjusted TSLA.Adjusted 
##        0.1390        0.2681        0.6027       -0.0098
attributes(gmvportws)
## $names
## [1] "call"    "er"      "sd"      "weights"
## 
## $class
## [1] "portfolio"
gmvportws$weights
## AMZN.Adjusted  JPM.Adjusted  WMT.Adjusted TSLA.Adjusted 
##        0.1390        0.2681        0.6027       -0.0098
class(gmvportws)
## [1] "portfolio"
gmvportwos <- globalMin.portfolio(exp.rets, COV, shorts = FALSE)

# Print the object
gmvportwos
## Call:
## globalMin.portfolio(er = exp.rets, cov.mat = COV, shorts = FALSE)
## 
## Portfolio expected return:     0.016 
## Portfolio standard deviation:  0.043 
## Portfolio weights:
## AMZN.Adjusted  JPM.Adjusted  WMT.Adjusted TSLA.Adjusted 
##          0.13          0.26          0.60          0.00

2.3 The Efficient Frontier

ef <- efficient.frontier(exp.rets, COV, nport = 100, 
                         alpha.min = -0.5, 
                         alpha.max = 1.5, shorts = TRUE)
attributes(ef)
## $names
## [1] "call"    "er"      "sd"      "weights"
## 
## $class
## [1] "Markowitz"
plot(ef, plot.assets = TRUE, col = "blue", pch = 16)

ef <- efficient.frontier(exp.rets, COV, nport = 100, 
                         alpha.min = -0.5, 
                         alpha.max = 1, shorts = TRUE)

plot(ef, plot.assets = TRUE, col = "blue", pch = 16)

INTERPRETATION

THIS GRAPH SHOWS THAT THE RISKIER BUT WITH THE HIGHER RETURNS IS TSLA, FOLLOWED BY AMZN, JPM AND LAST BY WMT WHICH IS AS I EARLY MENTIONED THE MORE SECURE.

2.3.1 The Tangent (optimal) portfolio

r.free = 0.0
tan.port <- tangency.portfolio(exp.rets, COV, r.free)
tanportweights<-getPortfolio(er=exp.rets,cov.mat=COV,weights=tan.port$weights)
plot(tanportweights, col="blue")

gmin.port<-globalMin.portfolio(exp.rets, COV)
efrontier <- efficient.frontier(exp.rets, COV, alpha.min=-0.5,
                                alpha.max=1.5, nport=30)
attributes(efrontier)
## $names
## [1] "call"    "er"      "sd"      "weights"
## 
## $class
## [1] "Markowitz"
plot(efrontier)

# AGAIN THE PLOT FUNCTION IS USED TO GRAPH THE EFFICIENT FRONTIER IN COLOR BLUE 
plot(efrontier, plot.assets=TRUE, col="blue", pch=16)
# HERE THE POINTS FUNCTION RECEIVES THE STANDARD DEVIATION AND EXPECTED RETURN OF THE GLOBAL MINIMUM PORTFOLIO AND GRAPHS IT AS A GREEN POINT IN THE ALREADY EXISTING PLOT 
points(gmin.port$sd, gmin.port$er, col="green", pch=16, cex=2)
# THE SAME AS IN THE PREVIOUS LINE BUT NOW WITH THE TANGENT PORTFOLIO AND IN RED COLOR
points(tan.port$sd, tan.port$er, col="red", pch=16, cex=2)
# THE TEXT FUNCTION RECEIVES THE SAME INFORMATION AS THE POINTS FUNCTION ABOUT THE GLOBAL MINIMUM VARIANCE TO LABEL IT AS "GLOBAL MIN"
text(gmin.port$sd, gmin.port$er, labels="GLOBAL MIN", pos=2)
# SAME PROCEDURE BUT WITH THE TANGENT PORTFOLIO INFO AND THE LABEL IS "TANGENCY"
text(tan.port$sd, tan.port$er, labels="TANGENCY", pos=2)
# HERE THE SHARPE RATIO IS CALCULATED BY FOLLOWING A FORMULA, THE SHARPE RATIO IS THE AVERAGE RETURN ABOVE RISK-FREE RATE PER UNIT OF RISK
sr.tan = (tan.port$er - r.free)/tan.port$sd
# FINALLY THE ABLINE FUNCTION RECEIVES THE RISK FREE RATE AND SHARPE RATIO TO ADD THE CAPITAL MERKET LINE TO THE PLOT, THIS IS THE LINE FROM THE RISK-FREE RATE TO THE EFFICIENT FRONTIER 
abline(a=r.free, b=sr.tan, col="green", lwd=2)

3 CHALLENGE 2- Frontiers of 2-asset portfolios with different correlations

You have to simulate 5 frontiers of 2-asset portfolios where each frontier you assume a hypothetical correlation between the 2 assets, starting from -1 up to +1 jumping by 0.5. Do the following:

1 Download monthly price data for WMT and AMZN from Yahoo from Jan 2016 to date. Calculate cc returns

2 Calculate the expected returns and store them in a vector

3 Calculate the Variance-Covariance matrix of these 2 stock returns

4 Create a vector wa for simulating different weights for WMT. Create this vector with sequential values from 0 to 1. Create the vector wb equal to the complement of wa (1-wa) that represent the % invested in AMZN.

5 Then, with these weight vectors of 11 elements you have to estimate the expected return, variance and expected standard deviation of each of these 11 portfolios.

6 Do a scatter plot for the portfolio frontier, so that you can see the relationship between risk and return of these 11 portfolios.

7 You have to simulate 5 portfolio frontiers using the weight vectors with positive weights. Each of these portfolio frontiers will have a hypothetical correlation between WMT and AMZN. Create the first portfolio frontier with a hypothetical correlation of -1, then the 2nd portfolio frontier with a correlation of -0.5, then the 3rd with a correlation of 0, then the 4rd frontier with a correlation of 0.5, and finally, the 5th frontier with a correlation of 1.

Graph the 5 frontiers in one plot. What do you observe? EXPLAIN with your own words.

8 Encapsulate the code you wrote in a function that receives the two tickers, initial date and end date, and do the previous steps finishing in the simulation of 5 portfolio frontiers with different levels of correlation.

rm(list=ls())
library(quantmod)
library(dplyr)
library(PerformanceAnalytics)
library(IntroCompFinR)
library(readxl)
getSymbols(Symbols=c("WMT","AMZN"), 
            from="01-01-2016",
            src="yahoo",
            periodicity="monthly")
## [1] "WMT"  "AMZN"
P1<-Ad(merge(WMT,AMZN))

r<-diff(log(P1))
rets.df <-as.data.frame(na.omit(Ad(r))) 
names(rets.df)<-c("rwmt","rtsla")
ExRet <-exp(apply(rets.df,2,mean, na.rm=TRUE))-1
cov2<-cov(rets.df)
cov2
##         rwmt  rtsla
## rwmt  0.0036 0.0019
## rtsla 0.0019 0.0235
wWMT <- seq(from = 0, to = 1, by = 0.1)
wAMZN <- 1-wWMT
weights <- rbind(wWMT,wAMZN)
port2 <- as.data.frame(t(weights)%*%ExRet)
colnames(port2)<- "ExpRet"
port2$Var <- diag(t(weights) %*% cov2 %*% weights)
port2$SD <- sqrt(port2$Var)
plot(port2$SD,port2$ExpRet, xlab="Portfolio volatility", 
     ylab="Portfolio Expected Return",
     main="11 Portfolios of 2 Stocks")

Simulation of 5 portfolio frontiers

# I generate a cov matrix
Mcov <- cov2
# I get the SD to use the Cov= COrr*(SD1*SD2)
SD_WMT <-sd(r$WMT.Adjusted)
SD_AMZN <-sd(r$AMZN.Adjusted)
e.frontiers <- as.data.frame(t(weights)%*%ExRet)
# loop
for(corr in seq(from=-1, to=1, by=0.5 )){
  # get cov from correlation
  cv <- corr*SD_WMT*SD_AMZN
  # change cov values
  Mcov[1,2] <- cv
  Mcov[2,1] <- cv
  # Calculate risk
RISK <- sqrt(diag(t(weights) %*% Mcov %*% weights))
# Add risk
 e.frontiers <- cbind(e.frontiers, RISK)
}
# Change names
colnames(e.frontiers) <- c("ER", "RISK1", "RISK2", "RISK3", "RISK4", "RISK5")

Now I plot

#plot(x= e.frontiers$RISK1, y= e.frontiers$ER, col="blue", type = "b", xlab="Portfolio volatility", ylab="Portfolio Expected Return",
     #main="Efficient Frontiers")
#lines(x= e.frontiers$RISK2, y= e.frontiers$ER,col="red", type ="b" )
#lines(x= e.frontiers$RISK3, y= e.frontiers$ER,col="green", type ="b" )
#lines(x= e.frontiers$RISK4, y= e.frontiers$ER,col="orange", type ="b" )
#lines(x= e.frontiers$RISK5, y= e.frontiers$ER,col="black", type ="b" )
#My code got stuck in there teacher, but I worked with Debbi and Pao and as their code run in excelent way, I can say that.

#TALKING ABOUT THE EFFICIENT FRONTIERS GRAPH, WE CAN CONCLUDE THAT THE HIGHER THE RISK, THE HIGHER THE CORRELATION.