# Đọc và làm sạch dữ liệu (Cập nhật tên file tiếng Anh)
dax <- read.csv("DAX Historical Data.csv") %>% select(Date, Price) %>% rename(DAX = Price, Ngày = Date)
hnx <- read.csv("HNX Historical Data.csv") %>% select(Date, Price) %>% rename(HNX30 = Price, Ngày = Date)
vn30 <- read.csv("VN 30 Historical Data.csv") %>% select(Date, Price) %>% rename(VN30 = Price, Ngày = Date)

clean_num <- function(x) as.numeric(gsub(",", "", as.character(x)))
dax$DAX <- clean_num(dax$DAX)
hnx$HNX30 <- clean_num(hnx$HNX30)
vn30$VN30 <- clean_num(vn30$VN30)

# Định dạng ngày
dax$Ngày <- as.Date(dax$Ngày, tryFormats = c("%m/%d/%Y", "%d/%m/%Y", "%Y-%m-%d"))
hnx$Ngày <- as.Date(hnx$Ngày, tryFormats = c("%m/%d/%Y", "%d/%m/%Y", "%Y-%m-%d"))
vn30$Ngày <- as.Date(vn30$Ngày, tryFormats = c("%m/%d/%Y", "%d/%m/%Y", "%Y-%m-%d"))

# Gộp dữ liệu lấy các ngày trùng khớp và cắt đúng 280 mẫu mới nhất
df <- vn30 %>%
  inner_join(hnx, by = "Ngày") %>%
  inner_join(dax, by = "Ngày") %>%
  na.omit() %>%
  arrange(Ngày) %>%
  tail(280)

# IN RA KẾT QUẢ DỮ LIỆU
head(df)
##           Ngày    VN30  HNX30      DAX
## 150 2025-08-14 1793.78 285.15 24377.50
## 151 2025-08-15 1783.25 282.34 24359.30
## 152 2025-08-18 1786.37 283.87 24314.77
## 153 2025-08-19 1810.46 286.45 24423.07
## 154 2025-08-20 1828.46 283.73 24276.97
## 155 2025-08-21 1874.91 284.39 24293.34
dim(df)
## [1] 280   4
names(df)
## [1] "Ngày"  "VN30"  "HNX30" "DAX"
str(df)
## 'data.frame':    280 obs. of  4 variables:
##  $ Ngày : Date, format: "2025-08-14" "2025-08-15" ...
##  $ VN30 : num  1794 1783 1786 1810 1828 ...
##  $ HNX30: num  285 282 284 286 284 ...
##  $ DAX  : num  24378 24359 24315 24423 24277 ...

2. Mã hóa dữ liệu (Câu b)

# Nhận xét
# Dữ liệu gồm 280 quan sát và các biến định lượng: VN30, HNX30, DAX.
# Các chỉ số này được đo lường bằng thang đo Ratio Scale.

# CÂU b
# MA HOA VN30
# Chuyển biến VN30 từ thang đo Ratio sang Ordinal Scale thành 2 nhóm:
# Nhóm 1 (Thấp) là các giá trị nhỏ hơn hoặc bằng giá trị trung vị.
# Nhóm 2 (Cao) là các giá trị lớn hơn giá trị trung vị.

VN30_GOC = as.numeric(df$VN30)
VN30_MH = VN30_GOC
VN30_MH = replace(VN30_MH, VN30_GOC <= median(VN30_GOC), 1)
VN30_MH = replace(VN30_MH, VN30_GOC > median(VN30_GOC), 2)

# Gắn biến đã mã hóa vào bảng dữ liệu gốc để dùng cho các câu sau
df$VN30_Cat = factor(VN30_MH, levels = c(1, 2), labels = c("Thấp", "Cao"), ordered = TRUE)

# In ra 15 dòng đầu tiên để kiểm tra
bang_ma_hoa = data.frame(VN30_GOC, VN30_MH)
head(bang_ma_hoa, 15)
##    VN30_GOC VN30_MH
## 1   1793.78       1
## 2   1783.25       1
## 3   1786.37       1
## 4   1810.46       1
## 5   1828.46       1
## 6   1874.91       1
## 7   1814.02       1
## 8   1783.12       1
## 9   1849.05       1
## 10  1848.55       1
## 11  1861.20       1
## 12  1865.38       1
## 13  1859.59       1
## 14  1883.59       1
## 15  1845.48       1
# CÂU c
# Thống kê cơ bản các biến Ratio Scale
dulieu_ratio <- df %>% select(VN30, HNX30, DAX)
summary(dulieu_ratio)
##       VN30          HNX30            DAX       
##  Min.   :1741   Min.   :235.4   Min.   :22301  
##  1st Qu.:1876   1st Qu.:255.8   1st Qu.:23960  
##  Median :1940   Median :267.4   Median :24423  
##  Mean   :1938   Mean   :270.6   Mean   :24554  
##  3rd Qu.:1997   3rd Qu.:280.1   3rd Qu.:25119  
##  Max.   :2097   Max.   :336.2   Max.   :26570
# Thống kê chi tiết bằng thư viện psych giống bài mẫu
library(psych)
describe(dulieu_ratio)
##       vars   n     mean     sd   median  trimmed    mad      min      max
## VN30     1 280  1937.89  76.73  1940.37  1938.17  94.09  1741.05  2096.76
## HNX30    2 280   270.55  19.06   267.44   268.39  18.32   235.36   336.16
## DAX      3 280 24554.18 856.64 24422.82 24535.94 870.70 22300.75 26569.99
##         range  skew kurtosis    se
## VN30   355.71 -0.04    -0.75  4.59
## HNX30  100.80  0.95     0.71  1.14
## DAX   4269.24  0.09    -0.24 51.19
# Số lượng quan sát ở mỗi nhóm của biến phụ thuộc vào dữ liệu thực tế
# và được xác định thông qua bảng tần số sau khi mã hóa.
table(df$VN30_Cat)
## 
## Thấp  Cao 
##  140  140

4. Vẽ đồ thị (Câu d)

library(ggplot2)

# CÂU d.1: Đồ thị đường cho 3 biến định lượng (Ratio Scale)
# Chia DAX cho 10 để đồ thị dễ nhìn hơn khi đặt cạnh VN30 và HNX30
ggplot(df, aes(x = Ngày)) +
  geom_line(aes(y = VN30, color = "VN30"), linewidth=1) +
  geom_line(aes(y = HNX30, color = "HNX30"), linewidth=1) +
  geom_line(aes(y = DAX/10, color = "DAX (thu nhỏ 10 lần)"), linewidth=1) +
  labs(title = "Biểu đồ biến động giá: VN30, HNX30 và DAX", 
       y = "Điểm chỉ số", x = "Thời gian") + 
  theme_minimal()

# CÂU d.2: Đồ thị cột cho biến phân loại (Ordinal Scale)
ggplot(df, aes(x = VN30_Cat, fill = VN30_Cat)) +
  geom_bar() +
  labs(title = "Biểu đồ cột: Phân loại VN30 (Cao/Thấp)", 
       x = "Nhóm", y = "Tần số") + 
  theme_minimal()

# CÂU d.3: Đồ thị tròn cho biến phân loại (Ordinal Scale)
ggplot(as.data.frame(table(df$VN30_Cat)), aes(x="", y=Freq, fill=Var1)) +
  geom_bar(stat="identity", width=1) + 
  coord_polar("y", start=0) + 
  labs(title = "Biểu đồ tròn: Tỷ trọng phân loại VN30") +
  theme_void()

## 5. Phân tích tương quan (Câu e)

library(corrplot)

# Tính ma trận tương quan
cor_matrix <- cor(df[, c("VN30", "HNX30", "DAX")])
print("Ma trận tương quan:")
## [1] "Ma trận tương quan:"
print(cor_matrix)
##              VN30       HNX30       DAX
## VN30  1.000000000 0.004535101 0.3851028
## HNX30 0.004535101 1.000000000 0.4238143
## DAX   0.385102783 0.423814257 1.0000000
# Vẽ biểu đồ tương quan (Heatmap)
corrplot(cor_matrix, method = "color", addCoef.col = "black", 
         title = "Ma trận tương quan giữa VN30, HNX30 và DAX", 
         mar=c(0,0,2,0), tl.col = "black", tl.srt = 0)

## 6. Mô hình Hồi quy và Kiểm định (Câu f & g)

library(car)
library(lmtest)

# CÂU f: Chạy mô hình hồi quy tuyến tính (VN30 theo HNX30 và DAX)
model <- lm(VN30 ~ HNX30 + DAX, data = df)
print("KẾT QUẢ MÔ HÌNH HỒI QUY:")
## [1] "KẾT QUẢ MÔ HÌNH HỒI QUY:"
summary(model)
## 
## Call:
## lm(formula = VN30 ~ HNX30 + DAX, data = df)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -166.079  -51.247   -4.772   57.925  128.274 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  1.121e+03  1.202e+02   9.331  < 2e-16 ***
## HNX30       -7.787e-01  2.420e-01  -3.218  0.00144 ** 
## DAX          4.183e-02  5.384e-03   7.771 1.53e-13 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 69.77 on 277 degrees of freedom
## Multiple R-squared:  0.179,  Adjusted R-squared:  0.1731 
## F-statistic:  30.2 on 2 and 277 DF,  p-value: 1.37e-12
# CÂU g: Thực hiện các kiểm định chẩn đoán mô hình
print("---------------------------------------------------")
## [1] "---------------------------------------------------"
print("1. Kiểm định Đa cộng tuyến (VIF):")
## [1] "1. Kiểm định Đa cộng tuyến (VIF):"
# Nếu VIF < 2 (hoặc < 10) là tốt, không bị đa cộng tuyến
vif(model)
##    HNX30      DAX 
## 1.218945 1.218945
print("---------------------------------------------------")
## [1] "---------------------------------------------------"
print("2. Kiểm định Phương sai sai số (Breusch-Pagan):")
## [1] "2. Kiểm định Phương sai sai số (Breusch-Pagan):"
# H0: Phương sai sai số không đổi. (p-value > 0.05 là tốt)
bptest(model)
## 
##  studentized Breusch-Pagan test
## 
## data:  model
## BP = 14.293, df = 2, p-value = 0.0007878
print("---------------------------------------------------")
## [1] "---------------------------------------------------"
print("3. Kiểm định Phân phối chuẩn của phần dư (Shapiro-Wilk):")
## [1] "3. Kiểm định Phân phối chuẩn của phần dư (Shapiro-Wilk):"
# H0: Phần dư có phân phối chuẩn. (p-value > 0.05 là tốt)
shapiro.test(resid(model))
## 
##  Shapiro-Wilk normality test
## 
## data:  resid(model)
## W = 0.97708, p-value = 0.0001808
print("---------------------------------------------------")
## [1] "---------------------------------------------------"
print("4. Kiểm định Tự tương quan (Durbin-Watson):")
## [1] "4. Kiểm định Tự tương quan (Durbin-Watson):"
# Thêm kiểm định DW giống bài mẫu
dwtest(model)
## 
##  Durbin-Watson test
## 
## data:  model
## DW = 0.15104, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0
print("---------------------------------------------------")
## [1] "---------------------------------------------------"
print("5. Vẽ đồ thị chẩn đoán phần dư:")
## [1] "5. Vẽ đồ thị chẩn đoán phần dư:"
# Chia màn hình làm 4 phần (2 dòng, 2 cột) để hiển thị cùng lúc 4 hình
par(mfrow = c(2, 2))
# Vẽ đồ thị
plot(model)