# ============================================================
# ANALISIS VOLATILITAS SAHAM APEX DENGAN ARCH/GARCH
# ============================================================
# 1. PACKAGE
library(readr)
## Warning: package 'readr' was built under R version 4.5.3
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.5.3
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.5.3
library(tseries)
## Warning: package 'tseries' was built under R version 4.5.3
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
library(FinTS)
## Warning: package 'FinTS' was built under R version 4.5.3
## Loading required package: zoo
## Warning: package 'zoo' was built under R version 4.5.3
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(rugarch)
## Warning: package 'rugarch' was built under R version 4.5.3
## Loading required package: parallel
# 2. IMPORT DAN PERSIAPAN DATA
apex <- read_csv(
"D:/Folder Farras/SEMESTER 4/ANALISIS RUNTUN WAKTU/uas/APEX.csv"
)
## Rows: 4601 Columns: 8
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): ticker
## dbl (6): open, high, low, close, adjclose, volume
## date (1): date
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Melihat struktur data awal
str(apex)
## spc_tbl_ [4,601 × 8] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ date : Date[1:4601], format: "2007-12-28" "2007-12-31" ...
## $ ticker : chr [1:4601] "APEX" "APEX" "APEX" "APEX" ...
## $ open : num [1:4601] 2100 2100 2100 2075 2075 ...
## $ high : num [1:4601] 2100 2100 2100 2075 2100 ...
## $ low : num [1:4601] 2050 2100 2025 2050 2075 ...
## $ close : num [1:4601] 2100 2100 2075 2075 2100 ...
## $ adjclose: num [1:4601] 2017 2017 1993 1993 2017 ...
## $ volume : num [1:4601] 51000 0 183000 49500 26000 ...
## - attr(*, "spec")=
## .. cols(
## .. date = col_date(format = ""),
## .. ticker = col_character(),
## .. open = col_double(),
## .. high = col_double(),
## .. low = col_double(),
## .. close = col_double(),
## .. adjclose = col_double(),
## .. volume = col_double()
## .. )
## - attr(*, "problems")=<externalptr>
# Mengubah format tanggal dan mengurutkan data
apex <- apex %>%
mutate(date = as.Date(date)) %>%
arrange(date)
# Melihat data
head(apex)
## # A tibble: 6 × 8
## date ticker open high low close adjclose volume
## <date> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2007-12-28 APEX 2100 2100 2050 2100 2017. 51000
## 2 2007-12-31 APEX 2100 2100 2100 2100 2017. 0
## 3 2008-01-02 APEX 2100 2100 2025 2075 1993. 183000
## 4 2008-01-03 APEX 2075 2075 2050 2075 1993. 49500
## 5 2008-01-04 APEX 2075 2100 2075 2100 2017. 26000
## 6 2008-01-07 APEX 2100 2100 2075 2075 1993. 18500
tail(apex)
## # A tibble: 6 × 8
## date ticker open high low close adjclose volume
## <date> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2026-09-21 APEX 183 191 180 186 186 14102500
## 2 2026-09-22 APEX 186 192 182 183 183 10242800
## 3 2026-09-23 APEX 184 187 178 185 185 9835900
## 4 2026-09-24 APEX 185 186 179 180 180 11312600
## 5 2026-09-25 APEX 182 183 172 172 172 12225800
## 6 2026-09-28 APEX 172 177 169 174 174 10130100
summary(apex)
## date ticker open high
## Min. :2007-12-28 Length:4601 Min. : 80 Min. : 87
## 1st Qu.:2012-09-12 Class :character 1st Qu.: 320 1st Qu.: 326
## Median :2017-05-26 Mode :character Median :1780 Median :1780
## Mean :2017-05-07 Mean :1635 Mean :1644
## 3rd Qu.:2021-12-13 3rd Qu.:2550 3rd Qu.:2550
## Max. :2026-09-28 Max. :4350 Max. :4350
## low close adjclose volume
## Min. : 77 Min. : 79 Min. : 79 Min. :0.000e+00
## 1st Qu.: 312 1st Qu.: 322 1st Qu.: 322 1st Qu.:0.000e+00
## Median :1780 Median :1780 Median :1780 Median :3.810e+04
## Mean :1626 Mean :1635 Mean :1633 Mean :5.597e+06
## 3rd Qu.:2550 3rd Qu.:2550 3rd Qu.:2550 3rd Qu.:3.302e+05
## Max. :4350 Max. :4350 Max. :4350 Max. :1.615e+09
# 3. MENGHITUNG LOG RETURN
apex <- apex %>%
mutate(
ret = 100 * log(adjclose / lag(adjclose))
) %>%
filter(!is.na(ret))
# Melihat hasil return
head(apex)
## # A tibble: 6 × 9
## date ticker open high low close adjclose volume ret
## <date> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2007-12-31 APEX 2100 2100 2100 2100 2017. 0 0
## 2 2008-01-02 APEX 2100 2100 2025 2075 1993. 183000 -1.20
## 3 2008-01-03 APEX 2075 2075 2050 2075 1993. 49500 0
## 4 2008-01-04 APEX 2075 2100 2075 2100 2017. 26000 1.20
## 5 2008-01-07 APEX 2100 2100 2075 2075 1993. 18500 -1.20
## 6 2008-01-08 APEX 2100 2100 2075 2075 1993. 143000 0
summary(apex$ret)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -28.76821 -0.26446 0.00000 -0.05327 0.00000 33.27058
# 4. PLOT RETURN
ggplot(apex, aes(x = date, y = ret)) +
geom_line() +
labs(
title = "Return Harian Saham APEX",
x = "Tanggal",
y = "Return (%)"
) +
theme_minimal()

# 5. PLOT RETURN KUADRAT
# Untuk melihat volatility clustering
ggplot(apex, aes(x = date, y = ret^2)) +
geom_line() +
labs(
title = "Return Kuadrat Saham APEX",
x = "Tanggal",
y = "Return Kuadrat"
) +
theme_minimal()

# 6. ACF DAN PACF RETURN
par(mfrow = c(1, 2))
acf(
apex$ret,
main = "ACF Return Saham APEX"
)
pacf(
apex$ret,
main = "PACF Return Saham APEX"
)

par(mfrow = c(1, 1))
# 7. ACF DAN PACF RETURN KUADRAT
# Untuk melihat dependensi volatilitas
par(mfrow = c(1, 2))
acf(
apex$ret^2,
main = "ACF Return Kuadrat APEX"
)
pacf(
apex$ret^2,
main = "PACF Return Kuadrat APEX"
)

par(mfrow = c(1, 1))
# 8. UJI STASIONERITAS ADF
adf_result <- adf.test(apex$ret)
## Warning in adf.test(apex$ret): p-value smaller than printed p-value
print(adf_result)
##
## Augmented Dickey-Fuller Test
##
## data: apex$ret
## Dickey-Fuller = -17.125, Lag order = 16, p-value = 0.01
## alternative hypothesis: stationary
# 9. UJI EFEK ARCH PADA RETURN
arch_test <- ArchTest(
apex$ret,
lags = 10,
demean = TRUE
)
print(arch_test)
##
## ARCH LM-test; Null hypothesis: no ARCH effects
##
## data: apex$ret
## Chi-squared = 633.85, df = 10, p-value < 2.2e-16
# ============================================================
# 10. PEMODELAN ARCH
# ============================================================
# Fungsi untuk membuat model ARCH
fit_arch <- function(order) {
spec <- ugarchspec(
variance.model = list(
model = "sGARCH",
garchOrder = c(order, 0)
),
mean.model = list(
armaOrder = c(0, 0),
include.mean = TRUE
),
distribution.model = "std"
)
ugarchfit(
spec = spec,
data = apex$ret,
solver = "hybrid"
)
}
# Estimasi ARCH(1) sampai ARCH(4)
model_arch1 <- fit_arch(1)
model_arch2 <- fit_arch(2)
model_arch3 <- fit_arch(3)
model_arch4 <- fit_arch(4)
# ============================================================
# 11. PEMODELAN GARCH
# ============================================================
# Fungsi untuk membuat model GARCH
fit_garch <- function(p, q) {
spec <- ugarchspec(
variance.model = list(
model = "sGARCH",
garchOrder = c(p, q)
),
mean.model = list(
armaOrder = c(0, 0),
include.mean = TRUE
),
distribution.model = "std"
)
ugarchfit(
spec = spec,
data = apex$ret,
solver = "hybrid"
)
}
# Estimasi 6 model GARCH
model_garch11 <- fit_garch(1, 1)
model_garch12 <- fit_garch(1, 2)
model_garch21 <- fit_garch(2, 1)
model_garch22 <- fit_garch(2, 2)
model_garch13 <- fit_garch(1, 3)
model_garch31 <- fit_garch(3, 1)
# ============================================================
# 12. PERBANDINGAN MODEL
# ============================================================
# Membuat daftar seluruh model
models <- list(
"ARCH(1)" = model_arch1,
"ARCH(2)" = model_arch2,
"ARCH(3)" = model_arch3,
"ARCH(4)" = model_arch4,
"GARCH(1,1)" = model_garch11,
"GARCH(1,2)" = model_garch12,
"GARCH(2,1)" = model_garch21,
"GARCH(2,2)" = model_garch22,
"GARCH(1,3)" = model_garch13,
"GARCH(3,1)" = model_garch31
)
# Membuat tabel perbandingan
comparison <- data.frame(
Model = names(models),
AIC = sapply(
models,
function(x) infocriteria(x)[1]
),
BIC = sapply(
models,
function(x) infocriteria(x)[2]
),
LogLik = sapply(
models,
likelihood
)
)
# Membulatkan hasil
comparison <- comparison %>%
mutate(
AIC = round(AIC, 6),
BIC = round(BIC, 6),
LogLik = round(LogLik, 6)
)
# Menampilkan tabel
print(comparison)
## Model AIC BIC LogLik
## ARCH(1) ARCH(1) -6.048294 -6.042699 13915.08
## ARCH(2) ARCH(2) -9.220501 -9.213508 21212.15
## ARCH(3) ARCH(3) -11.389306 -11.380914 26201.40
## ARCH(4) ARCH(4) -10.444803 -10.435012 24030.05
## GARCH(1,1) GARCH(1,1) -9.678723 -9.671730 22266.06
## GARCH(1,2) GARCH(1,2) -8.516924 -8.508532 19594.93
## GARCH(2,1) GARCH(2,1) -5.042101 -5.033709 11602.83
## GARCH(2,2) GARCH(2,2) -9.462262 -9.452471 21770.20
## GARCH(1,3) GARCH(1,3) -9.107590 -9.097799 20954.46
## GARCH(3,1) GARCH(3,1) -5.981170 -5.971380 13763.69
# ============================================================
# 13. PERINGKAT MODEL BERDASARKAN AIC
# ============================================================
comparison_aic <- comparison %>%
arrange(AIC)
cat("\n============================================\n")
##
## ============================================
cat("PERINGKAT MODEL BERDASARKAN AIC\n")
## PERINGKAT MODEL BERDASARKAN AIC
cat("============================================\n")
## ============================================
print(comparison_aic)
## Model AIC BIC LogLik
## ARCH(3) ARCH(3) -11.389306 -11.380914 26201.40
## ARCH(4) ARCH(4) -10.444803 -10.435012 24030.05
## GARCH(1,1) GARCH(1,1) -9.678723 -9.671730 22266.06
## GARCH(2,2) GARCH(2,2) -9.462262 -9.452471 21770.20
## ARCH(2) ARCH(2) -9.220501 -9.213508 21212.15
## GARCH(1,3) GARCH(1,3) -9.107590 -9.097799 20954.46
## GARCH(1,2) GARCH(1,2) -8.516924 -8.508532 19594.93
## ARCH(1) ARCH(1) -6.048294 -6.042699 13915.08
## GARCH(3,1) GARCH(3,1) -5.981170 -5.971380 13763.69
## GARCH(2,1) GARCH(2,1) -5.042101 -5.033709 11602.83
# ============================================================
# 14. PERINGKAT MODEL BERDASARKAN BIC
# ============================================================
comparison_bic <- comparison %>%
arrange(BIC)
cat("\n============================================\n")
##
## ============================================
cat("PERINGKAT MODEL BERDASARKAN BIC\n")
## PERINGKAT MODEL BERDASARKAN BIC
cat("============================================\n")
## ============================================
print(comparison_bic)
## Model AIC BIC LogLik
## ARCH(3) ARCH(3) -11.389306 -11.380914 26201.40
## ARCH(4) ARCH(4) -10.444803 -10.435012 24030.05
## GARCH(1,1) GARCH(1,1) -9.678723 -9.671730 22266.06
## GARCH(2,2) GARCH(2,2) -9.462262 -9.452471 21770.20
## ARCH(2) ARCH(2) -9.220501 -9.213508 21212.15
## GARCH(1,3) GARCH(1,3) -9.107590 -9.097799 20954.46
## GARCH(1,2) GARCH(1,2) -8.516924 -8.508532 19594.93
## ARCH(1) ARCH(1) -6.048294 -6.042699 13915.08
## GARCH(3,1) GARCH(3,1) -5.981170 -5.971380 13763.69
## GARCH(2,1) GARCH(2,1) -5.042101 -5.033709 11602.83
# ============================================================
# 15. KANDIDAT MODEL
# ============================================================
# Model dengan AIC terendah
best_aic_model <- comparison_aic$Model[1]
# Model dengan BIC terendah
best_bic_model <- comparison_bic$Model[1]
cat("\n============================================\n")
##
## ============================================
cat("MODEL DENGAN AIC TERENDAH\n")
## MODEL DENGAN AIC TERENDAH
cat("============================================\n")
## ============================================
cat(best_aic_model, "\n")
## ARCH(3)
cat("\n============================================\n")
##
## ============================================
cat("MODEL DENGAN BIC TERENDAH\n")
## MODEL DENGAN BIC TERENDAH
cat("============================================\n")
## ============================================
cat(best_bic_model, "\n")
## ARCH(3)
# ============================================================
# 16. MODEL KANDIDAT UTAMA
# ============================================================
# Untuk sementara menggunakan model dengan AIC terendah
# sebagai kandidat utama.
#
# Model final akan dikonfirmasi melalui:
# - Signifikansi parameter
# - Persistence
# - Ljung-Box residual
# - Ljung-Box residual kuadrat
# - ARCH-LM residual
best_model_name <- best_aic_model
best_model <- models[[best_model_name]]
cat("\n============================================\n")
##
## ============================================
cat("KANDIDAT MODEL UTAMA\n")
## KANDIDAT MODEL UTAMA
cat("============================================\n")
## ============================================
cat(best_model_name, "\n")
## ARCH(3)
show(best_model)
##
## *---------------------------------*
## * GARCH Model Fit *
## *---------------------------------*
##
## Conditional Variance Dynamics
## -----------------------------------
## GARCH Model : sGARCH(3,0)
## Mean Model : ARFIMA(0,0,0)
## Distribution : std
##
## Optimal Parameters
## ------------------------------------
## Estimate Std. Error t value Pr(>|t|)
## mu 0.0 0.000000 0.000039 0.99997
## omega 0.0 0.000000 0.000000 1.00000
## alpha1 1.0 0.061603 16.232987 0.00000
## alpha2 1.0 0.069643 14.358932 0.00000
## alpha3 1.0 0.071699 13.947192 0.00000
## shape 2.1 0.003159 664.726554 0.00000
##
## Robust Standard Errors:
## Estimate Std. Error t value Pr(>|t|)
## mu 0.0 0.000813 0.00000 1.000000
## omega 0.0 0.003256 0.00000 1.000000
## alpha1 1.0 2.060084 0.48542 0.627381
## alpha2 1.0 2.822331 0.35432 0.723101
## alpha3 1.0 3.200274 0.31247 0.754681
## shape 2.1 0.842841 2.49157 0.012718
##
## LogLikelihood : 26201.4
##
## Information Criteria
## ------------------------------------
##
## Akaike -11.389
## Bayes -11.381
## Shibata -11.389
## Hannan-Quinn -11.386
##
## Weighted Ljung-Box Test on Standardized Residuals
## ------------------------------------
## statistic p-value
## Lag[1] 0.0005562 0.9812
## Lag[2*(p+q)+(p+q)-1][2] 0.0008345 0.9989
## Lag[4*(p+q)+(p+q)-1][5] 0.0228383 0.9999
## d.o.f=0
## H0 : No serial correlation
##
## Weighted Ljung-Box Test on Standardized Squared Residuals
## ------------------------------------
## statistic p-value
## Lag[1] 0.005352 9.417e-01
## Lag[2*(p+q)+(p+q)-1][8] 1.468935 9.308e-01
## Lag[4*(p+q)+(p+q)-1][14] 43.551780 2.174e-09
## d.o.f=3
##
## Weighted ARCH LM Tests
## ------------------------------------
## Statistic Shape Scale P-Value
## ARCH Lag[4] 0.004922 0.500 2.000 0.9441
## ARCH Lag[6] 0.012951 1.461 1.711 0.9994
## ARCH Lag[8] 5.787956 2.368 1.583 0.1761
##
## Nyblom stability test
## ------------------------------------
## Joint Statistic: 1260.069
## Individual Statistics:
## mu 0.5114
## omega 887.0343
## alpha1 56.2590
## alpha2 35.0147
## alpha3 30.3118
## shape 207.2618
##
## Asymptotic Critical Values (10% 5% 1%)
## Joint Statistic: 1.49 1.68 2.12
## Individual Statistic: 0.35 0.47 0.75
##
## Sign Bias Test
## ------------------------------------
## t-value prob sig
## Sign Bias 1.049e+00 0.2944
## Negative Sign Bias 1.020e+00 0.3077
## Positive Sign Bias 3.268e-15 1.0000
## Joint Effect 2.232e+00 0.5257
##
##
## Adjusted Pearson Goodness-of-Fit Test:
## ------------------------------------
## group statistic p-value(g-1)
## 1 20 25418 0
## 2 30 39279 0
## 3 40 53077 0
## 4 50 66741 0
##
##
## Elapsed time : 2.652229
# ============================================================
# 17. PARAMETER MODEL TERPILIH
# ============================================================
coef_best <- coef(best_model)
cat("\n============================================\n")
##
## ============================================
cat("PARAMETER MODEL TERPILIH\n")
## PARAMETER MODEL TERPILIH
cat("============================================\n")
## ============================================
print(coef_best)
## mu omega alpha1 alpha2 alpha3 shape
## 2.404281e-12 2.220446e-16 1.000000e+00 1.000000e+00 1.000000e+00 2.100000e+00
# Melihat signifikansi parameter
cat("\n============================================\n")
##
## ============================================
cat("SIGNIFIKANSI PARAMETER\n")
## SIGNIFIKANSI PARAMETER
cat("============================================\n")
## ============================================
print(
best_model@fit$matcoef
)
## Estimate Std. Error t value Pr(>|t|)
## mu 2.404281e-12 6.105999e-08 3.937572e-05 0.9999686
## omega 2.220446e-16 7.645199e-08 2.904366e-09 1.0000000
## alpha1 1.000000e+00 6.160296e-02 1.623299e+01 0.0000000
## alpha2 1.000000e+00 6.964306e-02 1.435893e+01 0.0000000
## alpha3 1.000000e+00 7.169902e-02 1.394719e+01 0.0000000
## shape 2.100000e+00 3.159194e-03 6.647266e+02 0.0000000
# ============================================================
# 18. PERSISTENSI VOLATILITAS
# ============================================================
# Mengambil seluruh parameter alpha
alpha_values <- coef_best[
grep("^alpha", names(coef_best))
]
# Mengambil seluruh parameter beta
beta_values <- coef_best[
grep("^beta", names(coef_best))
]
# Menghitung persistence
persistence <- sum(
alpha_values,
beta_values
)
cat("\n============================================\n")
##
## ============================================
cat("PERSISTENSI VOLATILITAS\n")
## PERSISTENSI VOLATILITAS
cat("============================================\n")
## ============================================
cat(
"Alpha + Beta =",
persistence,
"\n"
)
## Alpha + Beta = 3
# ============================================================
# 19. CONDITIONAL VOLATILITY
# ============================================================
volatility_df <- data.frame(
date = apex$date,
volatility = as.numeric(
sigma(best_model)
)
)
ggplot(
volatility_df,
aes(x = date, y = volatility)
) +
geom_line() +
labs(
title = paste(
"Conditional Volatility Saham APEX -",
best_model_name
),
x = "Tanggal",
y = "Conditional Volatility"
) +
theme_minimal()

# ============================================================
# 20. RESIDUAL STANDAR
# ============================================================
residual_std <- as.numeric(
residuals(
best_model,
standardize = TRUE
)
)
residual_std <- na.omit(
residual_std
)
summary(residual_std)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -1.149e+09 0.000e+00 0.000e+00 -9.571e+05 0.000e+00 2.233e+09
# ============================================================
# 21. UJI LJUNG-BOX RESIDUAL
# ============================================================
ljung_residual <- Box.test(
residual_std,
lag = 10,
type = "Ljung-Box"
)
cat("\n============================================\n")
##
## ============================================
cat("LJUNG-BOX RESIDUAL\n")
## LJUNG-BOX RESIDUAL
cat("============================================\n")
## ============================================
print(ljung_residual)
##
## Box-Ljung test
##
## data: residual_std
## X-squared = 233.3, df = 10, p-value < 2.2e-16
# ============================================================
# 22. UJI LJUNG-BOX RESIDUAL KUADRAT
# ============================================================
ljung_squared <- Box.test(
residual_std^2,
lag = 10,
type = "Ljung-Box"
)
cat("\n============================================\n")
##
## ============================================
cat("LJUNG-BOX RESIDUAL KUADRAT\n")
## LJUNG-BOX RESIDUAL KUADRAT
cat("============================================\n")
## ============================================
print(ljung_squared)
##
## Box-Ljung test
##
## data: residual_std^2
## X-squared = 117.24, df = 10, p-value < 2.2e-16
# ============================================================
# 23. UJI ARCH-LM PADA RESIDUAL
# ============================================================
arch_residual <- ArchTest(
residual_std,
lags = 10,
demean = TRUE
)
cat("\n============================================\n")
##
## ============================================
cat("ARCH-LM RESIDUAL\n")
## ARCH-LM RESIDUAL
cat("============================================\n")
## ============================================
print(arch_residual)
##
## ARCH LM-test; Null hypothesis: no ARCH effects
##
## data: residual_std
## Chi-squared = 116.61, df = 10, p-value < 2.2e-16
# ============================================================
# 24. DIAGNOSTIC PLOT
# ============================================================
# Plot residual standar
plot(
residual_std,
type = "l",
main = paste(
"Standardized Residual -",
best_model_name
),
xlab = "Observasi",
ylab = "Residual Standar"
)

# ACF residual standar
acf(
residual_std,
main = paste(
"ACF Standardized Residual -",
best_model_name
)
)

# ACF residual standar kuadrat
acf(
residual_std^2,
main = paste(
"ACF Squared Standardized Residual -",
best_model_name
)
)
