42#include <ql/cashflows/cashflowvectors.hpp>
43#include <ql/cashflows/couponpricer.hpp>
44#include <ql/termstructures/yieldtermstructure.hpp>
45#include <ql/time/calendars/weekendsonly.hpp>
46#include <ql/utilities/vectors.hpp>
56 const ext::shared_ptr<OvernightIndex>& overnightIndex, Real gearing,
57 Spread spread,
const Date& refPeriodStart,
const Date& refPeriodEnd,
58 const DayCounter& dayCounter,
bool telescopicValueDates,
59 bool includeSpread,
const Period& lookback,
const Natural rateCutoff,
60 const Natural fixingDays,
const Date& rateComputationStartDate,
61 const Date& rateComputationEndDate)
62 :
FloatingRateCoupon(paymentDate, nominal, startDate, endDate, fixingDays, overnightIndex, gearing, spread,
63 refPeriodStart, refPeriodEnd, dayCounter, false),
64 overnightIndex_(overnightIndex), includeSpread_(includeSpread), lookback_(lookback), rateCutoff_(rateCutoff),
65 rateComputationStartDate_(rateComputationStartDate), rateComputationEndDate_(rateComputationEndDate) {
70 BusinessDayConvention bdc =
lookback.length() > 0 ? Preceding : Following;
76 Date tmpEndDate = valueEnd;
86 if (telescopicValueDates) {
89 Date evalDate = Settings::instance().evaluationDate();
90 tmpEndDate =
overnightIndex->fixingCalendar().advance(std::max(valueStart, evalDate), 7, Days, Following);
91 tmpEndDate = std::min(tmpEndDate, valueEnd);
93 Schedule sch = MakeSchedule()
103 if (telescopicValueDates) {
108 while (tmp1 <= tmp2) {
111 tmp1 =
overnightIndex->fixingCalendar().advance(tmp1, 1, Days, Following);
126 "internal error: first two value dates of on coupon are equal: " <<
valueDates_[0]);
128 "internal error: last two value dates of on coupon are equal: " <<
valueDates_[
n_]);
132 for (Size i = 0; i <
n_; ++i)
134 valueDates_[i], -
static_cast<Integer
>(FloatingRateCoupon::fixingDays()), Days, Preceding);
139 for (Size i = 0; i <
n_; ++i)
146 "rate cutoff (" <<
rateCutoff_ <<
") must be less than number of fixings in period (" <<
n_ <<
")");
155 Rate cutoffFixing =
fixings_[i - 1];
164 Visitor<OvernightIndexedCoupon>* v1 =
dynamic_cast<Visitor<OvernightIndexedCoupon>*
>(&v);
168 FloatingRateCoupon::accept(v);
175 auto p = ext::dynamic_pointer_cast<OvernightIndexedCouponPricer>(pricer());
176 QL_REQUIRE(p,
"OvernightIndexedCoupon::effectiveSpread(): expected OvernightIndexedCouponPricer");
177 p->initialize(*
this);
178 return p->effectiveSpread();
182 auto p = ext::dynamic_pointer_cast<OvernightIndexedCouponPricer>(pricer());
183 QL_REQUIRE(p,
"OvernightIndexedCoupon::effectiveSpread(): expected OvernightIndexedCouponPricer");
184 p->initialize(*
this);
185 return p->effectiveIndexFixing();
192 QL_ENSURE(
coupon_,
"wrong coupon type");
196 ext::shared_ptr<OvernightIndex> index = ext::dynamic_pointer_cast<OvernightIndex>(
coupon_->index());
204 <<
") must be less than number of fixings in period (" << n
208 Real compoundFactor = 1.0, compoundFactorWithoutSpread = 1.0;
211 Date today = Settings::instance().evaluationDate();
212 while (i < n && fixingDates[std::min(i, nCutoff)] < today) {
214 Rate pastFixing = index->pastFixing(fixingDates[std::min(i, nCutoff)]);
215 QL_REQUIRE(pastFixing != Null<Real>(),
216 "Missing " << index->name() <<
" fixing for " << fixingDates[std::min(i, nCutoff)]);
218 compoundFactorWithoutSpread *= (1.0 + pastFixing * dt[i]);
219 pastFixing +=
coupon_->spread();
221 compoundFactor *= (1.0 + pastFixing * dt[i]);
226 if (i < n && fixingDates[std::min(i, nCutoff)] == today) {
229 Rate pastFixing = index->pastFixing(fixingDates[std::min(i, nCutoff)]);
230 if (pastFixing != Null<Real>()) {
232 compoundFactorWithoutSpread *= (1.0 + pastFixing * dt[i]);
233 pastFixing +=
coupon_->spread();
235 compoundFactor *= (1.0 + pastFixing * dt[i]);
249 Handle<YieldTermStructure> curve = index->forwardingTermStructure();
250 QL_REQUIRE(!curve.empty(),
"null term structure set to this instance of " << index->name());
253 DiscountFactor startDiscount = curve->discount(dates[i]);
254 DiscountFactor endDiscount = curve->discount(dates[std::max(nCutoff, i)]);
259 DiscountFactor discountCutoffDate = curve->discount(dates[nCutoff] + 1) / curve->discount(dates[nCutoff]);
261 endDiscount *= std::pow(discountCutoffDate, dates[n] - dates[nCutoff]);
264 compoundFactor *= startDiscount / endDiscount;
267 compoundFactorWithoutSpread *= startDiscount / endDiscount;
270 Real tau = index->dayCounter().yearFraction(dates[i], dates.back()) / (dates.back() - dates[i]);
272 compoundFactor *= std::pow(1.0 + tau *
coupon_->spread(),
static_cast<int>(dates.back() - dates[i]));
276 Rate tau = index->dayCounter().yearFraction(dates.front(), dates.back());
277 Rate rate = (compoundFactor - 1.0) / tau;
307 const ext::shared_ptr<OvernightIndexedCoupon>& underlying, Real cap, Real floor,
bool nakedOption,
309 :
FloatingRateCoupon(underlying->date(), underlying->nominal(), underlying->accrualStartDate(),
310 underlying->accrualEndDate(), underlying->fixingDays(), underlying->index(),
311 underlying->gearing(), underlying->spread(), underlying->referencePeriodStart(),
312 underlying->referencePeriodEnd(), underlying->dayCounter(), false),
313 underlying_(underlying), nakedOption_(nakedOption), localCapFloor_(localCapFloor) {
316 "CappedFlooredOvernightIndexedCoupon: if include spread = true, only a gearing 1.0 is allowed - scale "
317 "the notional in this case instead.");
320 if (gearing_ > 0.0) {
331 if (
cap_ != Null<Real>() &&
floor_ != Null<Real>()) {
332 QL_REQUIRE(
cap_ >=
floor,
"cap level (" <<
cap_ <<
") less than floor level (" <<
floor_ <<
")");
340 LazyObject::alwaysForwardNotifications();
350 QL_REQUIRE(
underlying_->pricer(),
"pricer not set");
352 if (
floor_ != Null<Real>() ||
cap_ != Null<Real>())
353 pricer()->initialize(*
this);
354 Rate floorletRate = 0.;
355 if (
floor_ != Null<Real>())
357 Rate capletRate = 0.;
358 if (
cap_ != Null<Real>())
360 rate_ = swapletRate + floorletRate - capletRate;
361 auto p = QuantLib::ext::dynamic_pointer_cast<CappedFlooredOvernightIndexedCouponPricer>(pricer());
362 QL_REQUIRE(p,
"CappedFlooredOvernightIndexedCoupon::performCalculations(): internal error, could not cast to "
363 "CappedFlooredOvernightIndexedCouponPricer");
380 if (
cap_ == Null<Real>())
412 if (
floor_ == Null<Real>())
440 Visitor<CappedFlooredOvernightIndexedCoupon>* v1 =
dynamic_cast<Visitor<CappedFlooredOvernightIndexedCoupon>*
>(&v);
444 FloatingRateCoupon::accept(v);
450 const Handle<OptionletVolatilityStructure>& v,
const bool effectiveVolatilityInput)
451 : capletVol_(v), effectiveVolatilityInput_(effectiveVolatilityInput) {
470 : schedule_(schedule), overnightIndex_(i), paymentCalendar_(schedule.calendar()), paymentAdjustment_(Following),
471 paymentLag_(0), telescopicValueDates_(false), includeSpread_(false), lookback_(0 * Days), rateCutoff_(0),
472 fixingDays_(Null<Size>()), nakedOption_(false), localCapFloor_(false), inArrears_(true) {}
515 spreads_ = vector<Spread>(1, spread);
550 caps_ = std::vector<Rate>(1, cap);
560 floors_ = std::vector<Rate>(1, floor);
606 const QuantLib::ext::shared_ptr<CappedFlooredOvernightIndexedCouponPricer>& couponPricer) {
611OvernightLeg::operator Leg()
const {
613 QL_REQUIRE(!notionals_.empty(),
"no notional given for compounding overnight leg");
617 Calendar calendar = schedule_.calendar();
618 Calendar paymentCalendar = paymentCalendar_;
620 if (calendar.empty())
621 calendar = paymentCalendar;
622 if (calendar.empty())
623 calendar = WeekendsOnly();
624 if (paymentCalendar.empty())
625 paymentCalendar = calendar;
627 Date refStart, start, refEnd, end;
630 Size n = schedule_.size() - 1;
633 if (!paymentDates_.empty()) {
634 QL_REQUIRE(paymentDates_.size() == n,
"Expected the number of explicit payment dates ("
635 << paymentDates_.size()
636 <<
") to equal the number of calculation periods ("
640 for (Size i = 0; i < n; ++i) {
641 refStart = start = schedule_.date(i);
642 refEnd = end = schedule_.date(i + 1);
645 if (!paymentDates_.empty()) {
646 paymentDate = paymentDates_[i];
648 paymentDate = paymentCalendar.advance(end, paymentLag_, Days, paymentAdjustment_);
653 if (i == 0 && schedule_.hasIsRegular() && !schedule_.isRegular(i + 1))
654 refStart = calendar.adjust(end - schedule_.tenor(), paymentAdjustment_);
655 if (i == n - 1 && schedule_.hasIsRegular() && !schedule_.isRegular(i + 1))
656 refEnd = calendar.adjust(start + schedule_.tenor(), paymentAdjustment_);
663 Date rateComputationStartDate, rateComputationEndDate;
666 rateComputationStartDate = start;
667 rateComputationEndDate = end;
672 rateComputationStartDate = schedule_.date(i - 1);
673 rateComputationEndDate = schedule_.date(i);
676 rateComputationEndDate = start;
677 if (schedule_.hasTenor() && schedule_.tenor() != 0 * Days)
678 rateComputationStartDate = calendar.adjust(start - schedule_.tenor(), Preceding);
680 rateComputationStartDate = calendar.adjust(start - (end - start), Preceding);
684 if (lastRecentPeriod_) {
685 rateComputationStartDate = (lastRecentPeriodCalendar_.empty() ? calendar : lastRecentPeriodCalendar_)
686 .advance(rateComputationEndDate, -*lastRecentPeriod_);
691 if (
close_enough(detail::get(gearings_, i, 1.0), 0.0)) {
693 cashflows.push_back(QuantLib::ext::make_shared<FixedRateCoupon>(
694 paymentDate, detail::get(notionals_, i, 1.0), detail::effectiveFixedRate(spreads_, caps_, floors_, i),
695 paymentDayCounter_, start, end, refStart, refEnd));
698 auto cpn = ext::make_shared<OvernightIndexedCoupon>(
699 paymentDate, detail::get(notionals_, i, 1.0), start, end, overnightIndex_,
700 detail::get(gearings_, i, 1.0), detail::get(spreads_, i, 0.0), refStart, refEnd, paymentDayCounter_,
701 telescopicValueDates_, includeSpread_, lookback_, rateCutoff_, fixingDays_, rateComputationStartDate,
702 rateComputationEndDate);
704 cpn->setPricer(couponPricer_);
706 Real cap = detail::get(caps_, i, Null<Real>());
707 Real floor = detail::get(floors_, i, Null<Real>());
708 if (cap == Null<Real>() && floor == Null<Real>()) {
709 cashflows.push_back(cpn);
711 auto cfCpn = ext::make_shared<CappedFlooredOvernightIndexedCoupon>(cpn, cap, floor, nakedOption_,
713 if (capFlooredCouponPricer_) {
714 cfCpn->setPricer(capFlooredCouponPricer_);
716 cashflows.push_back(cfCpn);
CappedFlooredOvernightIndexedCoupon(const ext::shared_ptr< OvernightIndexedCoupon > &underlying, Real cap=Null< Real >(), Real floor=Null< Real >(), bool nakedOption=false, bool localCapFloor=false)
void performCalculations() const override
Real effectiveCapletVolatility() const
effective caplet volatility
Real effectiveCapletVolatility_
void deepUpdate() override
Rate rate() const override
virtual void accept(AcyclicVisitor &) override
Real effectiveFloorletVolatility() const
effective floorlet volatility
bool localCapFloor() const
Rate effectiveCap() const
effective cap of fixing
Real effectiveFloorletVolatility_
ext::shared_ptr< OvernightIndexedCoupon > underlying_
Rate effectiveFloor() const
effective floor of fixing
Rate convexityAdjustment() const override
void alwaysForwardNotifications() override
bool effectiveVolatilityInput() const
Real effectiveCapletVolatility() const
Real effectiveCapletVolatility_
Handle< OptionletVolatilityStructure > capletVolatility() const
Handle< OptionletVolatilityStructure > capletVol_
Real effectiveFloorletVolatility() const
Real effectiveFloorletVolatility_
bool effectiveVolatilityInput_
CappedFlooredOvernightIndexedCouponPricer(const Handle< OptionletVolatilityStructure > &v, const bool effectiveVolatilityInput=false)
Natural rateCutoff() const
rate cutoff
OvernightIndexedCoupon(const Date &paymentDate, Real nominal, const Date &startDate, const Date &endDate, const ext::shared_ptr< OvernightIndex > &overnightIndex, Real gearing=1.0, Spread spread=0.0, const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date(), const DayCounter &dayCounter=DayCounter(), bool telescopicValueDates=false, bool includeSpread=false, const Period &lookback=0 *Days, const Natural rateCutoff=0, const Natural fixingDays=Null< Size >(), const Date &rateComputationStartDate=Null< Date >(), const Date &rateComputationEndDate=Null< Date >())
Date rateComputationStartDate_
bool includeSpread() const
include spread in compounding?
std::vector< Date > fixingDates_
const ext::shared_ptr< OvernightIndex > & overnightIndex() const
the underlying index
const std::vector< Date > & valueDates() const
value dates for the rates to be compounded
Real effectiveIndexFixing() const
const std::vector< Rate > & indexFixings() const
fixings to be compounded
void accept(AcyclicVisitor &) override
std::vector< Rate > fixings_
Real effectiveSpread() const
const Period & lookback() const
lookback period
std::vector< Date > valueDates_
const std::vector< Time > & dt() const
accrual (compounding) periods
Date rateComputationEndDate_
const std::vector< Date > & fixingDates() const
fixing dates for the rates to be compounded
OvernightIndexedCoupon pricer.
void initialize(const FloatingRateCoupon &coupon) override
Real effectiveIndexFixing_
const OvernightIndexedCoupon * coupon_
Rate effectiveSpread() const
Rate effectiveIndexFixing() const
Rate swapletRate() const override
helper class building a sequence of overnight coupons
OvernightLeg & withLookback(const Period &lookback)
BusinessDayConvention paymentAdjustment_
std::vector< Rate > caps_
bool telescopicValueDates_
OvernightLeg(const Schedule &schedule, const ext::shared_ptr< OvernightIndex > &overnightIndex)
OvernightLeg & withGearings(Real gearing)
QuantLib::ext::shared_ptr< CappedFlooredOvernightIndexedCouponPricer > capFlooredCouponPricer_
OvernightLeg & withOvernightIndexedCouponPricer(const QuantLib::ext::shared_ptr< OvernightIndexedCouponPricer > &couponPricer)
OvernightLeg & withCapFlooredOvernightIndexedCouponPricer(const QuantLib::ext::shared_ptr< CappedFlooredOvernightIndexedCouponPricer > &couponPricer)
OvernightLeg & withPaymentCalendar(const Calendar &)
OvernightLeg & withLastRecentPeriod(const boost::optional< Period > &lastRecentPeriod)
Calendar paymentCalendar_
OvernightLeg & withFloors(Rate floor)
OvernightLeg & withTelescopicValueDates(bool telescopicValueDates)
OvernightLeg & withPaymentAdjustment(BusinessDayConvention)
boost::optional< Period > lastRecentPeriod_
std::vector< QuantLib::Date > paymentDates_
Calendar lastRecentPeriodCalendar_
std::vector< Real > notionals_
OvernightLeg & withNakedOption(const bool nakedOption)
std::vector< Spread > spreads_
OvernightLeg & withFixingDays(const Natural fixingDays)
OvernightLeg & withNotionals(Real notional)
OvernightLeg & withRateCutoff(const Natural rateCutoff)
OvernightLeg & withCaps(Rate cap)
OvernightLeg & withPaymentDayCounter(const DayCounter &)
OvernightLeg & withInArrears(const bool inArrears)
OvernightLeg & withSpreads(Spread spread)
OvernightLeg & withPaymentDates(const std::vector< Date > &paymentDates)
OvernightLeg & withLocalCapFloor(const bool localCapFloor)
std::vector< Rate > floors_
OvernightLeg & includeSpread(bool includeSpread)
OvernightLeg & withPaymentLag(Natural lag)
QuantLib::ext::shared_ptr< OvernightIndexedCouponPricer > couponPricer_
OvernightLeg & withLastRecentPeriodCalendar(const Calendar &lastRecentPeriodCalendar)
std::vector< Real > gearings_
DayCounter paymentDayCounter_
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
coupon paying the compounded daily overnight rate, copy of QL class, added includeSpread flag