library(quantmod)
library(tidyverse)
library(tseries)
library(FinTS)
library(rugarch)
library(forecast)
library(scales)
getSymbols(
"AAPL",
src = "yahoo",
from = "2022-04-11",
to = "2026-10-01",
auto.assign = TRUE
)
## [1] "AAPL"
head(AAPL)
## AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume AAPL.Adjusted
## 2022-04-11 168.71 169.03 165.50 165.75 72246700 162.1100
## 2022-04-12 168.02 169.87 166.64 167.66 79265200 163.9781
## 2022-04-13 167.39 171.04 166.77 170.40 70618900 166.6579
## 2022-04-14 170.62 171.27 165.04 165.29 75329400 161.6601
## 2022-04-18 163.92 166.60 163.57 165.07 69023900 161.4450
## 2022-04-19 165.02 167.82 163.91 167.40 67723800 163.7237
tail(AAPL)
## AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume AAPL.Adjusted
## 2026-09-23 341.08 341.80 335.50 337.02 31658800 337.02
## 2026-09-24 336.72 338.91 334.30 335.92 24733100 335.92
## 2026-09-25 336.04 341.67 334.53 341.07 30002500 341.07
## 2026-09-28 340.37 342.99 338.04 338.40 32820800 338.40
## 2026-09-29 336.97 337.09 328.70 329.40 38478000 329.40
## 2026-09-30 330.80 339.50 330.14 333.02 49931500 333.02
start(AAPL)
## [1] "2022-04-11"
end(AAPL)
## [1] "2026-09-30"
data_AAPL <- data.frame(
Date = index(AAPL),
Close = as.numeric(Cl(AAPL))
)
sum(is.na(data_AAPL$Close))
## [1] 0
head(data_AAPL)
## Date Close
## 1 2022-04-11 165.75
## 2 2022-04-12 167.66
## 3 2022-04-13 170.40
## 4 2022-04-14 165.29
## 5 2022-04-18 165.07
## 6 2022-04-19 167.40
tail(data_AAPL)
## Date Close
## 1117 2026-09-23 337.02
## 1118 2026-09-24 335.92
## 1119 2026-09-25 341.07
## 1120 2026-09-28 338.40
## 1121 2026-09-29 329.40
## 1122 2026-09-30 333.02
ggplot(data_AAPL, aes(x = Date, y = Close)) +
geom_line() +
labs(
title = "Pergerakan Harga Saham APPLE INC.",
x = "Tanggal",
y = "Harga Penutupan (Rp)"
) +
theme_minimal()
## Data Transformation (return log)
data_AAPL <- data_AAPL %>%
mutate(
LogReturn = c(NA, diff(log(Close)))
) %>%
drop_na(LogReturn)
head(data_AAPL)
## Date Close LogReturn
## 1 2022-04-12 167.66 0.011457512
## 2 2022-04-13 170.40 0.016210438
## 3 2022-04-14 165.29 -0.030447112
## 4 2022-04-18 165.07 -0.001331796
## 5 2022-04-19 167.40 0.014016451
## 6 2022-04-20 167.23 -0.001016037
#PLOT LOG RETURN
ggplot(data_AAPL, aes(x = Date, y = LogReturn)) +
geom_line() +
labs(
title = "Log Return Saham AAPL",
x = "Tanggal",
y = "Log Return"
) +
theme_minimal()
## Statistik Deskriptif
summary(data_AAPL$LogReturn)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -0.0970133 -0.0076099 0.0011396 0.0006224 0.0095100 0.1426175
# Statistik tambahan
sd(data_AAPL$LogReturn)
## [1] 0.01767914
mean(data_AAPL$LogReturn)
## [1] 0.0006224102
min(data_AAPL$LogReturn)
## [1] -0.09701334
max(data_AAPL$LogReturn)
## [1] 0.1426175
n <- nrow(data_AAPL)
n_train <- floor(0.80 * n)
train <- data_AAPL[1:n_train, ]
test <- data_AAPL[(n_train + 1):n, ]
cat("Jumlah data keseluruhan :", n, "\n")
## Jumlah data keseluruhan : 1121
cat("Jumlah data training :", nrow(train), "\n")
## Jumlah data training : 896
cat("Jumlah data testing :", nrow(test), "\n")
## Jumlah data testing : 225
cat(
"Periode training :",
as.character(min(train$Date)),
"sampai",
as.character(max(train$Date)),
"\n"
)
## Periode training : 2022-04-12 sampai 2025-11-05
cat(
"Periode testing :",
as.character(min(test$Date)),
"sampai",
as.character(max(test$Date)),
"\n"
)
## Periode testing : 2025-11-06 sampai 2026-09-30
return_train <- train$LogReturn
return_test <- test$LogReturn
adf_result <- adf.test(return_train)
adf_result
##
## Augmented Dickey-Fuller Test
##
## data: return_train
## Dickey-Fuller = -10.344, Lag order = 9, p-value = 0.01
## alternative hypothesis: stationary
Hasil uji Augmented Dickey-Fuller (ADF) pada data return pelatihan (return_train) menghasilkan nilai statistik Dickey-Fuller sebesar -10,344 dengan p-value < 0,01. Karena p-value lebih kecil dari tingkat signifikansi 0,05 (alpha = 5%), maka hipotesis nol ditolak. Hal ini menunjukkan bahwa data return saham AAPL telah stasioner dan siap digunakan untuk pemodelan lebih lanjut.
par(mfrow = c(1, 2))
acf(return_train,main = "ACF Return Saham AAPL")
pacf(return_train,main = "PACF Return Saham AAPL")
par(mfrow = c(1, 1))
model_arma <- auto.arima(
return_train,
seasonal = FALSE,
stationary = TRUE,
stepwise = FALSE,
approximation = FALSE
)
summary(model_arma)
## Series: return_train
## ARIMA(0,0,0) with zero mean
##
## sigma^2 = 0.0003283: log likelihood = 2322.3
## AIC=-4642.6 AICc=-4642.59 BIC=-4637.8
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 0.000545156 0.01811906 0.01266665 100 100 0.7081714 0.01030677
# Orde ARIMA
arimaorder(model_arma)
## p d q
## 0 0 0
Model ARIMA(0,0,0) dengan zero mean menunjukkan bahwa tidak ditemukan struktur AR maupun MA yang diperlukan untuk menjelaskan dinamika rata-rata return.
Dengan kata lain, berdasarkan prosedur auto.arima, return tidak memiliki struktur autoregresif/Moving Average yang kuat pada bagian mean equation.
Oleh karena itu, model mean yang digunakan sangat sederhana.
resid_arma <- residuals(model_arma)
resid_arma <- na.omit(resid_arma)
# Plot residual
plot(
resid_arma,
type = "l",
main = "Residual Model Mean",
xlab = "Observasi",
ylab = "Residual"
)
Residual merupakan bagian return yang belum dijelaskan oleh model mean.
Residual inilah yang kemudian diperiksa apakah memiliki pola volatilitas
yang berubah-ubah. Jika residual mengandung ARCH effect, maka model mean
saja belum cukup dan perlu model volatilitas seperti GARCH/EGARCH.
arch_test <- ArchTest(resid_arma,lags = 12)
arch_test
##
## ARCH LM-test; Null hypothesis: no ARCH effects
##
## data: resid_arma
## Chi-squared = 111.08, df = 12, p-value < 2.2e-16
Karena nilai < 2,2 ^-16 jauh lebih kecil dari tingkat signifikansi alpha = 0,05 (5%), maka keputusan ujinya adalah Tolak H0. Kesimpulan Akhir:Data residual dari model ARMA (resid_arma) terbukti secara signifikan mengandung efek ARCH (heteroskedastisitas). Residual memiliki efek ARCH yang signifikan. Artinya varians/volatilitas return tidak konstan dari waktu ke waktu. Ini merupakan alasan statistik yang kuat untuk melanjutkan ke model GARCH-family.
resid_kuadrat <- resid_arma^2
par(mfrow = c(1, 2))
acf(resid_kuadrat,main = "ACF Residual Kuadrat")
pacf(resid_kuadrat,main = "PACF Residual Kuadrat")
par(mfrow = c(1, 1))
Pengkuadratan residual digunakan untuk melihat ketergantungan pada varians/volatilitas. Jika residual kuadrat memiliki autokorelasi, berarti volatilitas pada suatu periode berkaitan dengan volatilitas periode sebelumnya. Hal tersebut merupakan karakteristik yang ingin ditangkap oleh GARCH/EGARCH.
spec_garch <- ugarchspec(
variance.model = list(
model = "sGARCH",
garchOrder = c(1, 1)
),
mean.model = list(
armaOrder = c(
arimaorder(model_arma)[1],
arimaorder(model_arma)[3]
),
include.mean = TRUE
),
distribution.model = "std"
)
fit_garch <- ugarchfit(
spec = spec_garch,
data = return_train
)
show(fit_garch)
##
## *---------------------------------*
## * GARCH Model Fit *
## *---------------------------------*
##
## Conditional Variance Dynamics
## -----------------------------------
## GARCH Model : sGARCH(1,1)
## Mean Model : ARFIMA(0,0,0)
## Distribution : std
##
## Optimal Parameters
## ------------------------------------
## Estimate Std. Error t value Pr(>|t|)
## mu 0.001080 0.000457 2.3604 0.018254
## omega 0.000008 0.000004 2.2231 0.026207
## alpha1 0.069817 0.005353 13.0439 0.000000
## beta1 0.907927 0.014542 62.4359 0.000000
## shape 4.335644 0.548825 7.8999 0.000000
##
## Robust Standard Errors:
## Estimate Std. Error t value Pr(>|t|)
## mu 0.001080 0.000477 2.2650 0.023513
## omega 0.000008 0.000007 1.2210 0.222078
## alpha1 0.069817 0.018744 3.7248 0.000195
## beta1 0.907927 0.016362 55.4884 0.000000
## shape 4.335644 0.658295 6.5862 0.000000
##
## LogLikelihood : 2437.761
##
## Information Criteria
## ------------------------------------
##
## Akaike -5.4303
## Bayes -5.4035
## Shibata -5.4303
## Hannan-Quinn -5.4200
##
## Weighted Ljung-Box Test on Standardized Residuals
## ------------------------------------
## statistic p-value
## Lag[1] 1.549 0.2133
## Lag[2*(p+q)+(p+q)-1][2] 1.552 0.3492
## Lag[4*(p+q)+(p+q)-1][5] 2.157 0.5817
## d.o.f=0
## H0 : No serial correlation
##
## Weighted Ljung-Box Test on Standardized Squared Residuals
## ------------------------------------
## statistic p-value
## Lag[1] 3.643 0.05630
## Lag[2*(p+q)+(p+q)-1][5] 7.418 0.04101
## Lag[4*(p+q)+(p+q)-1][9] 11.035 0.02986
## d.o.f=2
##
## Weighted ARCH LM Tests
## ------------------------------------
## Statistic Shape Scale P-Value
## ARCH Lag[3] 0.001495 0.500 2.000 0.96916
## ARCH Lag[5] 6.623725 1.440 1.667 0.04279
## ARCH Lag[7] 8.539669 2.315 1.543 0.03974
##
## Nyblom stability test
## ------------------------------------
## Joint Statistic: 3.2153
## Individual Statistics:
## mu 0.05912
## omega 0.87645
## alpha1 0.72877
## beta1 0.67622
## shape 1.19971
##
## Asymptotic Critical Values (10% 5% 1%)
## Joint Statistic: 1.28 1.47 1.88
## Individual Statistic: 0.35 0.47 0.75
##
## Sign Bias Test
## ------------------------------------
## t-value prob sig
## Sign Bias 0.2040 0.83838
## Negative Sign Bias 2.1584 0.03116 **
## Positive Sign Bias 0.5529 0.58048
## Joint Effect 5.7843 0.12259
##
##
## Adjusted Pearson Goodness-of-Fit Test:
## ------------------------------------
## group statistic p-value(g-1)
## 1 20 22.62 0.2547
## 2 30 19.40 0.9105
## 3 40 42.84 0.3099
## 4 50 41.95 0.7523
##
##
## Elapsed time : 0.266021
GARCH(1,1) memodelkan varians bersyarat berdasarkan:
konstanta volatilitas, kuadrat shock periode sebelumnya, volatilitas periode sebelumnya.
Distribusi std (Student-t) digunakan untuk mengakomodasi return yang memiliki kemungkinan ekor distribusi lebih tebal dibandingkan distribusi normal.
coef_garch <- coef(fit_garch)
coef_garch
## mu omega alpha1 beta1 shape
## 1.079575e-03 8.010634e-06 6.981734e-02 9.079271e-01 4.335644e+00
# Matriks koefisien
fit_garch@fit$matcoef
## Estimate Std. Error t value Pr(>|t|)
## mu 1.079575e-03 4.573638e-04 2.360429 1.825381e-02
## omega 8.010634e-06 3.603313e-06 2.223130 2.620702e-02
## alpha1 6.981734e-02 5.352507e-03 13.043858 0.000000e+00
## beta1 9.079271e-01 1.454175e-02 62.435908 0.000000e+00
## shape 4.335644e+00 5.488246e-01 7.899871 2.886580e-15
μ = 0,001080 Menunjukkan estimasi rata-rata return bersyarat.
α₁ = 0,069817 Menggambarkan respons volatilitas terhadap shock baru pada return.
β₁ = 0,907927 Menunjukkan persistensi volatilitas. Nilai yang tinggi menunjukkan bahwa volatilitas masa lalu memiliki pengaruh kuat terhadap volatilitas berikutnya.
Secara kasar: \[ \alpha_1+\beta_1 =0,069817+0,907927 \approx0,9777 \] Nilai yang mendekati 1 menunjukkan persistensi volatilitas yang tinggi.
infocriteria(fit_garch)
##
## Akaike -5.430271
## Bayes -5.403497
## Shibata -5.430333
## Hannan-Quinn -5.420041
signbias_garch<-signbias(fit_garch)
signbias_garch
## t-value prob sig
## Sign Bias 0.2040245 0.83838098
## Negative Sign Bias 2.1583826 0.03116459 **
## Positive Sign Bias 0.5528850 0.58048082
## Joint Effect 5.7843221 0.12258813
Hasil menunjukkan bahwa residual standar tidak memiliki serial correlation yang signifikan berdasarkan Ljung-Box pada beberapa lag, tetapi residual kuadrat masih menunjukkan beberapa p-value di bawah 0,05, dan ARCH LM pada lag 5 dan 7 juga signifikan.
Ini menunjukkan bahwa GARCH(1,1) belum sepenuhnya menghilangkan seluruh dinamika volatilitas.
Selain itu, Sign Bias Test menunjukkan:
\[ p_{\text{Negative Sign Bias}}=0,03116 \]
yang signifikan.
Artinya terdapat indikasi bahwa shock negatif memberikan pola pengaruh yang berbeda terhadap volatilitas yang belum sepenuhnya ditangkap oleh GARCH standar.
Temuan ini menjadi motivasi untuk mencoba EGARCH, karena EGARCH secara eksplisit memungkinkan adanya efek asimetris/leverage.
spec_egarch <- ugarchspec(
variance.model = list(
model = "eGARCH",
garchOrder = c(1, 1)
),
mean.model = list(
armaOrder = c(
arimaorder(model_arma)[1],
arimaorder(model_arma)[3]
),
include.mean = TRUE
),
distribution.model = "std"
)
fit_egarch <- ugarchfit(
spec = spec_egarch,
data = return_train
)
show(fit_egarch)
##
## *---------------------------------*
## * GARCH Model Fit *
## *---------------------------------*
##
## Conditional Variance Dynamics
## -----------------------------------
## GARCH Model : eGARCH(1,1)
## Mean Model : ARFIMA(0,0,0)
## Distribution : std
##
## Optimal Parameters
## ------------------------------------
## Estimate Std. Error t value Pr(>|t|)
## mu 0.00074 0.000424 1.7452 0.080947
## omega -0.24797 0.021469 -11.5502 0.000000
## alpha1 -0.10017 0.023454 -4.2709 0.000019
## beta1 0.97000 0.002750 352.7281 0.000000
## gamma1 0.12424 0.045988 2.7015 0.006902
## shape 4.70718 0.693244 6.7901 0.000000
##
## Robust Standard Errors:
## Estimate Std. Error t value Pr(>|t|)
## mu 0.00074 0.000515 1.4373 0.150639
## omega -0.24797 0.039287 -6.3118 0.000000
## alpha1 -0.10017 0.028040 -3.5724 0.000354
## beta1 0.97000 0.004870 199.1666 0.000000
## gamma1 0.12424 0.068184 1.8221 0.068445
## shape 4.70718 0.718040 6.5556 0.000000
##
## LogLikelihood : 2445.478
##
## Information Criteria
## ------------------------------------
##
## Akaike -5.4453
## Bayes -5.4131
## Shibata -5.4454
## Hannan-Quinn -5.4330
##
## Weighted Ljung-Box Test on Standardized Residuals
## ------------------------------------
## statistic p-value
## Lag[1] 1.860 0.1727
## Lag[2*(p+q)+(p+q)-1][2] 1.864 0.2863
## Lag[4*(p+q)+(p+q)-1][5] 2.179 0.5767
## d.o.f=0
## H0 : No serial correlation
##
## Weighted Ljung-Box Test on Standardized Squared Residuals
## ------------------------------------
## statistic p-value
## Lag[1] 6.128 0.01330
## Lag[2*(p+q)+(p+q)-1][5] 8.201 0.02627
## Lag[4*(p+q)+(p+q)-1][9] 10.363 0.04192
## d.o.f=2
##
## Weighted ARCH LM Tests
## ------------------------------------
## Statistic Shape Scale P-Value
## ARCH Lag[3] 0.3092 0.500 2.000 0.5782
## ARCH Lag[5] 3.1589 1.440 1.667 0.2675
## ARCH Lag[7] 4.5914 2.315 1.543 0.2692
##
## Nyblom stability test
## ------------------------------------
## Joint Statistic: 2.5339
## Individual Statistics:
## mu 0.07716
## omega 0.26748
## alpha1 0.24290
## beta1 0.22937
## gamma1 0.05075
## shape 0.98750
##
## 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 0.09105 0.9275
## Negative Sign Bias 1.54963 0.1216
## Positive Sign Bias 1.33625 0.1818
## Joint Effect 4.31478 0.2294
##
##
## Adjusted Pearson Goodness-of-Fit Test:
## ------------------------------------
## group statistic p-value(g-1)
## 1 20 27.39 0.09583
## 2 30 30.99 0.36606
## 3 40 42.93 0.30654
## 4 50 59.58 0.14308
##
##
## Elapsed time : 0.3226631
coef_egarch <- coef(fit_egarch)
coef_egarch
## mu omega alpha1 beta1 gamma1
## 0.0007404735 -0.2479682618 -0.1001682450 0.9700029298 0.1242362994
## shape
## 4.7071852760
# Matriks koefisien
fit_egarch@fit$matcoef
## Estimate Std. Error t value Pr(>|t|)
## mu 0.0007404735 0.0004242866 1.745220 8.094653e-02
## omega -0.2479682618 0.0214688281 -11.550154 0.000000e+00
## alpha1 -0.1001682450 0.0234535893 -4.270913 1.946741e-05
## beta1 0.9700029298 0.0027500017 352.728115 0.000000e+00
## gamma1 0.1242362994 0.0459876761 2.701513 6.902481e-03
## shape 4.7071852760 0.6932437264 6.790087 1.120659e-11
infocriteria(fit_egarch)
##
## Akaike -5.445262
## Bayes -5.413133
## Shibata -5.445351
## Hannan-Quinn -5.432986
comparison_model <- data.frame(
Model = c(
"GARCH(1,1)",
"EGARCH(1,1)"
),
AIC = c(
infocriteria(fit_garch)[1],
infocriteria(fit_egarch)[1]
),
BIC = c(
infocriteria(fit_garch)[2],
infocriteria(fit_egarch)[2]
),
LogLikelihood = c(
likelihood(fit_garch),
likelihood(fit_egarch)
)
)
comparison_model
## Model AIC BIC LogLikelihood
## 1 GARCH(1,1) -5.430271 -5.403497 2437.761
## 2 EGARCH(1,1) -5.445262 -5.413133 2445.478
egarch_coef <- fit_egarch@fit$matcoef
gamma_result <- egarch_coef[5, 1:4] # Baris ke-5 (gamma1), kolom 1 sampai 4
gamma_result
## Estimate Std. Error t value Pr(>|t|)
## 0.124236299 0.045987676 2.701512883 0.006902481
std_resid_egarch <- residuals(
fit_egarch,
standardize = TRUE
)
std_resid_egarch <- as.numeric(
na.omit(std_resid_egarch)
)
plot(
std_resid_egarch,
type = "l",
main = "Residual Terstandarisasi EGARCH",
xlab = "Observasi",
ylab = "Residual Terstandarisasi"
)
acf(
std_resid_egarch,
main = "ACF Residual Terstandarisasi EGARCH"
)
### ACF residual kuadrat
acf(
std_resid_egarch^2,
main = "ACF Kuadrat Residual Terstandarisasi EGARCH"
)
### UJI LJUNG-BOX RESIDUAL
ljung_box_residual <- Box.test(
std_resid_egarch,
lag = 10,
type = "Ljung-Box"
)
ljung_box_residual
##
## Box-Ljung test
##
## data: std_resid_egarch
## X-squared = 5.9154, df = 10, p-value = 0.8223
Residual terstandarisasi tidak menunjukkan autokorelasi yang signifikan. Ini mendukung bahwa model sudah cukup baik dalam menangkap dinamika mean.
ljung_box_squared <- Box.test(
std_resid_egarch^2,
lag = 10,
type = "Ljung-Box"
)
ljung_box_squared
##
## Box-Ljung test
##
## data: std_resid_egarch^2
## X-squared = 15.474, df = 10, p-value = 0.1157
Dinamika volatilitas yang tersisa tidak menunjukkan autokorelasi yang signifikan berdasarkan uji ini.
arch_test_egarch <- ArchTest(
std_resid_egarch,
lags = 12
)
arch_test_egarch
##
## ARCH LM-test; Null hypothesis: no ARCH effects
##
## data: std_resid_egarch
## Chi-squared = 16.305, df = 12, p-value = 0.1777
Tidak terdapat bukti yang cukup bahwa residual terstandarisasi masih mengandung efek ARCH.
signbias_egarch <- signbias(fit_egarch)
signbias_egarch
## t-value prob sig
## Sign Bias 0.09105241 0.9274714
## Negative Sign Bias 1.54962551 0.1215865
## Positive Sign Bias 1.33625222 0.1818080
## Joint Effect 4.31478442 0.2294181
Artinya tidak terdapat bukti statistik bahwa residual EGARCH masih mengandung efek sign bias yang signifikan.
jarque_bera_egarch <- jarque.bera.test(
std_resid_egarch
)
jarque_bera_egarch
##
## Jarque Bera Test
##
## data: std_resid_egarch
## X-squared = 254.92, df = 2, p-value < 2.2e-16
n_forecast <- nrow(test)
forecast_egarch <- ugarchforecast(
fit_egarch,
n.ahead = n_forecast
)
#mengambil hasil forecast return
return_forecast <- as.numeric(
fitted(forecast_egarch)
)
return_forecast
## [1] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [6] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [11] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [16] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [21] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [26] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [31] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [36] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [41] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [46] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [51] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [56] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [61] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [66] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [71] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [76] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [81] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [86] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [91] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [96] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [101] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [106] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [111] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [116] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [121] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [126] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [131] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [136] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [141] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [146] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [151] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [156] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [161] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [166] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [171] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [176] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [181] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [186] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [191] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [196] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [201] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [206] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [211] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [216] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
## [221] 0.0007404735 0.0007404735 0.0007404735 0.0007404735 0.0007404735
Hal ini terjadi karena model mean yang diperoleh adalah ARIMA(0,0,0). Jadi, ketika melakukan forecast multi-step, prediksi return cenderung menuju nilai mean model.
Ini bukan berarti model memprediksi return aktual akan selalu sama; melainkan nilai ekspektasi return bersyarat untuk horizon tersebut konstan.
#mengambil hasil forecast volatilitas
vol_forecast <- as.numeric(
sigma(forecast_egarch)
)
vol_forecast
## [1] 0.01199545 0.01210026 0.01220280 0.01230310 0.01240118 0.01249706
## [7] 0.01259077 0.01268235 0.01277181 0.01285919 0.01294453 0.01302784
## [13] 0.01310917 0.01318854 0.01326599 0.01334155 0.01341526 0.01348714
## [19] 0.01355724 0.01362558 0.01369220 0.01375714 0.01382042 0.01388208
## [25] 0.01394215 0.01400067 0.01405767 0.01411318 0.01416723 0.01421986
## [31] 0.01427110 0.01432098 0.01436953 0.01441678 0.01446276 0.01450750
## [37] 0.01455103 0.01459338 0.01463458 0.01467466 0.01471363 0.01475154
## [43] 0.01478840 0.01482424 0.01485910 0.01489298 0.01492592 0.01495795
## [49] 0.01498908 0.01501933 0.01504874 0.01507732 0.01510510 0.01513209
## [55] 0.01515832 0.01518380 0.01520856 0.01523262 0.01525599 0.01527869
## [61] 0.01530075 0.01532217 0.01534298 0.01536319 0.01538283 0.01540189
## [67] 0.01542041 0.01543840 0.01545586 0.01547282 0.01548929 0.01550528
## [73] 0.01552081 0.01553588 0.01555052 0.01556473 0.01557853 0.01559193
## [79] 0.01560493 0.01561756 0.01562981 0.01564171 0.01565326 0.01566447
## [85] 0.01567535 0.01568592 0.01569617 0.01570612 0.01571578 0.01572516
## [91] 0.01573426 0.01574309 0.01575166 0.01575998 0.01576805 0.01577589
## [97] 0.01578349 0.01579087 0.01579803 0.01580498 0.01581173 0.01581827
## [103] 0.01582462 0.01583079 0.01583677 0.01584257 0.01584820 0.01585366
## [109] 0.01585897 0.01586411 0.01586910 0.01587395 0.01587864 0.01588320
## [115] 0.01588763 0.01589192 0.01589609 0.01590013 0.01590405 0.01590785
## [121] 0.01591155 0.01591513 0.01591860 0.01592197 0.01592524 0.01592842
## [127] 0.01593149 0.01593448 0.01593738 0.01594019 0.01594292 0.01594556
## [133] 0.01594813 0.01595062 0.01595304 0.01595538 0.01595766 0.01595986
## [139] 0.01596200 0.01596408 0.01596609 0.01596805 0.01596994 0.01597178
## [145] 0.01597357 0.01597530 0.01597698 0.01597861 0.01598019 0.01598172
## [151] 0.01598321 0.01598465 0.01598605 0.01598741 0.01598872 0.01599000
## [157] 0.01599124 0.01599244 0.01599361 0.01599474 0.01599584 0.01599690
## [163] 0.01599793 0.01599894 0.01599991 0.01600085 0.01600177 0.01600265
## [169] 0.01600351 0.01600435 0.01600516 0.01600594 0.01600671 0.01600744
## [175] 0.01600816 0.01600886 0.01600953 0.01601019 0.01601082 0.01601144
## [181] 0.01601203 0.01601261 0.01601318 0.01601372 0.01601425 0.01601476
## [187] 0.01601526 0.01601574 0.01601621 0.01601667 0.01601711 0.01601754
## [193] 0.01601795 0.01601835 0.01601874 0.01601912 0.01601949 0.01601985
## [199] 0.01602019 0.01602053 0.01602085 0.01602117 0.01602147 0.01602177
## [205] 0.01602206 0.01602234 0.01602261 0.01602287 0.01602312 0.01602337
## [211] 0.01602361 0.01602384 0.01602407 0.01602429 0.01602450 0.01602471
## [217] 0.01602491 0.01602510 0.01602529 0.01602547 0.01602565 0.01602582
## [223] 0.01602599 0.01602615 0.01602630
Model memperkirakan volatilitas akan meningkat secara bertahap ketika horizon forecasting semakin jauh.
Hal ini menunjukkan adanya proses mean reversion menuju tingkat volatilitas jangka panjang yang dihasilkan model.
harga_terakhir <- tail(
train$Close,
1
)
harga_forecast <- harga_terakhir *
exp(cumsum(return_forecast))
Karena model memprediksi log return, hasil tersebut harus dikonversi kembali ke skala harga agar dapat dibandingkan dengan harga aktual.
hasil_forecast <- data.frame(
Date = test$Date,
Actual = test$Close,
Forecast = harga_forecast,
Return_Forecast = return_forecast,
Volatility = vol_forecast
)
head(hasil_forecast)
## Date Actual Forecast Return_Forecast Volatility
## 1 2025-11-06 269.77 270.3401 0.0007404735 0.01199545
## 2 2025-11-07 268.47 270.5404 0.0007404735 0.01210026
## 3 2025-11-10 269.43 270.7408 0.0007404735 0.01220280
## 4 2025-11-11 275.25 270.9413 0.0007404735 0.01230310
## 5 2025-11-12 273.47 271.1420 0.0007404735 0.01240118
## 6 2025-11-13 272.95 271.3429 0.0007404735 0.01249706
tail(hasil_forecast)
## Date Actual Forecast Return_Forecast Volatility
## 220 2026-09-23 337.02 317.9342 0.0007404735 0.01602547
## 221 2026-09-24 335.92 318.1697 0.0007404735 0.01602565
## 222 2026-09-25 341.07 318.4054 0.0007404735 0.01602582
## 223 2026-09-28 338.40 318.6413 0.0007404735 0.01602599
## 224 2026-09-29 329.40 318.8773 0.0007404735 0.01602615
## 225 2026-09-30 333.02 319.1135 0.0007404735 0.01602630
Tabel ini memungkinkan perbandingan langsung antara hasil prediksi dan kondisi aktual.
Contoh observasi pertama:
Aktual = 269,77 Forecast = 270,3401
Artinya forecast pada observasi pertama berada cukup dekat dengan harga aktual.
Namun pada akhir periode:
Aktual = 333,02 Forecast = 319,1135.
Terlihat bahwa semakin panjang horizon, perbedaan antara forecast dan aktual dapat semakin besar.
hasil_plot <- hasil_forecast %>%
select(
Date,
Actual,
Forecast
) %>%
pivot_longer(
cols = c(
Actual,
Forecast
),
names_to = "Jenis",
values_to = "Harga"
)
ggplot(
hasil_plot,
aes(
x = Date,
y = Harga,
linetype = Jenis
)
) +
geom_line(linewidth = 1) +
labs(
title = "Perbandingan Harga Aktual dan Hasil Peramalan Saham APPLE INC.",
x = "Tanggal",
y = "Harga Saham (Rp)",
linetype = ""
) +
theme_minimal()
Grafik memberikan evaluasi visual mengenai kemampuan model mengikuti
perubahan harga aktual.
Apabila garis forecast dekat dengan garis aktual, berarti error relatif kecil.
Sebaliknya, jarak yang semakin besar menunjukkan kesalahan prediksi yang semakin besar.
MAE <- mean(
abs(
hasil_forecast$Actual -
hasil_forecast$Forecast
),
na.rm = TRUE
)
MAE
## [1] 14.73405
RMSE <- sqrt(
mean(
(
hasil_forecast$Actual -
hasil_forecast$Forecast
)^2,
na.rm = TRUE
)
)
RMSE
## [1] 18.6248
MAPE <- mean(
abs(
(
hasil_forecast$Actual -
hasil_forecast$Forecast
) /
hasil_forecast$Actual
),
na.rm = TRUE
) * 100
MAPE
## [1] 5.339094
SMAPE <- mean(
2 *
abs(
hasil_forecast$Actual -
hasil_forecast$Forecast
) /
(
abs(hasil_forecast$Actual) +
abs(hasil_forecast$Forecast)
),
na.rm = TRUE
) * 100
SMAPE
## [1] 5.170464
evaluasi <- data.frame(Model = "EGARCH(1,1)",MAE = MAE,RMSE = RMSE,MAPE = MAPE,SMAPE = SMAPE
)
evaluasi
## Model MAE RMSE MAPE SMAPE
## 1 EGARCH(1,1) 14.73405 18.6248 5.339094 5.170464
MAE menunjukkan rata-rata nilai absolut kesalahan prediksi. Secara sederhana, hasil ini berarti: rata-rata selisih absolut antara harga aktual dan harga forecast sekitar 14,73 USD. MAE semakin kecil → kesalahan rata-rata semakin kecil.
RMSE memberikan bobot lebih besar terhadap kesalahan yang besar karena error dikuadratkan. Nilai 18,62 menunjukkan besarnya kesalahan prediksi setelah memperhitungkan error yang besar. Karena: \[ RMSE > MAE \] terdapat indikasi bahwa terdapat beberapa error yang relatif besar.
MAPE menunjukkan rata-rata persentase absolut kesalahan prediksi terhadap harga aktual. Hasilnya sekitar 5,34%. Artinya, secara rata-rata, kesalahan relatif forecast sekitar 5,34% dari harga aktual.
SMAPE merupakan ukuran error persentase yang menggunakan rata-rata nilai absolut aktual dan forecast sebagai penyebut. Nilai 5,17% menunjukkan tingkat kesalahan relatif yang diperoleh model berdasarkan formula SMAPE yang digunakan dalam penelitian.
Secara khusus, data return sudah stasioner dan residual model mean memiliki efek ARCH yang signifikan. GARCH kemudian menunjukkan adanya indikasi negative sign bias, sehingga model EGARCH digunakan untuk mengakomodasi kemungkinan asimetri tersebut.
EGARCH memiliki AIC dan BIC yang lebih rendah dibandingkan GARCH dalam hasil penelitian ini. Selain itu, diagnostik residual EGARCH menunjukkan tidak adanya autokorelasi residual yang signifikan, tidak adanya ARCH effect yang signifikan, dan tidak adanya sign bias yang signifikan.
# 1. Melakukan peramalan 12 langkah ke depan dari tanggal terakhir (30 Sep 2026)
forecast_12_ahead <- ugarchforecast(
fit_egarch,
n.ahead = 12
)
# 2. Mengambil hasil forecast return dan volatilitas (sigma)
return_12 <- as.numeric(fitted(forecast_12_ahead))
vol_12 <- as.numeric(sigma(forecast_12_ahead))
# 3. Mengambil harga penutupan terakhir dari seluruh dataset (30 September 2026)
harga_terakhir_total <- tail(data_AAPL$Close, 1)
# 4. Mengonversi log return menjadi perkiraan harga saham AAPL (USD)
harga_12 <- harga_terakhir_total * exp(cumsum(return_12))
# 5. Membuat estimasi tanggal perdagangan 12 hari ke depan (mengabaikan akhir pekan)
tanggal_terakhir <- max(data_AAPL$Date)
tanggal_12 <- seq(from = tanggal_terakhir + 1, by = "day", length.out = 20)
tanggal_12 <- tanggal_12[!weekdays(tanggal_12) %in% c("Saturday", "Sunday")][1:12]
# 6. Menyusun hasil peramalan ke dalam data frame
tabel_forecast_12 <- data.frame(
Periode = 1:12,
Tanggal = tanggal_12,
Forecast_Return = return_12,
Forecast_Volatilitas = vol_12,
Forecast_Harga_USD = harga_12
)
# Menampilkan tabel hasil peramalan
print("=== HASIL PERAMALAN 12 PERIODE KE DEPAN SAHAM AAPL ===")
## [1] "=== HASIL PERAMALAN 12 PERIODE KE DEPAN SAHAM AAPL ==="
print(tabel_forecast_12)
## Periode Tanggal Forecast_Return Forecast_Volatilitas Forecast_Harga_USD
## 1 1 2026-10-01 0.0007404735 0.01199545 333.2667
## 2 2 2026-10-02 0.0007404735 0.01210026 333.5135
## 3 3 2026-10-05 0.0007404735 0.01220280 333.7606
## 4 4 2026-10-06 0.0007404735 0.01230310 334.0078
## 5 5 2026-10-07 0.0007404735 0.01240118 334.2552
## 6 6 2026-10-08 0.0007404735 0.01249706 334.5028
## 7 7 2026-10-09 0.0007404735 0.01259077 334.7506
## 8 8 2026-10-12 0.0007404735 0.01268235 334.9986
## 9 9 2026-10-13 0.0007404735 0.01277181 335.2467
## 10 10 2026-10-14 0.0007404735 0.01285919 335.4951
## 11 11 2026-10-15 0.0007404735 0.01294453 335.7436
## 12 12 2026-10-16 0.0007404735 0.01302784 335.9923
Forecast return untuk 12 periode bernilai konstan:
\[ 0,0007404735 \]
Hal ini konsisten dengan model mean ARIMA(0,0,0).
Sementara itu, volatilitas diproyeksikan meningkat dari:
\[ 0,011995 \]
menjadi:
\[ 0,013028. \]
Jadi, model memperkirakan return ekspektasian yang relatif konstan, tetapi volatilitas meningkat secara bertahap selama horizon 12 hari.
Harga hasil forecast meningkat dari:
\[ 333,2667 \]
menjadi:
\[ 335,9923. \]
Kenaikan tersebut merupakan konsekuensi dari return forecast positif yang diaplikasikan secara kumulatif ke harga terakhir sebesar 333,02 USD. ### Visualisasi
ggplot(tabel_forecast_12, aes(x = Tanggal, y = Forecast_Harga_USD)) +
geom_line(color = "blue", linewidth = 1) +
geom_point(color = "red", size = 2) +
scale_x_date(date_labels = "%d %b %Y", date_breaks = "2 days") +
labs(
title = "Proyeksi Pergerakan Harga Saham AAPL (12 Periode Ke Depan)",
subtitle = "Diestimasi Menggunakan Model EGARCH(1,1)",
x = "Tanggal Perdagangan",
y = "Perkiraan Harga Saham (USD)"
) +
theme_minimal()
Kesimpulan: Pertama, data harga saham AAPL dikumpulkan untuk periode
April 2022 sampai September 2026. Harga penutupan kemudian digunakan
untuk membentuk log return. Kedua, return diuji menggunakan ADF dan
diperoleh hasil stasioner. Ketiga, model mean ditentukan menggunakan
Auto ARIMA dan diperoleh ARIMA(0,0,0) dengan zero mean. Keempat,
residual model mean diuji menggunakan ARCH-LM dan ditemukan adanya efek
ARCH yang signifikan, sehingga pemodelan volatilitas menggunakan
keluarga GARCH diperlukan. Kelima, model GARCH(1,1) dibangun dan
ditemukan indikasi Negative Sign Bias. Oleh karena itu, digunakan
EGARCH(1,1) yang dapat mengakomodasi asimetri volatilitas. Keenam, hasil
EGARCH menunjukkan AIC dan BIC yang lebih rendah dibandingkan GARCH.
Diagnostik residual EGARCH juga menunjukkan tidak adanya autokorelasi
residual dan tidak adanya ARCH effect yang signifikan. Ketujuh, model
EGARCH digunakan untuk melakukan forecasting pada data testing dan
menghasilkan MAE 14,73405, RMSE 18,6248, MAPE 5,3391%, dan SMAPE
5,1705%. Terakhir, forecasting 12 periode ke depan menghasilkan proyeksi
harga dari 333,27 USD hingga 335,99 USD dengan volatilitas yang
meningkat dari sekitar 0,0120 menjadi 0,0130.