HQu-0.0.0.0: test/normalimpliedvol/Spec.hs
module Main where
import Control.Monad (guard, unless, when)
import Data.List (intercalate)
import Q.Options.Bachelier
import Q.Options.ImpliedVol.Normal
import Q.Options
import Q.Types
import Test.Hspec hiding (shouldBe)
import Test.Hspec.Expectations
closeTo x y = compareWith (\x y -> (abs $ (x - y)) / (max x y) <= 1e-2) errorMessage x y where
errorMessage = "Is not close to"
compareWith :: (HasCallStack, Show a) => (a -> a -> Bool) -> String -> a -> a -> Expectation
compareWith comparator errorDesc result expected = expectTrue errorMsg (comparator expected result)
where errorMsg = show result ++ " " ++ errorDesc ++ " " ++ show expected
expectTrue msg b = unless b (expectationFailure msg)
test cp t (k, b@(Bachelier f r sigma))= do
let v = euOption b t cp k
p = vPremium v
sigma' = euImpliedVolWith Jackel cp f k t r p
df = discountFactor t r
when (hasTimeValue cp f k p df) $
it (intercalate ", " [show t, show f, show df, show cp, show k, show p, show sigma]) $ do
sigma' `closeTo` sigma
runTests f r strikes vols t = do
let bs = [Bachelier f r sigma | sigma <- vols]
testCases = [(k, b) | k <- strikes, b <- bs]
context "Call Option" $ do
mapM_ (test Call t) testCases
context "Put Option" $ do
mapM_ (test Put t) testCases
main = hspec $ do
describe "bachelier european implied vol" $ do
context "When asset price is positive ($100)" $ do
let strikes = [Strike k | k <- [80,81..120]]
vols = [Vol sigma | sigma <- [1,2..200]]
let f = Forward 100
context "1Y option" $ do
let t = YearFrac 1
context "When interest rate is zero (0%)" $ do
let r = Rate 0
runTests f r strikes vols t
context "When interest rate is slightly positive (1%)" $ do
let r = Rate 0.01
runTests f r strikes vols t
context "When interest rate is slightly negative (-1%)" $ do
let r = Rate (-0.01)
runTests f r strikes vols t