UAS Optimasi

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

JEREMI HERYANDI SAUDI

December 20, 2023

Pendahuluan

Dalam praktik ini, penulis memilih 5 saham berikut untuk diolah datanya, antara lain:


  • BANK CENTRAL ASIA Tbk (BBCA.JK)
  • BANK RAKYAT INDONESIA Tbk (BBRI.JK)
  • BANK TABUNGAN NEGARA Tbk (BBTN.JK)
    *BANK MANDIRI Tbk (BMRI.JK)
  • BANK SYARIAH INDONESIA (Persero) Tbk (BRIS.JK)

LibrarY

pacman::p_load(tidyverse,
               tidyquant,
               tidyr,
               DT,
               timetk,
               forcats,
               plotly,
               timetk,
               rmdformats)
## Error in download.file(url, destfile, method, mode = "wb", ...) : 
##   download from 'http://cran.rstudio.com/bin/windows/contrib/4.2/clock_0.7.0.zip' failed
## package 'shape' successfully unpacked and MD5 sums checked
## package 'future.apply' successfully unpacked and MD5 sums checked
## package 'progressr' successfully unpacked and MD5 sums checked
## package 'SQUAREM' successfully unpacked and MD5 sums checked
## package 'diagram' successfully unpacked and MD5 sums checked
## package 'lava' successfully unpacked and MD5 sums checked
## package 'prodlim' successfully unpacked and MD5 sums checked
## package 'globals' successfully unpacked and MD5 sums checked
## package 'listenv' successfully unpacked and MD5 sums checked
## package 'parallelly' successfully unpacked and MD5 sums checked
## package 'gower' successfully unpacked and MD5 sums checked
## package 'hardhat' successfully unpacked and MD5 sums checked
## package 'ipred' successfully unpacked and MD5 sums checked
## package 'furrr' successfully unpacked and MD5 sums checked
## package 'vctrs' successfully unpacked and MD5 sums checked
## package 'warp' successfully unpacked and MD5 sums checked
## package 'BH' successfully unpacked and MD5 sums checked
## package 'fracdiff' successfully unpacked and MD5 sums checked
## package 'lmtest' successfully unpacked and MD5 sums checked
## package 'tseries' successfully unpacked and MD5 sums checked
## package 'urca' successfully unpacked and MD5 sums checked
## package 'RcppRoll' successfully unpacked and MD5 sums checked
## package 'future' successfully unpacked and MD5 sums checked
## package 'quadprog' successfully unpacked and MD5 sums checked
## package 'recipes' successfully unpacked and MD5 sums checked
## package 'rsample' successfully unpacked and MD5 sums checked
## package 'padr' successfully unpacked and MD5 sums checked
## package 'slider' successfully unpacked and MD5 sums checked
## package 'anytime' successfully unpacked and MD5 sums checked
## package 'forecast' successfully unpacked and MD5 sums checked
## package 'tsfeatures' successfully unpacked and MD5 sums checked
## package 'PerformanceAnalytics' successfully unpacked and MD5 sums checked
## package 'Quandl' successfully unpacked and MD5 sums checked
## package 'riingo' successfully unpacked and MD5 sums checked
## package 'alphavantager' successfully unpacked and MD5 sums checked
## package 'timetk' successfully unpacked and MD5 sums checked
## package 'timeDate' successfully unpacked and MD5 sums checked
## package 'tidyquant' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\e7ils\AppData\Local\Temp\Rtmp8E1kCZ\downloaded_packages

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('BBCA.JK', 'BBRI.JK', 'BBTN.JK', 'BMRI.JK','BRIS.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('BBCA.JK', 'BBRI.JK', 'BBTN.JK', 'BMRI.JK','BRIS.JK')


data_harga <- tq_get(stock,
                     from = '2023-01-01',
                     to   = Sys.Date(),
                     get  = 'stock.prices')

data_harga

Hasil Output: Ada 1.165 data output dari 5 saham yang dipilih dengan nilai jual tertinggi, terendah, hingga volume terdapat di tabel tersebut.

Return Saham

return_saham <- data_harga %>%
  group_by(symbol) %>%
  tq_transmute(select     = adjusted,
               mutate_fun = periodReturn,
               period     = 'daily',
               col_rename = 'ret',
               type       = 'log')
 
datatable(return_saham)
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
##             BBCA.JK    BBRI.JK    BBTN.JK     BMRI.JK      BRIS.JK
## BBCA.JK 0.032042411 0.01854604 0.01370260  0.02782160  0.007834745
## BBRI.JK 0.018546036 0.04403661 0.01610801  0.01487984  0.014765971
## BBTN.JK 0.013702602 0.01610801 0.05455669  0.02747605  0.018433325
## BMRI.JK 0.027821603 0.01487984 0.02747605  1.06396005 -0.030063772
## BRIS.JK 0.007834745 0.01476597 0.01843332 -0.03006377  0.140139749

Hasil Output: Dikalikan 252 hari Karena dalam satu tahun, biasanya hari kerja berlaku 252 hari (karena ada hari libur dll)

Rata-rata pengembalian portofolio saham

rerata_oi <- colMeans(rerataan_return)
rerata_oi
##       BBCA.JK       BBRI.JK       BBTN.JK       BMRI.JK       BRIS.JK 
##  0.0004431038  0.0008220505 -0.0002011599  0.0010322179  0.0012366016

Hasil Output: Pada hasil di atas dapat dilihat bahwa rata-rata nilai return paling tinggi adalah saham BRIS atau BANK SYARIAH INDONESIA, kemudian di susul oleh BMRI atau BANK MANDIRI. Sebaliknya, saham BBTN atau BANK TABUNGAN NEGARA mendapat nilai paling rendah dibandingkan dengan 4 saham lainnya.

Penerapan Metode Portofolio


  • Bobot acak
  • Rata-rata pengembalian aset
  • Risiko portofolio
  • Bobot portofolio

Membuat bobot acak

# 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.141308

Hasil Output: Rata-rata pengembalian aset 0.1721148 artinya investasi anda rata-rata sebesar 17.21% 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.3227515

Hasil Output: Nilai 0.2212434 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,] 0.437823

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(BBCA.JK:BRIS.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 BMRI dan BRIS sangat sedikit. Mayoritas protofolio dlimpahkan investasinya ke saham BBCA dan BBTN

# Maksimum Sharpe Ratio
max_sr <- portfolio_values[which.max(portfolio_values$SharpeRatio),]

p <- max_sr %>%
  gather(BBCA.JK:BRIS.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 BBRI,, kemudian di susul oleh BRIS dan BMRI. Portofolio dengan sharpe terendah adalah BBCA.

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)