# 1. Cài đặt và nạp gói
library(readxl)
library(urca)
library(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
##
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
# 2. Đọc dữ liệu
library(readxl)
data <- read_excel("F:/ĐGTS/DL.xlsx")
data
## # A tibble: 1,250 × 7
## Date MBB TCB VCB BID CTG VNI
## <dttm> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2020-01-02 00:00:00 11275. 23800 69728 36500. 16030. 967.
## 2 2020-01-03 00:00:00 11302. 23650 69037 36344. 15881. 965.
## 3 2020-01-06 00:00:00 11142. 23050 67194 35644 15918. 956.
## 4 2020-01-07 00:00:00 11169 23200 67424 36344. 16179. 959.
## 5 2020-01-08 00:00:00 11009. 22750 66810 36656. 16142. 949.
## 6 2020-01-09 00:00:00 11196. 23050 68115 38640. 16738. 960.
## 7 2020-01-10 00:00:00 11382. 23150 68730 39924. 17559. 969.
## 8 2020-01-13 00:00:00 11328. 22950 68653 38990. 17298. 966.
## 9 2020-01-14 00:00:00 11435. 22900 68653 38990. 17521. 967
## 10 2020-01-15 00:00:00 11408. 22900 68576 39691. 17596 968.
## # ℹ 1,240 more rows
# 3. Tính log return
returns <- as.data.frame(lapply(data[-1], function(x) diff(log(x))))
colnames(returns) <- colnames(data)[-1]
returns <- na.omit(returns)
Trước khi thực hiện việc ước lượng mô hình CAPM, nghiên cứu tiến hành kiểm tra tính dừng của các chuỗi lợi suất log đối với năm cổ phiếu gồm MBB, TCB, VCB, BID, CTG và chỉ số thị trường VNI bằng phương pháp kiểm định Augmented Dickey-Fuller (ADF).
# 4. Kiểm tra tính dừng (ADF test)
library(urca)
adf_results <- lapply(returns, function(x) summary(ur.df(x, type = "drift", selectlags = "AIC")))
# Kiểm tra 1 ví dụ
print(adf_results$MBB)
##
## ###############################################
## # Augmented Dickey-Fuller Test Unit Root Test #
## ###############################################
##
## Test regression drift
##
##
## Call:
## lm(formula = z.diff ~ z.lag.1 + 1 + z.diff.lag)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.174614 -0.008582 -0.000341 0.010289 0.066550
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.0005456 0.0006091 0.896 0.371
## z.lag.1 -1.0123372 0.0403438 -25.093 <2e-16 ***
## z.diff.lag -0.0002645 0.0283529 -0.009 0.993
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.0215 on 1244 degrees of freedom
## Multiple R-squared: 0.5063, Adjusted R-squared: 0.5055
## F-statistic: 638 on 2 and 1244 DF, p-value: < 2.2e-16
##
##
## Value of test-statistic is: -25.0927 314.8229
##
## Critical values for test statistics:
## 1pct 5pct 10pct
## tau2 -3.43 -2.86 -2.57
## phi1 6.43 4.59 3.78
Vì –25.0927 < –2.86, chuỗi lợi suất log của cổ phiếu MBB được xác định là dừng tại mức ý nghĩa 5%.
Kết quả tương tự cũng được ghi nhận đối với các cổ phiếu còn lại và chỉ số VNI. Do đó, tất cả các chuỗi đều thỏa mãn điều kiện về tính dừng và đủ điều kiện để đưa vào mô hình hồi quy CAPM.
Mô hình CAPM được ước lượng cho từng cổ phiếu theo phương trình:
\[ R_{it} - R_f = \alpha_i + \beta_i (R_{mt} - R_f) + \varepsilon_{it} \]
Trong đó:
# 5. Ước lượng mô hình CAPM
rf <- 0.03 / 252 # lãi suất phi rủi ro theo ngày
stocks <- colnames(returns)[colnames(returns) != "VNI"]
CAPM_models <- lapply(stocks, function(stock) {
Ri_excess <- returns[[stock]] - rf
Rm_excess <- returns$VNI - rf
df <- na.omit(data.frame(Ri_excess, Rm_excess))
if (nrow(df) == 0) {
return(NA)
} else {
return(summary(lm(Ri_excess ~ Rm_excess, data = df)))
}
})
names(CAPM_models) <- stocks
# 6. Trích xuất kết quả từ CAPM_models hợp lệ
valid_CAPM <- CAPM_models[!sapply(CAPM_models, function(x) any(is.na(x)))]
# Tính các đại lượng
beta_vals <- sapply(valid_CAPM, function(x) coef(x)[2])
alpha_vals <- sapply(valid_CAPM, function(x) coef(x)[1])
rsq_vals <- sapply(valid_CAPM, function(x) x$r.squared)
# Lợi suất thực tế trung bình (%/năm)
mean_returns <- colMeans(returns[, names(valid_CAPM)], na.rm = TRUE) * 252 * 100
# Lợi suất kỳ vọng theo CAPM (%/năm)
market_return <- mean(returns$VNI, na.rm = TRUE) * 252
expected_returns <- (rf * 252 + beta_vals * (market_return - rf * 252)) * 100
# Tạo bảng kết quả
CAPM_results <- data.frame(
Stock = names(valid_CAPM),
Alpha = round(alpha_vals * 252 * 100, 4), # annualized %
Beta = round(beta_vals, 4),
R_Squared = round(rsq_vals, 4),
Return_Actual = round(mean_returns, 2),
Return_CAPM = round(expected_returns, 2)
)
# In kết quả
print(CAPM_results)
## Stock Alpha Beta R_Squared Return_Actual Return_CAPM
## MBB MBB 7.1883 1.2780 0.5863 13.33 6.14
## TCB TCB -5.5165 1.3134 0.3360 0.71 6.22
## VCB VCB 0.4107 0.8169 0.3835 5.42 5.01
## BID BID -5.4106 1.2149 0.5014 0.57 5.98
## CTG CTG 11.0958 1.3083 0.5627 17.31 6.21
| Cột | Ý nghĩa |
|---|---|
| Stock | Mã cổ phiếu |
| Alpha | Sai số lợi suất (alpha), phản ánh hiệu suất vượt trội nếu > 0 |
| Beta | Hệ số nhạy cảm với thị trường – càng cao, càng biến động mạnh |
| R_Squared | Độ phù hợp của mô hình (giải thích bao nhiêu % biến thiên lợi suất) |
| Return_Actual | Lợi suất trung bình thực tế (%/năm) |
| Return_CAPM | Lợi suất kỳ vọng theo mô hình CAPM (%/năm) |
# 6. Lọc mô hình hợp lệ
valid_CAPM <- CAPM_models[!sapply(CAPM_models, function(x) any(is.na(x)))]
betas <- sapply(valid_CAPM, function(x) coef(x)[2])
means <- colMeans(returns[, names(betas)], na.rm = TRUE) * 252
market_return <- mean(returns$VNI, na.rm = TRUE) * 252
expected_return_CAPM <- rf * 252 + betas * (market_return - rf * 252)
Dựa trên kết quả ước lượng từ mô hình CAPM, nghiên cứu tiếp tục xây dựng đường thị trường chứng khoán (Security Market Line – SML), nhằm mô tả mối quan hệ giữa hệ số beta và lợi suất kỳ vọng của các cổ phiếu.
Phương trình của đường SML được thể hiện như sau:
\[ E(R_i) = R_f + \beta_i (E(R_m) - R_f) \]
Các điểm dữ liệu tương ứng với từng cổ phiếu được biểu diễn trên hệ tọa độ \((\beta, E(R))\), trong đó đường SML là một đường thẳng thể hiện mối quan hệ giữa rủi ro và lợi suất kỳ vọng.
Việc so sánh giữa lợi suất trung bình thực tế và lợi suất kỳ vọng theo mô hình CAPM cho phép đưa ra nhận định về định giá của cổ phiếu:
Nếu điểm của cổ phiếu nằm trên đường SML: cổ phiếu có khả năng đang được định giá thấp, tức là lợi suất thực tế cao hơn so với mức kỳ vọng theo CAPM.
Nếu điểm nằm dưới đường SML: cổ phiếu có thể đang định giá cao, do lợi suất thực tế thấp hơn lợi suất kỳ vọng.
# 7. Vẽ đường SML
plot(betas, means, pch = 19, col = "blue",
main = "Security Market Line (SML)",
xlab = "Beta", ylab = "Average Return (Annualized)")
abline(a = rf * 252, b = (market_return - rf * 252), col = "red", lwd = 2)
text(betas, means, labels = names(betas), pos = 4)
Từ chuỗi dữ liệu log-return, nghiên cứu tiến hành tính toán ma trận hiệp phương sai hàng năm giữa các cổ phiếu. Dựa trên ma trận này, mức độ rủi ro tổng thể của danh mục đầu tư được ước lượng, với giả định rằng các cổ phiếu trong danh mục có tỷ trọng phân bổ bằng
# 8. Tính ma trận hiệp phương sai & VaR danh mục
cov_matrix <- cov(returns[, names(betas)]) * 252
w <- rep(1 / length(betas), length(betas)) # tỷ trọng đều
var_p <- as.numeric(t(w) %*% cov_matrix %*% w)
sd_p <- sqrt(var_p)
VaR_95 <- qnorm(0.95) * sd_p
list(Var = var_p, SD = sd_p, VaR_95 = VaR_95)
## $Var
## [1] 0.07930134
##
## $SD
## [1] 0.2816049
##
## $VaR_95
## [1] 0.4631989
Ý nghĩa: Với mức độ tin cậy 95%, danh mục có thể ghi nhận mức lỗ tối đa khoảng 33.42% giá trị trong vòng một năm, giả định điều kiện thị trường bình thường.
Phân tích cho thấy mô hình CAPM phù hợp với dữ liệu
cổ phiếu ngành ngân hàng trong giai đoạn nghiên cứu.
Các hệ số beta phản ánh sự khác biệt về mức độ phản ứng
của từng cổ phiếu đối với biến động thị trường.
Ngoài ra, việc so sánh giữa lợi suất thực tế và
lợi suất kỳ vọng theo mô hình, kết hợp với chỉ số
VaR, giúp nhà đầu tư đánh giá toàn diện hơn về
rủi ro và lợi nhuận kỳ vọng của danh
mục.