# Install package jika belum ada
pkgs <- c("forecast", "tseries", "FinTS", "rugarch",
"ggplot2", "dplyr", "lubridate", "nortest",
"lmtest", "zoo", "xts")
for (p in pkgs) {
if (!requireNamespace(p, quietly = TRUE)) install.packages(p)
}
library(forecast)
library(tseries)
library(FinTS)
library(rugarch)
library(ggplot2)
library(dplyr)
library(lubridate)
library(nortest)
library(lmtest)
library(zoo)
library(xts)# Muat data
df <- read.csv("C:\\Users\\aspir\\Documents\\Ekolan\\Data_Historis_GOTO (1).csv", stringsAsFactors = FALSE)
df$Date <- as.Date(df$Date)
df <- df[order(df$Date), ]
# Gunakan harga penutupan (Close)
close_ts <- df$Close
n <- length(close_ts)
cat("Jumlah observasi :", n, "\n")## Jumlah observasi : 481
## Periode : 2022-04-11 hingga 2024-04-05
## Statistik deskriptif harga Close:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 56.0 88.0 112.0 157.4 218.0 404.0
ggplot(df, aes(x = Date, y = Close)) +
geom_line(color = "#2c7bb6", linewidth = 0.7) +
labs(title = "Harga Penutupan Saham GOTO (GOTO.JK)",
subtitle = paste("Periode:", format(min(df$Date)), "–", format(max(df$Date))),
x = "Tanggal", y = "Harga (IDR)") +
theme_minimal(base_size = 13) +
theme(plot.title = element_text(face = "bold"))Uji Augmented Dickey-Fuller (ADF) digunakan untuk memeriksa apakah deret waktu bersifat stasioner. Hipotesis nol (H₀): data tidak stasioner (terdapat unit root).
##
## Augmented Dickey-Fuller Test
##
## data: close_ts
## Dickey-Fuller = -2.2508, Lag order = 7, p-value = 0.472
## alternative hypothesis: stationary
##
## -- Keputusan --
if (adf_level$p.value < 0.05) {
cat("H0 ditolak: Data STASIONER pada level (p =",
round(adf_level$p.value, 4), ")\n")
} else {
cat("H0 tidak ditolak: Data TIDAK STASIONER pada level (p =",
round(adf_level$p.value, 4), ") → perlu differencing\n")
}## H0 tidak ditolak: Data TIDAK STASIONER pada level (p = 0.472 ) → perlu differencing
##
## Augmented Dickey-Fuller Test
##
## data: close_diff
## Dickey-Fuller = -7.1166, Lag order = 7, p-value = 0.01
## alternative hypothesis: stationary
##
## -- Keputusan --
if (adf_diff$p.value < 0.05) {
cat("H0 ditolak: Data STASIONER setelah differencing 1 kali (p =",
round(adf_diff$p.value, 4), ") → d = 1\n")
} else {
cat("H0 tidak ditolak: Data masih TIDAK STASIONER (p =",
round(adf_diff$p.value, 4), ") → coba d = 2\n")
}## H0 ditolak: Data STASIONER setelah differencing 1 kali (p = 0.01 ) → d = 1
df_diff <- data.frame(
Date = df$Date[-1],
Diff = close_diff
)
ggplot(df_diff, aes(x = Date, y = Diff)) +
geom_line(color = "#d7191c", linewidth = 0.6) +
geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
labs(title = "Return/Differencing Pertama Harga Penutupan GOTO",
x = "Tanggal", y = "ΔClose (IDR)") +
theme_minimal(base_size = 13)ACF (Autocorrelation Function) dan PACF (Partial Autocorrelation Function) digunakan untuk mengidentifikasi orde AR (p) dan MA (q) yang sesuai pada model ARIMA.
par(mfrow = c(1, 2))
acf(close_ts, lag.max = 12, main = "ACF — Harga Close (Level)")
pacf(close_ts, lag.max = 12, main = "PACF — Harga Close (Level)")par(mfrow = c(1, 2))
acf(close_diff, lag.max = 12, main = "ACF — ΔClose (d=1)")
pacf(close_diff, lag.max = 12, main = "PACF — ΔClose (d=1)")Pembacaan: Berdasarkan pola ACF dan PACF pada data yang sudah di-differencing, kandidat model ARIMA diidentifikasi. Lag yang signifikan menunjukkan kandidat orde AR dan MA.
Beberapa kandidat model ARIMA diestimasi berdasarkan hasil correlogram. Parameter yang disertakan: dengan konstanta (c) dan tanpa konstanta. Model dengan MA lag ke-5 saja [5] membutuhkan parameter fixed.
# Helper untuk fit ARIMA dengan orde tertentu
y <- close_ts # data asli; differencing ditangani oleh order d=1
# ---- Model dengan konstanta (include.constant = TRUE) ----
fit_c110 <- Arima(y, order = c(1, 1, 0), include.constant = TRUE)
fit_c011 <- Arima(y, order = c(0, 1, 1), include.constant = TRUE)
fit_c111 <- Arima(y, order = c(1, 1, 1), include.constant = TRUE)
# ARIMA(0,1,[5]) dengan konstanta: MA hanya pada lag 5
# fixed = c(MA1=0, MA2=0, MA3=0, MA4=0, MA5=NA, konstanta=NA)
fit_c015 <- Arima(y, order = c(0, 1, 5),
include.constant = TRUE,
fixed = c(0, 0, 0, 0, NA, NA))
# ARIMA(1,1,[5]) dengan konstanta: AR1 + MA hanya pada lag 5
# fixed = c(AR1=NA, MA1=0, MA2=0, MA3=0, MA4=0, MA5=NA, konstanta=NA)
fit_c115 <- Arima(y, order = c(1, 1, 5),
include.constant = TRUE,
fixed = c(NA, 0, 0, 0, 0, NA, NA))
# ---- Model tanpa konstanta ----
fit_110 <- Arima(y, order = c(1, 1, 0), include.constant = FALSE)
fit_011 <- Arima(y, order = c(0, 1, 1), include.constant = FALSE)
fit_111 <- Arima(y, order = c(1, 1, 1), include.constant = FALSE)
fit_015 <- Arima(y, order = c(0, 1, 5),
include.constant = FALSE,
fixed = c(0, 0, 0, 0, NA))
fit_115 <- Arima(y, order = c(1, 1, 5),
include.constant = FALSE,
fixed = c(NA, 0, 0, 0, 0, NA))model_list <- list(
"c ARIMA(1,1,0)" = fit_c110,
"c ARIMA(0,1,1)" = fit_c011,
"c ARIMA(1,1,1)" = fit_c111,
"c ARIMA(0,1,[5])" = fit_c015,
"c ARIMA(1,1,[5])" = fit_c115,
"ARIMA(1,1,0)" = fit_110,
"ARIMA(0,1,1)" = fit_011,
"ARIMA(1,1,1)" = fit_111,
"ARIMA(0,1,[5])" = fit_015,
"ARIMA(1,1,[5])" = fit_115
)
aic_df <- data.frame(
Model = names(model_list),
AIC = sapply(model_list, AIC),
BIC = sapply(model_list, BIC),
LogLik = sapply(model_list, logLik)
)
aic_df <- aic_df[order(aic_df$AIC), ]
rownames(aic_df) <- NULL
# AIC per observasi (seperti pada output Excel)
aic_df$AIC_per_obs <- aic_df$AIC / n
print(aic_df)## Model AIC BIC LogLik AIC_per_obs
## 1 c ARIMA(1,1,[5]) 3319.835 3336.530 -1655.918 6.901944
## 2 ARIMA(1,1,[5]) 3319.844 3332.366 -1656.922 6.901963
## 3 c ARIMA(1,1,0) 3322.908 3335.430 -1658.454 6.908333
## 4 c ARIMA(0,1,1) 3322.957 3335.478 -1658.478 6.908434
## 5 ARIMA(1,1,0) 3323.286 3331.634 -1659.643 6.909118
## 6 ARIMA(0,1,1) 3323.494 3331.842 -1659.747 6.909552
## 7 c ARIMA(1,1,1) 3324.862 3341.557 -1658.431 6.912395
## 8 ARIMA(1,1,1) 3325.283 3337.805 -1659.642 6.913271
## 9 c ARIMA(0,1,[5]) 3333.567 3346.088 -1663.783 6.930492
## 10 ARIMA(0,1,[5]) 3334.428 3342.776 -1665.214 6.932283
# Tandai model terbaik
best_model_name <- aic_df$Model[1]
cat("\n✔ Model terbaik berdasarkan AIC:", best_model_name, "\n")##
## ✔ Model terbaik berdasarkan AIC: c ARIMA(1,1,[5])
## AIC = 3319.835
ggplot(aic_df, aes(x = reorder(Model, AIC), y = AIC, fill = (Model == best_model_name))) +
geom_col(show.legend = FALSE) +
scale_fill_manual(values = c("steelblue", "#e63946")) +
coord_flip() +
labs(title = "Perbandingan AIC Kandidat Model ARIMA",
subtitle = paste("Model terbaik:", best_model_name),
x = NULL, y = "AIC") +
theme_minimal(base_size = 12)# Gunakan ARIMA(1,1,[5]) dengan konstanta sebagai model terbaik (sesuai Excel)
best_fit <- fit_c115
cat("=== Ringkasan Model Terbaik: c ARIMA(1,1,[5]) ===\n")## === Ringkasan Model Terbaik: c ARIMA(1,1,[5]) ===
## Series: y
## ARIMA(1,1,5) with drift
##
## Coefficients:
## ar1 ma1 ma2 ma3 ma4 ma5 drift
## 0.1797 0 0 0 0 0.0981 -0.6626
## s.e. 0.0449 0 0 0 0 0.0429 0.4650
##
## sigma^2 = 58.43: log likelihood = -1655.92
## AIC=3319.84 AICc=3319.92 BIC=3336.53
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set 0.007967425 7.612315 4.740044 0.07831046 3.106406 0.9773287
## ACF1
## Training set 0.0004522709
##
## z test of coefficients:
##
## Estimate Std. Error z value Pr(>|z|)
## ar1 0.179675 0.044917 4.0002 6.33e-05 ***
## ma5 0.098117 0.042902 2.2870 0.02219 *
## drift -0.662595 0.464956 -1.4251 0.15414
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
resid_arima <- residuals(best_fit)
# Shapiro-Wilk (untuk n ≤ 5000)
if (length(resid_arima) <= 5000) {
sw_test <- shapiro.test(resid_arima)
cat("Shapiro-Wilk Test:\n")
print(sw_test)
cat("Keputusan:", ifelse(sw_test$p.value < 0.05,
"H0 ditolak — Residual TIDAK berdistribusi normal\n",
"H0 tidak ditolak — Residual berdistribusi normal\n"))
}## Shapiro-Wilk Test:
##
## Shapiro-Wilk normality test
##
## data: resid_arima
## W = 0.86077, p-value < 2.2e-16
##
## Keputusan: H0 ditolak — Residual TIDAK berdistribusi normal
# Kolmogorov-Smirnov
ks_test <- ks.test(scale(resid_arima), "pnorm")
cat("\nKolmogorov-Smirnov Test:\n")##
## Kolmogorov-Smirnov Test:
##
## Asymptotic one-sample Kolmogorov-Smirnov test
##
## data: scale(resid_arima)
## D = 0.11948, p-value = 2.17e-06
## alternative hypothesis: two-sided
##
## Jarque-Bera Test:
##
## Jarque Bera Test
##
## data: resid_arima
## X-squared = 1692, df = 2, p-value < 2.2e-16
cat("Keputusan:", ifelse(jb_test$p.value < 0.05,
"H0 ditolak — Residual TIDAK normal\n",
"H0 tidak ditolak — Residual normal\n"))## Keputusan: H0 ditolak — Residual TIDAK normal
par(mfrow = c(1, 2))
hist(resid_arima, breaks = 30, probability = TRUE,
main = "Histogram Residual", xlab = "Residual",
col = "#cce5ff", border = "white")
curve(dnorm(x, mean(resid_arima), sd(resid_arima)),
add = TRUE, col = "red", lwd = 2)
qqnorm(resid_arima, main = "Q-Q Plot Residual")
qqline(resid_arima, col = "red", lwd = 2)## === Uji Ljung-Box (White Noise) ===
for (lag in c(1, 6, 12, 24)) {
lb <- Box.test(resid_arima, lag = lag, type = "Ljung-Box", fitdf = 2)
cat(sprintf("Lag %-3d: Q = %.4f, p-value = %.4f → %s\n",
lag, lb$statistic, lb$p.value,
ifelse(lb$p.value > 0.05, "Tidak ada autokorelasi (White Noise ✓)",
"Terdapat autokorelasi (bukan White Noise ✗)")))
}## Lag 1 : Q = 0.0001, p-value = NaN → NA
## Lag 6 : Q = 3.9172, p-value = 0.4173 → Tidak ada autokorelasi (White Noise ✓)
## Lag 12 : Q = 10.0066, p-value = 0.4399 → Tidak ada autokorelasi (White Noise ✓)
## Lag 24 : Q = 32.2665, p-value = 0.0730 → Tidak ada autokorelasi (White Noise ✓)
par(mfrow = c(1, 2))
acf(resid_arima, lag.max = 30, main = "ACF Residual")
pacf(resid_arima, lag.max = 30, main = "PACF Residual")Uji ARCH-LM (Lagrange Multiplier) digunakan untuk mendeteksi adanya heteroskedastisitas kondisional (efek ARCH) pada residual model ARIMA.
## === Uji ARCH-LM pada Residual ARIMA ===
for (lag in 1:12) {
arch_lm <- ArchTest(resid_arima, lags = lag)
cat(sprintf("Lag %-3d: Chi² = %.4f, p-value = %.4f → %s\n",
lag, arch_lm$statistic, arch_lm$p.value,
ifelse(arch_lm$p.value < 0.05,
"Terdapat efek ARCH ✗",
"Tidak ada efek ARCH ✓")))
}## Lag 1 : Chi² = 29.5696, p-value = 0.0000 → Terdapat efek ARCH ✗
## Lag 2 : Chi² = 30.7980, p-value = 0.0000 → Terdapat efek ARCH ✗
## Lag 3 : Chi² = 42.5202, p-value = 0.0000 → Terdapat efek ARCH ✗
## Lag 4 : Chi² = 44.1316, p-value = 0.0000 → Terdapat efek ARCH ✗
## Lag 5 : Chi² = 44.0574, p-value = 0.0000 → Terdapat efek ARCH ✗
## Lag 6 : Chi² = 44.7274, p-value = 0.0000 → Terdapat efek ARCH ✗
## Lag 7 : Chi² = 46.3282, p-value = 0.0000 → Terdapat efek ARCH ✗
## Lag 8 : Chi² = 52.0703, p-value = 0.0000 → Terdapat efek ARCH ✗
## Lag 9 : Chi² = 78.4336, p-value = 0.0000 → Terdapat efek ARCH ✗
## Lag 10 : Chi² = 78.6379, p-value = 0.0000 → Terdapat efek ARCH ✗
## Lag 11 : Chi² = 85.7399, p-value = 0.0000 → Terdapat efek ARCH ✗
## Lag 12 : Chi² = 87.5614, p-value = 0.0000 → Terdapat efek ARCH ✗
Karena terdapat efek ARCH pada residual, dilakukan pemodelan volatilitas menggunakan model ARCH. Beberapa orde ARCH diuji untuk mendapatkan model terbaik.
# Gunakan paket rugarch untuk estimasi ARCH(q)
# Distribusi: normal; mean model: ARFIMA dengan urutan ARIMA(1,1,[5])
aic_arch <- c()
for (q in 1:5) {
spec <- ugarchspec(
variance.model = list(model = "sGARCH", garchOrder = c(q, 0)),
mean.model = list(armaOrder = c(1, 5),
include.mean = TRUE,
external.regressors = NULL),
distribution.model = "norm"
)
tryCatch({
fit_arch <- ugarchfit(spec = spec, data = close_ts,
solver = "hybrid", out.sample = 0)
ic <- infocriteria(fit_arch)
aic_val <- ic["Akaike", ]
aic_arch[q] <- aic_val
cat(sprintf("ARCH(%d): AIC = %.6f\n", q, aic_val))
}, error = function(e) {
cat(sprintf("ARCH(%d): Gagal diestimasi — %s\n", q, e$message))
aic_arch[q] <<- NA
})
}## ARCH(1): AIC = 6.656117
## ARCH(2): AIC = 6.650132
## ARCH(3): AIC = 6.491010
## ARCH(4): AIC = 6.492193
## ARCH(5): AIC = 6.458745
best_q <- which.min(aic_arch)
cat("\n✔ Model ARCH terbaik berdasarkan AIC: ARCH(", best_q, ")\n", sep = "")##
## ✔ Model ARCH terbaik berdasarkan AIC: ARCH(5)
## AIC = 6.458745
arch_df <- data.frame(
Orde = paste0("ARCH(", 1:length(aic_arch), ")"),
AIC = aic_arch
)
ggplot(arch_df[!is.na(arch_df$AIC), ], aes(x = Orde, y = AIC,
fill = (Orde == paste0("ARCH(", best_q, ")")))) +
geom_col(show.legend = FALSE) +
scale_fill_manual(values = c("steelblue", "#e63946")) +
labs(title = "Perbandingan AIC Model ARCH",
subtitle = paste("Model terbaik: ARCH(", best_q, ")"),
x = NULL, y = "AIC") +
theme_minimal(base_size = 12)spec_best <- ugarchspec(
variance.model = list(model = "sGARCH", garchOrder = c(5, 0)),
mean.model = list(armaOrder = c(1, 5), include.mean = TRUE),
distribution.model = "norm"
)
fit_best_arch <- ugarchfit(spec = spec_best, data = close_ts,
solver = "hybrid")
show(fit_best_arch)##
## *---------------------------------*
## * GARCH Model Fit *
## *---------------------------------*
##
## Conditional Variance Dynamics
## -----------------------------------
## GARCH Model : sGARCH(5,0)
## Mean Model : ARFIMA(1,0,5)
## Distribution : norm
##
## Optimal Parameters
## ------------------------------------
## Estimate Std. Error t value Pr(>|t|)
## mu 367.301942 5.031746 72.996920 0.000000
## ar1 0.999747 0.000716 1396.795089 0.000000
## ma1 0.049272 0.059078 0.834018 0.404271
## ma2 -0.082375 0.042941 -1.918310 0.055072
## ma3 0.036169 0.052152 0.693523 0.487981
## ma4 -0.090751 0.034375 -2.640051 0.008289
## ma5 0.007451 0.037432 0.199052 0.842222
## omega 7.670257 1.591272 4.820205 0.000001
## alpha1 0.257641 0.060126 4.285025 0.000018
## alpha2 0.051024 0.043601 1.170242 0.241903
## alpha3 0.554638 0.087555 6.334743 0.000000
## alpha4 0.000000 0.032782 0.000009 0.999992
## alpha5 0.135696 0.047707 2.844375 0.004450
##
## Robust Standard Errors:
## Estimate Std. Error t value Pr(>|t|)
## mu 367.301942 6.134227 59.877465 0.000000
## ar1 0.999747 0.001046 955.954714 0.000000
## ma1 0.049272 0.096327 0.511507 0.608996
## ma2 -0.082375 0.057451 -1.433829 0.151621
## ma3 0.036169 0.078311 0.461860 0.644182
## ma4 -0.090751 0.037702 -2.407074 0.016081
## ma5 0.007451 0.048946 0.152229 0.879006
## omega 7.670257 2.413212 3.178443 0.001481
## alpha1 0.257641 0.083547 3.083792 0.002044
## alpha2 0.051024 0.060078 0.849290 0.395720
## alpha3 0.554638 0.192897 2.875314 0.004036
## alpha4 0.000000 0.040231 0.000008 0.999994
## alpha5 0.135696 0.078533 1.727891 0.084008
##
## LogLikelihood : -1540.328
##
## Information Criteria
## ------------------------------------
##
## Akaike 6.4587
## Bayes 6.5716
## Shibata 6.4573
## Hannan-Quinn 6.5031
##
## Weighted Ljung-Box Test on Standardized Residuals
## ------------------------------------
## statistic p-value
## Lag[1] 0.1774 6.736e-01
## Lag[2*(p+q)+(p+q)-1][17] 11.7706 9.447e-06
## Lag[4*(p+q)+(p+q)-1][29] 16.7253 2.613e-01
## d.o.f=6
## H0 : No serial correlation
##
## Weighted Ljung-Box Test on Standardized Squared Residuals
## ------------------------------------
## statistic p-value
## Lag[1] 0.1817 0.6699
## Lag[2*(p+q)+(p+q)-1][14] 3.0796 0.9511
## Lag[4*(p+q)+(p+q)-1][24] 6.5977 0.9490
## d.o.f=5
##
## Weighted ARCH LM Tests
## ------------------------------------
## Statistic Shape Scale P-Value
## ARCH Lag[6] 0.1416 0.500 2.000 0.7067
## ARCH Lag[8] 0.5766 1.480 1.774 0.8804
## ARCH Lag[10] 1.4806 2.424 1.650 0.8642
##
## Nyblom stability test
## ------------------------------------
## Joint Statistic: 5.5301
## Individual Statistics:
## mu 0.005307
## ar1 0.047884
## ma1 0.471348
## ma2 0.504265
## ma3 0.033829
## ma4 0.155076
## ma5 0.409911
## omega 0.991344
## alpha1 1.176312
## alpha2 0.362509
## alpha3 0.522782
## alpha4 0.277211
## alpha5 0.984235
##
## Asymptotic Critical Values (10% 5% 1%)
## Joint Statistic: 2.89 3.15 3.69
## Individual Statistic: 0.35 0.47 0.75
##
## Sign Bias Test
## ------------------------------------
## t-value prob sig
## Sign Bias 1.407 0.1602
## Negative Sign Bias 1.129 0.2596
## Positive Sign Bias 1.351 0.1772
## Joint Effect 3.244 0.3555
##
##
## Adjusted Pearson Goodness-of-Fit Test:
## ------------------------------------
## group statistic p-value(g-1)
## 1 20 51.27 8.514e-05
## 2 30 71.79 1.721e-05
## 3 40 84.24 3.602e-05
## 4 50 106.01 4.424e-06
##
##
## Elapsed time : 0.7286229
coef_arch <- coef(fit_best_arch)
se_arch <- sqrt(diag(vcov(fit_best_arch)))
z_arch <- coef_arch / se_arch
p_arch <- 2 * pnorm(abs(z_arch), lower.tail = FALSE)
sig_df <- data.frame(
Parameter = names(coef_arch),
Estimasi = round(coef_arch, 6),
Std_Error = round(se_arch, 6),
z_value = round(z_arch, 4),
p_value = round(p_arch, 4),
Signifikan = ifelse(p_arch < 0.05, "Ya ✓", "Tidak ✗")
)
print(sig_df)## Parameter Estimasi Std_Error z_value p_value Signifikan
## mu mu 367.301942 5.031746 72.9969 0.0000 Ya ✓
## ar1 ar1 0.999747 0.000716 1396.7951 0.0000 Ya ✓
## ma1 ma1 0.049272 0.059078 0.8340 0.4043 Tidak ✗
## ma2 ma2 -0.082375 0.042941 -1.9183 0.0551 Tidak ✗
## ma3 ma3 0.036169 0.052152 0.6935 0.4880 Tidak ✗
## ma4 ma4 -0.090751 0.034375 -2.6401 0.0083 Ya ✓
## ma5 ma5 0.007451 0.037432 0.1991 0.8422 Tidak ✗
## omega omega 7.670257 1.591272 4.8202 0.0000 Ya ✓
## alpha1 alpha1 0.257641 0.060126 4.2850 0.0000 Ya ✓
## alpha2 alpha2 0.051024 0.043601 1.1702 0.2419 Tidak ✗
## alpha3 alpha3 0.554638 0.087555 6.3347 0.0000 Ya ✓
## alpha4 alpha4 0.000000 0.032782 0.0000 1.0000 Tidak ✗
## alpha5 alpha5 0.135696 0.047707 2.8444 0.0044 Ya ✓
resid_arch <- residuals(fit_best_arch, standardize = TRUE)
cat("=== Uji ARCH-LM pada Residual Model ARCH(3) ===\n\n")## === Uji ARCH-LM pada Residual Model ARCH(3) ===
for (lag in c(1, 5, 10, 15)) {
arch_lm2 <- ArchTest(resid_arch, lags = lag)
cat(sprintf("Lag %-3d: Chi² = %.4f, p-value = %.4f → %s\n",
lag, arch_lm2$statistic, arch_lm2$p.value,
ifelse(arch_lm2$p.value > 0.05,
"Tidak ada efek ARCH (model cukup ✓)",
"Masih terdapat efek ARCH ✗")))
}## Lag 1 : Chi² = 0.1806, p-value = 0.6708 → Tidak ada efek ARCH (model cukup ✓)
## Lag 5 : Chi² = 2.0143, p-value = 0.8472 → Tidak ada efek ARCH (model cukup ✓)
## Lag 10 : Chi² = 4.2293, p-value = 0.9364 → Tidak ada efek ARCH (model cukup ✓)
## Lag 15 : Chi² = 9.0539, p-value = 0.8747 → Tidak ada efek ARCH (model cukup ✓)
sigma_arch <- sigma(fit_best_arch)
vol_df <- data.frame(
Date = df$Date,
Close = close_ts,
Sigma = sigma_arch
)
p1 <- ggplot(vol_df, aes(x = Date, y = Close)) +
geom_line(color = "#2c7bb6") +
labs(title = "Harga Penutupan GOTO", x = NULL, y = "Harga (IDR)") +
theme_minimal(base_size = 11)
p2 <- ggplot(vol_df, aes(x = Date, y = Sigma)) +
geom_line(color = "#e63946") +
labs(title = "Estimasi Volatilitas Kondisional — ARCH(3)",
x = "Tanggal", y = "σ_t (Std Dev Kondisional)") +
theme_minimal(base_size = 11)
gridExtra::grid.arrange(p1, p2, ncol = 1)Dilakukan peramalan harga saham GOTO menggunakan model terbaik ARIMA(1,1,[5])-ARCH(5) untuk 30 hari ke depan.
h <- 30 # horizon peramalan (hari kerja)
fc_arima <- forecast(best_fit, h = h, level = c(80, 95))
autoplot(fc_arima) +
labs(title = "Forecast Harga GOTO — ARIMA(1,1,[5]) dengan Konstanta",
subtitle = paste("Horizon:", h, "hari ke depan"),
x = "Waktu", y = "Harga (IDR)") +
theme_minimal(base_size = 12)tanggal_fc <- seq(max(df$Date) + 1, by = "day", length.out = h * 2)
tanggal_fc <- tanggal_fc[!weekdays(tanggal_fc) %in% c("Saturday", "Sunday")][1:h]
fc_df <- data.frame(
Tanggal = tanggal_fc,
Forecast = round(as.numeric(fc_arima$mean), 2),
Lower_80 = round(as.numeric(fc_arima$lower[, 1]), 2),
Upper_80 = round(as.numeric(fc_arima$upper[, 1]), 2),
Lower_95 = round(as.numeric(fc_arima$lower[, 2]), 2),
Upper_95 = round(as.numeric(fc_arima$upper[, 2]), 2)
)
print(fc_df)## Tanggal Forecast Lower_80 Upper_80 Lower_95 Upper_95
## 1 2024-04-08 67.17 57.37 76.96 52.19 82.15
## 2 2024-04-09 66.74 51.59 81.89 43.57 89.91
## 3 2024-04-10 65.94 46.69 85.18 36.50 95.37
## 4 2024-04-11 65.44 42.80 88.09 30.81 100.08
## 5 2024-04-12 64.71 39.11 90.31 25.56 103.87
## 6 2024-04-15 64.04 35.37 92.71 20.20 107.88
## 7 2024-04-16 63.38 31.87 94.88 15.19 111.56
## 8 2024-04-17 62.71 28.59 96.84 10.52 114.90
## 9 2024-04-18 62.05 25.49 98.61 6.14 117.96
## 10 2024-04-19 61.39 22.55 100.23 1.99 120.79
## 11 2024-04-22 60.72 19.73 101.72 -1.97 123.42
## 12 2024-04-23 60.06 17.02 103.10 -5.76 125.89
## 13 2024-04-24 59.40 14.41 104.39 -9.41 128.21
## 14 2024-04-25 58.74 11.87 105.60 -12.94 130.41
## 15 2024-04-26 58.07 9.41 106.74 -16.35 132.50
## 16 2024-04-29 57.41 7.01 107.81 -19.67 134.49
## 17 2024-04-30 56.75 4.67 108.83 -22.90 136.40
## 18 2024-05-01 56.09 2.38 109.79 -26.05 138.22
## 19 2024-05-02 55.42 0.14 110.71 -29.13 139.97
## 20 2024-05-03 54.76 -2.06 111.58 -32.13 141.66
## 21 2024-05-06 54.10 -4.21 112.41 -35.08 143.28
## 22 2024-05-07 53.44 -6.33 113.20 -37.97 144.84
## 23 2024-05-08 52.77 -8.42 113.96 -40.81 146.35
## 24 2024-05-09 52.11 -10.47 114.69 -43.60 147.82
## 25 2024-05-10 51.45 -12.49 115.39 -46.34 149.23
## 26 2024-05-13 50.79 -14.48 116.05 -49.04 150.61
## 27 2024-05-14 50.12 -16.45 116.70 -51.69 151.94
## 28 2024-05-15 49.46 -18.39 117.31 -54.31 153.23
## 29 2024-05-16 48.80 -20.31 117.91 -56.89 154.49
## 30 2024-05-17 48.13 -22.21 118.48 -59.44 155.71
fc_arch <- ugarchforecast(fit_best_arch, n.ahead = h)
sigma_fc <- as.numeric(sigma(fc_arch))
mean_fc <- as.numeric(fitted(fc_arch))
fc_vol_df <- data.frame(
Hari = 1:h,
Tanggal = tanggal_fc,
Mean_FC = round(mean_fc, 4),
Sigma_FC = round(sigma_fc, 4),
Lower_95 = round(mean_fc - 1.96 * sigma_fc, 4),
Upper_95 = round(mean_fc + 1.96 * sigma_fc, 4)
)
print(fc_vol_df)## Hari Tanggal Mean_FC Sigma_FC Lower_95 Upper_95
## 1 1 2024-04-08 67.5617 3.5133 60.6757 74.4477
## 2 2 2024-04-09 68.0746 3.6094 61.0002 75.1491
## 3 3 2024-04-10 67.9312 3.7351 60.6104 75.2520
## 4 4 2024-04-11 68.1627 4.3714 59.5947 76.7307
## 5 5 2024-04-12 68.2264 4.5688 59.2716 77.1813
## 6 6 2024-04-15 68.3020 4.8411 58.8135 77.7905
## 7 7 2024-04-16 68.3775 5.2096 58.1666 78.5883
## 8 8 2024-04-17 68.4530 5.4156 57.8383 79.0676
## 9 9 2024-04-18 68.5285 5.6748 57.4059 79.6510
## 10 10 2024-04-19 68.6039 5.9455 56.9507 80.2571
## 11 11 2024-04-22 68.6794 6.1537 56.6181 80.7406
## 12 12 2024-04-23 68.7548 6.3855 56.2393 81.2703
## 13 13 2024-04-24 68.8302 6.6101 55.8744 81.7860
## 14 14 2024-04-25 68.9056 6.8103 55.5573 82.2538
## 15 15 2024-04-26 68.9809 7.0186 55.2245 82.7374
## 16 16 2024-04-29 69.0563 7.2181 54.9088 83.2037
## 17 17 2024-04-30 69.1316 7.4071 54.6138 83.6494
## 18 18 2024-05-01 69.2069 7.5970 54.3167 84.0971
## 19 19 2024-05-02 69.2822 7.7801 54.0332 84.5312
## 20 20 2024-05-03 69.3575 7.9577 53.7604 84.9545
## 21 21 2024-05-06 69.4327 8.1336 53.4910 85.3745
## 22 22 2024-05-07 69.5079 8.3044 53.2314 85.7845
## 23 23 2024-05-08 69.5832 8.4716 52.9789 86.1874
## 24 24 2024-05-09 69.6584 8.6363 52.7313 86.5854
## 25 25 2024-05-10 69.7335 8.7972 52.4910 86.9760
## 26 26 2024-05-13 69.8087 8.9553 52.2564 87.3610
## 27 27 2024-05-14 69.8838 9.1108 52.0267 87.7410
## 28 28 2024-05-15 69.9589 9.2634 51.8027 88.1152
## 29 29 2024-05-16 70.0340 9.4136 51.5835 88.4846
## 30 30 2024-05-17 70.1091 9.5614 51.3688 88.8494
# Gabungkan data historis dan forecast
hist_df <- data.frame(
Tanggal = df$Date,
Close = close_ts,
Type = "Aktual"
)
fc_plot_df <- data.frame(
Tanggal = tanggal_fc,
Mean = mean_fc,
Lower_95 = mean_fc - 1.96 * sigma_fc,
Upper_95 = mean_fc + 1.96 * sigma_fc
)
# Ambil 60 hari terakhir data historis untuk visualisasi
hist_recent <- tail(hist_df, 60)
ggplot() +
geom_line(data = hist_recent, aes(x = Tanggal, y = Close),
color = "#2c7bb6", linewidth = 0.8) +
geom_ribbon(data = fc_plot_df,
aes(x = Tanggal, ymin = Lower_95, ymax = Upper_95),
fill = "#e63946", alpha = 0.2) +
geom_line(data = fc_plot_df, aes(x = Tanggal, y = Mean),
color = "#e63946", linewidth = 0.9, linetype = "dashed") +
geom_vline(xintercept = as.numeric(max(df$Date)),
linetype = "dotted", color = "gray50") +
annotate("text", x = max(df$Date) + 2, y = max(hist_recent$Close),
label = "← Forecast", hjust = 0, color = "#e63946", size = 3.5) +
labs(title = "Forecast Harga Penutupan GOTO — ARIMA(1,1,[5])-ARCH(3)",
subtitle = paste("Horizon:", h, "hari kerja | Pita: 95% CI"),
x = "Tanggal", y = "Harga (IDR)") +
theme_minimal(base_size = 12)## ============================================================
## RINGKASAN ANALISIS DERET WAKTU SAHAM GOTO
## ============================================================
## [1] Stasioneritas:
## • Data level tidak stasioner → differencing 1 kali (d = 1)
## • ADF setelah differencing: p = 0.01 → stasioner
## [2] Model ARIMA Terbaik: c ARIMA(1,1,[5])
## • AIC terkecil di antara semua kandidat model
## • Komponen: AR(1) + MA(5) + konstanta + differencing 1
## [3] Diagnostik Residual:
## • Uji White Noise (Ljung-Box): lihat output Bagian 3b
## • Uji Normalitas (JB): lihat output Bagian 3a
## • Efek ARCH terdeteksi → perlu model ARCH
## [4] Model ARCH Terbaik: ARCH(5)
## • Dipilih berdasarkan AIC terkecil di antara ARCH(1)–ARCH(5)
## yang parameternya signifikan
## • Residual ARCH(5) tidak mengandung efek ARCH lagi
## [5] Forecast: 30 hari ke depan
## • Menggunakan model gabungan ARIMA(1,1,[5])-ARCH(3)
## • Interval kepercayaan 95% disertakan
## ============================================================
Analisis dilakukan dengan R. Paket utama: forecast,
tseries, rugarch, FinTS.