library(quantmod)
## Loading required package: xts
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
## Loading required package: TTR
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
symbols <- c("BBCA.JK", "UNVR.JK", "BBNI.JK", "PGAS.JK", "AALI.JK")
getSymbols(symbols, src = "yahoo", from = "2020-01-01", to = "2024-01-01")
## [1] "BBCA.JK" "UNVR.JK" "BBNI.JK" "PGAS.JK" "AALI.JK"
# Define the function to calculate daily returns
calculate_returns <- function(prices) {
# Calculate the percentage change in prices
returns <- diff(prices) / lag(prices, 1)
return(returns)
}
# Memanggil fungsi calculate_returns() untuk setiap seri harga saham
BBCA_returns <- calculate_returns(Cl(BBCA.JK))
UNVR_returns <- calculate_returns(Cl(UNVR.JK))
BBNI_returns <- calculate_returns(Cl(BBNI.JK))
PGAS_returns <- calculate_returns(Cl(PGAS.JK))
AALI_returns <- calculate_returns(Cl(AALI.JK))
stock_returns <- do.call(merge, lapply(symbols, function(sym) calculate_returns(Cl(get(sym)))))
na.omit(stock_returns)
## BBCA.JK.Close UNVR.JK.Close BBNI.JK.Close PGAS.JK.Close
## 2020-01-03 0.0164424514 0.002923977 0.003215434 0.009345794
## 2020-01-06 -0.0095588235 -0.011661808 -0.022435897 -0.004629630
## 2020-01-07 0.0007423905 -0.002949853 -0.009836066 -0.023255814
## 2020-01-08 -0.0089020772 -0.014792899 -0.016556291 0.000000000
## 2020-01-09 0.0089820359 0.003003003 0.037037037 0.000000000
## 2020-01-10 -0.0022255193 -0.011976048 0.003246753 -0.009523810
## 2020-01-13 0.0029739777 0.018181818 0.006472492 0.004807692
## 2020-01-14 0.0185322461 0.008928571 0.009646302 0.000000000
## 2020-01-15 -0.0050946143 0.000000000 -0.022292994 -0.023923445
## 2020-01-16 0.0021945867 -0.005899705 0.003257329 -0.004901961
## ...
## 2023-12-14 0.0432276657 -0.014492754 0.033816425 0.009259259
## 2023-12-15 0.0193370166 0.029411765 -0.014018692 -0.009174312
## 2023-12-18 -0.0027100271 -0.025714286 -0.014218009 -0.013888889
## 2023-12-19 0.0054347826 0.005865103 0.000000000 0.028169014
## 2023-12-20 0.0054054054 0.008746356 0.000000000 0.009132420
## 2023-12-21 0.0026881720 0.002890173 -0.009615385 -0.004524887
## 2023-12-22 0.0000000000 0.000000000 0.019417476 0.000000000
## 2023-12-27 0.0053619303 0.000000000 0.004761905 0.000000000
## 2023-12-28 0.0026666667 0.020172911 0.014218009 0.027272727
## 2023-12-29 0.0000000000 -0.002824859 0.004672897 0.000000000
## AALI.JK.Close
## 2020-01-03 0.005347594
## 2020-01-06 -0.042553191
## 2020-01-07 -0.007407407
## 2020-01-08 -0.005597015
## 2020-01-09 0.039399625
## 2020-01-10 -0.012635379
## 2020-01-13 0.001828154
## 2020-01-14 -0.036496350
## 2020-01-15 -0.051136364
## 2020-01-16 0.011976048
## ...
## 2023-12-14 -0.003533569
## 2023-12-15 0.000000000
## 2023-12-18 -0.003546099
## 2023-12-19 0.007117438
## 2023-12-20 0.000000000
## 2023-12-21 -0.007067138
## 2023-12-22 0.000000000
## 2023-12-27 0.000000000
## 2023-12-28 0.003558719
## 2023-12-29 -0.003546099
meanret <- colMeans(stock_returns)
meanret <- as.numeric(meanret)
meanret
## [1] NA NA NA NA NA
# Menghitung matriks korelasi dari tingkat pengembalian
correlation_matrix <- cor(stock_returns, use = "complete.obs")
# Menampilkan matriks korelasi
print(correlation_matrix)
## BBCA.JK.Close UNVR.JK.Close BBNI.JK.Close PGAS.JK.Close
## BBCA.JK.Close 1.0000000 0.2959520 0.5718388 0.3551319
## UNVR.JK.Close 0.2959520 1.0000000 0.2663953 0.2139542
## BBNI.JK.Close 0.5718388 0.2663953 1.0000000 0.4877845
## PGAS.JK.Close 0.3551319 0.2139542 0.4877845 1.0000000
## AALI.JK.Close 0.3625702 0.2644401 0.4406279 0.4066985
## AALI.JK.Close
## BBCA.JK.Close 0.3625702
## UNVR.JK.Close 0.2644401
## BBNI.JK.Close 0.4406279
## PGAS.JK.Close 0.4066985
## AALI.JK.Close 1.0000000
# Install dan muat paket corrplot
library(corrplot)
## corrplot 0.92 loaded
# Visualisasi matriks korelasi
corrplot(correlation_matrix, method = "color")
corrplot(correlation_matrix, method = "number")
## f. Calculate the portfolio’s returns and standard deviation based on
equal weights for each stock.
library(PerformanceAnalytics)
##
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
equal_weights <- rep(1/length(symbols), length(symbols))
portfolio_returns <- Return.portfolio(stock_returns, weights = equal_weights)
## Warning in Return.portfolio(stock_returns, weights = equal_weights): NA's
## detected: filling NA's with zeros
portfolio_sd <- sqrt(sum(equal_weights^2 * apply(stock_returns, 1, sd)^2))
## Warning in equal_weights^2 * apply(stock_returns, 1, sd)^2: longer object
## length is not a multiple of shorter object length
div_ratio <- portfolio_sd / sqrt(sum(correlation_matrix * outer(equal_weights, equal_weights)))
objective_function <- function(weights) -sum(weights * colMeans(stock_returns))
constraints <- function(weights) sum(weights) - 1
library(quadprog)
library(Matrix)
# Example data (replace with your actual data)
expected_returns <- symbols # Expected returns for assets
cov_matrix <- matrix(correlation_matrix, nrow=5) # Covariance matrix
pdmat <- nearPD(correlation_matrix)
# Use the positive definite matrix for optimization
Matrix1 <- as.matrix(pdmat$mat)
Matrix2 <- rep(0, length(expected_returns))
Matrix3 <- cbind(rep(1, length(expected_returns)), diag(length(expected_returns)))
Matrix4 <- c(1, Matrix2)
# Solve quadratic programming problem
output <- solve.QP(Dmat = Matrix1, dvec = Matrix2, Amat = Matrix3, bvec = Matrix4, meq = 1)
# Optimal portfolio weights
optimal_weights <- output$solution
print(optimal_weights)
## [1] 0.18297122 0.29789158 0.09885815 0.22003204 0.20024701
Bobot portofolio optimal yang memaksimalkan return portofolio dengan memperhatikan matriks kovarians dan batasan adalah 0.18297122, 0.29789158, 0.09885815, 0.22003204, 0.20024701.
library(plotly)
## Loading required package: ggplot2
##
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
# Assuming optimal_weights is your vector of weights and symbols is your stock symbols
data_frame <- data.frame(Symbol = symbols, Weight = optimal_weights)
# Define a list of pastel colors
pastel_colors <- c('#08F1DD', '#ABF108', '#FFB61B', '#0EF88E', '#F1085E')
# Create the bar plot using plotly with custom pastel colors
plot_ly(data_frame, x = ~Symbol, y = ~Weight, type = 'bar',
marker = list(color = pastel_colors)) %>%
layout(title = "Optimal Weights",
xaxis = list(title = "Symbol"),
yaxis = list(title = "Weight"))
optimalisasi maksimal portofolionya adalah - AALI.JK = 0,200247 - BBCA.JK = 0,1829712 - BBNI.JK = 0,0988582 - PGAS.JK = 0,220032 - UNVR.JK = 0,2978916
# Calculate expected return of the portfolio
expected_return_portfolio <- sum(equal_weights * optimal_weights)
# Calculate portfolio volatility
portfolio_volatility <- sqrt(t(optimal_weights) %*% correlation_matrix %*% optimal_weights)
print(paste("Expected Return of the Portfolio:", expected_return_portfolio))
## [1] "Expected Return of the Portfolio: 0.2"
print(paste("Volatility of the Portfolio:", portfolio_volatility))
## [1] "Volatility of the Portfolio: 0.691670260990252"
jadi disimpulkan bahwa ekspetasi Pengembalian Portofolio sebesar 20% dan Volatilitas Portofolio sebesar 0.691670260990252
set.seed(123) # For reproducibility
# Parameters
n_policies <- 10000
n_years <- 13
mean_claims <- 0.3 # Average number of claims per policy per year
mean_claim_amount <- 1003 # Average claim amount
sd_claim_amount <- 2003 # Standard deviation of claim amount
# Initialize an empty data frame for the claims data
claims_data <- data.frame(policy_id = 1:n_policies)
# Generate claims data
for(year in 1:n_years) {
# Simulate number of claims for each policy for the year
num_claims <- rpois(n_policies, mean_claims)
# For each policy, simulate claim amounts and sum them
total_claims_amount <- sapply(num_claims, function(n) sum(rnorm(n, mean_claim_amount, sd_claim_amount)))
# Add the total claims amount for the year to the data frame
claims_data[paste("Year", year, sep = "_")] <- total_claims_amount
}
# View the first few rows of the claims data
head(claims_data)
## policy_id Year_1 Year_2 Year_3 Year_4 Year_5 Year_6
## 1 1 0.00000 -21.54231 0.0000 3673.0322 1907.779 0.0000
## 2 2 13.16972 2288.61773 3944.5866 0.0000 0.000 280.9027
## 3 3 0.00000 959.68322 0.0000 0.0000 0.000 939.5597
## 4 4 3261.56971 0.00000 0.0000 0.0000 0.000 0.0000
## 5 5 -1294.33995 0.00000 758.6653 -980.3451 0.000 0.0000
## 6 6 0.00000 1619.56698 0.0000 3461.1275 0.000 0.0000
## Year_7 Year_8 Year_9 Year_10 Year_11 Year_12 Year_13
## 1 0.0000 0.000 0.00 1109.1397 0.000 0.0000 0
## 2 883.1891 0.000 0.00 0.0000 -1127.416 1125.4423 0
## 3 0.0000 0.000 0.00 0.0000 0.000 0.0000 0
## 4 -158.4454 0.000 1562.65 319.8526 0.000 3189.2786 0
## 5 -175.9640 0.000 0.00 2910.7604 0.000 0.0000 0
## 6 0.0000 1401.443 0.00 0.0000 0.000 192.6661 0
# Parameters for the claim frequency distribution
mean_claims_frequency <- 0.1
# Generate claim frequencies for each policy for each year
for(year in 1:n_years) {
claim_frequencies <- rpois(n_policies, mean_claims_frequency)
# Add claim frequencies to the claims_data data frame
claims_data[paste("Claim_Freq_Year", year, sep = "_")] <- claim_frequencies
}
# View the first few rows to confirm claim frequencies are added
head(claims_data)
## policy_id Year_1 Year_2 Year_3 Year_4 Year_5 Year_6
## 1 1 0.00000 -21.54231 0.0000 3673.0322 1907.779 0.0000
## 2 2 13.16972 2288.61773 3944.5866 0.0000 0.000 280.9027
## 3 3 0.00000 959.68322 0.0000 0.0000 0.000 939.5597
## 4 4 3261.56971 0.00000 0.0000 0.0000 0.000 0.0000
## 5 5 -1294.33995 0.00000 758.6653 -980.3451 0.000 0.0000
## 6 6 0.00000 1619.56698 0.0000 3461.1275 0.000 0.0000
## Year_7 Year_8 Year_9 Year_10 Year_11 Year_12 Year_13 premiums
## 1 0.0000 0.000 0.00 1109.1397 0.000 0.0000 0 2621.033
## 2 883.1891 0.000 0.00 0.0000 -1127.416 1125.4423 0 1358.957
## 3 0.0000 0.000 0.00 0.0000 0.000 0.0000 0 1679.548
## 4 -158.4454 0.000 1562.65 319.8526 0.000 3189.2786 0 1496.055
## 5 -175.9640 0.000 0.00 2910.7604 0.000 0.0000 0 -1477.976
## 6 0.0000 1401.443 0.00 0.0000 0.000 192.6661 0 3547.261
## Claim_Freq_Year_1 Claim_Freq_Year_2 Claim_Freq_Year_3 Claim_Freq_Year_4
## 1 0 1 0 0
## 2 0 0 0 0
## 3 0 0 0 0
## 4 0 0 0 0
## 5 0 0 0 0
## 6 0 0 1 0
## Claim_Freq_Year_5 Claim_Freq_Year_6 Claim_Freq_Year_7 Claim_Freq_Year_8
## 1 0 0 0 0
## 2 0 1 1 0
## 3 0 0 1 1
## 4 0 0 0 0
## 5 0 0 0 0
## 6 0 0 0 0
## Claim_Freq_Year_9 Claim_Freq_Year_10 Claim_Freq_Year_11 Claim_Freq_Year_12
## 1 0 0 0 0
## 2 0 0 0 0
## 3 0 0 0 0
## 4 0 0 0 0
## 5 0 0 0 0
## 6 0 0 0 0
## Claim_Freq_Year_13
## 1 0
## 2 0
## 3 0
## 4 0
## 5 0
## 6 0
# Parameters for the claim amount distribution
mean_claim_amount <- 5003
sd_claim_amount <- 2003
# Assuming claims_data already contains claim frequencies for each year
# Simulate claim amounts for each policy and each year
for(year in 1:n_years) {
# Initialize a column for claim amounts for the year
claims_data[[paste("Claim_Amt_Year", year, sep = "_")]] <- NA
for(policy in 1:n_policies) {
# Number of claims for the policy in the year
num_claims <- claims_data[policy, paste("Claim_Freq_Year", year, sep = "_")]
# If there are claims, simulate claim amounts
if(num_claims > 0) {
claim_amounts <- rnorm(num_claims, mean_claim_amount, sd_claim_amount)
# Store the sum of claim amounts for the policy-year
claims_data[policy, paste("Claim_Amt_Year", year, sep = "_")] <- sum(claim_amounts)
} else {
# If no claims, set claim amount to 0
claims_data[policy, paste("Claim_Amt_Year", year, sep = "_")] <- 0
}
}
}
# View the first few rows to confirm claim amounts are added
head(claims_data)
## policy_id Year_1 Year_2 Year_3 Year_4 Year_5 Year_6
## 1 1 0.00000 -21.54231 0.0000 3673.0322 1907.779 0.0000
## 2 2 13.16972 2288.61773 3944.5866 0.0000 0.000 280.9027
## 3 3 0.00000 959.68322 0.0000 0.0000 0.000 939.5597
## 4 4 3261.56971 0.00000 0.0000 0.0000 0.000 0.0000
## 5 5 -1294.33995 0.00000 758.6653 -980.3451 0.000 0.0000
## 6 6 0.00000 1619.56698 0.0000 3461.1275 0.000 0.0000
## Year_7 Year_8 Year_9 Year_10 Year_11 Year_12 Year_13 premiums
## 1 0.0000 0.000 0.00 1109.1397 0.000 0.0000 0 2621.033
## 2 883.1891 0.000 0.00 0.0000 -1127.416 1125.4423 0 1358.957
## 3 0.0000 0.000 0.00 0.0000 0.000 0.0000 0 1679.548
## 4 -158.4454 0.000 1562.65 319.8526 0.000 3189.2786 0 1496.055
## 5 -175.9640 0.000 0.00 2910.7604 0.000 0.0000 0 -1477.976
## 6 0.0000 1401.443 0.00 0.0000 0.000 192.6661 0 3547.261
## Claim_Freq_Year_1 Claim_Freq_Year_2 Claim_Freq_Year_3 Claim_Freq_Year_4
## 1 0 1 0 0
## 2 0 0 0 0
## 3 0 0 0 0
## 4 0 0 0 0
## 5 0 0 0 0
## 6 0 0 1 0
## Claim_Freq_Year_5 Claim_Freq_Year_6 Claim_Freq_Year_7 Claim_Freq_Year_8
## 1 0 0 0 0
## 2 0 1 1 0
## 3 0 0 1 1
## 4 0 0 0 0
## 5 0 0 0 0
## 6 0 0 0 0
## Claim_Freq_Year_9 Claim_Freq_Year_10 Claim_Freq_Year_11 Claim_Freq_Year_12
## 1 0 0 0 0
## 2 0 0 0 0
## 3 0 0 0 0
## 4 0 0 0 0
## 5 0 0 0 0
## 6 0 0 0 0
## Claim_Freq_Year_13 Claim_Amt_Year_1 Claim_Amt_Year_2 Claim_Amt_Year_3
## 1 0 0 3761.039 0.000
## 2 0 0 0.000 0.000
## 3 0 0 0.000 0.000
## 4 0 0 0.000 0.000
## 5 0 0 0.000 0.000
## 6 0 0 0.000 5033.805
## Claim_Amt_Year_4 Claim_Amt_Year_5 Claim_Amt_Year_6 Claim_Amt_Year_7
## 1 0 0 0.000 0.000
## 2 0 0 4795.381 5080.491
## 3 0 0 0.000 6581.609
## 4 0 0 0.000 0.000
## 5 0 0 0.000 0.000
## 6 0 0 0.000 0.000
## Claim_Amt_Year_8 Claim_Amt_Year_9 Claim_Amt_Year_10 Claim_Amt_Year_11
## 1 0.000 0 0 0
## 2 0.000 0 0 0
## 3 6659.996 0 0 0
## 4 0.000 0 0 0
## 5 0.000 0 0 0
## 6 0.000 0 0 0
## Claim_Amt_Year_12 Claim_Amt_Year_13
## 1 0 0
## 2 0 0
## 3 0 0
## 4 0 0
## 5 0 0
## 6 0 0
hist(claims_data$loss_ratio, breaks = 50, main = "Histogram Ratios", xlab = "Loss Ratio")
# Calculate mean of loss ratios
mean_loss_ratio <- mean(claims_data$loss_ratio, na.rm = TRUE)
# Calculate median of loss ratios
median_loss_ratio <- median(claims_data$loss_ratio, na.rm = TRUE)
# Calculate 95th percentile of loss ratios
percentile_95_loss_ratio <- quantile(claims_data$loss_ratio, 0.95, na.rm = TRUE)
# Print summary statistics
cat("Rasio Kerugian Rata-Rata:", mean_loss_ratio, "\n")
## Rasio Kerugian Rata-Rata: 12.68774
cat("Median Rasio Kerugian:", median_loss_ratio, "\n")
## Median Rasio Kerugian: 0.6960554
cat("Persentil ke-95 Rasio Kerugian:", percentile_95_loss_ratio, "\n")
## Persentil ke-95 Rasio Kerugian: 25.3606
Rasio Kerugian Rata-Rata: 80.81482. Rasio kerugian menunjukkan seberapa banyak uang yang digunakan untuk klaim dibandingkan dengan seberapa banyak yang diperoleh dari premi.
Median Loss Ratio: 0.5484808. ini berarti setengah dari kebijakan memiliki rasio kerugian di bawah nilai ini dan setengahnya lagi memiliki rasio kerugian di atas nilai ini.secara umum, semakin rendah rasio kerugian, semakin baik bagi perusahaan asuransi karena menunjukkan bahwa klaim yang diajukan tidak signifikan dibandingkan dengan premi yang diterima. Jadi, jika standar industri atau tujuan perusahaan adalah untuk mempertahankan rasio kerugian serendah mungkin, maka nilai median 0.5484808 mungkin dianggap cukup baik.
Persentil ke-95 Rasio Kerugian: 22.70649. maka ini berarti bahwa 95% dari kebijakan memiliki rasio kerugian sebesar 22.70649 atau kurang. Hanya 5% dari kebijakan yang memiliki rasio kerugian yang lebih tinggi dari nilai ini. jika tujuan perusahaan adalah untuk membatasi klaim yang mahal, nilai persentil ke-95 sebesar 22.70649 mungkin dianggap sebagai nilai yang dapat diterima.