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
|