Load Packages

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.2     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.4     
## ── 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(tidyquant)
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo 
## ── Attaching core tidyquant packages ─────────────────────── tidyquant 1.0.11 ──
## ✔ PerformanceAnalytics 2.0.8      ✔ TTR                  0.24.4
## ✔ quantmod             0.4.27     ✔ xts                  0.14.1── Conflicts ────────────────────────────────────────── tidyquant_conflicts() ──
## ✖ zoo::as.Date()                 masks base::as.Date()
## ✖ zoo::as.Date.numeric()         masks base::as.Date.numeric()
## ✖ dplyr::filter()                masks stats::filter()
## ✖ xts::first()                   masks dplyr::first()
## ✖ dplyr::lag()                   masks stats::lag()
## ✖ xts::last()                    masks dplyr::last()
## ✖ PerformanceAnalytics::legend() masks graphics::legend()
## ✖ quantmod::summary()            masks base::summary()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

1. Get Stock Prices & Convert to Monthly Returns

Ra <- c("V", "AMZN", "NFLX", "WMT", "KO") %>%
  tq_get(get = "stock.prices", from = "2010-01-01", to = Sys.Date()) %>%
  group_by(symbol) %>%
  tq_transmute(
    select     = adjusted,
    mutate_fun = periodReturn,
    period     = "monthly",
    col_rename = "Ra"
  )

2. Get Baseline (XLK) & Convert to Monthly Returns

Rb <- "XLK" %>%
  tq_get(get = "stock.prices", from = "2010-01-01", to = Sys.Date()) %>%
  tq_transmute(
    select     = adjusted,
    mutate_fun = periodReturn,
    period     = "monthly",
    col_rename = "Rb"
  )

3. Join the Two Tables

RaRb <- left_join(Ra, Rb, by = "date")

4. Calculate CAPM

RaRb_capm <- RaRb %>%
  tq_performance(
    Ra = Ra,
    Rb = Rb,
    performance_fun = table.CAPM
  )
## Registered S3 method overwritten by 'robustbase':
##   method          from     
##   hatvalues.lmrob RobStatTM

View the CAPM results

RaRb_capm
## # A tibble: 5 × 18
## # Groups:   symbol [5]
##   symbol ActivePremium  Alpha AlphaRobust AnnualizedAlpha  Beta `Beta-`
##   <chr>          <dbl>  <dbl>       <dbl>           <dbl> <dbl>   <dbl>
## 1 V             0.0309 0.0069      0.0096          0.0864 0.701  0.927 
## 2 AMZN          0.0719 0.0058      0.0039          0.0719 1.10   1.20  
## 3 NFLX          0.212  0.0247      0.0172          0.340  0.986  0.926 
## 4 WMT          -0.0364 0.007       0.0069          0.0876 0.348  0.0845
## 5 KO           -0.0805 0.0039      0.0053          0.0478 0.313  0.368 
## # ℹ 11 more variables: `Beta-Robust` <dbl>, `Beta+` <dbl>, `Beta+Robust` <dbl>,
## #   BetaRobust <dbl>, Correlation <dbl>, `Correlationp-value` <dbl>,
## #   InformationRatio <dbl>, `R-squared` <dbl>, `R-squaredRobust` <dbl>,
## #   TrackingError <dbl>, TreynorRatio <dbl>