Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
flexiswap.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2018 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
20
21#include <ql/cashflows/couponpricer.hpp>
22#include <ql/cashflows/fixedratecoupon.hpp>
23#include <ql/cashflows/iborcoupon.hpp>
24
25#include <boost/make_shared.hpp>
26
27using namespace QuantLib;
28
29namespace QuantExt {
30
31FlexiSwap::FlexiSwap(const VanillaSwap::Type type, const std::vector<Real>& fixedNominal,
32 const std::vector<Real>& floatingNominal, const Schedule& fixedSchedule,
33 const std::vector<Real>& fixedRate, const DayCounter& fixedDayCount,
34 const Schedule& floatingSchedule, const QuantLib::ext::shared_ptr<IborIndex>& iborIndex,
35 const std::vector<Real>& gearing, const std::vector<Spread>& spread,
36 const std::vector<Real>& cappedRate, const std::vector<Real>& flooredRate,
37 const DayCounter& floatingDayCount, const std::vector<Real>& lowerNotionalBound,
38 const QuantLib::Position::Type optionPosition, const std::vector<bool>& notionalCanBeDecreased,
39 boost::optional<BusinessDayConvention> paymentConvention)
40 : Swap(2), type_(type), fixedNominal_(fixedNominal), floatingNominal_(floatingNominal),
41 fixedSchedule_(fixedSchedule), fixedRate_(fixedRate), fixedDayCount_(fixedDayCount),
42 floatingSchedule_(floatingSchedule), iborIndex_(iborIndex), gearing_(gearing), spread_(spread),
43 cappedRate_(cappedRate), flooredRate_(flooredRate), floatingDayCount_(floatingDayCount),
44 lowerNotionalBound_(lowerNotionalBound), optionPosition_(optionPosition),
45 notionalCanBeDecreased_(notionalCanBeDecreased) {
46
49 else
50 paymentConvention_ = floatingSchedule_.businessDayConvention();
51
52 QL_REQUIRE(floatingNominal.size() > 0, "FloatingNominal size is zero");
53 QL_REQUIRE(fixedNominal.size() > 0, "FixedNominal size is zero");
54 QL_REQUIRE(floatingNominal.size() % fixedNominal.size() == 0,
55 "Fixed nominal size (" << fixedNominal.size() << ") must divide floating nominal size ("
56 << floatingNominal.size() << ")");
57 QL_REQUIRE(fixedNominal_.size() == fixedRate_.size(), "Fixed nominal size (" << fixedNominal_.size()
58 << ") does not match fixed rate size ("
59 << fixedRate_.size() << ")");
60 QL_REQUIRE(fixedNominal_.size() == fixedSchedule_.size() - 1,
61 "Fixed nominal size (" << fixedNominal_.size() << ") does not match schedule size ("
62 << fixedSchedule_.size() << ") - 1");
63 QL_REQUIRE(fixedNominal_.size() == lowerNotionalBound_.size(),
64 "Fixed nominal size (" << fixedNominal_.size() << ") does not match lowerNotionalBound size ("
65 << lowerNotionalBound_.size() << ")");
66
67 QL_REQUIRE(floatingNominal_.size() == floatingSchedule_.size() - 1,
68 "Floating nominal size (" << floatingNominal_.size() << ") does not match schedule size ("
69 << floatingSchedule_.size() << ") - 1");
70
71 QL_REQUIRE(floatingNominal_.size() == gearing_.size(),
72 "Floating nominal size (" << floatingNominal_.size() << ") does not match gearing size ("
73 << gearing_.size() << ")");
74 QL_REQUIRE(floatingNominal_.size() == spread_.size(), "Floating nominal size (" << floatingNominal_.size()
75 << ") does not match spread size ("
76 << spread_.size() << ")");
77 QL_REQUIRE(floatingNominal_.size() == cappedRate_.size(),
78 "Floating nominal size (" << floatingNominal_.size() << ") does not match spread size ("
79 << cappedRate_.size() << ")");
80 QL_REQUIRE(floatingNominal_.size() == flooredRate_.size(),
81 "Floating nominal size (" << floatingNominal_.size() << ") does not match spread size ("
82 << flooredRate_.size() << ")");
83
84 QL_REQUIRE(notionalCanBeDecreased.empty() || notionalCanBeDecreased_.size() == fixedSchedule.size() - 1,
85 "notionalCanBeDecreased (" << notionalCanBeDecreased_.size() << ") must match number of fixed periods ("
86 << fixedSchedule.size() - 1 << ")");
87
88 // if the gearing is zero then the ibor leg will be set up with fixed
89 // coupons which makes trouble here in this context. We therefore use
90 // a dirty trick and enforce the gearing to be non zero.
91
92 // TODO do we need this?
93
94 std::vector<Real> gearingTmp(gearing_);
95 for (Size i = 0; i < gearingTmp.size(); ++i) {
96 if (close(gearingTmp[i], 0.0))
97 gearingTmp[i] = QL_EPSILON;
98 }
99
100 legs_[0] = FixedRateLeg(fixedSchedule_)
101 .withNotionals(fixedNominal_)
102 .withCouponRates(fixedRate_, fixedDayCount_)
103 .withPaymentAdjustment(paymentConvention_);
104
105 legs_[1] = IborLeg(floatingSchedule_, iborIndex_)
106 .withNotionals(floatingNominal_)
107 .withPaymentDayCounter(floatingDayCount_)
108 .withPaymentAdjustment(paymentConvention_)
109 .withSpreads(spread_)
110 .withGearings(gearingTmp)
111 .withCaps(cappedRate_)
112 .withFloors(flooredRate_);
113
114 for (Leg::const_iterator i = legs_[1].begin(); i < legs_[1].end(); ++i)
115 registerWith(*i);
116
117 auto cpnPricer = QuantLib::ext::make_shared<BlackIborCouponPricer>();
118 setCouponPricer(legs_[1], cpnPricer);
119
120 switch (type_) {
121 case VanillaSwap::Payer:
122 payer_[0] = -1.0;
123 payer_[1] = +1.0;
124 break;
125 case VanillaSwap::Receiver:
126 payer_[0] = +1.0;
127 payer_[1] = -1.0;
128 break;
129 default:
130 QL_FAIL("Unknown vanilla swap type");
131 }
132}
133
135 Swap::setupArguments(args);
136 auto arguments = dynamic_cast<FlexiSwap::arguments*>(args);
137
138 // QL_REQUIRE(arguments != nullptr, "FlexiSwap::setupArguments(): wrong argument type");
139
140 // allow for swap engine
141 if (arguments == nullptr)
142 return;
143
154 notionalCanBeDecreased_.empty() ? std::vector<bool>(fixedNominal_.size(), true) : notionalCanBeDecreased_;
155
156 const Leg& fixedCoupons = fixedLeg();
157
158 arguments->fixedResetDates = arguments->fixedPayDates = std::vector<Date>(fixedCoupons.size());
159 arguments->fixedCoupons = std::vector<Real>(fixedCoupons.size());
160
161 for (Size i = 0; i < fixedCoupons.size(); ++i) {
162 auto coupon = QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(fixedCoupons[i]);
163 QL_REQUIRE(coupon != nullptr, "FlexiSwap::setupArguments(): expected fixed rate coupon");
164 arguments->fixedPayDates[i] = coupon->date();
165 arguments->fixedResetDates[i] = coupon->accrualStartDate();
166 arguments->fixedCoupons[i] = coupon->amount();
167 }
168
169 const Leg& floatingCoupons = floatingLeg();
170
172 std::vector<Date>(floatingCoupons.size());
173 arguments->floatingAccrualTimes = std::vector<Time>(floatingCoupons.size());
174 arguments->floatingSpreads = std::vector<Spread>(floatingCoupons.size());
175 arguments->floatingGearings = std::vector<Real>(floatingCoupons.size());
176 arguments->floatingCoupons = std::vector<Real>(floatingCoupons.size());
177
178 for (Size i = 0; i < floatingCoupons.size(); ++i) {
179 auto coupon = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(floatingCoupons[i]);
180 QL_REQUIRE(coupon != nullptr, "FlexiSwap::setupArguments(): expected fixed rate coupon");
181 arguments->floatingResetDates[i] = coupon->accrualStartDate();
182 arguments->floatingPayDates[i] = coupon->date();
183 arguments->floatingFixingDates[i] = coupon->fixingDate();
184 arguments->floatingAccrualTimes[i] = coupon->accrualPeriod();
185 arguments->floatingSpreads[i] = coupon->spread();
186 arguments->floatingGearings[i] = coupon->gearing();
187 try {
188 arguments->floatingCoupons[i] = coupon->amount();
189 } catch (const std::exception&) {
190 arguments->floatingCoupons[i] = Null<Real>();
191 }
192 }
193}
194
196 calculate();
197 QL_REQUIRE(underlyingValue_ != Null<Real>(), "FlexiSwap: underlying value not provided");
198 return underlyingValue_;
199}
200
202 Swap::setupExpired();
203 underlyingValue_ = 0.0;
204}
205
206void FlexiSwap::fetchResults(const PricingEngine::results* r) const {
207 Swap::fetchResults(r);
208 auto results = dynamic_cast<const FlexiSwap::results*>(r);
209
210 // QL_REQUIRE(results != nullptr, "FlexiSwap::fetchResult(): wrong result type");
211
212 // allow for swap engine
213 if (results == nullptr)
214 return;
215
217}
218
220 Swap::arguments::validate();
221 Size ratio = floatingNominal.size() / fixedNominal.size(); // we know there is no remainder
222 bool hasOptionality = false;
223 Date today = Settings::instance().evaluationDate();
224 for (Size i = 0; i < fixedNominal.size(); ++i) {
225 for (Size j = 0; j < ratio; ++j) {
226 QL_REQUIRE(QuantLib::close_enough(fixedNominal[i], floatingNominal[i * ratio + j]),
227 "FlexiSwap::arguments::validate(): fixedNominal["
228 << i << "] = " << fixedNominal[i] << " does not match floatingNominal[" << i * ratio + j
229 << "] = " << floatingNominal[i * ratio + j] << ", ratio is " << ratio);
230 }
231 QL_REQUIRE(lowerNotionalBound[i] < fixedNominal[i] ||
232 QuantLib::close_enough(lowerNotionalBound[i], fixedNominal[i]),
233 "FlexiSwap::arguments::validate(): lowerNotionalBound[" << i << "] = " << lowerNotionalBound[i]
234 << " must be leq fixedNominal[" << i
235 << "] = " << fixedNominal[i]);
236 if (floatingResetDates[ratio * i] > today && notionalCanBeDecreased[i])
237 hasOptionality = hasOptionality || !QuantLib::close_enough(lowerNotionalBound[i], fixedNominal[i]);
238 if (i > 0 && hasOptionality) {
239 QL_REQUIRE(lowerNotionalBound[i] < lowerNotionalBound[i - 1] ||
240 QuantLib::close_enough(lowerNotionalBound[i], lowerNotionalBound[i - 1]),
241 "FlexiSwap::arguments::validate(): lowerNotionalBound["
242 << i - 1 << "] = " << lowerNotionalBound[i - 1] << " < lowerNotionalBound[" << i << "] = "
243 << lowerNotionalBound[i] << ", not allowed, since optionality has kicked in already");
244 QL_REQUIRE(fixedNominal[i] < fixedNominal[i - 1] ||
245 QuantLib::close_enough(fixedNominal[i], fixedNominal[i - 1]),
246 "FlexiSwap::arguments::validate(): fixedNominal["
247 << i - 1 << "] = " << fixedNominal[i - 1] << " < fixedNominal[" << i
248 << "] = " << fixedNominal[i] << ", not allowed, since optionality has kicked in already");
249 }
250 }
251}
252
254 Swap::results::reset();
255 underlyingValue = Null<Real>();
256}
257
258} // namespace QuantExt
Arguments for Flexi-Swap
Definition: flexiswap.hpp:128
std::vector< Real > cappedRate
Definition: flexiswap.hpp:145
std::vector< Date > floatingResetDates
Definition: flexiswap.hpp:137
QuantLib::ext::shared_ptr< IborIndex > iborIndex
Definition: flexiswap.hpp:149
std::vector< Real > floatingGearings
Definition: flexiswap.hpp:143
std::vector< Real > floatingSpreads
Definition: flexiswap.hpp:144
std::vector< Date > floatingFixingDates
Definition: flexiswap.hpp:138
std::vector< Real > flooredRate
Definition: flexiswap.hpp:146
std::vector< Date > fixedPayDates
Definition: flexiswap.hpp:135
std::vector< Real > fixedNominal
Definition: flexiswap.hpp:132
std::vector< Date > fixedResetDates
Definition: flexiswap.hpp:134
std::vector< Real > floatingNominal
Definition: flexiswap.hpp:132
QuantLib::Position::Type optionPosition
Definition: flexiswap.hpp:152
void validate() const override
Definition: flexiswap.cpp:219
std::vector< Real > floatingCoupons
Definition: flexiswap.hpp:147
std::vector< bool > notionalCanBeDecreased
Definition: flexiswap.hpp:153
std::vector< Real > lowerNotionalBound
Definition: flexiswap.hpp:151
std::vector< Real > fixedRate
Definition: flexiswap.hpp:142
std::vector< Time > floatingAccrualTimes
Definition: flexiswap.hpp:136
std::vector< Real > fixedCoupons
Definition: flexiswap.hpp:141
std::vector< Date > floatingPayDates
Definition: flexiswap.hpp:139
Results for Flexi-Swap
Definition: flexiswap.hpp:159
void fetchResults(const QuantLib::PricingEngine::results *) const override
Definition: flexiswap.cpp:206
const std::vector< bool > & notionalCanBeDecreased() const
Definition: flexiswap.hpp:92
const std::vector< Real > & fixedNominal() const
Definition: flexiswap.hpp:75
const std::vector< Real > fixedRate_
Definition: flexiswap.hpp:106
FlexiSwap(const VanillaSwap::Type type, const std::vector< Real > &fixedNominal, const std::vector< Real > &floatingNominal, const Schedule &fixedSchedule, const std::vector< Real > &fixedRate, const DayCounter &fixedDayCount, const Schedule &floatingSchedule, const QuantLib::ext::shared_ptr< IborIndex > &iborIndex, const std::vector< Real > &gearing, const std::vector< Real > &spread, const std::vector< Real > &cappedRate, const std::vector< Real > &flooredRate, const DayCounter &floatingDayCount, const std::vector< Real > &lowerNotionalBound, const QuantLib::Position::Type optionPosition, const std::vector< bool > &notionalCanBeDecreased=std::vector< bool >(), boost::optional< BusinessDayConvention > paymentConvention=boost::none)
Definition: flexiswap.cpp:31
BusinessDayConvention paymentConvention() const
Definition: flexiswap.hpp:94
const Schedule & fixedSchedule() const
Definition: flexiswap.hpp:78
const Schedule fixedSchedule_
Definition: flexiswap.hpp:105
const std::vector< Real > lowerNotionalBound_
Definition: flexiswap.hpp:115
const Leg & floatingLeg() const
Definition: flexiswap.hpp:97
Real underlyingValue() const
Definition: flexiswap.cpp:195
const std::vector< Real > cappedRate_
Definition: flexiswap.hpp:112
const std::vector< Real > fixedNominal_
Definition: flexiswap.hpp:104
const QuantLib::ext::shared_ptr< IborIndex > & iborIndex() const
Definition: flexiswap.hpp:83
const QuantLib::Position::Type optionPosition_
Definition: flexiswap.hpp:116
const DayCounter fixedDayCount_
Definition: flexiswap.hpp:107
const std::vector< bool > notionalCanBeDecreased_
Definition: flexiswap.hpp:117
const std::vector< Real > flooredRate_
Definition: flexiswap.hpp:113
const Schedule floatingSchedule_
Definition: flexiswap.hpp:108
BusinessDayConvention paymentConvention_
Definition: flexiswap.hpp:118
const VanillaSwap::Type type_
Definition: flexiswap.hpp:103
const Leg & fixedLeg() const
Definition: flexiswap.hpp:96
void setupExpired() const override
Definition: flexiswap.cpp:201
const std::vector< Real > gearing_
Definition: flexiswap.hpp:110
void setupArguments(QuantLib::PricingEngine::arguments *) const override
Definition: flexiswap.cpp:134
const DayCounter floatingDayCount_
Definition: flexiswap.hpp:114
const std::vector< Real > floatingNominal_
Definition: flexiswap.hpp:104
const QuantLib::ext::shared_ptr< IborIndex > iborIndex_
Definition: flexiswap.hpp:109
const std::vector< Real > spread_
Definition: flexiswap.hpp:111
const std::vector< Real > & floatingNominal() const
Definition: flexiswap.hpp:76
Flexi-Swap instrument with global notional bounds.
void setCouponPricer(const Leg &leg, const QuantLib::ext::shared_ptr< FloatingRateCouponPricer > &pricer)
Set Coupon Pricer.
SimpleQuote & spread_