# Đọc dữ liệu
library(readr)
df <- read.csv("C:/Users/Welcome !/OneDrive - UFM/Desktop/Datacapm.csv", 
               header = TRUE, sep = ",")
# Đổi tên cột ngày
colnames(df)[1] <- "Date"
df$Date <- as.Date(df$Date, format = "%d/%m/%Y")

# Ép kiểu numeric cho toàn bộ các cột giá cổ phiếu (trừ cột Date)
df <- df %>%
  mutate(across(-Date, ~ as.numeric(gsub(",", "", .)))) %>%
  arrange(Date)

Câu 1: Chọn một số cổ phiếu trên thị trường để ước lượng mô hình CAPM bằng việc sử dụng VN index đại diện cho danh mục thị trường

# Tính log return
returns <- df %>%
  mutate(across(-Date, ~ log(. / lag(.)), .names = "ret_{.col}")) %>%
  drop_na()

Kiểm định tính dừng ADF cho các chuỗi lợi suất giá cổ phiếu

Giả thuyết gốc (H₀): Chuỗi không dừng.

Giả thuyết đối (H₁): Chuỗi dừng.

# Kiểm định tính dừng ADF
ret_cols <- names(returns)[grepl("^ret_", names(returns))]
adf_results <- sapply(ret_cols, function(col) {
  test <- adf.test(returns[[col]])
  c(statistic = test$statistic, p.value = test$p.value, stationary = test$p.value < 0.05)
})
## Warning in adf.test(returns[[col]]): p-value smaller than printed p-value
## Warning in adf.test(returns[[col]]): p-value smaller than printed p-value
## Warning in adf.test(returns[[col]]): p-value smaller than printed p-value
## Warning in adf.test(returns[[col]]): p-value smaller than printed p-value
## Warning in adf.test(returns[[col]]): p-value smaller than printed p-value
## Warning in adf.test(returns[[col]]): p-value smaller than printed p-value
## Warning in adf.test(returns[[col]]): p-value smaller than printed p-value
adf_results <- as.data.frame(t(adf_results))
print(adf_results)
##         statistic.Dickey-Fuller p.value stationary
## ret_BID               -7.744899    0.01          1
## ret_MBB               -7.489377    0.01          1
## ret_OCB               -7.264208    0.01          1
## ret_MSB               -7.091005    0.01          1
## ret_ACB               -8.157487    0.01          1
## ret_VCB               -7.903273    0.01          1
## ret_VNI               -7.325569    0.01          1

Với mức ý nghĩa 1%, 5% hay 10% → đều bác bỏ H₀.

Tất cả chuỗi lợi suất giá cổ phiếu và VNIndex đều dừng.

Có thể sử dụng trực tiếp các chuỗi này để ước lượng mô hình CAPM, phân tích tương quan, tính VaR, v.v.

Không cần lấy sai phân thêm vì lợi suất log thường đã là chuỗi dừng (thực nghiệm tài chính phổ biến).

Ước lượng CAPM

Mô hình hồi quy được sử dụng là hồi quy tuyến tính đơn (simple linear regression), theo công thức của mô hình CAPM:

\[ R_i = \alpha_i + \beta_i R_m + \varepsilon_i \]

Trong đó:

  • \(R_i\): Lợi suất của cổ phiếu \(i\)
  • \(R_m\): Lợi suất của danh mục thị trường (ở đây là lợi suất log của VN-Index)
  • \(\alpha_i\): Phần chênh lệch lợi suất không giải thích bởi rủi ro thị trường (hay còn gọi là alpha)
  • \(\beta_i\): Hệ số đo lường mức độ nhạy cảm của cổ phiếu đối với rủi ro thị trường (beta)
  • \(\varepsilon_i\): Sai số ngẫu nhiên
# Ước lượng CAPM
market_ret <- returns$ret_VNI
capm_list <- list()

for (col in ret_cols[ret_cols != "ret_VNI"]) {
  model <- lm(returns[[col]] ~ market_ret)
  summary_model <- summary(model)
  beta <- coef(model)[2]
  alpha <- coef(model)[1]
  E_Ri <- mean(returns[[col]])
  E_Rm <- mean(market_ret)
  Rf_est <- (E_Ri - beta * E_Rm) / (1 - beta)
  capm_list[[col]] <- data.frame(
    ticker = gsub("ret_", "", col),
    alpha = alpha,
    beta = beta,
    Rf_est = Rf_est,
    E_Ri = E_Ri
  )
}
capm_df <- do.call(rbind, capm_list)
Rf_final <- mean(capm_df$Rf_est)
print(capm_df)
##         ticker         alpha      beta        Rf_est          E_Ri
## ret_BID    BID -5.102265e-04 1.0616275  0.0082792035  6.096980e-05
## ret_MBB    MBB  7.013856e-04 1.1071299 -0.0065470580  1.297064e-03
## ret_OCB    OCB -3.449717e-04 0.9830889 -0.0203991822  1.839679e-04
## ret_MSB    MSB -4.691588e-05 1.0628101  0.0007469484  5.249166e-04
## ret_ACB    ACB -5.037030e-04 0.9688301 -0.0161599083  1.756473e-05
## ret_VCB    VCB -1.453080e-03 0.8664972 -0.0108842667 -9.868713e-04
cat("\n>>> Rf trung bình ", round(Rf_final, 6))
## 
## >>> Rf trung bình  -0.007494

Nhận xét

Đánh giá hệ số Beta (\(\beta_i\)):

Các cổ phiếu như BID (\(\beta = 1.06\)), MBB (\(\beta = 1.11\)) và MSB (\(\beta = 1.06\)) có \(\beta_i > 1\), cho thấy chúng có mức độ biến động cao hơn thị trường → phù hợp với nhà đầu tư chấp nhận rủi ro cao. Các cổ phiếu như VCB (\(\beta = 0.87\)), ACB (\(\beta = 0.97\)) và OCB (\(\beta = 0.98\)) có \(\beta_i < 1\), cho thấy chúng biến động thấp hơn thị trường → ít rủi ro hơn, thích hợp với nhà đầu tư thận trọng.

Đánh giá hệ số Alpha (\(\alpha_i\)):

Trong mô hình CAPM, nếu \(\alpha_i > 0\), cổ phiếu mang lại lợi suất vượt trội so với kỳ vọng từ thị trường. Chỉ có MBB\(\alpha = 0.0007\) là dương → cổ phiếu này có khả năng sinh lời tốt hơn so với mức rủi ro hệ thống mà nó chịu. Các cổ phiếu còn lại có \(\alpha_i < 0\)không đạt hiệu suất như kỳ vọng từ thị trường.

Lợi suất kỳ vọng thực tế \(E(R_i)\):

Các cổ phiếu có \(E(R_i)\) dương gồm MBB, BID, MSB, OCB, ACB, nhưng đều rất nhỏ → cho thấy thị trường không có nhiều cổ phiếu sinh lời vượt trội trong giai đoạn này. Đặc biệt, VCB\(E(R_i) < 0\) → cổ phiếu có hiệu suất kém nhất trong nhóm phân tích.

Lãi suất phi rủi ro ước lượng:

Giá trị \(R_f\) nội suy từ mô hình trung bình là:

\[ \bar{R}_f = -0.007494 \]

Lãi suất phi rủi ro âm là bất hợp lý trong bối cảnh thực tế, cho thấy mô hình có thể bị ảnh hưởng bởi dữ liệu nhiễu hoặc biến động thị trường bất thường. Nên thay thế \(R_f\) nội suy bằng lãi suất thực tế (ví dụ: lợi suất trái phiếu Chính phủ kỳ hạn ngắn) trong các phân tích định giá.


Kết luận:

MBB là cổ phiếu tốt nhất theo CAPM với \(\alpha > 0\), \(\beta > 1\), và \(E(R_i) > 0\). VCB là cổ phiếu kém hiệu quả nhất với \(\alpha < 0\), \(\beta < 1\), và \(E(R_i) < 0\). Mô hình CAPM đã giúp xác định mức độ rủi ro hệ thống qua \(\beta\) và lợi suất vượt trội qua \(\alpha\), song cần thận trọng với việc nội suy \(R_f\).

Câu 2 Từ kết quả ước lượng trên hãy chọn CAPM thích hợp để ước lượng SML cho thị trường cổ phiếu Việt Nam và cho nhận xét giá cổ phiếu.

# Vẽ SML
capm_df <- capm_df %>%
  mutate(expected_return = Rf_final + beta * (mean(market_ret) - Rf_final))

ggplot(capm_df, aes(x = beta, y = E_Ri, label = ticker)) +
  geom_point(color = "blue", size = 3) +
  geom_abline(intercept = Rf_final, slope = mean(market_ret) - Rf_final, color = "red", linetype = "dashed") +
  geom_text(vjust = -1) +
  labs(title = "Security Market Line (SML)",
       x = "Beta",
       y = "Expected Return") +
  theme_minimal()

Mô hình CAPM được ước lượng theo công thức hồi quy tuyến tính:

\[ R_i = \alpha_i + \beta_i R_m + \varepsilon_i \]

Trong đó: - \(R_i\): Lợi suất log của cổ phiếu \(i\) - \(R_m\): Lợi suất log của chỉ số VN-Index (thị trường) - \(\alpha_i\): Phần lợi suất không phụ thuộc thị trường (alpha) - \(\beta_i\): Hệ số đo mức độ nhạy cảm với thị trường (beta) - \(\varepsilon_i\): Sai số ngẫu nhiên

Kết quả mô hình cho thấy:

  • MBB nằm trên đường SML, nghĩa là lợi suất thực tế \(E(R_i)\) lớn hơn lợi suất kỳ vọng theo CAPM \(R_f + \beta_i(E(R_m) - R_f)\). Điều này cho thấy MBB đang bị định giá thấp (underpriced), là cơ hội đầu tư hấp dẫn.

  • MSBBID nằm dưới đường SML, tức là lợi suất thực tế thấp hơn mức lý thuyết kỳ vọng. Đây là dấu hiệu các cổ phiếu này đang bị định giá cao (overpriced), ít hấp dẫn với nhà đầu tư.

  • VCB\(\beta < 1\) nhưng lợi suất \(E(R_i) < 0\), vừa mang lại lợi suất âm vừa có rủi ro thị trường → cổ phiếu kém hấp dẫn nhất.

  • OCBACB nằm gần đường SML, có lợi suất thực tế gần đúng với lý thuyết CAPM → được định giá hợp lý.

CAPM và đường SML là công cụ hữu ích để đánh giá định giá cổ phiếu. Trong mẫu nghiên cứu này: - MBB là cổ phiếu tốt nhất theo mô hình CAPM. - VCB là cổ phiếu có hiệu suất tệ nhất. - Các cổ phiếu còn lại có mức định giá tương đối hợp lý hoặc hơi cao so với kỳ vọng.

# Ma trận hiệp phương sai
ret_matrix <- returns %>% select(all_of(ret_cols[ret_cols != "ret_VNI"])) %>% as.matrix()
cov_matrix <- cov(ret_matrix)
print(round(cov_matrix, 6))
##          ret_BID  ret_MBB  ret_OCB  ret_MSB  ret_ACB  ret_VCB
## ret_BID 0.000229 0.000154 0.000117 0.000134 0.000129 0.000112
## ret_MBB 0.000154 0.000233 0.000147 0.000167 0.000159 0.000086
## ret_OCB 0.000117 0.000147 0.000258 0.000156 0.000120 0.000093
## ret_MSB 0.000134 0.000167 0.000156 0.000243 0.000135 0.000101
## ret_ACB 0.000129 0.000159 0.000120 0.000135 0.000249 0.000094
## ret_VCB 0.000112 0.000086 0.000093 0.000101 0.000094 0.000584

câu 3 Sử dụng CAPM ước lượng ma trận hiệp phương sai , VaR của cổ phiếu và danh mục

# Tính VaR 95% cho từng cổ phiếu (theo return)
VaR_95_individual <- apply(ret_matrix, 2, function(x) quantile(x, 0.05))

# Tính VaR 95% cho danh mục với tỷ trọng đều nhau
weights <- rep(1 / ncol(ret_matrix), ncol(ret_matrix))
returns$Portfolio <- ret_matrix %*% weights
VaR_95_portfolio <- quantile(returns$Portfolio, 0.05)

# In kết quả
cat(">>> VaR 95% (1 ngày) của từng cổ phiếu:\n")
## >>> VaR 95% (1 ngày) của từng cổ phiếu:
print(round(abs(VaR_95_individual), 6))
##  ret_BID  ret_MBB  ret_OCB  ret_MSB  ret_ACB  ret_VCB 
## 0.018936 0.019187 0.020479 0.021835 0.016325 0.012601
cat("\n>>> VaR 95% (1 ngày) của danh mục đầu tư:\n")
## 
## >>> VaR 95% (1 ngày) của danh mục đầu tư:
cat(round(abs(VaR_95_portfolio), 6), "\n")
## 0.015199

ựa trên kết quả ước lượng Value at Risk (VaR) 95% trong 1 ngày, ta có:

  • VaR 95% của từng cổ phiếu (mức lỗ tối đa kỳ vọng trong điều kiện bình thường với độ tin cậy 95%):
    • ret_BID: 0.018936
    • ret_MBB: 0.019187
    • ret_OCB: 0.020479
    • ret_MSB: 0.021835
    • ret_ACB: 0.016325
    • ret_VCB: 0.012601

Điều này có nghĩa là với độ tin cậy 95%, trong điều kiện bình thường, cổ phiếu MSB có rủi ro cao nhất (VaR ≈ 2.18%) trong khi VCB có rủi ro thấp nhất (VaR ≈ 1.26%).

  • VaR 95% của danh mục đầu tư với tỷ trọng đều nhau0.015199 (≈ 1.52%).