Tentang Proyek Portofolio Ini
Dokumen ini merupakan bagian dari rangkaian analisis peramalan kurs USD/IDR periode 2021–2025 menggunakan pemodelan stokastik Geometric Brownian Motion (GBM) dan Simulasi Monte Carlo. Proyek ini bertujuan untuk mengestimasi lintasan nilai tukar harian ke depan berdasarkan volatilitas dan drift historis.
Struktur Publikasi:
- [Data Wrangling] Persiapan & Transformasi Data
- [Statistik Deskriptif] Eksplorasi Deret Waktu
- [Uji Normalitas] Pengujian Asumsi Distribusi Log-Return
- [Simulasi] Estimasi Parameter & Monte Carlo
- [Analisis] Interval Kepercayaan & Proyeksi Final
🔗 Tautan Terkait: GitHub Repository | Dashboard Interaktif R Shiny
Model GBM mendefinisikan dinamika harga aset \(S_t\) sebagai proses stokastik:
\[dS_t = \mu S_t \, dt + \sigma S_t \, dW_t\]
di mana \(W_t\) adalah proses Wiener standar. Dalam bentuk diskrit yang digunakan untuk simulasi:
\[S_{t+\Delta t} = S_t \cdot \exp\left[\left(\mu - \frac{\sigma^2}{2}\right)\Delta t + \sigma\sqrt{\Delta t}\, Z_t\right], \quad Z_t \sim \mathcal{N}(0,1)\]
Parameter \(\mu\) (drift) dan \(\sigma\) (volatilitas) diestimasi langsung dari data historis log-return harian.
# Baca langsung dari CSV
df_raw <- read.csv(
"C:/Users/anjan/Documents/Downloads/usd-idr-portfolio-github/usd-idr-gbm-montecarlo/data/Data Historis USD_IDR.csv",
header = TRUE,
stringsAsFactors = FALSE,
fileEncoding = "UTF-8-BOM"
)
# Wrangling
df_usd_idr <- df_raw %>%
select(Tanggal, Terakhir) %>%
mutate(
Kurs = as.numeric(gsub(",", ".", gsub("\\.", "", Terakhir))),
Tanggal = as.Date(Tanggal, format = "%d/%m/%Y")
) %>%
select(Tanggal, Kurs) %>%
arrange(Tanggal)
# Hitung log-return
df_return <- df_usd_idr %>%
mutate(Log_Return = log(Kurs / lag(Kurs))) %>%
filter(!is.na(Log_Return))
cat("Data berhasil dimuat.\n")## Data berhasil dimuat.
## Observasi kurs : 1268
## Observasi return : 1267
cat("Periode :", format(min(df_usd_idr$Tanggal), "%d %B %Y"),
"–", format(max(df_usd_idr$Tanggal), "%d %B %Y"), "\n")## Periode : 01 January 2021 – 31 December 2025
Parameter GBM diestimasi dari statistik log-return harian:
rt <- df_return$Log_Return
n_ret <- length(rt)
# Parameter harian
mu_hat <- mean(rt)
sigma_hat <- sd(rt)
# Parameter disetahunkan (asumsi 252 hari perdagangan)
mu_annual <- mu_hat * 252
sigma_annual <- sigma_hat * sqrt(252)
# Kurs awal simulasi (S0) = kurs penutupan terakhir
S0 <- tail(df_usd_idr$Kurs, 1)
T_akhir <- as.Date("2025-12-31")
T0 <- max(df_usd_idr$Tanggal)
cat("=== PARAMETER GBM YANG DIESTIMASI ===\n\n")## === PARAMETER GBM YANG DIESTIMASI ===
cat(sprintf("S₀ (kurs terakhir) : Rp %s per USD\n",
formatC(S0, format = "f", digits = 1, big.mark = ".")))## S₀ (kurs terakhir) : Rp 16.675.0 per USD
## µ (drift harian) : 0.00012605
## σ (volatilitas har.) : 0.00321561
## µ (drift tahunan) : 0.031764 (3.1764%)
## σ (volatilitas thn.) : 0.051046 (5.1046%)
## n (obs. return) : 1267 hari perdagangan
library(knitr)
library(kableExtra)
# Membuat dataframe parameter berdasarkan output kalkulasi data aktual
df_param_gbm <- data.frame(
Parameter = c("Kurs Awal Aktual", "Tren Pertumbuhan (Drift)", "Fluktuasi Acak (Volatilitas)", "Horizon Waktu Proyeksi"),
Notasi = c("S0", "μ (mu)", "σ (sigma)", "T"),
Nilai_Harian = c("Rp 16.420,00", "0,000129", "0,003667", "252 Hari Kerja"),
Nilai_Tahunan = c("-", "0,032506 (3,25%)", "0,058209 (5,82%)", "1 Tahun Kalender")
)
# Membuat visualisasi tabel profesional dengan kableExtra
df_param_gbm %>%
kable(
col.names = c("Nama Parameter", "Notasi Matematis", "Skala Harian", "Skala Tahunan (Annualized)"),
align = c("l", "c", "r", "r"),
caption = "Tabel 3.3: Parameter Model Stokastik Geometric Brownian Motion (GBM)"
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center"
) %>%
row_spec(0, bold = TRUE, color = "white", background = "#00b4d8") %>% # Warna Cyan/Biru Portofolio
column_spec(1, bold = TRUE) %>%
column_spec(2, italic = TRUE)| Nama Parameter | Notasi Matematis | Skala Harian | Skala Tahunan (Annualized) |
|---|---|---|---|
| Kurs Awal Aktual | S0 | Rp 16.420,00 |
|
| Tren Pertumbuhan (Drift) | μ (mu) | 0,000129 | 0,032506 (3,25%) |
| Fluktuasi Acak (Volatilitas) | σ (sigma) | 0,003667 | 0,058209 (5,82%) |
| Horizon Waktu Proyeksi | T | 252 Hari Kerja | 1 Tahun Kalender |
# Tentukan horizon simulasi
# Simulasi ke depan dari kurs terakhir
horizon_hari <- 252 # 1 tahun perdagangan ke depan
dt <- 1 # time step = 1 hari
cat("=== HORIZON SIMULASI ===\n")## === HORIZON SIMULASI ===
## Titik awal (S₀) : 31 December 2025
## Horizon : 252 hari perdagangan (~1 tahun)
## Time step (Δt) : 1 hari
# Fungsi simulasi GBM diskrit
# Output: matrix (horizon+1) x n_sim — baris = waktu, kolom = satu lintasan
simulasi_gbm <- function(S0, mu, sigma, dt, horizon, n_sim) {
# Inisialisasi matrix hasil
# Baris 1 = S0, baris 2 s.d. horizon+1 = hasil simulasi
S_matrix <- matrix(NA, nrow = horizon + 1, ncol = n_sim)
S_matrix[1, ] <- S0
# Loop simulasi
for (t in 2:(horizon + 1)) {
Z <- rnorm(n_sim) # n_sim bilangan acak N(0,1)
S_matrix[t, ] <- S_matrix[t - 1, ] *
exp((mu - 0.5 * sigma^2) * dt + sigma * sqrt(dt) * Z)
}
return(S_matrix)
}
cat("Fungsi simulasi GBM berhasil didefinisikan.\n")## Fungsi simulasi GBM berhasil didefinisikan.
## Formula: S(t+dt) = S(t) × exp[(µ - σ²/2)dt + σ√dt × Z]
## Z ~ N(0,1)
## Menjalankan simulasi 1.000 iterasi...
t_start <- proc.time()
sim_1000 <- simulasi_gbm(
S0 = S0,
mu = mu_hat,
sigma = sigma_hat,
dt = 1,
horizon = horizon_hari,
n_sim = 1000
)
t_1000 <- proc.time() - t_start
cat(sprintf("✓ Selesai dalam %.3f detik.\n", t_1000["elapsed"]))## ✓ Selesai dalam 0.300 detik.
## Dimensi matrix : 253 baris × 1000 kolom
cat(sprintf("Kurs akhir rata-rata : Rp %s\n",
formatC(mean(sim_1000[nrow(sim_1000), ]),
format = "f", digits = 0, big.mark = ".")))## Kurs akhir rata-rata : Rp 17.197
## Menjalankan simulasi 5.000 iterasi...
t_start <- proc.time()
sim_5000 <- simulasi_gbm(
S0 = S0,
mu = mu_hat,
sigma = sigma_hat,
dt = 1,
horizon = horizon_hari,
n_sim = 5000
)
t_5000 <- proc.time() - t_start
cat(sprintf("✓ Selesai dalam %.3f detik.\n", t_5000["elapsed"]))## ✓ Selesai dalam 0.600 detik.
cat(sprintf("Kurs akhir rata-rata : Rp %s\n",
formatC(mean(sim_5000[nrow(sim_5000), ]),
format = "f", digits = 0, big.mark = ".")))## Kurs akhir rata-rata : Rp 17.212
## Menjalankan simulasi 10.000 iterasi...
t_start <- proc.time()
sim_10000 <- simulasi_gbm(
S0 = S0,
mu = mu_hat,
sigma = sigma_hat,
dt = 1,
horizon = horizon_hari,
n_sim = 10000
)
t_10000 <- proc.time() - t_start
cat(sprintf("✓ Selesai dalam %.3f detik.\n", t_10000["elapsed"]))## ✓ Selesai dalam 1.410 detik.
cat(sprintf("Kurs akhir rata-rata : Rp %s\n",
formatC(mean(sim_10000[nrow(sim_10000), ]),
format = "f", digits = 0, big.mark = ".")))## Kurs akhir rata-rata : Rp 17.218
tbl_compute <- data.frame(
Skenario = c("Skenario 1", "Skenario 2", "Skenario 3"),
Iterasi = c("1.000", "5.000", "10.000"),
Waktu_detik = c(
round(t_1000["elapsed"], 3),
round(t_5000["elapsed"], 3),
round(t_10000["elapsed"], 3)
),
Mean_Akhir = c(
formatC(mean(sim_1000[nrow(sim_1000), ]), format="f", digits=0, big.mark="."),
formatC(mean(sim_5000[nrow(sim_5000), ]), format="f", digits=0, big.mark="."),
formatC(mean(sim_10000[nrow(sim_10000),]), format="f", digits=0, big.mark=".")
),
SD_Akhir = c(
formatC(sd(sim_1000[nrow(sim_1000), ]), format="f", digits=0, big.mark="."),
formatC(sd(sim_5000[nrow(sim_5000), ]), format="f", digits=0, big.mark="."),
formatC(sd(sim_10000[nrow(sim_10000),]), format="f", digits=0, big.mark=".")
)
)
kable(tbl_compute,
caption = "Tabel 6.1 — Perbandingan Tiga Skenario Simulasi Monte Carlo",
align = c("l","r","r","r","r"),
col.names = c("Skenario", "Iterasi",
"Waktu (detik)", "Mean Kurs Akhir (IDR)", "SD Kurs Akhir (IDR)")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "bordered"),
full_width = TRUE) %>%
column_spec(2, bold = TRUE) %>%
column_spec(4, bold = TRUE, color = "#2c7bb6") %>%
row_spec(3, background = "#eafaf1", bold = TRUE)| Skenario | Iterasi | Waktu (detik) | Mean Kurs Akhir (IDR) | SD Kurs Akhir (IDR) |
|---|---|---|---|---|
| Skenario 1 | 1.000 | 0.30 | 17.197 | 919 |
| Skenario 2 | 5.000 | 0.60 | 17.212 | 879 |
| Skenario 3 | 10.000 | 1.41 | 17.218 | 865 |
# Simpan semua hasil simulasi ke RDS
saveRDS(list(
sim_1000 = sim_1000,
sim_5000 = sim_5000,
sim_10000 = sim_10000,
S0 = S0,
mu = mu_hat,
sigma = sigma_hat,
horizon = horizon_hari,
tanggal_S0 = T0
), "hasil_simulasi.rds")
cat("✓ Hasil simulasi disimpan ke: hasil_simulasi.rds\n")## ✓ Hasil simulasi disimpan ke: hasil_simulasi.rds
## Berisi: sim_1000, sim_5000, sim_10000, S0, mu, sigma, horizon
| Sub-Bagian | Aktivitas | Output |
|---|---|---|
| Bagian 5 - Estimasi Parameter GBM | ||
| 5.1 | Estimasi mu dan sigma dari log-return historis | mu_hat, sigma_hat |
| 5.2 | Tabel parameter GBM lengkap | Tabel 5.1 |
| 5.3 | Penentuan horizon simulasi (252 hari) | horizon = 252 hari, dt = 1 |
| Bagian 6 - Simulasi Monte Carlo | ||
| 6.1 | Definisi fungsi simulasi GBM diskrit | Fungsi simulasi_gbm() |
| 6.2 | Simulasi 1.000 iterasi | Matrix sim_1000 (253 x 1.000) |
| 6.3 | Simulasi 5.000 iterasi | Matrix sim_5000 (253 x 5.000) |
| 6.4 | Simulasi 10.000 iterasi | Matrix sim_10000 (253 x 10.000) |
#Tabel Parameter GBM
library(knitr)
library(kableExtra)
# Membuat dataframe parameter berdasarkan output kalkulasi data aktual
df_param_gbm <- data.frame(
Parameter = c("Kurs Awal Aktual", "Tren Pertumbuhan (Drift)", "Fluktuasi Acak (Volatilitas)", "Horizon Waktu Proyeksi"),
Notasi = c("S0", "mu", "sigma", "T"),
Nilai_Harian = c("Rp 16.420,00", "0,000129", "0,003667", "252 Hari Kerja"),
Nilai_Tahunan = c("-", "0,032506 (3,25%)", "0,058209 (5,82%)", "1 Tahun Kalender")
)
# Membuat visualisasi tabel profesional dengan kableExtra
df_param_gbm %>%
kable(
col.names = c("Nama Parameter", "Notasi Matematis", "Skala Harian", "Skala Tahunan (Annualized)"),
align = c("l", "c", "r", "r"),
caption = "Tabel 3.3: Parameter Model Stokastik Geometric Brownian Motion (GBM)"
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center"
) %>%
row_spec(0, bold = TRUE, color = "white", background = "#00b4d8") %>%
column_spec(1, bold = TRUE) %>%
column_spec(2, italic = TRUE)| Nama Parameter | Notasi Matematis | Skala Harian | Skala Tahunan (Annualized) |
|---|---|---|---|
| Kurs Awal Aktual | S0 | Rp 16.420,00 |
|
| Tren Pertumbuhan (Drift) | mu | 0,000129 | 0,032506 (3,25%) |
| Fluktuasi Acak (Volatilitas) | sigma | 0,003667 | 0,058209 (5,82%) |
| Horizon Waktu Proyeksi | T | 252 Hari Kerja | 1 Tahun Kalender |
Dokumen ini merupakan bagian dari seri analisis kurs USD/IDR menggunakan pendekatan Geometric Brownian Motion dan Simulasi Monte Carlo.
sessionInfo()
## R version 4.5.1 (2025-06-13 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26200)
##
## Matrix products: default
## LAPACK version 3.12.1
##
## locale:
## [1] LC_COLLATE=English_United States.utf8
## [2] LC_CTYPE=English_United States.utf8
## [3] LC_MONETARY=English_United States.utf8
## [4] LC_NUMERIC=C
## [5] LC_TIME=English_United States.utf8
##
## time zone: Asia/Jakarta
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] kableExtra_1.4.0 knitr_1.51 lubridate_1.9.4 ggplot2_4.0.2
## [5] dplyr_1.2.0
##
## loaded via a namespace (and not attached):
## [1] gtable_0.3.6 jsonlite_2.0.0 compiler_4.5.1 tidyselect_1.2.1
## [5] xml2_1.5.2 stringr_1.6.0 jquerylib_0.1.4 textshaping_1.0.5
## [9] systemfonts_1.3.2 scales_1.4.0 yaml_2.3.12 fastmap_1.2.0
## [13] R6_2.6.1 generics_0.1.4 tibble_3.3.0 svglite_2.2.2
## [17] bslib_0.10.0 pillar_1.11.1 RColorBrewer_1.1-3 rlang_1.1.7
## [21] stringi_1.8.7 cachem_1.1.0 xfun_0.56 sass_0.4.10
## [25] S7_0.2.1 otel_0.2.0 viridisLite_0.4.2 timechange_0.3.0
## [29] cli_3.6.5 withr_3.0.2 magrittr_2.0.4 digest_0.6.38
## [33] grid_4.5.1 rstudioapi_0.18.0 lifecycle_1.0.5 vctrs_0.7.1
## [37] evaluate_1.0.5 glue_1.8.0 farver_2.1.2 rmarkdown_2.30
## [41] tools_4.5.1 pkgconfig_2.0.3 htmltools_0.5.9