UAS Optimasi

5 data saham pada Bursa Efek Indonesia yang termaksud pada saham LQ45

Naftali Brigitta Gunawan

December 14, 2023


Kontak \(\downarrow\)
Email
Instagram 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)