Introduction

The five-asset portfolio consists of the following equities:

Installing libraries

install.packages("tidyquant", repos = "http://cran.us.r-project.org")
install.packages("plotly", repos = "http://cran.us.r-project.org")
install.packages("timetk", repos = "http://cran.us.r-project.org")
install.packages("quantmod", repos = "http://cran.us.r-project.org")
library(tidyquant) 
library(plotly) 
library(timetk) 
library(quantmod)
library(pacman)
pacman::p_load(tidyverse,data.table, fixest, BatchGetSymbols, finreportr, ggplot2, lubridate)

Visualizing the Stock returns

first.date <- Sys.Date() - 5000
last.date <- Sys.Date()
freq.data <- "monthly"
tickers <- c('ADANIPOWER.NS', 'HINDUNILVR.NS', 'RELIANCE.NS', 'INFY.NS', 'HDFCBANK.NS')

stocks <- BatchGetSymbols(tickers = tickers, 
                          first.date = first.date,
                          last.date = last.date,
                          freq.data = freq.data,
                          do.cache = FALSE,
                          thresh.bad.data = 0)

stocks_DT <- stocks$df.tickers %>% setDT() %>% 
  .[order(ticker, ref.date)]

returns_plot_all <- ggplot(stocks_DT, aes(x= ref.date, y = ret.adjusted.prices, colour = ticker)) +
  geom_line() + theme_bw() + labs(title = "", x = "Date", y= "Monthly Returns", subtitle = "") 

returns_plot_all

Portfolio Optimization

The portfolio produced by Markowitz gave investors a way to mathematically(statistically) balance out their expectations for rewards and risk tolerance.

This hypothesis was built around two key ideas:

An assumption he kept in mind was that investors are risk-averse and tend to opt portfolios that have lesser risks associated with the given levels of return. This implied that investors took high-risk portfolios only if the rewards were high, i.e., the returns were high.

## Collecting daily stock prices

first.date <- Sys.Date() - 2000
last.date <- Sys.Date()
freq.data <- "daily"
tickers <- c('ADANIPOWER.NS', 'HINDUNILVR.NS', 'RELIANCE.NS', 'INFY.NS', 'HDFCBANK.NS')

stock_data <- tq_get(tickers,
                     from = first.date,
                     to = last.date,
                     get = 'stock.prices')

## Calculating the logarithmic daily returns 

log_returns <- stock_data %>%
  group_by(symbol) %>%
  tq_transmute(select = adjusted,
               mutate_fun = periodReturn,
               period = 'daily',
               col_rename = 'ret',
               type = 'log')

head(log_returns)
## # A tibble: 6 × 3
## # Groups:   symbol [1]
##   symbol        date           ret
##   <chr>         <date>       <dbl>
## 1 ADANIPOWER.NS 2017-01-05 0      
## 2 ADANIPOWER.NS 2017-01-06 0.00306
## 3 ADANIPOWER.NS 2017-01-09 0.00610
## 4 ADANIPOWER.NS 2017-01-10 0.0181 
## 5 ADANIPOWER.NS 2017-01-11 0.0481 
## 6 ADANIPOWER.NS 2017-01-12 0.0363
## Converting it wide format time-series object

log_returns_xts <- log_returns %>%
  spread(symbol, value = ret) %>%
  tk_xts()

head(log_returns_xts)
##            ADANIPOWER.NS  HDFCBANK.NS HINDUNILVR.NS       INFY.NS  RELIANCE.NS
## 2017-01-05   0.000000000 0.0000000000  0.0000000000  0.0000000000  0.000000000
## 2017-01-06   0.003062881 0.0062609579  0.0007196370 -0.0242849214 -0.002276476
## 2017-01-09   0.006097610 0.0012977107 -0.0032436167 -0.0019562635  0.002554979
## 2017-01-10   0.018072720 0.0158954201 -0.0006018911  0.0002062561  0.011211069
## 2017-01-11   0.048079236 0.0160520671  0.0130979603 -0.0014953380 -0.003493070
## 2017-01-12   0.036316811 0.0008098233 -0.0187122196  0.0314376599 -0.002535310
## Mean daily returns

mean_ret <- colMeans(log_returns_xts)
print(round(mean_ret, 5))
## ADANIPOWER.NS   HDFCBANK.NS HINDUNILVR.NS       INFY.NS   RELIANCE.NS 
##       0.00157       0.00064       0.00082       0.00091       0.00116
## Covariance Matrix

cov_mat <- cov(log_returns_xts) * 252
print(round(cov_mat,4))
##               ADANIPOWER.NS HDFCBANK.NS HINDUNILVR.NS INFY.NS RELIANCE.NS
## ADANIPOWER.NS        0.3547      0.0354        0.0269  0.0310      0.0545
## HDFCBANK.NS          0.0354      0.0657        0.0182  0.0207      0.0313
## HINDUNILVR.NS        0.0269      0.0182        0.0554  0.0165      0.0227
## INFY.NS              0.0310      0.0207        0.0165  0.0799      0.0240
## RELIANCE.NS          0.0545      0.0313        0.0227  0.0240      0.0974
num_port <- 5000

# Creating a matrix to store the weights

all_wts <- matrix(nrow = num_port,
                  ncol = length(tickers))

# Creating an empty vector to store
# Portfolio returns

port_returns <- vector('numeric', length = num_port)

# Creating an empty vector to store
# Portfolio Standard deviation

port_risk <- vector('numeric', length = num_port)

# Creating an empty vector to store
# Portfolio Sharpe Ratio

sharpe_ratio <- vector('numeric', length = num_port)
for (i in seq_along(port_returns)) {
  
  wts <- runif(length(tickers))
  wts <- wts/sum(wts)
  
  # Storing weight in the matrix
  all_wts[i,] <- wts
  
  # Portfolio returns
  
  port_ret <- sum(wts * mean_ret)
  port_ret <- ((port_ret + 1)^252) - 1
  
  # Storing Portfolio Returns values
  port_returns[i] <- port_ret
  
  
  # Creating and storing portfolio risk
  port_sd <- sqrt(t(wts) %*% (cov_mat  %*% wts))
  port_risk[i] <- port_sd
  
  # Creating and storing Portfolio Sharpe Ratios
  # Assuming 0% Risk free rate
  
  sr <- port_ret/port_sd
  sharpe_ratio[i] <- sr
  
}
# Storing the values in the table
portfolio_values <- tibble(Return = port_returns,
                  Risk = port_risk,
                  SharpeRatio = sharpe_ratio)


# Converting matrix to a tibble and changing column names
all_wts <- tk_tbl(all_wts)

colnames(all_wts) <- colnames(log_returns_xts)

# Combing all the values together
portfolio_values <- tk_tbl(cbind(all_wts, portfolio_values))

head(portfolio_values)
## # A tibble: 6 × 8
##   ADANIPOWER.NS HDFCBANK.NS HINDUNILVR.NS INFY.NS RELIANCE.NS Return  Risk
##           <dbl>       <dbl>         <dbl>   <dbl>       <dbl>  <dbl> <dbl>
## 1        0.113      0.595         0.111    0.171      0.00938  0.228 0.213
## 2        0.298      0.152         0.106    0.159      0.285    0.328 0.263
## 3        0.451      0.00849       0.0791   0.268      0.194    0.369 0.324
## 4        0.0436     0.523         0.00295  0.0932     0.337    0.248 0.220
## 5        0.326      0.215         0.282    0.0463     0.130    0.311 0.263
## 6        0.345      0.0388        0.267    0.0619     0.288    0.344 0.280
## # … with 1 more variable: SharpeRatio <dbl>
min_var <- portfolio_values[which.min(portfolio_values$Risk),]
max_sr <- portfolio_values[which.max(portfolio_values$SharpeRatio),]
print(min_var)
## # A tibble: 1 × 8
##   ADANIPOWER.NS HDFCBANK.NS HINDUNILVR.NS INFY.NS RELIANCE.NS Return  Risk
##           <dbl>       <dbl>         <dbl>   <dbl>       <dbl>  <dbl> <dbl>
## 1        0.0199       0.277         0.361   0.217       0.125  0.238 0.182
## # … with 1 more variable: SharpeRatio <dbl>
print(max_sr)
## # A tibble: 1 × 8
##   ADANIPOWER.NS HDFCBANK.NS HINDUNILVR.NS INFY.NS RELIANCE.NS Return  Risk
##           <dbl>       <dbl>         <dbl>   <dbl>       <dbl>  <dbl> <dbl>
## 1        0.0945    0.000944         0.339   0.257       0.308  0.293 0.205
## # … with 1 more variable: SharpeRatio <dbl>
p <- min_var %>%
  gather(ADANIPOWER.NS:RELIANCE.NS, key = Asset,
         value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  ggplot(aes(x = fct_reorder(Asset,Weights), y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_classic() +
  labs(x = 'Assets', y = 'Weights', title = "Minimum Variance Portfolio Weights") +
  scale_y_continuous(labels = scales::percent) 

ggplotly(p)
p <- max_sr %>%
  gather(ADANIPOWER.NS:RELIANCE.NS, key = Asset,
         value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  ggplot(aes(x = fct_reorder(Asset,Weights), y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = 'Assets', y = 'Weights', title = "Tangency Portfolio Weights") +
  scale_y_continuous(labels = scales::percent) 

ggplotly(p)
p <- portfolio_values %>%
  ggplot(aes(x = Risk, y = Return, color = SharpeRatio)) +
  geom_point() +
  theme_classic() +
  scale_y_continuous(labels = scales::percent) +
  scale_x_continuous(labels = scales::percent) +
  labs(x = 'Annualized Risk',
       y = 'Annualized Returns',
       title = "Portfolio Optimization & Efficient Frontier") +
  geom_point(aes(x = Risk,
                 y = Return), data = min_var, color = 'red') +
  geom_point(aes(x = Risk,
                 y = Return), data = max_sr, color = 'red') +
  annotate('text', x = 0.21, y = 0.28, label = "Tangency Portfolio") +
  annotate('text', x = 0.21, y = 0.21, label = "Minimum variance portfolio") 

ggplotly(p)