A primer into Risk Management with R. Analyzing VaR and CVaR with Monte Carlo Simulations

A primer into Risk Management with R. Analyzing VaR and CVaR with Monte Carlo Simulations

Introduction

Risk management is a crucial aspect of financial modeling, and one of the key metrics used to measure risk is Value at Risk (VaR). In this project, we explore different approaches to computing VaR, including Historical VaR, Parametric VaR, and Cornish-Fisher VaR, as well as Conditional VaR (CVaR). Additionally, we compare these risk measures across different shock distributions using Monte Carlo simulations.

Step 1: Simulating Historical Price Data

To analyze risk, we first generate synthetic historical price data using a Geometric Brownian Motion (GBM) model with normal shocks. The resulting price series is converted into an xts object for time series analysis.

# Generating synthetic historical data from a GBM with normal shocks
historical_data <- simulate_gbm_with_shocks(S0 = 100, drift = 0.05, sigma = 0.2, T = 1, N = 252, distribution = "std_normal")

# Convert to xts object
dates <- seq(as.Date("2023-01-01"), by = "day", length.out = 253)
historical_xts <- xts(historical_data, order.by = dates)

Step 2: Computing Historical VaR

Historical VaR is calculated by analyzing the empirical distribution of daily log returns.

returns <- diff(log(historical_xts))[-1]
VaR_95 <- quantile(returns, probs = 0.05)
VaR_99 <- quantile(returns, probs = 0.01)

Step 3: Parametric VaR

Parametric VaR assumes that returns follow a normal distribution, allowing us to use the mean and standard deviation to estimate risk.

mean_return <- mean(returns)
sd_return <- sd(returns)
parametric_VaR_95 <- mean_return + sd_return * qnorm(0.05)
parametric_VaR_99 <- mean_return + sd_return * qnorm(0.01)

Step 4: Computing CVaR (Expected Shortfall)

Conditional VaR (CVaR) provides an expectation of losses beyond the VaR threshold.

CVaR_95 <- mean(returns[returns <= VaR_95])
CVaR_99 <- mean(returns[returns <= VaR_99])

Step 5: Cornish-Fisher Expansion

The Cornish-Fisher expansion adjusts VaR estimates by incorporating skewness and kurtosis.

skewness <- PerformanceAnalytics::skewness(returns)
kurtosis <- PerformanceAnalytics::kurtosis(returns)

z_95 <- qnorm(0.05)
z_99 <- qnorm(0.01)

adjusted_z_95 <- z_95 + (skewness / 6) * (z_95^2 - 1) + (kurtosis / 24) * (z_95^3 - 3 * z_95)
CF_VaR_95 <- mean_return + sd_return * adjusted_z_95

Step 6: Scenario Analysis Across Different Distributions

We expand our analysis by simulating returns from different shock distributions:

  • Standard Normal
  • Skewed Normal
  • Heavy-Tailed Normal
  • t-Distribution
  • Skewed t-Distribution

Each scenario is analyzed using the same risk measures.

scenarios <- list(
  list(distribution = "std_normal"),
  list(distribution = "skewed_normal", alpha = 5),
  list(distribution = "heavy_tail_normal", df = 3),
  list(distribution = "std_t", df = 5)
)
results_list <- map(scenarios, ~ do.call(analyze_shock_scenario, .))
results_df <- bind_rows(results_list)

Step 7: Monte Carlo Simulations

We run 1,000 Monte Carlo simulations to test the robustness of our risk measures across different distributions.

monte_carlo_results <- future_map(1:1000, ~ {
  map(scenarios, ~ do.call(analyze_shock_scenario, c(., seed = runif(n = 1)*1000000)))
}, .progress = TRUE)

Step 8: Visualizing Results

We use ggplot2 to visualize the comparison of different risk measures.

ggplot(results_df, aes(x = Distribution, y = Value, fill = Metric)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Comparison of Risk Measures", x = "Shock Distribution", y = "Value") +
  theme_minimal()

Conclusion

This project demonstrates how to systematically analyze financial risk using different VaR methodologies and Monte Carlo simulations. By incorporating various shock distributions, we gain deeper insights into the robustness of risk metrics under different market conditions.