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

Ra <- c("ATCO-A.ST", "SINCH.ST", "INVE-B.st", "SSAB-B.ST", "SAAB-B.ST", "AXFO.ST", "VOLCAR-B.ST", "NDA-SE.ST", "ERIC-B.ST", "CAST.ST", "ORRON.ST", "AZN.ST") %>%
    tq_get(get  = "stock.prices",
           from = "2025-03-01",
           to   = Sys.Date()) %>%
    group_by(symbol) %>%
    tq_transmute(select     = adjusted, 
                 mutate_fun = periodReturn, 
                 period     = "weekly", 
                 col_rename = "Ra")
Ra
## # A tibble: 144 × 3
## # Groups:   symbol [12]
##    symbol    date             Ra
##    <chr>     <date>        <dbl>
##  1 ATCO-A.ST 2025-03-07  0.0116 
##  2 ATCO-A.ST 2025-03-14 -0.0338 
##  3 ATCO-A.ST 2025-03-21 -0.0564 
##  4 ATCO-A.ST 2025-03-28 -0.0191 
##  5 ATCO-A.ST 2025-04-04 -0.126  
##  6 ATCO-A.ST 2025-04-11  0.0366 
##  7 ATCO-A.ST 2025-04-17  0.00539
##  8 ATCO-A.ST 2025-04-25  0.0405 
##  9 ATCO-A.ST 2025-05-02 -0.0121 
## 10 ATCO-A.ST 2025-05-09 -0.00296
## # ℹ 134 more rows

2 Get Baseline & Convert To Returns

Rb <- "^OMXSPI" %>%
    tq_get(get  = "stock.prices",
           from = "2025-03-01") %>%
    tq_transmute(select = adjusted,
                 mutate_fun = periodReturn, 
                 period     = "weekly", 
                 col_rename = "Rb")
Rb
## # A tibble: 12 × 2
##    date             Rb
##    <date>        <dbl>
##  1 2025-03-07 -0.0165 
##  2 2025-03-14 -0.0140 
##  3 2025-03-21 -0.0130 
##  4 2025-03-28 -0.0315 
##  5 2025-04-04 -0.0908 
##  6 2025-04-11 -0.0111 
##  7 2025-04-17  0.0339 
##  8 2025-04-25  0.0339 
##  9 2025-05-02  0.0191 
## 10 2025-05-09 -0.00381
## 11 2025-05-16  0.0326 
## 12 2025-05-21 -0.00111

3 Join the two tables

RaRb <- left_join(Ra, Rb, by = c("date" = "date"))
RaRb
## # A tibble: 144 × 4
## # Groups:   symbol [12]
##    symbol    date             Ra       Rb
##    <chr>     <date>        <dbl>    <dbl>
##  1 ATCO-A.ST 2025-03-07  0.0116  -0.0165 
##  2 ATCO-A.ST 2025-03-14 -0.0338  -0.0140 
##  3 ATCO-A.ST 2025-03-21 -0.0564  -0.0130 
##  4 ATCO-A.ST 2025-03-28 -0.0191  -0.0315 
##  5 ATCO-A.ST 2025-04-04 -0.126   -0.0908 
##  6 ATCO-A.ST 2025-04-11  0.0366  -0.0111 
##  7 ATCO-A.ST 2025-04-17  0.00539  0.0339 
##  8 ATCO-A.ST 2025-04-25  0.0405   0.0339 
##  9 ATCO-A.ST 2025-05-02 -0.0121   0.0191 
## 10 ATCO-A.ST 2025-05-09 -0.00296 -0.00381
## # ℹ 134 more rows

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
RaRb_capm
## # A tibble: 12 × 18
## # Groups:   symbol [12]
##    symbol      ActivePremium   Alpha AlphaRobust AnnualizedAlpha  Beta `Beta-`
##    <chr>               <dbl>   <dbl>       <dbl>           <dbl> <dbl>   <dbl>
##  1 ATCO-A.ST         -0.0682  0.0001      0.0001          0.0044 1.23   1.40  
##  2 SINCH.ST           0.743   0.0209      0.0197          1.93   1.98   2.55  
##  3 INVE-B.st         -0.0705 -0.0019     -0.004          -0.0941 0.994  1.08  
##  4 SSAB-B.ST         -0.075   0.0013      0.0012          0.0683 1.37   1.55  
##  5 SAAB-B.ST          2.37    0.025       0.025           2.61   0.302  0.627 
##  6 AXFO.ST            1.77    0.0189      0.0205          1.64   0.136 -0.281 
##  7 VOLCAR-B.ST       -0.228  -0.0069      0.0014         -0.304  0.888  1.04  
##  8 NDA-SE.ST          0.214   0.0061      0.0127          0.373  1.14   1.09  
##  9 ERIC-B.ST          0.170   0.0054     -0.0029          0.326  1.19   1.01  
## 10 CAST.ST            0.255   0.002      -0.0025          0.112  0.350 -0.241 
## 11 ORRON.ST          -0.328  -0.0104     -0.0098         -0.421  0.930  0.0612
## 12 AZN.ST            -0.262  -0.0099     -0.0039         -0.405  0.691  0.300 
## # ℹ 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>

5 Which stock has a positively skewed distribution of returns?

RaRb_capm <- RaRb %>%
    tq_performance(Ra = Ra, 
                   Rb = Rb, 
                   performance_fun = VolatilitySkewness)
RaRb_capm
## # A tibble: 12 × 2
## # Groups:   symbol [12]
##    symbol      VolatilitySkewness.1
##    <chr>                      <dbl>
##  1 ATCO-A.ST                 1.15  
##  2 SINCH.ST                  2.22  
##  3 INVE-B.st                 0.0121
##  4 SSAB-B.ST                 1.29  
##  5 SAAB-B.ST                24.1   
##  6 AXFO.ST                  13.7   
##  7 VOLCAR-B.ST               1.57  
##  8 NDA-SE.ST                 2.44  
##  9 ERIC-B.ST                 2.62  
## 10 CAST.ST                   1.01  
## 11 ORRON.ST                  4.79  
## 12 AZN.ST                    0.618