# Load Required Libraries

library(xts)
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
library(zoo)
library(quantmod)
## Loading required package: TTR
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
# Create the Data Files


start.date <- "2014-04-01"
end.date   <- "2019-04-01"

# Download each stock individually
getSymbols("NVDA", from = start.date, to = end.date, src = "yahoo", auto.assign = TRUE)
## [1] "NVDA"
getSymbols("MSFT", from = start.date, to = end.date, src = "yahoo", auto.assign = TRUE)
## [1] "MSFT"
getSymbols("BAC",  from = start.date, to = end.date, src = "yahoo", auto.assign = TRUE)
## [1] "BAC"
getSymbols("PLD",  from = start.date, to = end.date, src = "yahoo", auto.assign = TRUE)
## [1] "PLD"
data.NVDA <- NVDA
data.MSFT <- MSFT
data.BAC  <- BAC
data.PLD  <- PLD

names(data.NVDA) <- paste0("NVDA.", c("Open","High","Low","Close","Volume","Adjusted"))
names(data.MSFT) <- paste0("MSFT.", c("Open","High","Low","Close","Volume","Adjusted"))
names(data.BAC)  <- paste0("BAC.",  c("Open","High","Low","Close","Volume","Adjusted"))
names(data.PLD)  <- paste0("PLD.",  c("Open","High","Low","Close","Volume","Adjusted"))


# Subset to Period (Year 3)

hw2.start <- "2016-04-01"
hw2.end   <- "2017-03-31"

NVDA.hw2 <- window(data.NVDA, start = hw2.start, end = hw2.end)
MSFT.hw2 <- window(data.MSFT, start = hw2.start, end = hw2.end)
BAC.hw2  <- window(data.BAC,  start = hw2.start, end = hw2.end)
PLD.hw2  <- window(data.PLD,  start = hw2.start, end = hw2.end)


# PART A – Individual Security Returns


# 1. Price Returns (using Close prices)

NVDA.close <- NVDA.hw2$NVDA.Close
MSFT.close <- MSFT.hw2$MSFT.Close
BAC.close  <- BAC.hw2$BAC.Close
PLD.close  <- PLD.hw2$PLD.Close

NVDA.pr <- diff(NVDA.close) / lag(NVDA.close, 1); NVDA.pr <- na.omit(NVDA.pr)
MSFT.pr <- diff(MSFT.close) / lag(MSFT.close, 1); MSFT.pr <- na.omit(MSFT.pr)
BAC.pr  <- diff(BAC.close)  / lag(BAC.close, 1);  BAC.pr  <- na.omit(BAC.pr)
PLD.pr  <- diff(PLD.close)  / lag(PLD.close, 1);  PLD.pr  <- na.omit(PLD.pr)

# Cumulative price return (growth of $1)
NVDA.pr.cum <- cumprod(1 + NVDA.pr)
MSFT.pr.cum <- cumprod(1 + MSFT.pr)
BAC.pr.cum  <- cumprod(1 + BAC.pr)
PLD.pr.cum  <- cumprod(1 + PLD.pr)

cat("=== Total Price Returns (Year 3) ===\n")
## === Total Price Returns (Year 3) ===
cat("NVDA:", round((as.numeric(tail(NVDA.pr.cum, 1)) - 1) * 100, 2), "%\n")
## NVDA: 201.33 %
cat("MSFT:", round((as.numeric(tail(MSFT.pr.cum, 1)) - 1) * 100, 2), "%\n")
## MSFT: 18.52 %
cat("BAC: ", round((as.numeric(tail(BAC.pr.cum, 1)) - 1) * 100, 2), "%\n")
## BAC:  73.97 %
cat("PLD: ", round((as.numeric(tail(PLD.pr.cum, 1)) - 1) * 100, 2), "%\n")
## PLD:  16.27 %
# 2a. Total Gross Returns (using Adjusted prices)

NVDA.adj <- NVDA.hw2$NVDA.Adjusted
MSFT.adj <- MSFT.hw2$MSFT.Adjusted
BAC.adj  <- BAC.hw2$BAC.Adjusted
PLD.adj  <- PLD.hw2$PLD.Adjusted

NVDA.gr <- diff(NVDA.adj) / lag(NVDA.adj, 1); NVDA.gr <- na.omit(NVDA.gr)
MSFT.gr <- diff(MSFT.adj) / lag(MSFT.adj, 1); MSFT.gr <- na.omit(MSFT.gr)
BAC.gr  <- diff(BAC.adj)  / lag(BAC.adj, 1);  BAC.gr  <- na.omit(BAC.gr)
PLD.gr  <- diff(PLD.adj)  / lag(PLD.adj, 1);  PLD.gr  <- na.omit(PLD.gr)

# Cumulative gross return (growth of $1)
NVDA.gr.cum <- cumprod(1 + NVDA.gr)
MSFT.gr.cum <- cumprod(1 + MSFT.gr)
BAC.gr.cum  <- cumprod(1 + BAC.gr)
PLD.gr.cum  <- cumprod(1 + PLD.gr)

cat("\n=== Total Gross Returns (Year 3) ===\n")
## 
## === Total Gross Returns (Year 3) ===
cat("NVDA:", round((as.numeric(tail(NVDA.gr.cum, 1)) - 1) * 100, 2), "%\n")
## NVDA: 203.5 %
cat("MSFT:", round((as.numeric(tail(MSFT.gr.cum, 1)) - 1) * 100, 2), "%\n")
## MSFT: 21.63 %
cat("BAC: ", round((as.numeric(tail(BAC.gr.cum, 1)) - 1) * 100, 2), "%\n")
## BAC:  76.56 %
cat("PLD: ", round((as.numeric(tail(PLD.gr.cum, 1)) - 1) * 100, 2), "%\n")
## PLD:  20.27 %
# 2b. Logarithmic Gross Returns

NVDA.loggr <- diff(log(NVDA.adj)); NVDA.loggr <- na.omit(NVDA.loggr)
MSFT.loggr <- diff(log(MSFT.adj)); MSFT.loggr <- na.omit(MSFT.loggr)
BAC.loggr  <- diff(log(BAC.adj));  BAC.loggr  <- na.omit(BAC.loggr)
PLD.loggr  <- diff(log(PLD.adj));  PLD.loggr  <- na.omit(PLD.loggr)

# Cumulative log return
NVDA.loggr.cum <- cumsum(NVDA.loggr)
MSFT.loggr.cum <- cumsum(MSFT.loggr)
BAC.loggr.cum  <- cumsum(BAC.loggr)
PLD.loggr.cum  <- cumsum(PLD.loggr)

cat("\n=== Total Log Gross Returns (Year 3) ===\n")
## 
## === Total Log Gross Returns (Year 3) ===
cat("NVDA:", round(as.numeric(tail(NVDA.loggr.cum, 1)) * 100, 2), "%\n")
## NVDA: 111.02 %
cat("MSFT:", round(as.numeric(tail(MSFT.loggr.cum, 1)) * 100, 2), "%\n")
## MSFT: 19.58 %
cat("BAC: ", round(as.numeric(tail(BAC.loggr.cum, 1)) * 100, 2), "%\n")
## BAC:  56.85 %
cat("PLD: ", round(as.numeric(tail(PLD.loggr.cum, 1)) * 100, 2), "%\n")
## PLD:  18.46 %
# 2c. Are the results the same?

cat("\n=== Comparison: Are the Results the Same? ===\n")
## 
## === Comparison: Are the Results the Same? ===
cat("No. Price returns use Close prices and capture only capital gains.\n")
## No. Price returns use Close prices and capture only capital gains.
cat("Gross returns use Adjusted prices and include dividends and splits.\n")
## Gross returns use Adjusted prices and include dividends and splits.
cat("Log gross returns are the natural log transformation of gross returns.\n")
## Log gross returns are the natural log transformation of gross returns.
cat("The three measures move in the same direction but differ numerically.\n")
## The three measures move in the same direction but differ numerically.
# 3. Plot: Total Price Returns vs Total Gross Returns

par(mfrow = c(2, 2))

# NVDA
y.range <- range(c(as.numeric(NVDA.pr.cum), as.numeric(NVDA.gr.cum)))
plot(index(NVDA.pr.cum), as.numeric(NVDA.pr.cum), type = "l", col = "steelblue",
     lwd = 2, ylim = y.range, xlab = "Date", ylab = "Growth of $1",
     main = "NVDA: Price vs Gross Return")
lines(index(NVDA.gr.cum), as.numeric(NVDA.gr.cum), col = "firebrick", lwd = 2)
abline(h = 1, lty = 2, col = "gray50")
legend("topleft", legend = c("Price Return", "Gross Return"),
       col = c("steelblue", "firebrick"), lwd = 2, cex = 0.7)

# MSFT
y.range <- range(c(as.numeric(MSFT.pr.cum), as.numeric(MSFT.gr.cum)))
plot(index(MSFT.pr.cum), as.numeric(MSFT.pr.cum), type = "l", col = "steelblue",
     lwd = 2, ylim = y.range, xlab = "Date", ylab = "Growth of $1",
     main = "MSFT: Price vs Gross Return")
lines(index(MSFT.gr.cum), as.numeric(MSFT.gr.cum), col = "firebrick", lwd = 2)
abline(h = 1, lty = 2, col = "gray50")
legend("topleft", legend = c("Price Return", "Gross Return"),
       col = c("steelblue", "firebrick"), lwd = 2, cex = 0.7)

# BAC
y.range <- range(c(as.numeric(BAC.pr.cum), as.numeric(BAC.gr.cum)))
plot(index(BAC.pr.cum), as.numeric(BAC.pr.cum), type = "l", col = "steelblue",
     lwd = 2, ylim = y.range, xlab = "Date", ylab = "Growth of $1",
     main = "BAC: Price vs Gross Return")
lines(index(BAC.gr.cum), as.numeric(BAC.gr.cum), col = "firebrick", lwd = 2)
abline(h = 1, lty = 2, col = "gray50")
legend("topleft", legend = c("Price Return", "Gross Return"),
       col = c("steelblue", "firebrick"), lwd = 2, cex = 0.7)

# PLD
y.range <- range(c(as.numeric(PLD.pr.cum), as.numeric(PLD.gr.cum)))
plot(index(PLD.pr.cum), as.numeric(PLD.pr.cum), type = "l", col = "steelblue",
     lwd = 2, ylim = y.range, xlab = "Date", ylab = "Growth of $1",
     main = "PLD: Price vs Gross Return")
lines(index(PLD.gr.cum), as.numeric(PLD.gr.cum), col = "firebrick", lwd = 2)
abline(h = 1, lty = 2, col = "gray50")
legend("topleft", legend = c("Price Return", "Gross Return"),
       col = c("steelblue", "firebrick"), lwd = 2, cex = 0.7)

par(mfrow = c(1, 1))


# PART B – Portfolio Returns


# Setup: Merge Adjusted Prices

prices <- merge(NVDA.adj, MSFT.adj, BAC.adj, PLD.adj)
prices <- na.omit(prices)
colnames(prices) <- c("NVDA", "MSFT", "BAC", "PLD")

# Daily simple returns from adjusted prices
ret <- diff(prices) / lag(prices, 1)
ret <- na.omit(ret)

# Daily gross return factors (1 + r)
gross <- ret + 1

# Identify Quarter Boundaries

dates <- index(prices)
qtr.label <- paste(format(dates, "%Y"), quarters(dates), sep = "-")
qtr.starts <- dates[!duplicated(qtr.label)]

cat("\n=== Rebalance Dates ===\n")
## 
## === Rebalance Dates ===
print(qtr.starts)
## [1] "2016-04-01" "2016-07-01" "2016-10-03" "2017-01-03"
# B1. Equally Weighted Portfolio

n.stocks <- 4
ew.weights <- rep(1 / n.stocks, n.stocks)

ew.daily.ret <- xts(rep(NA, nrow(gross)), order.by = index(gross))
w <- ew.weights

for (i in 1:nrow(gross)) {
  d <- index(gross)[i]
  
  # Rebalance at start of each quarter
  if (d %in% qtr.starts) {
    w <- ew.weights
  }
  
  day.gross <- as.numeric(gross[i, ])
  port.ret  <- sum(w * day.gross) - 1
  ew.daily.ret[i] <- port.ret
  
  # Let weights drift
  w <- w * day.gross
  w <- w / sum(w)
}

ew.daily.ret <- na.omit(ew.daily.ret)
ew.value <- cumprod(1 + ew.daily.ret)
colnames(ew.value) <- "EW"


# B2. Value Weighted Portfolio

# Value-weighted: weights based on each stock's current
# dollar value at the rebalance date. On day 1, all stocks
# start with equal dollar amounts, then weights drift with
# price changes. At each quarter start, weights are set to
# the proportional value of each holding.

vw.daily.ret <- xts(rep(NA, nrow(gross)), order.by = index(gross))
vw.weight.history <- list()

# Initialize holdings as equal dollar values
holdings <- rep(1, n.stocks)

for (i in 1:nrow(gross)) {
  d <- index(gross)[i]
  
  # At quarter start, set weights to current value proportions
  if (d %in% qtr.starts) {
    w <- holdings / sum(holdings)
    vw.weight.history[[as.character(d)]] <- w
  }
  
  day.gross <- as.numeric(gross[i, ])
  port.ret  <- sum(w * day.gross) - 1
  vw.daily.ret[i] <- port.ret
  
  # Update holdings
  holdings <- holdings * day.gross
  w <- holdings / sum(holdings)
}

vw.daily.ret <- na.omit(vw.daily.ret)
vw.value <- cumprod(1 + vw.daily.ret)
colnames(vw.value) <- "VW"


# B2a. Pie Charts for Each Quarter

n.pies <- length(vw.weight.history)
rows <- ceiling(n.pies / 2)

par(mfrow = c(rows, 2))

colors <- c("steelblue", "darkorange", "firebrick", "darkgreen")

for (nm in names(vw.weight.history)) {
  wts <- round(vw.weight.history[[nm]] * 100, 1)
  lbls <- paste0(c("NVDA", "MSFT", "BAC", "PLD"), "\n", wts, "%")
  pie(vw.weight.history[[nm]],
      labels = lbls,
      col = colors,
      main = paste("VW Weights –", nm))
}

par(mfrow = c(1, 1))

# B3. Plot: EW vs VW Portfolio

y.range <- range(c(as.numeric(ew.value), as.numeric(vw.value)))

plot(index(ew.value), as.numeric(ew.value), type = "l", col = "steelblue",
     lwd = 2, ylim = y.range, xlab = "Date",
     ylab = "Portfolio Value (Growth of $1)",
     main = "Equally Weighted vs Value Weighted Portfolio\nApril 2016 – March 2017")
lines(index(vw.value), as.numeric(vw.value), col = "firebrick", lwd = 2)
abline(h = 1, lty = 2, col = "gray50")
legend("topleft",
       legend = c("Equally Weighted", "Value Weighted"),
       col = c("steelblue", "firebrick"), lwd = 2)