Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
crossccybasismtmresetswaphelper.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#include <ql/cashflows/iborcoupon.hpp>
19#include <ql/utilities/null_deleter.hpp>
21
23
24#include <boost/make_shared.hpp>
25
26namespace QuantExt {
27
29 const Handle<Quote>& spreadQuote, const Handle<Quote>& spotFX, Natural settlementDays,
30 const Calendar& settlementCalendar, const Period& swapTenor, BusinessDayConvention rollConvention,
31 const QuantLib::ext::shared_ptr<QuantLib::IborIndex>& foreignCcyIndex,
32 const QuantLib::ext::shared_ptr<QuantLib::IborIndex>& domesticCcyIndex,
33 const Handle<YieldTermStructure>& foreignCcyDiscountCurve,
34 const Handle<YieldTermStructure>& domesticCcyDiscountCurve,
35 const Handle<YieldTermStructure>& foreignCcyFxFwdRateCurve,
36 const Handle<YieldTermStructure>& domesticCcyFxFwdRateCurve, bool eom, bool spreadOnForeignCcy,
37 boost::optional<Period> foreignTenor, boost::optional<Period> domesticTenor, Size foreignPaymentLag,
38 Size domesticPaymentLag, boost::optional<bool> foreignIncludeSpread, boost::optional<Period> foreignLookback,
39 boost::optional<Size> foreignFixingDays, boost::optional<Size> foreignRateCutoff,
40 boost::optional<bool> foreignIsAveraged, boost::optional<bool> domesticIncludeSpread,
41 boost::optional<Period> domesticLookback, boost::optional<Size> domesticFixingDays,
42 boost::optional<Size> domesticRateCutoff, boost::optional<bool> domesticIsAveraged, const bool telescopicValueDates)
43 : RelativeDateRateHelper(spreadQuote), spotFX_(spotFX), settlementDays_(settlementDays),
44 settlementCalendar_(settlementCalendar), swapTenor_(swapTenor), rollConvention_(rollConvention),
45 foreignCcyIndex_(foreignCcyIndex), domesticCcyIndex_(domesticCcyIndex),
46 foreignCcyDiscountCurve_(foreignCcyDiscountCurve), domesticCcyDiscountCurve_(domesticCcyDiscountCurve),
47 foreignCcyFxFwdRateCurve_(foreignCcyFxFwdRateCurve), domesticCcyFxFwdRateCurve_(domesticCcyFxFwdRateCurve),
48 eom_(eom), spreadOnForeignCcy_(spreadOnForeignCcy),
49 foreignTenor_(foreignTenor ? *foreignTenor : foreignCcyIndex_->tenor()),
50 domesticTenor_(domesticTenor ? *domesticTenor : domesticCcyIndex_->tenor()),
51 foreignPaymentLag_(foreignPaymentLag), domesticPaymentLag_(domesticPaymentLag),
52 foreignIncludeSpread_(foreignIncludeSpread), foreignLookback_(foreignLookback),
53 foreignFixingDays_(foreignFixingDays), foreignRateCutoff_(foreignRateCutoff),
54 foreignIsAveraged_(foreignIsAveraged), domesticIncludeSpread_(domesticIncludeSpread),
55 domesticLookback_(domesticLookback), domesticFixingDays_(domesticFixingDays),
56 domesticRateCutoff_(domesticRateCutoff), domesticIsAveraged_(domesticIsAveraged),
57 telescopicValueDates_(telescopicValueDates) {
58
62 "matching currencies not allowed on CrossCcyBasisMtMResetSwapHelper");
63
64 bool foreignIndexHasCurve = !foreignCcyIndex_->forwardingTermStructure().empty();
65 bool domesticIndexHasCurve = !domesticCcyIndex_->forwardingTermStructure().empty();
66 bool haveForeignDiscountCurve = !foreignCcyDiscountCurve_.empty();
67 bool haveDomesticDiscountCurve = !domesticCcyDiscountCurve_.empty();
68
69 QL_REQUIRE(
70 !(foreignIndexHasCurve && domesticIndexHasCurve && haveForeignDiscountCurve && haveDomesticDiscountCurve),
71 "CrossCcyBasisMtMResetSwapHelper - Have all curves, nothing to solve for.");
72
73 /* Link the curve being bootstrapped to the index if the index has
74 no projection curve */
75 if (foreignIndexHasCurve && haveForeignDiscountCurve) {
76 if (!domesticIndexHasCurve) {
79 }
80 // if we have both index and discounting curve on foreign leg,
81 // check foreignCcyFxFwdRateCurve and link it to foreign discount curve if empty
82 // (we are bootstrapping on domestic leg in this instance, so foreign leg needs to be fully determined
83 if (foreignCcyFxFwdRateCurve_.empty())
85 } else if (domesticIndexHasCurve && haveDomesticDiscountCurve) {
86 if (!foreignIndexHasCurve) {
89 }
90 // if we have both index and discounting curve on domestic leg,
91 // check domesticCcyFxFwdRateCurve and link it to domestic discount curve if empty
92 // (we are bootstrapping on foreign leg in this instance, so domestic leg needs to be fully determined
95 } else {
96 QL_FAIL("Need one leg of the cross currency basis swap to "
97 "have all of its curves.");
98 }
99
100 registerWith(spotFX_);
101 registerWith(domesticCcyIndex_);
102 registerWith(foreignCcyIndex_);
103 registerWith(foreignCcyDiscountCurve_);
104 registerWith(domesticCcyDiscountCurve_);
105 registerWith(foreignCcyFxFwdRateCurve_);
106 registerWith(domesticCcyFxFwdRateCurve_);
107
109}
110
112
113 Date refDate = evaluationDate_;
114 // if the evaluation date is not a business day
115 // then move to the next business day
116 refDate = settlementCalendar_.adjust(refDate);
117
118 Date settlementDate = settlementCalendar_.advance(refDate, settlementDays_, Days);
119 Date maturityDate = settlementDate + swapTenor_;
120
121 Schedule foreignLegSchedule = MakeSchedule()
122 .from(settlementDate)
123 .to(maturityDate)
124 .withTenor(foreignTenor_)
125 .withCalendar(settlementCalendar_)
126 .withConvention(rollConvention_)
127 .endOfMonth(eom_);
128
129 Schedule domesticLegSchedule = MakeSchedule()
130 .from(settlementDate)
131 .to(maturityDate)
132 .withTenor(domesticTenor_)
133 .withCalendar(settlementCalendar_)
134 .withConvention(rollConvention_)
135 .endOfMonth(eom_);
136
137 Real foreignNominal = 1.0;
138 // build an FX index for forward rate projection (TODO - review settlement and calendar)
139
140 QuantLib::ext::shared_ptr<FxIndex> fxIdx =
141 QuantLib::ext::make_shared<FxIndex>("dummy", settlementDays_, foreignCurrency_, domesticCurrency_, settlementCalendar_,
143
144 swap_ = QuantLib::ext::make_shared<CrossCcyBasisMtMResetSwap>(
145 foreignNominal, foreignCurrency_, foreignLegSchedule, foreignCcyIndex_, 0.0, domesticCurrency_,
146 domesticLegSchedule, domesticCcyIndex_, 0.0, fxIdx, true, foreignPaymentLag_, domesticPaymentLag_,
150
151 QuantLib::ext::shared_ptr<PricingEngine> engine = QuantLib::ext::make_shared<CrossCcySwapEngine>(
153 swap_->setPricingEngine(engine);
154
155 earliestDate_ = swap_->startDate();
156 latestDate_ = swap_->maturityDate();
157
158/* May need to adjust latestDate_ if you are projecting libor based
159 on tenor length rather than from accrual date to accrual date. */
160 if (!IborCoupon::Settings::instance().usingAtParCoupons()) {
161 if (termStructureHandle_ == foreignCcyIndex_->forwardingTermStructure()) {
162 Size numCashflows = swap_->leg(0).size();
163 Date endDate = latestDate_;
164 if (numCashflows > 0) {
165 for (Size i = numCashflows - 1; i >= 0; i--) {
166 QuantLib::ext::shared_ptr<FloatingRateCoupon> lastFloating =
167 QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(swap_->leg(0)[i]);
168 if (!lastFloating)
169 continue;
170 else {
171 Date fixingValueDate = foreignCcyIndex_->valueDate(lastFloating->fixingDate());
172 endDate = domesticCcyIndex_->maturityDate(fixingValueDate);
173 Date endValueDate = foreignCcyIndex_->maturityDate(fixingValueDate);
174 latestDate_ = std::max(latestDate_, endValueDate);
175 break;
176 }
177 }
178 }
179 }
180 if (termStructureHandle_ == domesticCcyIndex_->forwardingTermStructure()) {
181 Size numCashflows = swap_->leg(1).size();
182 Date endDate = latestDate_;
183 if (numCashflows > 0) {
184 for (Size i = numCashflows - 1; i >= 0; i--) {
185 QuantLib::ext::shared_ptr<FloatingRateCoupon> lastFloating =
186 QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(swap_->leg(1)[i]);
187 if (!lastFloating)
188 continue;
189 else {
190 Date fixingValueDate = domesticCcyIndex_->valueDate(lastFloating->fixingDate());
191 endDate = domesticCcyIndex_->maturityDate(fixingValueDate);
192 Date endValueDate = domesticCcyIndex_->maturityDate(fixingValueDate);
193 latestDate_ = std::max(latestDate_, endValueDate);
194 break;
195 }
196 }
197 }
198 }
199 }
200}
201
203
204 bool observer = false;
205 QuantLib::ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
206
207 termStructureHandle_.linkTo(temp, observer);
208
209 if (foreignCcyDiscountCurve_.empty())
210 foreignDiscountRLH_.linkTo(temp, observer);
211 else
213
214 if (domesticCcyDiscountCurve_.empty())
215 domesticDiscountRLH_.linkTo(temp, observer);
216 else
218
219 // the below are the curves used for FX forward rate projection (for the resetting cashflows)
220 if (foreignCcyFxFwdRateCurve_.empty())
221 foreignCcyFxFwdRateCurveRLH_.linkTo(temp, observer);
222 else
224
225 if (domesticCcyFxFwdRateCurve_.empty())
226 domesticCcyFxFwdRateCurveRLH_.linkTo(temp, observer);
227 else
229
230 RelativeDateRateHelper::setTermStructure(t);
231}
232
234 QL_REQUIRE(termStructure_, "Term structure needs to be set");
235 swap_->deepUpdate();
237 return swap_->fairForeignSpread();
238 else
239 return swap_->fairDomesticSpread();
240}
241
243 Visitor<CrossCcyBasisMtMResetSwapHelper>* v1 = dynamic_cast<Visitor<CrossCcyBasisMtMResetSwapHelper>*>(&v);
244 if (v1)
245 v1->visit(*this);
246 else
247 RateHelper::accept(v);
248}
249} // namespace QuantExt
CrossCcyBasisMtMResetSwapHelper(const Handle< Quote > &spreadQuote, const Handle< Quote > &spotFX, Natural settlementDays, const Calendar &settlementCalendar, const Period &swapTenor, BusinessDayConvention rollConvention, const QuantLib::ext::shared_ptr< QuantLib::IborIndex > &foreignCcyIndex, const QuantLib::ext::shared_ptr< QuantLib::IborIndex > &domesticCcyIndex, const Handle< YieldTermStructure > &foreignCcyDiscountCurve, const Handle< YieldTermStructure > &domesticCcyDiscountCurve, const Handle< YieldTermStructure > &foreignCcyFxFwdRateCurve=Handle< YieldTermStructure >(), const Handle< YieldTermStructure > &domesticCcyFxFwdRateCurve=Handle< YieldTermStructure >(), bool eom=false, bool spreadOnForeignCcy=true, boost::optional< QuantLib::Period > foreignTenor=boost::none, boost::optional< QuantLib::Period > domesticTenor=boost::none, Size foreignPaymentLag=0, Size domesticPaymentLag=0, boost::optional< bool > foreignIncludeSpread=boost::none, boost::optional< Period > foreignLookback=boost::none, boost::optional< Size > foreignFixingDays=boost::none, boost::optional< Size > foreignRateCutoff=boost::none, boost::optional< bool > foreignIsAveraged=boost::none, boost::optional< bool > domesticIncludeSpread=boost::none, boost::optional< Period > domesticLookback=boost::none, boost::optional< Size > domesticFixingDays=boost::none, boost::optional< Size > domesticRateCutoff=boost::none, boost::optional< bool > domesticIsAveraged=boost::none, const bool telescopicValueDates=false)
RelinkableHandle< YieldTermStructure > foreignCcyFxFwdRateCurveRLH_
RelinkableHandle< YieldTermStructure > termStructureHandle_
RelinkableHandle< YieldTermStructure > domesticDiscountRLH_
QuantLib::ext::shared_ptr< QuantLib::IborIndex > domesticCcyIndex_
RelinkableHandle< YieldTermStructure > foreignDiscountRLH_
QuantLib::ext::shared_ptr< CrossCcyBasisMtMResetSwap > swap_
QuantLib::ext::shared_ptr< QuantLib::IborIndex > foreignCcyIndex_
RelinkableHandle< YieldTermStructure > domesticCcyFxFwdRateCurveRLH_
Cross currency basis swap helper with MTM reset.
Cross currency swap engine.