R Markdown
# Install and load necessary packages (uncomment if needed)
# install.packages("quantmod")
# install.packages("PerformanceAnalytics")
# install.packages("ggplot2")
# Install and load necessary packages (uncomment if needed)
# install.packages("quantmod")
# install.packages("PerformanceAnalytics")
# install.packages("ggplot2")
# install.packages("zoo") # Added for rolling standard deviation
# Load the required libraries
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(PerformanceAnalytics)
##
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
library(ggplot2)
library(reshape2)
library(zoo) # Added for rolling standard deviation
# tickers
tickers <- c("SPY", "VUSTX")
# download data from yahoo finance
getSymbols(tickers, src = "yahoo", from = "1997-01-01", to = "2023-05-31", periodicity = "weekly")
## [1] "SPY" "VUSTX"
#weekly returns
data <- merge(Cl(SPY), Cl(VUSTX))
returns <- na.omit(ROC(data, type = "discrete"))
colnames(returns) <- c("SPY_Returns", "VUSTX_Returns")
#rolling std for chart
rolling_sd_SPY <- rollapply(returns$SPY_Returns, width = 20, FUN = sd, fill = NA, align = "right")
rolling_sd_VUSTX <- rollapply(returns$VUSTX_Returns, width = 20, FUN = sd, fill = NA, align = "right")
returns$Rolling_SD_SPY <- rolling_sd_SPY
returns$Rolling_SD_VUSTX <- rolling_sd_VUSTX
returns_long <- data.frame(Date = index(returns), coredata(returns))
returns_long <- melt(returns_long, id.vars = "Date")
# plot returns over time
ggplot(returns_long[returns_long$variable %in% c("SPY_Returns", "VUSTX_Returns"), ],
aes(x = Date, y = value, color = variable)) +
geom_line() +
labs(title = "Weekly Returns of SPY (Stocks) and VUSTX (Bonds)",
x = "Date", y = "Weekly Returns",
color = "Asset") +
theme_minimal()

# plot rolling std
ggplot(returns_long[returns_long$variable %in% c("Rolling_SD_SPY", "Rolling_SD_VUSTX"), ],
aes(x = Date, y = value, color = variable)) +
geom_line() +
labs(title = "20-Week Rolling Standard Deviation of SPY and VUSTX",
x = "Date", y = "Rolling Standard Deviation",
color = "Asset") +
theme_minimal()
## Warning: Removed 38 rows containing missing values or values outside the scale range
## (`geom_line()`).

# plot distribution
ggplot(returns_long[returns_long$variable %in% c("SPY_Returns", "VUSTX_Returns"), ],
aes(x = value, fill = variable)) +
geom_histogram(bins = 50, alpha = 0.5, position = "identity") +
labs(title = "Distribution of Weekly Returns",
x = "Weekly Returns", y = "Frequency",
fill = "Asset") +
theme_minimal()

spy_returns <- returns_long[returns_long$variable == "SPY_Returns", "value"]
vustx_returns <- returns_long[returns_long$variable == "VUSTX_Returns", "value"]
#test for normality with shapiro-wilk
shapiro_spy <- shapiro.test(spy_returns)
shapiro_vustx <- shapiro.test(vustx_returns)
cat("Shapiro-Wilk test for SPY returns:\n")
## Shapiro-Wilk test for SPY returns:
print(shapiro_spy)
##
## Shapiro-Wilk normality test
##
## data: spy_returns
## W = 0.95343, p-value < 2.2e-16
cat("\nShapiro-Wilk test for VUSTX returns:\n")
##
## Shapiro-Wilk test for VUSTX returns:
print(shapiro_vustx)
##
## Shapiro-Wilk normality test
##
## data: vustx_returns
## W = 0.98626, p-value = 3.935e-10
# Q-Q plots
qqnorm(spy_returns, main = "Q-Q Plot for SPY Returns")
qqline(spy_returns, col = "blue")

qqnorm(vustx_returns, main = "Q-Q Plot for VUSTX Returns")
qqline(vustx_returns, col = "blue")

#question 1
#2. Explain the main idea behind the Modern Portfolio Theory.
#The main idea behind the Modern Portfolio Theory is to maximize the return at a given level of risk. Or minimize risk for a given level #of return. A brief description of the steps we would go through to apply modern portfolio theory would be as follows, first we would compute the expected returns using historical data, next my team would calculate the variance and standard deviation of each asset in our invest able universe. From here the next step would be to calculate the covariance and correlation of each asset and begin to construct the covariance matrix. From here we would solve a minimization problem to find the least risk we could take for a given level of expected returns, using something like a LaGrange multiplier.
# question 1
# 4
# Install and load necessary packages (uncomment if needed)
# install.packages("quantmod")
# install.packages("PerformanceAnalytics")
# install.packages("quadprog")
# Install and load necessary packages (uncomment if needed)
# install.packages("quantmod")
# install.packages("PerformanceAnalytics")
# install.packages("Rsolnp")
# Load the required libraries
# Install and load necessary packages (uncomment if needed)
# install.packages("quantmod")
# install.packages("PerformanceAnalytics")
# install.packages("Rsolnp")
# Load the required libraries
library(quantmod)
library(PerformanceAnalytics)
library(Rsolnp)
tickers <- c("SPY", "VUSTX")
getSymbols(tickers, src = "yahoo", from = "1997-01-01", to = "2023-05-31", periodicity = "weekly")
## [1] "SPY" "VUSTX"
prices <- merge(Cl(SPY), Cl(VUSTX))
returns <- na.omit(ROC(prices, type = "discrete"))
colnames(returns) <- c("SPY_Returns", "VUSTX_Returns")
mean_returns <- colMeans(returns) * 52
std_devs <- apply(returns, 2, sd) * sqrt(52)
cov_matrix <- cov(returns) * 52
# risk-free rate
risk_free_rate <- 0
# optimization function
opt_portfolio <- function(mean_returns, cov_matrix, risk_free_rate) {
n <- length(mean_returns)
objective_function <- function(weights) {
portfolio_return <- sum(weights * mean_returns)
portfolio_volatility <- sqrt(t(weights) %*% cov_matrix %*% weights)
sharpe_ratio <- (portfolio_return - risk_free_rate) / portfolio_volatility
return(-sharpe_ratio)
}
# sum(weights) = 1
eq_constraint <- function(weights) {
return(sum(weights) - 1)
}
# Initial guess
init_weights <- rep(1/n, n)
# Optimize portfolio weights
opt_result <- solnp(pars = init_weights,
fun = objective_function,
eqfun = eq_constraint,
eqB = 0,
LB = rep(0, n),
UB = rep(1, n))
return(opt_result$pars)
}
optimal_weights <- opt_portfolio(mean_returns, cov_matrix, risk_free_rate)
## Warning in cbind(temp, funv): number of rows of result is not a multiple of
## vector length (arg 1)
##
## Iter: 1 fn: -0.4774 Pars: 0.71023 0.28977
## Warning in cbind(temp, funv): number of rows of result is not a multiple of
## vector length (arg 1)
##
## Iter: 2 fn: -0.4774 Pars: 0.71023 0.28977
## solnp--> Completed in 2 iterations
# Portfolio return, volatility, and Sharpe ratio
optimal_return <- sum(optimal_weights * mean_returns)
optimal_volatility <- sqrt(t(optimal_weights) %*% cov_matrix %*% optimal_weights)
sharpe_ratio <- (optimal_return - risk_free_rate) / optimal_volatility
# Calculate correlation between SPY and VUSTX returns over the full period
correlation_spy_vustx <- cor(returns$SPY_Returns, returns$VUSTX_Returns)
# Create a dataframe to display results
result_metrics <- data.frame(
Metric = c("Mean Return (Annualized)", "Standard Deviation (Annualized)", "Optimal Weight", "Sharpe Ratio"),
SPY = c(mean_returns["SPY_Returns"], std_devs["SPY_Returns"], optimal_weights[1], ""),
VUSTX = c(mean_returns["VUSTX_Returns"], std_devs["VUSTX_Returns"], optimal_weights[2], ""),
Optimal_Portfolio = c(optimal_return, optimal_volatility, NA, sharpe_ratio)
)
cat("Optimal Risky Portfolio Metrics:\n")
## Optimal Risky Portfolio Metrics:
print(result_metrics)
## Metric SPY VUSTX
## 1 Mean Return (Annualized) 0.0801928046110917 0.00265254035560577
## 2 Standard Deviation (Annualized) 0.173962815200851 0.110907241698559
## 3 Optimal Weight 0.710225974634222 0.289774025365778
## 4 Sharpe Ratio
## Optimal_Portfolio
## 1 0.05772365
## 2 0.12092093
## 3 NA
## 4 0.47736689
cat("\nExpected Return of Optimal Portfolio (Annualized):", round(optimal_return, 4))
##
## Expected Return of Optimal Portfolio (Annualized): 0.0577
cat("\nStandard Deviation of Optimal Portfolio (Annualized):", round(optimal_volatility, 4))
##
## Standard Deviation of Optimal Portfolio (Annualized): 0.1209
cat("\nSharpe Ratio of Optimal Portfolio:", round(sharpe_ratio, 4))
##
## Sharpe Ratio of Optimal Portfolio: 0.4774
cat("\n\nRisk-Free Rate Used:", risk_free_rate * 100, "%\n")
##
##
## Risk-Free Rate Used: 0 %
# Output correlation of SPY and VUSTX over the full period
cat("\nCorrelation between SPY and VUSTX over the full period:", round(correlation_spy_vustx, 4), "\n")
##
## Correlation between SPY and VUSTX over the full period: -0.2111
# Question1
# 6 show client what would have happened in each recession
# Install and load necessary packages (uncomment if needed)
# install.packages("quantmod")
# install.packages("PerformanceAnalytics")
# install.packages("ggplot2")
# Load the required libraries
#install.packages("corrplot")
# Load the corrplot package
library(corrplot)
## corrplot 0.92 loaded
library(quantmod)
library(PerformanceAnalytics)
library(ggplot2)
tickers <- c("SPY", "VUSTX")
getSymbols(tickers, src = "yahoo", from = "1997-01-01", to = "2023-05-31", periodicity = "weekly")
## [1] "SPY" "VUSTX"
prices <- merge(Cl(SPY), Cl(VUSTX))
returns <- na.omit(ROC(prices, type = "discrete"))
colnames(returns) <- c("SPY_Returns", "VUSTX_Returns")
# recessions
recession_periods <- list(
"Dot-com Bubble" = c("2001-03-01", "2001-11-30"),
"Great Recession" = c("2007-12-01", "2009-03-31"),
"COVID-19 Recession" = c("2020-02-01", "2023-05-31")
)
analyze_recession <- function(start_date, end_date, returns, optimal_weights) {
# Filter the data for the recession period
recession_returns <- returns[index(returns) >= start_date & index(returns) <= end_date, ]
mean_returns <- colMeans(recession_returns) * 52
std_devs <- apply(recession_returns, 2, sd) * sqrt(52)
cov_matrix <- cov(recession_returns) * 52
correlation_matrix <- cor(recession_returns)
portfolio_return <- sum(optimal_weights * mean_returns)
portfolio_volatility <- sqrt(t(optimal_weights) %*% cov_matrix %*% optimal_weights)
# summary data frame
recession_summary <- data.frame(
Metric = c("Mean Return (Annualized)", "Standard Deviation (Annualized)", "Correlation"),
SPY = c(mean_returns["SPY_Returns"], std_devs["SPY_Returns"], correlation_matrix[1, 2]),
VUSTX = c(mean_returns["VUSTX_Returns"], std_devs["VUSTX_Returns"], NA)
)
#display
cat(paste("Recession period:", start_date, "to", end_date, "\n"))
print(recession_summary)
cat("\nExpected Return of Portfolio (Annualized):", round(portfolio_return, 4))
cat("\nStandard Deviation of Portfolio (Annualized):", round(portfolio_volatility, 4))
cat("\n\n")
}
optimal_weights <- c(0.7102260, 0.289774025365778) # actual weights from above
# portfolio performance during each recession
for (recession_name in names(recession_periods)) {
start_date <- recession_periods[[recession_name]][1]
end_date <- recession_periods[[recession_name]][2]
cat("\n", recession_name, ":\n")
analyze_recession(start_date, end_date, returns, optimal_weights)
}
##
## Dot-com Bubble :
## Recession period: 2001-03-01 to 2001-11-30
## Metric SPY VUSTX
## 1 Mean Return (Annualized) -0.09211963 0.02538946
## 2 Standard Deviation (Annualized) 0.23526779 0.09978496
## 3 Correlation -0.01036029 NA
##
## Expected Return of Portfolio (Annualized): -0.0581
## Standard Deviation of Portfolio (Annualized): 0.1693
##
##
## Great Recession :
## Recession period: 2007-12-01 to 2009-03-31
## Metric SPY VUSTX
## 1 Mean Return (Annualized) -0.4179294 0.0424250
## 2 Standard Deviation (Annualized) 0.2805457 0.1354035
## 3 Correlation -0.2929740 NA
##
## Expected Return of Portfolio (Annualized): -0.2845
## Standard Deviation of Portfolio (Annualized): 0.1915
##
##
## COVID-19 Recession :
## Recession period: 2020-02-01 to 2023-05-31
## Metric SPY VUSTX
## 1 Mean Return (Annualized) 0.09341091 -0.1194986
## 2 Standard Deviation (Annualized) 0.19821961 0.1544739
## 3 Correlation 0.04171946 NA
##
## Expected Return of Portfolio (Annualized): 0.0317
## Standard Deviation of Portfolio (Annualized): 0.1495
recession_periods <- list(
"Dot-com Bubble" = c("2001-03-01", "2001-11-30"),
"Great Recession" = c("2007-12-01", "2009-03-31"),
"COVID-19 Recession" = c("2020-02-01", "2023-05-31")
)
tickers <- c("SPY", "VUSTX")
getSymbols(tickers, src = "yahoo", from = "1997-01-01", to = "2023-05-31", periodicity = "weekly")
## [1] "SPY" "VUSTX"
prices <- merge(Cl(SPY), Cl(VUSTX))
returns <- na.omit(ROC(prices, type = "discrete"))
colnames(returns) <- c("SPY_Returns", "VUSTX_Returns")
for (recession_name in names(recession_periods)) {
start_date <- recession_periods[[recession_name]][1]
end_date <- recession_periods[[recession_name]][2]
cat("\n", recession_name, ":\n")
# plot_recession_correlation(start_date, end_date, returns)
}
##
## Dot-com Bubble :
##
## Great Recession :
##
## COVID-19 Recession :
# Load the required libraries
library(quantmod)
library(PerformanceAnalytics)
library(Rsolnp)
opt_portfolio <- function(mean_returns, cov_matrix, risk_free_rate) {
n <- length(mean_returns)
objective_function <- function(weights) {
portfolio_return <- sum(weights * mean_returns)
portfolio_volatility <- sqrt(t(weights) %*% cov_matrix %*% weights)
sharpe_ratio <- (portfolio_return - risk_free_rate) / portfolio_volatility
return(-sharpe_ratio)
}
eq_constraint <- function(weights) {
return(sum(weights) - 1)
}
init_weights <- rep(1/n, n)
opt_result <- solnp(pars = init_weights,
fun = objective_function,
eqfun = eq_constraint,
eqB = 0,
LB = rep(0, n),
UB = rep(1, n))
optimal_weights <- opt_result$pars
portfolio_return <- sum(optimal_weights * mean_returns)
portfolio_volatility <- sqrt(t(optimal_weights) %*% cov_matrix %*% optimal_weights)
sharpe_ratio <- (portfolio_return - risk_free_rate) / portfolio_volatility
return(list(weights = optimal_weights,
return = portfolio_return,
risk = portfolio_volatility,
sharpe = sharpe_ratio))
}
# scenarios to test
risk_free_rates <- c(0, 2, 5) # 0%, 2%, 5%
#scenario analysis
scenario_results <- lapply(risk_free_rates, function(rf) {
result <- opt_portfolio(mean_returns, cov_matrix, rf)
data.frame(
Risk_Free_Rate = rf,
SPY_Weight = result$weights[1],
VUSTX_Weight = result$weights[2],
Expected_Return = result$return,
Portfolio_Risk = result$risk,
Sharpe_Ratio = result$sharpe
)
})
## Warning in cbind(temp, funv): number of rows of result is not a multiple of
## vector length (arg 1)
##
## Iter: 1 fn: -0.4774 Pars: 0.71023 0.28977
## Warning in cbind(temp, funv): number of rows of result is not a multiple of
## vector length (arg 1)
##
## Iter: 2 fn: -0.4774 Pars: 0.71023 0.28977
## solnp--> Completed in 2 iterations
## Warning in cbind(temp, funv): number of rows of result is not a multiple of
## vector length (arg 1)
##
## Iter: 1 fn: 11.0357 Pars: 0.999999991626 0.000000008374
## Warning in cbind(temp, funv): number of rows of result is not a multiple of
## vector length (arg 1)
##
## Iter: 2 fn: 11.0357 Pars: 0.999999995555 0.000000004445
## solnp--> Completed in 2 iterations
## Warning in cbind(temp, funv): number of rows of result is not a multiple of
## vector length (arg 1)
##
## Iter: 1 fn: 28.2808 Pars: 0.999999991418 0.000000008582
## Warning in cbind(temp, funv): number of rows of result is not a multiple of
## vector length (arg 1)
##
## Iter: 2 fn: 28.2808 Pars: 0.999999995334 0.000000004666
## solnp--> Completed in 2 iterations
scenario_df <- do.call(rbind, scenario_results)
print(scenario_df)
## Risk_Free_Rate SPY_Weight VUSTX_Weight Expected_Return Portfolio_Risk
## 1 0 0.710226 2.897740e-01 0.05772365 0.1209209
## 2 2 1.000000 4.444572e-09 0.08019280 0.1739628
## 3 5 1.000000 4.666057e-09 0.08019280 0.1739628
## Sharpe_Ratio
## 1 0.4773669
## 2 -11.0357331
## 3 -28.2807979
cat("\nAnalysis of Sensitivity to Changing Risk-Free Rates:\n")
##
## Analysis of Sensitivity to Changing Risk-Free Rates:
for (i in 1:nrow(scenario_df)) {
cat(paste0("\nRisk-Free Rate: ", scenario_df$Risk_Free_Rate[i] * 100, "%\n"))
cat(paste("Optimal Weights (SPY, VUSTX):", round(scenario_df$SPY_Weight[i], 4), ",", round(scenario_df$VUSTX_Weight[i], 4)), "\n")
cat(paste("Expected Return (Annualized):", round(scenario_df$Expected_Return[i], 4)), "\n")
cat(paste("Portfolio Risk (Standard Deviation):", round(scenario_df$Portfolio_Risk[i], 4)), "\n")
cat(paste("Sharpe Ratio:", round(scenario_df$Sharpe_Ratio[i], 4)), "\n")
}
##
## Risk-Free Rate: 0%
## Optimal Weights (SPY, VUSTX): 0.7102 , 0.2898
## Expected Return (Annualized): 0.0577
## Portfolio Risk (Standard Deviation): 0.1209
## Sharpe Ratio: 0.4774
##
## Risk-Free Rate: 200%
## Optimal Weights (SPY, VUSTX): 1 , 0
## Expected Return (Annualized): 0.0802
## Portfolio Risk (Standard Deviation): 0.174
## Sharpe Ratio: -11.0357
##
## Risk-Free Rate: 500%
## Optimal Weights (SPY, VUSTX): 1 , 0
## Expected Return (Annualized): 0.0802
## Portfolio Risk (Standard Deviation): 0.174
## Sharpe Ratio: -28.2808
# alpha for each period
calculate_alpha <- function(start_date, end_date, returns, portfolio_return) {
period_returns <- subset(returns, index(returns) >= start_date & index(returns) <= end_date)
actual_return <- mean(period_returns$SPY_Returns) * 52
alpha <- actual_return - portfolio_return
return(alpha)
}
alpha_recessions <- sapply(names(recession_periods), function(recession) {
period <- recession_periods[[recession]]
start_date <- period[1]
end_date <- period[2]
calculate_alpha(start_date, end_date, returns, optimal_return)
})
#alpha whole period
alpha_whole_period <- calculate_alpha(min(index(returns)), max(index(returns)), returns, optimal_return)
#
cat("Alpha for Each Recession:\n")
## Alpha for Each Recession:
for (i in 1:length(alpha_recessions)) {
cat(paste(names(alpha_recessions)[i], ":", round(alpha_recessions[i], 4), "\n"))
}
## Dot-com Bubble : -0.1498
## Great Recession : -0.4757
## COVID-19 Recession : 0.0357
cat("\nAlpha for the Whole Period:", round(alpha_whole_period, 4), "\n")
##
## Alpha for the Whole Period: 0.0225
# Load the required libraries
# install.packages("corrplot")
# Load the corrplot package
library(corrplot)
library(quantmod)
library(PerformanceAnalytics)
library(ggplot2)
tickers <- c("SPY", "VUSTX")
getSymbols(tickers, src = "yahoo", from = "1997-01-01", to = "2023-05-31", periodicity = "weekly")
## [1] "SPY" "VUSTX"
prices <- merge(Cl(SPY), Cl(VUSTX))
returns <- na.omit(ROC(prices, type = "discrete"))
colnames(returns) <- c("SPY_Returns", "VUSTX_Returns")
recession_periods <- list(
"Dot-com Bubble" = c("2001-03-01", "2001-11-30"),
"Great Recession" = c("2007-12-01", "2009-03-31"),
"COVID-19 Recession" = c("2020-02-01", "2023-05-31") # ongoing at the time of data
)
analyze_recession <- function(start_date, end_date, returns, optimal_weights, initial_investment = 1000000) {
recession_returns <- returns[index(returns) >= start_date & index(returns) <= end_date, ]
mean_returns <- colMeans(recession_returns) * 52
std_devs <- apply(recession_returns, 2, sd) * sqrt(52)
cov_matrix <- cov(recession_returns) * 52
correlation_matrix <- cor(recession_returns)
portfolio_return <- sum(optimal_weights * mean_returns)
portfolio_volatility <- sqrt(t(optimal_weights) %*% cov_matrix %*% optimal_weights)
spy_return <- mean_returns["SPY_Returns"]
spy_volatility <- std_devs["SPY_Returns"]
# values of $1,000,000 investment
portfolio_final_value <- initial_investment * (1 + portfolio_return)
spy_final_value <- initial_investment * (1 + spy_return)
recession_summary <- data.frame(
Metric = c("Mean Return (Annualized)", "Standard Deviation (Annualized)", "Correlation"),
SPY = c(mean_returns["SPY_Returns"], std_devs["SPY_Returns"], correlation_matrix[1, 2]),
VUSTX = c(mean_returns["VUSTX_Returns"], std_devs["VUSTX_Returns"], NA)
)
cat(paste("Recession period:", start_date, "to", end_date, "\n"))
print(recession_summary)
cat("\nExpected Return of Portfolio (Annualized):", round(portfolio_return, 4))
cat("\nStandard Deviation of Portfolio (Annualized):", round(portfolio_volatility, 4))
cat("\nFinal Value of Portfolio ($1,000,000 investment): $", round(portfolio_final_value, 2))
cat("\n\nSPY Only Investment:\n")
cat("Expected Return of SPY (Annualized):", round(spy_return, 4))
cat("\nStandard Deviation of SPY (Annualized):", round(spy_volatility, 4))
cat("\nFinal Value of SPY ($1,000,000 investment): $", round(spy_final_value, 2))
cat("\n\n")
}
optimal_weights <- c(0.7102260, 0.289774025365778) # actual weights from above
#portfolio performance for each recession
for (recession_name in names(recession_periods)) {
start_date <- recession_periods[[recession_name]][1]
end_date <- recession_periods[[recession_name]][2]
cat("\n", recession_name, ":\n")
analyze_recession(start_date, end_date, returns, optimal_weights)
}
##
## Dot-com Bubble :
## Recession period: 2001-03-01 to 2001-11-30
## Metric SPY VUSTX
## 1 Mean Return (Annualized) -0.09211963 0.02538946
## 2 Standard Deviation (Annualized) 0.23526779 0.09978496
## 3 Correlation -0.01036029 NA
##
## Expected Return of Portfolio (Annualized): -0.0581
## Standard Deviation of Portfolio (Annualized): 0.1693
## Final Value of Portfolio ($1,000,000 investment): $ 941931.4
##
## SPY Only Investment:
## Expected Return of SPY (Annualized): -0.0921
## Standard Deviation of SPY (Annualized): 0.2353
## Final Value of SPY ($1,000,000 investment): $ 907880.4
##
##
## Great Recession :
## Recession period: 2007-12-01 to 2009-03-31
## Metric SPY VUSTX
## 1 Mean Return (Annualized) -0.4179294 0.0424250
## 2 Standard Deviation (Annualized) 0.2805457 0.1354035
## 3 Correlation -0.2929740 NA
##
## Expected Return of Portfolio (Annualized): -0.2845
## Standard Deviation of Portfolio (Annualized): 0.1915
## Final Value of Portfolio ($1,000,000 investment): $ 715469.4
##
## SPY Only Investment:
## Expected Return of SPY (Annualized): -0.4179
## Standard Deviation of SPY (Annualized): 0.2805
## Final Value of SPY ($1,000,000 investment): $ 582070.7
##
##
## COVID-19 Recession :
## Recession period: 2020-02-01 to 2023-05-31
## Metric SPY VUSTX
## 1 Mean Return (Annualized) 0.09341091 -0.1194986
## 2 Standard Deviation (Annualized) 0.19821961 0.1544739
## 3 Correlation 0.04171946 NA
##
## Expected Return of Portfolio (Annualized): 0.0317
## Standard Deviation of Portfolio (Annualized): 0.1495
## Final Value of Portfolio ($1,000,000 investment): $ 1031715
##
## SPY Only Investment:
## Expected Return of SPY (Annualized): 0.0934
## Standard Deviation of SPY (Annualized): 0.1982
## Final Value of SPY ($1,000,000 investment): $ 1093411
plot_recession_correlation <- function(start_date, end_date, returns) {
recession_returns <- returns[index(returns) >= start_date & index(returns) <= end_date, ]
correlation_matrix <- cor(recession_returns)
corrplot(correlation_matrix, method = "circle", type = "upper",
title = paste("Correlation Matrix during Recession:", start_date, "to", end_date),
addCoef.col = "black", tl.col = "black", tl.srt = 45)
}
for (recession_name in names(recession_periods)) {
start_date <- recession_periods[[recession_name]][1]
end_date <- recession_periods[[recession_name]][2]
cat("\n", recession_name, ":\n")
plot_recession_correlation(start_date, end_date, returns)
}
##
## Dot-com Bubble :

##
## Great Recession :

##
## COVID-19 Recession :

# Load the required libraries
# install.packages("corrplot")
# Load the corrplot package
library(corrplot)
library(quantmod)
library(PerformanceAnalytics)
library(ggplot2)
tickers <- c("SPY", "VUSTX")
getSymbols(tickers, src = "yahoo", from = "1997-01-01", to = "2023-05-31", periodicity = "weekly")
## [1] "SPY" "VUSTX"
prices <- merge(Cl(SPY), Cl(VUSTX))
returns <- na.omit(ROC(prices, type = "discrete"))
colnames(returns) <- c("SPY_Returns", "VUSTX_Returns")
recession_periods <- list(
"Dot-com Bubble" = c("2001-03-01", "2001-11-30"),
"Great Recession" = c("2007-12-01", "2009-03-31"),
"COVID-19 Recession" = c("2020-02-01", "2023-05-31")
)
analyze_recession <- function(start_date, end_date, returns, optimal_weights, initial_investment = 1000000) {
recession_returns <- returns[index(returns) >= start_date & index(returns) <= end_date, ]
mean_returns <- colMeans(recession_returns) * 52
std_devs <- apply(recession_returns, 2, sd) * sqrt(52)
cov_matrix <- cov(recession_returns) * 52
correlation_matrix <- cor(recession_returns)
portfolio_return <- sum(optimal_weights * mean_returns)
portfolio_volatility <- sqrt(t(optimal_weights) %*% cov_matrix %*% optimal_weights)
spy_return <- mean_returns["SPY_Returns"]
spy_volatility <- std_devs["SPY_Returns"]
vustx_return <- mean_returns["VUSTX_Returns"]
vustx_volatility <- std_devs["VUSTX_Returns"]
# value of $1,000,000 investment
portfolio_final_value <- initial_investment * (1 + portfolio_return)
spy_final_value <- initial_investment * (1 + spy_return)
vustx_final_value <- initial_investment * (1 + vustx_return)
recession_summary <- data.frame(
Metric = c("Mean Return (Annualized)", "Standard Deviation (Annualized)", "Correlation"),
SPY = c(mean_returns["SPY_Returns"], std_devs["SPY_Returns"], correlation_matrix[1, 2]),
VUSTX = c(mean_returns["VUSTX_Returns"], std_devs["VUSTX_Returns"], NA)
)
cat(paste("Recession period:", start_date, "to", end_date, "\n"))
print(recession_summary)
cat("\nExpected Return of Portfolio (Annualized):", round(portfolio_return, 4))
cat("\nStandard Deviation of Portfolio (Annualized):", round(portfolio_volatility, 4))
cat("\nFinal Value of Portfolio ($1,000,000 investment): $", round(portfolio_final_value, 2))
cat("\n\nSPY Only Investment:\n")
cat("Expected Return of SPY (Annualized):", round(spy_return, 4))
cat("\nStandard Deviation of SPY (Annualized):", round(spy_volatility, 4))
cat("\nFinal Value of SPY ($1,000,000 investment): $", round(spy_final_value, 2))
cat("\n\nVUSTX Only Investment:\n")
cat("Expected Return of VUSTX (Annualized):", round(vustx_return, 4))
cat("\nStandard Deviation of VUSTX (Annualized):", round(vustx_volatility, 4))
cat("\nFinal Value of VUSTX ($1,000,000 investment): $", round(vustx_final_value, 2))
cat("\n\n")
}
optimal_weights <- c(0.7102260, 0.289774025365778) # actual weights from above
for (recession_name in names(recession_periods)) {
start_date <- recession_periods[[recession_name]][1]
end_date <- recession_periods[[recession_name]][2]
cat("\n", recession_name, ":\n")
analyze_recession(start_date, end_date, returns, optimal_weights)
}
##
## Dot-com Bubble :
## Recession period: 2001-03-01 to 2001-11-30
## Metric SPY VUSTX
## 1 Mean Return (Annualized) -0.09211963 0.02538946
## 2 Standard Deviation (Annualized) 0.23526779 0.09978496
## 3 Correlation -0.01036029 NA
##
## Expected Return of Portfolio (Annualized): -0.0581
## Standard Deviation of Portfolio (Annualized): 0.1693
## Final Value of Portfolio ($1,000,000 investment): $ 941931.4
##
## SPY Only Investment:
## Expected Return of SPY (Annualized): -0.0921
## Standard Deviation of SPY (Annualized): 0.2353
## Final Value of SPY ($1,000,000 investment): $ 907880.4
##
## VUSTX Only Investment:
## Expected Return of VUSTX (Annualized): 0.0254
## Standard Deviation of VUSTX (Annualized): 0.0998
## Final Value of VUSTX ($1,000,000 investment): $ 1025389
##
##
## Great Recession :
## Recession period: 2007-12-01 to 2009-03-31
## Metric SPY VUSTX
## 1 Mean Return (Annualized) -0.4179294 0.0424250
## 2 Standard Deviation (Annualized) 0.2805457 0.1354035
## 3 Correlation -0.2929740 NA
##
## Expected Return of Portfolio (Annualized): -0.2845
## Standard Deviation of Portfolio (Annualized): 0.1915
## Final Value of Portfolio ($1,000,000 investment): $ 715469.4
##
## SPY Only Investment:
## Expected Return of SPY (Annualized): -0.4179
## Standard Deviation of SPY (Annualized): 0.2805
## Final Value of SPY ($1,000,000 investment): $ 582070.7
##
## VUSTX Only Investment:
## Expected Return of VUSTX (Annualized): 0.0424
## Standard Deviation of VUSTX (Annualized): 0.1354
## Final Value of VUSTX ($1,000,000 investment): $ 1042425
##
##
## COVID-19 Recession :
## Recession period: 2020-02-01 to 2023-05-31
## Metric SPY VUSTX
## 1 Mean Return (Annualized) 0.09341091 -0.1194986
## 2 Standard Deviation (Annualized) 0.19821961 0.1544739
## 3 Correlation 0.04171946 NA
##
## Expected Return of Portfolio (Annualized): 0.0317
## Standard Deviation of Portfolio (Annualized): 0.1495
## Final Value of Portfolio ($1,000,000 investment): $ 1031715
##
## SPY Only Investment:
## Expected Return of SPY (Annualized): 0.0934
## Standard Deviation of SPY (Annualized): 0.1982
## Final Value of SPY ($1,000,000 investment): $ 1093411
##
## VUSTX Only Investment:
## Expected Return of VUSTX (Annualized): -0.1195
## Standard Deviation of VUSTX (Annualized): 0.1545
## Final Value of VUSTX ($1,000,000 investment): $ 880501.4
for (recession_name in names(recession_periods)) {
start_date <- recession_periods[[recession_name]][1]
end_date <- recession_periods[[recession_name]][2]
cat("\n", recession_name, ":\n")
# plot_recession_correlation(start_date, end_date, returns)
}
##
## Dot-com Bubble :
##
## Great Recession :
##
## COVID-19 Recession :