Load data
library(quantmod)
## Warning: package 'quantmod' was built under R version 4.3.3
## Loading required package: xts
## Warning: package 'xts' was built under R version 4.3.3
## Loading required package: zoo
## Warning: package 'zoo' was built under R version 4.3.3
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
## Loading required package: TTR
## Warning: package 'TTR' was built under R version 4.3.3
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
library(xts)
library(PerformanceAnalytics)
## Warning: package 'PerformanceAnalytics' was built under R version 4.3.3
##
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
library(quadprog)
# Tải dữ liệu từ Yahoo Finance
getSymbols("HSG.VN", src = "yahoo", from = "2015-01-01", to = "2025-01-01")
## Warning: HSG.VN 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.
## [1] "HSG.VN"
getSymbols("VCB.VN", src = "yahoo", from = "2015-01-01", to = "2025-01-01")
## Warning: VCB.VN 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.
## [1] "VCB.VN"
getSymbols("PNJ.VN", src = "yahoo", from = "2015-01-01", to = "2025-01-01")
## Warning: PNJ.VN 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.
## [1] "PNJ.VN"
getSymbols("MBB.VN", src = "yahoo", from = "2015-01-01", to = "2025-01-01")
## Warning: MBB.VN 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.
## [1] "MBB.VN"
getSymbols("BID.VN", src = "yahoo", from = "2015-01-01", to = "2025-01-01")
## Warning: BID.VN 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.
## [1] "BID.VN"
# Chuyển đổi dữ liệu thành dạng weekly
vcb <- to.weekly(VCB.VN)
## Warning in to.period(x, "weeks", name = name, ...): missing values removed from
## data
HSG <- to.weekly(HSG.VN)
## Warning in to.period(x, "weeks", name = name, ...): missing values removed from
## data
PNJ <- to.weekly(PNJ.VN)
## Warning in to.period(x, "weeks", name = name, ...): missing values removed from
## data
MBB <- to.weekly(MBB.VN)
## Warning in to.period(x, "weeks", name = name, ...): missing values removed from
## data
bid <- to.weekly(BID.VN)
## Warning in to.period(x, "weeks", name = name, ...): missing values removed from
## data
# Kết hợp dữ liệu từ tất cả các cổ phiếu và chỉ giữ lại ngày chung
data_xts <- merge.xts(vcb$VCB.VN.Close, HSG$HSG.VN.Close, PNJ$PNJ.VN.Close, MBB$MBB.VN.Close, bid$BID.VN.Close)
# Đổi tên cột cho dễ hiểu
colnames(data_xts) <- c("VCB", "HSG", "PNJ", "MBB", "BID")
# Loại bỏ các dòng có NA (dữ liệu thiếu)
data_xts <- na.omit(data_xts)
# Tính toán lợi suất logarit
data_rt <- CalculateReturns(data_xts, method = "log")[-1,]
# Tính ma trận hiệp phương sai và kỳ vọng
covar <- cov(data_rt)
er <- sapply(data_rt, mean)
# Hàm giải bài toán Frontier Portfolio
frontier_portfolio <- function(expected_returns, cov_matrix, target_return) {
n <- length(expected_returns)
# Ma trận D cho hàm mục tiêu (1/2)w'Vw
Dmat <- cov_matrix
# Vector d cho hàm mục tiêu (ở đây bằng 0)
dvec <- rep(0, n)
# Ràng buộc:
# 1. Tổng trọng số bằng 1
# 2. Lợi nhuận kỳ vọng bằng target_return
# 3. Tất cả trọng số >= 0 (nếu muốn không cho phép bán khống)
Amat <- cbind(
rep(1, n), # Ràng buộc tổng trọng số
expected_returns, # Ràng buộc lợi nhuận
diag(n) # Ràng buộc không âm (tùy chọn)
)
bvec <- c(
1, # Tổng trọng số bằng 1
target_return, # Lợi nhuận mục tiêu
rep(0, n) # Trọng số >= 0 (tùy chọn)
)
# Giải bài toán
solution <- solve.QP(
Dmat = Dmat,
dvec = dvec,
Amat = Amat,
bvec = bvec,
meq = 2 # 2 ràng buộc đầu là đẳng thức
)
# Trả về trọng số tối ưu
weights <- solution$solution
names(weights) <- names(expected_returns)
return(weights)
}
# Tính toán danh mục với lợi nhuận mục tiêu 0.3%
target_return <- 0.003
optimal_weights <- frontier_portfolio(er, covar, target_return)
# Kết quả
print("Trọng số tối ưu:")
## [1] "Trọng số tối ưu:"
print(optimal_weights)
## VCB HSG PNJ MBB BID
## 1.339461e-01 0.000000e+00 3.432802e-01 5.227737e-01 -2.775558e-17
# Kiểm tra ràng buộc
print(paste("Tổng trọng số:", sum(optimal_weights)))
## [1] "Tổng trọng số: 1"
print(paste("Lợi nhuận kỳ vọng:", sum(optimal_weights * er)))
## [1] "Lợi nhuận kỳ vọng: 0.003"
print(paste("Phương sai danh mục:", t(optimal_weights) %*% covar %*% optimal_weights))
## [1] "Phương sai danh mục: 0.000615830225527991"
html_content <- "<html><body><h1>Xin chào, Thế giới!</h1></body></html>"
# Lưu nội dung HTML vào tệp
writeLines(html_content, con = "output.html")