1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 3 /* 4 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl 5 Copyright (C) 2003, 2004, 2005, 2006, 2007 StatPro Italia srl 6 Copyright (C) 2007 Ferdinando Ametrano 7 8 This file is part of QuantLib, a free-software/open-source library 9 for financial quantitative analysts and developers - http://quantlib.org/ 10 11 QuantLib is free software: you can redistribute it and/or modify it 12 under the terms of the QuantLib license. You should have received a 13 copy of the license along with this program; if not, please email 14 <quantlib-dev@lists.sf.net>. The license is also available online at 15 <http://quantlib.org/license.shtml>. 16 17 This program is distributed in the hope that it will be useful, but WITHOUT 18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 19 FOR A PARTICULAR PURPOSE. See the license for more details. 20 */ 21 22 #include <ql/instruments/vanillaswap.hpp> 23 #include <ql/cashflows/fixedratecoupon.hpp> 24 #include <ql/cashflows/iborcoupon.hpp> 25 #include <ql/cashflows/cashflowvectors.hpp> 26 #include <ql/cashflows/cashflows.hpp> 27 #include <ql/cashflows/couponpricer.hpp> 28 #include <ql/indexes/iborindex.hpp> 29 #include <ql/termstructures/yieldtermstructure.hpp> 30 31 namespace QuantLib { 32 VanillaSwap(Type type,Real nominal,const Schedule & fixedSchedule,Rate fixedRate,const DayCounter & fixedDayCount,const Schedule & floatSchedule,const ext::shared_ptr<IborIndex> & iborIndex,Spread spread,const DayCounter & floatingDayCount,boost::optional<BusinessDayConvention> paymentConvention)33 VanillaSwap::VanillaSwap( 34 Type type, 35 Real nominal, 36 const Schedule& fixedSchedule, 37 Rate fixedRate, 38 const DayCounter& fixedDayCount, 39 const Schedule& floatSchedule, 40 const ext::shared_ptr<IborIndex>& iborIndex, 41 Spread spread, 42 const DayCounter& floatingDayCount, 43 boost::optional<BusinessDayConvention> paymentConvention) 44 : Swap(2), type_(type), nominal_(nominal), 45 fixedSchedule_(fixedSchedule), fixedRate_(fixedRate), 46 fixedDayCount_(fixedDayCount), 47 floatingSchedule_(floatSchedule), iborIndex_(iborIndex), spread_(spread), 48 floatingDayCount_(floatingDayCount) { 49 50 if (paymentConvention) // NOLINT(readability-implicit-bool-conversion) 51 paymentConvention_ = *paymentConvention; 52 else 53 paymentConvention_ = floatingSchedule_.businessDayConvention(); 54 55 legs_[0] = FixedRateLeg(fixedSchedule_) 56 .withNotionals(nominal_) 57 .withCouponRates(fixedRate_, fixedDayCount_) 58 .withPaymentAdjustment(paymentConvention_); 59 60 legs_[1] = IborLeg(floatingSchedule_, iborIndex_) 61 .withNotionals(nominal_) 62 .withPaymentDayCounter(floatingDayCount_) 63 .withPaymentAdjustment(paymentConvention_) 64 .withSpreads(spread_); 65 for (Leg::const_iterator i = legs_[1].begin(); i < legs_[1].end(); ++i) 66 registerWith(*i); 67 68 switch (type_) { 69 case Payer: 70 payer_[0] = -1.0; 71 payer_[1] = +1.0; 72 break; 73 case Receiver: 74 payer_[0] = +1.0; 75 payer_[1] = -1.0; 76 break; 77 default: 78 QL_FAIL("Unknown vanilla-swap type"); 79 } 80 } 81 setupArguments(PricingEngine::arguments * args) const82 void VanillaSwap::setupArguments(PricingEngine::arguments* args) const { 83 84 Swap::setupArguments(args); 85 86 VanillaSwap::arguments* arguments = 87 dynamic_cast<VanillaSwap::arguments*>(args); 88 89 if (arguments == 0) // it's a swap engine... 90 return; 91 92 arguments->type = type_; 93 arguments->nominal = nominal_; 94 95 const Leg& fixedCoupons = fixedLeg(); 96 97 arguments->fixedResetDates = arguments->fixedPayDates = 98 std::vector<Date>(fixedCoupons.size()); 99 arguments->fixedCoupons = std::vector<Real>(fixedCoupons.size()); 100 101 for (Size i=0; i<fixedCoupons.size(); ++i) { 102 ext::shared_ptr<FixedRateCoupon> coupon = 103 ext::dynamic_pointer_cast<FixedRateCoupon>(fixedCoupons[i]); 104 105 arguments->fixedPayDates[i] = coupon->date(); 106 arguments->fixedResetDates[i] = coupon->accrualStartDate(); 107 arguments->fixedCoupons[i] = coupon->amount(); 108 } 109 110 const Leg& floatingCoupons = floatingLeg(); 111 112 arguments->floatingResetDates = arguments->floatingPayDates = 113 arguments->floatingFixingDates = 114 std::vector<Date>(floatingCoupons.size()); 115 arguments->floatingAccrualTimes = 116 std::vector<Time>(floatingCoupons.size()); 117 arguments->floatingSpreads = 118 std::vector<Spread>(floatingCoupons.size()); 119 arguments->floatingCoupons = std::vector<Real>(floatingCoupons.size()); 120 for (Size i=0; i<floatingCoupons.size(); ++i) { 121 ext::shared_ptr<IborCoupon> coupon = 122 ext::dynamic_pointer_cast<IborCoupon>(floatingCoupons[i]); 123 124 arguments->floatingResetDates[i] = coupon->accrualStartDate(); 125 arguments->floatingPayDates[i] = coupon->date(); 126 127 arguments->floatingFixingDates[i] = coupon->fixingDate(); 128 arguments->floatingAccrualTimes[i] = coupon->accrualPeriod(); 129 arguments->floatingSpreads[i] = coupon->spread(); 130 try { 131 arguments->floatingCoupons[i] = coupon->amount(); 132 } catch (Error&) { 133 arguments->floatingCoupons[i] = Null<Real>(); 134 } 135 } 136 } 137 fairRate() const138 Rate VanillaSwap::fairRate() const { 139 calculate(); 140 QL_REQUIRE(fairRate_ != Null<Rate>(), "result not available"); 141 return fairRate_; 142 } 143 fairSpread() const144 Spread VanillaSwap::fairSpread() const { 145 calculate(); 146 QL_REQUIRE(fairSpread_ != Null<Spread>(), "result not available"); 147 return fairSpread_; 148 } 149 fixedLegBPS() const150 Real VanillaSwap::fixedLegBPS() const { 151 calculate(); 152 QL_REQUIRE(legBPS_[0] != Null<Real>(), "result not available"); 153 return legBPS_[0]; 154 } 155 floatingLegBPS() const156 Real VanillaSwap::floatingLegBPS() const { 157 calculate(); 158 QL_REQUIRE(legBPS_[1] != Null<Real>(), "result not available"); 159 return legBPS_[1]; 160 } 161 fixedLegNPV() const162 Real VanillaSwap::fixedLegNPV() const { 163 calculate(); 164 QL_REQUIRE(legNPV_[0] != Null<Real>(), "result not available"); 165 return legNPV_[0]; 166 } 167 floatingLegNPV() const168 Real VanillaSwap::floatingLegNPV() const { 169 calculate(); 170 QL_REQUIRE(legNPV_[1] != Null<Real>(), "result not available"); 171 return legNPV_[1]; 172 } 173 setupExpired() const174 void VanillaSwap::setupExpired() const { 175 Swap::setupExpired(); 176 legBPS_[0] = legBPS_[1] = 0.0; 177 fairRate_ = Null<Rate>(); 178 fairSpread_ = Null<Spread>(); 179 } 180 fetchResults(const PricingEngine::results * r) const181 void VanillaSwap::fetchResults(const PricingEngine::results* r) const { 182 static const Spread basisPoint = 1.0e-4; 183 184 Swap::fetchResults(r); 185 186 const VanillaSwap::results* results = 187 dynamic_cast<const VanillaSwap::results*>(r); 188 if (results != 0) { // might be a swap engine, so no error is thrown 189 fairRate_ = results->fairRate; 190 fairSpread_ = results->fairSpread; 191 } else { 192 fairRate_ = Null<Rate>(); 193 fairSpread_ = Null<Spread>(); 194 } 195 196 if (fairRate_ == Null<Rate>()) { 197 // calculate it from other results 198 if (legBPS_[0] != Null<Real>()) 199 fairRate_ = fixedRate_ - NPV_/(legBPS_[0]/basisPoint); 200 } 201 if (fairSpread_ == Null<Spread>()) { 202 // ditto 203 if (legBPS_[1] != Null<Real>()) 204 fairSpread_ = spread_ - NPV_/(legBPS_[1]/basisPoint); 205 } 206 } 207 validate() const208 void VanillaSwap::arguments::validate() const { 209 Swap::arguments::validate(); 210 QL_REQUIRE(nominal != Null<Real>(), "nominal null or not set"); 211 QL_REQUIRE(fixedResetDates.size() == fixedPayDates.size(), 212 "number of fixed start dates different from " 213 "number of fixed payment dates"); 214 QL_REQUIRE(fixedPayDates.size() == fixedCoupons.size(), 215 "number of fixed payment dates different from " 216 "number of fixed coupon amounts"); 217 QL_REQUIRE(floatingResetDates.size() == floatingPayDates.size(), 218 "number of floating start dates different from " 219 "number of floating payment dates"); 220 QL_REQUIRE(floatingFixingDates.size() == floatingPayDates.size(), 221 "number of floating fixing dates different from " 222 "number of floating payment dates"); 223 QL_REQUIRE(floatingAccrualTimes.size() == floatingPayDates.size(), 224 "number of floating accrual Times different from " 225 "number of floating payment dates"); 226 QL_REQUIRE(floatingSpreads.size() == floatingPayDates.size(), 227 "number of floating spreads different from " 228 "number of floating payment dates"); 229 QL_REQUIRE(floatingPayDates.size() == floatingCoupons.size(), 230 "number of floating payment dates different from " 231 "number of floating coupon amounts"); 232 } 233 reset()234 void VanillaSwap::results::reset() { 235 Swap::results::reset(); 236 fairRate = Null<Rate>(); 237 fairSpread = Null<Spread>(); 238 } 239 operator <<(std::ostream & out,VanillaSwap::Type t)240 std::ostream& operator<<(std::ostream& out, 241 VanillaSwap::Type t) { 242 switch (t) { 243 case VanillaSwap::Payer: 244 return out << "Payer"; 245 case VanillaSwap::Receiver: 246 return out << "Receiver"; 247 default: 248 QL_FAIL("unknown VanillaSwap::Type(" << Integer(t) << ")"); 249 } 250 } 251 252 } 253