File: test_sabr.py

package info (click to toggle)
quantlib-swig 1.40-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,276 kB
  • sloc: python: 6,024; java: 1,552; cs: 774; makefile: 309; sh: 22
file content (120 lines) | stat: -rw-r--r-- 4,067 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""
 Copyright (C) 2019 Klaus Spanderen

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <quantlib-dev@lists.sf.net>. The license is also available online at
 <https://www.quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
"""

import math
import unittest

import QuantLib as ql

class SabrTest(unittest.TestCase):

    def testHagenFormula(self):
        """ Testing Hagen et al. formula """

        today = ql.Date(9,1,2019)
        dc = ql.Actual365Fixed()
        maturityDate = today + ql.Period(6, ql.Months)
        maturityTime = dc.yearFraction(today, maturityDate)

        alpha = 0.35
        beta = 0.85
        nu = 0.75
        rho = 0.85
        f0 = 100.0
        strike = 110.0

        sabrVol = ql.sabrVolatility(strike, f0, maturityTime, alpha, beta, nu, rho)

        self.assertAlmostEqual(sabrVol, 0.205953, 6,
                               msg="Unable to reproduce Hagen et al. SABR volatility")

        flochKennedyVol = ql.sabrFlochKennedyVolatility(
            strike, f0, maturityTime, alpha, beta, nu, rho)

        self.assertAlmostEqual(flochKennedyVol, 0.205447, 6,
                               msg="Unable to reproduce Le Floc'h-Kennedy SABR volatility")

    def testPdeSolver(self):
        """ Testing BENCHOP-SLV SABR example value """

        today = ql.Date(8, 1, 2019)
        dc = ql.Actual365Fixed()
        maturityDate = today + ql.Period(10 * 365, ql.Days)
        maturityTime = dc.yearFraction(today, maturityDate)

        f0 = 0.07
        alpha = 0.4
        nu = 0.8
        beta = 0.5
        rho = -0.6
        strike = f0 * math.exp(-0.1 * math.sqrt(maturityTime))

        rTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.0, dc))

        # see https://ir.cwi.nl/pub/28249
        expected = 0.052450313614407

        option = ql.VanillaOption(
            ql.PlainVanillaPayoff(ql.Option.Call, strike),
            ql.EuropeanExercise(maturityDate))

        option.setPricingEngine(ql.FdSabrVanillaEngine(f0, alpha, beta, nu, rho, rTS, 30, 800, 30, 1, 0.8))

        calculated = option.NPV()

        self.assertAlmostEqual(calculated, expected, 4,
                               msg="Unable to reproduce Le Floc'h-Kennedy SABR volatility")


    def testSabrPdeVsCevPdeVsAnalyticCev(self):
        """ Testing SABR PDE vs CEV PDE vs Analytic CEV """

        today = ql.Date(1, 3, 2019)
        dc = ql.Actual365Fixed()

        maturityDate = today + ql.Period(12, ql.Months)
        f0 = 1.2
        alpha = 0.35
        beta = 0.9
        nu = 1e-3
        rho = 0.25
        strike = 1.1

        rTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.05, dc))

        option = ql.VanillaOption(
            ql.PlainVanillaPayoff(ql.Option.Call, strike),
            ql.EuropeanExercise(maturityDate))

        option.setPricingEngine(ql.FdSabrVanillaEngine(f0, alpha, beta, nu, rho, rTS, 30, 400, 3))
        fdSabrNPV = option.NPV()

        option.setPricingEngine(ql.FdCEVVanillaEngine(f0, alpha, beta, rTS, 30, 400))
        fdCevNPV = option.NPV()

        option.setPricingEngine(ql.AnalyticCEVEngine(f0, alpha, beta, rTS))
        analyticCevNPV = option.NPV()

        self.assertAlmostEqual(fdSabrNPV, analyticCevNPV, 4,
                               msg="Unable to match PDE SABR value with analytic CEV value")

        self.assertAlmostEqual(fdCevNPV, analyticCevNPV, 4,
                               msg="Unable to match PDE CEV value with analytic CEV value")

if __name__ == '__main__':
    print("testing QuantLib", ql.__version__)
    unittest.main(verbosity=2)