0

I was working with a project and I used the VaR() function from the PerformanceAnalytics package to calculate Value-at-risk. I wanted to find out the probability of a stock generating making a loss of 1% or more. I found a solution to the problem by plugging numbers in to the probability variable, and controlling to see if it was approaching -1%. However, I was curious if it was possible to flip the formula so that I can just plug in the output and then the function will produce what would have been the input.

Produced the loss at 97.5% probability:

VaR(DNOlog, p = 0.975)

Produced a loss of -1% by changing the probability until it fit:

VaR(DNOlog, p = 0.6512184)
Stakerauo
  • 11
  • 3

2 Answers2

0

What you want is the inverse function. If it is not too expensive to compute a lot of values of your function, then you can get a good approximation of this by computing many x-y pairs and then getting y as a function of x. Since you don't really say what your function is, I will use a simple function y = x + sin(x) as an example.

x = seq(0,6, 0.01)
y = x + sin(x)
InverseFunction = approxfun(y,x)

## Test with an example
InverseFunction(4)      ## gives 4.967601

x1 = 4.967601
x1 + sin(x1)            ## 3.999991

If you want more accuracy, use a smaller spacing between the x's.

G5W
  • 36,531
  • 10
  • 47
  • 80
0

Let's get a reproducible example to demonstrate how you would go about this:

library(PerformanceAnalytics)

set.seed(2)
returns <- rnorm(1000, sd = 0.01)

This gives us a sensible result from VaR

VaR(returns, p = 0.975)
#>            [,1]
#> VaR -0.01893631

To reverse this, we can use uniroot. This is a function which uses an iterative approach to finding the input value that makes a function return 0:

inverse_VaR <- function(x, target) {
  f <- function(p) VaR(x, p)[1, 1] - target
  uniroot(f, c(0.6, 0.99999), tol = .Machine$double.eps)$root
}

In our example, if we want to find the p value that makes VaR give an output of -0.01 with our vector returns, we can do:

inverse_VaR(returns, -0.01)
#> [1] 0.848303

And to show this works, we can do:

VaR(returns, 0.848303)
#>             [,1]
#> VaR -0.009999999

Created on 2022-04-16 by the reprex package (v2.0.1)

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87
  • This solution worked satisfactorily! I was able to flip the function and produce a probability of 0.6512455(Target: 0.6512184) of a -0.01000208 return(Target: -0.1). Clearly this falls under the category of "close enough", but if you have any suggestions to how to increase the accuracy of the model I would love to hear it.I am not fluent with uniroot so if you have time I would love to hear how this flipped the model. – Stakerauo Apr 17 '22 at 10:16
  • @Stakerauo `uniroot` just does automatically what you did yourself manually - it tweaks the input value until it finds the input that gives the expected result, so under the hood it is just trying different p values and homing in on the desired result. In terms of accuracy, as you say, it gives values that are "close enough" rather than exact. You can set the `tol` argument to increase the accuracy - see my update. – Allan Cameron Apr 17 '22 at 11:19