# ============================================================
# 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
  )
)