UTS Permodelan dan Teori Risiko

Ferdinand Nathaniel

2024-03-19

Soal 1

Consider a portfolio consisting of five stocks from different sectors in Indonesia and analyze the diversification benefits of combining stocks.

Stock Data Import

Menggunakan Library quantmod yang terhubung ke yahoo finance, Kita akan melakukan analisis terhadap 5 emiten saham di Indonesia. Yaitu 1. Adaro Energy Tbk. (ADRO) di bidang Energy
2. Barito Pacific Tbk. (BRPT) di bidang Energy
3. Indofood CBP Sukses Makmur Tbk. (ICBP) di bidang Produksi Pangan
4. PT. Saratoga Investama Sedaya (SRTG) di bidang Investasi
5. Sumber Alfaria Trijaya Tbk (AMRT) di bidang Perdagangan, Jasa dan Investasi

library(quantmod)
library(plotly)
library(PerformanceAnalytics)


tick = c('ADRO.JK', 'BRPT.JK', 'ICBP.JK','SRTG.JK', 'AMRT.JK')
ticklabel = c("Adaro Energy Tbk.", "Barito Pacific Renewable Energy", "Indofood CBP Sukses Makmur Tbk.", " PT. Saratoga Investama Sedaya ", "Sumber Alfaria Trijaya Tbk.")


stocksss = getSymbols(tick, from="2022-03-01", to="2024-03-01", src="yahoo", adjust=F)

stocksss
## [1] "ADRO.JK" "BRPT.JK" "ICBP.JK" "SRTG.JK" "AMRT.JK"

Calculate daily returns and Combine (B&C)

closing = NULL
for (stock in tick) { closing = cbind(closing, Cl(get(stock)))}

return = Return.calculate(closing)
return = data.frame(return)
head (return)
##            ADRO.JK.Close BRPT.JK.Close ICBP.JK.Close SRTG.JK.Close
## 2022-03-01            NA            NA            NA            NA
## 2022-03-02    0.01162791    0.00000000  -0.039393939    0.05109489
## 2022-03-04    0.16475096    0.00000000  -0.012618297    0.06250000
## 2022-03-07    0.06578947   -0.06629833  -0.054313099   -0.03594771
## 2022-03-08   -0.03703704   -0.02366863   0.027027027    0.01016949
## 2022-03-09   -0.01282051    0.01818178   0.003289474   -0.03020134
##            AMRT.JK.Close
## 2022-03-01            NA
## 2022-03-02   0.000000000
## 2022-03-04  -0.004587156
## 2022-03-07   0.055299539
## 2022-03-08  -0.065502183
## 2022-03-09  -0.014018692

Correlation matrix using Cor()

corstock = cor(na.omit(return))
corstock
##               ADRO.JK.Close BRPT.JK.Close ICBP.JK.Close SRTG.JK.Close
## ADRO.JK.Close   1.000000000    0.11337547  -0.007553162    0.47225880
## BRPT.JK.Close   0.113375466    1.00000000   0.118088004    0.03514881
## ICBP.JK.Close  -0.007553162    0.11808800   1.000000000    0.01073091
## SRTG.JK.Close   0.472258801    0.03514881   0.010730909    1.00000000
## AMRT.JK.Close   0.104400474    0.02611816  -0.048232684    0.06136409
##               AMRT.JK.Close
## ADRO.JK.Close    0.10440047
## BRPT.JK.Close    0.02611816
## ICBP.JK.Close   -0.04823268
## SRTG.JK.Close    0.06136409
## AMRT.JK.Close    1.00000000

Using the Corrplot()

library(corrplot)
## corrplot 0.92 loaded
corrplot(corstock, method = 'number')

Using Plotly

colnames(corstock) = rownames(corstock) = ticklabel #Renaming 

mask = matrix(F, nrow=nrow(corstock), ncol=ncol(corstock))
mask[lower.tri(mask)] = T

heatmap = plot_ly(z=corstock, x=ticklabel, y=ticklabel, type="heatmap")
heatmap = heatmap %>%
  layout(title = "Correlation Heatmap of Indonesian Stocks Return Price", 
         xaxis = list(title=""), 
         yaxis=list(title=""),
         colorscale= "Inferno",
         margin = list(l=60, r=80, t=100, b=60))

heatmap

Each Stocks Tends to have low correlation between each others. This means that the portfolio has slightly been diversed.

Calculate the portfolios returns and standard deviation based on equal weights for each stock.

 num_stocks <- length(closing)
  weights <- rep(1/num_stocks, num_stocks)
  
  portfolio_returns <- rowSums(closing * weights)
    portfolio_sd <- sqrt(var(portfolio_returns))
    
cat("Portfolio Returns:", mean(portfolio_returns), "\n")
## Portfolio Returns: 7.641943
cat("Portfolio Standard Deviation:", portfolio_sd, "\n")
## Portfolio Standard Deviation: 0.4734845

If a portfolio has a return of 7.64%, it means that over a specific period (in this case 2 years), the value of the portfolio has increased by 7.64% compared to its initial value. With the standard Deviation of 0.47%. Which brings us to the growth interval of 7-8%.

Diversification Ratio

return = na.omit(return)
column_mean = apply(return, 2, mean, na.rm=T)
column_sd <- apply(return, 2, sd, na.rm = TRUE)

# Print the standard deviation of each column
print(column_sd)
## ADRO.JK.Close BRPT.JK.Close ICBP.JK.Close SRTG.JK.Close AMRT.JK.Close 
##    0.02598076    0.03410616    0.01638133    0.02718201    0.02349844
calculate_diversification_ratio <- function(portfolio_sd, column_sd) {
  weighted_avg_individual_sd <- sum(column_sd) / length(column_sd)
  
  # Calculate diversification ratio
  diversification_ratio <- weighted_avg_individual_sd / portfolio_sd
  
  return(diversification_ratio)
}

diversification_ratio <- calculate_diversification_ratio(portfolio_sd, column_sd)
cat("Diversification Ratio:", diversification_ratio, "\n")
## Diversification Ratio: 0.05370765

A diversification ratio of 0.05 suggests that diversification has significantly reduced the portfolio’s risk. Typically, a lower diversification ratio indicates a greater reduction in risk due to diversification.

Define Functions and Constraints for Portofolio Optimizations

Assume we want a flat 8% Profit of returns, and the covariance matrix is the corelation between the Stocks.

library(quadprog)
# Example data (replace with your actual data)
expected_returns <- c(0.08, 0.08, 0.08, 0.08, 0.08)  # Expected returns for assets
cov_matrix <- matrix(corstock, nrow=5)  # Covariance matrix

library(Matrix)
pd_D_mat <- nearPD(cov_matrix)

# Use the positive definite matrix for optimization
D_mat <- as.matrix(pd_D_mat$mat)
d_vec <- rep(0, length(expected_returns))
A_mat <- cbind(rep(1, length(expected_returns)), diag(length(expected_returns)))
b_vec <- c(1, d_vec)

# Solve quadratic programming problem
library(quadprog)
output <- solve.QP(Dmat = D_mat, dvec = d_vec, Amat = A_mat, bvec = b_vec, meq = 1)

# Optimal portfolio weights
optimal_weights <- output$solution
print(optimal_weights)
## [1] 0.1320957 0.2040455 0.2474381 0.1735723 0.2428484

The Conclusion will then be Visualize.

Visualize Optimal Weight

pie <- plot_ly(labels = ticklabel, values = optimal_weights, type = "pie")

pie <- pie %>% layout(title = "Optimized Portfolio Weight", xaxis = list(title = ""), yaxis = list(title = ""))

pie

Expected Return and Volatility.

expected_return_portfolio <- sum(optimal_weights * expected_returns)

# Calculate portfolio volatility (standard deviation)
portfolio_volatility <- sqrt(t(optimal_weights) %*% cov_matrix %*% optimal_weights)

# Print the results
cat("Expected Return of the Portfolio:", expected_return_portfolio, "\n")
## Expected Return of the Portfolio: 0.08
cat("Portfolio Volatility (Standard Deviation):", portfolio_volatility*portfolio_sd, "\n")
## Portfolio Volatility (Standard Deviation): 0.2417485

As the expected Return was flat 8%, so does the restult of Optimized Portfolio. Meanwhile, Volatility is often expressed as the standard deviation of returns. A standard deviation measures the dispersion or variability of a set of values. In this case, it measures how much the returns of the financial instrument fluctuate around their 0.24% of their average return of 8% .

Soal 2

Data Generating

# Set the seed for reproducibility
set.seed(123)

# Number of policies
policies <- 10000

# Number of years
years <- 16

# Mean number of claims per policy per year (assuming Poisson distribution)
lambda <- 0.1


# Initialize empty data frame to store claims data
claims_data <- data.frame(
  PolicyID = integer(),
  Year = integer(),
  Claims = numeric(),
  ClaimAmount = numeric()
)

# Generate claims data for each policy and year
for (policy_id in 1:policies) {
  for (year in 1:years) {
    # Generate number of claims for the policy and year
    num_claims <- rpois(1, lambda)
    
    if (num_claims > 0) {
    # Generate claim amounts for each claim
    claim_amounts <- rnorm(num_claims, 5006, 2006)
    
    # Append data to claims_data data frame
    claims_data <- rbind(claims_data, data.frame(
      PolicyID = rep(policy_id, num_claims),
      Year = rep(year, num_claims),
      Claims = num_claims,
      ClaimAmount = claim_amounts
    ))
  }
}
}
# View the first few rows of the claims data
head(claims_data)
##   PolicyID Year Claims ClaimAmount
## 1        1    5      1    1616.751
## 2        1    9      1    4770.813
## 3        1   16      1    7461.508
## 4        2    2      1    5809.948
## 5        2    7      1    7603.295
## 6        5   13      1    7499.295

Random Policy Premiums

set.seed(123)
premiums <- abs(rnorm((nrow(claims_data)), mean = 1006, sd = 2006))

claims_data$Premiums = premiums

head(claims_data)
##   PolicyID Year Claims ClaimAmount  Premiums
## 1        1    5      1    1616.751  118.3141
## 2        1    9      1    4770.813  544.2640
## 3        1   16      1    7461.508 4132.7689
## 4        2    2      1    5809.948 1147.4398
## 5        2    7      1    7603.295 1265.3512
## 6        5   13      1    7499.295 4446.4204

Simulate Claim Amounts

Simulate claim frequencies for each policy from a Poisson distribution with a mean of 0.1 (i.e., on average, each policy has 0.1 claims per year). and then Simulate claim amounts for each policy and each year from a normal distribution with a mean of 5006 and a standard deviation of 2006.

All was Done in Point 1

head(claims_data)
##   PolicyID Year Claims ClaimAmount  Premiums
## 1        1    5      1    1616.751  118.3141
## 2        1    9      1    4770.813  544.2640
## 3        1   16      1    7461.508 4132.7689
## 4        2    2      1    5809.948 1147.4398
## 5        2    7      1    7603.295 1265.3512
## 6        5   13      1    7499.295 4446.4204

Calculate total claim amounts per policy and then calculate loss ratios

total_claim_amounts <- tapply(claims_data$ClaimAmount, claims_data$PolicyID, sum)

total_premiums <- tapply(claims_data$Premiums, claims_data$PolicyID, sum)

loss_ratios <- total_claim_amounts / total_premiums

# Display the first few loss ratios
ratio = data.frame(loss_ratios)
head(ratio)
##   loss_ratios
## 1    2.888023
## 2    5.559223
## 5    1.686592
## 6    5.225253
## 7    1.619086
## 8    2.596906

Only Positice Ratio Loss were viewed. If the loss ratios are positive, it means that the total claim amounts for a policy exceed the premiums paid for that policy.The insurance company is experiencing losses on those policies. It suggests that the company is paying out more in claims than it had anticipated based on the premiums it charged.

Histogram

loss_ratio_histogram <- plot_ly(x = loss_ratios, type = "histogram", 
                                name = "Loss Ratios", 
                                xbins = list(size = 0.1), 
                                marker = list(color = "pink"))

loss_ratio_histogram <- loss_ratio_histogram %>% 
  layout(title = "Histogram of Loss Ratios",
         xaxis = list(title = "Loss Ratio"),
         yaxis = list(title = "Frequency"))

# Show the histogram
loss_ratio_histogram

An Outlier Detected that messed up the Histogram created, here let we see where the outlieres were

boxplot(ratio)

Terdapat banyak outliers, mengindikasikan operusahaan banyak mengalami kerugian.

Summary

mean_loss_ratio <- mean(loss_ratios)
median_loss_ratio <- median(loss_ratios)
p95_loss_ratio <- quantile(loss_ratios, probs = 0.95)

# Display summary statistics
cat("Mean Loss Ratio:", mean_loss_ratio, "\n")
## Mean Loss Ratio: 9.421615
cat("Median Loss Ratio:", median_loss_ratio, "\n")
## Median Loss Ratio: 2.954068
cat("95th Percentile of Loss Ratios:", p95_loss_ratio, "\n")
## 95th Percentile of Loss Ratios: 16.92062

Mean of the Loss Ratio was 9.42 with 95th Percentile in 16.9 Implying that the company is suffering loss because more claims than premium acquired.