diff --git a/ql/instruments/makeois.cpp b/ql/instruments/makeois.cpp index 4e896ac3b92..eef85a1a1e7 100644 --- a/ql/instruments/makeois.cpp +++ b/ql/instruments/makeois.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include namespace QuantLib { @@ -33,9 +34,8 @@ namespace QuantLib { const Period& forwardStart) : swapTenor_(swapTenor), overnightIndex_(overnightIndex), fixedRate_(fixedRate), forwardStart_(forwardStart), - - calendar_(overnightIndex->fixingCalendar()), - + fixedCalendar_(overnightIndex->fixingCalendar()), + overnightCalendar_(overnightIndex->fixingCalendar()), fixedDayCount_(overnightIndex->dayCounter()) {} MakeOIS::operator OvernightIndexedSwap() const { @@ -52,45 +52,74 @@ namespace QuantLib { Date refDate = Settings::instance().evaluationDate(); // if the evaluation date is not a business day // then move to the next business day - refDate = calendar_.adjust(refDate); - Date spotDate = calendar_.advance(refDate, - settlementDays_*Days); + refDate = overnightCalendar_.adjust(refDate); + Date spotDate = overnightCalendar_.advance(refDate, + settlementDays_*Days); startDate = spotDate+forwardStart_; if (forwardStart_.length()<0) - startDate = calendar_.adjust(startDate, Preceding); + startDate = overnightCalendar_.adjust(startDate, Preceding); else - startDate = calendar_.adjust(startDate, Following); + startDate = overnightCalendar_.adjust(startDate, Following); } // OIS end of month default bool usedEndOfMonth = - isDefaultEOM_ ? calendar_.isEndOfMonth(startDate) : endOfMonth_; + isDefaultEOM_ ? overnightCalendar_.isEndOfMonth(startDate) : endOfMonth_; Date endDate = terminationDate_; if (endDate == Date()) { if (usedEndOfMonth) - endDate = calendar_.advance(startDate, - swapTenor_, - ModifiedFollowing, - usedEndOfMonth); + endDate = overnightCalendar_.advance(startDate, + swapTenor_, + ModifiedFollowing, + usedEndOfMonth); else endDate = startDate + swapTenor_; } - Schedule schedule(startDate, endDate, - Period(paymentFrequency_), - calendar_, - ModifiedFollowing, - ModifiedFollowing, - rule_, - usedEndOfMonth); + Frequency fixedPaymentFrequency, overnightPaymentFrequency; + DateGeneration::Rule fixedRule, overnightRule; + if (fixedPaymentFrequency_ == Once || fixedRule_ == DateGeneration::Zero) { + fixedPaymentFrequency = Once; + fixedRule = DateGeneration::Zero; + } else { + fixedPaymentFrequency = fixedPaymentFrequency_; + fixedRule = fixedRule_; + } + if (overnightPaymentFrequency_ == Once || overnightRule_ == DateGeneration::Zero) { + overnightPaymentFrequency = Once; + overnightRule = DateGeneration::Zero; + } else { + overnightPaymentFrequency = overnightPaymentFrequency_; + overnightRule = overnightRule_; + } + + Schedule fixedSchedule(startDate, endDate, + Period(fixedPaymentFrequency), + fixedCalendar_, + ModifiedFollowing, + ModifiedFollowing, + fixedRule, + usedEndOfMonth); + ext::optional overnightSchedule; + if (fixedPaymentFrequency != overnightPaymentFrequency || fixedRule != overnightRule || + fixedCalendar_ != overnightCalendar_) { + overnightSchedule.emplace(startDate, endDate, + Period(overnightPaymentFrequency), + overnightCalendar_, + ModifiedFollowing, + ModifiedFollowing, + overnightRule, + usedEndOfMonth); + } Rate usedFixedRate = fixedRate_; if (fixedRate_ == Null()) { OvernightIndexedSwap temp(type_, nominal_, - schedule, + fixedSchedule, 0.0, // fixed rate fixedDayCount_, + overnightSchedule ? *overnightSchedule : fixedSchedule, overnightIndex_, overnightSpread_, paymentLag_, paymentAdjustment_, paymentCalendar_, telescopicValueDates_); @@ -112,8 +141,9 @@ namespace QuantLib { ext::shared_ptr ois(new OvernightIndexedSwap(type_, nominal_, - schedule, + fixedSchedule, usedFixedRate, fixedDayCount_, + overnightSchedule ? *overnightSchedule : fixedSchedule, overnightIndex_, overnightSpread_, paymentLag_, paymentAdjustment_, paymentCalendar_, telescopicValueDates_, @@ -165,9 +195,16 @@ namespace QuantLib { } MakeOIS& MakeOIS::withPaymentFrequency(Frequency f) { - paymentFrequency_ = f; - if (paymentFrequency_==Once) - rule_ = DateGeneration::Zero; + return withFixedLegPaymentFrequency(f).withOvernightLegPaymentFrequency(f); + } + + MakeOIS& MakeOIS::withFixedLegPaymentFrequency(Frequency f) { + fixedPaymentFrequency_ = f; + return *this; + } + + MakeOIS& MakeOIS::withOvernightLegPaymentFrequency(Frequency f) { + overnightPaymentFrequency_ = f; return *this; } @@ -186,10 +223,27 @@ namespace QuantLib { return *this; } + MakeOIS& MakeOIS::withFixedLegCalendar(const Calendar& cal) { + fixedCalendar_ = cal; + return *this; + } + + MakeOIS& MakeOIS::withOvernightLegCalendar(const Calendar& cal) { + overnightCalendar_ = cal; + return *this; + } + MakeOIS& MakeOIS::withRule(DateGeneration::Rule r) { - rule_ = r; - if (r==DateGeneration::Zero) - paymentFrequency_ = Once; + return withFixedLegRule(r).withOvernightLegRule(r); + } + + MakeOIS& MakeOIS::withFixedLegRule(DateGeneration::Rule r) { + fixedRule_ = r; + return *this; + } + + MakeOIS& MakeOIS::withOvernightLegRule(DateGeneration::Rule r) { + overnightRule_ = r; return *this; } diff --git a/ql/instruments/makeois.hpp b/ql/instruments/makeois.hpp index 117d598d483..6c39b9a69e7 100644 --- a/ql/instruments/makeois.hpp +++ b/ql/instruments/makeois.hpp @@ -54,11 +54,17 @@ namespace QuantLib { MakeOIS& withEffectiveDate(const Date&); MakeOIS& withTerminationDate(const Date&); MakeOIS& withRule(DateGeneration::Rule r); + MakeOIS& withFixedLegRule(DateGeneration::Rule r); + MakeOIS& withOvernightLegRule(DateGeneration::Rule r); MakeOIS& withPaymentFrequency(Frequency f); + MakeOIS& withFixedLegPaymentFrequency(Frequency f); + MakeOIS& withOvernightLegPaymentFrequency(Frequency f); MakeOIS& withPaymentAdjustment(BusinessDayConvention convention); MakeOIS& withPaymentLag(Integer lag); MakeOIS& withPaymentCalendar(const Calendar& cal); + MakeOIS& withFixedLegCalendar(const Calendar& cal); + MakeOIS& withOvernightLegCalendar(const Calendar& cal); MakeOIS& withEndOfMonth(bool flag = true); @@ -83,14 +89,16 @@ namespace QuantLib { Natural settlementDays_ = 2; Date effectiveDate_, terminationDate_; - Calendar calendar_; + Calendar fixedCalendar_, overnightCalendar_; - Frequency paymentFrequency_ = Annual; + Frequency fixedPaymentFrequency_ = Annual; + Frequency overnightPaymentFrequency_ = Annual; Calendar paymentCalendar_; BusinessDayConvention paymentAdjustment_ = Following; Integer paymentLag_ = 0; - DateGeneration::Rule rule_ = DateGeneration::Backward; + DateGeneration::Rule fixedRule_ = DateGeneration::Backward; + DateGeneration::Rule overnightRule_ = DateGeneration::Backward; bool endOfMonth_ = false, isDefaultEOM_ = true; Swap::Type type_ = Swap::Payer; diff --git a/ql/termstructures/yield/oisratehelper.cpp b/ql/termstructures/yield/oisratehelper.cpp index ab9707ae212..a20843d4dd8 100644 --- a/ql/termstructures/yield/oisratehelper.cpp +++ b/ql/termstructures/yield/oisratehelper.cpp @@ -42,13 +42,16 @@ namespace QuantLib { Pillar::Choice pillar, Date customPillarDate, RateAveraging::Type averagingMethod, - ext::optional endOfMonth) + ext::optional endOfMonth, + ext::optional fixedPaymentFrequency, + Calendar fixedCalendar) : RelativeDateRateHelper(fixedRate), pillarChoice_(pillar), settlementDays_(settlementDays), tenor_(tenor), discountHandle_(std::move(discount)), telescopicValueDates_(telescopicValueDates), paymentLag_(paymentLag), paymentConvention_(paymentConvention), paymentFrequency_(paymentFrequency), paymentCalendar_(std::move(paymentCalendar)), forwardStart_(forwardStart), overnightSpread_(overnightSpread), - averagingMethod_(averagingMethod), endOfMonth_(endOfMonth) { + averagingMethod_(averagingMethod), endOfMonth_(endOfMonth), + fixedPaymentFrequency_(fixedPaymentFrequency), fixedCalendar_(std::move(fixedCalendar)) { overnightIndex_ = ext::dynamic_pointer_cast(overnightIndex->clone(termStructureHandle_)); @@ -79,10 +82,15 @@ namespace QuantLib { .withOvernightLegSpread(overnightSpread_) .withAveragingMethod(averagingMethod_); if (endOfMonth_) { - swap_ = tmp.withEndOfMonth(*endOfMonth_); - } else { - swap_ = tmp; + tmp.withEndOfMonth(*endOfMonth_); } + if (fixedPaymentFrequency_) { + tmp.withFixedLegPaymentFrequency(*fixedPaymentFrequency_); + } + if (!fixedCalendar_.empty()) { + tmp.withFixedLegCalendar(fixedCalendar_); + } + swap_ = tmp; simplifyNotificationGraph(*swap_, true); @@ -162,7 +170,9 @@ namespace QuantLib { const Calendar& paymentCalendar, const Period& forwardStart, Spread overnightSpread, - ext::optional endOfMonth) + ext::optional endOfMonth, + ext::optional fixedPaymentFrequency, + const Calendar& fixedCalendar) : RateHelper(fixedRate), discountHandle_(std::move(discount)), telescopicValueDates_(telescopicValueDates), averagingMethod_(averagingMethod) { @@ -190,10 +200,15 @@ namespace QuantLib { .withOvernightLegSpread(overnightSpread) .withAveragingMethod(averagingMethod_); if (endOfMonth) { - swap_ = tmp.withEndOfMonth(*endOfMonth); - } else { - swap_ = tmp; + tmp.withEndOfMonth(*endOfMonth); + } + if (fixedPaymentFrequency) { + tmp.withFixedLegPaymentFrequency(*fixedPaymentFrequency); + } + if (!fixedCalendar.empty()) { + tmp.withFixedLegCalendar(fixedCalendar); } + swap_ = tmp; earliestDate_ = swap_->startDate(); Date lastPaymentDate = std::max(swap_->overnightLeg().back()->date(), diff --git a/ql/termstructures/yield/oisratehelper.hpp b/ql/termstructures/yield/oisratehelper.hpp index f65ada8bd5b..4390421f931 100644 --- a/ql/termstructures/yield/oisratehelper.hpp +++ b/ql/termstructures/yield/oisratehelper.hpp @@ -50,7 +50,9 @@ namespace QuantLib { Pillar::Choice pillar = Pillar::LastRelevantDate, Date customPillarDate = Date(), RateAveraging::Type averagingMethod = RateAveraging::Compound, - ext::optional endOfMonth = ext::nullopt); + ext::optional endOfMonth = ext::nullopt, + ext::optional fixedPaymentFrequency = ext::nullopt, + Calendar fixedCalendar = Calendar()); //! \name RateHelper interface //@{ Real impliedQuote() const override; @@ -88,6 +90,8 @@ namespace QuantLib { Spread overnightSpread_; RateAveraging::Type averagingMethod_; ext::optional endOfMonth_; + ext::optional fixedPaymentFrequency_; + Calendar fixedCalendar_; }; //! Rate helper for bootstrapping over Overnight Indexed Swap rates @@ -107,7 +111,9 @@ namespace QuantLib { const Calendar& paymentCalendar = Calendar(), const Period& forwardStart = 0 * Days, Spread overnightSpread = 0.0, - ext::optional endOfMonth = ext::nullopt); + ext::optional endOfMonth = ext::nullopt, + ext::optional fixedPaymentFrequency = ext::nullopt, + const Calendar& fixedCalendar = Calendar()); //! \name RateHelper interface //@{ Real impliedQuote() const override;