# 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)
