| Kontak | \(\downarrow\) |
| naftaligunawan@gmail.com | |
| https://www.instagram.com/nbrigittag/ | |
| RPubs | https://rpubs.com/naftalibrigitta/ |
| Nama | Naftali Brigitta Gunawan |
| NIM | 20214920002 |
Pendahuluan
Dalam praktik ini, penulis memilih 5 saham berikut untuk diolah datanya, antara lain:
- PT XL Axiata Tbk (EXCL.JK)
- PT Telekomunikasi Indonesia Tbk (TLKM.JK)
- PT Indosat Ooredoo Hutchison Tbk (ISAT.JK)
- PT Smartfren Telecom Tbk (FREN.JK)
- PT Wijaya Karya (Persero) Tbk (WIKA.JK)
Library yang dibutuhkan
Library adalah sebuah packages yang dibutuhkan untuk menjalankan suatu koding di R Studio, karena tanpa menjalani library, koding tidak akan berjalan.
pacman::p_load(tidyverse,
tidyquant,
tidyr,
DT,
timetk,
forcats,
plotly,
timetk,
rmdformats)
Grafik Market Saham dari awal tahun 2023
Di bawah ini merupakan koding untuk melihat grafik pertumbuhan market saham dari 1 Januari 2023 hinga hari ini, adalah sebagai berikut:
stock <- c('ISAT.JK', 'TLKM.JK', 'EXCL.JK', 'WIKA.JK','FREN.JK')
data_harga <- tq_get(stock,
from = '2023-01-01',
to = Sys.Date(),
get = 'stock.prices')
data_harga %>%
plot_ly(x = ~date,
type = 'candlestick',
open = ~open,
close = ~close,
high = ~high,
low = ~low) %>%
layout(title = 'Harga 5 Stock Saham Tahun 2023',
xaxis = list(rangeslider = list(visible = F)))
Hasil Output: Grafik atau plot di atas merupakan grafik pertumbuhan market saham dari 1 Januari 2023 hingga hari ini.
Proses Optimasi
Import Data
stock <- c('ISAT.JK', 'TLKM.JK', 'EXCL.JK', 'WIKA.JK','FREN.JK')
data_harga <- tq_get(stock,
from = '2023-01-01',
to = Sys.Date(),
get = 'stock.prices')
data_harga
Hasil Output: Ada 1.145 data output dari 5 saham yang dipilih dengan nilai jual tertinggi, terendah, hingga volume terdapat di tabel tersebut.
Return Saham
Return atau pengembalian saham akan kita hitung menggunakan pengembalian logaritmik, sebagai berikut:
return_saham <- data_harga %>%
group_by(symbol) %>%
tq_transmute(select = adjusted,
mutate_fun = periodReturn,
period = 'daily',
col_rename = 'ret',
type = 'log')
datatable(return_saham)
Selanjutnya kita akan menggunakan fungsi spread untuk mengubah format menjadi format yang lebar. Fungsi xts() juga kita gunakan untuk membuat data kita menjadi time series
rerataan_return <- return_saham %>% # Rata-rata pengembalian portofolio saham
spread(symbol, value = ret) %>%
tk_xts()
datatable(rerataan_return)
Matriks Kovariansi
Menghitung matriks kovariansi untuk semua stok saham dengan mengalikan dengan 365 dalam format tahunan, sebagai berikut:
kov_metriks <- cov(rerataan_return) * 252
kov_metriks
## EXCL.JK FREN.JK ISAT.JK TLKM.JK WIKA.JK
## EXCL.JK 0.13308319 0.018311700 0.0254724800 0.0119174219 0.0254861155
## FREN.JK 0.01831170 0.123048556 0.0169913063 0.0078693332 0.0250394305
## ISAT.JK 0.02547248 0.016991306 0.0943237803 0.0009402123 0.0003919693
## TLKM.JK 0.01191742 0.007869333 0.0009402123 0.0415521356 -0.0023561570
## WIKA.JK 0.02548612 0.025039430 0.0003919693 -0.0023561570 0.3325012856
Hasil Output: Mengapa dikalikan dengan 252 hari? Karena dalam satu tahun, biasanya hari kerja berlaku 252 hari (karena ada hari libur dll)
Rata-rata pengembalian portofolio saham
Menghitung rata-rata pengembalian harian untuk setiap aset yang telah dipilih, sebagai berikut:
rerata_oi <- colMeans(rerataan_return)
rerata_oi
## EXCL.JK FREN.JK ISAT.JK TLKM.JK WIKA.JK
## -0.0004275715 -0.0012780332 0.0021202456 0.0003157814 -0.0061914529
Hasil Output: Pada hasil di atas dapat dilihat bahwa rata-rata nilai return paling tinggi adalah saham ISAT atau Indosat, kemudian di susul oleh TLKM atau Telkomsel. Sebaliknya, saham EXCL atau XL mendapat nilai paling rendah dibandingkan dengan 4 saham lainnya.
Penerapan Metode Portofolio
Sekarang kita akan menerapkan metode portofolio untuk memperhitungkan pengembalian dan risiko portofolio (standard deviasi). Dibawah ini merupakan langkah-langkah pada satu portofolio, antara lain:
- Bobot acak
- Rata-rata pengembalian aset
- Risiko portofolio
- Bobot portofolio
Membuat bobot acak
Penulis ingin membuat bobot secara acak, sebagai berikut:
# membuat bobot acak
acak <- runif(n = length(data_harga))
acak <- acak/sum(acak)
Rata-rata pengembalian aset
Penulis ingin menghitung rata-rata pengembalian aset, sebagai berikut:
# rata-rata pengembalian aset
port_returns <- (sum(acak * rerata_oi) + 1)^252 - 1
port_returns
## [1] -0.3406403
Hasil Output: Rata-rata pengembalian aset -0.3744835 artinya investasi anda rata-rata rugi sekitar 37.45% setahun
Risiko portofolio
Penulis ingin menghitung risiko portofolio, sebagai berikut:
# risiko portofolio
# Assuming you have 5 stocks
acak <- runif(5)
acak <- acak / sum(acak)
# Convert acak to a matrix or one-column vector if necessary
acak_matrix <- matrix(acak, nrow = 5, ncol = 1)
# Calculate portfolio risk
port_risk <- sqrt(t(acak_matrix) %*% (kov_metriks %*% acak_matrix))
port_risk
## [,1]
## [1,] 0.2673145
Hasil Output: Nilai 0.2243255 ini menunjukkan tingkat risiko yang sedang, yang cukup umum untuk portofolio saham. Semakin tinggi angkanya, semakin besar kemungkinan nilai investasi Anda naik turun secara signifikan.
Bobot portofolio sharpe ratio
Penulis ingin menghitung bobot portofolio sharpe ratio, sebagai berikut:
# bobot portofolio sharpe ratio
sharpe_ratio <- port_returns/port_risk
sharpe_ratio
## [,1]
## [1,] -1.274306
Hasil Output: Nilai Sharpe ratio -1.663697 itu artinya portofolio anda performanya kurang bagus, rugi lebih besar dibanding dengan risikonya.
Membentuk protofolio secara acak
Proses pembentukan protfolio secara acak dengan simulasi 5000 kali untuk memastikan signifikansinya secara statistik, sebagai berikut:
num_port <- 5000
all_wts <- matrix(nrow = num_port, ncol = length(data_harga))
port_returns <- vector('numeric', length = num_port)
port_risk <- vector('numeric', length = num_port)
sharpe_ratio <- vector('numeric', length = num_port)
Lalu jalankan loop sebanyak 5000 kali, sebagai berikut:
# Number of portfolios to simulate
num_portfolios <- length(port_returns)
# Initialize all_wts with the correct dimensions
all_wts <- matrix(nrow = num_portfolios, ncol = 5)
for (i in seq_along(port_returns)) {
# Generate random weights for 5 stocks
acak <- runif(5)
acak <- acak/sum(acak)
all_wts[i,] <- acak
# Calculate portfolio return
port_ret <- sum(acak * rerata_oi)
port_ret <- ((port_ret + 1)^252) - 1
port_returns[i] <- port_ret
# Calculate portfolio risk
port_sd <- sqrt(t(acak) %*% (kov_metriks %*% acak))
port_risk[i] <- port_sd
# Calculate Sharpe Ratio
sr <- port_ret/port_sd
sharpe_ratio[i] <- sr
}
Lalu membuat tabel data untuk menyimpan semua nilai nya, sebagai berikut:
portfolio_values <- tibble(Return = port_returns,
Risk = port_risk,
SharpeRatio = sharpe_ratio)
all_wts <- tk_tbl(all_wts)
colnames(all_wts) <- colnames(rerataan_return)
portfolio_values <- tk_tbl(cbind(all_wts, portfolio_values))
datatable(portfolio_values)
Hasil Output: Penulis telah berhasil menentukan bobot untuk setiap aset dengan mengukur risiko dan pengembalian, serta menghitung sharpe_ratio dari setiap portofolio. Langkah berikutnya adalah mengidentifikasi portofolio yang paling optimal, yaitu yang memiliki varian minimum dan nilai Sharpe ratio tertinggi, untuk memaksimalkan efisiensi investasi.
Sekarang kita akan menghitung variansi minimum, sebagai berikut:
Variansi minimum
library(forcats) # menggunakan fungsi `fct_reorder`
# Minumum Variansi
min_var <- portfolio_values[which.min(portfolio_values$Risk),]
min_var
p <- min_var %>%
gather(EXCL.JK:WIKA.JK, key = Asset,
value = Weights) %>%
mutate(Asset = as.factor(Asset)) %>%
ggplot(aes(x = fct_reorder(Asset,Weights), y = Weights, fill = Asset)) +
geom_bar(stat = 'identity') +
theme_minimal() +
labs(x = 'Aset',
y = 'Bobot',
title = "Bobot Portofolio dengan Variansi Minimum") +
scale_y_continuous(labels = scales::percent) +
theme(legend.position="none")
ggplotly(p)
Hasil Output: Dari hasil bagan di atas, portofolio varian minimum tidak memiliki alokasi untuk WIKA dan XL sangat sedikit. Mayoritas protofolio dlimpahkan investasinya ke saham Indosat dan Telkomsel.
# Maksimum Sharpe Ratio
max_sr <- portfolio_values[which.max(portfolio_values$SharpeRatio),]
p <- max_sr %>%
gather(EXCL.JK:WIKA.JK, key = Asset,
value = Weights) %>%
mutate(Asset = as.factor(Asset)) %>%
ggplot(aes(x = fct_reorder(Asset,Weights), y = Weights, fill = Asset)) +
geom_bar(stat = 'identity') +
theme_minimal() +
labs(x = 'Aset',
y = 'Bobot',
title = "Bobot Portofolio Tangensi (Maksimum Sharpe Ratio)") +
scale_y_continuous(labels = scales::percent)+
theme(legend.position="none")
ggplotly(p)
Hasil Output: Dari hasil bagan di atas, portofolio dengan rasio sharpe tertinggi di raih oleh Indosat, kemudian di susul oleh Telkomsel dan XL. Portofolio dengan sharpe terendah lagi-lagi dipegang oleh WIKA dan ditemani oleh Smartfren.
Batas Efisien Portofolio
Plot semua portofolio acak dan akan di visualisasikan sesuai dengan batas efisien nya, sebagai berikut:
p <- portfolio_values %>%
ggplot(aes(x = Risk, y = Return, color = SharpeRatio)) +
geom_point() +
scale_color_gradient(low = "#BA292E", high = "#3149FF") +
theme_classic() +
scale_y_continuous(labels = scales::percent) +
scale_x_continuous(labels = scales::percent) +
labs(x = 'Risiko Tahunan',
y = 'Pengembalian Tahunan',
title = "Optimasi Portofolio & Perbatasan yang Efisien") +
geom_point(aes(x = Risk, y = Return), data = min_var, color = 'yellow') +
geom_point(aes(x = Risk, y = Return), data = max_sr, color = 'yellow') +
annotate('text', x = 0.31, y = 0.31, label = "Portofolio Tangensi") +
annotate('text', x = 0.24, y = 0.11, label = "Portofolio Varians minimum") +
annotate(geom = 'segment', x = 0.3023, xend = 0.3023, y = 0.23,
yend = 0.29, color = 'red', arrow = arrow(type = "open")) +
annotate(geom = 'segment', x = 0.25, xend = 0.25, y = 0.015,
yend = 0.10, color = 'red', arrow = arrow(type = "open"))
ggplotly(p)