| 1 | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
| 2 | |
| 3 | /* |
| 4 | Copyright (C) 2009, 2012 Roland Lichters |
| 5 | Copyright (C) 2009, 2012 Ferdinando Ametrano |
| 6 | |
| 7 | This file is part of QuantLib, a free-software/open-source library |
| 8 | for financial quantitative analysts and developers - http://quantlib.org/ |
| 9 | |
| 10 | QuantLib is free software: you can redistribute it and/or modify it |
| 11 | under the terms of the QuantLib license. You should have received a |
| 12 | copy of the license along with this program; if not, please email |
| 13 | <quantlib-dev@lists.sf.net>. The license is also available online at |
| 14 | <http://quantlib.org/license.shtml>. |
| 15 | |
| 16 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 17 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 18 | FOR A PARTICULAR PURPOSE. See the license for more details. |
| 19 | */ |
| 20 | |
| 21 | #include <ql/instruments/makeois.hpp> |
| 22 | #include <ql/instruments/simplifynotificationgraph.hpp> |
| 23 | #include <ql/pricingengines/swap/discountingswapengine.hpp> |
| 24 | #include <ql/termstructures/yield/oisratehelper.hpp> |
| 25 | #include <ql/utilities/null_deleter.hpp> |
| 26 | #include <utility> |
| 27 | |
| 28 | namespace QuantLib { |
| 29 | |
| 30 | OISRateHelper::OISRateHelper(Natural settlementDays, |
| 31 | const Period& tenor, // swap maturity |
| 32 | const Handle<Quote>& fixedRate, |
| 33 | const ext::shared_ptr<OvernightIndex>& overnightIndex, |
| 34 | Handle<YieldTermStructure> discount, |
| 35 | bool telescopicValueDates, |
| 36 | Natural paymentLag, |
| 37 | BusinessDayConvention paymentConvention, |
| 38 | Frequency paymentFrequency, |
| 39 | Calendar paymentCalendar, |
| 40 | const Period& forwardStart, |
| 41 | const Spread overnightSpread, |
| 42 | Pillar::Choice pillar, |
| 43 | Date customPillarDate, |
| 44 | RateAveraging::Type averagingMethod, |
| 45 | ext::optional<bool> endOfMonth) |
| 46 | : RelativeDateRateHelper(fixedRate), pillarChoice_(pillar), settlementDays_(settlementDays), tenor_(tenor), |
| 47 | discountHandle_(std::move(discount)), telescopicValueDates_(telescopicValueDates), |
| 48 | paymentLag_(paymentLag), paymentConvention_(paymentConvention), |
| 49 | paymentFrequency_(paymentFrequency), paymentCalendar_(std::move(paymentCalendar)), |
| 50 | forwardStart_(forwardStart), overnightSpread_(overnightSpread), |
| 51 | averagingMethod_(averagingMethod), endOfMonth_(endOfMonth) { |
| 52 | |
| 53 | overnightIndex_ = |
| 54 | ext::dynamic_pointer_cast<OvernightIndex>(r: overnightIndex->clone(h: termStructureHandle_)); |
| 55 | // We want to be notified of changes of fixings, but we don't |
| 56 | // want notifications from termStructureHandle_ (they would |
| 57 | // interfere with bootstrapping.) |
| 58 | overnightIndex_->unregisterWith(h: termStructureHandle_); |
| 59 | |
| 60 | registerWith(h: overnightIndex_); |
| 61 | registerWith(h: discountHandle_); |
| 62 | |
| 63 | pillarDate_ = customPillarDate; |
| 64 | OISRateHelper::initializeDates(); |
| 65 | } |
| 66 | |
| 67 | void OISRateHelper::initializeDates() { |
| 68 | |
| 69 | // input discount curve Handle might be empty now but it could |
| 70 | // be assigned a curve later; use a RelinkableHandle here |
| 71 | MakeOIS tmp = MakeOIS(tenor_, overnightIndex_, 0.0, forwardStart_) |
| 72 | .withDiscountingTermStructure(discountingTermStructure: discountRelinkableHandle_) |
| 73 | .withSettlementDays(settlementDays: settlementDays_) |
| 74 | .withTelescopicValueDates(telescopicValueDates: telescopicValueDates_) |
| 75 | .withPaymentLag(lag: paymentLag_) |
| 76 | .withPaymentAdjustment(convention: paymentConvention_) |
| 77 | .withPaymentFrequency(f: paymentFrequency_) |
| 78 | .withPaymentCalendar(cal: paymentCalendar_) |
| 79 | .withOvernightLegSpread(sp: overnightSpread_) |
| 80 | .withAveragingMethod(averagingMethod: averagingMethod_); |
| 81 | if (endOfMonth_) { |
| 82 | swap_ = tmp.withEndOfMonth(flag: *endOfMonth_); |
| 83 | } else { |
| 84 | swap_ = tmp; |
| 85 | } |
| 86 | |
| 87 | simplifyNotificationGraph(swap&: *swap_, unregisterCoupons: true); |
| 88 | |
| 89 | earliestDate_ = swap_->startDate(); |
| 90 | maturityDate_ = swap_->maturityDate(); |
| 91 | |
| 92 | Date lastPaymentDate = std::max(a: swap_->overnightLeg().back()->date(), |
| 93 | b: swap_->fixedLeg().back()->date()); |
| 94 | latestRelevantDate_ = std::max(a: maturityDate_, b: lastPaymentDate); |
| 95 | |
| 96 | switch (pillarChoice_) { |
| 97 | case Pillar::MaturityDate: |
| 98 | pillarDate_ = maturityDate_; |
| 99 | break; |
| 100 | case Pillar::LastRelevantDate: |
| 101 | pillarDate_ = latestRelevantDate_; |
| 102 | break; |
| 103 | case Pillar::CustomDate: |
| 104 | // pillarDate_ already assigned at construction time |
| 105 | QL_REQUIRE(pillarDate_ >= earliestDate_, |
| 106 | "pillar date (" << pillarDate_ << ") must be later " |
| 107 | "than or equal to the instrument's earliest date (" << |
| 108 | earliestDate_ << ")" ); |
| 109 | QL_REQUIRE(pillarDate_ <= latestRelevantDate_, |
| 110 | "pillar date (" << pillarDate_ << ") must be before " |
| 111 | "or equal to the instrument's latest relevant date (" << |
| 112 | latestRelevantDate_ << ")" ); |
| 113 | break; |
| 114 | default: |
| 115 | QL_FAIL("unknown Pillar::Choice(" << Integer(pillarChoice_) << ")" ); |
| 116 | } |
| 117 | |
| 118 | latestDate_ = std::max(a: swap_->maturityDate(), b: lastPaymentDate); |
| 119 | } |
| 120 | |
| 121 | void OISRateHelper::setTermStructure(YieldTermStructure* t) { |
| 122 | // do not set the relinkable handle as an observer - |
| 123 | // force recalculation when needed |
| 124 | bool observer = false; |
| 125 | |
| 126 | ext::shared_ptr<YieldTermStructure> temp(t, null_deleter()); |
| 127 | termStructureHandle_.linkTo(h: temp, registerAsObserver: observer); |
| 128 | |
| 129 | if (discountHandle_.empty()) |
| 130 | discountRelinkableHandle_.linkTo(h: temp, registerAsObserver: observer); |
| 131 | else |
| 132 | discountRelinkableHandle_.linkTo(h: *discountHandle_, registerAsObserver: observer); |
| 133 | |
| 134 | RelativeDateRateHelper::setTermStructure(t); |
| 135 | } |
| 136 | |
| 137 | Real OISRateHelper::impliedQuote() const { |
| 138 | QL_REQUIRE(termStructure_ != nullptr, "term structure not set" ); |
| 139 | // we didn't register as observers - force calculation |
| 140 | swap_->deepUpdate(); |
| 141 | return swap_->fairRate(); |
| 142 | } |
| 143 | |
| 144 | void OISRateHelper::accept(AcyclicVisitor& v) { |
| 145 | auto* v1 = dynamic_cast<Visitor<OISRateHelper>*>(&v); |
| 146 | if (v1 != nullptr) |
| 147 | v1->visit(*this); |
| 148 | else |
| 149 | RateHelper::accept(v); |
| 150 | } |
| 151 | |
| 152 | DatedOISRateHelper::DatedOISRateHelper(const Date& startDate, |
| 153 | const Date& endDate, |
| 154 | const Handle<Quote>& fixedRate, |
| 155 | const ext::shared_ptr<OvernightIndex>& overnightIndex, |
| 156 | Handle<YieldTermStructure> discount, |
| 157 | bool telescopicValueDates, |
| 158 | RateAveraging::Type averagingMethod, |
| 159 | Natural paymentLag, |
| 160 | BusinessDayConvention paymentConvention, |
| 161 | Frequency paymentFrequency, |
| 162 | const Calendar& paymentCalendar, |
| 163 | const Period& forwardStart, |
| 164 | Spread overnightSpread, |
| 165 | ext::optional<bool> endOfMonth) |
| 166 | : RateHelper(fixedRate), discountHandle_(std::move(discount)), |
| 167 | telescopicValueDates_(telescopicValueDates), averagingMethod_(averagingMethod) { |
| 168 | |
| 169 | auto clonedOvernightIndex = |
| 170 | ext::dynamic_pointer_cast<OvernightIndex>(r: overnightIndex->clone(h: termStructureHandle_)); |
| 171 | // We want to be notified of changes of fixings, but we don't |
| 172 | // want notifications from termStructureHandle_ (they would |
| 173 | // interfere with bootstrapping.) |
| 174 | clonedOvernightIndex->unregisterWith(h: termStructureHandle_); |
| 175 | |
| 176 | registerWith(h: clonedOvernightIndex); |
| 177 | registerWith(h: discountHandle_); |
| 178 | |
| 179 | // input discount curve Handle might be empty now but it could |
| 180 | // be assigned a curve later; use a RelinkableHandle here |
| 181 | auto tmp = MakeOIS(Period(), clonedOvernightIndex, 0.0, forwardStart) |
| 182 | .withDiscountingTermStructure(discountingTermStructure: discountRelinkableHandle_) |
| 183 | .withEffectiveDate(startDate) |
| 184 | .withTerminationDate(endDate) |
| 185 | .withTelescopicValueDates(telescopicValueDates: telescopicValueDates_) |
| 186 | .withPaymentLag(lag: paymentLag) |
| 187 | .withPaymentAdjustment(convention: paymentConvention) |
| 188 | .withPaymentFrequency(f: paymentFrequency) |
| 189 | .withPaymentCalendar(cal: paymentCalendar) |
| 190 | .withOvernightLegSpread(sp: overnightSpread) |
| 191 | .withAveragingMethod(averagingMethod: averagingMethod_); |
| 192 | if (endOfMonth) { |
| 193 | swap_ = tmp.withEndOfMonth(flag: *endOfMonth); |
| 194 | } else { |
| 195 | swap_ = tmp; |
| 196 | } |
| 197 | |
| 198 | earliestDate_ = swap_->startDate(); |
| 199 | Date lastPaymentDate = std::max(a: swap_->overnightLeg().back()->date(), |
| 200 | b: swap_->fixedLeg().back()->date()); |
| 201 | latestDate_ = std::max(a: swap_->maturityDate(), b: lastPaymentDate); |
| 202 | } |
| 203 | |
| 204 | void DatedOISRateHelper::setTermStructure(YieldTermStructure* t) { |
| 205 | // do not set the relinkable handle as an observer - |
| 206 | // force recalculation when needed |
| 207 | bool observer = false; |
| 208 | |
| 209 | ext::shared_ptr<YieldTermStructure> temp(t, null_deleter()); |
| 210 | termStructureHandle_.linkTo(h: temp, registerAsObserver: observer); |
| 211 | |
| 212 | if (discountHandle_.empty()) |
| 213 | discountRelinkableHandle_.linkTo(h: temp, registerAsObserver: observer); |
| 214 | else |
| 215 | discountRelinkableHandle_.linkTo(h: *discountHandle_, registerAsObserver: observer); |
| 216 | |
| 217 | RateHelper::setTermStructure(t); |
| 218 | } |
| 219 | |
| 220 | Real DatedOISRateHelper::impliedQuote() const { |
| 221 | QL_REQUIRE(termStructure_ != nullptr, "term structure not set" ); |
| 222 | // we didn't register as observers - force calculation |
| 223 | swap_->deepUpdate(); |
| 224 | return swap_->fairRate(); |
| 225 | } |
| 226 | |
| 227 | void DatedOISRateHelper::accept(AcyclicVisitor& v) { |
| 228 | auto* v1 = dynamic_cast<Visitor<DatedOISRateHelper>*>(&v); |
| 229 | if (v1 != nullptr) |
| 230 | v1->visit(*this); |
| 231 | else |
| 232 | RateHelper::accept(v); |
| 233 | } |
| 234 | |
| 235 | } |
| 236 | |