Loading [MathJax]/jax/output/HTML-CSS/config.js
QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
blackswaptionengine.hpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2007 Ferdinando Ametrano
5 Copyright (C) 2001, 2002, 2003 Sadruddin Rejeb
6 Copyright (C) 2006 StatPro Italia srl
7 Copyright (C) 2015, 2016, 2017 Peter Caspers
8 Copyright (C) 2017 Paul Giltinan
9 Copyright (C) 2017 Werner Kuerzinger
10 Copyright (C) 2020 Marcin Rybacki
11
12 This file is part of QuantLib, a free-software/open-source library
13 for financial quantitative analysts and developers - http://quantlib.org/
14
15 QuantLib is free software: you can redistribute it and/or modify it
16 under the terms of the QuantLib license. You should have received a
17 copy of the license along with this program; if not, please email
18 <quantlib-dev@lists.sf.net>. The license is also available online at
19 <http://quantlib.org/license.shtml>.
20
21 This program is distributed in the hope that it will be useful, but WITHOUT
22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
23 FOR A PARTICULAR PURPOSE. See the license for more details.
24*/
25
26/*! \file blackswaptionengine.hpp
27 \brief Black-formula swaption engine
28*/
29
30#ifndef quantlib_pricers_black_swaption_hpp
31#define quantlib_pricers_black_swaption_hpp
32
35#include <ql/exercise.hpp>
43#include <utility>
44
45namespace QuantLib {
46
47 class Quote;
48
49 namespace detail {
50
51 /*! Generic Black-style-formula swaption engine
52 This is the base class for the Black and Bachelier swaption engines */
53 template<class Spec>
55 public:
58 Volatility vol,
59 const DayCounter& dc = Actual365Fixed(),
60 Real displacement = 0.0,
63 const Handle<Quote>& vol,
64 const DayCounter& dc = Actual365Fixed(),
65 Real displacement = 0.0,
70 void calculate() const override;
73
74 private:
78 };
79
80 // shifted lognormal type engine
81 struct Black76Spec {
83 Real value(const Option::Type type, const Real strike,
84 const Real atmForward, const Real stdDev, const Real annuity,
85 const Real displacement) {
86 return blackFormula(type, strike, atmForward, stdDev, annuity,
87 displacement);
88 }
89 Real vega(const Real strike, const Real atmForward, const Real stdDev,
90 const Real exerciseTime, const Real annuity,
91 const Real displacement) {
92 return std::sqrt(exerciseTime) *
93 blackFormulaStdDevDerivative(strike, atmForward, stdDev,
94 annuity, displacement);
95 }
96 Real delta(const Option::Type type, const Real strike,
97 const Real atmForward, const Real stdDev, const Real annuity,
98 const Real displacement) {
99 return blackFormulaForwardDerivative(type, strike, atmForward, stdDev,
100 annuity, displacement);
101 }
102 };
103
104 // normal type engine
106 static constexpr VolatilityType type = Normal;
107 Real value(const Option::Type type, const Real strike,
108 const Real atmForward, const Real stdDev, const Real annuity,
109 const Real) {
110 return bachelierBlackFormula(type, strike, atmForward, stdDev,
111 annuity);
112 }
113 Real vega(const Real strike, const Real atmForward, const Real stdDev,
114 const Real exerciseTime, const Real annuity, const Real) {
115 return std::sqrt(exerciseTime) *
117 strike, atmForward, stdDev, annuity);
118 }
119 Real delta(const Option::Type type, const Real strike,
120 const Real atmForward, const Real stdDev, const Real annuity,
121 const Real) {
123 type, strike, atmForward, stdDev, annuity);
124 }
125 };
126
127 } // namespace detail
128
129 //! Shifted Lognormal Black-formula swaption engine
130 /*! \ingroup swaptionengines
131
132 \warning The engine assumes that the exercise date lies before the
133 start date of the passed swap.
134 */
135
137 : public detail::BlackStyleSwaptionEngine<detail::Black76Spec> {
138 public:
140 Volatility vol,
141 const DayCounter& dc = Actual365Fixed(),
142 Real displacement = 0.0,
145 const Handle<Quote>& vol,
146 const DayCounter& dc = Actual365Fixed(),
147 Real displacement = 0.0,
152 };
153
154 //! Normal Bachelier-formula swaption engine
155 /*! \ingroup swaptionengines
156
157 \warning The engine assumes that the exercise date lies before the
158 start date of the passed swap.
159 */
160
162 : public detail::BlackStyleSwaptionEngine<detail::BachelierSpec> {
163 public:
165 Volatility vol,
166 const DayCounter& dc = Actual365Fixed(),
169 const Handle<Quote>& vol,
170 const DayCounter& dc = Actual365Fixed(),
175 };
176
177 // implementation
178
179 namespace detail {
180
181 template <class Spec>
183 Handle<YieldTermStructure> discountCurve,
184 Volatility vol,
185 const DayCounter& dc,
186 Real displacement,
187 CashAnnuityModel model)
188 : discountCurve_(std::move(discountCurve)),
190 0, NullCalendar(), Following, vol, dc, Spec().type, displacement))),
191 model_(model) {
193 }
194
195 template <class Spec>
197 Handle<YieldTermStructure> discountCurve,
198 const Handle<Quote>& vol,
199 const DayCounter& dc,
200 Real displacement,
201 CashAnnuityModel model)
202 : discountCurve_(std::move(discountCurve)),
204 0, NullCalendar(), Following, vol, dc, Spec().type, displacement))),
205 model_(model) {
208 }
209
210 template <class Spec>
212 Handle<YieldTermStructure> discountCurve,
214 CashAnnuityModel model)
215 : discountCurve_(std::move(discountCurve)), vol_(std::move(volatility)), model_(model) {
218 }
219
220 template<class Spec>
222 static const Spread basisPoint = 1.0e-4;
223
224 QL_REQUIRE(arguments_.exercise->type() == Exercise::European,
225 "not a European option");
226
227 Date exerciseDate = arguments_.exercise->date(0);
228
229 // The part of the swap preceding exerciseDate should be truncated to avoid taking into
230 // account unwanted cashflows. For the moment we add a check avoiding this situation.
231 // Furthermore, we take a copy of the underlying swap. This avoids notifying the swaption
232 // when we set a pricing engine on the swap below.
233 auto swap = arguments_.swap;
234
235 const Leg& fixedLeg = swap->fixedLeg();
236 ext::shared_ptr<FixedRateCoupon> firstCoupon =
237 ext::dynamic_pointer_cast<FixedRateCoupon>(fixedLeg[0]);
238 QL_REQUIRE(firstCoupon->accrualStartDate() >= exerciseDate,
239 "swap start (" << firstCoupon->accrualStartDate() << ") before exercise date ("
240 << exerciseDate << ") not supported in Black swaption engine");
241
242 Rate strike = swap->fixedRate();
243
244 // using the discounting curve
245 // swap.iborIndex() might be using a different forwarding curve
246 auto engine = ext::make_shared<DiscountingSwapEngine>(discountCurve_, false);
248 swap->setPricingEngine(engine);
250 Date valuation_date = results_.valuationDate = swap->valuationDate();
251 Rate atmForward = swap->fairRate();
252
253 // Volatilities are quoted for zero-spreaded swaps.
254 // Therefore, any spread on the floating leg must be removed
255 // with a corresponding correction on the fixed leg.
256 Real spread = swap->spread();
257 if (spread!=0.0) {
258 Spread correction =
259 spread * std::fabs(swap->floatingLegBPS() / swap->fixedLegBPS());
260 strike -= correction;
261 atmForward -= correction;
262 results_.additionalResults["spreadCorrection"] = correction;
263 } else {
264 results_.additionalResults["spreadCorrection"] = Real(0.0);
265 }
266 results_.additionalResults["strike"] = strike;
267 results_.additionalResults["atmForward"] = atmForward;
268
269 Real annuity;
270 if (arguments_.settlementType == Settlement::Physical ||
271 (arguments_.settlementType == Settlement::Cash &&
272 arguments_.settlementMethod ==
274 annuity = std::fabs(swap->fixedLegBPS()) / basisPoint;
275 } else if (arguments_.settlementType == Settlement::Cash &&
276 arguments_.settlementMethod == Settlement::ParYieldCurve) {
277 DayCounter dayCount = firstCoupon->dayCounter();
278 // we assume that the cash settlement date is equal
279 // to the swap start date
280 Date discountDate = model_ == DiscountCurve
281 ? firstCoupon->accrualStartDate()
282 : valuation_date;
283 Frequency freq = Annual;
284 const Schedule& fixedSchedule = swap->fixedSchedule();
285 if (fixedSchedule.hasTenor()) {
286 freq = fixedSchedule.tenor().frequency();
287 }
288 Real fixedLegCashBPS =
289 CashFlows::bps(fixedLeg,
290 InterestRate(atmForward, dayCount, Compounded, freq),
291 false, discountDate);
292 annuity = std::fabs(fixedLegCashBPS / basisPoint) *
293 discountCurve_->discount(discountDate);
294 } else {
295 QL_FAIL("invalid (settlementType, settlementMethod) pair");
296 }
297 results_.additionalResults["annuity"] = annuity;
298
299 const Schedule& floatingSchedule = swap->floatingSchedule();
300 Time swapLength = vol_->swapLength(floatingSchedule.dates().front(),
301 floatingSchedule.dates().back());
302
303 // swapLength is rounded to whole months. To ensure we can read a variance
304 // and a shift from vol_ we floor swapLength at 1/12 here therefore.
305 swapLength = std::max(swapLength, 1.0 / 12.0);
306 results_.additionalResults["swapLength"] = swapLength;
307
308 Real variance = vol_->blackVariance(exerciseDate, swapLength, strike);
309
310 Real displacement =
311 vol_->volatilityType() == ShiftedLognormal ?
312 vol_->shift(exerciseDate, swapLength) : 0.0;
313
314 Real stdDev = std::sqrt(variance);
315 results_.additionalResults["stdDev"] = stdDev;
317 results_.value = Spec().value(w, strike, atmForward, stdDev, annuity, displacement);
318
319 Time exerciseTime = vol_->timeFromReference(exerciseDate);
320 results_.additionalResults["vega"] = Spec().vega(
321 strike, atmForward, stdDev, exerciseTime, annuity, displacement);
322 results_.additionalResults["delta"] = Spec().delta(
323 w, strike, atmForward, stdDev, annuity, displacement);
324 results_.additionalResults["timeToExpiry"] = exerciseTime;
325 results_.additionalResults["impliedVolatility"] = Real(stdDev / std::sqrt(exerciseTime));
326 results_.additionalResults["forwardPrice"] = Real(results_.value / discountCurve_->discount(exerciseDate));
327 }
328
329 } // namespace detail
330
331}
332
333#endif
Black formula.
const YieldTermStructure & discountCurve_
Definition: cashflows.cpp:418
Cash-flow analysis functions.
ext::shared_ptr< SimpleQuote > vol_
Definition: cdsoption.cpp:62
const Instrument::results * results_
Definition: cdsoption.cpp:63
Actual/365 (Fixed) day count convention.
Normal Bachelier-formula swaption engine.
Shifted Lognormal Black-formula swaption engine.
static Real bps(const Leg &leg, const YieldTermStructure &discountCurve, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date())
Basis-point sensitivity of the cash flows.
Definition: cashflows.cpp:450
Constant swaption volatility, no time-strike dependence.
Concrete date class.
Definition: date.hpp:125
day counter class
Definition: daycounter.hpp:44
Shared handle to an observable.
Definition: handle.hpp:41
Concrete interest rate class.
YieldTermStructure based on interpolation of discount factors.
Calendar for reproducing theoretical calculations.
void disableUpdates(bool deferred=false)
Definition: observable.hpp:91
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:226
Frequency frequency() const
Definition: period.cpp:69
Payment schedule.
Definition: schedule.hpp:40
const std::vector< Date > & dates() const
Definition: schedule.hpp:73
bool hasTenor() const
Definition: schedule.hpp:198
const Period & tenor() const
Definition: schedule.hpp:202
static ObservableSettings & instance()
access to the unique instance
Definition: singleton.hpp:104
base class for swaption engines
Definition: swaption.hpp:152
BlackStyleSwaptionEngine(Handle< YieldTermStructure > discountCurve, Volatility vol, const DayCounter &dc=Actual365Fixed(), Real displacement=0.0, CashAnnuityModel model=DiscountCurve)
Handle< SwaptionVolatilityStructure > volatility()
BlackStyleSwaptionEngine(Handle< YieldTermStructure > discountCurve, const Handle< Quote > &vol, const DayCounter &dc=Actual365Fixed(), Real displacement=0.0, CashAnnuityModel model=DiscountCurve)
BlackStyleSwaptionEngine(Handle< YieldTermStructure > discountCurve, Handle< SwaptionVolatilityStructure > vol, CashAnnuityModel model=DiscountCurve)
Handle< SwaptionVolatilityStructure > vol_
Handle< YieldTermStructure > termStructure()
discounting swap engine
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Definition: errors.hpp:92
Option exercise classes and payoff function.
LinearInterpolation variance
Coupon paying a fixed annual rate.
Frequency
Frequency of events.
Definition: frequency.hpp:37
@ Annual
once a year
Definition: frequency.hpp:39
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
Real Volatility
volatility
Definition: types.hpp:78
Real Spread
spreads on interest rates
Definition: types.hpp:74
Real Rate
interest rates
Definition: types.hpp:70
base class for Inter-Bank-Offered-Rate indexes
Definition: any.hpp:37
Real bachelierBlackFormulaStdDevDerivative(Rate strike, Rate forward, Real stdDev, Real discount)
Real bachelierBlackFormula(Option::Type optionType, Real strike, Real forward, Real stdDev, Real discount)
void swap(Array &v, Array &w) noexcept
Definition: array.hpp:891
Real blackFormulaForwardDerivative(Option::Type optionType, Real strike, Real forward, Real stdDev, Real discount, Real displacement)
Real bachelierBlackFormulaForwardDerivative(Option::Type optionType, Real strike, Real forward, Real stdDev, Real discount)
Real blackFormula(Option::Type optionType, Real strike, Real forward, Real stdDev, Real discount, Real displacement)
Real blackFormulaStdDevDerivative(Rate strike, Rate forward, Real stdDev, Real discount, Real displacement)
std::vector< ext::shared_ptr< CashFlow > > Leg
Sequence of cash-flows.
Definition: cashflow.hpp:78
STL namespace.
Calendar for reproducing theoretical calculations.
Real vega(const Real strike, const Real atmForward, const Real stdDev, const Real exerciseTime, const Real annuity, const Real)
Real value(const Option::Type type, const Real strike, const Real atmForward, const Real stdDev, const Real annuity, const Real)
Real delta(const Option::Type type, const Real strike, const Real atmForward, const Real stdDev, const Real annuity, const Real)
static constexpr VolatilityType type
Real value(const Option::Type type, const Real strike, const Real atmForward, const Real stdDev, const Real annuity, const Real displacement)
Real vega(const Real strike, const Real atmForward, const Real stdDev, const Real exerciseTime, const Real annuity, const Real displacement)
static constexpr VolatilityType type
Real delta(const Option::Type type, const Real strike, const Real atmForward, const Real stdDev, const Real annuity, const Real displacement)
Swaption class.
Constant swaption volatility.
Swaption volatility structure.