1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2001, 2002, 2003 Sadruddin Rejeb
5 Copyright (C) 2006 Cristina Duminuco
6 Copyright (C) 2006 Marco Bianchetti
7 Copyright (C) 2007 StatPro Italia srl
8 Copyright (C) 2014 Ferdinando Ametrano
9 Copyright (C) 2016, 2018 Peter Caspers
10
11 This file is part of QuantLib, a free-software/open-source library
12 for financial quantitative analysts and developers - http://quantlib.org/
13
14 QuantLib is free software: you can redistribute it and/or modify it
15 under the terms of the QuantLib license. You should have received a
16 copy of the license along with this program; if not, please email
17 <quantlib-dev@lists.sf.net>. The license is also available online at
18 <http://quantlib.org/license.shtml>.
19
20 This program is distributed in the hope that it will be useful, but WITHOUT
21 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22 FOR A PARTICULAR PURPOSE. See the license for more details.
23*/
24
25#include <ql/any.hpp>
26#include <ql/exercise.hpp>
27#include <ql/instruments/swaption.hpp>
28#include <ql/math/solvers1d/newtonsafe.hpp>
29#include <ql/pricingengines/swaption/blackswaptionengine.hpp>
30#include <ql/quotes/simplequote.hpp>
31#include <ql/shared_ptr.hpp>
32#include <utility>
33
34namespace QuantLib {
35
36 namespace {
37
38 class ImpliedSwaptionVolHelper {
39 public:
40 ImpliedSwaptionVolHelper(const Swaption&,
41 Handle<YieldTermStructure> discountCurve,
42 Real targetValue,
43 Real displacement,
44 VolatilityType type);
45 Real operator()(Volatility x) const;
46 Real derivative(Volatility x) const;
47 private:
48 ext::shared_ptr<PricingEngine> engine_;
49 Handle<YieldTermStructure> discountCurve_;
50 Real targetValue_;
51 ext::shared_ptr<SimpleQuote> vol_;
52 const Instrument::results* results_;
53 };
54
55 ImpliedSwaptionVolHelper::ImpliedSwaptionVolHelper(const Swaption& swaption,
56 Handle<YieldTermStructure> discountCurve,
57 Real targetValue,
58 Real displacement,
59 VolatilityType type)
60 : discountCurve_(std::move(discountCurve)), targetValue_(targetValue),
61 vol_(ext::make_shared<SimpleQuote>(args: -1.0)) {
62
63 // vol_ is set an implausible value, so that calculation is forced
64 // at first ImpliedSwaptionVolHelper::operator()(Volatility x) call
65
66 Handle<Quote> h(vol_);
67
68 switch (type) {
69 case ShiftedLognormal:
70 engine_ = ext::make_shared<BlackSwaptionEngine>(
71 args&: discountCurve_, args&: h, args: Actual365Fixed(), args&: displacement);
72 break;
73 case Normal:
74 engine_ = ext::make_shared<BachelierSwaptionEngine>(
75 args&: discountCurve_, args&: h, args: Actual365Fixed());
76 break;
77 default:
78 QL_FAIL("unknown VolatilityType (" << type << ")");
79 break;
80 }
81 swaption.setupArguments(engine_->getArguments());
82 results_ = dynamic_cast<const Instrument::results *>(
83 engine_->getResults());
84 }
85
86 Real ImpliedSwaptionVolHelper::operator()(Volatility x) const {
87 if (x!=vol_->value()) {
88 vol_->setValue(x);
89 engine_->calculate();
90 }
91 return results_->value-targetValue_;
92 }
93
94 Real ImpliedSwaptionVolHelper::derivative(Volatility x) const {
95 if (x!=vol_->value()) {
96 vol_->setValue(x);
97 engine_->calculate();
98 }
99 auto vega_ = results_->additionalResults.find(x: "vega");
100 QL_REQUIRE(vega_ != results_->additionalResults.end(),
101 "vega not provided");
102 return ext::any_cast<Real>(operand: vega_->second);
103 }
104 }
105
106 std::ostream& operator<<(std::ostream& out,
107 Settlement::Type t) {
108 switch (t) {
109 case Settlement::Physical:
110 return out << "Delivery";
111 case Settlement::Cash:
112 return out << "Cash";
113 default:
114 QL_FAIL("unknown Settlement::Type(" << Integer(t) << ")");
115 }
116 }
117
118 std::ostream& operator<<(std::ostream& out, Settlement::Method m) {
119 switch (m) {
120 case Settlement::PhysicalOTC:
121 return out << "PhysicalOTC";
122 case Settlement::PhysicalCleared:
123 return out << "PhysicalCleared";
124 case Settlement::CollateralizedCashPrice:
125 return out << "CollateralizedCashPrice";
126 case Settlement::ParYieldCurve:
127 return out << "ParYieldCurve";
128 default:
129 QL_FAIL("unknown Settlement::Method(" << Integer(m) << ")");
130 }
131 }
132
133 Swaption::Swaption(ext::shared_ptr<VanillaSwap> swap,
134 const ext::shared_ptr<Exercise>& exercise,
135 Settlement::Type delivery,
136 Settlement::Method settlementMethod)
137 : Option(ext::shared_ptr<Payoff>(), exercise), swap_(std::move(swap)),
138 settlementType_(delivery), settlementMethod_(settlementMethod) {
139 registerWith(h: swap_);
140 // When we ask for the NPV of an expired swaption, the
141 // swap is not recalculated and thus wouldn't forward
142 // later notifications according to the default behavior of
143 // LazyObject instances. This means that even if the
144 // evaluation date changes so that the swaption is no longer
145 // expired, the instrument wouldn't be notified and thus it
146 // wouldn't recalculate. To avoid this, we override the
147 // default behavior of the underlying swap.
148 swap_->alwaysForwardNotifications();
149 }
150
151 void Swaption::deepUpdate() {
152 swap_->deepUpdate();
153 update();
154 }
155
156 bool Swaption::isExpired() const {
157 return detail::simple_event(exercise_->dates().back()).hasOccurred();
158 }
159
160 void Swaption::setupArguments(PricingEngine::arguments* args) const {
161
162 swap_->setupArguments(args);
163
164 auto* arguments = dynamic_cast<Swaption::arguments*>(args);
165
166 QL_REQUIRE(arguments != nullptr, "wrong argument type");
167
168 arguments->swap = swap_;
169 arguments->settlementType = settlementType_;
170 arguments->settlementMethod = settlementMethod_;
171 arguments->exercise = exercise_;
172 }
173
174 void Swaption::arguments::validate() const {
175 VanillaSwap::arguments::validate();
176 QL_REQUIRE(swap, "vanilla swap not set");
177 QL_REQUIRE(exercise, "exercise not set");
178 Settlement::checkTypeAndMethodConsistency(settlementType,
179 settlementMethod);
180 }
181
182 Volatility Swaption::impliedVolatility(Real targetValue,
183 const Handle<YieldTermStructure>& d,
184 Volatility guess,
185 Real accuracy,
186 Natural maxEvaluations,
187 Volatility minVol,
188 Volatility maxVol,
189 VolatilityType type,
190 Real displacement) const {
191 //calculate();
192 QL_REQUIRE(!isExpired(), "instrument expired");
193
194 ImpliedSwaptionVolHelper f(*this, d, targetValue, displacement, type);
195 //Brent solver;
196 NewtonSafe solver;
197 solver.setMaxEvaluations(maxEvaluations);
198 return solver.solve(f, accuracy, guess, xMin: minVol, xMax: maxVol);
199 }
200
201 void Settlement::checkTypeAndMethodConsistency(
202 Settlement::Type settlementType,
203 Settlement::Method settlementMethod) {
204 if (settlementType == Physical) {
205 QL_REQUIRE(settlementMethod == PhysicalOTC ||
206 settlementMethod == PhysicalCleared,
207 "invalid settlement method for physical settlement");
208 }
209 if (settlementType == Cash) {
210 QL_REQUIRE(settlementMethod == CollateralizedCashPrice ||
211 settlementMethod == ParYieldCurve,
212 "invalid settlement method for cash settlement");
213 }
214 }
215
216}
217

source code of quantlib/ql/instruments/swaption.cpp

Morty Proxy This is a proxified and sanitized view of the page, visit original site.