Historical VaR Fails When the Tail Index Rounds to Zero
Summary
The document explains why a historical portfolio Value at Risk calculation can return an empty result at a high confidence level. The cited implementation converts the confidence level to a lower-tail probability, multiplies that probability by the number of observations, and selects the corresponding sorted portfolio return using the floored index. When the product is below one, the index becomes zero, which produces an empty selection in R. The answer also notes that historical component VaR can be meaningless for an asset whose sampled returns do not reach the relevant loss tail.
The example contrasts a 99.5% request with a 95% request and reports that a Gaussian method works. The method-level explanation is useful, but the document contains an inconsistency: the displayed return object has six rows, while the explanation later refers to 102 observations and computes a different index. The precise sample size and behavior therefore need checking against the actual data and package version.
Key ideas
- Historical VaR selects an order statistic from observed portfolio returns.
- At extreme confidence levels, a small sample may yield a tail index below one.
- Flooring that index to zero can make the selected R vector empty.
- Assets without losses in the relevant sample tail may not support a meaningful historical loss estimate.
- The displayed data dimensions and the answer's observation count do not agree.
Tags
Full text
# R returns numeric(0) when putting p=0.995 for calculating VaR
# R returns numeric(0) when putting p=0.995 for calculating VaR
My code actually works just fine. What I don't understand is, if I put p=0.995 instead of 0.95, the console gives me numeric(0). What can cause this error? However, when I use "gaussian" method, it works just fine.
The function tries to calculate the Value at Risk at the probability level of 99.5%. At 95% the function works as it should. You can reconstruct using the following code.
Thanks!
```
VaR(bonds.returns,p=0.995, weights= weights,portfolio_method = "component", method="historical")
```
bonds.returns
```
structure(c(0.0075452479085516, -0.000430602750240983, -0.000618087487474384,
0.00222086866888427, 0.0106496372204352, 0.00136921667853951,
0.00423968343697001, 0.0024904263575809, -0.000195676402276579,
0.000280808046426939, 0.00478090360779571, 0.0034797185745854,
0.00730203951222119, -0.000343622174203362, -0.00819027347184287,
-0.00430557592076686, 0.0121157759451644, 0.00511236623854172,
0.00632861635220117, 0.00281239014100998, -0.000272659992988644,
0.00102275383776207, 0.00580914478101358, 0.00408258034556819,
0.00683299709040042, 0.00444050627813075, 0.00112276199450645,
-0.00105140888790989, 0.00547308066278407, 0.00292103243043851,
0.000354539209820759, 0.000498394063572771, 0.000774893452150316,
0.00578507825894592, 0.00786336442020064, 0.00264068177602228,
0.0044426685809873, 0.00123386036476414, 0.000437716332879923,
0.00273957849531858, 0.00459152849567035, 0.00344127119889892,
0.00372234677044103, 0.00235998145728855, -0.000988017658188123,
0.000196396130996312, 0.00448116019271083, 0.00288335334692413,
0.00421227034351057, 0.00228605784355529, -0.00052312928966014,
0.00158416670737593, 0.00452201783723516, 0.0028924387350957,
0.00519960504742145, 0.00304595059792567, 0.00181483311621222,
0.00192813007255133, 0.00722328637152936, 0.00474544339681326,
0.00443227606157648, 0.00133718717534648, -5.13615959075731e-05,
-0.00041091387245229, 0.00307284387075546, 0.00220280114340743,
0.00575621301775153, 0.00313461918612856, -0.000187677120282226,
0.000272182906913443, 0.00450387051372281, 0.00321330157395727,
0.0056956454201833, 0.00323328013180268, 0.000923749602274482,
0.00117925737548585, 0.00519286314193823, 0.00386179068890669,
0.00449726636750203, 0.00136557388242409, 6.81855816717647e-05,
-9.74013324506195e-06, 0.00322401550644313, 0.00166993533855031,
0.00521548174581388, 0.0035394698147293, -0.000146521679975864,
0.000879258910347014, 0.00566832951610041, 0.00377491914601547,
0.00289058379650298, -0.00118324046075591, 8.10011745171479e-05,
-0.000577086623739564, 0.0027756673251278, 0.00217195850043939,
0.00844551759115331, 0.00488711529000163, 0.000326399164418012,
0.0021100258858846, 0.00678345055135887, 0.00597233751253223,
0, -0.00294687131050764, -0.0124380701571574, -0.00119904076738608,
0.00780792316926782, -0.00107682631649164, 0.00416801143436785,
0.00224983241044274, -5.49742537244713e-05, 0.000394003811757804,
0.00469870579507048, 0.00247967034970653, 0.00207520724910104,
0.00483573674509374, 0.000787690448444067, 0.00624265490733067,
0.00121078347334125, -0.00618572147130281, 0.00466954738246472,
0.00228923662382208, -0.00131503490280616, -0.000811840997970381,
0.00319055121231049, 0.00204454540964982, 0.000172922203210746,
0.0043951044178534, 0.00170323796408711, -0.000533617929562413,
0.000841575646791437, 0.0009493670886076, 0.00477505036185932,
0.00240800263076935, 0.00104766339315954, 0.000909138960833111,
0.00509077850888784, 0.00328909345018547, 0.00160412259506937,
0.00107103890774041, 0.00254974502549743, 0.000578467062284815,
0.00337908555366173, -0.00140072718602857, 0.00422467406148375,
0.00172189447526239, -0.000234400179706773, -0.000341913740047883,
0.00276556239616932, 0.00202703361172563), .indexCLASS = "Date", tclass = "Date", .indexTZ = "UTC", tzone = "UTC", class = c("xts",
"zoo"), index = structure(c(1491177600, 1491264000, 1491350400,
1491436800, 1491523200, 1491782400), tzone = "UTC", tclass = "Date"), .Dim = c(6L, 25L), .Dimnames = list(NULL, c("BE0000343526", "BE6248644013",
"FR0010171975", "FR0013152907", "IE00BV8C9186", "SI0002103677",
"XS0162513211", "XS0162869076", "XS0162990229", "XS0908570459",
"XS1117298247", "XS1146286205", "XS1196380031", "XS1196817586",
"XS1200679667", "XS1202849086", "XS1203860934", "XS1313004928",
"XS1362373224", "XS1388864503", "XS1405784015", "XS1418788599",
"XS1463101680", "XS1538284230", "XS1570260460")))
```
weights
```
c(0.039728041, 0.040869022, 0.042067239, 0.039212564, 0.039765805,
0.040603312, 0.041035065, 0.04158508, 0.039500351, 0.042032909,
0.040638835, 0.040266658, 0.040995045, 0.04002851, 0.040191534,
0.039809092, 0.039765018, 0.041233473, 0.04085667, 0.027147317,
0.041430642, 0.040688867, 0.040016652, 0.040498212, 0.040034086
)
```
## Answer by AK88 (score 1, accepted)
https://quant.stackexchange.com/a/35303
The problem arises due to your data. Some of your columns do not have a negative value in that percentile (check for example `XS1463101680` and `XS1203860934` -- all positives), thus historical VaR is meaningless (your losses cannot be a positive value, loss is always negative). Therefore, you will get an error.
Also, your code for `p = 0.95` returns the same error.
EDIT
Unfortunately, this particular function will not work if you have less than 200 data observations (returns). Why? Well, having investigated the code, I found the following:
On the bottom of this page you can see the formula that is used to compute historical component VaR:
```
component = {
# @todo need to add another loop here for subsetting, I think, when weights is a timeseries
#if (mu=NULL or sigma=NULL) {
# pfolioret = Return.portfolio(R, weights, wealth.index = FALSE, contribution=FALSE, method = c("simple"))
#}
# for now, use as.vector
weights=as.vector(weights)
names(weights)<-colnames(R)
switch(method,
modified = { return(VaR.CornishFisher.portfolio(p,weights,mu,sigma,m3,m4))},
gaussian = { return(VaR.Gaussian.portfolio(p,weights,mu,sigma)) },
historical = { return(VaR.historical.portfolio(R, p,weights)) },
kernel = { return(VaR.kernel.portfolio(R, p,weights)) }
)
}, # end component portfolio switch
```
Tracing back the function `VaR.historical.portfolio`, on the bottom of this page we observe:
```
VaR.historical.portfolio = function(R,p,w)
{
alpha = .setalphaprob(p)
portret = c();
T = dim(R)[1]
N = dim(R)[2]
for( t in c(1:T) ){
portret = c(portret,sum(w*as.numeric(R[t,])))
}
hVaR = -1* sort(portret)[floor(alpha*T)]
return(hVaR)
}
```
`T = dim(R)[1]` piece gives you the number of rows of your data. Your alpha is `1 - 0.995` or `0.005`. Then you have this code `floor(alpha*T)` which is basically destroying everything as `alpha*T` is `0.76` and `floor(0.76)` is 0. And `sort(portret)[0]` returns `numeric(0)`.
The function works for `p = 0.95` because your alpha is `0.05` and `102 * 0.05 = 5.1` and `floor(5.1) = 5` so you're getting the fifth element as your historical component VaR.Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.