Skip to content

Commit d823f4e

Browse files
authored
Implement ZeroCouponInflationSwap::fixedLegBPS() (#2360)
2 parents aa0fa6f + db1b59c commit d823f4e

File tree

4 files changed

+43
-4
lines changed

4 files changed

+43
-4
lines changed

ql/instruments/zerocouponinflationswap.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,25 @@ namespace QuantLib {
143143
// maturityDate(), observationLag(), infIndex_->interpolated());
144144
}
145145

146+
Real ZeroCouponInflationSwap::fixedLegBPS() const {
147+
// legBPS_[0] is 0, because fixed leg uses a SimpleCashFlow. BPSCalculator assumes
148+
// that simple cashflows are not sensitive to fixedRate. We could change that to a
149+
// FixedRateCoupon, however BPSCalculator also assumes that all coupons are linear
150+
// in fixedRate. Our fixed leg uses annual compounding, so it does not compute the
151+
// right number.
152+
calculate();
153+
QL_REQUIRE(endDiscounts_[0] != Null<DiscountFactor>(),
154+
"cannot calculate fixedLegBPS because end discount is not populated");
155+
156+
const Spread basisPoint = 1.0e-4;
157+
DiscountFactor df = payer_[0] * endDiscounts_[0];
158+
Real T =
159+
inflationYearFraction(infIndex_->frequency(),
160+
detail::CPI::isInterpolated(observationInterpolation_),
161+
dayCounter_, baseDate_, obsDate_);
162+
163+
return df * nominal_ * (pow(1.0 + fixedRate_ + basisPoint, T) - pow(1.0 + fixedRate_, T));
164+
}
146165

147166
Real ZeroCouponInflationSwap::fixedLegNPV() const {
148167
calculate();

ql/instruments/zerocouponinflationswap.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ namespace QuantLib {
120120
//! \name Results
121121
//@{
122122
Real fixedLegNPV() const;
123+
Real fixedLegBPS() const;
123124
Real inflationLegNPV() const;
124125
Real fairRate() const;
125126
//@}

ql/instruments/zerocouponswap.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ namespace QuantLib {
107107
paymentDelay) {
108108

109109
legs_[0].push_back(
110-
ext::shared_ptr<CashFlow>(new SimpleCashFlow(fixedPayment, paymentDate_)));
110+
ext::make_shared<SimpleCashFlow>(fixedPayment, paymentDate_));
111111
}
112112

113113
ZeroCouponSwap::ZeroCouponSwap(Type type,
@@ -130,8 +130,8 @@ namespace QuantLib {
130130
paymentDelay) {
131131

132132
InterestRate interest(fixedRate, fixedDayCounter, Compounded, Annual);
133-
legs_[0].push_back(ext::shared_ptr<CashFlow>(
134-
new FixedRateCoupon(paymentDate_, baseNominal_, interest, startDate, maturityDate)));
133+
legs_[0].push_back(ext::make_shared<FixedRateCoupon>(
134+
paymentDate_, baseNominal_, std::move(interest), startDate, maturityDate));
135135
}
136136

137137
Real ZeroCouponSwap::fixedLegNPV() const {

test-suite/inflation.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ BOOST_AUTO_TEST_CASE(testZeroTermStructure) {
391391
// first check that the quoted swaps are repriced correctly
392392

393393
const Real eps = 1.0e-7;
394+
const Spread basisPoint = 1.0e-4;
394395
auto engine = ext::make_shared<DiscountingSwapEngine>(nominalTS);
395396

396397
for (const auto& datum: zcData) {
@@ -408,7 +409,25 @@ BOOST_AUTO_TEST_CASE(testZeroTermStructure) {
408409
"zero-coupon inflation swap does not reprice to zero"
409410
<< "\n NPV: " << nzcis.NPV()
410411
<< "\n maturity: " << nzcis.maturityDate()
411-
<< "\n rate: " << datum.rate/100.0);
412+
<< "\n rate: " << nzcis.fixedRate());
413+
414+
ZeroCouponInflationSwap nzcisBumped(Swap::Payer,
415+
1000000.0,
416+
evaluationDate,
417+
datum.date,
418+
calendar, bdc, dc,
419+
datum.rate/100.0 + basisPoint,
420+
ii, observationLag,
421+
CPI::AsIndex);
422+
nzcisBumped.setPricingEngine(engine);
423+
424+
const Real expected = nzcisBumped.legNPV(0) - nzcis.legNPV(0);
425+
BOOST_CHECK_MESSAGE(std::fabs(nzcis.fixedLegBPS() - expected) < eps,
426+
"zero-coupon inflation swap does not have correct fixedLegBPS"
427+
<< "\n actual: " << nzcis.fixedLegBPS()
428+
<< "\n expected: " << expected
429+
<< "\n maturity: " << nzcis.maturityDate()
430+
<< "\n rate: " << nzcis.fixedRate());
412431
}
413432

414433
//===========================================================================================

0 commit comments

Comments
 (0)