Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
crossccybasisswaphelper.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#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>& flatIndex, const QuantLib::ext::shared_ptr<QuantLib::IborIndex>& spreadIndex,
32 const Handle<YieldTermStructure>& flatDiscountCurve, const Handle<YieldTermStructure>& spreadDiscountCurve,
33 bool eom, bool flatIsDomestic, boost::optional<Period> flatTenor, boost::optional<Period> spreadTenor,
34 Real spreadOnFlatLeg, Real flatGearing, Real spreadGearing, const Calendar& flatCalendar,
35 const Calendar& spreadCalendar, const std::vector<Natural>& spotFXSettleDaysVec,
36 const std::vector<Calendar>& spotFXSettleCalendarVec, Size paymentLag, Size flatPaymentLag,
37 boost::optional<bool> includeSpread, boost::optional<Period> lookback, boost::optional<Size> fixingDays,
38 boost::optional<Size> rateCutoff, boost::optional<bool> isAveraged, boost::optional<bool> flatIncludeSpread,
39 boost::optional<Period> flatLookback, boost::optional<Size> flatFixingDays, boost::optional<Size> flatRateCutoff,
40 boost::optional<bool> flatIsAveraged, const bool telescopicValueDates)
41 : RelativeDateRateHelper(spreadQuote), spotFX_(spotFX), settlementDays_(settlementDays),
42 settlementCalendar_(settlementCalendar), swapTenor_(swapTenor), rollConvention_(rollConvention),
43 flatIndex_(flatIndex), spreadIndex_(spreadIndex), flatDiscountCurve_(flatDiscountCurve),
44 spreadDiscountCurve_(spreadDiscountCurve), eom_(eom), flatIsDomestic_(flatIsDomestic),
45 flatTenor_(flatTenor ? *flatTenor : flatIndex_->tenor()),
46 spreadTenor_(spreadTenor ? *spreadTenor : spreadIndex_->tenor()), spreadOnFlatLeg_(spreadOnFlatLeg),
47 flatGearing_(flatGearing), spreadGearing_(spreadGearing), flatCalendar_(flatCalendar),
48 spreadCalendar_(spreadCalendar), spotFXSettleDaysVec_(spotFXSettleDaysVec),
49 spotFXSettleCalendarVec_(spotFXSettleCalendarVec), paymentLag_(paymentLag), flatPaymentLag_(flatPaymentLag),
50 includeSpread_(includeSpread), lookback_(lookback), fixingDays_(fixingDays), rateCutoff_(rateCutoff),
51 isAveraged_(isAveraged), flatIncludeSpread_(flatIncludeSpread), flatLookback_(flatLookback),
52 flatFixingDays_(flatFixingDays), flatRateCutoff_(flatRateCutoff), flatIsAveraged_(flatIsAveraged),
53 telescopicValueDates_(telescopicValueDates) {
54
55 flatLegCurrency_ = flatIndex_->currency();
56 spreadLegCurrency_ = spreadIndex_->currency();
57
58 bool flatIndexHasCurve = !flatIndex_->forwardingTermStructure().empty();
59 bool spreadIndexHasCurve = !spreadIndex_->forwardingTermStructure().empty();
60 bool haveFlatDiscountCurve = !flatDiscountCurve_.empty();
61 bool haveSpreadDiscountCurve = !spreadDiscountCurve_.empty();
62
63 QL_REQUIRE(!(flatIndexHasCurve && spreadIndexHasCurve && haveFlatDiscountCurve && haveSpreadDiscountCurve),
64 "Have all curves, "
65 "nothing to solve for.");
66
67 if (flatCalendar_.empty())
68 flatCalendar_ = settlementCalendar;
69 if (spreadCalendar_.empty())
70 spreadCalendar_ = settlementCalendar;
71
72 // check spotFXSettleDaysVec_ and spotFXSettleCalendarVec_
73 Size numSpotFXSettleDays = spotFXSettleDaysVec_.size();
74 QL_REQUIRE(numSpotFXSettleDays == spotFXSettleCalendarVec_.size(),
75 "Array size of spot fx settlement days must equal that of spot fx settlement calendars");
76 if (numSpotFXSettleDays == 0) {
77 spotFXSettleDaysVec_.resize(1, 0);
78 spotFXSettleCalendarVec_.resize(1, settlementCalendar);
79 }
80
81 /* Link the curve being bootstrapped to the index if the index has
82 no projection curve */
83 if (flatIndexHasCurve && haveFlatDiscountCurve) {
84 if (!spreadIndexHasCurve) {
86 spreadIndex_->unregisterWith(termStructureHandle_);
87 }
88 } else if (spreadIndexHasCurve && haveSpreadDiscountCurve) {
89 if (!flatIndexHasCurve) {
91 flatIndex_->unregisterWith(termStructureHandle_);
92 }
93 } else {
94 QL_FAIL("Need one leg of the cross currency basis swap to "
95 "have all of its curves.");
96 }
97
98 registerWith(spotFX_);
99 registerWith(flatIndex_);
100 registerWith(spreadIndex_);
101 registerWith(flatDiscountCurve_);
102 registerWith(spreadDiscountCurve_);
103
105}
106
108
109 Date refDate = evaluationDate_;
110 // if the evaluation date is not a business day
111 // then move to the next business day
112 refDate = settlementCalendar_.adjust(refDate);
113
114 Date settlementDate = settlementCalendar_.advance(refDate, settlementDays_, Days);
115 Date maturityDate = settlementDate + swapTenor_;
116
117 // calc spotFXSettleDate
118 Date spotFXSettleDate = refDate;
119 Size numSpotFXSettleDays = spotFXSettleDaysVec_.size(); // guaranteed to be at least 1
120 for (Size i = 0; i < numSpotFXSettleDays; i++) {
121 // Guaranteed here that spotFXSettleDaysVec_ and spotFXSettleCalendarVec_ have the same size
122 spotFXSettleDate = spotFXSettleCalendarVec_[i].advance(spotFXSettleDate, spotFXSettleDaysVec_[i], Days);
123 }
124
125 Schedule flatLegSchedule = MakeSchedule()
126 .from(settlementDate)
127 .to(maturityDate)
128 .withTenor(flatTenor_)
129 .withCalendar(flatCalendar_)
130 .withConvention(rollConvention_)
131 .endOfMonth(eom_);
132
133 Schedule spreadLegSchedule = MakeSchedule()
134 .from(settlementDate)
135 .to(maturityDate)
136 .withTenor(spreadTenor_)
137 .withCalendar(spreadCalendar_)
138 .withConvention(rollConvention_)
139 .endOfMonth(eom_);
140
141 Real flatLegNominal = 1.0;
142 Real spreadLegNominal = 1.0;
143 if (flatIsDomestic_) {
144 flatLegNominal = spotFX_->value();
145 } else {
146 spreadLegNominal = spotFX_->value();
147 }
148
149 /* Arbitrarily set the spread leg as the pay leg */
150 swap_ = QuantLib::ext::make_shared<CrossCcyBasisSwap>(
151 spreadLegNominal, spreadLegCurrency_, spreadLegSchedule, spreadIndex_, 0.0, spreadGearing_, flatLegNominal,
155
156 QuantLib::ext::shared_ptr<PricingEngine> engine;
157 if (flatIsDomestic_) {
158 engine = QuantLib::ext::make_shared<CrossCcySwapEngine>(flatLegCurrency_, flatDiscountRLH_, spreadLegCurrency_,
159 spreadDiscountRLH_, spotFX_, boost::none, Date(), Date(),
160 spotFXSettleDate);
161 } else {
162 engine = QuantLib::ext::make_shared<CrossCcySwapEngine>(spreadLegCurrency_, spreadDiscountRLH_, flatLegCurrency_,
163 flatDiscountRLH_, spotFX_, boost::none, Date(), Date(),
164 spotFXSettleDate);
165 }
166 swap_->setPricingEngine(engine);
167
168 earliestDate_ = swap_->startDate();
169 latestDate_ = swap_->maturityDate();
170
171/* May need to adjust latestDate_ if you are projecting libor based
172 on tenor length rather than from accrual date to accrual date. */
173 if (!IborCoupon::Settings::instance().usingAtParCoupons()) {
174 if (termStructureHandle_ == spreadIndex_->forwardingTermStructure()) {
175 Size numCashflows = swap_->leg(0).size();
176 if (numCashflows > 2) {
177 QuantLib::ext::shared_ptr<FloatingRateCoupon> lastFloating =
178 QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(swap_->leg(0)[numCashflows - 2]);
179 Date fixingValueDate = spreadIndex_->valueDate(lastFloating->fixingDate());
180 Date endValueDate = spreadIndex_->maturityDate(fixingValueDate);
181 latestDate_ = std::max(latestDate_, endValueDate);
182 }
183 }
184 if (termStructureHandle_ == flatIndex_->forwardingTermStructure()) {
185 Size numCashflows = swap_->leg(1).size();
186 if (numCashflows > 2) {
187 QuantLib::ext::shared_ptr<FloatingRateCoupon> lastFloating =
188 QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(swap_->leg(1)[numCashflows - 2]);
189 Date fixingValueDate = flatIndex_->valueDate(lastFloating->fixingDate());
190 Date endValueDate = flatIndex_->maturityDate(fixingValueDate);
191 latestDate_ = std::max(latestDate_, endValueDate);
192 }
193 }
194 }
195}
196
197void CrossCcyBasisSwapHelper::setTermStructure(YieldTermStructure* t) {
198
199 bool observer = false;
200 QuantLib::ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
201
202 termStructureHandle_.linkTo(temp, observer);
203
204 if (flatDiscountCurve_.empty())
205 flatDiscountRLH_.linkTo(temp, observer);
206 else
207 flatDiscountRLH_.linkTo(*flatDiscountCurve_, observer);
208
209 if (spreadDiscountCurve_.empty())
210 spreadDiscountRLH_.linkTo(temp, observer);
211 else
212 spreadDiscountRLH_.linkTo(*spreadDiscountCurve_, observer);
213
214 RelativeDateRateHelper::setTermStructure(t);
215}
216
218 QL_REQUIRE(termStructure_, "Term structure needs to be set");
219 swap_->deepUpdate();
220 return swap_->fairPaySpread();
221}
222
223void CrossCcyBasisSwapHelper::accept(AcyclicVisitor& v) {
224 Visitor<CrossCcyBasisSwapHelper>* v1 = dynamic_cast<Visitor<CrossCcyBasisSwapHelper>*>(&v);
225 if (v1)
226 v1->visit(*this);
227 else
228 RateHelper::accept(v);
229}
230} // namespace QuantExt
RelinkableHandle< YieldTermStructure > spreadDiscountRLH_
void setTermStructure(YieldTermStructure *) override
CrossCcyBasisSwapHelper(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 > &flatIndex, const QuantLib::ext::shared_ptr< QuantLib::IborIndex > &spreadIndex, const Handle< YieldTermStructure > &flatDiscountCurve, const Handle< YieldTermStructure > &spreadDiscountCurve, bool eom=false, bool flatIsDomestic=true, boost::optional< QuantLib::Period > flatTenor=boost::none, boost::optional< QuantLib::Period > spreadTenor=boost::none, Real spreadOnFlatLeg=0.0, Real flatGearing=1.0, Real spreadGearing=1.0, const Calendar &flatCalendar=Calendar(), const Calendar &spreadCalendar=Calendar(), const std::vector< Natural > &spotFXSettleDaysVec=std::vector< Natural >(), const std::vector< Calendar > &spotFXSettleCalendar=std::vector< Calendar >(), Size paymentLag=0, Size flatPaymentLag=0, boost::optional< bool > includeSpread=boost::none, boost::optional< Period > lookback=boost::none, boost::optional< Size > fixingDays=boost::none, boost::optional< Size > rateCutoff=boost::none, boost::optional< bool > isAveraged=boost::none, boost::optional< bool > flatIncludeSpread=boost::none, boost::optional< Period > flatLookback=boost::none, boost::optional< Size > flatFixingDays=boost::none, boost::optional< Size > flatRateCutoff=boost::none, boost::optional< bool > flatIsAveraged=boost::none, const bool telescopicValueDates=false)
RelinkableHandle< YieldTermStructure > termStructureHandle_
boost::optional< QuantLib::Size > fixingDays_
boost::optional< QuantLib::Size > flatFixingDays_
boost::optional< QuantLib::Period > lookback_
RelinkableHandle< YieldTermStructure > flatDiscountRLH_
void accept(AcyclicVisitor &) override
QuantLib::ext::shared_ptr< QuantLib::IborIndex > spreadIndex_
Handle< YieldTermStructure > spreadDiscountCurve_
QuantLib::ext::shared_ptr< CrossCcyBasisSwap > swap_
boost::optional< QuantLib::Period > flatLookback_
QuantLib::ext::shared_ptr< QuantLib::IborIndex > flatIndex_
Handle< YieldTermStructure > flatDiscountCurve_
std::vector< Calendar > spotFXSettleCalendarVec_
Cross currency basis swap helper.
Cross currency swap engine.