Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
balanceguaranteedswap.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
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
32 const VanillaSwap::Type type, const std::vector<std::vector<Real>>& trancheNominals,
33 const Schedule& nominalSchedule, const Size referencedTranche, const Schedule& fixedSchedule,
34 const std::vector<Real>& fixedRate, const DayCounter& fixedDayCount, const Schedule& floatingSchedule,
35 const QuantLib::ext::shared_ptr<IborIndex>& iborIndex, const std::vector<Real>& gearing, const std::vector<Real>& spread,
36 const std::vector<Real>& cappedRate, const std::vector<Real>& flooredRate, const DayCounter& floatingDayCount,
37 boost::optional<BusinessDayConvention> paymentConvention)
38 : Swap(2), type_(type), trancheNominals_(trancheNominals), nominalSchedule_(nominalSchedule),
39 referencedTranche_(referencedTranche), fixedSchedule_(fixedSchedule), fixedRate_(fixedRate),
40 fixedDayCount_(fixedDayCount), floatingSchedule_(floatingSchedule), iborIndex_(iborIndex), gearing_(gearing),
41 spread_(spread), cappedRate_(cappedRate), flooredRate_(flooredRate), floatingDayCount_(floatingDayCount) {
42
43 // checks
44
47 else
48 paymentConvention_ = floatingSchedule_.businessDayConvention();
49
50 QL_REQUIRE(nominalSchedule.size() > 0, "Nominal schedule size is zero");
51 QL_REQUIRE(nominalSchedule.hasTenor(), "Nominal schedule needs a tenor");
52 QL_REQUIRE(nominalSchedule.tenor().frequency() != QuantLib::OtherFrequency,
53 "Nominal schedule tenor (" << nominalSchedule.tenor() << ") not allowed, corresponds to OtherFrequency");
54 QL_REQUIRE(fixedSchedule.size() > 0, "Fixed schedule size is zero");
55 QL_REQUIRE(floatingSchedule.size() > 0, "Floating schedule size is zero");
56 QL_REQUIRE(fixedSchedule_.size() - 1 == fixedRate_.size(),
57 "Fixed schedule size (" << fixedSchedule_.size() << ") does not match fixed rate size ("
58 << fixedRate_.size() << ")");
59
60 QL_REQUIRE(floatingSchedule_.size() - 1 == gearing_.size(),
61 "Floating schedule size (" << floatingSchedule_.size() << ") does not match gearing size ("
62 << gearing_.size() << ")");
63 QL_REQUIRE(floatingSchedule_.size() - 1 == spread_.size(),
64 "Floating schedule size (" << floatingSchedule_.size() << ") does not match spread size ("
65 << spread_.size() << ")");
66 QL_REQUIRE(floatingSchedule_.size() - 1 == cappedRate_.size(),
67 "Floating schedule size (" << floatingSchedule_.size() << ") does not match spread size ("
68 << cappedRate_.size() << ")");
69 QL_REQUIRE(floatingSchedule_.size() - 1 == flooredRate_.size(),
70 "Floating schedule size (" << floatingSchedule_.size() << ") does not match spread size ("
71 << flooredRate_.size() << ")");
72 QL_REQUIRE((floatingSchedule.size() - 1) % (fixedSchedule.size() - 1) == 0,
73 "fixed schedule size - 1 (" << fixedSchedule.size() - 1 << ") must divide floating schedule size - 1 ("
74 << floatingSchedule.size() - 1 << ")");
75
76 QL_REQUIRE(trancheNominals.size() > 0, "trancheNominals must be non-empty");
77 QL_REQUIRE(referencedTranche < trancheNominals.size(),
78 "referencedTranche (" << referencedTranche << ") out of range 0..." << (trancheNominals.size() - 1));
79 for (Size i = 0; i < trancheNominals.size(); ++i) {
80 QL_REQUIRE(trancheNominals[i].size() == nominalSchedule.size() - 1,
81 "Tranche nominals at " << i << " (" << trancheNominals.size() << ") do not match nominal schedule ("
82 << nominalSchedule.size() << ")");
83 }
84
85 // build the fixed and floating nominal for the swap
86 std::vector<Real> fixedNominal, floatingNominal;
87 for (Size i = 0; i < fixedSchedule.size() - 1; ++i) {
88 fixedNominal.push_back(trancheNominal(referencedTranche_, fixedSchedule[i]));
89 }
90 // derive floating nominal schedule from fixed to ensure they match
91 Size ratio = (floatingSchedule.size() - 1) / (fixedSchedule.size() - 1); // we know there is no remainder
92 floatingNominal.resize(fixedNominal.size() * ratio);
93 Size i = 0; // remove in C++14 and instead write [i=0, &fixedNotional] in the capture below
94 std::generate(floatingNominal.begin(), floatingNominal.end(),
95 [i, &fixedNominal, ratio]() mutable { return fixedNominal[i++ / ratio]; });
96
97 // if the gearing is zero then the ibor leg will be set up with fixed
98 // coupons which makes trouble here in this context. We therefore use
99 // a dirty trick and enforce the gearing to be non zero.
100
101 // TODO do we need this?
102
103 std::vector<Real> gearingTmp(gearing_);
104 for (Size i = 0; i < gearingTmp.size(); ++i) {
105 if (close(gearingTmp[i], 0.0))
106 gearingTmp[i] = QL_EPSILON;
107 }
108
109 legs_[0] = FixedRateLeg(fixedSchedule_)
110 .withNotionals(fixedNominal)
111 .withCouponRates(fixedRate_, fixedDayCount_)
112 .withPaymentAdjustment(paymentConvention_);
113
114 legs_[1] = IborLeg(floatingSchedule_, iborIndex_)
115 .withNotionals(floatingNominal)
116 .withPaymentDayCounter(floatingDayCount_)
117 .withPaymentAdjustment(paymentConvention_)
118 .withSpreads(spread_)
119 .withGearings(gearingTmp)
120 .withCaps(cappedRate_)
121 .withFloors(flooredRate_);
122
123 for (Leg::const_iterator i = legs_[1].begin(); i < legs_[1].end(); ++i)
124 registerWith(*i);
125
126 auto cpnPricer = QuantLib::ext::make_shared<BlackIborCouponPricer>();
127 setCouponPricer(legs_[1], cpnPricer);
128
129 switch (type_) {
130 case VanillaSwap::Payer:
131 payer_[0] = -1.0;
132 payer_[1] = +1.0;
133 break;
134 case VanillaSwap::Receiver:
135 payer_[0] = +1.0;
136 payer_[1] = -1.0;
137 break;
138 default:
139 QL_FAIL("Unknown vanilla swap type");
140 }
141}
142
144 Swap::setupArguments(args);
145 auto arguments = dynamic_cast<BalanceGuaranteedSwap::arguments*>(args);
146
147 // QL_REQUIRE(arguments != nullptr, "BalanceGuaranteedSwap::setupArguments(): wrong argument type");
148
149 // allow for swap engine
150 if (arguments == nullptr)
151 return;
152
162
163 const Leg& fixedCoupons = fixedLeg();
164
165 arguments->fixedResetDates = arguments->fixedPayDates = std::vector<Date>(fixedCoupons.size());
166 arguments->fixedCoupons = std::vector<Real>(fixedCoupons.size());
167
168 for (Size i = 0; i < fixedCoupons.size(); ++i) {
169 auto coupon = QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(fixedCoupons[i]);
170 QL_REQUIRE(coupon != nullptr, "BalanceGuaranteedSwap::setupArguments(): expected fixed rate coupon");
171 arguments->fixedPayDates[i] = coupon->date();
172 arguments->fixedResetDates[i] = coupon->accrualStartDate();
173 arguments->fixedCoupons[i] = coupon->amount();
174 }
175
176 const Leg& floatingCoupons = floatingLeg();
177
179 std::vector<Date>(floatingCoupons.size());
180 arguments->floatingAccrualTimes = std::vector<Time>(floatingCoupons.size());
181 arguments->floatingSpreads = std::vector<Spread>(floatingCoupons.size());
182 arguments->floatingGearings = std::vector<Real>(floatingCoupons.size());
183 arguments->floatingCoupons = std::vector<Real>(floatingCoupons.size());
184
185 for (Size i = 0; i < floatingCoupons.size(); ++i) {
186 auto coupon = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(floatingCoupons[i]);
187 QL_REQUIRE(coupon != nullptr, "BalanceGuaranteedSwap::setupArguments(): expected fixed rate coupon");
188 arguments->floatingResetDates[i] = coupon->accrualStartDate();
189 arguments->floatingPayDates[i] = coupon->date();
190 arguments->floatingFixingDates[i] = coupon->fixingDate();
191 arguments->floatingAccrualTimes[i] = coupon->accrualPeriod();
192 arguments->floatingSpreads[i] = coupon->spread();
193 arguments->floatingGearings[i] = coupon->gearing();
194 try {
195 arguments->floatingCoupons[i] = coupon->amount();
196 } catch (const std::exception&) {
197 arguments->floatingCoupons[i] = Null<Real>();
198 }
199 }
200
201 arguments->fixedLeg = legs_[0];
202 arguments->floatingLeg = legs_[1];
203}
204
205Real BalanceGuaranteedSwap::trancheNominal(const Size trancheIndex, const Date& d) {
206 QL_REQUIRE(trancheIndex < trancheNominals_.size(), "BalanceGuaranteedSwap::trancheNominal(): tranceIndex ("
207 << trancheIndex << ") out of range 0..."
208 << trancheNominals_.size() - 1);
209 if (d < nominalSchedule_.dates().front() || d >= nominalSchedule_.dates().back())
210 return 0.0;
211 Size l = std::upper_bound(nominalSchedule_.dates().begin(), nominalSchedule_.dates().end(), d) -
212 nominalSchedule_.dates().begin();
213 return trancheNominals_[trancheIndex][l - 1];
214}
215
216void BalanceGuaranteedSwap::setupExpired() const { Swap::setupExpired(); }
217
218void BalanceGuaranteedSwap::fetchResults(const PricingEngine::results* r) const {
219 Swap::fetchResults(r);
220 auto results = dynamic_cast<const BalanceGuaranteedSwap::results*>(r);
221
222 // QL_REQUIRE(results != nullptr, "BalanceGuaranteedSwap::fetchResult(): wrong result type");
223
224 // allow for swap engine
225 if (results == nullptr)
226 return;
227}
228
230 Swap::arguments::validate();
231 // TODO
232}
233
234void BalanceGuaranteedSwap::results::reset() { Swap::results::reset(); }
235
236} // namespace QuantExt
Balance Guaranteed Swap instrument.
Arguments for Balance Guaranteed Swap
std::vector< std::vector< Real > > trancheNominals
QuantLib::ext::shared_ptr< IborIndex > iborIndex
Results for Balance Guaranteed Swap
void fetchResults(const QuantLib::PricingEngine::results *) const override
const std::vector< Real > fixedRate_
BalanceGuaranteedSwap(const VanillaSwap::Type type, const std::vector< std::vector< Real > > &trancheNominals, const Schedule &nominalSchedule, const Size referencedTranche, 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, boost::optional< BusinessDayConvention > paymentConvention=boost::none)
BusinessDayConvention paymentConvention() const
const Schedule & fixedSchedule() const
const std::vector< std::vector< Real > > trancheNominals_
const std::vector< Real > cappedRate_
const Schedule & floatingSchedule() const
const QuantLib::ext::shared_ptr< IborIndex > & iborIndex() const
const std::vector< Real > flooredRate_
void setupArguments(QuantLib::PricingEngine::arguments *) const override
const Schedule & nominalSchedule() const
const QuantLib::ext::shared_ptr< IborIndex > iborIndex_
const std::vector< std::vector< Real > > & trancheNominal() const
void setCouponPricer(const Leg &leg, const QuantLib::ext::shared_ptr< FloatingRateCouponPricer > &pricer)
Set Coupon Pricer.
SimpleQuote & spread_