Skip to content

Commit 92ca401

Browse files
pcaspersjenkins
authored andcommitted
Resolve QPR-11670
1 parent 81f0590 commit 92ca401

1 file changed

Lines changed: 142 additions & 32 deletions

File tree

OREData/ored/portfolio/capfloor.cpp

Lines changed: 142 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
#include <ored/utilities/log.hpp>
2929
#include <ored/utilities/to_string.hpp>
3030

31+
#include <qle/cashflows/averageonindexedcoupon.hpp>
32+
#include <qle/cashflows/overnightindexedcoupon.hpp>
33+
#include <qle/cashflows/cappedflooredaveragebmacoupon.hpp>
34+
3135
#include <ql/experimental/coupons/strippedcapflooredcoupon.hpp>
3236
#include <ql/instruments/capfloor.hpp>
3337
#include <ql/instruments/compositeinstrument.hpp>
@@ -541,42 +545,148 @@ const std::map<std::string, boost::any>& CapFloor::additionalData() const {
541545
boost::shared_ptr<FloatingRateCoupon> frc = boost::dynamic_pointer_cast<FloatingRateCoupon>(flow);
542546
if (frc) {
543547
fixingDates.push_back(frc->fixingDate());
544-
indexFixings.push_back(frc->indexFixing());
548+
549+
// indexFixing for overnight indices
550+
if (auto on = boost::dynamic_pointer_cast<QuantExt::AverageONIndexedCoupon>(frc)) {
551+
indexFixings.push_back((on->rate() - on->spread()) / on->gearing());
552+
} else if (auto on = boost::dynamic_pointer_cast<QuantExt::OvernightIndexedCoupon>(frc)) {
553+
indexFixings.push_back((on->rate() - on->effectiveSpread()) / on->gearing());
554+
} else if (auto c = boost::dynamic_pointer_cast<QuantExt::CappedFlooredOvernightIndexedCoupon>(
555+
frc)) {
556+
indexFixings.push_back((c->underlying()->rate() - c->underlying()->effectiveSpread()) /
557+
c->underlying()->gearing());
558+
} else if (auto c = boost::dynamic_pointer_cast<QuantExt::CappedFlooredAverageONIndexedCoupon>(frc)) {
559+
indexFixings.push_back((c->underlying()->rate() - c->underlying()->spread()) /
560+
c->underlying()->gearing());
561+
}
562+
// indexFixing for BMA and subPeriod Coupons
563+
else if (auto c = boost::dynamic_pointer_cast<QuantLib::AverageBMACoupon>(frc)) {
564+
indexFixings.push_back((c->rate() - c->spread()) / c->gearing());
565+
} else if (auto c = boost::dynamic_pointer_cast<QuantExt::CappedFlooredAverageBMACoupon>(frc)) {
566+
indexFixings.push_back((c->underlying()->rate() - c->underlying()->spread()) / c->underlying()->gearing());
567+
} else if (auto sp = boost::dynamic_pointer_cast<QuantExt::SubPeriodsCoupon1>(frc))
568+
indexFixings.push_back((sp->rate() - sp->spread()) / sp->gearing());
569+
else {
570+
// this sets indexFixing to the last single overnight fixing
571+
indexFixings.push_back(frc->indexFixing());
572+
}
573+
545574
spreads.push_back(frc->spread());
546575

547576
// The below code adds cap/floor levels, vols, and amounts
548-
// for capped/floored Ibor coupons
549-
550-
boost::shared_ptr<StrippedCappedFlooredCoupon> strippedCfc =
551-
boost::dynamic_pointer_cast<StrippedCappedFlooredCoupon>(flow);
552-
if (!strippedCfc)
553-
continue;
554-
555-
boost::shared_ptr<CappedFlooredCoupon> cfc = strippedCfc->underlying();
556-
// enfore coupon pricer to hold the results of the current coupon
557-
cfc->deepUpdate();
558-
cfc->amount();
559-
boost::shared_ptr<IborCouponPricer> pricer =
560-
boost::dynamic_pointer_cast<IborCouponPricer>(cfc->pricer());
561-
if (pricer && (cfc->fixingDate() > asof)) {
562-
// We write the vols if an Ibor coupon pricer is found and the fixing date is in the future
563-
if (cfc->isCapped()) {
564-
caps.push_back(cfc->cap());
565-
const Rate effectiveCap = cfc->effectiveCap();
566-
effectiveCaps.push_back(effectiveCap);
567-
capletVols.push_back(
568-
pricer->capletVolatility()->volatility(cfc->fixingDate(), effectiveCap));
569-
capletAmounts.push_back(pricer->capletRate(effectiveCap) * coupon->accrualPeriod() *
570-
coupon->nominal());
577+
// for capped/floored Ibor coupons and overnight coupons
578+
boost::shared_ptr<CashFlow> c = flow;
579+
if (auto strippedCfc = boost::dynamic_pointer_cast<StrippedCappedFlooredCoupon>(flow)) {
580+
c = strippedCfc->underlying();
581+
}
582+
583+
if (auto cfc = boost::dynamic_pointer_cast<CappedFlooredCoupon>(c)) {
584+
// enfore coupon pricer to hold the results of the current coupon
585+
cfc->deepUpdate();
586+
cfc->amount();
587+
boost::shared_ptr<IborCouponPricer> pricer =
588+
boost::dynamic_pointer_cast<IborCouponPricer>(cfc->pricer());
589+
if (pricer && (cfc->fixingDate() > asof)) {
590+
// We write the vols if an Ibor coupon pricer is found and the fixing date is in the
591+
// future
592+
if (cfc->isCapped()) {
593+
caps.push_back(cfc->cap());
594+
const Rate effectiveCap = cfc->effectiveCap();
595+
effectiveCaps.push_back(effectiveCap);
596+
capletVols.push_back(
597+
pricer->capletVolatility()->volatility(cfc->fixingDate(), effectiveCap));
598+
capletAmounts.push_back(pricer->capletRate(effectiveCap) * coupon->accrualPeriod() *
599+
coupon->nominal());
600+
}
601+
if (cfc->isFloored()) {
602+
floors.push_back(cfc->floor());
603+
const Rate effectiveFloor = cfc->effectiveFloor();
604+
effectiveFloors.push_back(effectiveFloor);
605+
floorletVols.push_back(
606+
pricer->capletVolatility()->volatility(cfc->fixingDate(), effectiveFloor));
607+
floorletAmounts.push_back(pricer->floorletRate(effectiveFloor) *
608+
coupon->accrualPeriod() * coupon->nominal());
609+
}
610+
}
611+
} else if (auto tmp = boost::dynamic_pointer_cast<QuantExt::CappedFlooredOvernightIndexedCoupon>(c)) {
612+
tmp->deepUpdate();
613+
tmp->amount();
614+
boost::shared_ptr<QuantExt::CappedFlooredOvernightIndexedCouponPricer> pricer =
615+
boost::dynamic_pointer_cast<QuantExt::CappedFlooredOvernightIndexedCouponPricer>(
616+
tmp->pricer());
617+
if (pricer && (tmp->fixingDate() > asof)) {
618+
if (tmp->isCapped()) {
619+
caps.push_back(tmp->cap());
620+
const Rate effectiveCap = tmp->effectiveCap();
621+
effectiveCaps.push_back(effectiveCap);
622+
capletVols.push_back(
623+
pricer->capletVolatility()->volatility(tmp->fixingDate(), effectiveCap));
624+
capletAmounts.push_back(pricer->capletRate(effectiveCap) * coupon->accrualPeriod() *
625+
coupon->nominal());
626+
}
627+
if (tmp->isFloored()) {
628+
floors.push_back(tmp->floor());
629+
const Rate effectiveFloor = tmp->effectiveFloor();
630+
effectiveFloors.push_back(effectiveFloor);
631+
floorletVols.push_back(
632+
pricer->capletVolatility()->volatility(tmp->fixingDate(), effectiveFloor));
633+
floorletAmounts.push_back(pricer->floorletRate(effectiveFloor) *
634+
coupon->accrualPeriod() * coupon->nominal());
635+
}
571636
}
572-
if (cfc->isFloored()) {
573-
floors.push_back(cfc->floor());
574-
const Rate effectiveFloor = cfc->effectiveFloor();
575-
effectiveFloors.push_back(effectiveFloor);
576-
floorletVols.push_back(
577-
pricer->capletVolatility()->volatility(cfc->fixingDate(), effectiveFloor));
578-
floorletAmounts.push_back(pricer->floorletRate(effectiveFloor) * coupon->accrualPeriod() *
579-
coupon->nominal());
637+
} else if (auto tmp =
638+
boost::dynamic_pointer_cast<QuantExt::CappedFlooredAverageONIndexedCoupon>(c)) {
639+
tmp->deepUpdate();
640+
tmp->amount();
641+
boost::shared_ptr<QuantExt::CapFlooredAverageONIndexedCouponPricer> pricer =
642+
boost::dynamic_pointer_cast<QuantExt::CapFlooredAverageONIndexedCouponPricer>(
643+
tmp->pricer());
644+
if (pricer && (tmp->fixingDate() > asof)) {
645+
if (tmp->isCapped()) {
646+
caps.push_back(tmp->cap());
647+
const Rate effectiveCap = tmp->effectiveCap();
648+
effectiveCaps.push_back(effectiveCap);
649+
capletVols.push_back(
650+
pricer->capletVolatility()->volatility(tmp->fixingDate(), effectiveCap));
651+
capletAmounts.push_back(pricer->capletRate(effectiveCap) * coupon->accrualPeriod() *
652+
coupon->nominal());
653+
}
654+
if (tmp->isFloored()) {
655+
floors.push_back(tmp->floor());
656+
const Rate effectiveFloor = tmp->effectiveFloor();
657+
effectiveFloors.push_back(effectiveFloor);
658+
floorletVols.push_back(
659+
pricer->capletVolatility()->volatility(tmp->fixingDate(), effectiveFloor));
660+
floorletAmounts.push_back(pricer->floorletRate(effectiveFloor) *
661+
coupon->accrualPeriod() * coupon->nominal());
662+
}
663+
}
664+
665+
} else if (auto tmp = boost::dynamic_pointer_cast<QuantExt::CappedFlooredAverageBMACoupon>(c)) {
666+
tmp->deepUpdate();
667+
tmp->amount();
668+
boost::shared_ptr<QuantExt::CapFlooredAverageBMACouponPricer> pricer =
669+
boost::dynamic_pointer_cast<QuantExt::CapFlooredAverageBMACouponPricer>(
670+
tmp->pricer());
671+
if (pricer && (tmp->fixingDate() > asof)) {
672+
if (tmp->isCapped()) {
673+
caps.push_back(tmp->cap());
674+
const Rate effectiveCap = tmp->effectiveCap();
675+
effectiveCaps.push_back(effectiveCap);
676+
capletVols.push_back(
677+
pricer->capletVolatility()->volatility(tmp->fixingDate(), effectiveCap));
678+
capletAmounts.push_back(pricer->capletRate(effectiveCap) * coupon->accrualPeriod() *
679+
coupon->nominal());
680+
}
681+
if (tmp->isFloored()) {
682+
floors.push_back(tmp->floor());
683+
const Rate effectiveFloor = tmp->effectiveFloor();
684+
effectiveFloors.push_back(effectiveFloor);
685+
floorletVols.push_back(
686+
pricer->capletVolatility()->volatility(tmp->fixingDate(), effectiveFloor));
687+
floorletAmounts.push_back(pricer->floorletRate(effectiveFloor) *
688+
coupon->accrualPeriod() * coupon->nominal());
689+
}
580690
}
581691
}
582692
}

0 commit comments

Comments
 (0)