Optimasi

Tugas 2


Kontak : \(\downarrow\)
Email
Instagram yyosia
RPubs https://rpubs.com/yosia/

Optimalisasi Portofolio

Import Data

ITMG.JK = PT Indo Tambangraya Megah Tbk

BBCA.JK = PT Bank Central Asia Tbk

BRIS.JK = PT Bank Syariah Indonesia Tbk

BIPI.JK = PT Astrindo Nusantara Infrastruktur Tbk

BUMI.JK = PT Bumi Resources Tbk

library(tidyquant) 
library(plotly) 
library(timetk)
tick <- c('ITMG.JK', 'BBCA.JK', 'BRIS.JK', 'BIPI.JK', 'BUMI.JK')


price_data <- tq_get(tick,
                     from = '2020-01-01',
                     to   = '2022-12-09',
                     get  = 'stock.prices')

head(price_data)

Return

Selanjutnya menghitung pengembalian (Return) harian untuk saham-saham ini dengan menggunakan pengembalian logaritmik (untuk memastikan data stasioner).

log_ret_tidy <- price_data %>%
  group_by(symbol) %>%
  tq_transmute(select     = adjusted,
               mutate_fun = periodReturn,
               period     = 'daily',
               col_rename = 'ret',
               type       = 'log')

library(DT) 
datatable(log_ret_tidy)

Selanjutnya akan digunakan fungsi spread() untuk mengubahnya menjadi format lebar. dan kita juga akan mengubahnya menjadi objek time series menggunakan fungsi xts() .

library(tidyr)

log_ret_xts <- log_ret_tidy %>%
  spread(symbol, value = ret) %>%
  tk_xts()
## Warning: Non-numeric columns being dropped: date
## Using column `date` for date_var.
datatable(log_ret_xts)

Rata-rata Pengembalian

Menghitung rata-rata pengembalian harian untuk setiap aset.

mean_ret <- colMeans(log_ret_xts)
print ( round (mean_ret, 4))
## BBCA.JK BIPI.JK BRIS.JK BUMI.JK ITMG.JK 
##  0.0004  0.0018  0.0019  0.0013  0.0023

Matriks Kovariansi

Selanjutnya, menghitung matriks kovarians untuk semua stok dengan mengalikannya dengan 252 dalam format tahunan.

cov_mat <- cov(log_ret_xts) * 252
print(round(cov_mat,4))
##         BBCA.JK BIPI.JK BRIS.JK BUMI.JK ITMG.JK
## BBCA.JK  0.0831  0.0034  0.0590  0.0094  0.0456
## BIPI.JK  0.0034  0.2165 -0.0006  0.0427  0.0244
## BRIS.JK  0.0590 -0.0006  0.4782  0.0300  0.0743
## BUMI.JK  0.0094  0.0427  0.0300  0.4120  0.0734
## ITMG.JK  0.0456  0.0244  0.0743  0.0734  0.2240

Penerapan Metode Portofolio

  • Bobot acak

  • Rata-rata pengembalian aset

  • Risiko portofolio

  • Bobot portofolio

wts <- runif(n = length(tick))
wts <- wts/sum(wts)

port_returns <- (sum(wts * mean_ret) + 1)^252 - 1
port_risk <- sqrt(t(wts) %*% (cov_mat %*% wts))
sharpe_ratio <- port_returns/port_risk

Selanjutnya dilakukan proses pembetukan portofolio secara acak dengan simulasi 5000 kali untuk memastikan signifikansinya secara statistik. Persiapkan vektor kosong untuk masing-masing langkah diatas:

num_port <- 5000

all_wts <- matrix(nrow = num_port, ncol = length(tick))
port_returns <- vector('numeric', length = num_port)
port_risk <- vector('numeric', length = num_port)
sharpe_ratio <- vector('numeric', length = num_port)

Selanjutnya mari kita jalankan for loop 5000 kali.

for (i in seq_along(port_returns)) {
  
  wts <- runif(length(tick))
  wts <- wts/sum(wts)
  
  all_wts[i,] <- wts
  
  
  port_ret <- sum(wts * mean_ret)
  port_ret <- ((port_ret + 1)^252) - 1
  
  port_returns[i] <- port_ret
  
  
  port_sd <- sqrt(t(wts) %*% (cov_mat  %*% wts))
  port_risk[i] <- port_sd
  
  sr <- port_ret/port_sd
  sharpe_ratio[i] <- sr
  
}

Selanjutnya, membuat tabel data untuk menyimpan semua nilai secara bersamaan.

portfolio_values <- tibble(Return = port_returns,
                             Risk = port_risk,
                      SharpeRatio = sharpe_ratio)


all_wts <- tk_tbl(all_wts)
## Warning in tk_tbl.data.frame(as.data.frame(data), preserve_index,
## rename_index, : Warning: No index to preserve. Object otherwise converted to
## tibble successfully.
colnames(all_wts) <- colnames(log_ret_xts)

portfolio_values <- tk_tbl(cbind(all_wts, portfolio_values))
## Warning in tk_tbl.data.frame(cbind(all_wts, portfolio_values)): Warning: No
## index to preserve. Object otherwise converted to tibble successfully.
datatable(portfolio_values)

Sekarang, kita sudah memiliki bobot di setiap aset dengan risiko dan pengembalian bersama dengan Sharpe ratio dari setiap portofolio. Selanjutnya, mari kita lihat portofolio yang paling penting dengan varians minimum dan juga Sharpe ratio tertinggi.

Variansi Minimum

library(forcats)

min_var <- portfolio_values[which.min(portfolio_values$Risk),]

p <- min_var %>%
  gather(BBCA.JK:ITMG.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)

Seperti yang dapat kita amati, portofolio Varian minimum tidak memiliki alokasi untuk ITMG.JK dan BRIS.JK sangat sedikit. Mayoritas portofolio diinvestasikan di saham BUMI.JK, BIPI.JK & BBCA.JK.

Portofolio Tangensi

Selanjutnya, mari kita lihat portofolio tangency atau portofolio dengan Sharpe ratio tertinggi.

max_sr <- portfolio_values[which.max(portfolio_values$SharpeRatio),]

p <- max_sr %>%
  gather(BBCA.JK:ITMG.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)

Tidak mengherankan, portofolio dengan rasio Sharpe tertinggi hanya memiliki sedikit investasi di BBCA.JK & BUMI.JK. Portofolio ini sebenarnya memiliki sebagian besar aset yang diinvestasikan di BRIS.JK, BIPI.JK, ITMG.JK. Ketiga saham tersebut berkinerja terbaik dalam satu dekade.

Batas Efisien Portofolio

Akhirnya mari kita plot semua portofolio acak dan memvisualisasikan batas efisien.

p <- portfolio_values %>%
  ggplot(aes(x = Risk, y = Return, color = SharpeRatio)) +
  geom_point() +
  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 = 'red') +
  geom_point(aes(x = Risk,y = Return), data = max_sr, color = 'red') +
  annotate('text', x = 0.329, y = 0.78, label = "Portofolio Tangensi") +
  annotate('text', x = 0.287, y = 0.429, label = "Portofolio Varians minimum") +
  annotate(geom = 'segment', x = 0.3163, xend = 0.3163,  y = 0.659, 
           yend = 0.74, color = 'red', arrow = arrow(type = "open")) +
  annotate(geom = 'segment', x = 0.2383, xend = 0.2383,  y = 0.328, 
           yend = 0.40, color = 'red', arrow = arrow(type = "open"))
  

ggplotly(p)