I computed historic VaR on a simple equity portfolio (for simplicity's sake, let's say there are only two stocks with one year of daily history). Then I did it again using the PerformanceAnalytics R package. My two results don't match.
Am I missing something on how to do basic VaR, or is PerformanceAnalytics doing something strange?
My sample code is below:
library(xts)
# (I'll define "sr" at the end of the question. It's a big xts structure)
weights = c(0.7929511, 0.2070489)
p = 0.95
# How I do it:
m = data.matrix(as.data.frame(sr))
daily_whatif_scenario = tcrossprod(weights, m)[1,]
my_historic_VaR = as.numeric(-quantile(daily_whatif_scenario, 1 - p)[1])
# How PerformanceAnalytics does it:
their_historic_VaR = PerformanceAnalytics::VaR(R = sr, p = p,
method = "historical", portfolio_method = "component", weights = weights)
My calculation comes up with 1.325%, but the package gives me 1.395%. Why such a big difference? These differences only get bigger as I add more stocks and history to my example. Am I doing something wrong?
Here is the result of dput(sr)
:
sr = structure(c(-0.0162, 0.0049, 0.0029, -1e-04, -0.0079, -0.0101,
0.0053, 0.007, -0.0107, 0.001, -0.003, -0.0033, 0.0013, 0.0163,
0.0102, 2e-04, -0.0027, 0.0303, -0.0149, 0.0034, 0.0073, 0.0111,
-0.0057, 0.0022, 0.0266, 0.0038, 0.0062, -0.0063, 0.0078, 0.0022,
0.0091, -0.0074, 0.008, 0.0068, 0.0048, 0.0031, 0.0142, -0.0034,
-0.0089, 0.001, 0.001, -0.0141, 0.0042, 0.0026, -0.017, 0.001,
-0.006, 0.0048, 0.0064, -0.0063, -0.0122, 0.0122, -0.0126, 0.0239,
-0.0236, -9e-04, 0.004, -0.0049, 0.0028, -0.0109, 0.0106, 0.0066,
0.0096, 0.0075, 0.0082, -0.008, 0.047, -6e-04, 5e-04, -0.005,
-0.0084, -0.0074, 0.0078, -0.0029, 0.0071, 5e-04, 0.0118, 0.0068,
-0.0032, 0.0068, -0.0011, -0.0095, 0.0029, -0.0019, -0.0084,
0.0065, -0.014, 0.0049, -0.0042, 0.0071, -0.0097, -0.0038, -0.0049,
0.0045, 0.001, -7e-04, -0.0056, 0.0098, -0.0112, 0.0093, 5e-04,
-6e-04, 0, -0.0013, 0.0026, 0.0199, -8e-04, 0.0023, -0.0038,
-0.0035, -0.0045, -0.0323, -0.0021, -0.0054, -0.0102, 0.0222,
-0.0139, -0.0027, 6e-04, -5e-04, -0.0069, -8e-04, 0.0074, -0.0071,
0.0017, -0.0142, 0.0111, 0.0022, -0.0085, 0.0183, -0.0061, -0.0031,
0.0083, 0.0111, -0.0028, -0.0051, -0.0149, 0.0026, -0.0046, -0.0105,
-0.003, 0.0019, 0.0055, 0.0471, 0.0042, 9e-04, -0.0226, -0.0175,
0.0169, 3e-04, 8e-04, -0.0258, -0.0047, -0.0044, 0.0071, 0.0129,
0.0063, 0.0248, 0.0107, 0.0133, -0.0214, 0.0045, 0.0175, -0.0034,
0.0048, -1e-04, -0.0118, 0.0082, -0.0024, 0.0019, -0.0139, 0.0037,
-0.0018, -0.0166, -0.002, -0.0058, 0.0053, -0.0086, 0.0159, 0.0027,
-0.0097, 0.0186, -0.0099, 0.0362, 0.0034, -0.0044, 0.005, -0.0074,
0.0031, 0.0151, 0, -0.0036, -0.0054, -0.004, -0.0088, 0, 0.015,
-0.0019, 3e-04, 0.0087, -0.0017, 0.0015, 0.0046, -0.0177, 0.0018,
0.0021, -0.0142, 4e-04, -0.005, -0.001, -0.0108, -5e-04, 0.0167,
0, -7e-04, -0.0079, 0.0397, -6e-04, -0.0132, -0.0013, -0.0022,
0.001, -0.0021, 0.0119, -0.0031, 0.0065, 0.001, -0.0014, -0.0054,
8e-04, -0.0021, 0.0103, -0.0016, -0.0014, 0.0169, -4e-04, -0.0067,
0.0249, 0.0018, 0.0047, -0.0117, -0.0015, 0.0133, 0.0144, -3e-04,
-0.0084, -0.0067, 0.0048, -0.0226, 0.001, -0.0079, -1e-04, 0.0062,
0.0037, 0, 7e-04, -0.0046, -0.0045, -7e-04, 0.0097, -0.0066,
-0.0054, -0.0029, -0.0041, -0.0113, 0.0059, -0.0134, -0.0177,
0.0057, -0.0043, -0.0106, -0.0115, -0.0198, 0.0131, 0.0086, -0.008,
0.0286, -0.0042, 6e-04, 0.0151, 0.0071, 0.0058, 0.0056, 0.0165,
0.0143, 0.0092, 0.0023, 0.0168, 0.0068, -0.0033, -0.0296, -5e-04,
0.0191, -0.0106, 0.0062, -0.002, -0.001, 0.0038, 0.0039, 0.001,
-0.01, 0.0059, 0.0036, -0.0063, -0.0082, -0.0034, 0.0039, 0.0184,
0.0055, -0.0084, 0.0093, -0.0104, 0.0289, -0.01, -0.0098, 0.0108,
-0.0068, -0.0056, 0.002, 0.0206, -0.008, 0.0212, 0.0496, 0.0038,
-0.008, 0.0122, 0.0029, -0.0014, -9e-04, -0.0077, -0.016, 0.0064,
0.0012, 0.0056, 0.0039, 0.0176, -0.0125, -0.0088, 0.0075, 0.0049,
-0.0131, -0.004, 0.0052, -0.004, 0.0021, -0.0162, -0.0126, 0.0042,
0.0032, -0.0059, 0.0014, -0.0034, 7e-04, 0.0043, -6e-04, -0.0067,
0.0067, 0.0045, 0.0096, -3e-04, -0.0082, 0.0038, 0.0053, -0.013,
0.0197, -0.0057, 0.0041, -0.0142, 0.0114, -0.0045, -0.0123, -0.0433,
-0.0066, -0.0212, 0.0257, -0.0068, 8e-04, -0.0031, -0.0029, -0.0097,
-0.0074, 0.0065, -0.013, -0.0036, -0.013, -0.002, 0.0032, -0.0087,
0.0054, -0.001, -0.0118, 0.0034, 0.0051, -0.0065, 2e-04, 0.0015,
-3e-04, 0.0043, -0.0168, 8e-04, -0.0033, -0.0094, -0.0017, -4e-04,
0.0024, -3e-04, -0.0087, 0.0073, 0.0176, 0.0014, -0.0121, -0.005,
-0.006, -0.0059, 0.0159, 0.0273, -0.0071, -0.0163, 0.0041, 0.004,
-6e-04, 0.0095, 0.0012, 0.0156, 0.003, 0.0153, -0.0203, -0.0024,
0.0101, -0.0108, 0.0118, -0.0172, -0.0077, -2e-04, 0, 2e-04,
0.0287, -0.0023, 0.0096, 0.0043, -0.0016, -0.0169, 0.0221, 0.0208,
-0.0036, -0.0236, 0.014, 0.0047, 0.0023, 0, -0.0013, -0.0033,
0.0024, -0.0134, 0, 0.0081, -0.0085, -0.006, -0.0014, -0.0184,
-0.0066, 0.0103, -0.0123, -0.0022, 0.0021, 0.0059, -0.0014, -0.0046,
0.0124, -0.009, 0.0079, 0.0096, -0.0019, -0.0025, -0.0024, -0.0063,
-0.0139, -0.0094, 0.0152, -0.0145, 0.0061, 0.0055, 0.016, -0.0105,
0.0061, 0.0053, -0.0058, -0.0272, -0.0345, -0.0021, 0.0322, -0.0092,
-0.0022, 0.0154, -0.0243, 0.0072, 0.0078, 0.0152, -7e-04, -0.0081,
-0.0042, 0.0038, 0.0157, -0.0064, -0.0063, -3e-04, 0.0094, -0.0162,
-0.0045, -0.0122, -0.0062, -0.0081, 0.0112, -1e-04, -0.0059,
9e-04, 0.0043, -0.0081), .indexCLASS = "Date", tclass = c("POSIXct",
"POSIXt"), .indexTZ = "", tzone = "", class = c("xts", "zoo"), index = structure(c(1459728000,
1459814400, 1459900800, 1459987200, 1460073600, 1460332800, 1460419200,
1460505600, 1460592000, 1460678400, 1460937600, 1461024000, 1461110400,
1461196800, 1461283200, 1461542400, 1461628800, 1461715200, 1461801600,
1461888000, 1462147200, 1462233600, 1462320000, 1462406400, 1462492800,
1462752000, 1462838400, 1462924800, 1463011200, 1463097600, 1463356800,
1463443200, 1463529600, 1463616000, 1463702400, 1463961600, 1464048000,
1464134400, 1464220800, 1464307200, 1464566400, 1464652800, 1464739200,
1464825600, 1464912000, 1465171200, 1465257600, 1465344000, 1465430400,
1465516800, 1465776000, 1465862400, 1465948800, 1466035200, 1466121600,
1466380800, 1466467200, 1466553600, 1466640000, 1466726400, 1466985600,
1467072000, 1467158400, 1467244800, 1467331200, 1467590400, 1467676800,
1467763200, 1467849600, 1467936000, 1468195200, 1468281600, 1468368000,
1468454400, 1468540800, 1468800000, 1468886400, 1468972800, 1469059200,
1469145600, 1469404800, 1469491200, 1469577600, 1469664000, 1469750400,
1470009600, 1470096000, 1470182400, 1470268800, 1470355200, 1470614400,
1470700800, 1470787200, 1470873600, 1470960000, 1471219200, 1471305600,
1471392000, 1471478400, 1471564800, 1471824000, 1471910400, 1471996800,
1472083200, 1472169600, 1472428800, 1472515200, 1472601600, 1472688000,
1472774400, 1473033600, 1473120000, 1473206400, 1473292800, 1473379200,
1473638400, 1473724800, 1473811200, 1473897600, 1473984000, 1474243200,
1474329600, 1474416000, 1474502400, 1474588800, 1474848000, 1474934400,
1475020800, 1475107200, 1475193600, 1475452800, 1475539200, 1475625600,
1475712000, 1475798400, 1476057600, 1476144000, 1476230400, 1476316800,
1476403200, 1476662400, 1476748800, 1476835200, 1476921600, 1477008000,
1477267200, 1477353600, 1477440000, 1477526400, 1477612800, 1477872000,
1477958400, 1478044800, 1478131200, 1478217600, 1478476800, 1478563200,
1478649600, 1478736000, 1478822400, 1479081600, 1479168000, 1479254400,
1479340800, 1479427200, 1479686400, 1479772800, 1479859200, 1479945600,
1480032000, 1480291200, 1480377600, 1480464000, 1480550400, 1480636800,
1480896000, 1480982400, 1481068800, 1481155200, 1481241600, 1481500800,
1481587200, 1481673600, 1481760000, 1481846400, 1482105600, 1482192000,
1482278400, 1482364800, 1482451200, 1482710400, 1482796800, 1482883200,
1482969600, 1483056000, 1483315200, 1483401600, 1483488000, 1483574400,
1483660800, 1483920000, 1484006400, 1484092800, 1484179200, 1484265600,
1484524800, 1484611200, 1484697600, 1484784000, 1484870400, 1485129600,
1485216000, 1485302400, 1485388800, 1485475200, 1485734400, 1485820800,
1485907200, 1485993600, 1486080000, 1486339200, 1486425600, 1486512000,
1486598400, 1486684800, 1486944000, 1487030400, 1487116800, 1487203200,
1487289600, 1487548800, 1487635200, 1487721600, 1487808000, 1487894400,
1488153600, 1488240000, 1488326400, 1488412800, 1488499200, 1488758400,
1488844800, 1488931200, 1489017600, 1489104000, 1489363200, 1489449600,
1489536000, 1489622400, 1489708800, 1489968000, 1490054400, 1490140800,
1490227200, 1490313600, 1490572800, 1490659200, 1490745600, 1490832000
), tclass = "Date"), .Dim = c(259L, 2L), .Dimnames = list(NULL,
c("DHR.US", "GIS.US")))
So I dug up the code that is run when VaR is called with the parameters you specified. Please see below.
As you read my answer please note that this domain is out side of my skill set and the math is a bit over my head, however it appears that the major difference between your code and theirs is they sort the data and select the transposed cross product identified by alpha. Where as you use quantile. For some reason this means you select adjacent numbers - it appears to be basically a rounding error. Please see the following excel screen shot of your daily_whatif_scenario to illustrate this point:
Code for VaR:
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)
}
Where:
.setalphaprob = function (p)
{
if ( p >= 0.51 ) {
# looks like p was a percent like .99
alpha <- 1-p
} else {
alpha = p
}
return (alpha)
}