Portfolio: SPY, TLT, GLD, HYG
# 1. LOAD LIBRARIES
library(quantmod) # Financial data
library(MASS) # Monte Carlo simulation
library(ggplot2) # Visualisation
# 2. DATA COLLECTION
# Multi-asset portfolio
assets = c("SPY", "TLT", "GLD", "HYG")
# Pull historical data
getSymbols(assets, from = "2020-01-01")
## [1] "SPY" "TLT" "GLD" "HYG"
# Extract closing prices and merge
prices = na.omit(merge(
Cl(SPY), Cl(TLT), Cl(GLD), Cl(HYG)
))
# 3. RETURN CALCULATION
# Compute log returns (standard in finance)
returns = na.omit(diff(log(prices)))
# 4. PORTFOLIO CONSTRUCTION
# Equal weights
weights = c(0.25, 0.25, 0.25, 0.25)
# Portfolio returns (matrix multiplication)
portfolio_returns = returns %*% weights
# 5. PARAMETRIC VaR FUNCTION
parametric_var = function(returns, weights, alpha = 0.99, V = 1e6) {
mu = colMeans(returns) # Mean returns per asset
cov_mat = cov(returns) # Covariance matrix
port_mean = sum(weights * mu) # Portfolio mean
port_sd = sqrt(t(weights) %*% cov_mat %*% weights) # Portfolio standard deviation
z = qnorm(1 - alpha) # Normal quantile
VaR = V * (port_mean + z * port_sd) # Convert to monetary VaR
return(abs(VaR))
}
# 6. HISTORICAL VaR FUNCTION
historical_var = function(portfolio_returns, alpha = 0.99, V = 1e6) {
VaR = quantile(portfolio_returns, probs = 1 - alpha)
return(abs(V * VaR))
}
# 7. MONTE CARLO VaR FUNCTION
monte_carlo_var = function(returns, weights, alpha = 0.99,
V = 1e6, n_sim = 10000) {
mu = colMeans(returns)
cov_mat = cov(returns)
# Simulate correlated returns
sim_returns = mvrnorm(n_sim, mu = mu, Sigma = cov_mat)
# Portfolio simulation
port_sim = sim_returns %*% weights
VaR = quantile(port_sim, probs = 1 - alpha)
return(abs(V * VaR))
}
# 8. COMPUTE VaR VALUES
V = 1e6 # Portfolio value in dollars
var_param = as.numeric(parametric_var(returns, weights, 0.99, V))
var_hist = historical_var(portfolio_returns, 0.99, V)
var_mc = monte_carlo_var(returns, weights, 0.99, V)
cat("Parametric VaR:", var_param, "\n")
## Parametric VaR: 14812.46
cat("Historical VaR:", var_hist, "\n")
## Historical VaR: 16184.21
cat("Monte Carlo VaR:", var_mc, "\n")
## Monte Carlo VaR: 14836
# 9. BACKTESTING FUNCTION
backtest_var = function(returns, VaR, V = 1e6) {
returns = as.numeric(returns)
VaR_return = VaR / V
violations = returns < -VaR_return
x = sum(violations)
n = length(returns)
violation_rate = x / n
return(list(
violations = x,
total_obs = n,
violation_rate = violation_rate
))
}
# 10. KUPIEC TEST FUNCTION
kupiec_test = function(returns, VaR, alpha = 0.99, V = 1e6) {
returns = as.numeric(returns)
VaR_return = VaR / V
violations = returns < -VaR_return
x = sum(violations)
n = length(returns)
p_hat = x / n
p = 1 - alpha
LR = -2 * log(((1 - p)^(n - x) * p^x) /
((1 - p_hat)^(n - x) * p_hat^x))
p_value = 1 - pchisq(LR, df = 1)
return(list(
violations = x,
violation_rate = p_hat,
expected_rate = p,
LR_stat = LR,
p_value = p_value
))
}
# 11. RUN BACKTESTING
bt_param = kupiec_test(portfolio_returns, var_param, 0.99, V)
bt_hist = kupiec_test(portfolio_returns, var_hist, 0.99, V)
bt_mc = kupiec_test(portfolio_returns, var_mc, 0.99, V)
print(bt_param)
## $violations
## [1] 23
##
## $violation_rate
## [1] 0.01471529
##
## $expected_rate
## [1] 0.01
##
## $LR_stat
## [1] 3.065054
##
## $p_value
## [1] 0.07999251
print(bt_hist)
## $violations
## [1] 16
##
## $violation_rate
## [1] 0.01023672
##
## $expected_rate
## [1] 0.01
##
## $LR_stat
## [1] 0.00877897
##
## $p_value
## [1] 0.9253505
print(bt_mc)
## $violations
## [1] 23
##
## $violation_rate
## [1] 0.01471529
##
## $expected_rate
## [1] 0.01
##
## $LR_stat
## [1] 3.065054
##
## $p_value
## [1] 0.07999251
# 12. EXPECTED SHORTFALL (CVaR)
expected_shortfall = function(returns, alpha = 0.99) {
returns = as.numeric(returns)
VaR = quantile(returns, probs = 1 - alpha)
ES = mean(returns[returns <= VaR])
return(abs(ES))
}
es_value = expected_shortfall(portfolio_returns)
cat("Expected Shortfall (ES):", es_value, "\n")
## Expected Shortfall (ES): 0.02550301
# 13. VISUALISATION
df = data.frame(returns = portfolio_returns)
ggplot(df, aes(x = returns)) +
geom_histogram(bins = 50, fill="steelblue", color="black") +
ggtitle("Portfolio Return Distribution") +
xlab("Daily Log Returns") +
ylab("Frequency")
# Save plot
ggsave("var_distribution_new_data.png")
## Saving 7 x 5 in image