Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
tenorbasisswaphelper.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 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/cashflows/iborcoupon.hpp>
20#include <ql/indexes/ibor/libor.hpp>
21#include <ql/pricingengines/swap/discountingswapengine.hpp>
22#include <ql/utilities/null_deleter.hpp>
23
25namespace QuantExt {
26
27TenorBasisSwapHelper::TenorBasisSwapHelper(Handle<Quote> spread, const Period& swapTenor,
28 const QuantLib::ext::shared_ptr<IborIndex> payIndex,
29 const QuantLib::ext::shared_ptr<IborIndex> receiveIndex,
30 const Handle<YieldTermStructure>& discountingCurve, bool spreadOnRec,
31 bool includeSpread, const Period& payFrequency, const Period& recFrequency,
32 const bool telescopicValueDates, QuantExt::SubPeriodsCoupon1::Type type)
33 : RelativeDateRateHelper(spread), swapTenor_(swapTenor), payIndex_(payIndex), receiveIndex_(receiveIndex),
34 spreadOnRec_(spreadOnRec), includeSpread_(includeSpread), payFrequency_(payFrequency),
35 recFrequency_(recFrequency), telescopicValueDates_(telescopicValueDates), type_(type),
36 discountHandle_(discountingCurve) {
37
38 /* depending on the given curves we proceed as outlined in the following table
39
40 x = curve is given
41 . = curve is missing
42
43 Case | PAY | REC | Discount | Action
44 =========================================
45 0 | . | . | . | throw exception
46 1 | . | . | x | throw exception
47 2 | . | x | . | imply PAY = Discount
48 3 | . | x | x | imply PAY
49 4 | x | . | . | imply REC = Discount
50 5 | x | . | x | imply REC
51 6 | x | x | . | imply Discount
52 7 | x | x | x | throw exception
53
54 Overnight(ON) vs. IBOR CASE:
55 Case 2 from above:
56 if REC (given) is ON, REC = Discount = OIS, imply PAY only
57 else : PAY (missing) is ON, imply PAY = Discount = OIS (as before)
58
59 Case 4 from above:
60 if PAY (given) is ON, PAY = Discount = OIS , imply REC only
61 else : REC (missing) is ON, then imply REC = Discount = OIS (as before)
62
63 */
64
66
67 bool payGiven = !payIndex_->forwardingTermStructure().empty();
68 bool recGiven = !receiveIndex_->forwardingTermStructure().empty();
69 bool discountGiven = !discountHandle_.empty();
70
71 QuantLib::ext::shared_ptr<OvernightIndex> payIndexON = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(payIndex_);
72 QuantLib::ext::shared_ptr<OvernightIndex> recIndexON = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(receiveIndex_);
73
74 if (!payGiven && !recGiven && !discountGiven) {
75 // case 0
76 QL_FAIL("no curve given");
77 } else if (!payGiven && !recGiven && discountGiven) {
78 // case 1
79 QL_FAIL("no index curve given");
80 } else if (!payGiven && recGiven && !discountGiven) {
81 // case 2
82 payIndex_ = QuantLib::ext::static_pointer_cast<IborIndex>(payIndex_->clone(termStructureHandle_));
83 payIndex_->unregisterWith(termStructureHandle_);
84 if (!payIndexON && recIndexON)
85 discountRelinkableHandle_.linkTo(*receiveIndex_->forwardingTermStructure());
86 else
88 } else if (!payGiven && recGiven && discountGiven) {
89 // case 3
90 payIndex_ = QuantLib::ext::static_pointer_cast<IborIndex>(payIndex_->clone(termStructureHandle_));
91 payIndex_->unregisterWith(termStructureHandle_);
92 } else if (payGiven && !recGiven && !discountGiven) {
93 // case 4
94 receiveIndex_ = QuantLib::ext::static_pointer_cast<IborIndex>(receiveIndex_->clone(termStructureHandle_));
95 receiveIndex_->unregisterWith(termStructureHandle_);
96 if (payIndexON && !recIndexON)
97 discountRelinkableHandle_.linkTo(*payIndex_->forwardingTermStructure());
98 else
100 } else if (payGiven && !recGiven && discountGiven) {
101 // case 5
102 receiveIndex_ = QuantLib::ext::static_pointer_cast<IborIndex>(receiveIndex_->clone(termStructureHandle_));
103 receiveIndex_->unregisterWith(termStructureHandle_);
104 } else if (payGiven && recGiven && !discountGiven) {
105 // case 6
107 } else if (payGiven && recGiven && discountGiven) {
108 // case 7
109 QL_FAIL("Both Index and the Discount curves are all given");
110 }
111
112 payFrequency_ = payFrequency == Period() ? payIndex_->tenor() : payFrequency;
113 recFrequency_ = recFrequency == Period() ? receiveIndex_->tenor() : recFrequency;
114
115 registerWith(payIndex_);
116 registerWith(receiveIndex_);
117 registerWith(discountHandle_);
119}
120
122
123 //CHECK : should the spot shift be based on pay ore receive, here we have the pay leg...
124 QuantLib::ext::shared_ptr<Libor> payIndexAsLibor = QuantLib::ext::dynamic_pointer_cast<Libor>(payIndex_);
125 Calendar spotCalendar = payIndexAsLibor != NULL ? payIndexAsLibor->jointCalendar() : payIndex_->fixingCalendar();
126 Natural spotDays = payIndex_->fixingDays();
127
128 Date valuationDate = Settings::instance().evaluationDate();
129 // if the evaluation date is not a business day
130 // then move to the next business day
131 valuationDate = spotCalendar.adjust(valuationDate);
132
133 Date effectiveDate = spotCalendar.advance(valuationDate, spotDays * Days);
134
135 swap_ = QuantLib::ext::shared_ptr<TenorBasisSwap>(new TenorBasisSwap(
136 effectiveDate, 1.0, swapTenor_, payIndex_, 0.0, payFrequency_, receiveIndex_, 0.0, recFrequency_,
137 DateGeneration::Backward, includeSpread_, spreadOnRec_, type_, telescopicValueDates_));
138
139 QuantLib::ext::shared_ptr<PricingEngine> engine(new DiscountingSwapEngine(discountRelinkableHandle_));
140 swap_->setPricingEngine(engine);
141
142 earliestDate_ = swap_->startDate();
143 latestDate_ = swap_->maturityDate();
144
145 QuantLib::ext::shared_ptr<FloatingRateCoupon> lastFloating = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(
146 termStructureHandle_ == receiveIndex_->forwardingTermStructure() ? swap_->recLeg().back()
147 : swap_->payLeg().back());
148 if (IborCoupon::Settings::instance().usingAtParCoupons()) {
149 /* Subperiods coupons do not have a par approximation either... */
150 if (QuantLib::ext::dynamic_pointer_cast<QuantExt::SubPeriodsCoupon1>(lastFloating)) {
151 Date fixingValueDate = receiveIndex_->valueDate(lastFloating->fixingDate());
152 Date endValueDate = receiveIndex_->maturityDate(fixingValueDate);
153 latestDate_ = std::max(latestDate_, endValueDate);
154 }
155 } else {
156 /* May need to adjust latestDate_ if you are projecting libor based
157 on tenor length rather than from accrual date to accrual date. */
158 Date fixingValueDate = receiveIndex_->valueDate(lastFloating->fixingDate());
159 Date endValueDate = receiveIndex_->maturityDate(fixingValueDate);
160 latestDate_ = std::max(latestDate_, endValueDate);
161 }
162}
163
164void TenorBasisSwapHelper::setTermStructure(YieldTermStructure* t) {
165
166 bool observer = false;
167
168 QuantLib::ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
169 termStructureHandle_.linkTo(temp, observer);
170
172 discountRelinkableHandle_.linkTo(temp, observer);
173 else
175
176 RelativeDateRateHelper::setTermStructure(t);
177}
178
180 QL_REQUIRE(termStructure_ != 0, "Termstructure not set");
181 // we didn't register as observers - force calculation
182 swap_->deepUpdate();
183 return (spreadOnRec_ ? swap_->fairRecLegSpread() : swap_->fairPayLegSpread());
184}
185
186void TenorBasisSwapHelper::accept(AcyclicVisitor& v) {
187 Visitor<TenorBasisSwapHelper>* v1 = dynamic_cast<Visitor<TenorBasisSwapHelper>*>(&v);
188 if (v1 != 0)
189 v1->visit(*this);
190 else
191 RateHelper::accept(v);
192}
193} // namespace QuantExt
QuantLib::ext::shared_ptr< IborIndex > payIndex_
RelinkableHandle< YieldTermStructure > discountRelinkableHandle_
void setTermStructure(YieldTermStructure *) override
QuantLib::ext::shared_ptr< IborIndex > receiveIndex_
TenorBasisSwapHelper(Handle< Quote > spread, const Period &swapTenor, const QuantLib::ext::shared_ptr< IborIndex > payIndex, const QuantLib::ext::shared_ptr< IborIndex > receiveIndex, const Handle< YieldTermStructure > &discountingCurve=Handle< YieldTermStructure >(), bool spreadOnRec=true, bool includeSpread=false, const Period &payFrequency=Period(), const Period &recFrequency=Period(), const bool telescopicValueDates=false, QuantExt::SubPeriodsCoupon1::Type type=QuantExt::SubPeriodsCoupon1::Compounding)
RelinkableHandle< YieldTermStructure > termStructureHandle_
Handle< YieldTermStructure > discountHandle_
void accept(AcyclicVisitor &) override
QuantLib::ext::shared_ptr< TenorBasisSwap > swap_
QuantExt::SubPeriodsCoupon1::Type type_
Single currency tenor basis swap.
Single currency tenor basis swap helper.