Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
optionletstripper.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2019 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19#include <ql/indexes/iborindex.hpp>
20#include <ql/instruments/makecapfloor.hpp>
21#include <ql/pricingengines/capfloor/blackcapfloorengine.hpp>
24
25using std::vector;
26using namespace QuantLib;
27
28namespace QuantExt {
29
30OptionletStripper::OptionletStripper(const ext::shared_ptr<QuantExt::CapFloorTermVolSurface>& termVolSurface,
31 const ext::shared_ptr<IborIndex>& index,
32 const Handle<YieldTermStructure>& discount, const VolatilityType type,
33 const Real displacement, const Period& rateComputationPeriod,
34 const Size onCapSettlementDays)
35 : termVolSurface_(termVolSurface), index_(index), discount_(discount), nStrikes_(termVolSurface->strikes().size()),
36 volatilityType_(type), displacement_(displacement),
37 rateComputationPeriod_(rateComputationPeriod == 0 * Days ? index->tenor() : rateComputationPeriod),
38 onCapSettlementDays_(onCapSettlementDays) {
39
40 bool isOis = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(index_) != nullptr;
41
42 QL_REQUIRE(!isOis || rateComputationPeriod != 0 * Days,
43 "OptionletStripper: For an OIS index the rateComputationPeriod must be given");
44 QL_REQUIRE(isOis || rateComputationPeriod == 0 * Days || rateComputationPeriod == index_->tenor(),
45 "OptionletStripper: For an Ibor index the Ibor tenor ("
46 << index_->tenor() << ") must match the rateComputationPeriod (" << rateComputationPeriod
47 << ") if the latter is given.");
48
49 if (volatilityType_ == Normal) {
50 QL_REQUIRE(displacement_ == 0.0, "non-null displacement is not allowed with Normal model");
51 }
52
53 registerWith(termVolSurface);
54 registerWith(index_);
55 registerWith(discount_);
56 registerWith(Settings::instance().evaluationDate());
57
58 QL_REQUIRE(termVolSurface->optionTenors().size() > 0, "OptionletStripper: No OptionTenors provided.");
59 Period maxCapFloorTenor = termVolSurface->optionTenors().back();
60
61 // optionlet tenors and capFloor lengths
63 capFloorLengths_.push_back(optionletTenors_.back() + (isOis ? 0 * Days : rateComputationPeriod_));
64 QL_REQUIRE(maxCapFloorTenor >= capFloorLengths_.back(),
65 "too short (" << maxCapFloorTenor << ") capfloor term vol termVolSurface");
66 Period nextCapFloorLength = capFloorLengths_.back() + rateComputationPeriod_;
67 while (nextCapFloorLength <= maxCapFloorTenor) {
68 if (capFloorLengths_.back() > optionletTenors_.back())
69 optionletTenors_.push_back(capFloorLengths_.back());
70 capFloorLengths_.push_back(nextCapFloorLength);
71 nextCapFloorLength += rateComputationPeriod_;
72 }
73 if(isOis)
74 optionletTenors_.push_back(capFloorLengths_.back());
76
77 optionletVolatilities_ = vector<vector<Volatility>>(nOptionletTenors_, vector<Volatility>(nStrikes_));
78 optionletStrikes_ = vector<vector<Rate>>(nOptionletTenors_, termVolSurface->strikes());
79 optionletDates_ = vector<Date>(nOptionletTenors_);
80 optionletTimes_ = vector<Time>(nOptionletTenors_);
84}
85
86const vector<Rate>& OptionletStripper::optionletStrikes(Size i) const {
87 calculate();
88 QL_REQUIRE(i < optionletStrikes_.size(),
89 "index (" << i << ") must be less than optionletStrikes size (" << optionletStrikes_.size() << ")");
90 return optionletStrikes_[i];
91}
92
93const vector<Volatility>& OptionletStripper::optionletVolatilities(Size i) const {
94 calculate();
95 QL_REQUIRE(i < optionletVolatilities_.size(), "index (" << i << ") must be less than optionletVolatilities size ("
96 << optionletVolatilities_.size() << ")");
97 return optionletVolatilities_[i];
98}
99
100const vector<Period>& OptionletStripper::optionletFixingTenors() const { return optionletTenors_; }
101
102const vector<Date>& OptionletStripper::optionletFixingDates() const {
103 calculate();
104 return optionletDates_;
105}
106
107const vector<Time>& OptionletStripper::optionletFixingTimes() const {
108 calculate();
109 return optionletTimes_;
110}
111
113
114const vector<Date>& OptionletStripper::optionletPaymentDates() const {
115 calculate();
117}
118
120 calculate();
122}
123
124const vector<Rate>& OptionletStripper::atmOptionletRates() const {
125 calculate();
126 return atmOptionletRate_;
127}
128
129DayCounter OptionletStripper::dayCounter() const { return termVolSurface_->dayCounter(); }
130
131Calendar OptionletStripper::calendar() const { return termVolSurface_->calendar(); }
132
133Natural OptionletStripper::settlementDays() const { return termVolSurface_->settlementDays(); }
134
135BusinessDayConvention OptionletStripper::businessDayConvention() const {
136 return termVolSurface_->businessDayConvention();
137}
138
139ext::shared_ptr<CapFloorTermVolSurface> OptionletStripper::termVolSurface() const { return termVolSurface_; }
140
141ext::shared_ptr<IborIndex> OptionletStripper::index() const { return index_; }
142
144
145VolatilityType OptionletStripper::volatilityType() const { return volatilityType_; }
146
148
150
151 bool isOis = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(index_) != nullptr;
152
153 Date referenceDate = termVolSurface_->referenceDate();
154 DayCounter dc = termVolSurface_->dayCounter();
155 QuantLib::ext::shared_ptr<BlackCapFloorEngine> dummyEngine =
156 QuantLib::ext::make_shared<BlackCapFloorEngine>(index_->forwardingTermStructure(), 0.20, dc);
157
158 for (Size i = 0; i < nOptionletTenors_; ++i) {
159 if (isOis) {
160 Leg dummyCap =
161 MakeOISCapFloor(CapFloor::Cap, capFloorLengths_[i], QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(index_),
165 auto lastCoupon = QuantLib::ext::dynamic_pointer_cast<CappedFlooredOvernightIndexedCoupon>(dummyCap.back());
166 QL_REQUIRE(lastCoupon, "OptionletStripper::populateDates(): expected CappedFlooredOvernightIndexedCoupon");
167 optionletDates_[i] = std::max(referenceDate + 1, lastCoupon->underlying()->fixingDates().front());
168 optionletPaymentDates_[i] = lastCoupon->underlying()->date();
169 optionletAccrualPeriods_[i] = lastCoupon->underlying()->accrualPeriod();
170 optionletTimes_[i] = dc.yearFraction(referenceDate, optionletDates_[i]);
171 atmOptionletRate_[i] = lastCoupon->underlying()->rate();
172 } else {
173 CapFloor dummyCap =
174 MakeCapFloor(CapFloor::Cap, capFloorLengths_[i], index_, 0.04, 0 * Days).withPricingEngine(dummyEngine);
175 QuantLib::ext::shared_ptr<FloatingRateCoupon> lastCoupon = dummyCap.lastFloatingRateCoupon();
176 optionletDates_[i] = std::max(referenceDate + 1, lastCoupon->fixingDate());
177 optionletPaymentDates_[i] = lastCoupon->date();
178 optionletAccrualPeriods_[i] = lastCoupon->accrualPeriod();
179 optionletTimes_[i] = dc.yearFraction(referenceDate, optionletDates_[i]);
180 atmOptionletRate_[i] = lastCoupon->indexFixing();
181 }
182 QL_REQUIRE(i == 0 || optionletDates_[i] > optionletDates_[i - 1],
183 "OptionletStripper::populateDates(): got non-increasing optionletDates "
184 << optionletDates_[i - 1] << ", " << optionletDates_[i] << " for tenors "
185 << capFloorLengths_[i - 1] << ", " << capFloorLengths_[i] << " and index " << index_->name());
186 }
187}
188
189} // namespace QuantExt
MakeOISCapFloor & withSettlementDays(Natural settlementDays)
MakeOISCapFloor & withTelescopicValueDates(bool telescopicValueDates)
Calendar calendar() const override
const Period & rateComputationPeriod() const
std::vector< Rate > atmOptionletRate_
std::vector< std::vector< Volatility > > optionletVolatilities_
const std::vector< Date > & optionletFixingDates() const override
std::vector< Period > capFloorLengths_
ext::shared_ptr< CapFloorTermVolSurface > termVolSurface() const
Handle< YieldTermStructure > discount_
const std::vector< Rate > & optionletStrikes(Size i) const override
std::vector< Date > optionletPaymentDates_
std::vector< Time > optionletAccrualPeriods_
const std::vector< Time > & optionletFixingTimes() const override
const std::vector< Date > & optionletPaymentDates() const
const std::vector< Volatility > & optionletVolatilities(Size i) const override
const std::vector< Rate > & atmOptionletRates() const override
std::vector< Period > optionletTenors_
VolatilityType volatilityType() const override
std::vector< Time > optionletTimes_
std::vector< Date > optionletDates_
Natural settlementDays() const override
DayCounter dayCounter() const override
const std::vector< Period > & optionletFixingTenors() const
const VolatilityType volatilityType_
OptionletStripper(const ext::shared_ptr< QuantExt::CapFloorTermVolSurface > &, const ext::shared_ptr< IborIndex > &index, const Handle< YieldTermStructure > &discount=Handle< YieldTermStructure >(), const VolatilityType type=ShiftedLognormal, const Real displacement=0.0, const Period &rateComputationPeriod=0 *Days, const Size onCapSettlementDays=0)
BusinessDayConvention businessDayConvention() const override
std::vector< std::vector< Rate > > optionletStrikes_
Real displacement() const override
virtual void populateDates() const
Method to populate the dates, times and accruals that can be overridden in derived classes.
ext::shared_ptr< IborIndex > index() const
ext::shared_ptr< CapFloorTermVolSurface > termVolSurface_
const std::vector< Time > & optionletAccrualPeriods() const
Size optionletMaturities() const override
ext::shared_ptr< IborIndex > index_
helper class to instantiate standard market OIS cap / floors
optionlet (caplet/floorlet) volatility stripper
vector< Real > strikes