Skip to content

Commit 761692e

Browse files
committed
Improved test.
1 parent 1511ab5 commit 761692e

File tree

8 files changed

+72
-10
lines changed

8 files changed

+72
-10
lines changed

pkg/R/bachelier_impvol.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ BachelierImpvol <- function(
6060

6161
v <- abs( forward - strike ) / price.straddle
6262

63+
# when the time value is very slightly negative, we correct to give zero vol.
64+
v[price>0 & 1<v & v<1+8*.Machine$double.eps] <- 1
6365
nu <- ifelse(v<1e-8, 1/(1+v*v*(1/3 + v*v/5)), v/atanh(v))
6466

6567
poly.nu <- (((((((a[8]*nu+a[7])*nu+a[6])*nu+a[5]))*nu+a[4])*nu+a[3])*nu+a[2])*nu+a[1]

pkg/R/blackscholes_impvol.R

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@ BlackScholesImpvol <- function(
3333
intr=0, divr=0, cp=1L,
3434
forward=spot*exp(-divr*texp)/df, df=exp(-intr*texp)
3535
){
36-
optval <- (price/df - pmax(cp*(forward-strike), 0))/pmin(forward, strike)
36+
timeval <- (price/df - pmax(cp*(forward-strike), 0))/pmin(forward, strike)
37+
# when the time value is very slightly negative, we correct to give zero vol.
38+
timeval[price>0 & -8*.Machine$double.eps<timeval & timeval<0] <- 0
3739

3840
# we use inverse CDF of inversegaussian distribution
3941
mu <- 2/abs(log(strike/forward))
40-
x <- statmod::qinvgauss(optval, mean=mu, lower.tail=F)
42+
x <- statmod::qinvgauss(timeval, mean=mu, lower.tail=F)
4143
sig <- 2/sqrt(x*texp)
4244
return( sig )
4345
}

pkg/R/blackscholes_price.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ BlackScholesPrice <- function(
2929
){
3030
stdev <- sigma*sqrt(texp)
3131

32-
# a trick to get the intrinsic value for negative or zero vol
32+
# a trick to get the intrinsic value for zero (or slightly negative) vol
3333
# also avoid NAN in case forward=strike
34-
stdev[stdev < 1e-32] <- 1e-32
34+
stdev[abs(stdev) < .Machine$double.eps] <- .Machine$double.eps
3535

3636
d1 <- log(forward/strike)/stdev + 0.5*stdev
3737
d2 <- d1 - stdev

pkg/tests/testthat/test-BS.R

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
library(FER)
2+
3+
test_that("Bachelier Price and Impvol", {
4+
strike <- runif(1000, 50, 150)
5+
sigma <- runif(1000, 1, 20)
6+
texp <- runif(1000, 1e-4, 10)
7+
intr <- runif(1000, 0, 0.1)
8+
divr <- runif(1000, 0, 0.1)
9+
cp <- ifelse(runif(1000)>0.5, 1L, -1L)
10+
11+
p <- FER::BachelierPrice(strike, 100, texp, sigma, cp=cp, intr=intr, divr=divr)
12+
iv <- FER::BachelierImpvol(p, strike, 100, texp, cp=cp, intr=intr, divr=divr)
13+
p2 <- FER::BachelierPrice(strike, 100, texp, iv, cp=cp, intr=intr, divr=divr)
14+
expect_equal(p, p2, tolerance = 1e-8)
15+
})
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
library(FER)
2+
3+
test_that("Black-Scholes Price and Impvol", {
4+
strike <- runif(1000, 50, 150)
5+
sigma <- runif(1000, 0.001, 2)
6+
texp <- runif(1000, 1e-4, 10)
7+
intr <- runif(1000, 0, 0.1)
8+
divr <- runif(1000, 0, 0.1)
9+
cp <- ifelse(runif(100)>0.5, 1L, -1L)
10+
11+
p <- FER::BlackScholesPrice(strike, 100, texp, sigma, cp=cp, intr=intr, divr=divr)
12+
iv <- FER::BlackScholesImpvol(p, strike, 100, texp, cp=cp, intr=intr, divr=divr)
13+
p2 <- FER::BlackScholesPrice(strike, 100, texp, iv, cp=cp, intr=intr, divr=divr)
14+
expect_equal(p, p2, tolerance = 1e-8)
15+
})

pkg/tests/testthat/test-CEV.R

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
library(FER)
2+
3+
test_that("CEV", {
4+
value <- round( FER::CevPrice(
5+
strike=seq(0.4, 2, 0.4)*0.05, spot=0.05, texp=1, sigma=0.4, beta=0.3),
6+
digits=5 )
7+
value2 <- c(0.04608, 0.04229, 0.03868, 0.03525, 0.03203)
8+
expect_equal(value, value2, tolerance = 1e-6)
9+
})

pkg/tests/testthat/test-SABR.R

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
library(FER)
2+
3+
test_that("SabrHagan2002 BS Volatility Table 1", {
4+
value <- round( FER::SabrHagan2002(
5+
strike=seq(0.1, 2, 0.1), spot=1, texp=10, sigma=0.25,
6+
vov=0.3, rho=-0.8, beta=0.3), digits = 4 )
7+
value2 <- c(
8+
0.7176, 0.5725, 0.4886, 0.4293, 0.3835,
9+
0.3462, 0.3148, 0.2876, 0.2638, 0.2427,
10+
0.2238, 0.2068, 0.1916, 0.1781, 0.1663,
11+
0.1562, 0.1478, 0.1412, 0.136, 0.1322)
12+
expect_equal(value, value2, tolerance = 1e-5)
13+
})
14+
15+
test_that("SabrHagan2002 BS Volatility Table 13", {
16+
value <- round( FER::SabrHagan2002(
17+
strike=seq(0.1, 2, 0.1), spot=1, texp=20, sigma=0.25,
18+
vov=0.3, rho=-0.5, beta=0.3), digits=4 )
19+
value2 <- c(
20+
0.7603, 0.5973, 0.5078, 0.4463, 0.3997,
21+
0.3626, 0.332, 0.3063, 0.2844, 0.2658,
22+
0.2498, 0.2364, 0.2251, 0.2158, 0.2083,
23+
0.2023, 0.1976, 0.1941, 0.1914, 0.1895)
24+
expect_equal(value, value2, tolerance = 1e-5)
25+
})

0 commit comments

Comments
 (0)