23#include <ql/cashflows/cashflowvectors.hpp>
24#include <ql/time/daycounters/thirty360.hpp>
27#include <ql/cashflows/cpicouponpricer.hpp>
35 Rate r = QuantLib::CPICoupon::rate() ;
37 Rate adjusted_r = r / fixedRate_;
38 r = (adjusted_r - 1) * fixedRate_;
49 if (cap != Null<Rate>()) {
53 if (floor != Null<Rate>()) {
58 if (cap != Null<Rate>()) {
62 if (floor != Null<Rate>()) {
68 QL_REQUIRE(cap >= floor,
"cap level (" << cap <<
") less than floor level (" << floor <<
")");
74 :
CPICoupon(underlying->baseCPI(), underlying->baseDate(), underlying->date(), underlying->nominal(), underlying->accrualStartDate(),
75 underlying->accrualEndDate(), underlying->cpiIndex(),
76 underlying->observationLag(), underlying->observationInterpolation(), underlying->dayCounter(),
77 underlying->fixedRate(), underlying->referencePeriodStart(),
78 underlying->referencePeriodEnd(), underlying->exCouponDate(), underlying->subtractInflationNotional()),
79 underlying_(underlying), startDate_(startDate), isFloored_(false), isCapped_(false) {
84 Calendar cal =
underlying->cpiIndex()->fixingCalendar();
85 BusinessDayConvention conv = Unadjusted;
88 Rate effectiveCap =
cap_;
89 cpiCap_ = QuantLib::ext::make_shared<CPICapFloor>(
102 Rate effectiveFloor =
floor_;
103 cpiFloor_ = QuantLib::ext::make_shared<CPICapFloor>(
105 cal, conv, effectiveFloor,
underlying_->cpiIndex(),
113 QuantLib::ext::shared_ptr<CappedFlooredCPICouponPricer> blackPricer =
114 QuantLib::ext::dynamic_pointer_cast<CappedFlooredCPICouponPricer>(
pricer_);
115 QL_REQUIRE(blackPricer,
"BlackCPICouponPricer or BachelierCPICouponPricer expected");
116 Real capValue = 0.0, floorValue = 0.0;
118 cpiCap_->setPricingEngine(blackPricer->engine());
122 cpiFloor_->setPricingEngine(blackPricer->engine());
125 Real discount = blackPricer->yieldCurve()->discount(
underlying_->date());
128 Real capAmount = capValue / (nominal * discount);
129 Real floorAmount = floorValue / (nominal * discount);
133 Rate floorletRate = floorAmount *
underlying_->fixedRate();
134 Rate capletRate = capAmount *
underlying_->fixedRate();
136 Rate totalRate = swapletRate + floorletRate - capletRate;
144 Visitor<CappedFlooredCPICoupon>* v1 =
dynamic_cast<Visitor<CappedFlooredCPICoupon>*
>(&v);
148 CPICoupon::accept(v);
152 Period observationLag, Rate cap, Rate floor)
153 : CPICashFlow(underlying->notional(), underlying->cpiIndex(),
154 startDate - observationLag, underlying->baseFixing(), underlying->observationDate(),
155 underlying->observationLag(), underlying->interpolation(),
157 underlying->growthOnly()),
158 underlying_(underlying), startDate_(startDate), observationLag_(observationLag), isFloored_(false),
164 auto index = QuantLib::ext::dynamic_pointer_cast<ZeroInflationIndex>(
underlying->index());
165 Calendar cal = index->fixingCalendar();
166 BusinessDayConvention conv = Unadjusted;
184 if (cap != Null<Rate>()) {
188 if (floor != Null<Rate>()) {
193 QL_REQUIRE(cap >= floor,
"cap level (" << cap <<
") less than floor level (" << floor <<
")");
207 QL_REQUIRE(
pricer_,
"pricer not set for capped/floored CPI cashflow");
208 Real capValue = 0.0, floorValue = 0.0;
218 Real capAmount = capValue / discount;
219 Real floorAmount = floorValue / discount;
221 Real totalAmount = underlyingAmount - capAmount + floorAmount;
225CPILeg::CPILeg(
const Schedule& schedule,
const ext::shared_ptr<ZeroInflationIndex>& index,
226 const Handle<YieldTermStructure>& rateCurve,
const Real baseCPI,
const Period& observationLag)
227 : schedule_(schedule), index_(index), rateCurve_(rateCurve), baseCPI_(baseCPI), observationLag_(observationLag),
228 paymentDayCounter_(Thirty360(Thirty360::BondBasis)), paymentAdjustment_(ModifiedFollowing), paymentCalendar_(schedule.calendar()),
229 fixingDays_(std::vector<Natural>(1, 0)), observationInterpolation_(CPI::AsIndex), subtractInflationNominal_(true),
230 finalFlowCap_(Null<Real>()), finalFlowFloor_(Null<Real>()), subtractInflationNominalAllCoupons_(false),
231 startDate_(schedule_.dates().front()) {
232 QL_REQUIRE(
schedule_.dates().size() > 0,
"empty schedule passed to CPILeg");
296 caps_ = std::vector<Rate>(1, cap);
306 floors_ = std::vector<Rate>(1, floor);
349CPILeg::operator Leg()
const {
351 QL_REQUIRE(!notionals_.empty(),
"no notional given");
352 Size n = schedule_.size() - 1;
355 Date baseDate = baseDate_ == Date() ? startDate_ - observationLag_ : baseDate_;
357 QL_REQUIRE(!fixedRates_.empty(),
"no fixedRates given");
359 Date refStart, start, refEnd, end;
361 for (Size i = 0; i < n; ++i) {
362 refStart = start = schedule_.date(i);
363 refEnd = end = schedule_.date(i + 1);
364 Date paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_);
367 if (exCouponPeriod_ != Period()) {
369 exCouponCalendar_.advance(paymentDate, -exCouponPeriod_, exCouponAdjustment_, exCouponEndOfMonth_);
372 if (i == 0 && schedule_.hasIsRegular() && !schedule_.isRegular(i + 1)) {
373 BusinessDayConvention bdc = schedule_.businessDayConvention();
374 refStart = schedule_.calendar().adjust(end - schedule_.tenor(), bdc);
376 if (i == n - 1 && schedule_.hasIsRegular() && !schedule_.isRegular(i + 1)) {
377 BusinessDayConvention bdc = schedule_.businessDayConvention();
378 refEnd = schedule_.calendar().adjust(start + schedule_.tenor(), bdc);
381 auto coup = ext::make_shared<CPICoupon>(
383 baseDate, paymentDate, detail::get(notionals_, i, 0.0), start, end, index_, observationLag_,
384 observationInterpolation_, paymentDayCounter_, detail::get(fixedRates_, i, 0.0),
385 refStart, refEnd, exCouponDate, subtractInflationNominalAllCoupons_);
388 auto pricer = ext::make_shared<CPICouponPricer>(Handle<YieldTermStructure>(rateCurve_));
389 coup->setPricer(pricer);
391 if (detail::noOption(caps_, floors_, i)) {
394 auto cfCoup = ext::make_shared<CappedFlooredCPICoupon>(
395 coup, startDate_, detail::get(caps_, i, Null<Rate>()), detail::get(floors_, i, Null<Rate>()));
397 leg.push_back(cfCoup);
405 Date observationDate = paymentCalendar_.adjust(schedule_.date(n), paymentAdjustment_);
406 Date paymentDate = paymentCalendar_.advance(schedule_.date(n), paymentLag_, Days, paymentAdjustment_);
408 ext::shared_ptr<CPICashFlow> xnl = ext::make_shared<CPICashFlow>(
409 detail::get(notionals_, n, 0.0), index_, baseDate, baseCPI_, observationDate, observationLag_,
410 observationInterpolation_, paymentDate, subtractInflationNominal_);
412 if (finalFlowCap_ == Null<Real>() && finalFlowFloor_ == Null<Real>()) {
415 ext::shared_ptr<CappedFlooredCPICashFlow> cfxnl = ext::make_shared<CappedFlooredCPICashFlow>(
416 xnl, startDate_, observationLag_, finalFlowCap_, finalFlowFloor_);
417 leg.push_back(cfxnl);
virtual Rate rate() const override
bool subtractInflationNominal_
Helper class building a sequence of capped/floored CPI coupons.
CPILeg & withNotionals(Real notional)
BusinessDayConvention paymentAdjustment_
std::vector< Rate > caps_
CPILeg & withPaymentAdjustment(BusinessDayConvention)
BusinessDayConvention exCouponAdjustment_
CPILeg & withFinalFlowCap(Rate cap)
CPILeg & withSubtractInflationNominal(bool)
Calendar paymentCalendar_
CPILeg & withFixingDays(Natural fixingDays)
CPILeg & withObservationLag(const Period &observationLag)
CPILeg & withFixedRates(Real fixedRate)
CPILeg & withFinalFlowFloor(Rate floor)
CPILeg & withExCouponPeriod(const Period &, const Calendar &, BusinessDayConvention, bool endOfMonth=false)
CPILeg(const Schedule &schedule, const ext::shared_ptr< ZeroInflationIndex > &index, const Handle< YieldTermStructure > &rateCurve, const Real baseCPI, const Period &observationLag)
std::vector< Real > notionals_
CPILeg & withCaps(Rate cap)
CPILeg & withPaymentDayCounter(const DayCounter &)
CPILeg & withStartDate(const Date &startDate)
CPILeg & withPaymentCalendar(const Calendar &)
CPILeg & withFloors(Rate floor)
std::vector< Real > fixedRates_
std::vector< Natural > fixingDays_
CPI::InterpolationType observationInterpolation_
bool subtractInflationNominalAllCoupons_
Calendar exCouponCalendar_
CPILeg & withSubtractInflationNominalAllCoupons(bool subtractInflationNominalAllCoupons)
std::vector< Rate > floors_
CPILeg & withPaymentLag(Natural lag)
bool subtractInflationNominal_
CPILeg & withObservationInterpolation(CPI::InterpolationType)
DayCounter paymentDayCounter_
ext::shared_ptr< CPICashFlow > underlying_
ext::shared_ptr< CPICashFlow > underlying() const
void setPricer(const ext::shared_ptr< InflationCashFlowPricer > &pricer)
ext::shared_ptr< CPICapFloor > cpiCap_
void setCommon(Rate cap, Rate floor)
CappedFlooredCPICashFlow(const ext::shared_ptr< CPICashFlow > &underlying, Date startDate=Date(), Period observationLag=0 *Days, Rate cap=Null< Rate >(), Rate floor=Null< Rate >())
ext::shared_ptr< InflationCashFlowPricer > pricer_
virtual Real amount() const override
ext::shared_ptr< CPICapFloor > cpiFloor_
CappedFlooredCPICoupon(const ext::shared_ptr< CPICoupon > &underlying, Date startDate=Date(), Rate cap=Null< Rate >(), Rate floor=Null< Rate >())
ext::shared_ptr< CPICapFloor > cpiCap_
virtual void setCommon(Rate cap, Rate floor)
virtual Rate rate() const override
ext::shared_ptr< CPICoupon > underlying() const
ext::shared_ptr< CPICoupon > underlying_
virtual void accept(AcyclicVisitor &v) override
ext::shared_ptr< CPICapFloor > cpiFloor_
const QuantLib::ext::shared_ptr< FloatingRateCouponPricer > pricer_
CPI cap/floor engine using the Black pricing formula and interpreting the volatility data as lognorma...
CPI leg builder extending QuantLib's to handle caps and floors.
CPI cash flow and coupon pricers that handle caps/floors using a CpiCapFloorEngine.