## factorModelFactorEsDecomposition.r
##
## author: Eric Zivot
## created: January 1, 2009
## revised: March 11, 2011
factorModelFactorEsDecomposition <- function(bootData, beta.vec, sig2.e, tail.prob = 0.01,
method=c("average"),
VaR.method=c("HS", "CornishFisher")) {
## Compute factor model factor ES decomposition based on Euler's theorem given historic
## or simulated data and factor model parameters.
## The partial derivative of ES wrt factor beta is computed
## as the expected factor return given fund return is less than or equal to its VaR
## VaR is compute either as the sample quantile or as an estimated quantile
## using the Cornish-Fisher expansion
## inputs:
## bootData B x (k+2) matrix of bootstrap data. First column contains the fund returns,
## second through k+1 columns contain factor returns, (k+2)nd column contain residuals
## scaled to have variance 1.
## beta.vec k x 1 vector of factor betas
## sig2.e scalar, residual variance from factor model
## tail.prob scalar tail probability
## method character, method for computing marginal ES. Valid choices are
## "average" for approximating E[Fj | R<=VaR]
## VaR.method character, method for computing VaR. Valid choices are "HS" for
## historical simulation (empirical quantile); "CornishFisher" for
## modified VaR based on Cornish-Fisher quantile estimate. Cornish-Fisher
## computation is done with the VaR.CornishFisher in the PerformanceAnalytics
## package
## output:
## A list with the following components:
## VaR.fm scalar, bootstrap VaR value for fund reported as a positive number
## n.exceed scalar, number of observations beyond VaR
## idx.exceed n.exceed x 1 vector giving index values of exceedences
## ES.fm scalar, bootstrap ES value for fund reported as a positive number
## mcES.fm k+1 x 1 vector of factor marginal contributions to ES
## cES.fm k+1 x 1 vector of factor component contributions to ES
## pcES.fm k+1 x 1 vector of factor percent contributions to ES
## Remarks:
## The factor model has the form
## R(t) = beta'F(t) + e(t) = beta.star'F.star(t)
## where beta.star = (beta, sig.e)' and F.star(t) = (F(t)', z(t))'
## By Euler's theorem
## ES.fm = sum(cES.fm) = sum(beta.star*mcES.fm)
## References:
## 1. Hallerback (2003), "Decomposing Portfolio Value-at-Risk: A General Analysis",
## The Journal of Risk 5/2.
## 2. Yamai and Yoshiba (2002). "Comparative Analyses of Expected Shortfall and
## Value-at-Risk: Their Estimation Error, Decomposition, and Optimization
## Bank of Japan.
## 3. Meucci (2007). "Risk Contributions from Generic User-Defined Factors," Risk.
require(PerformanceAnalytics)
VaR.method = VaR.method[1]
bootData = as.matrix(bootData)
ncol.bootData = ncol(bootData)
if(is.matrix(beta.vec)) {
beta.names = c(rownames(beta.vec), "residual")
} else if(is.vector(beta.vec)) {
beta.names = c(names(beta.vec), "residual")
} else {
stop("beta.vec is not an n x 1 matrix or a vector")
}
# beta.names = c(names(beta.vec), "residual")
beta.star.vec = c(beta.vec, sqrt(sig2.e))
names(beta.star.vec) = beta.names
if (VaR.method == "HS") {
VaR.fm = quantile(bootData[, 1], prob=tail.prob)
idx = which(bootData[, 1] <= VaR.fm)
ES.fm = -mean(bootData[idx, 1])
} else {
VaR.fm = -VaR.CornishFisher(bootData[, 1], p=(1-tail.prob))
idx = which(bootData[, 1] <= pVaR)
ES.fm = -mean(bootData[idx, 1])
}
##
## compute marginal contribution to ES
##
if (method == "average") {
## compute marginal ES as expected value of factor return given fund
## return is less than or equal to VaR
mcES.fm = -as.matrix(colMeans(bootData[idx, -1]))
} else {
stop("invalid method")
}
## compute correction factor so that sum of weighted marginal ES adds to portfolio ES
#cf = as.numeric( ES.fm / sum(mcES.fm*beta.star.vec) )
#mcES.fm = cf*mcES.fm
cES.fm = mcES.fm*beta.star.vec
pcES.fm = cES.fm/ES.fm
colnames(mcES.fm) = "MCES"
colnames(cES.fm) = "CES"
colnames(pcES.fm) = "PCES"
ans = list(VaR.fm = -VaR.fm,
n.exceed = length(idx),
idx.exceed = idx,
ES.fm = ES.fm,
mcES.fm = t(mcES.fm),
cES.fm = t(cES.fm),
pcES.fm = t(pcES.fm))
return(ans)
}