QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
blackswaptionengine.hpp
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
30#ifndef quantlib_pricers_black_swaption_hpp
31#define quantlib_pricers_black_swaption_hpp
32
33#include <ql/cashflows/cashflows.hpp>
34#include <ql/cashflows/fixedratecoupon.hpp>
35#include <ql/exercise.hpp>
36#include <ql/indexes/iborindex.hpp>
37#include <ql/instruments/swaption.hpp>
38#include <ql/pricingengines/blackformula.hpp>
39#include <ql/pricingengines/swap/discountingswapengine.hpp>
40#include <ql/termstructures/volatility/swaption/swaptionconstantvol.hpp>
41#include <ql/termstructures/volatility/swaption/swaptionvolstructure.hpp>
42#include <ql/time/calendars/nullcalendar.hpp>
43#include <utility>
44
45namespace QuantLib {
46
47 class Quote;
48
49 namespace detail {
50
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
130
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
155
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
227 // to avoid taking into account unwanted cashflows
228 // for the moment we add a check avoiding this situation
229 VanillaSwap swap = *arguments_.swap;
230 const Leg& fixedLeg = swap.fixedLeg();
231 ext::shared_ptr<FixedRateCoupon> firstCoupon =
232 ext::dynamic_pointer_cast<FixedRateCoupon>(fixedLeg[0]);
233 QL_REQUIRE(firstCoupon->accrualStartDate() >= exerciseDate,
234 "swap start (" << firstCoupon->accrualStartDate() << ") before exercise date ("
235 << exerciseDate << ") not supported in Black swaption engine");
236
237 Rate strike = swap.fixedRate();
238
239 // using the discounting curve
240 // swap.iborIndex() might be using a different forwarding curve
241 swap.setPricingEngine(ext::shared_ptr<PricingEngine>(new
242 DiscountingSwapEngine(discountCurve_, false)));
243 Rate atmForward = swap.fairRate();
244
245 // Volatilities are quoted for zero-spreaded swaps.
246 // Therefore, any spread on the floating leg must be removed
247 // with a corresponding correction on the fixed leg.
248 if (swap.spread()!=0.0) {
249 Spread correction = swap.spread() *
250 std::fabs(swap.floatingLegBPS()/swap.fixedLegBPS());
251 strike -= correction;
252 atmForward -= correction;
253 results_.additionalResults["spreadCorrection"] = correction;
254 } else {
255 results_.additionalResults["spreadCorrection"] = Real(0.0);
256 }
257 results_.additionalResults["strike"] = strike;
258 results_.additionalResults["atmForward"] = atmForward;
259
260 // using the discounting curve
261 swap.setPricingEngine(ext::shared_ptr<PricingEngine>(
262 new DiscountingSwapEngine(discountCurve_, false)));
263 Real annuity;
264 if (arguments_.settlementType == Settlement::Physical ||
265 (arguments_.settlementType == Settlement::Cash &&
266 arguments_.settlementMethod ==
268 annuity = std::fabs(swap.fixedLegBPS()) / basisPoint;
269 } else if (arguments_.settlementType == Settlement::Cash &&
270 arguments_.settlementMethod == Settlement::ParYieldCurve) {
271 DayCounter dayCount = firstCoupon->dayCounter();
272 // we assume that the cash settlement date is equal
273 // to the swap start date
274 Date discountDate = model_ == DiscountCurve
275 ? firstCoupon->accrualStartDate()
276 : discountCurve_->referenceDate();
277 Real fixedLegCashBPS = CashFlows::bps(
278 fixedLeg,
279 InterestRate(atmForward, dayCount, Compounded, Annual), false,
280 discountDate);
281 annuity = std::fabs(fixedLegCashBPS / basisPoint) *
282 discountCurve_->discount(discountDate);
283 } else {
284 QL_FAIL("invalid (settlementType, settlementMethod) pair");
285 }
286 results_.additionalResults["annuity"] = annuity;
287
288 Time swapLength = vol_->swapLength(swap.floatingSchedule().dates().front(),
289 swap.floatingSchedule().dates().back());
290
291 // swapLength is rounded to whole months. To ensure we can read a variance
292 // and a shift from vol_ we floor swapLength at 1/12 here therefore.
293 swapLength = std::max(swapLength, 1.0 / 12.0);
294 results_.additionalResults["swapLength"] = swapLength;
295
296 Real variance = vol_->blackVariance(exerciseDate, swapLength, strike);
297
298 Real displacement =
299 vol_->volatilityType() == ShiftedLognormal ?
300 vol_->shift(exerciseDate, swapLength) : 0.0;
301
302 Real stdDev = std::sqrt(variance);
303 results_.additionalResults["stdDev"] = stdDev;
304 Option::Type w = (arguments_.type==Swap::Payer) ? Option::Call : Option::Put;
305 results_.value = Spec().value(w, strike, atmForward, stdDev, annuity, displacement);
306
307 Time exerciseTime = vol_->timeFromReference(exerciseDate);
308 results_.additionalResults["vega"] = Spec().vega(
309 strike, atmForward, stdDev, exerciseTime, annuity, displacement);
310 results_.additionalResults["delta"] = Spec().delta(
311 w, strike, atmForward, stdDev, annuity, displacement);
312 results_.additionalResults["timeToExpiry"] = exerciseTime;
313 results_.additionalResults["impliedVolatility"] = Real(stdDev / std::sqrt(exerciseTime));
314 }
315
316 } // namespace detail
317
318}
319
320#endif
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.
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:228
base class for swaption engines
Definition: swaption.hpp:141
Plain-vanilla swap: fix vs ibor leg.
Definition: vanillaswap.hpp:65
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()
@ 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
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.
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)