Financial Mathematics 1 - Homework 2

Instructor: Dr. Le Nhat Tan

Le Nguyen Dang Khoa

March 2023

1 Import library

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.0     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.1     ✔ tibble    3.1.8
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.0
## ✔ purrr     1.0.1     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(lubridate)
library(readxl)
library(highcharter)
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library(tidyquant)
## Loading required package: 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 ###################################
## # We noticed you have dplyr installed. 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 enter or source() into this session won't     #
## # work correctly.                                                             #
## #                                                                             #
## # All package code is unaffected because it is protected by the R namespace   #
## # mechanism.                                                                  #
## #                                                                             #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning.  #
## #                                                                             #
## # You can 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.                                #
## ################################### 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
## 
## Loading required package: quantmod
## Loading required package: TTR
library(timetk)
library(tibbletime)
## 
## Attaching package: 'tibbletime'
## 
## The following object is masked from 'package:stats':
## 
##     filter
library(quantmod)
library(PerformanceAnalytics)
library(scales)
## 
## Attaching package: 'scales'
## 
## The following object is masked from 'package:purrr':
## 
##     discard
## 
## The following object is masked from 'package:readr':
## 
##     col_factor
library(plotly)
## 
## Attaching package: 'plotly'
## 
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## 
## The following object is masked from 'package:stats':
## 
##     filter
## 
## The following object is masked from 'package:graphics':
## 
##     layout
library(rvest)
## 
## Attaching package: 'rvest'
## 
## The following object is masked from 'package:readr':
## 
##     guess_encoding
library(xml2)
library(tibble)
library(httr)
## 
## Attaching package: 'httr'
## 
## The following object is masked from 'package:plotly':
## 
##     config
library(purrr)
library(dplyr)

2 US Stock Data

2.1 Asset prices series

symbols <- c( "JPM", "DIS", "^GSPC", "BAC")

prices=tq_get(symbols, get = "stock.prices",from = "2015-03-12")

2.1.1 Daily Stock Price

## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.

2.1.2 Monthly Stock Price

monthly_prices=prices %>% group_by(symbol) %>%
  tq_transmute(select     = open:adjusted, 
               mutate_fun = to.period, 
               period     = "months")
glimpse(monthly_prices)
## Rows: 388
## Columns: 8
## Groups: symbol [4]
## $ symbol   <chr> "JPM", "JPM", "JPM", "JPM", "JPM", "JPM", "JPM", "JPM", "JPM"…
## $ date     <date> 2015-03-31, 2015-04-30, 2015-05-29, 2015-06-30, 2015-07-31, …
## $ open     <dbl> 60.72, 63.58, 66.18, 67.89, 69.01, 63.61, 60.70, 65.30, 67.28…
## $ high     <dbl> 60.94, 63.88, 66.22, 68.11, 69.04, 64.35, 61.00, 65.34, 67.52…
## $ low      <dbl> 60.42, 62.92, 65.36, 67.16, 68.40, 63.47, 60.11, 64.13, 66.68…
## $ close    <dbl> 60.58, 63.26, 65.78, 67.76, 68.53, 64.10, 60.97, 64.25, 66.68…
## $ volume   <dbl> 17346700, 16840900, 14310700, 20677400, 11911800, 14223400, 1…
## $ adjusted <dbl> 48.41022, 50.88782, 52.91498, 54.50774, 55.48743, 51.90055, 4…

2.1.3 Yearly Stock Price

yearly_prices=prices %>% group_by(symbol) %>%
  tq_transmute(select     = open:adjusted, 
               mutate_fun = to.period, 
               period     = "years")
glimpse(yearly_prices)
## Rows: 36
## Columns: 8
## Groups: symbol [4]
## $ symbol   <chr> "JPM", "JPM", "JPM", "JPM", "JPM", "JPM", "JPM", "JPM", "JPM"…
## $ date     <date> 2015-12-31, 2016-12-30, 2017-12-29, 2018-12-31, 2019-12-31, …
## $ open     <dbl> 66.19, 86.10, 108.09, 97.59, 138.51, 125.09, 158.45, 132.81, …
## $ high     <dbl> 66.78, 86.42, 108.28, 98.81, 139.48, 127.33, 159.29, 134.33, …
## $ low      <dbl> 66.00, 85.66, 106.94, 96.77, 138.29, 124.82, 157.96, 132.44, …
## $ close    <dbl> 66.03, 86.29, 106.94, 97.62, 139.40, 127.07, 158.35, 134.10, …
## $ volume   <dbl> 14654300, 13617800, 8925700, 13237200, 7201600, 8580200, 5805…
## $ adjusted <dbl> 53.84901, 72.44651, 91.83227, 85.74950, 126.27217, 119.28329,…

2.2 Asset prices to returns

2.2.1 Daily return

prices_daily_log_returns <- prices %>%
  group_by(symbol) %>%
  tq_transmute(select     = adjusted, 
               mutate_fun = periodReturn, 
               period     = "daily", 
               type       = "log",
               col_rename = "daily.returns")

prices_daily_log_returns %>% ggplot(aes(x=date, y=daily.returns, col=symbol))+geom_line()+facet_wrap(symbol~.)

t=prices_daily_log_returns %>%
  ggplot(aes(x =daily.returns)) +
  geom_density( aes(y=..density..)) +
  labs(title = "Density of the Daily Log Returns",
       x = "Daily Returns", y = "Density") +
  theme_tq() +
  scale_fill_tq() + scale_x_continuous(limits = c(-0.2, 0.2)) +
  facet_wrap(~ symbol, ncol = 2)+stat_function(fun = dnorm,
                                               args = list(mean = mean(prices_daily_log_returns$daily.returns),
                                                           sd = sd(prices_daily_log_returns$daily.returns)),
                                               col = "red",
                                               size = 0.2)
t
## Warning: The dot-dot notation (`..density..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(density)` instead.

t=prices_daily_log_returns %>%
  ggplot(aes(x =daily.returns)) +
  geom_density( aes(y=..density..)) +
  labs(title = "Charting the Daily Log Returns",
       x = "Daily Returns", y = "Density") +
  theme_tq() +
  scale_fill_tq() + scale_x_continuous(limits = c(0.05,0.2 )) +
  facet_wrap(~ symbol, ncol = 2)+stat_function(fun = dnorm,
                                               args = list(mean = mean(prices_daily_log_returns$daily.returns),
                                                           sd = sd(prices_daily_log_returns$daily.returns)),
                                               col = "red",
                                               size = 0.2)
t
## Warning: Removed 8001 rows containing non-finite values (`stat_density()`).

### Monthly returns

prices_monthly_log_returns <- prices %>%
  group_by(symbol) %>%
  tq_transmute(select     = adjusted, 
               mutate_fun = periodReturn, 
               period     = "monthly", 
               type       = "log",
               col_rename = "monthly.returns")

prices_monthly_log_returns %>%
  ggplot(aes(x = monthly.returns)) +
  geom_density( aes(y=..density..)) +
  labs(title = "Charting the Monthly Log Returns",
       x = "Monthly Returns", y = "Density") +
  theme_tq() +
  scale_fill_tq() + scale_x_continuous(limits = c(-0.5, 0.5)) +
  facet_wrap(~ symbol, ncol = 2)+stat_function(fun = dnorm,
                                               args = list(mean = mean(prices_monthly_log_returns$monthly.returns),
                                                           sd = sd(prices_monthly_log_returns$monthly.returns)),
                                               col = "#1b98e0",
                                               size = 0.3)

prices_monthly_log_returns <- prices %>%
  group_by(symbol) %>%
  tq_transmute(select     = adjusted, 
               mutate_fun = periodReturn, 
               period     = "monthly", 
               type       = "log",
               col_rename = "monthly.returns")

prices_monthly_log_returns %>%
  ggplot(aes(x = monthly.returns)) +
  geom_density( aes(y=..density..)) +
  labs(title = "Charting the Monthly Log Returns",
       x = "Monthly Returns", y = "Density") +
  theme_tq() +
  scale_fill_tq() + scale_x_continuous(limits = c(-0.5, -0.05)) +
  facet_wrap(~ symbol, ncol = 2)+stat_function(fun = dnorm,
                                               args = list(mean = mean(prices_monthly_log_returns$monthly.returns),
                                                           sd = sd(prices_monthly_log_returns$monthly.returns)),
                                               col = "#1b98e0",
                                               size = 0.3)
## Warning: Removed 314 rows containing non-finite values (`stat_density()`).

prices_monthly_log_returns <- prices %>%
  group_by(symbol) %>%
  tq_transmute(select     = adjusted, 
               mutate_fun = periodReturn, 
               period     = "monthly", 
               type       = "log",
               col_rename = "monthly.returns")

prices_monthly_log_returns %>%
  ggplot(aes(x = monthly.returns)) +
  geom_density( aes(y=..density..)) +
  labs(title = "Charting the Monthly Log Returns",
       x = "Monthly Returns", y = "Density") +
  theme_tq() +
  scale_fill_tq() + scale_x_continuous(limits = c(0.05, 0.5)) +
  facet_wrap(~ symbol, ncol = 2)+stat_function(fun = dnorm,
                                               args = list(mean = mean(prices_monthly_log_returns$monthly.returns),
                                                           sd = sd(prices_monthly_log_returns$monthly.returns)),
                                               col = "#1b98e0",
                                               size = 0.3)
## Warning: Removed 292 rows containing non-finite values (`stat_density()`).

prices_monthly_log_returns %>%
  ggplot(aes(x = monthly.returns, fill = symbol)) +
  geom_histogram(alpha = 0.5) +
  labs(title = "Charting the Monthly Log Returns",
       x = "Monthly Returns", y = "Density") +
  theme_tq() +
  scale_fill_tq() + 
  facet_wrap(~ symbol, ncol = 2)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

prices_monthly_log_returns%>%
  ggplot(aes(x = monthly.returns)) +
  geom_density(aes(color =symbol), alpha = 1) +
  geom_histogram(aes(fill = symbol), alpha = 0.45, binwidth = .01) +
  guides(fill = FALSE) +
  facet_wrap(~symbol) +
  ggtitle("Monthly Returns") +
  xlab("monthly returns") +
  ylab("distribution") +
  theme_update(plot.title = element_text(hjust = 0.5))
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.

2.2.2 Yearly returns

(prices_yearly_log_returns <- prices %>%
    group_by(symbol) %>%
    tq_transmute(select     = adjusted, 
                 mutate_fun = periodReturn, 
                 period     = "yearly", 
                 type       = "log",
                 col_rename = "yearly.returns"))
## # A tibble: 36 × 3
## # Groups:   symbol [4]
##    symbol date       yearly.returns
##    <chr>  <date>              <dbl>
##  1 JPM    2015-12-31        0.0935 
##  2 JPM    2016-12-30        0.297  
##  3 JPM    2017-12-29        0.237  
##  4 JPM    2018-12-31       -0.0685 
##  5 JPM    2019-12-31        0.387  
##  6 JPM    2020-12-31       -0.0569 
##  7 JPM    2021-12-31        0.245  
##  8 JPM    2022-12-30       -0.135  
##  9 JPM    2023-03-16       -0.0179 
## 10 DIS    2015-12-31       -0.00751
## # … with 26 more rows
prices_yearly_log_returns %>% ggplot(aes(x=date, y=yearly.returns, col=symbol))+geom_line()+facet_wrap(symbol~.)

2.3 Mean return for the whole period

2.3.1 Daily mean return for the whole period

prices_daily_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = daily.returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  select(ArithmeticMean,Median, Maximum, Minimum) %>%
  group_by(symbol) %>% 
  summarize(mean_return = round(ArithmeticMean, 4) * 100,
            median_return = round(Median, 4) * 100,
            maximum_return = round(Maximum, 4) * 100,
            minimum_return = round(Minimum, 4) * 100)
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 5
##   symbol mean_return median_return maximum_return minimum_return
##   <chr>        <dbl>         <dbl>          <dbl>          <dbl>
## 1 BAC           0.04          0.04          16.4           -16.7
## 2 DIS           0             0.01          13.5           -14.1
## 3 JPM           0.05          0.02          16.6           -16.2
## 4 ^GSPC         0.03          0.06           8.97          -12.8
prices_daily_log_returns %>% ggplot(aes(x=date, y=daily.returns, col=symbol))+geom_line()+facet_wrap(symbol~.)

2.3.2 Monthly mean return for the whole period

prices_monthly_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = monthly.returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  select(ArithmeticMean,Median, Maximum, Minimum) %>%
  group_by(symbol) %>% 
  summarize(mean_return = round(ArithmeticMean, 4) * 100,
            median_return = round(Median, 4) * 100,
            maximum_return = round(Maximum, 4) * 100,
            minimum_return = round(Minimum, 4) * 100)
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 5
##   symbol mean_return median_return maximum_return minimum_return
##   <chr>        <dbl>         <dbl>          <dbl>          <dbl>
## 1 BAC           0.77          2.41           25.1          -28.8
## 2 DIS          -0.06         -0.31           22.2          -20.6
## 3 JPM           1.01          1.97           19.5          -25.4
## 4 ^GSPC         0.67          1.15           11.9          -13.4
prices_monthly_log_returns %>% ggplot(aes(x=date, y=monthly.returns, col=symbol))+geom_line()+facet_wrap(symbol~.)

2.3.3 Yearly mean return for the whole period

prices_yearly_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = yearly.returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  select(ArithmeticMean,Median, Maximum, Minimum) %>%
  group_by(symbol) %>% 
  summarize(mean_return = round(ArithmeticMean, 4) * 100,
            median_return = round(Median, 4) * 100,
            maximum_return = round(Maximum, 4) * 100,
            minimum_return = round(Minimum, 4) * 100)
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 5
##   symbol mean_return median_return maximum_return minimum_return
##   <chr>        <dbl>         <dbl>          <dbl>          <dbl>
## 1 BAC           8.27          5.4            40.3          -27.2
## 2 DIS          -0.64          3.54           28.9          -57.8
## 3 JPM          10.9           9.35           38.7          -13.5
## 4 ^GSPC         7.23          9.11           25.4          -21.6
prices_yearly_log_returns %>% ggplot(aes(x=date, y=yearly.returns, col=symbol))+geom_line()+facet_wrap(symbol~.)

2.4 Stock volatility for the whole period

2.4.1 Daily Stock volatility for the whole period

prices_daily_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = daily.returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  select(ArithmeticMean,Median,Stdev, Maximum, Minimum) %>%
  group_by(symbol) %>% 
  summarize(mean_return = round(ArithmeticMean, 4) * 100,
            median_return = round(Median, 4) * 100,
            volatility=round(Stdev, 4) * 100,
            maximum_return = round(Maximum, 4) * 100,
            minimum_return = round(Minimum, 4) * 100)
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 6
##   symbol mean_return median_return volatility maximum_return minimum_return
##   <chr>        <dbl>         <dbl>      <dbl>          <dbl>          <dbl>
## 1 BAC           0.04          0.04       2.04          16.4           -16.7
## 2 DIS           0             0.01       1.78          13.5           -14.1
## 3 JPM           0.05          0.02       1.79          16.6           -16.2
## 4 ^GSPC         0.03          0.06       1.2            8.97          -12.8
prices_daily_log_returns %>%  ggplot(aes(x=daily.returns,col=symbol))+geom_boxplot()+facet_wrap(symbol~.)

2.4.2 Monthly Stock volatility for the whole period

prices_monthly_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = monthly.returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  select(ArithmeticMean,Median,Stdev, Maximum, Minimum) %>%
  group_by(symbol) %>% 
  summarize(mean_return = round(ArithmeticMean, 4) * 100,
            median_return = round(Median, 4) * 100,
            volatility=round(Stdev, 4) * 100,
            maximum_return = round(Maximum, 4) * 100,
            minimum_return = round(Minimum, 4) * 100)
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 6
##   symbol mean_return median_return volatility maximum_return minimum_return
##   <chr>        <dbl>         <dbl>      <dbl>          <dbl>          <dbl>
## 1 BAC           0.77          2.41       8.84           25.1          -28.8
## 2 DIS          -0.06         -0.31       8.32           22.2          -20.6
## 3 JPM           1.01          1.97       7.14           19.5          -25.4
## 4 ^GSPC         0.67          1.15       4.59           11.9          -13.4
prices_monthly_log_returns %>%  ggplot(aes(x=monthly.returns,col=symbol))+geom_boxplot()+facet_wrap(symbol~.)

2.4.3 Yearly Stock volatility for the whole period

prices_yearly_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = yearly.returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  select(ArithmeticMean,Median,Stdev, Maximum, Minimum) %>%
  group_by(symbol) %>% 
  summarize(mean_return = round(ArithmeticMean, 4) * 100,
            median_return = round(Median, 4) * 100,
            volatility=round(Stdev, 4) * 100,
            maximum_return = round(Maximum, 4) * 100,
            minimum_return = round(Minimum, 4) * 100)
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 6
##   symbol mean_return median_return volatility maximum_return minimum_return
##   <chr>        <dbl>         <dbl>      <dbl>          <dbl>          <dbl>
## 1 BAC           8.27          5.4        26.4           40.3          -27.2
## 2 DIS          -0.64          3.54       25.1           28.9          -57.8
## 3 JPM          10.9           9.35       18.8           38.7          -13.5
## 4 ^GSPC         7.23          9.11       15.4           25.4          -21.6
prices_yearly_log_returns %>%  ggplot(aes(x=yearly.returns,col=symbol))+geom_boxplot()+facet_wrap(symbol~.)

2.5 Rolling stock volatility

daily_window=30
daily_return_rolling=prices_daily_log_returns %>% group_by(symbol) %>% 
  mutate(rolling_mean_return = rollapply(daily.returns,
                                         FUN = mean,
                                         width = daily_window,align="right",
                                         fill = NA),
         rolling_median_return = rollapply(daily.returns,
                                           FUN = median,
                                           width = daily_window,
                                           fill = NA),
         rolling_max_return = rollapply(daily.returns,
                                        FUN = max,
                                        width = daily_window,
                                        fill = NA),
         rolling_min_return = rollapply(daily.returns,
                                        FUN = min,
                                        width = daily_window,
                                        fill = NA),
         rolling_volatility = rollapply(daily.returns,
                                        FUN = sd,
                                        width = daily_window,
                                        fill = NA))

2.5.1 Rolling daily mean return

daily_return_rolling %>% ggplot(aes(x=date, y=rolling_mean_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 116 rows containing missing values (`geom_line()`).

#### Rolling maximum daily return

daily_return_rolling %>% ggplot(aes(x=date, y=rolling_max_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 116 rows containing missing values (`geom_line()`).

#### Rolling minimum daily return

daily_return_rolling %>% ggplot(aes(x=date, y=rolling_min_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 116 rows containing missing values (`geom_line()`).

#### Rolling daily volatility return

daily_return_rolling %>% ggplot(aes(x=date, y=rolling_volatility*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 116 rows containing missing values (`geom_line()`).

### Rolling monthly stock volatility

monthly_window=12
monthly_return_rolling=prices_monthly_log_returns %>% group_by(symbol) %>% 
  mutate(rolling_mean_return = rollapply(monthly.returns,
                                         FUN = mean,
                                         width = monthly_window,align="right",
                                         fill = NA),
         rolling_median_return = rollapply(monthly.returns,
                                           FUN = median,
                                           width = monthly_window,
                                           fill = NA),
         rolling_max_return = rollapply(monthly.returns,
                                        FUN = max,
                                        width = monthly_window,
                                        fill = NA),
         rolling_min_return = rollapply(monthly.returns,
                                        FUN = min,
                                        width = monthly_window,
                                        fill = NA),
         rolling_volatility = rollapply(monthly.returns,
                                        FUN = sd,
                                        width = monthly_window,
                                        fill = NA))
glimpse(monthly_return_rolling)
## Rows: 388
## Columns: 8
## Groups: symbol [4]
## $ symbol                <chr> "JPM", "JPM", "JPM", "JPM", "JPM", "JPM", "JPM",…
## $ date                  <date> 2015-03-31, 2015-04-30, 2015-05-29, 2015-06-30,…
## $ monthly.returns       <dbl> -0.012955828, 0.049912731, 0.039062736, 0.029656…
## $ rolling_mean_return   <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, -0.0…
## $ rolling_median_return <dbl> NA, NA, NA, NA, NA, 0.004009175, 0.023735072, 0.…
## $ rolling_max_return    <dbl> NA, NA, NA, NA, NA, 0.05958916, 0.05958916, 0.07…
## $ rolling_min_return    <dbl> NA, NA, NA, NA, NA, -0.09744716, -0.09744716, -0…
## $ rolling_volatility    <dbl> NA, NA, NA, NA, NA, 0.05190794, 0.05420360, 0.05…

2.5.1.1 Rolling monthly mean return

monthly_return_rolling %>% ggplot(aes(x=date, y=rolling_max_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 44 rows containing missing values (`geom_line()`).

2.5.1.2 Rolling minimum monthly return

monthly_return_rolling %>% ggplot(aes(x=date, y=rolling_volatility*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 44 rows containing missing values (`geom_line()`).

2.5.2 Rolling yearly stock volatility

yearly_window=3
yearly_return_rolling=prices_yearly_log_returns %>% group_by(symbol) %>% 
  mutate(rolling_mean_return = rollapply(yearly.returns,
                                         FUN = mean,
                                         width = yearly_window,align="right",
                                         fill = NA),
         rolling_median_return = rollapply(yearly.returns,
                                           FUN = median,
                                           width = yearly_window,
                                           fill = NA),
         rolling_max_return = rollapply(yearly.returns,
                                        FUN = max,
                                        width = yearly_window,
                                        fill = NA),
         rolling_min_return = rollapply(yearly.returns,
                                        FUN = min,
                                        width = yearly_window,
                                        fill = NA),
         rolling_volatility = rollapply(yearly.returns,
                                        FUN = sd,
                                        width = yearly_window,
                                        fill = NA))
glimpse(yearly_return_rolling)
## Rows: 36
## Columns: 8
## Groups: symbol [4]
## $ symbol                <chr> "JPM", "JPM", "JPM", "JPM", "JPM", "JPM", "JPM",…
## $ date                  <date> 2015-12-31, 2016-12-30, 2017-12-29, 2018-12-31,…
## $ yearly.returns        <dbl> 0.093517296, 0.296664403, 0.237115243, -0.068533…
## $ rolling_mean_return   <dbl> NA, NA, 0.20909898, 0.15508204, 0.18519706, 0.08…
## $ rolling_median_return <dbl> NA, 0.237115243, 0.237115243, 0.237115243, -0.05…
## $ rolling_max_return    <dbl> NA, 0.29666440, 0.29666440, 0.38700946, 0.387009…
## $ rolling_min_return    <dbl> NA, 0.093517296, -0.068533531, -0.068533531, -0.…
## $ rolling_volatility    <dbl> NA, 0.10443117, 0.19593230, 0.23216692, 0.259725…

2.5.2.1 Rolling yearly mean return

yearly_return_rolling %>% ggplot(aes(x=date, y=rolling_mean_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 8 rows containing missing values (`geom_line()`).

2.5.2.2 Rolling maximum yearly return

yearly_return_rolling %>% ggplot(aes(x=date, y=rolling_max_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 8 rows containing missing values (`geom_line()`).

2.5.2.3 Rolling minimum yearly return

yearly_return_rolling %>% ggplot(aes(x=date, y=rolling_min_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 8 rows containing missing values (`geom_line()`).

2.5.2.4 Rolling yearly volatility return

yearly_return_rolling %>% ggplot(aes(x=date, y=rolling_volatility*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 8 rows containing missing values (`geom_line()`).

2.6 Shape of return distribution

2.6.1 Skewness and kurtosis for the whole period

2.6.1.1 Daily returns

prices_daily_log_returns%>%
  ggplot(aes(x = daily.returns)) +
  geom_density(aes(color =symbol), alpha = 1) +
  geom_histogram(aes(fill = symbol), alpha = 0.45, binwidth = .01) +
  guides(fill = FALSE) +
  facet_wrap(~symbol) +
  ggtitle("daily Returns") +
  xlab("daily returns") +
  ylab("distribution") +
  theme_update(plot.title = element_text(hjust = 0.5))

prices_daily_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = daily.returns,
                 Rb = NULL,
                 performance_fun = table.Distributions) %>%
  select(Skewness,Kurtosis) 
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 3
## # Groups:   symbol [4]
##   symbol Skewness Kurtosis
##   <chr>     <dbl>    <dbl>
## 1 JPM     -0.0727     16.2
## 2 DIS     -0.0342     14.3
## 3 ^GSPC   -0.810      18.2
## 4 BAC     -0.0786     12.9

2.6.1.2 Monthly returns

prices_monthly_log_returns%>%
  ggplot(aes(x = monthly.returns)) +
  geom_density(aes(color =symbol), alpha = 1) +
  geom_histogram(aes(fill = symbol), alpha = 0.45, binwidth = .01) +
  guides(fill = FALSE) +
  facet_wrap(~symbol) +
  ggtitle("Monthly Returns") +
  xlab("monthly returns") +
  ylab("distribution") +
  theme_update(plot.title = element_text(hjust = 0.5))

prices_monthly_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = monthly.returns,
                 Rb = NULL,
                 performance_fun = table.Distributions) %>%
  select(Skewness,Kurtosis) 
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 3
## # Groups:   symbol [4]
##   symbol Skewness Kurtosis
##   <chr>     <dbl>    <dbl>
## 1 JPM      -0.425     4.47
## 2 DIS       0.159     3.74
## 3 ^GSPC    -0.514     3.57
## 4 BAC      -0.404     3.64

2.6.2 Rolling monthly Skewness and Kurtosis

monthly_window=12
monthly_normality_rolling=prices_monthly_log_returns %>% group_by(symbol) %>% 
  mutate(rolling_skew_return = rollapply(monthly.returns,
                                         FUN = skewness,
                                         width = monthly_window,align="right",
                                         fill = NA),
         rolling_kurtosis_return = rollapply(monthly.returns,
                                             FUN = kurtosis,
                                             width = monthly_window,align="right",
                                             fill = NA))

monthly_normality_rolling %>% ggplot(aes(x=date, y=rolling_skew_return,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 44 rows containing missing values (`geom_line()`).

monthly_normality_rolling %>% ggplot(aes(x=date, y=rolling_kurtosis_return,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 44 rows containing missing values (`geom_line()`).

2.7 Downside risk measures

prices_daily_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = daily.returns,
                 Rb = NULL,
                 performance_fun = table.DownsideRisk) %>%
  select(SemiDeviation,"HistoricalVaR(95%)" , "HistoricalES(95%)",MaximumDrawdown) 
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 5
## # Groups:   symbol [4]
##   symbol SemiDeviation `HistoricalVaR(95%)` `HistoricalES(95%)` MaximumDrawdown
##   <chr>          <dbl>                <dbl>               <dbl>           <dbl>
## 1 JPM           0.0127              -0.0267             -0.0411           0.473
## 2 DIS           0.0126              -0.0263             -0.0422           0.620
## 3 ^GSPC         0.0089              -0.0183             -0.03             0.361
## 4 BAC           0.0145              -0.0303             -0.0478           0.526

##         From     Trough         To   Depth Length To Trough Recovery
## 1 2020-02-20 2020-03-23 2020-09-02 -0.3610    137        23      114
## 2 2022-01-04 2022-10-12       <NA> -0.2711    302       195       NA
## 3 2018-09-21 2018-12-24 2019-07-01 -0.2025    194        65      129
## 4 2015-05-22 2016-02-11 2016-07-18 -0.1516    291       183      108
## 5 2018-01-29 2018-04-02 2018-08-27 -0.1056    147        44      103

charts.PerformanceSummary(fb_return_xts, 
                          ylog       = TRUE,
                          legend.loc = "topleft",
                          main       = "Tesla stock Performance"
)

##         From     Trough         To   Depth Length To Trough Recovery
## 1 2020-01-03 2020-03-23 2021-05-05 -0.4730    337        55      282
## 2 2021-10-25 2022-10-11       <NA> -0.4115    351       243       NA
## 3 2015-07-23 2016-02-11 2016-11-09 -0.2481    330       141      189
## 4 2018-02-27 2018-12-24 2019-09-13 -0.2254    390       209      181
## 5 2017-03-02 2017-05-31 2017-07-05 -0.1205     87        63       24

charts.PerformanceSummary(fb_return_xts, 
                          ylog       = TRUE,
                          legend.loc = "topleft",
                          main       = "Apple stock Performance"
)

##         From     Trough         To   Depth Length To Trough Recovery
## 1 2021-03-09 2022-12-28       <NA> -0.6195    511       457       NA
## 2 2019-11-27 2020-03-23 2020-12-11 -0.4568    263        79      184
## 3 2015-08-05 2016-02-10 2019-04-12 -0.2820    929       131      798
## 4 2019-07-30 2019-10-03 2019-11-13 -0.1293     76        47       29
## 5 2021-01-04 2021-01-27 2021-02-08 -0.1016     25        17        8

charts.PerformanceSummary(fb_return_xts, 
                          ylog       = TRUE,
                          legend.loc = "topleft",
                          main       = "Disney stock Performance"
)

##         From     Trough         To   Depth Length To Trough Recovery
## 1 2020-01-03 2020-03-23 2021-05-06 -0.5255    338        55      283
## 2 2022-02-09 2023-03-15       <NA> -0.4375    277       275       NA
## 3 2015-07-23 2016-02-11 2016-11-14 -0.4101    333       141      192
## 4 2018-03-13 2018-12-24 2019-12-06 -0.3139    439       199      240
## 5 2021-06-07 2021-07-19 2021-10-05 -0.1508     85        30       55

charts.PerformanceSummary(fb_return_xts, 
                          ylog       = TRUE,
                          legend.loc = "topleft",
                          main       = "Adobe stock Performance"
)

3 Vietnamese stocks

new=NULL
id_list=c("TCB","TPB","BID","VCB")
for (j in id_list){
  for (i in 1:10){
    query_params <- list(currentPage=i,id = j)
    parameter_response <- GET("https://www.cophieu68.vn/historyprice.php", query = query_params)
    stock_share =read_html(parameter_response)
    new1=html_nodes(stock_share, xpath="//table[@class='stock']") %>%
      html_table(header = TRUE,fill=TRUE) %>% as.data.frame()
    new1=new1[,2:13]
    new1$symbol=j
    new=rbind(new,new1)
  }}
## Warning: NAs introduced by coercion

## Warning: NAs introduced by coercion

## Warning: NAs introduced by coercion

## Warning: NAs introduced by coercion

## Warning: NAs introduced by coercion

## Warning: NAs introduced by coercion

## Warning: NAs introduced by coercion

## Warning: NAs introduced by coercion

## Warning: NAs introduced by coercion

## Warning: NAs introduced by coercion

## Warning: NAs introduced by coercion

3.1 Asset prices series

3.1.1 Daily prices

3.1.2 Monthly stock prices

monthly_prices=prices %>% group_by(symbol) %>%
  tq_transmute(select     = 2:12, 
               mutate_fun = to.period, 
               period     = "months")
glimpse(monthly_prices)
## Rows: 196
## Columns: 13
## Groups: symbol [4]
## $ symbol                  <chr> "TCB", "TCB", "TCB", "TCB", "TCB", "TCB", "TCB…
## $ date                    <date> 2019-03-29, 2019-04-26, 2019-05-31, 2019-06-2…
## $ Last_closed_price       <dbl> 25.55, 24.15, 22.95, 20.20, 20.70, 21.35, 23.2…
## $ absolute_price_change   <dbl> 0.05, 0.00, -0.35, 0.15, -0.15, 0.15, 0.15, -0…
## $ Percentage_price_change <dbl> 0.001956947, 0.000000000, -0.015250545, 0.0074…
## $ Closed_price            <dbl> 25.60, 24.15, 22.60, 20.35, 20.55, 21.50, 23.3…
## $ Trading_Volume          <dbl> 1656270, 898530, 1452700, 2795060, 1219550, 12…
## $ Open_price              <dbl> 25.55, 24.05, 22.95, 20.35, 20.70, 21.40, 23.3…
## $ Highest_price           <dbl> 25.80, 24.20, 23.00, 20.40, 20.70, 21.50, 23.5…
## $ Lowest_price            <dbl> 25.55, 24.00, 22.60, 19.95, 20.55, 21.25, 23.1…
## $ Exchange_volume         <dbl> 4086090, 0, 0, 12202710, 0, 20000, 0, 100000, …
## $ Foregin_buy_volume      <dbl> 4105880, 0, 0, 141490, 2669990, 0, 0, 0, 0, 0,…
## $ Foreign_sell_volume     <dbl> 4104580, 0, 0, 141490, 2669990, 0, 0, 0, 0, 0,…

3.1.3 Yearly stock prices

yearly_prices=prices %>% group_by(symbol) %>%
  tq_transmute(select     = 2:12, 
               mutate_fun = to.period, 
               period     = "years")
glimpse(yearly_prices)
## Rows: 20
## Columns: 13
## Groups: symbol [4]
## $ symbol                  <chr> "TCB", "TCB", "TCB", "TCB", "TCB", "TPB", "TPB…
## $ date                    <date> 2019-12-31, 2020-12-31, 2021-12-31, 2022-12-3…
## $ Last_closed_price       <dbl> 23.45, 29.90, 49.30, 25.95, 26.75, 12.79, 19.6…
## $ absolute_price_change   <dbl> 0.10, 1.60, 0.70, -0.10, -0.10, -0.03, 0.19, 0…
## $ Percentage_price_change <dbl> 0.004264392, 0.053511706, 0.014198783, -0.0038…
## $ Closed_price            <dbl> 23.55, 31.50, 50.00, 25.85, 26.65, 12.76, 19.8…
## $ Trading_Volume          <dbl> 731740, 16486510, 9547100, 2181900, 1199600, 4…
## $ Open_price              <dbl> 23.45, 29.95, 49.50, 25.95, 26.80, 12.82, 19.8…
## $ Highest_price           <dbl> 23.75, 31.75, 50.50, 26.10, 27.10, 12.82, 19.9…
## $ Lowest_price            <dbl> 23.45, 29.90, 49.45, 25.85, 26.60, 12.73, 19.5…
## $ Exchange_volume         <dbl> 229800, 0, 391300, 3321000, 0, 0, 0, 120300, 0…
## $ Foregin_buy_volume      <dbl> 0, 9030, 0, 115, 329200, 0, 10, 57700, 7340, 1…
## $ Foreign_sell_volume     <dbl> 0, 50, 0, 0, 329200, 0, 0, 11000, 0, 27100, 13…

3.2 Asset prices to returns

3.2.1 Daily return

prices_daily_log_returns <- prices %>%
  group_by(symbol) %>%
  tq_transmute(select     = Closed_price, 
               mutate_fun = periodReturn, 
               period     = "daily", 
               type       = "log",
               col_rename = "daily.returns")

prices_daily_log_returns %>% ggplot(aes(x=date, y=daily.returns, col=symbol))+geom_line()+facet_wrap(symbol~.)

prices_daily_log_returns %>%
  ggplot(aes(x = daily.returns, fill = symbol)) +
  geom_histogram(alpha = 0.5) +
  labs(title = "Charting the Daily Log Returns",
       x = "Daily Returns", y = "Density") +
  theme_tq() +
  scale_fill_tq() + 
  facet_wrap(~ symbol, ncol = 2)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

3.2.2 Monthly returns

prices_monthly_log_returns <- prices %>%
  group_by(symbol) %>%
  tq_transmute(select     = Closed_price, 
               mutate_fun = periodReturn, 
               period     = "monthly", 
               type       = "log",
               col_rename = "monthly.returns")


prices_monthly_log_returns%>%
  ggplot(aes(x = monthly.returns)) +
  geom_density(aes(color =symbol), alpha = 1) +
  geom_histogram(aes(fill = symbol), alpha = 0.45, binwidth = .01) +
  guides(fill = FALSE) +
  facet_wrap(~symbol) +
  ggtitle("Monthly Returns") +
  xlab("monthly returns") +
  ylab("distribution") +
  theme_update(plot.title = element_text(hjust = 0.5))

prices_monthly_log_returns%>%
  ggplot(aes(x = monthly.returns)) +
  geom_boxplot(aes(fill =symbol), alpha = 1) +
  ggtitle("Monthly Returns") +
  xlab("monthly returns") +
  ylab("distribution") +
  theme_update(plot.title = element_text(hjust = 0.5))

3.2.3 Yearly returns

prices_yearly_log_returns <- prices %>%
  group_by(symbol) %>%
  tq_transmute(select     = Closed_price, 
               mutate_fun = periodReturn, 
               period     = "yearly", 
               type       = "log",
               col_rename = "yearly.returns")
prices_yearly_log_returns %>% ggplot(aes(x=date, y=yearly.returns,col=symbol))+geom_line()+facet_wrap(.~symbol)

3.3 Mean return for the whole period

3.3.1 Daily mean return for the whole period

prices_daily_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = daily.returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  select(ArithmeticMean,Median, Maximum, Minimum) %>%
  group_by(symbol) %>% 
  summarize(mean_return = round(ArithmeticMean, 4) * 100,
            median_return = round(Median, 4) * 100,
            maximum_return = round(Maximum, 4) * 100,
            minimum_return = round(Minimum, 4) * 100)
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 5
##   symbol mean_return median_return maximum_return minimum_return
##   <chr>        <dbl>         <dbl>          <dbl>          <dbl>
## 1 BID           0.05             0           6.77          -7.24
## 2 TCB           0                0           6.73          -7.25
## 3 TPB           0.07             0           6.74          -7.27
## 4 VCB           0.06             0           6.67          -7.24
prices_daily_log_returns %>% ggplot(aes(x=date, y=daily.returns, col=symbol))+geom_line()+facet_wrap(symbol~.)

3.3.2 Monthly mean return for the whole period

prices_monthly_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = monthly.returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  select(ArithmeticMean,Median, Maximum, Minimum) %>%
  group_by(symbol) %>% 
  summarize(mean_return = round(ArithmeticMean, 4) * 100,
            median_return = round(Median, 4) * 100,
            maximum_return = round(Maximum, 4) * 100,
            minimum_return = round(Minimum, 4) * 100)
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 5
##   symbol mean_return median_return maximum_return minimum_return
##   <chr>        <dbl>         <dbl>          <dbl>          <dbl>
## 1 BID           1.05          1.26           25.6          -38.8
## 2 TCB           0             0.56           27.0          -39.4
## 3 TPB           1.38          0.22           31.2          -22.1
## 4 VCB           1.15          0.82           22.6          -28.4
prices_monthly_log_returns %>% ggplot(aes(x=date, y=monthly.returns, col=symbol))+geom_line()+facet_wrap(symbol~.)

3.3.3 Yearly mean return for the whole period

prices_yearly_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = yearly.returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  select(ArithmeticMean,Median, Maximum, Minimum) %>%
  group_by(symbol) %>% 
  summarize(mean_return = round(ArithmeticMean, 4) * 100,
            median_return = round(Median, 4) * 100,
            maximum_return = round(Maximum, 4) * 100,
            minimum_return = round(Minimum, 4) * 100)
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 5
##   symbol mean_return median_return maximum_return minimum_return
##   <chr>        <dbl>         <dbl>          <dbl>          <dbl>
## 1 BID          10.3           5.39           26.2          -2.16
## 2 TCB           0.04          3.05           46.2         -66.0 
## 3 TPB          13.6          18.4            72.7         -66.8 
## 4 VCB          11.2           9              31.1           1.51
prices_yearly_log_returns %>% ggplot(aes(x=date, y=yearly.returns, col=symbol))+geom_line()+facet_wrap(symbol~.)

3.4 Stock volatility for the whole period

3.4.1 Daily Stock volatility for the whole period

prices_daily_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = daily.returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  select(ArithmeticMean,Median,Stdev, Maximum, Minimum) %>%
  group_by(symbol) %>% 
  summarize(mean_return = round(ArithmeticMean, 4) * 100,
            median_return = round(Median, 4) * 100,
            volatility=round(Stdev, 4) * 100,
            maximum_return = round(Maximum, 4) * 100,
            minimum_return = round(Minimum, 4) * 100)
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 6
##   symbol mean_return median_return volatility maximum_return minimum_return
##   <chr>        <dbl>         <dbl>      <dbl>          <dbl>          <dbl>
## 1 BID           0.05             0       2.31           6.77          -7.24
## 2 TCB           0                0       2.25           6.73          -7.25
## 3 TPB           0.07             0       2.26           6.74          -7.27
## 4 VCB           0.06             0       1.78           6.67          -7.24
prices_daily_log_returns %>%  ggplot(aes(x=daily.returns,col=symbol))+geom_boxplot()+facet_wrap(symbol~.)

3.4.2 Monthly Stock volatility for the whole period

prices_monthly_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = monthly.returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  select(ArithmeticMean,Median,Stdev, Maximum, Minimum) %>%
  group_by(symbol) %>% 
  summarize(mean_return = round(ArithmeticMean, 4) * 100,
            median_return = round(Median, 4) * 100,
            volatility=round(Stdev, 4) * 100,
            maximum_return = round(Maximum, 4) * 100,
            minimum_return = round(Minimum, 4) * 100)
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 6
##   symbol mean_return median_return volatility maximum_return minimum_return
##   <chr>        <dbl>         <dbl>      <dbl>          <dbl>          <dbl>
## 1 BID           1.05          1.26      11.4            25.6          -38.8
## 2 TCB           0             0.56      12.0            27.0          -39.4
## 3 TPB           1.38          0.22      10.5            31.2          -22.1
## 4 VCB           1.15          0.82       8.62           22.6          -28.4
prices_monthly_log_returns %>%  ggplot(aes(x=monthly.returns,col=symbol))+geom_boxplot()+facet_wrap(symbol~.)

3.4.3 Yearly Stock volatility for the whole period

prices_yearly_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = yearly.returns,
                 Rb = NULL,
                 performance_fun = table.Stats) %>%
  select(ArithmeticMean,Median,Stdev, Maximum, Minimum) %>%
  group_by(symbol) %>% 
  summarize(mean_return = round(ArithmeticMean, 4) * 100,
            median_return = round(Median, 4) * 100,
            volatility=round(Stdev, 4) * 100,
            maximum_return = round(Maximum, 4) * 100,
            minimum_return = round(Minimum, 4) * 100)
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 6
##   symbol mean_return median_return volatility maximum_return minimum_return
##   <chr>        <dbl>         <dbl>      <dbl>          <dbl>          <dbl>
## 1 BID          10.3           5.39       11.6           26.2          -2.16
## 2 TCB           0.04          3.05       43.3           46.2         -66.0 
## 3 TPB          13.6          18.4        52.7           72.7         -66.8 
## 4 VCB          11.2           9          11.7           31.1           1.51
prices_yearly_log_returns %>%  ggplot(aes(x=yearly.returns,col=symbol))+geom_boxplot()+facet_wrap(symbol~.)

3.5 Rolling stock volatility

3.5.1 Rolling daily stock volatility

daily_window=30
daily_return_rolling=prices_daily_log_returns %>% group_by(symbol) %>% 
  mutate(rolling_mean_return = rollapply(daily.returns,
                                         FUN = mean,
                                         width = daily_window,align="right",
                                         fill = NA),
         rolling_median_return = rollapply(daily.returns,
                                           FUN = median,
                                           width = daily_window,
                                           fill = NA),
         rolling_max_return = rollapply(daily.returns,
                                        FUN = max,
                                        width = daily_window,
                                        fill = NA),
         rolling_min_return = rollapply(daily.returns,
                                        FUN = min,
                                        width = daily_window,
                                        fill = NA),
         rolling_volatility = rollapply(daily.returns,
                                        FUN = sd,
                                        width = daily_window,
                                        fill = NA))

3.5.1.1 Rolling daily mean return

daily_return_rolling %>% ggplot(aes(x=date, y=rolling_mean_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 116 rows containing missing values (`geom_line()`).

3.5.1.2 Rolling maximum daily return

daily_return_rolling %>% ggplot(aes(x=date, y=rolling_max_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 116 rows containing missing values (`geom_line()`).

3.5.1.3 Rolling minimum daily return

daily_return_rolling %>% ggplot(aes(x=date, y=rolling_min_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 116 rows containing missing values (`geom_line()`).

3.5.1.4 Rolling daily volatility return

daily_return_rolling %>% ggplot(aes(x=date, y=rolling_volatility*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 116 rows containing missing values (`geom_line()`).

3.5.2 Rolling monthly stock volatility

monthly_window=12
monthly_return_rolling=prices_monthly_log_returns %>% group_by(symbol) %>% 
  mutate(rolling_mean_return = rollapply(monthly.returns,
                                         FUN = mean,
                                         width = monthly_window,align="right",
                                         fill = NA),
         rolling_median_return = rollapply(monthly.returns,
                                           FUN = median,
                                           width = monthly_window,
                                           fill = NA),
         rolling_max_return = rollapply(monthly.returns,
                                        FUN = max,
                                        width = monthly_window,
                                        fill = NA),
         rolling_min_return = rollapply(monthly.returns,
                                        FUN = min,
                                        width = monthly_window,
                                        fill = NA),
         rolling_volatility = rollapply(monthly.returns,
                                        FUN = sd,
                                        width = monthly_window,
                                        fill = NA))

3.5.2.1 Rolling monthly mean return

monthly_return_rolling %>% ggplot(aes(x=date, y=rolling_mean_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 44 rows containing missing values (`geom_line()`).

3.5.2.2 Rolling maximum monthly return

monthly_return_rolling %>% ggplot(aes(x=date, y=rolling_max_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 44 rows containing missing values (`geom_line()`).

3.5.2.3 Rolling minimum monthly return

monthly_return_rolling %>% ggplot(aes(x=date, y=rolling_min_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 44 rows containing missing values (`geom_line()`).

3.5.2.4 Rolling monthly volatility return

monthly_return_rolling %>% ggplot(aes(x=date, y=rolling_volatility*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 44 rows containing missing values (`geom_line()`).

3.5.3 Rolling yearly stock volatility

yearly_window=3
yearly_return_rolling=prices_yearly_log_returns %>% group_by(symbol) %>% 
  mutate(rolling_mean_return = rollapply(yearly.returns,
                                         FUN = mean,
                                         width = yearly_window,align="right",
                                         fill = NA),
         rolling_median_return = rollapply(yearly.returns,
                                           FUN = median,
                                           width = yearly_window,
                                           fill = NA),
         rolling_max_return = rollapply(yearly.returns,
                                        FUN = max,
                                        width = yearly_window,
                                        fill = NA),
         rolling_min_return = rollapply(yearly.returns,
                                        FUN = min,
                                        width = yearly_window,
                                        fill = NA),
         rolling_volatility = rollapply(yearly.returns,
                                        FUN = sd,
                                        width = yearly_window,
                                        fill = NA))
glimpse(yearly_return_rolling)
## Rows: 20
## Columns: 8
## Groups: symbol [4]
## $ symbol                <chr> "TCB", "TCB", "TCB", "TCB", "TCB", "TPB", "TPB",…
## $ date                  <date> 2019-12-31, 2020-12-31, 2021-12-31, 2022-12-30,…
## $ yearly.returns        <dbl> -0.121785395, 0.290861725, 0.462035460, -0.65971…
## $ rolling_mean_return   <dbl> NA, NA, 0.21037060, 0.03106159, -0.05573280, NA,…
## $ rolling_median_return <dbl> NA, 0.29086173, 0.29086173, 0.03047855, NA, NA, …
## $ rolling_max_return    <dbl> NA, 0.46203546, 0.46203546, 0.46203546, NA, NA, …
## $ rolling_min_return    <dbl> NA, -0.121785395, -0.659712404, -0.659712404, NA…
## $ rolling_volatility    <dbl> NA, 0.30011800, 0.60431916, 0.56582141, NA, NA, …

3.5.3.1 Rolling yearly mean return

yearly_return_rolling %>% ggplot(aes(x=date, y=rolling_mean_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 8 rows containing missing values (`geom_line()`).

3.5.3.2 Rolling maximum yearly return

yearly_return_rolling %>% ggplot(aes(x=date, y=rolling_max_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 8 rows containing missing values (`geom_line()`).

3.5.3.3 Rolling minimum yearly return

yearly_return_rolling %>% ggplot(aes(x=date, y=rolling_min_return*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 8 rows containing missing values (`geom_line()`).

3.5.3.4 Rolling yearly volatility return

yearly_return_rolling %>% ggplot(aes(x=date, y=rolling_volatility*100,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 8 rows containing missing values (`geom_line()`).

3.6 Shape of return distribution

3.6.1 Skewness and kurtosis for the whole period

3.6.1.1 Daily returns

prices_daily_log_returns%>%
  ggplot(aes(x = daily.returns)) +
  geom_density(aes(color =symbol), alpha = 1) +
  geom_histogram(aes(fill = symbol), alpha = 0.45, binwidth = .01) +
  guides(fill = FALSE) +
  facet_wrap(~symbol) +
  ggtitle("daily Returns") +
  xlab("daily returns") +
  ylab("distribution") +
  theme_update(plot.title = element_text(hjust = 0.5))

prices_daily_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = daily.returns,
                 Rb = NULL,
                 performance_fun = table.Distributions) %>%
  select(Skewness,Kurtosis) 
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 3
## # Groups:   symbol [4]
##   symbol Skewness Kurtosis
##   <chr>     <dbl>    <dbl>
## 1 TCB      -0.384     5.25
## 2 TPB      -0.174     4.86
## 3 BID      -0.326     4.63
## 4 VCB      -0.210     5.23

3.6.1.2 Monthly returns

prices_monthly_log_returns%>%
  ggplot(aes(x = monthly.returns)) +
  geom_density(aes(color =symbol), alpha = 1) +
  geom_histogram(aes(fill = symbol), alpha = 0.45, binwidth = .01) +
  guides(fill = FALSE) +
  facet_wrap(~symbol) +
  ggtitle("Monthly Returns") +
  xlab("monthly returns") +
  ylab("distribution") +
  theme_update(plot.title = element_text(hjust = 0.5))

prices_monthly_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = monthly.returns,
                 Rb = NULL,
                 performance_fun = table.Distributions) %>%
  select(Skewness,Kurtosis) 
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 3
## # Groups:   symbol [4]
##   symbol Skewness Kurtosis
##   <chr>     <dbl>    <dbl>
## 1 TCB      -0.414     4.84
## 2 TPB       0.358     3.66
## 3 BID      -0.717     4.63
## 4 VCB      -0.496     5.06

3.6.2 Rolling monthly Skewness and Kurtosis

monthly_window=12
monthly_normality_rolling=prices_monthly_log_returns %>% group_by(symbol) %>% 
  mutate(rolling_skew_return = rollapply(monthly.returns,
                                         FUN = skewness,
                                         width = monthly_window,align="right",
                                         fill = NA),
         rolling_kurtosis_return = rollapply(monthly.returns,
                                             FUN = kurtosis,
                                             width = monthly_window,align="right",
                                             fill = NA))
monthly_normality_rolling %>% ggplot(aes(x=date, y=rolling_skew_return,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 44 rows containing missing values (`geom_line()`).

monthly_normality_rolling %>% ggplot(aes(x=date, y=rolling_kurtosis_return,col=symbol))+geom_line()+facet_wrap(symbol~.)
## Warning: Removed 44 rows containing missing values (`geom_line()`).

3.7 Downside risk measures

prices_daily_log_returns %>% group_by(symbol) %>% 
  tq_performance(Ra = daily.returns,
                 Rb = NULL,
                 performance_fun = table.DownsideRisk) %>%
  select(SemiDeviation,"HistoricalVaR(95%)" , "HistoricalES(95%)",MaximumDrawdown) 
## Adding missing grouping variables: `symbol`
## # A tibble: 4 × 5
## # Groups:   symbol [4]
##   symbol SemiDeviation `HistoricalVaR(95%)` `HistoricalES(95%)` MaximumDrawdown
##   <chr>          <dbl>                <dbl>               <dbl>           <dbl>
## 1 TCB           0.0165              -0.0398             -0.0598           0.675
## 2 TPB           0.0162              -0.0387             -0.0567           0.578
## 3 BID           0.0169              -0.0395             -0.0587           0.462
## 4 VCB           0.0127              -0.0266             -0.0424           0.405

3.7.1 TCB stock performance

fb=prices %>% filter(symbol=='TCB') %>% select(symbol, date, open=Open_price,high=Highest_price, low=Lowest_price,close=Closed_price, volume=Exchange_volume)
glimpse(fb)
## Rows: 1,000
## Columns: 7
## $ symbol <chr> "TCB", "TCB", "TCB", "TCB", "TCB", "TCB", "TCB", "TCB", "TCB", …
## $ date   <date> 2023-03-17, 2023-03-16, 2023-03-15, 2023-03-14, 2023-03-13, 20…
## $ open   <dbl> 26.80, 26.90, 26.80, 26.65, 26.55, 27.50, 27.50, 26.90, 27.20, …
## $ high   <dbl> 27.10, 26.95, 27.40, 26.75, 26.95, 27.60, 27.85, 27.40, 27.50, …
## $ low    <dbl> 26.60, 26.60, 26.80, 26.30, 26.55, 27.00, 27.20, 26.80, 27.05, …
## $ close  <dbl> 26.65, 26.70, 27.20, 26.30, 26.75, 27.15, 27.80, 27.30, 27.10, …
## $ volume <dbl> 0, 0, 2406200, 1571600, 41232600, 0, 1529500, 720000, 54000, 45…
fb_xts=xts(fb[,3:7], order.by = fb$date)
fb_xts%>% 
  chartSeries( 
    # Add Bollinger Bands, Volume, Moving Average Convergence/Divergence
    TA = 'addBBands();
          addVo();
 addRSI();
          '
    , 
    theme  = chartTheme("white.mono"),                    
    name = "TCB Stock Prices Evolution", 
    minor.ticks = FALSE, 
    up.col = "seagreen3", 
    dn.col = "indianred2",
    colov.vol = c("indianred2", "seagreen2")
  )  

fb_r=prices_daily_log_returns %>% filter(symbol=="TCB")
fb_return_xts=xts(fb_r[,3],order.by=fb_r$date)
table.Drawdowns(fb_return_xts)
##         From     Trough         To   Depth Length To Trough Recovery
## 1 2021-07-06 2022-11-15       <NA> -0.6753    426       343       NA
## 2 2019-03-21 2020-03-30 2020-12-18 -0.4642    442       257      185
## 3 2021-01-18 2021-01-28 2021-02-17 -0.1598     18         9        9
## 4 2021-06-04 2021-06-08 2021-07-05 -0.0990     22         3       19
## 5 2021-04-08 2021-04-26 2021-05-04 -0.0672     16        12        4
# Plot of drawdowns
chart.Drawdown(fb_return_xts)

charts.PerformanceSummary(fb_return_xts, 
                          ylog       = TRUE,
                          legend.loc = "topleft",
                          main       = "TCB stock Performance"
)

3.7.2 TPB stock performance

fb=prices %>% filter(symbol=='TPB') %>% select(symbol, date, open=Open_price,high=Highest_price, low=Lowest_price,close=Closed_price, volume=Exchange_volume)
glimpse(fb)
## Rows: 1,000
## Columns: 7
## $ symbol <chr> "TPB", "TPB", "TPB", "TPB", "TPB", "TPB", "TPB", "TPB", "TPB", …
## $ date   <date> 2023-03-17, 2023-03-16, 2023-03-15, 2023-03-14, 2023-03-13, 20…
## $ open   <dbl> 24.65, 24.55, 24.60, 24.45, 23.70, 24.20, 24.00, 23.40, 23.70, …
## $ high   <dbl> 25.50, 24.60, 25.10, 24.45, 24.60, 24.45, 24.55, 24.00, 23.80, …
## $ low    <dbl> 24.65, 24.35, 24.30, 23.85, 23.65, 23.90, 23.90, 23.30, 23.40, …
## $ close  <dbl> 25.30, 24.35, 24.65, 24.20, 24.30, 24.00, 24.50, 23.95, 23.50, …
## $ volume <dbl> 0, 0, 0, 0, 0, 0, 0, 20191, 0, 0, 0, 0, 0, 110000, 0, 0, 800000…
fb_xts=xts(fb[,3:7], order.by = fb$date)
fb_xts%>% 
  chartSeries( 
    # Add Bollinger Bands, Volume, Moving Average Convergence/Divergence
    TA = 'addBBands();
          addVo();
 addRSI();
          '
    , 
    theme  = chartTheme("white.mono"),                    
    name = "TPB Stock Prices Evolution", 
    minor.ticks = FALSE, 
    up.col = "seagreen3", 
    dn.col = "indianred2",
    colov.vol = c("indianred2", "seagreen2")
  )  

fb_r=prices_daily_log_returns %>% filter(symbol=="TPB")
fb_return_xts=xts(fb_r[,3],order.by=fb_r$date)
table.Drawdowns(fb_return_xts)
##         From     Trough         To   Depth Length To Trough Recovery
## 1 2022-01-13 2022-10-11       <NA> -0.5776    292       184       NA
## 2 2019-06-12 2020-04-01 2020-11-30 -0.3814    373       204      169
## 3 2021-07-06 2021-07-19 2021-09-17 -0.2046     52        10       42
## 4 2021-01-19 2021-01-28 2021-03-02 -0.1939     26         8       18
## 5 2021-06-07 2021-06-08 2021-07-05 -0.1052     21         2       19
# Plot of drawdowns
chart.Drawdown(fb_return_xts)

charts.PerformanceSummary(fb_return_xts, 
                          ylog       = TRUE,
                          legend.loc = "topleft",
                          main       = "TPB stock Performance"
)