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 :