QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
capfloor.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2006, 2014 Ferdinando Ametrano
5 Copyright (C) 2006 François du Vignaud
6 Copyright (C) 2001, 2002, 2003 Sadruddin Rejeb
7 Copyright (C) 2006, 2007 StatPro Italia srl
8 Copyright (C) 2016 Paolo Mazzocchi
9
10 This file is part of QuantLib, a free-software/open-source library
11 for financial quantitative analysts and developers - http://quantlib.org/
12
13 QuantLib is free software: you can redistribute it and/or modify it
14 under the terms of the QuantLib license. You should have received a
15 copy of the license along with this program; if not, please email
16 <quantlib-dev@lists.sf.net>. The license is also available online at
17 <http://quantlib.org/license.shtml>.
18
19 This program is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21 FOR A PARTICULAR PURPOSE. See the license for more details.
22*/
23
24#include <ql/any.hpp>
25#include <ql/cashflows/cashflows.hpp>
26#include <ql/instruments/capfloor.hpp>
27#include <ql/math/solvers1d/newtonsafe.hpp>
28#include <ql/pricingengines/capfloor/bacheliercapfloorengine.hpp>
29#include <ql/pricingengines/capfloor/blackcapfloorengine.hpp>
30#include <ql/quotes/simplequote.hpp>
31#include <ql/termstructures/yieldtermstructure.hpp>
32#include <ql/utilities/dataformatters.hpp>
33#include <utility>
34
35namespace QuantLib {
36
37 namespace {
38
39 class ImpliedCapVolHelper {
40 public:
41 ImpliedCapVolHelper(const CapFloor&,
42 Handle<YieldTermStructure> discountCurve,
43 Real targetValue,
44 Real displacement,
45 VolatilityType type);
46 Real operator()(Volatility x) const;
47 Real derivative(Volatility x) const;
48 private:
49 ext::shared_ptr<PricingEngine> engine_;
50 Handle<YieldTermStructure> discountCurve_;
51 Real targetValue_;
52 ext::shared_ptr<SimpleQuote> vol_;
53 const Instrument::results* results_;
54 };
55
56 ImpliedCapVolHelper::ImpliedCapVolHelper(const CapFloor& cap,
57 Handle<YieldTermStructure> discountCurve,
58 Real targetValue,
59 Real displacement,
60 VolatilityType type)
61 : discountCurve_(std::move(discountCurve)), targetValue_(targetValue),
62 vol_(ext::make_shared<SimpleQuote>(-1.0)) {
63
64 // vol_ is set an implausible value, so that calculation is forced
65 // at first ImpliedCapVolHelper::operator()(Volatility x) call
66 Handle<Quote> h(vol_);
67
68 switch (type) {
70 engine_ = ext::shared_ptr<PricingEngine>(new
71 BlackCapFloorEngine(discountCurve_, h, Actual365Fixed(),
72 displacement));
73 break;
74 case Normal:
75 engine_ = ext::shared_ptr<PricingEngine>(new
76 BachelierCapFloorEngine(discountCurve_, h,
77 Actual365Fixed()));
78 break;
79 default:
80 QL_FAIL("unknown VolatilityType (" << type << ")");
81 break;
82 }
83
84 cap.setupArguments(engine_->getArguments());
85
86 results_ =
87 dynamic_cast<const Instrument::results*>(engine_->getResults());
88 }
89
90 Real ImpliedCapVolHelper::operator()(Volatility x) const {
91 if (x!=vol_->value()) {
92 vol_->setValue(x);
93 engine_->calculate();
94 }
95 return results_->value-targetValue_;
96 }
97
98 Real ImpliedCapVolHelper::derivative(Volatility x) const {
99 if (x!=vol_->value()) {
100 vol_->setValue(x);
101 engine_->calculate();
102 }
103 auto vega_ = results_->additionalResults.find("vega");
104 QL_REQUIRE(vega_ != results_->additionalResults.end(),
105 "vega not provided");
106 return ext::any_cast<Real>(vega_->second);
107 }
108 }
109
110 std::ostream& operator<<(std::ostream& out,
111 CapFloor::Type t) {
112 switch (t) {
113 case CapFloor::Cap:
114 return out << "Cap";
115 case CapFloor::Floor:
116 return out << "Floor";
117 case CapFloor::Collar:
118 return out << "Collar";
119 default:
120 QL_FAIL("unknown CapFloor::Type (" << Integer(t) << ")");
121 }
122 }
123
124 CapFloor::CapFloor(CapFloor::Type type,
125 Leg floatingLeg,
126 std::vector<Rate> capRates,
127 std::vector<Rate> floorRates)
128 : type_(type), floatingLeg_(std::move(floatingLeg)), capRates_(std::move(capRates)),
129 floorRates_(std::move(floorRates)) {
130 if (type_ == Cap || type_ == Collar) {
131 QL_REQUIRE(!capRates_.empty(), "no cap rates given");
132 capRates_.reserve(floatingLeg_.size());
133 while (capRates_.size() < floatingLeg_.size())
134 capRates_.push_back(capRates_.back());
135 }
136 if (type_ == Floor || type_ == Collar) {
137 QL_REQUIRE(!floorRates_.empty(), "no floor rates given");
138 floorRates_.reserve(floatingLeg_.size());
139 while (floorRates_.size() < floatingLeg_.size())
140 floorRates_.push_back(floorRates_.back());
141 }
142 Leg::const_iterator i;
143 for (i = floatingLeg_.begin(); i != floatingLeg_.end(); ++i)
144 registerWith(*i);
145
146 registerWith(Settings::instance().evaluationDate());
147 }
148
149 CapFloor::CapFloor(CapFloor::Type type, Leg floatingLeg, const std::vector<Rate>& strikes)
150 : type_(type), floatingLeg_(std::move(floatingLeg)) {
151 QL_REQUIRE(!strikes.empty(), "no strikes given");
152 if (type_ == Cap) {
153 capRates_ = strikes;
154 capRates_.reserve(floatingLeg_.size());
155 while (capRates_.size() < floatingLeg_.size())
156 capRates_.push_back(capRates_.back());
157 } else if (type_ == Floor) {
158 floorRates_ = strikes;
159 floorRates_.reserve(floatingLeg_.size());
160 while (floorRates_.size() < floatingLeg_.size())
161 floorRates_.push_back(floorRates_.back());
162 } else
163 QL_FAIL("only Cap/Floor types allowed in this constructor");
164
165 Leg::const_iterator i;
166 for (i = floatingLeg_.begin(); i != floatingLeg_.end(); ++i)
167 registerWith(*i);
168
169 registerWith(Settings::instance().evaluationDate());
170 }
171
172 bool CapFloor::isExpired() const {
173 for (Size i=floatingLeg_.size(); i>0; --i)
174 if (!floatingLeg_[i-1]->hasOccurred())
175 return false;
176 return true;
177 }
178
181 }
182
185 }
186
187 ext::shared_ptr<FloatingRateCoupon>
189 ext::shared_ptr<CashFlow> lastCF(floatingLeg_.back());
190 ext::shared_ptr<FloatingRateCoupon> lastFloatingCoupon =
191 ext::dynamic_pointer_cast<FloatingRateCoupon>(lastCF);
192 return lastFloatingCoupon;
193 }
194
195 ext::shared_ptr<CapFloor> CapFloor::optionlet(const Size i) const {
196 QL_REQUIRE(i < floatingLeg().size(),
197 io::ordinal(i+1) << " optionlet does not exist, only " <<
198 floatingLeg().size());
199 Leg cf(1, floatingLeg()[i]);
200
201 std::vector<Rate> cap, floor;
202 if (type() == Cap || type() == Collar)
203 cap.push_back(capRates()[i]);
204 if (type() == Floor || type() == Collar)
205 floor.push_back(floorRates()[i]);
206
207 return ext::make_shared<CapFloor>(type(), cf, cap, floor);
208 }
209
211 auto* arguments = dynamic_cast<CapFloor::arguments*>(args);
212 QL_REQUIRE(arguments != nullptr, "wrong argument type");
213
214 Size n = floatingLeg_.size();
215
216 arguments->startDates.resize(n);
217 arguments->fixingDates.resize(n);
218 arguments->endDates.resize(n);
219 arguments->accrualTimes.resize(n);
220 arguments->forwards.resize(n);
221 arguments->nominals.resize(n);
222 arguments->gearings.resize(n);
223 arguments->capRates.resize(n);
224 arguments->floorRates.resize(n);
225 arguments->spreads.resize(n);
226 arguments->indexes.resize(n);
227
229
231
232 for (Size i=0; i<n; ++i) {
233 ext::shared_ptr<FloatingRateCoupon> coupon =
234 ext::dynamic_pointer_cast<FloatingRateCoupon>(
235 floatingLeg_[i]);
236 QL_REQUIRE(coupon, "non-FloatingRateCoupon given");
237 arguments->startDates[i] = coupon->accrualStartDate();
238 arguments->fixingDates[i] = coupon->fixingDate();
239 arguments->endDates[i] = coupon->date();
240
241 // this is passed explicitly for precision
242 arguments->accrualTimes[i] = coupon->accrualPeriod();
243
244 // this is passed explicitly for precision...
245 if (arguments->endDates[i] >= today) { // ...but only if needed
246 arguments->forwards[i] = coupon->adjustedFixing();
247 } else {
249 }
250
251 arguments->nominals[i] = coupon->nominal();
252 Spread spread = coupon->spread();
253 Real gearing = coupon->gearing();
254 arguments->gearings[i] = gearing;
255 arguments->spreads[i] = spread;
256
257 if (type_ == Cap || type_ == Collar)
258 arguments->capRates[i] = (capRates_[i]-spread)/gearing;
259 else
261
262 if (type_ == Floor || type_ == Collar)
263 arguments->floorRates[i] = (floorRates_[i]-spread)/gearing;
264 else
266
267 arguments->indexes[i] = coupon->index();
268 }
269 }
270
272 for (auto& i : floatingLeg_) {
273 i->deepUpdate();
274 }
275 update();
276 }
277
279 QL_REQUIRE(endDates.size() == startDates.size(),
280 "number of start dates (" << startDates.size()
281 << ") different from that of end dates ("
282 << endDates.size() << ")");
283 QL_REQUIRE(accrualTimes.size() == startDates.size(),
284 "number of start dates (" << startDates.size()
285 << ") different from that of accrual times ("
286 << accrualTimes.size() << ")");
287 QL_REQUIRE(type == CapFloor::Floor ||
288 capRates.size() == startDates.size(),
289 "number of start dates (" << startDates.size()
290 << ") different from that of cap rates ("
291 << capRates.size() << ")");
292 QL_REQUIRE(type == CapFloor::Cap ||
293 floorRates.size() == startDates.size(),
294 "number of start dates (" << startDates.size()
295 << ") different from that of floor rates ("
296 << floorRates.size() << ")");
297 QL_REQUIRE(gearings.size() == startDates.size(),
298 "number of start dates (" << startDates.size()
299 << ") different from that of gearings ("
300 << gearings.size() << ")");
301 QL_REQUIRE(spreads.size() == startDates.size(),
302 "number of start dates (" << startDates.size()
303 << ") different from that of spreads ("
304 << spreads.size() << ")");
305 QL_REQUIRE(nominals.size() == startDates.size(),
306 "number of start dates (" << startDates.size()
307 << ") different from that of nominals ("
308 << nominals.size() << ")");
309 QL_REQUIRE(forwards.size() == startDates.size(),
310 "number of start dates (" << startDates.size()
311 << ") different from that of forwards ("
312 << forwards.size() << ")");
313 }
314
315 Rate CapFloor::atmRate(const YieldTermStructure& discountCurve) const {
316 bool includeSettlementDateFlows = false;
317 Date settlementDate = discountCurve.referenceDate();
318 return CashFlows::atmRate(floatingLeg_, discountCurve,
319 includeSettlementDateFlows,
320 settlementDate);
321 }
322
325 Volatility guess,
326 Real accuracy,
327 Natural maxEvaluations,
328 Volatility minVol,
329 Volatility maxVol,
331 Real displacement) const {
332 //calculate();
333 QL_REQUIRE(!isExpired(), "instrument expired");
334
335 ImpliedCapVolHelper f(*this, d, targetValue, displacement, type);
336 //Brent solver;
337 NewtonSafe solver;
338 solver.setMaxEvaluations(maxEvaluations);
339 return solver.solve(f, accuracy, guess, minVol, maxVol);
340 }
341
342}
Arguments for cap/floor calculation
Definition: capfloor.hpp:138
std::vector< Time > accrualTimes
Definition: capfloor.hpp:145
std::vector< Rate > forwards
Definition: capfloor.hpp:148
std::vector< Date > startDates
Definition: capfloor.hpp:142
std::vector< Real > gearings
Definition: capfloor.hpp:149
std::vector< Rate > floorRates
Definition: capfloor.hpp:147
std::vector< ext::shared_ptr< InterestRateIndex > > indexes
Definition: capfloor.hpp:152
std::vector< Real > nominals
Definition: capfloor.hpp:151
std::vector< Date > endDates
Definition: capfloor.hpp:144
std::vector< Rate > capRates
Definition: capfloor.hpp:146
std::vector< Date > fixingDates
Definition: capfloor.hpp:143
std::vector< Real > spreads
Definition: capfloor.hpp:150
void validate() const override
Definition: capfloor.cpp:278
Volatility impliedVolatility(Real price, const Handle< YieldTermStructure > &disc, Volatility guess, Real accuracy=1.0e-4, Natural maxEvaluations=100, Volatility minVol=1.0e-7, Volatility maxVol=4.0, VolatilityType type=ShiftedLognormal, Real displacement=0.0) const
implied term volatility
Definition: capfloor.cpp:323
ext::shared_ptr< CapFloor > optionlet(Size n) const
Returns the n-th optionlet as a new CapFloor with only one cash flow.
Definition: capfloor.cpp:195
CapFloor(Type type, Leg floatingLeg, std::vector< Rate > capRates, std::vector< Rate > floorRates)
Definition: capfloor.cpp:124
void setupArguments(PricingEngine::arguments *) const override
Definition: capfloor.cpp:210
bool isExpired() const override
returns whether the instrument might have value greater than zero.
Definition: capfloor.cpp:172
const std::vector< Rate > & capRates() const
Definition: capfloor.hpp:77
const Leg & floatingLeg() const
Definition: capfloor.hpp:79
void deepUpdate() override
Definition: capfloor.cpp:271
Date startDate() const
Definition: capfloor.cpp:179
ext::shared_ptr< FloatingRateCoupon > lastFloatingRateCoupon() const
Definition: capfloor.cpp:188
Rate atmRate(const YieldTermStructure &discountCurve) const
Definition: capfloor.cpp:315
Date maturityDate() const
Definition: capfloor.cpp:183
const std::vector< Rate > & floorRates() const
Definition: capfloor.hpp:78
std::vector< Rate > capRates_
Definition: capfloor.hpp:102
std::vector< Rate > floorRates_
Definition: capfloor.hpp:103
Type type() const
Definition: capfloor.hpp:76
Concrete cap class.
Definition: capfloor.hpp:108
static Date maturityDate(const Leg &leg)
Definition: cashflows.cpp:52
static Date startDate(const Leg &leg)
Definition: cashflows.cpp:38
static Rate atmRate(const Leg &leg, const YieldTermStructure &discountCurve, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date(), Real npv=Null< Real >())
At-the-money rate of the cash flows.
Definition: cashflows.cpp:521
Concrete collar class.
Definition: capfloor.hpp:128
Concrete date class.
Definition: date.hpp:125
Concrete floor class.
Definition: capfloor.hpp:118
Shared handle to an observable.
Definition: handle.hpp:41
void update() override
Definition: lazyobject.hpp:188
safe Newton 1-D solver
Definition: newtonsafe.hpp:40
template class providing a null value for a given type.
Definition: null.hpp:76
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:228
DateProxy & evaluationDate()
the date at which pricing is to be performed.
Definition: settings.hpp:147
static Settings & instance()
access to the unique instance
Definition: singleton.hpp:104
void setMaxEvaluations(Size evaluations)
Definition: solver1d.hpp:238
Real solve(const F &f, Real accuracy, Real guess, Real step) const
Definition: solver1d.hpp:84
virtual const Date & referenceDate() const
the date at which discount = 1.0 and/or variance = 0.0
Interest-rate term structure.
detail::ordinal_holder ordinal(Size)
outputs naturals as 1st, 2nd, 3rd...
QL_REAL Real
real number
Definition: types.hpp:50
unsigned QL_INTEGER Natural
positive integer
Definition: types.hpp:43
Real Volatility
volatility
Definition: types.hpp:78
QL_INTEGER Integer
integer number
Definition: types.hpp:35
Real Spread
spreads on interest rates
Definition: types.hpp:74
Real Rate
interest rates
Definition: types.hpp:70
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
std::ostream & operator<<(std::ostream &out, GFunctionFactory::YieldCurveModel type)
std::vector< ext::shared_ptr< CashFlow > > Leg
Sequence of cash-flows.
Definition: cashflow.hpp:78
STL namespace.