Pendahuluan
Dalam praktik ini, penulis memilih 5 saham berikut untuk diolah datanya, antara lain:
- Kalbe Farma Tbk (KLBF.JK)
- Indofood CBP Sukses Makmur Tbk (ICBP.JK)
- Indofood Sukses Makmur Tbk (INDF.JK)
- Industri Jamu dan Farmasi Sido Muncul Tbk (SIDO.JK)
- unilever INDONESIA (Persero) Tbk (UNVR.JK)
LibrarY
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('KLBF.JK', 'ICBP.JK', 'INDF.JK', 'SIDO.JK','UNVR.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('KLBF.JK', 'ICBP.JK', 'INDF.JK', 'SIDO.JK','UNVR.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
## ICBP.JK INDF.JK KLBF.JK SIDO.JK UNVR.JK
## ICBP.JK 0.062584405 0.011496445 0.006946459 0.006922401 0.011291524
## INDF.JK 0.011496445 0.038330515 0.007618546 0.002528558 0.008781774
## KLBF.JK 0.006946459 0.007618546 0.099701736 0.010627966 0.021147041
## SIDO.JK 0.006922401 0.002528558 0.010627966 0.093157173 0.013345334
## UNVR.JK 0.011291524 0.008781774 0.021147041 0.013345334 0.070028165
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
## ICBP.JK INDF.JK KLBF.JK SIDO.JK UNVR.JK
## 0.0002474151 -0.0001443074 -0.0008493001 -0.0010356133 -0.0010540967
Hasil Output: Pada hasil di atas dapat dilihat bahwa rata-rata nilai return paling tinggi adalah saham ICBP atau Indofood CBP Sukses Makmur Sebaliknya, saham INDF atau Indofood Sukses Makmur 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.0928083
Hasil Output: Rata-rata pengembalian aset -0.1125351 artinya investasi anda rata-rata RUGI sebesar 11.25% 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.1642992
Hasil Output: Nilai 0.1724537 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.5648738
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(ICBP.JK:UNVR.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 KLBF dan SIDO sangat sedikit. Mayoritas protofolio dlimpahkan investasinya ke saham ICBP dan INDF
# Maksimum Sharpe Ratio
max_sr <- portfolio_values[which.max(portfolio_values$SharpeRatio),]
p <- max_sr %>%
gather(ICBP.JK:UNVR.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 ICBP,, kemudian di susul oleh INDF dan UNVR. Portofolio dengan sharpe terendah adalah SIDO
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 = "#314FDD") +
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)