# Core
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.1 ✔ 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
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.28 ✔ 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
library(timetk)
##
## Attaching package: 'timetk'
##
## The following object is masked from 'package:tidyquant':
##
## FANG
library(PerformanceAnalytics)
library(e1071)
##
## Attaching package: 'e1071'
##
## The following objects are masked from 'package:PerformanceAnalytics':
##
## kurtosis, skewness
##
## The following object is masked from 'package:ggplot2':
##
## element
Visualize and compare skewness of your portfolio and its assets.
symbols <- c("NVDA", "AAPL", "AMD", "GOOG", "INTC")
prices <- tq_get(x = symbols,
get = "stock.prices",
from = "2012-12-31",
to = "2017-12-31")
head(prices)
## # A tibble: 6 × 8
## symbol date open high low close volume adjusted
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 NVDA 2012-12-31 0.301 0.308 0.301 0.306 326460000 0.283
## 2 NVDA 2013-01-02 0.314 0.318 0.313 0.318 478836000 0.293
## 3 NVDA 2013-01-03 0.318 0.322 0.315 0.318 298888000 0.294
## 4 NVDA 2013-01-04 0.319 0.330 0.318 0.329 524968000 0.303
## 5 NVDA 2013-01-07 0.329 0.329 0.317 0.319 610732000 0.295
## 6 NVDA 2013-01-08 0.320 0.321 0.310 0.312 466424000 0.288
asset_returns_tbl <- prices %>%
group_by(symbol) %>%
tq_transmute(select = adjusted,
mutate_fun = periodReturn,
period = "monthly",
type = "log") %>%
slice(-1) %>%
ungroup() %>%
set_names(c("asset", "date", "returns"))
head(asset_returns_tbl)
## # A tibble: 6 × 3
## asset date returns
## <chr> <date> <dbl>
## 1 AAPL 2013-01-31 -0.156
## 2 AAPL 2013-02-28 -0.0256
## 3 AAPL 2013-03-28 0.00285
## 4 AAPL 2013-04-30 0.000271
## 5 AAPL 2013-05-31 0.0222
## 6 AAPL 2013-06-28 -0.126
symbols <- asset_returns_tbl %>% distinct(asset) %>% pull()
weights <- c(0.25, 0.25, 0.20, 0.20, 0.10)
w_tbl <- tibble(symbols, weights)
w_tbl
## # A tibble: 5 × 2
## symbols weights
## <chr> <dbl>
## 1 AAPL 0.25
## 2 AMD 0.25
## 3 GOOG 0.2
## 4 INTC 0.2
## 5 NVDA 0.1
portfolio_returns_tbl <- asset_returns_tbl %>%
tq_portfolio(assets_col = asset,
returns_col = returns,
weights = w_tbl,
rebalance_on = "months",
col_rename = "returns")
head(portfolio_returns_tbl)
## # A tibble: 6 × 2
## date returns
## <date> <dbl>
## 1 2013-01-31 -0.00164
## 2 2013-02-28 -0.00108
## 3 2013-03-28 0.0152
## 4 2013-04-30 0.0583
## 5 2013-05-31 0.114
## 6 2013-06-28 -0.0279
portfolio_skew_tidyquant_builtin_percent <- portfolio_returns_tbl %>%
tq_performance(Ra = returns, performance_fun = table.Stats) %>%
select(Skewness)
portfolio_skew_tidyquant_builtin_percent
## # A tibble: 1 × 1
## Skewness
## <dbl>
## 1 0.338
asset_skewness_tbl <- asset_returns_tbl %>%
group_by(asset) %>%
summarise(skew = skewness(returns)) %>%
ungroup() %>%
add_row(tibble(asset = "Portfolio",
skew = skewness(portfolio_returns_tbl$returns)))
asset_skewness_tbl
## # A tibble: 6 × 2
## asset skew
## <chr> <dbl>
## 1 AAPL -0.541
## 2 AMD 0.285
## 3 GOOG 0.765
## 4 INTC -0.0313
## 5 NVDA 0.876
## 6 Portfolio 0.330
# Plot skewness comparison
asset_skewness_tbl %>%
ggplot(aes(x = asset, y = skew, color = asset)) +
geom_point(size = 3) +
geom_text(aes(label = asset), vjust = -1.2, size = 3.5) +
labs(y = "Skewness", title = "Skewness Comparison: Assets vs Portfolio") +
theme_minimal()
rolling_skew_tbl <- portfolio_returns_tbl %>%
tq_mutate(select = returns,
mutate_fun = rollapply,
width = 24,
FUN = skewness,
col_rename = "Skew") %>%
select(-returns) %>%
na.omit()
# Plot rolling skewness
rolling_skew_tbl %>%
ggplot(aes(x = date, y = Skew)) +
geom_line(color = "cornflowerblue") +
geom_hline(yintercept = 0, linetype = "dotted", size = 1.2) +
scale_y_continuous(limits = c(-1, 1), breaks = seq(-1, 1, 0.2)) +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5)) +
labs(y = "Skewness", x = NULL, title = "Rolling 24-Month Skewness") +
annotate(geom = "text",
x = as.Date("2016-07-01"), y = 0.8,
color = "red", size = 4,
label = "Positive skewness about half the time; overall skewness near neutral.")
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.