QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
Loading...
Searching...
No Matches
crosscurrencyratehelpers.cpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2021 Marcin Rybacki
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
26#include <utility>
27
28namespace QuantLib {
29
30 namespace {
31
32 Schedule legSchedule(const Date& evaluationDate,
33 const Period& tenor,
34 const Period& frequency,
35 Natural fixingDays,
36 const Calendar& calendar,
37 BusinessDayConvention convention,
38 bool endOfMonth) {
39 QL_REQUIRE(tenor >= frequency,
40 "XCCY instrument tenor should not be smaller than coupon frequency.");
41
42 Date referenceDate = calendar.adjust(evaluationDate);
43 Date earliestDate = calendar.advance(referenceDate, fixingDays * Days, convention);
44 Date maturity = earliestDate + tenor;
45 return MakeSchedule()
46 .from(earliestDate)
47 .to(maturity)
48 .withTenor(frequency)
49 .withCalendar(calendar)
50 .withConvention(convention)
51 .endOfMonth(endOfMonth)
52 .backwards();
53 }
54
55 Leg buildFloatingLeg(const Date& evaluationDate,
56 const Period& tenor,
57 Natural fixingDays,
58 const Calendar& calendar,
59 BusinessDayConvention convention,
60 bool endOfMonth,
61 const ext::shared_ptr<IborIndex>& idx,
62 Frequency paymentFrequency,
63 Integer paymentLag) {
64 auto overnightIndex = ext::dynamic_pointer_cast<OvernightIndex>(idx);
65
66 Period freqPeriod;
67 if (paymentFrequency == NoFrequency) {
68 QL_REQUIRE(!overnightIndex, "Require payment frequency for overnight indices.");
69 freqPeriod = idx->tenor();
70 } else {
71 freqPeriod = Period(paymentFrequency);
72 }
73
74 Schedule sch = legSchedule(evaluationDate, tenor, freqPeriod, fixingDays, calendar,
75 convention, endOfMonth);
76 if (overnightIndex != nullptr) {
77 return OvernightLeg(sch, overnightIndex)
78 .withNotionals(1.0)
79 .withPaymentLag(paymentLag);
80 }
81 return IborLeg(sch, idx).withNotionals(1.0).withPaymentLag(paymentLag);
82 }
83
84 std::pair<Real, Real>
85 npvbpsConstNotionalLeg(const Leg& iborLeg,
86 const Date& initialNotionalExchangeDate,
87 const Date& finalNotionalExchangeDate,
88 const Handle<YieldTermStructure>& discountCurveHandle) {
89 const Spread basisPoint = 1.0e-4;
90 Date refDt = discountCurveHandle->referenceDate();
91 const YieldTermStructure& discountRef = **discountCurveHandle;
92 bool includeSettleDtFlows = true;
93 auto [npv, bps] = CashFlows::npvbps(iborLeg, discountRef, includeSettleDtFlows, refDt, refDt);
94 // Include NPV of the notional exchange at start and maturity.
95 npv += (-1.0) * discountRef.discount(initialNotionalExchangeDate);
96 npv += discountRef.discount(finalNotionalExchangeDate);
97 bps /= basisPoint;
98 return { npv, bps };
99 }
100
101 class ResettingLegHelper {
102 public:
103 explicit ResettingLegHelper(const YieldTermStructure& discountCurve,
104 const YieldTermStructure& foreignCurve)
105 : discountCurve_(discountCurve), foreignCurve_(foreignCurve) {}
106 DiscountFactor discount(const Date& d) const {
107 return discountCurve_.discount(d);
108 }
109 Real notionalAdjustment(const Date& d) const {
110 return foreignCurve_.discount(d) / discountCurve_.discount(d);
111 }
112
113 private:
114 const YieldTermStructure& discountCurve_;
115 const YieldTermStructure& foreignCurve_;
116 };
117
118 class ResettingLegCalculator : public AcyclicVisitor, public Visitor<Coupon> {
119 public:
120 explicit ResettingLegCalculator(const YieldTermStructure& discountCurve,
121 const YieldTermStructure& foreignCurve,
122 Integer paymentLag,
123 Calendar paymentCalendar,
124 BusinessDayConvention convention)
125 : helper_(discountCurve, foreignCurve), paymentLag_(paymentLag),
126 paymentCalendar_(std::move(paymentCalendar)), convention_(convention) {}
127
128 void visit(Coupon& c) override {
129 Date start = c.accrualStartDate();
130 Date end = c.accrualEndDate();
131 Time accrual = c.accrualPeriod();
132 Real adjustedNotional = c.nominal() * helper_.notionalAdjustment(start);
133
134 DiscountFactor discountStart, discountEnd;
135
136 if (paymentLag_ == 0) {
137 discountStart = helper_.discount(start);
138 discountEnd = helper_.discount(end);
139 } else {
140 Date paymentStart =
141 paymentCalendar_.advance(start, paymentLag_, Days, convention_);
142 Date paymentEnd = paymentCalendar_.advance(end, paymentLag_, Days, convention_);
143 discountStart = helper_.discount(paymentStart);
144 discountEnd = helper_.discount(paymentEnd);
145 }
146
147 // NPV of a resetting coupon consists of a redemption of borrowed amount occurring
148 // at the end of the accrual period plus the accrued interest, minus the borrowed
149 // amount at the start of the period. All amounts are corrected by an adjustment
150 // corresponding to the implied forward exchange rate, which is estimated by
151 // the ratio of foreign and domestic curves discount factors.
152 Real npvRedeemedAmount =
153 adjustedNotional * discountEnd * (1.0 + c.rate() * accrual);
154 Real npvBorrowedAmount = -adjustedNotional * discountStart;
155
156 npv_ += (npvRedeemedAmount + npvBorrowedAmount);
157 bps_ += adjustedNotional * discountEnd * accrual;
158 }
159 Real NPV() const { return npv_; }
160 Real BPS() const { return bps_; }
161
162 private:
163 ResettingLegHelper helper_;
164 Real npv_ = 0.0;
165 Real bps_ = 0.0;
169 };
170
171 std::pair<Real, Real> npvbpsResettingLeg(const Leg& iborLeg,
172 Integer paymentLag,
173 const Calendar& paymentCalendar,
174 BusinessDayConvention convention,
175 const Handle<YieldTermStructure>& discountCurveHandle,
176 const Handle<YieldTermStructure>& foreignCurveHandle) {
177 const YieldTermStructure& discountCurveRef = **discountCurveHandle;
178 const YieldTermStructure& foreignCurveRef = **foreignCurveHandle;
179
180 ResettingLegCalculator calc(discountCurveRef, foreignCurveRef, paymentLag,
181 paymentCalendar, convention);
182 for (const auto& i : iborLeg) {
183 CashFlow& cf = *i;
184 cf.accept(calc);
185 }
186 return { calc.NPV(), calc.BPS() };
187 }
188 }
189
191 const Handle<Quote>& basis,
192 const Period& tenor,
193 Natural fixingDays,
194 Calendar calendar,
195 BusinessDayConvention convention,
196 bool endOfMonth,
197 ext::shared_ptr<IborIndex> baseCurrencyIndex,
198 ext::shared_ptr<IborIndex> quoteCurrencyIndex,
199 Handle<YieldTermStructure> collateralCurve,
200 bool isFxBaseCurrencyCollateralCurrency,
201 bool isBasisOnFxBaseCurrencyLeg,
202 Frequency paymentFrequency,
203 Integer paymentLag)
204 : RelativeDateRateHelper(basis), tenor_(tenor), fixingDays_(fixingDays),
205 calendar_(std::move(calendar)), convention_(convention), endOfMonth_(endOfMonth),
206 baseCcyIdx_(std::move(baseCurrencyIndex)), quoteCcyIdx_(std::move(quoteCurrencyIndex)),
207 collateralHandle_(std::move(collateralCurve)),
208 isFxBaseCurrencyCollateralCurrency_(isFxBaseCurrencyCollateralCurrency),
209 isBasisOnFxBaseCurrencyLeg_(isBasisOnFxBaseCurrencyLeg),
210 paymentFrequency_(paymentFrequency), paymentLag_(paymentLag) {
215 }
216
226 if (paymentLag_ == 0) {
229 } else {
232 }
233 Date lastPaymentDate = std::max(baseCcyIborLeg_.back()->date(), quoteCcyIborLeg_.back()->date());
234 latestRelevantDate_ = latestDate_ = std::max(maturityDate_, lastPaymentDate);
235 }
236
239 QL_REQUIRE(!termStructureHandle_.empty(), "term structure not set");
240 QL_REQUIRE(!collateralHandle_.empty(), "collateral term structure not set");
242 }
243
246 QL_REQUIRE(!termStructureHandle_.empty(), "term structure not set");
247 QL_REQUIRE(!collateralHandle_.empty(), "collateral term structure not set");
249 }
250
252 // do not set the relinkable handle as an observer -
253 // force recalculation when needed
254 bool observer = false;
255
256 ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
257 termStructureHandle_.linkTo(temp, observer);
258
260 }
261
263 const Handle<Quote>& basis,
264 const Period& tenor,
265 Natural fixingDays,
266 const Calendar& calendar,
267 BusinessDayConvention convention,
268 bool endOfMonth,
269 const ext::shared_ptr<IborIndex>& baseCurrencyIndex,
270 const ext::shared_ptr<IborIndex>& quoteCurrencyIndex,
271 const Handle<YieldTermStructure>& collateralCurve,
272 bool isFxBaseCurrencyCollateralCurrency,
273 bool isBasisOnFxBaseCurrencyLeg,
274 Frequency paymentFrequency,
275 Integer paymentLag)
277 tenor,
278 fixingDays,
279 calendar,
280 convention,
281 endOfMonth,
282 baseCurrencyIndex,
283 quoteCurrencyIndex,
284 collateralCurve,
285 isFxBaseCurrencyCollateralCurrency,
286 isBasisOnFxBaseCurrencyLeg,
287 paymentFrequency,
288 paymentLag) {}
289
291 auto [npvBaseCcy, bpsBaseCcy] = npvbpsConstNotionalLeg(baseCcyIborLeg_, initialNotionalExchangeDate_, finalNotionalExchangeDate_, baseCcyLegDiscountHandle());
292 auto [npvQuoteCcy, bpsQuoteCcy] = npvbpsConstNotionalLeg(quoteCcyIborLeg_, initialNotionalExchangeDate_, finalNotionalExchangeDate_, quoteCcyLegDiscountHandle());
293 Real bps = isBasisOnFxBaseCurrencyLeg_ ? -bpsBaseCcy : bpsQuoteCcy;
294 return -(npvQuoteCcy - npvBaseCcy) / bps;
295 }
296
299 if (v1 != nullptr)
300 v1->visit(*this);
301 else
303 }
304
306 const Handle<Quote>& basis,
307 const Period& tenor,
308 Natural fixingDays,
309 const Calendar& calendar,
310 BusinessDayConvention convention,
311 bool endOfMonth,
312 const ext::shared_ptr<IborIndex>& baseCurrencyIndex,
313 const ext::shared_ptr<IborIndex>& quoteCurrencyIndex,
314 const Handle<YieldTermStructure>& collateralCurve,
315 bool isFxBaseCurrencyCollateralCurrency,
316 bool isBasisOnFxBaseCurrencyLeg,
317 bool isFxBaseCurrencyLegResettable,
318 Frequency paymentFrequency,
319 Integer paymentLag)
321 tenor,
322 fixingDays,
323 calendar,
324 convention,
325 endOfMonth,
326 baseCurrencyIndex,
327 quoteCurrencyIndex,
328 collateralCurve,
329 isFxBaseCurrencyCollateralCurrency,
330 isBasisOnFxBaseCurrencyLeg,
331 paymentFrequency,
332 paymentLag),
333 isFxBaseCurrencyLegResettable_(isFxBaseCurrencyLegResettable) {}
334
336 Real npvBaseCcy = 0.0, bpsBaseCcy = 0.0;
337 Real npvQuoteCcy = 0.0, bpsQuoteCcy = 0.0;
339 std::tie(npvBaseCcy, bpsBaseCcy) =
340 npvbpsResettingLeg(baseCcyIborLeg_, paymentLag_, calendar_, convention_,
342 std::tie(npvQuoteCcy, bpsQuoteCcy) =
343 npvbpsConstNotionalLeg(quoteCcyIborLeg_, initialNotionalExchangeDate_,
345 } else {
346 std::tie(npvBaseCcy, bpsBaseCcy) =
347 npvbpsConstNotionalLeg(baseCcyIborLeg_, initialNotionalExchangeDate_,
349 std::tie(npvQuoteCcy, bpsQuoteCcy) = npvbpsResettingLeg(
352 }
353
354 Real bps = isBasisOnFxBaseCurrencyLeg_ ? -bpsBaseCcy : bpsQuoteCcy;
355
356 return -(npvQuoteCcy - npvBaseCcy) / bps;
357 }
358
360 auto* v1 = dynamic_cast<Visitor<MtMCrossCurrencyBasisSwapRateHelper>*>(&v);
361 if (v1 != nullptr)
362 v1->visit(*this);
363 else
365 }
366}
Real bps_
Definition: cashflows.cpp:419
Real npv_
Definition: cashflows.cpp:1185
const YieldTermStructure & discountCurve_
Definition: cashflows.cpp:418
Cash-flow analysis functions.
degenerate base class for the Acyclic Visitor pattern
Definition: visitor.hpp:33
virtual void accept(AcyclicVisitor &)
virtual void setTermStructure(TS *)
sets the term structure to be used for pricing
calendar class
Definition: calendar.hpp:61
Date advance(const Date &, Integer n, TimeUnit unit, BusinessDayConvention convention=Following, bool endOfMonth=false) const
Definition: calendar.cpp:130
static Date maturityDate(const Leg &leg)
Definition: cashflows.cpp:52
static Date startDate(const Leg &leg)
Definition: cashflows.cpp:38
static std::pair< Real, Real > npvbps(const Leg &leg, const YieldTermStructure &discountCurve, bool includeSettlementDateFlows, Date settlementDate=Date(), Date npvDate=Date())
NPV and BPS of the cash flows.
Definition: cashflows.cpp:473
ConstNotionalCrossCurrencyBasisSwapRateHelper(const Handle< Quote > &basis, const Period &tenor, Natural fixingDays, const Calendar &calendar, BusinessDayConvention convention, bool endOfMonth, const ext::shared_ptr< IborIndex > &baseCurrencyIndex, const ext::shared_ptr< IborIndex > &quoteCurrencyIndex, const Handle< YieldTermStructure > &collateralCurve, bool isFxBaseCurrencyCollateralCurrency, bool isBasisOnFxBaseCurrencyLeg, Frequency paymentFrequency=NoFrequency, Integer paymentLag=0)
Base class for cross-currency basis swap rate helpers.
void setTermStructure(YieldTermStructure *) override
RelinkableHandle< YieldTermStructure > termStructureHandle_
const Handle< YieldTermStructure > & baseCcyLegDiscountHandle() const
const Handle< YieldTermStructure > & quoteCcyLegDiscountHandle() const
CrossCurrencyBasisSwapRateHelperBase(const Handle< Quote > &basis, const Period &tenor, Natural fixingDays, Calendar calendar, BusinessDayConvention convention, bool endOfMonth, ext::shared_ptr< IborIndex > baseCurrencyIndex, ext::shared_ptr< IborIndex > quoteCurrencyIndex, Handle< YieldTermStructure > collateralCurve, bool isFxBaseCurrencyCollateralCurrency, bool isBasisOnFxBaseCurrencyLeg, Frequency paymentFrequency=NoFrequency, Integer paymentLag=0)
Concrete date class.
Definition: date.hpp:125
Shared handle to an observable.
Definition: handle.hpp:41
MtMCrossCurrencyBasisSwapRateHelper(const Handle< Quote > &basis, const Period &tenor, Natural fixingDays, const Calendar &calendar, BusinessDayConvention convention, bool endOfMonth, const ext::shared_ptr< IborIndex > &baseCurrencyIndex, const ext::shared_ptr< IborIndex > &quoteCurrencyIndex, const Handle< YieldTermStructure > &collateralCurve, bool isFxBaseCurrencyCollateralCurrency, bool isBasisOnFxBaseCurrencyLeg, bool isFxBaseCurrencyLegResettable, Frequency paymentFrequency=NoFrequency, Integer paymentLag=0)
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:226
Bootstrap helper with date schedule relative to global evaluation date.
Visitor for a specific class
Definition: visitor.hpp:40
virtual void visit(T &)=0
Interest-rate term structure.
ResettingLegHelper helper_
Calendar paymentCalendar_
Integer paymentLag_
BusinessDayConvention convention_
const YieldTermStructure & foreignCurve_
FX and cross currency basis swaps rate helpers.
const DefaultType & t
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
Date d
Frequency
Frequency of events.
Definition: frequency.hpp:37
BusinessDayConvention
Business Day conventions.
@ NoFrequency
null frequency
Definition: frequency.hpp:37
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
Real DiscountFactor
discount factor between dates
Definition: types.hpp:66
unsigned QL_INTEGER Natural
positive integer
Definition: types.hpp:43
QL_INTEGER Integer
integer number
Definition: types.hpp:35
Real Spread
spreads on interest rates
Definition: types.hpp:74
Coupon paying a Libor-type index.
Definition: any.hpp:37
MarketModelMultiProduct::CashFlow CashFlow
std::vector< ext::shared_ptr< CashFlow > > Leg
Sequence of cash-flows.
Definition: cashflow.hpp:78
STL namespace.
empty deleter for shared_ptr
coupon paying the compounded daily overnight rate
ext::shared_ptr< BlackVolTermStructure > v
Predetermined cash flow.