# Libraries
libs <- c("tidyverse", "dplyr", "knitr", "ggplot2", "tinytex", "nlme", "quantmod", "lubridate", "rugarch", "forecast")
for (i in libs) {
library(package=i, character.only=TRUE)
}
## Warning: package 'ggplot2' was built under R version 4.4.3
## Warning: package 'tibble' was built under R version 4.4.3
## Warning: package 'purrr' was built under R version 4.4.3
## Warning: package 'stringr' was built under R version 4.4.3
## Warning: package 'lubridate' was built under R version 4.4.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.2
## ✔ ggplot2 4.0.0 ✔ tibble 3.3.0
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.1.0
## ── 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
## Warning: package 'knitr' was built under R version 4.4.3
## Warning: package 'tinytex' was built under R version 4.4.3
## Warning: package 'nlme' was built under R version 4.4.3
##
## Attaching package: 'nlme'
##
## The following object is masked from 'package:dplyr':
##
## collapse
## Warning: package 'quantmod' was built under R version 4.4.3
## Loading required package: xts
## Warning: package 'xts' was built under R version 4.4.2
## Loading required package: zoo
## Warning: package 'zoo' was built under R version 4.4.3
##
## 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
##
## Loading required package: TTR
## Warning: package 'TTR' was built under R version 4.4.2
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
## Warning: package 'rugarch' was built under R version 4.4.3
## Loading required package: parallel
##
## Attaching package: 'rugarch'
##
## The following object is masked from 'package:purrr':
##
## reduce
## Warning: package 'forecast' was built under R version 4.4.3
##
## Attaching package: 'forecast'
##
## The following object is masked from 'package:nlme':
##
## getResponse
# Fetch data
df <- NULL
# Define date range
end <- Sys.time()
start <- end - days(365*5)
# Define tickers
tickers <- c("VAR.OL", "OSEBX.OL", "CL=F")
# Fetch stock data
for(ticker in tickers) {
df <- cbind(df, getSymbols(ticker,
src = "yahoo",
from = start,
end = end,
periodicity = 'daily',
auto.assign = FALSE)[,6])
}
## Warning: OSEBX.OL contains missing values. Some functions will not work if
## objects contain missing values in the middle of the series. Consider using
## na.omit(), na.approx(), na.fill(), etc to remove or replace them.
## Warning: CL=F contains missing values. Some functions will not work if objects
## contain missing values in the middle of the series. Consider using na.omit(),
## na.approx(), na.fill(), etc to remove or replace them.
# We use log returns
returns <- (log(df / lag(df))) %>% na.omit() %>% as.data.frame()
colnames(returns) <- c("VAR", "OSEBX", "Oil")
attach(returns)
# Compute covariance matrix
factor_returns <- returns[c("OSEBX", "Oil")]
factor_returns_mtx <- factor_returns |> as.matrix()
factor_cov <- cov(factor_returns)
VAR.fit <- lm(VAR ~ OSEBX + Oil)
summary(VAR.fit)
##
## Call:
## lm(formula = VAR ~ OSEBX + Oil)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.082700 -0.009833 0.000127 0.009593 0.110900
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.0002490 0.0005909 0.421 0.674
## OSEBX 1.1165684 0.0680994 16.396 <2e-16 ***
## Oil 0.2739399 0.0266712 10.271 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.01715 on 841 degrees of freedom
## Multiple R-squared: 0.3969, Adjusted R-squared: 0.3955
## F-statistic: 276.8 on 2 and 841 DF, p-value: < 2.2e-16
# Perform an eigen rotation
# Covariance matrix
Sigma_X <- cov(factor_returns_mtx)
# Eigen rotation
eig <- eigen(Sigma_X)
# Rotation matrix (orthonormal)
Q <- eig$vectors
# Rotated orthogonal components
Z <- factor_returns_mtx %*% Q
OSEBX <- Z[, 1]
Oil <- Z[, 2]
cov(Z)
## [,1] [,2]
## [1,] 5.665794e-04 -1.005921e-20
## [2,] -1.005921e-20 7.373646e-05
VAR.fit <- lm(VAR ~ OSEBX + Oil)
summary(VAR.fit)
##
## Call:
## lm(formula = VAR ~ OSEBX + Oil)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.082700 -0.009833 0.000127 0.009593 0.110900
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.0002490 0.0005909 0.421 0.674
## OSEBX 0.4407117 0.0248185 17.757 <2e-16 ***
## Oil -1.0618574 0.0687962 -15.435 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.01715 on 841 degrees of freedom
## Multiple R-squared: 0.3969, Adjusted R-squared: 0.3955
## F-statistic: 276.8 on 2 and 841 DF, p-value: < 2.2e-16
oil_variance_prop <- (var(Oil) * VAR.fit$coefficients[3]**2) / var(VAR)
OSEBX_variance_prop <- (var(OSEBX) * VAR.fit$coefficients[2]**2) / var(VAR)
idio_variance_prop <- (var(VAR.fit$residuals)) / var(VAR)
idio_variance_prop
## [1] 0.6030581
oil_variance_prop
## Oil
## 0.1708309
OSEBX_variance_prop
## OSEBX
## 0.226111