tlkm <- read.csv("D:/Ardi/.Kuliah/.Semester 6/PSB/TLKM.JK.csv")
tlkm <- tlkm[,-c(2,3,4,6,7)]
View(tlkm)
tlkm$Date <- as.POSIXct(tlkm$Date)
tlkm$Close <- as.numeric(tlkm$Close)
## Warning: NAs introduced by coercion
ts.tlkm <- ts(tlkm)
View(ts.tlkm)
kableExtra::kable(head(tlkm) ,caption = 'Subset Data Harian Harga Tutupan Saham')
| Date | Close |
|---|---|
| 2013-03-04 | 2100 |
| 2013-03-05 | 2100 |
| 2013-03-06 | 2220 |
| 2013-03-07 | 2120 |
| 2013-03-08 | 2150 |
| 2013-03-11 | 2170 |
str(tlkm)
## 'data.frame': 2489 obs. of 2 variables:
## $ Date : POSIXct, format: "2013-03-04" "2013-03-05" ...
## $ Close: num 2100 2100 2220 2120 2150 2170 2170 2120 2060 2100 ...
summary(tlkm)
## Date Close
## Min. :2013-03-04 00:00:00 Min. :1950
## 1st Qu.:2015-09-21 00:00:00 1st Qu.:2865
## Median :2018-03-15 00:00:00 Median :3620
## Mean :2018-03-09 12:22:16 Mean :3483
## 3rd Qu.:2020-08-25 00:00:00 3rd Qu.:4070
## Max. :2023-03-03 00:00:00 Max. :4800
## NA's :1
tlkm$Date <- as.Date(tlkm$Date)
View(tlkm)
ts.tlkm <- ts(tlkm)
str(tlkm)
## 'data.frame': 2489 obs. of 2 variables:
## $ Date : Date, format: "2013-03-03" "2013-03-04" ...
## $ Close: num 2100 2100 2220 2120 2150 2170 2170 2120 2060 2100 ...
# Boxplot
y <- tlkm$Date
x <- tlkm$Close
boxplot(x, xlab="Harga Tutupan Saham TLKM", col="lightblue")
Data tidak terlihat memiliki pencilan
# plot harian
ggplot(tlkm, aes(x=Date, y=Close)) +
geom_line() +
labs(title = "Plot Data Harian Harga Tutupan Saham TLKM",
subtitle = "1 Januari 2012 - 31 Desember 2022") +
theme(plot.title = element_text(face = "bold", hjust=.5),
plot.subtitle = element_text(hjust=.5),
legend.position = "bottom",
panel.background = element_rect(fill=NA))
Berdasarkan plot time series yang ditampilkan di atas, pola data nilai
tukar cenderung berbentuk campuran.
p=(2206/2489)
f=as.integer(p*2489)
jumlah.train <- as.integer(p*nrow(tlkm))
ggplot(tlkm, aes(x=Date, y=Close)) +
geom_line() +
labs(title = "Plot Data Harian Harga Tutupan Saham TLKM",
subtitle = "1 Januari 2012 - 31 Desember 2022") +
geom_vline(aes(xintercept = Date[jumlah.train],
col="Pemisah_data_train"), lty=2, lwd=.7) +
theme(plot.title = element_text(face = "bold", hjust=.5),
plot.subtitle = element_text(hjust=.5),
legend.position = "bottom",
panel.background = element_rect(fill=NA)) +
scale_color_manual(name = "", values = c(Pemisah_data_train="blue"))
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## i Please use `linewidth` instead.
Berdasarkan hasil eksplorasi dan pertimbangan terkait pola data,
didapatkan titik potong yang dinilai tepat dalam membagi data training
dan data testing, yaitu pada nilai proporsi data training sebesar 88.6%.
Titik pemisah data training dan data testing tersebut bertepatan pada
tanggal 10 Januari 2022.
tlkm[jumlah.train,1]
## [1] "2022-01-10"
train=1:f
training.ts <- ts(tlkm$Close[train])
testing.ts <- ts(tlkm$Close[-train], start = f+1)
# Mengisi nilai yang hilang dengan nilai rata-rata
library(imputeTS)
## Warning: package 'imputeTS' was built under R version 4.1.3
##
## Attaching package: 'imputeTS'
## The following object is masked from 'package:tseries':
##
## na.remove
## The following object is masked from 'package:zoo':
##
## na.locf
training.ts <- na_mean(training.ts)
#Plot data training
ggplot(tlkm[1:2206,], aes(x=Date, y=Close)) +
geom_line() +
labs(title = "Plot Time Series Data Training Harga Tutupan Saham TLKM",
subtitle = "(Januari 2012 - Januari 2022)") +
theme(plot.title = element_text(face = "bold", hjust=.5),
plot.subtitle = element_text(hjust=.5),
legend.position = "bottom",
panel.background = element_rect(fill=NA))
#Plot data testing
ggplot(tlkm[2207:2489,], aes(x=Date, y=Close)) +
geom_line() +
labs(title = "Plot Time Series Data Testing Harga Tutupan Saham TLKM",
subtitle = "(Januari 2022 - Desember 2022)") +
theme(plot.title = element_text(face = "bold", hjust=.5),
plot.subtitle = element_text(hjust=.5),
legend.position = "bottom",
panel.background = element_rect(fill=NA))
par(mfrow=c(1,2))
acf(training.ts, main = "ACF Plot for MA(q)")
pacf(training.ts, main = "PACF Plot for AR(p)")
Hipotesis yang diuji: H0 : data tidak stasioner H1 : data stasioner
adf.test(training.ts)
##
## Augmented Dickey-Fuller Test
##
## data: training.ts
## Dickey-Fuller = -1.8986, Lag order = 13, p-value = 0.6212
## alternative hypothesis: stationary
Hasil di atas menunjukkan bahwa \(P-value\) hasil uji di atas lebih besar dari \(alpha=0.05\), sehingga terima H0. Artinya, pada taraf nyata 5% tidak cukup bukti untuk menyatakan bahwa data telah stasioner.
train.diff<-diff(training.ts, differences = 1)
par(mfrow=c(1,2))
acf(train.diff, main = "ACF Plot for MA(q)")
pacf(train.diff, main = "PACF Plot for AR(p)")
adf.test(train.diff)
## Warning in adf.test(train.diff): p-value smaller than printed p-value
##
## Augmented Dickey-Fuller Test
##
## data: train.diff
## Dickey-Fuller = -14.133, Lag order = 13, p-value = 0.01
## alternative hypothesis: stationary
Hasil di atas menunjukkan bahwa \(P-value=0.01\) kurang dari \(alpha=0.05\), sehingga tolak H0. Artinya, pada taraf nyata 5% cukup bukti untuk menyatakan bahwa data telah stasioner.
Penentuan ordo model ARIMA dapat dilakukan dengan menampilkan plot ACF,PACF, dan EACF sebagai berikut:
#Identifikasi Model ARIMA dengan ACF, PACF, dan EACF
acf(train.diff, main="ACF data harga tutupan saham")
pacf(train.diff, main="PACF data harga tutupan saham")
eacf(train.diff)
## AR/MA
## 0 1 2 3 4 5 6 7 8 9 10 11 12 13
## 0 x x o x o o o o o x o o o o
## 1 x x o x o o o o o x o o o o
## 2 x x o o o o o o o o o o o o
## 3 x x x o o o o o o o o o o o
## 4 x x x x o o o o o o o o o o
## 5 x x x x x o o o o o o o o o
## 6 x x x x x o o o o x o o o o
## 7 x x x x x x x o o o o o o o
Berdasarkan plot di atas, didapatkan kandidat model ARIMA sebagai berikut: ARIMA(2,1,2) ARIMA(0,1,4) ARIMA(1,1,4) ARIMA(0,1,10) ARIMA(3,1,3)
Model terbaik dipilih berdasarkan AIC terkecil
model1 <- Arima(train.diff,order = c(2,1,2),method ="ML")
summary(model1)
## Series: train.diff
## ARIMA(2,1,2)
##
## Coefficients:
## ar1 ar2 ma1 ma2
## 0.4781 -0.0412 -1.5931 0.5931
## s.e. 0.1599 0.0356 0.1604 0.1604
##
## sigma^2 = 3952: log likelihood = -12256.2
## AIC=24522.41 AICc=24522.43 BIC=24550.9
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set -0.6559372 62.79158 43.57541 NaN Inf 0.6698031 0.0006962465
model2 <- Arima(train.diff,order = c(0,1,4),method ="ML")
summary(model2)
## Series: train.diff
## ARIMA(0,1,4)
##
## Coefficients:
## ma1 ma2 ma3 ma4
## -1.1117 -0.0056 0.1133 0.0039
## s.e. 0.0214 0.0327 0.0328 0.0214
##
## sigma^2 = 3951: log likelihood = -12255.96
## AIC=24521.92 AICc=24521.95 BIC=24550.41
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set -0.6164583 62.78647 43.50353 NaN Inf 0.6686983 -0.0001815814
model3 <- Arima(train.diff,order = c(1,1,4),method ="ML")
summary(model3)
## Series: train.diff
## ARIMA(1,1,4)
##
## Coefficients:
## ar1 ma1 ma2 ma3 ma4
## -0.4743 -0.6373 -0.5334 0.1279 0.0429
## s.e. 0.4923 0.4927 0.5477 0.0246 0.0560
##
## sigma^2 = 3952: log likelihood = -12255.68
## AIC=24523.35 AICc=24523.39 BIC=24557.54
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set -0.6076433 62.77894 43.48479 NaN Inf 0.6684102 0.000617637
model4 <- Arima(train.diff,order = c(0,1,10),method = "ML")
summary(model4)
## Series: train.diff
## ARIMA(0,1,10)
##
## Coefficients:
## ma1 ma2 ma3 ma4 ma5 ma6 ma7 ma8
## -1.1136 0.0039 0.1091 -0.0509 0.0508 -0.0056 -0.0126 0.0427
## s.e. 0.0216 0.0321 0.0320 0.0320 0.0331 0.0330 0.0325 0.0326
## ma9 ma10
## -0.0530 0.0292
## s.e. 0.0308 0.0211
##
## sigma^2 = 3944: log likelihood = -12250.99
## AIC=24523.98 AICc=24524.1 BIC=24586.66
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set -0.676067 62.64185 43.45061 NaN Inf 0.6678847 0.001070975
model5 <- Arima(train.diff,order = c(3,1,3),method = "ML")
summary(model5)
## Series: train.diff
## ARIMA(3,1,3)
##
## Coefficients:
## ar1 ar2 ar3 ma1 ma2 ma3
## 0.0327 0.4609 0.0572 -1.1456 -0.4161 0.5616
## s.e. 0.1710 0.1291 0.0298 0.1702 0.2822 0.1304
##
## sigma^2 = 3944: log likelihood = -12253.22
## AIC=24520.44 AICc=24520.49 BIC=24560.33
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set -0.7183649 62.70349 43.46665 NaN Inf 0.6681312 -0.000134308
Model <- c("ARIMA (2,1,2)","ARIMA (0,1,4)","ARIMA (1,1,4)","ARIMA (0,1,10)","ARIMA(3,1,3)")
AIC <- c(model1$aic,model2$aic,model3$aic,model4$aic,model5$aic)
BIC <- c(model1$bic,model2$bic,model3$bic,model4$bic,model5$bic)
Akurasi <- data.frame(Model,AIC,BIC)
kableExtra::kable(Akurasi)
| Model | AIC | BIC |
|---|---|---|
| ARIMA (2,1,2) | 24522.41 | 24550.90 |
| ARIMA (0,1,4) | 24521.92 | 24550.41 |
| ARIMA (1,1,4) | 24523.35 | 24557.54 |
| ARIMA (0,1,10) | 24523.98 | 24586.66 |
| ARIMA(3,1,3) | 24520.44 | 24560.33 |
paste("Model yang terbaik berdasarkan akurasi adalah model",Akurasi$Model[which.min(Akurasi[,"AIC"])])
## [1] "Model yang terbaik berdasarkan akurasi adalah model ARIMA(3,1,3)"
model6 <- Arima(train.diff, order=c(4,1,3),method="ML") #intersep signifikan
lmtest::coeftest(model6)
##
## z test of coefficients:
##
## Estimate Std. Error z value Pr(>|z|)
## ar1 0.174304 0.301205 0.5787 0.5628
## ar2 0.212070 0.276067 0.7682 0.4424
## ar3 0.046585 0.038570 1.2078 0.2271
## ar4 -0.021750 0.040793 -0.5332 0.5939
## ma1 -1.287008 0.301049 -4.2751 1.911e-05 ***
## ma2 -0.017680 0.544142 -0.0325 0.9741
## ma3 0.304692 0.297229 1.0251 0.3053
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Model <- c("ARIMA (4,1,3)")
AIC <- c(model6$aic)
BIC <- c(model6$bic)
Akurasi <- data.frame(Model,AIC,BIC)
Akurasi
## Model AIC BIC
## 1 ARIMA (4,1,3) 24521.41 24567
Model <- c("ARIMA (3,1,3)","ARIMA (4,1,3)")
AIC <- c(model5$aic, model6$aic)
BIC <- c(model5$bic, model6$bic)
Akurasi <- data.frame(Model,AIC,BIC)
kableExtra::kable(Akurasi)
| Model | AIC | BIC |
|---|---|---|
| ARIMA (3,1,3) | 24520.44 | 24560.33 |
| ARIMA (4,1,3) | 24521.41 | 24567.00 |
Model terbaik adalah ARIMA(3,1,3)
sisaan <- model5$residuals
tsdiag(model5)
par(mfrow = c(2,2))
qqnorm(sisaan)
qqline(sisaan, col = "blue", lwd = 2)
plot(sisaan, type="o",
ylab = "Sisaan", xlab = "Order", main = "Sisaan Model 5 vs Order")
abline(h = 0, col='red')
acf(sisaan)
pacf(sisaan)
1. Normal Q-Q Plot Berdasarkan hasil eksplorasi di atas, terlihat bahwa
banyak amatan yang cenderung menjauhi garis qq-plot distribusi normal,
sehingga secara eksploratif, dapat disimpulkan bahwa sisaan belum cukup
menyebar normal.
Residual vs Order Berdasarkan hasil eksplorasi di atas, titik pada plot kebebasan sisaan mayoritas bergerak di sekitar titik nol. Namun, terdapat beberapa titik amatan yang terletak cukup jauh dari titik nol. Sehingga, belum dapat disimpulkan apakah terdapat autokorelasi atau tidak.
Plot ACF dan PACF Berdasarkan hasil eksplorasi di atas, baik dari plot ACF maupun plot PACF, pada keduanya terdapat garis vertikal di lag tertentu yang melebihi tinggi garis biru horizontal. Artinya, menurut kedua plot ini, terdapat autokorelasi pada model.
1) Sisaan Menyebar Normal
Hipotesis yang digunakan adalah sebagai berikut: H0: Sisaan mengikuti sebaran normal H1: Sisaan tidak mengikuti sebaran normal
jarque.bera.test(sisaan)
##
## Jarque Bera Test
##
## data: sisaan
## X-squared = 7981.3, df = 2, p-value < 2.2e-16
Berdasarkan Jarque Bera Test, diperoleh p-value < α (0.05), maka Tolak H0. Artinya, cukup bukti untuk menyatakan bahwa sisaan tidak menyebar normal pada taraf nyata 5%.
2) Sisaan saling bebas/tidak ada autokorelasi Hipotesis yang digunakan adalah sebagai berikut: H0: Tidak ada autokorelasi H1: Ada autokorelasi
Box.test(sisaan, type = "Ljung")
##
## Box-Ljung test
##
## data: sisaan
## X-squared = 3.9829e-05, df = 1, p-value = 0.995
Berdasarkan hasil uji di atas, didapat nilai \(P−Value=0.995\) yang berarti
TERIMA H0. Artinya, pada taraf nyata 5%, ada bukti untuk
menyatakan bahwa tidak ada autokorelasi pada data.
3) Nilai tengah sisaan sama dengan nol Hipotesis yang digunakan adalah sebagai berikut: H0: Nilai tengah sisaan bernilai nol H1: Nilai tengah sisaan tak bernilai nol
t.test(sisaan, mu = 0, conf.level = 0.95)
##
## One Sample t-test
##
## data: sisaan
## t = -0.53788, df = 2204, p-value = 0.5907
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## -3.337416 1.900687
## sample estimates:
## mean of x
## -0.7183649
Berdasarkan hasil uji di atas, didapat nilai \(P−Value=0.5907\) yang berarti
TERIMA H0. Artinya, pada taraf nyata 5%, ada bukti untuk
menyatakan bahwa nilai tengah sisaan bernilai nol.
Identifikasi adanya proses ARCH pada sisaan model ARIMA(3,1,3) dapat dilakukan dengan uji Lagrange Multiplier (LM). Hipotesis yang digunakan adalah sebagai berikut: H0 : Tidak terjadi heteroskedastisitas H1 : Terjadi Heteroskedastisitas
for (i in 1:15) {
ArchTest <- ArchTest(model5$residuals, lags=i, demean=TRUE)
cat("P Value LM Test lag ke", i,"adalah" , ArchTest$p.value, "\n") }
## P Value LM Test lag ke 1 adalah 0
## P Value LM Test lag ke 2 adalah 0
## P Value LM Test lag ke 3 adalah 0
## P Value LM Test lag ke 4 adalah 0
## P Value LM Test lag ke 5 adalah 0
## P Value LM Test lag ke 6 adalah 0
## P Value LM Test lag ke 7 adalah 0
## P Value LM Test lag ke 8 adalah 0
## P Value LM Test lag ke 9 adalah 0
## P Value LM Test lag ke 10 adalah 0
## P Value LM Test lag ke 11 adalah 0
## P Value LM Test lag ke 12 adalah 0
## P Value LM Test lag ke 13 adalah 0
## P Value LM Test lag ke 14 adalah 0
## P Value LM Test lag ke 15 adalah 0
Berdasarkan hasil uji diperoleh nilai \(P-Value\) sampai lag ke-15 yang didapat lebih kecil dari α = 5%, maka keputusan yang diambil adalah Tolak H0. Dengan kata lain, dapat disimpulkan bahwa terdapat unsur heteroskedastisitas pada sisaan model ARIMA(3,1,3). Kondisi yang menolak H0 ini terjadi sampai dengan lag ke-15 sehingga dapat dikatakan bahwa indikasi pemodelan sisaan ini lebih cocok menggunakan model GARCH dibandingkan model ARCH. Hal tersebut bersesuaian dengan pernyataan Desvina & Meijer (2018) yang menyebutkan bahwa ketika pemeriksaan sisaan yang dilakukan dari lag 1 sampai 12 signifikan, maka model ARCH lebih cocok digunakan. Akan tetapi, jika pemeriksaan sisaan dilakukan hingga lebih dari lag 12, maka model GARCH lebih cocok digunakan. Oleh karena itu, selanjutnya akan dilakukan pendugaan model dengan menggunakan GARCH.
Pendugaan model GARCH untuk mendapat model terbaik ditentukan dengan cmempertimbangkan nilai \(p-value\) ARCH-LM, nilai AIC terkecil, dan signifikansi parameternya.
library(fGarch)
## Warning: package 'fGarch' was built under R version 4.1.3
## NOTE: Packages 'fBasics', 'timeDate', and 'timeSeries' are no longer
## attached to the search() path when 'fGarch' is attached.
##
## If needed attach them yourself in your R script by e.g.,
## require("timeSeries")
##
## Attaching package: 'fGarch'
## The following object is masked from 'package:TTR':
##
## volatility
Hasil trial and error menghasilkan model ARIMA(3,1,3)-GARCH(3,4) dengan \(p-value\) uji ARCH-LM sebesar 0,9708, artinya efek ARCH sudah teratasi. Selanjutnya akan dilakukan overfitting pada model GARCH.
Dari overfitting didapatkan ringkasan tabel sebagai berikut.
| Model | Signifikansi Parameter | AIC |
|---|---|---|
| ARIMA(3,1,3)-GARCH(3,4) | Signifikan | 10.982 |
| ARIMA(3,1,3)-GARCH(4,4) | Signifikan | 10.983 |
| ARIMA(3,1,3)-GARCH(3,5) | Signifikan | 10.983 |
Berdasarkan tabel di atas, didapat bahwa model ARIMA(3,1,3)-GARCH(3,4) hasil overfitting telah menghasilkan nilai AIC paling minimum sehingga dipilih menjadi model terbaik. Selanjutnya, sebelum melakukan peramalan, dilakukan uji diagnostik kembali pada model ARIMA(3,1,3)-GARCH(3,4) dengan uji Shapiro.Wilk dan uji LM ARCH dan hasilnya sebagai berikut:
| Jenis Pengujian | P-value |
|---|---|
| Normalitas | 0.02 |
| Efek ARCH | 0.96 |
Tabel di atas menunjukkan hasil uji diagnostik model ARIMA(3,1,3) GARCH(3,4) untuk normalitas dan heterokesdatisitas. Berdasarkan nilai \(P-value\) yang didapatkan dari kedua uji tersebut, model sudah memenuhi asumsi kenormalan dan kehomogenan ragam karena memiliki p-value yang lebih besar daripada \(α = 1%\). Hasil tersebut menunjukkan bahwa model GARCH sudah mengatasi heteroskesdastisitas dan ketidaknormalan sisaan hasil uji formal pada model ARIMA tanpa GARCH.
Peramalan dilakukan dengan menggunakan model terbaik yang didapatka dari pendugaan model GARCH. Hasil ramalan harga tutupan saham TLKM menggunakan model ARIMA (3,1,3)-GARCH (3,4) selama 40 periode ke depan ditunjukkan pada plot di bawah:
# Peramalan
garchSpec <- ugarchspec(
variance.model=list(model="sGARCH",
garchOrder=c(3,4)),
mean.model=list(armaOrder=c(3,3)),
distribution.model="std")
garchFitt <- ugarchfit(spec=garchSpec, data=train.diff)
## Warning in arima(data, order = c(modelinc[2], 0, modelinc[3]), include.mean =
## modelinc[1], : possible convergence problem: optim gave code = 1
forc<- ugarchforecast(fitORspec = garchFitt, data = tlkm$Close, n.ahead = 283, n.roll = 0)
plot(forc, which= 1)
Hasil forecasting di atas masih perlu ditransformasi balik karena adanya prosess differencing. Hasil transformasi balik serta perbandingan data ramalan dengan data aktual dapat dilihat di pada tabel berikut.
pt_1 <- tlkm$Close[2206] #nilai akhir data latih
hasil.forc.Diff <- forc@forecast$seriesFor[,1]
hasil <- diffinv(hasil.forc.Diff, differences = 1) + pt_1
perbandingan <- data.frame("Aktual"= testing.ts,
"Ramalan" = hasil[-1])
head(perbandingan,10)
## Aktual Ramalan
## 1 4110 4098.744
## 2 4180 4100.707
## 3 4190 4104.104
## 4 4180 4105.586
## 5 4250 4106.977
## 6 4250 4108.368
## 7 4220 4109.340
## 8 4330 4110.527
## 9 4300 4111.516
## 10 4290 4112.567
Date<-c(tlkm$Date[2207:2489])
dataframe <- data.frame(Date, perbandingan)
T <- nrow(dataframe)
MAPE <- 1/T*sum(abs((dataframe$Aktual-dataframe$Ramalan)/dataframe$Aktual)*100)
MAPE
## [1] 7.049918
Menurut Marikar (2019), nilai MAPE yang kurang dari 10% dikategorikan sebagai hasil peramalan yang sangat baik. Hasil akurasi peramalan data nilai tukar rupiah menggunakan nilai MAPE menunjukkan angka 7.05%. Hal ini berarti peramalan data nilai tukar rupiah terhadap dolar AS dengan menggunakan model ARIMA(3,1,3)-GARCH(3,4) sudah tepat digunakan karena cukup mendekati data aktual.