R Prep

# rm(list=ls())
# install.packages("quantmod")
# install.packages("psych")
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(psych)

Data Acquisition

getSymbols(c("AAPL", "TSLA", "MSFT", "WMT"))
## [1] "AAPL" "TSLA" "MSFT" "WMT"
p.aapl <- AAPL[,6]
p.tsla <- TSLA[,6]
p.msft <- MSFT[,6]
p.wmt  <- WMT[,6]

p.all <- merge(p.aapl, p.tsla)
p.all <- merge(p.all, p.msft)
p.all <- merge(p.all, p.wmt)
p.all <- na.omit(p.all)

r.aapl <- dailyReturn(AAPL[,6])
r.tsla <- dailyReturn(TSLA[,6])
r.msft <- dailyReturn(MSFT[,6])
r.wmt  <- dailyReturn(WMT[,6])

r.all <- merge(r.aapl, r.tsla)
r.all <- merge(r.all, r.msft)
r.all <- merge(r.all, r.wmt)
r.all <- na.omit(r.all)

colnames(r.all) <- c("AAPL", "TSLA", "MSFT", "WMT")

r.all[1,]
##                   AAPL TSLA        MSFT         WMT
## 2010-06-29 -0.04521044    0 -0.04113537 -0.01351607
r.all[dim(r.all)[1],]
##                  AAPL      TSLA       MSFT         WMT
## 2024-07-02 0.01623993 0.1019727 0.00558314 0.008743277
r_precovid  <- window(r.all, start = "2010-06-29", end = "2019-12-31")
r_covid     <- window(r.all, start = "2020-01-01", end = "2021-12-31")
r_postcovid <- window(r.all, start = "2022-01-01", end = "2024-07-02")

# Returns Descriptive Statistics 

describe(r_precovid)
##      vars    n mean   sd median trimmed  mad   min  max range  skew kurtosis se
## AAPL    1 2394    0 0.02      0       0 0.01 -0.12 0.09  0.21 -0.22     4.62  0
## TSLA    2 2394    0 0.03      0       0 0.02 -0.19 0.24  0.44  0.51     6.29  0
## MSFT    3 2394    0 0.01      0       0 0.01 -0.11 0.10  0.22  0.08     6.57  0
## WMT     4 2394    0 0.01      0       0 0.01 -0.10 0.11  0.21  0.16    16.11  0
describe(r_covid)
##      vars   n mean   sd median trimmed  mad   min  max range  skew kurtosis se
## AAPL    1 505 0.00 0.02      0    0.00 0.02 -0.13 0.12  0.25 -0.01     5.26  0
## TSLA    2 505 0.01 0.05      0    0.01 0.03 -0.21 0.20  0.41  0.09     3.43  0
## MSFT    3 505 0.00 0.02      0    0.00 0.01 -0.15 0.14  0.29 -0.08     9.46  0
## WMT     4 505 0.00 0.02      0    0.00 0.01 -0.09 0.12  0.21  1.05    12.67  0
describe(r_postcovid)
##      vars   n mean   sd median trimmed  mad   min  max range  skew kurtosis se
## AAPL    1 627    0 0.02      0       0 0.01 -0.06 0.09  0.15  0.28     2.31  0
## TSLA    2 627    0 0.04      0       0 0.03 -0.12 0.15  0.28  0.08     1.26  0
## MSFT    3 627    0 0.02      0       0 0.02 -0.08 0.08  0.16  0.08     1.65  0
## WMT     4 627    0 0.01      0       0 0.01 -0.11 0.07  0.18 -1.42    15.24  0
cor(r_precovid)
##           AAPL      TSLA      MSFT       WMT
## AAPL 1.0000000 0.2453949 0.4473265 0.2204632
## TSLA 0.2453949 1.0000000 0.2550375 0.1297112
## MSFT 0.4473265 0.2550375 1.0000000 0.3014131
## WMT  0.2204632 0.1297112 0.3014131 1.0000000
cor(r_covid)
##           AAPL      TSLA      MSFT       WMT
## AAPL 1.0000000 0.4666709 0.8062024 0.4731757
## TSLA 0.4666709 1.0000000 0.4766670 0.1544624
## MSFT 0.8062024 0.4766670 1.0000000 0.5159741
## WMT  0.4731757 0.1544624 0.5159741 1.0000000
cor(r_postcovid)
##           AAPL      TSLA      MSFT       WMT
## AAPL 1.0000000 0.5415414 0.6956278 0.2561616
## TSLA 0.5415414 1.0000000 0.4232098 0.1497285
## MSFT 0.6956278 0.4232098 1.0000000 0.2362502
## WMT  0.2561616 0.1497285 0.2362502 1.0000000
# Price and Return Time Series

par(mfrow = c(2,4))

plot(p.all[,1], main = "AAPL Price")
plot(p.all[,2], main = "TSLA Price")
plot(p.all[,3], main = "MSFT Price")
plot(p.all[,4], main = "WMT Price")

plot(r.all[,1], main = "AAPL")
plot(r.all[,2], main = "TSLA")
plot(r.all[,3], main = "MSFT")
plot(r.all[,4], main = "WMT")

par(mfrow = c(1,1))

# Return Histograms

par(mfrow = c(3,4))

hist(r_precovid[,1], main = "AAPL Pre-COVID", xlim = c(-0.25, 0.15))
hist(r_precovid[,2], main = "TSLA Pre-COVID", xlim = c(-0.25, 0.15))
hist(r_precovid[,3], main = "MSFT Pre-COVID", xlim = c(-0.25, 0.15))
hist(r_precovid[,4], main = "WMT Pre-COVID", xlim = c(-0.25, 0.15))

hist(r_covid[,1], main = "AAPL COVID", xlim = c(-0.25, 0.15))
hist(r_covid[,2], main = "TSLA COVID", xlim = c(-0.25, 0.15))
hist(r_covid[,3], main = "MSFT COVID", xlim = c(-0.25, 0.15))
hist(r_covid[,4], main = "WMT COVID", xlim = c(-0.25, 0.15))

hist(r_postcovid[,1], main = "AAPL Post-COVID", xlim = c(-0.25, 0.15))
hist(r_postcovid[,2], main = "TSLA Post-COVID", xlim = c(-0.25, 0.15))
hist(r_postcovid[,3], main = "MSFT Post-COVID", xlim = c(-0.25, 0.15))
hist(r_postcovid[,4], main = "WMT Post-COVID", xlim = c(-0.25, 0.15))

par(mfrow = c(1,1))

Rolling Correlation Matrix Plots

# Assuming df is your data frame with N time series
# N is the number of time series, T is the length of each time series

# Parameters
H <- 150  # Number of days for rolling correlation
T <- dim(r.all)[1]
num_series <- ncol(r.all)  # Number of time series

# Calculate rolling correlations
correlations <- matrix(NA, nrow = T, ncol = choose(num_series, 2))

col_counter <- 1
for (i in 1:(num_series - 1)) {
  for (j in (i + 1):num_series) {
    ts1 <- r.all[, i]
    ts2 <- r.all[, j]
    rolling_cor <- rollapplyr(cbind(ts1, ts2), width = H, FUN = function(x) cor(x[,1], x[,2]), by.column = FALSE, align = "right")
    correlations[, col_counter] <- rolling_cor
    col_counter <- col_counter + 1
  }
}

# Plotting
plot_titles <- combn(colnames(r.all), 2, paste, collapse = " vs ")

par(mfrow = c(3, 2))  # Adjust rows and columns as needed for your number of time series

for (k in 1:ncol(correlations)) {
  plot(correlations[, k], type = 'l', xlab = 'Time', ylab = 'Correlation', main = paste("Rolling correlation:", plot_titles[k]), ylim = c(-0.1, 1))
}

# Reset plotting parameters
par(mfrow = c(1, 1))  # Reset to default plotting layout

Portfolio Allocation

#install.packages("DEOptim")
#library(DEOptim)

#install.packages("PortfolioAnalytics")
library(PortfolioAnalytics)
## Loading required package: foreach
## Loading required package: PerformanceAnalytics
## 
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
## 
##     legend
?portfolio.spec
## starting httpd help server ...
##  done
Port1 <- portfolio.spec(assets=colnames(r.all))

?add.constraint
Port1 <- add.constraint(Port1, type="full_investment")
Port1 <- add.constraint(Port1, type="long_only")

?add.objective
Port1 <- add.objective(Port1, type="risk", name="StdDev")

?optimize.portfolio

result <- optimize.portfolio(r.all, portfolio = Port1)
## Leverage constraint min_sum and max_sum are restrictive, 
##               consider relaxing. e.g. 'full_investment' constraint should be min_sum=0.99 and max_sum=1.01
## Iteration: 1 bestvalit: 0.011039 bestmemit:    0.046000    0.014000    0.260000    0.680000
## Iteration: 2 bestvalit: 0.011039 bestmemit:    0.046000    0.014000    0.260000    0.680000
## Iteration: 3 bestvalit: 0.011039 bestmemit:    0.046000    0.014000    0.260000    0.680000
## Iteration: 4 bestvalit: 0.011039 bestmemit:    0.046000    0.014000    0.260000    0.680000
## Iteration: 5 bestvalit: 0.011039 bestmemit:    0.046000    0.014000    0.260000    0.680000
## Iteration: 6 bestvalit: 0.011039 bestmemit:    0.046000    0.014000    0.260000    0.680000
## Iteration: 7 bestvalit: 0.011039 bestmemit:    0.046000    0.014000    0.260000    0.680000
## Iteration: 8 bestvalit: 0.011039 bestmemit:    0.046000    0.014000    0.260000    0.680000
## [1] 0.046 0.014 0.260 0.680