By following the 5 factor model and 10 industry monthly returns based on Fama-French database website.

(https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html),

you can construct the MVP portfolio and its monthly returns using the previous 5-year monthly returns data. Show its cumulative returns starting from 1969.

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(tidyr)
library(tibble)
library(tseries)
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library(PerformanceAnalytics)
## Loading required package: xts
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## 
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## 
## 
## ######################### Warning from 'xts' package ##########################
## #                                                                             #
## # The dplyr lag() function breaks how base R's lag() function is supposed to  #
## # work, which breaks lag(my_xts). Calls to lag(my_xts) that you type or       #
## # source() into this session won't work correctly.                            #
## #                                                                             #
## # Use stats::lag() to make sure you're not using dplyr::lag(), or you can add #
## # conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop           #
## # dplyr from breaking base R's lag() function.                                #
## #                                                                             #
## # Code in packages is not affected. It's protected by R's namespace mechanism #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning.  #
## #                                                                             #
## ###############################################################################
## 
## Attaching package: 'xts'
## 
## The following objects are masked from 'package:dplyr':
## 
##     first, last
## 
## 
## Attaching package: 'PerformanceAnalytics'
## 
## The following object is masked from 'package:graphics':
## 
##     legend
library(ggplot2)
library(readr)

ff_factors <- read_csv("F-F_Research_Data_5_Factors_2x3.csv", skip = 3, col_names = FALSE, col_types = cols(
  X1 = col_character(),
  X2 = col_double(),
  X3 = col_double(),
  X4 = col_double(),
  X5 = col_double(),
  X6 = col_double(),
  X7 = col_double()
))
## Warning: One or more parsing issues, call `problems()` on your data frame for details,
## e.g.:
##   dat <- vroom(...)
##   problems(dat)
colnames(ff_factors) <- c("Date", "Mkt_RF", "SMB", "HML", "RMW", "CMA", "RF")
ff_factors <- ff_factors %>%
  filter(as.Date(paste0(Date, "01"), format = "%Y%m%d") >= as.Date("1969-01-01"))
ff_factors$Date <- as.Date(paste0(ff_factors$Date, "01"), format = "%Y%m%d")
industry_returns <- read_csv("10_Industry_Portfolios.CSV", skip = 11, col_names = FALSE, col_types = cols(
  X1 = col_character(),
  X2 = col_double(),
  X3 = col_double(),
  X4 = col_double(),
  X5 = col_double(),
  X6 = col_double(),
  X7 = col_double(),
  X8 = col_double(),
  X9 = col_double(),
  X10 = col_double(),
  X11 = col_double()
))
## Warning: One or more parsing issues, call `problems()` on your data frame for details,
## e.g.:
##   dat <- vroom(...)
##   problems(dat)
colnames(industry_returns) <- c("Date", "Ind1", "Ind2", "Ind3", "Ind4", "Ind5", "Ind6", "Ind7", "Ind8", "Ind9", "Ind10")

# Filter data from 1969
industry_returns <- industry_returns %>%
  filter(as.Date(paste0(Date, "01"), format = "%Y%m%d") >= as.Date("1969-01-01"))

# Convert dates to Date type
industry_returns$Date <- as.Date(paste0(industry_returns$Date, "01"), format = "%Y%m%d")

# Calculate cumulative returns for Fama-French 5 factors
ff_factors_cumulative <- ff_factors %>%
  mutate(
    Mkt_RF_Cumulative = cumprod(1 + Mkt_RF/100),
    SMB_Cumulative = cumprod(1 + SMB/100),
    HML_Cumulative = cumprod(1 + HML/100),
    RMW_Cumulative = cumprod(1 + RMW/100),
    CMA_Cumulative = cumprod(1 + CMA/100)
  )

# Plot cumulative returns for Fama-French 5 factors
ff_factors_long <- ff_factors_cumulative %>%
  select(Date, Mkt_RF_Cumulative, SMB_Cumulative, HML_Cumulative, RMW_Cumulative, CMA_Cumulative) %>%
  pivot_longer(cols = -Date, names_to = "Factor", values_to = "Cumulative_Return")

ggplot(ff_factors_long, aes(x = Date, y = Cumulative_Return, color = Factor)) +
  geom_line() +
  labs(title = "Cumulative Returns of Fama-French 5 Factors",
       x = "Date",
       y = "Cumulative Return") +
  theme_minimal()