1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 3 /* 4 Copyright (C) 2007, 2009 Chris Kenyon 5 Copyright (C) 2009 StatPro Italia srl 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/yearonyearinflationswap.hpp> 22 #include <ql/time/schedule.hpp> 23 #include <ql/cashflows/fixedratecoupon.hpp> 24 #include <ql/cashflows/yoyinflationcoupon.hpp> 25 #include <ql/cashflows/cashflowvectors.hpp> 26 #include <ql/cashflows/cashflows.hpp> 27 #include <ql/cashflows/couponpricer.hpp> 28 #include <ql/indexes/inflationindex.hpp> 29 #include <ql/termstructures/yieldtermstructure.hpp> 30 31 namespace QuantLib { 32 33 YearOnYearInflationSwap:: YearOnYearInflationSwap(Type type,Real nominal,const Schedule & fixedSchedule,Rate fixedRate,const DayCounter & fixedDayCount,const Schedule & yoySchedule,const ext::shared_ptr<YoYInflationIndex> & yoyIndex,const Period & observationLag,Spread spread,const DayCounter & yoyDayCount,const Calendar & paymentCalendar,BusinessDayConvention paymentConvention)34 YearOnYearInflationSwap( 35 Type type, 36 Real nominal, 37 const Schedule& fixedSchedule, 38 Rate fixedRate, 39 const DayCounter& fixedDayCount, 40 const Schedule& yoySchedule, 41 const ext::shared_ptr<YoYInflationIndex>& yoyIndex, 42 const Period& observationLag, 43 Spread spread, 44 const DayCounter& yoyDayCount, 45 const Calendar& paymentCalendar, 46 BusinessDayConvention paymentConvention) 47 : Swap(2), type_(type), nominal_(nominal), 48 fixedSchedule_(fixedSchedule), fixedRate_(fixedRate), 49 fixedDayCount_(fixedDayCount), 50 yoySchedule_(yoySchedule), yoyIndex_(yoyIndex), 51 observationLag_(observationLag), 52 spread_(spread), 53 yoyDayCount_(yoyDayCount), paymentCalendar_(paymentCalendar), 54 paymentConvention_(paymentConvention) 55 { 56 // N.B. fixed leg gets its calendar from the schedule! 57 Leg fixedLeg = FixedRateLeg(fixedSchedule_) 58 .withNotionals(nominal_) 59 .withCouponRates(fixedRate_, fixedDayCount_) // Simple compounding by default 60 .withPaymentAdjustment(paymentConvention_); 61 62 Leg yoyLeg = yoyInflationLeg(yoySchedule_, paymentCalendar_, yoyIndex_, observationLag_) 63 .withNotionals(nominal_) 64 .withPaymentDayCounter(yoyDayCount_) 65 .withPaymentAdjustment(paymentConvention_) 66 .withSpreads(spread_); 67 68 Leg::const_iterator i; 69 for (i = yoyLeg.begin(); i < yoyLeg.end(); ++i) 70 registerWith(*i); 71 72 legs_[0] = fixedLeg; 73 legs_[1] = yoyLeg; 74 if (type_==Payer) { 75 payer_[0] = -1.0; 76 payer_[1] = +1.0; 77 } else { 78 payer_[0] = +1.0; 79 payer_[1] = -1.0; 80 } 81 } 82 83 setupArguments(PricingEngine::arguments * args) const84 void YearOnYearInflationSwap::setupArguments(PricingEngine::arguments* args) const { 85 86 Swap::setupArguments(args); 87 88 YearOnYearInflationSwap::arguments* arguments = 89 dynamic_cast<YearOnYearInflationSwap::arguments*>(args); 90 91 if (arguments == 0) // it's a swap engine... 92 return; 93 94 arguments->type = type_; 95 arguments->nominal = nominal_; 96 97 const Leg& fixedCoupons = fixedLeg(); 98 99 arguments->fixedResetDates = arguments->fixedPayDates = 100 std::vector<Date>(fixedCoupons.size()); 101 arguments->fixedCoupons = std::vector<Real>(fixedCoupons.size()); 102 103 for (Size i=0; i<fixedCoupons.size(); ++i) { 104 ext::shared_ptr<FixedRateCoupon> coupon = 105 ext::dynamic_pointer_cast<FixedRateCoupon>(fixedCoupons[i]); 106 107 arguments->fixedPayDates[i] = coupon->date(); 108 arguments->fixedResetDates[i] = coupon->accrualStartDate(); 109 arguments->fixedCoupons[i] = coupon->amount(); 110 } 111 112 const Leg& yoyCoupons = yoyLeg(); 113 114 arguments->yoyResetDates = arguments->yoyPayDates = 115 arguments->yoyFixingDates = 116 std::vector<Date>(yoyCoupons.size()); 117 arguments->yoyAccrualTimes = 118 std::vector<Time>(yoyCoupons.size()); 119 arguments->yoySpreads = 120 std::vector<Spread>(yoyCoupons.size()); 121 arguments->yoyCoupons = std::vector<Real>(yoyCoupons.size()); 122 for (Size i=0; i<yoyCoupons.size(); ++i) { 123 ext::shared_ptr<YoYInflationCoupon> coupon = 124 ext::dynamic_pointer_cast<YoYInflationCoupon>(yoyCoupons[i]); 125 126 arguments->yoyResetDates[i] = coupon->accrualStartDate(); 127 arguments->yoyPayDates[i] = coupon->date(); 128 129 arguments->yoyFixingDates[i] = coupon->fixingDate(); 130 arguments->yoyAccrualTimes[i] = coupon->accrualPeriod(); 131 arguments->yoySpreads[i] = coupon->spread(); 132 try { 133 arguments->yoyCoupons[i] = coupon->amount(); 134 } catch (Error&) { 135 arguments->yoyCoupons[i] = Null<Real>(); 136 } 137 } 138 } 139 140 fairRate() const141 Rate YearOnYearInflationSwap::fairRate() const { 142 calculate(); 143 QL_REQUIRE(fairRate_ != Null<Rate>(), "result not available"); 144 return fairRate_; 145 } 146 fairSpread() const147 Spread YearOnYearInflationSwap::fairSpread() const { 148 calculate(); 149 QL_REQUIRE(fairSpread_ != Null<Spread>(), "result not available"); 150 return fairSpread_; 151 } 152 153 fixedLegNPV() const154 Real YearOnYearInflationSwap::fixedLegNPV() const { 155 calculate(); 156 QL_REQUIRE(legNPV_[0] != Null<Real>(), "result not available"); 157 return legNPV_[0]; 158 } 159 yoyLegNPV() const160 Real YearOnYearInflationSwap::yoyLegNPV() const { 161 calculate(); 162 QL_REQUIRE(legNPV_[1] != Null<Real>(), "result not available"); 163 return legNPV_[1]; 164 } 165 setupExpired() const166 void YearOnYearInflationSwap::setupExpired() const { 167 Swap::setupExpired(); 168 legBPS_[0] = legBPS_[1] = 0.0; 169 fairRate_ = Null<Rate>(); 170 fairSpread_ = Null<Spread>(); 171 } 172 fetchResults(const PricingEngine::results * r) const173 void YearOnYearInflationSwap::fetchResults(const PricingEngine::results* r) const { 174 static const Spread basisPoint = 1.0e-4; 175 176 // copy from VanillaSwap 177 // works because similarly simple instrument 178 // that we always expect to be priced with a swap engine 179 180 Swap::fetchResults(r); 181 182 const YearOnYearInflationSwap::results* results = 183 dynamic_cast<const YearOnYearInflationSwap::results*>(r); 184 if (results != 0) { // might be a swap engine, so no error is thrown 185 fairRate_ = results->fairRate; 186 fairSpread_ = results->fairSpread; 187 } else { 188 fairRate_ = Null<Rate>(); 189 fairSpread_ = Null<Spread>(); 190 } 191 192 if (fairRate_ == Null<Rate>()) { 193 // calculate it from other results 194 if (legBPS_[0] != Null<Real>()) 195 fairRate_ = fixedRate_ - NPV_/(legBPS_[0]/basisPoint); 196 } 197 if (fairSpread_ == Null<Spread>()) { 198 // ditto 199 if (legBPS_[1] != Null<Real>()) 200 fairSpread_ = spread_ - NPV_/(legBPS_[1]/basisPoint); 201 } 202 203 } 204 validate() const205 void YearOnYearInflationSwap::arguments::validate() const { 206 Swap::arguments::validate(); 207 QL_REQUIRE(nominal != Null<Real>(), "nominal null or not set"); 208 QL_REQUIRE(fixedResetDates.size() == fixedPayDates.size(), 209 "number of fixed start dates different from " 210 "number of fixed payment dates"); 211 QL_REQUIRE(fixedPayDates.size() == fixedCoupons.size(), 212 "number of fixed payment dates different from " 213 "number of fixed coupon amounts"); 214 QL_REQUIRE(yoyResetDates.size() == yoyPayDates.size(), 215 "number of yoy start dates different from " 216 "number of yoy payment dates"); 217 QL_REQUIRE(yoyFixingDates.size() == yoyPayDates.size(), 218 "number of yoy fixing dates different from " 219 "number of yoy payment dates"); 220 QL_REQUIRE(yoyAccrualTimes.size() == yoyPayDates.size(), 221 "number of yoy accrual Times different from " 222 "number of yoy payment dates"); 223 QL_REQUIRE(yoySpreads.size() == yoyPayDates.size(), 224 "number of yoy spreads different from " 225 "number of yoy payment dates"); 226 QL_REQUIRE(yoyPayDates.size() == yoyCoupons.size(), 227 "number of yoy payment dates different from " 228 "number of yoy coupon amounts"); 229 } 230 reset()231 void YearOnYearInflationSwap::results::reset() { 232 Swap::results::reset(); 233 fairRate = Null<Rate>(); 234 fairSpread = Null<Spread>(); 235 } 236 operator <<(std::ostream & out,YearOnYearInflationSwap::Type t)237 std::ostream& operator<<(std::ostream& out, 238 YearOnYearInflationSwap::Type t) { 239 switch (t) { 240 case YearOnYearInflationSwap::Payer: 241 return out << "Payer"; 242 case YearOnYearInflationSwap::Receiver: 243 return out << "Receiver"; 244 default: 245 QL_FAIL("unknown VanillaSwap::Type(" << Integer(t) << ")"); 246 } 247 } 248 249 } 250 251