#=====================================================
# Reference: https://www.pfaffikus.de/books/jwex2/
#=====================================================
# Clear workspace:
rm(list = ls())
# Import data:
library(tidyverse)
read_csv("C:/Users/Admin/Documents/CafeF.HSX.Upto27.01.2021.csv") -> raw_data
# Select and rename some columns:
raw_data %>%
select(1, 2, 6) -> raw_data_mini
names(raw_data_mini) <- c("symbol", "date_ymd", "close")
# Select some symbols:
symbols_vn30 <- readxl::read_excel("C:/Users/Admin/Documents/data.xlsx", sheet = 1) %>% pull(2)
# Filter data belongs to VN30
library(lubridate)
my_date <- "2016-12-28"
raw_data_mini %>%
mutate(date_ymd = ymd(date_ymd)) %>%
filter(symbol %in% symbols_vn30, date_ymd >= ymd(my_date)) -> df_return_long
# Stocks that >= 1021 observations:
df_return_long %>%
group_by(symbol) %>%
count(sort = TRUE) %>%
ungroup() %>%
filter(n >= 1021) %>%
pull(symbol) -> my_symbols
# Convert to wide form and claculate return:
df_return_long %>%
filter(symbol %in% my_symbols) %>%
pivot_wider(names_from = symbol, values_from = close) %>%
slice(order(date_ymd)) %>%
mutate_if(is.numeric, function(x) {x / lag(x, n = 1L) - 1}) %>%
na.omit() -> data_wide_return
# Function calculates portfolio return:
library(fPortfolio)
window_size <- 700
portfolio_return <- function(k_initial) {
data_wide_return %>% slice((1 + k_initial):(window_size + k_initial)) -> train_data
data_wide_return %>% slice(window_size + k_initial + 1) -> test_data
# Prepare data for back-testing and portfolio optimization:
date_ymd <- train_data$date_ymd
stocks_data <- train_data %>% select(-date_ymd)
stocks_data %>%
timeSeries::timeSeries(charvec = as.character(date_ymd)) %>%
na.omit() -> stock_return
# Portfolio 1:
pspec <- portfolioSpec()
gmv <- pspec
gmvpf <- minvariancePortfolio(data = stock_return, spec = pspec, constraints = "LongOnly")
wGMV <- getWeights(gmvpf)
test_data %>%
select(-date_ymd) %>%
as.vector() -> asset_returns
p_return_minVar <- sum(asset_returns*wGMV)
# Portfolio 2:
cvar <- pspec
setType(cvar) <- "CVaR"
setAlpha(cvar) <- 0.1
setSolver(cvar) <- "solveRglpk.CVAR"
cvarpf <- minriskPortfolio(data = stock_return, spec = cvar, constraints = "LongOnly")
wCVAR <- getWeights(cvarpf)
p_return_minRisk <- sum(asset_returns*wCVAR)
test_data %>%
mutate(p_return_minVar = p_return_minVar,
p_return_minRisk = p_return_minRisk) -> port_return
return(port_return)
}
# Use the function:
n_days <- nrow(data_wide_return)
n_future_days <- n_days - window_size - 1
lapply(0:n_future_days, portfolio_return) -> port_return_list
do.call("bind_rows", port_return_list) -> port_return_rolling
initial_investment <- 100
k <- nrow(port_return_rolling)
calculate_port_return_t <- function(t) {
port_return_rolling$p_return_minVar[1:t] + 1 -> r_minVar
port_return_rolling$p_return_minRisk[1:t] + 1 -> r_minRisk
prod(r_minVar) -> r_minVar
value_minVar <- r_minVar*initial_investment
prod(r_minRisk) -> r_minRisk
value_minRisk <- r_minRisk*initial_investment
port_return_rolling %>%
slice(t) %>%
select(date_ymd, contains("return")) %>%
mutate(value_minRisk = value_minRisk, value_minVar = value_minVar) -> df_final
return(df_final)
}
lapply(1:k, calculate_port_return_t) -> return_port_list
do.call("bind_rows", return_port_list) -> port_values
port_values %>%
select(date_ymd, contains("value")) %>%
pivot_longer(cols = c("value_minRisk", "value_minVar"), names_to = "type", values_to = "value") -> df_long
df_long %>%
ggplot(aes(date_ymd, value, color = type)) +
geom_line() +
theme(legend.title = element_blank()) +
labs(title = "Backtesting for comparing Daily-Value of Portfolio", x = NULL, y = "Investment Value") -> p
plotly::ggplotly(p)