File: implied_volatility.rb

package info (click to toggle)
quantlib-ruby 0.2.1.cvs20020322-1
  • links: PTS
  • area: main
  • in suites: woody
  • size: 972 kB
  • ctags: 1,309
  • sloc: cpp: 16,141; ruby: 2,578; makefile: 59
file content (123 lines) | stat: -rw-r--r-- 4,143 bytes parent folder | download
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
121
122
123
=begin
 Copyright (C) 2000, 2001, 2002 RiskMap srl

 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 ferdinando@ametrano.net
 The license is also available online at http://quantlib.org/html/license.html

 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.
=end

# $Id: implied_volatility.rb,v 1.4 2002/01/16 15:17:06 nando Exp $

require 'QuantLib'
require 'runit/testcase'
require 'runit/testsuite'
require 'runit/cui/testrunner'

def pricer(type,underlying,strike,divCurve,rfCurve,exDate,volatility)
    QuantLib::PlainOption.new(type,underlying,strike,divCurve,rfCurve,
        exDate,volatility,QuantLib::EuropeanEngine.new)
end

def quote(value)
    h = QuantLib::MarketElementHandle.new
    h.linkTo QuantLib::SimpleMarketElement.new(value)
    return h
end

def flatCurve(forward)
    h = QuantLib::TermStructureHandle.new
    h.linkTo QuantLib::FlatForward.new('EUR',
                                       QuantLib::DayCounter.new('act/360'),
                                       QuantLib::Date.new(12,10,2001),
                                       QuantLib::Calendar.new('TARGET'), 2,
                                       forward)
    return h
end


class ImpliedVolatilityTest < RUNIT::TestCase
    include QuantLib
    def name
        "Testing implied volatility calculation..."
    end
    def test
        maxEval = 100
        tol = 1.0e-6

        [0.01, 0.05, 0.10].each { |qRate|
            divCurve = flatCurve(qRate)

        [0.01, 0.05, 0.10].each { |rRate|
            rfCurve  = flatCurve(rRate)

        [0.01, 0.2, 0.3, 0.7, 0.9].each { |vol|
            volatility = quote(vol)

        [80, 95, 99.9, 100, 100.1, 105, 120].each { |under|
            underlying = quote(under)

        [1,36,180,360,1080].each { |days|
            exDate = Date.new(16,10,2001) + days

        [50, 99.5, 100, 100.5, 150].each { |strike|
        ['Call','Put','Straddle'].each   { |type|

            bsm = pricer(type,underlying,strike,
                         divCurve,rfCurve,exDate,volatility)
            bsmValue = bsm.NPV
            next if bsmValue == 0.0

        [0.5, 0.999, 1.0, 1.001, 1.5].each { |dVol|
            volatility2 = quote(vol*dVol)
            bsm2 = pricer(type,underlying,strike,
                          divCurve,rfCurve,exDate,volatility2)
            begin
                implVol = bsm2.impliedVolatility(bsmValue,tol,maxEval)
            rescue StandardError => e
                assert_fail(<<-MESSAGE

    Exception: #{e}
    Option details: #{type} #{under} #{strike} #{qRate} #{rRate} #{days}
        volatility:   #{vol*dVol}
        option value: #{bsm2.NPV}
        while trying to calculate implied vol from value #{bsmValue}

                    MESSAGE
                )
            end

            if (implVol-vol).abs > tol
                volatility3 = quote(vol*dVol)
                bsm3 = pricer(type,underlying,strike,
                              divCurve,rfCurve,exDate,volatility3)
                bsm3Value = bsm3.NPV
                unless (bsm3Value-bsmValue).abs/under <= 1.0e-3
                    assert_fail(<<-MESSAGE

    Option details: #{type} #{under} #{strike} #{qRate} #{rRate} #{days}
        at #{vol} vol the option value is #{bsmValue}
        at #{vol+dVol} vol the option value is #{bsm2.NPV}
        at #{bsmValue} value the implied vol is #{implVol}
        at #{implVol} vol the option value is #{bsm3value}
        which is #{(bsm3Value - bsmValue)} above target value

                        MESSAGE
                    )
                end
            end
        }}}}}}}}
    end
end

if $0 == __FILE__
    RUNIT::CUI::TestRunner.run(ImpliedVolatilityTest.suite)
end