QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
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 const 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 Date exerciseDate = arguments_.exercise->date(0);
225
226 // The part of the swap preceding exerciseDate should be truncated to avoid taking into
227 // account unwanted cashflows. For the moment we add a check avoiding this situation.
228 // Furthermore, we take a copy of the underlying swap. This avoids notifying the swaption
229 // when we set a pricing engine on the swap below.
230 auto swap = arguments_.swap;
231
232 const Leg& fixedLeg = swap->fixedLeg();
233 ext::shared_ptr<FixedRateCoupon> firstCoupon =
234 ext::dynamic_pointer_cast<FixedRateCoupon>(fixedLeg[0]);
235 QL_REQUIRE(firstCoupon->accrualStartDate() >= exerciseDate,
236 "swap start (" << firstCoupon->accrualStartDate() << ") before exercise date ("
237 << exerciseDate << ") not supported in Black swaption engine");
238
239 Rate strike = swap->fixedRate();
240
241 // using the discounting curve
242 // swap.iborIndex() might be using a different forwarding curve
243 auto engine = ext::make_shared<DiscountingSwapEngine>(discountCurve_, false);
245 swap->setPricingEngine(engine);
247 Date valuation_date = results_.valuationDate = swap->valuationDate();
248 Rate atmForward = swap->fairRate();
249
250 // Volatilities are quoted for zero-spreaded swaps.
251 // Therefore, any spread on the floating leg must be removed
252 // with a corresponding correction on the fixed leg.
253 Real spread = swap->spread();
254 if (spread!=0.0) {
255 Spread correction =
256 spread * std::fabs(swap->floatingLegBPS() / swap->fixedLegBPS());
257 strike -= correction;
258 atmForward -= correction;
259 results_.additionalResults["spreadCorrection"] = correction;
260 } else {
261 results_.additionalResults["spreadCorrection"] = Real(0.0);
262 }
263 results_.additionalResults["strike"] = strike;
264 results_.additionalResults["atmForward"] = atmForward;
265
266 Real annuity;
267 if (arguments_.settlementType == Settlement::Physical ||
268 (arguments_.settlementType == Settlement::Cash &&
269 arguments_.settlementMethod ==
271 annuity = std::fabs(swap->fixedLegBPS()) / basisPoint;
272 } else if (arguments_.settlementType == Settlement::Cash &&
273 arguments_.settlementMethod == Settlement::ParYieldCurve) {
274 DayCounter dayCount = firstCoupon->dayCounter();
275 // we assume that the cash settlement date is equal
276 // to the swap start date
277 Date discountDate = model_ == DiscountCurve
278 ? firstCoupon->accrualStartDate()
279 : valuation_date;
280 Frequency freq = Annual;
281 const Schedule& fixedSchedule = swap->fixedSchedule();
282 if (fixedSchedule.hasTenor()) {
283 freq = fixedSchedule.tenor().frequency();
284 }
285 Real fixedLegCashBPS =
286 CashFlows::bps(fixedLeg,
287 InterestRate(atmForward, dayCount, Compounded, freq),
288 false, discountDate);
289 annuity = std::fabs(fixedLegCashBPS / basisPoint) *
290 discountCurve_->discount(discountDate);
291 } else {
292 QL_FAIL("invalid (settlementType, settlementMethod) pair");
293 }
294 results_.additionalResults["annuity"] = annuity;
295
296 const Schedule& floatingSchedule = swap->floatingSchedule();
297 Time swapLength = vol_->swapLength(floatingSchedule.dates().front(),
298 floatingSchedule.dates().back());
299
300 // swapLength is rounded to whole months. To ensure we can read a variance
301 // and a shift from vol_ we floor swapLength at 1/12 here therefore.
302 swapLength = std::max(swapLength, 1.0 / 12.0);
303 results_.additionalResults["swapLength"] = swapLength;
304
305 Real variance = vol_->blackVariance(exerciseDate, swapLength, strike);
306
307 Real displacement =
308 vol_->volatilityType() == ShiftedLognormal ?
309 vol_->shift(exerciseDate, swapLength) : 0.0;
310
311 Real stdDev = std::sqrt(variance);
312 results_.additionalResults["stdDev"] = stdDev;
314 results_.value = Spec().value(w, strike, atmForward, stdDev, annuity, displacement);
315
316 Time exerciseTime = vol_->timeFromReference(exerciseDate);
317 results_.additionalResults["vega"] = Spec().vega(
318 strike, atmForward, stdDev, exerciseTime, annuity, displacement);
319 results_.additionalResults["delta"] = Spec().delta(
320 w, strike, atmForward, stdDev, annuity, displacement);
321 results_.additionalResults["timeToExpiry"] = exerciseTime;
322 results_.additionalResults["impliedVolatility"] = Real(stdDev / std::sqrt(exerciseTime));
323 }
324
325 } // namespace detail
326
327}
328
329#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:228
Frequency frequency() const
Definition: period.cpp:69
Payment schedule.
Definition: schedule.hpp:40
const std::vector< Date > & dates() const
Definition: schedule.hpp:75
bool hasTenor() const
Definition: schedule.hpp:186
const Period & tenor() const
Definition: schedule.hpp:190
static ObservableSettings & instance()
access to the unique instance
Definition: singleton.hpp:104
base class for swaption engines
Definition: swaption.hpp:158
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:35
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:903
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 const 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 const 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.