1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 3 /* 4 Copyright (C) 2007, 2009, 2011 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/time/schedule.hpp> 22 #include <ql/cashflows/fixedratecoupon.hpp> 23 #include <ql/cashflows/cashflowvectors.hpp> 24 #include <ql/cashflows/cashflows.hpp> 25 #include <ql/cashflows/simplecashflow.hpp> 26 #include <ql/cashflows/iborcoupon.hpp> 27 #include <ql/cashflows/couponpricer.hpp> 28 #include <ql/indexes/inflationindex.hpp> 29 #include <ql/termstructures/yieldtermstructure.hpp> 30 31 #include <ql/instruments/cpiswap.hpp> 32 #include <ql/cashflows/cpicoupon.hpp> 33 34 namespace QuantLib { 35 36 // accrual adjustment is already in the schedules, as are calendars 37 CPISwap:: CPISwap(Type type,Real nominal,bool subtractInflationNominal,Spread spread,const DayCounter & floatDayCount,const Schedule & floatSchedule,const BusinessDayConvention & floatPaymentRoll,Natural fixingDays,const ext::shared_ptr<IborIndex> & floatIndex,Rate fixedRate,Real baseCPI,const DayCounter & fixedDayCount,const Schedule & fixedSchedule,const BusinessDayConvention & fixedPaymentRoll,const Period & observationLag,const ext::shared_ptr<ZeroInflationIndex> & fixedIndex,CPI::InterpolationType observationInterpolation,Real inflationNominal)38 CPISwap(Type type, 39 Real nominal, 40 bool subtractInflationNominal, 41 // float + spread leg 42 Spread spread, 43 const DayCounter& floatDayCount, 44 const Schedule& floatSchedule, 45 const BusinessDayConvention& floatPaymentRoll, 46 Natural fixingDays, 47 const ext::shared_ptr<IborIndex>& floatIndex, 48 // fixed x inflation leg 49 Rate fixedRate, 50 Real baseCPI, 51 const DayCounter& fixedDayCount, 52 const Schedule& fixedSchedule, 53 const BusinessDayConvention& fixedPaymentRoll, 54 const Period& observationLag, 55 const ext::shared_ptr<ZeroInflationIndex>& fixedIndex, 56 CPI::InterpolationType observationInterpolation, 57 Real inflationNominal 58 ) 59 : Swap(2), type_(type), nominal_(nominal), subtractInflationNominal_(subtractInflationNominal), 60 spread_(spread), floatDayCount_(floatDayCount), floatSchedule_(floatSchedule), 61 floatPaymentRoll_(floatPaymentRoll), fixingDays_(fixingDays), 62 floatIndex_(floatIndex), 63 fixedRate_(fixedRate), baseCPI_(baseCPI), fixedDayCount_(fixedDayCount), fixedSchedule_(fixedSchedule), 64 fixedPaymentRoll_(fixedPaymentRoll), fixedIndex_(fixedIndex), 65 observationLag_(observationLag), 66 observationInterpolation_(observationInterpolation) 67 { 68 QL_REQUIRE(!floatSchedule_.empty(), "empty float schedule"); 69 QL_REQUIRE(!fixedSchedule_.empty(), "empty fixed schedule"); 70 // \todo if roll!=unadjusted then need calendars ... 71 72 if (inflationNominal==Null<Real>()) inflationNominal_ = nominal_; 73 else inflationNominal_ = inflationNominal; 74 75 Leg floatingLeg; 76 if (floatSchedule_.size() > 1) { 77 floatingLeg = IborLeg(floatSchedule_, floatIndex_) 78 .withNotionals(nominal_) 79 .withSpreads(spread_) 80 .withPaymentDayCounter(floatDayCount_) 81 .withPaymentAdjustment(floatPaymentRoll_) 82 .withFixingDays(fixingDays_); 83 } 84 85 if (floatSchedule_.size()==1 || 86 !subtractInflationNominal_ || 87 (subtractInflationNominal && std::fabs(nominal_-inflationNominal_)>0.00001) 88 ) 89 { 90 Date payNotional; 91 if (floatSchedule_.size()==1) { // no coupons 92 payNotional = floatSchedule_[0]; 93 payNotional = floatSchedule_.calendar().adjust(payNotional, floatPaymentRoll_); 94 } else { // use the pay date of the last coupon 95 payNotional = floatingLeg.back()->date(); 96 } 97 98 Real floatAmount = subtractInflationNominal_ ? nominal_ - inflationNominal_ : nominal_; 99 ext::shared_ptr<CashFlow> nf(new SimpleCashFlow(floatAmount, payNotional)); 100 floatingLeg.push_back(nf); 101 } 102 103 // a CPIleg know about zero legs and inclusion of base inflation notional 104 Leg cpiLeg = CPILeg(fixedSchedule_, fixedIndex_, 105 baseCPI_, observationLag_) 106 .withNotionals(inflationNominal_) 107 .withFixedRates(fixedRate_) 108 .withPaymentDayCounter(fixedDayCount_) 109 .withPaymentAdjustment(fixedPaymentRoll_) 110 .withObservationInterpolation(observationInterpolation_) 111 .withSubtractInflationNominal(subtractInflationNominal_); 112 113 114 Leg::const_iterator i; 115 for (i = cpiLeg.begin(); i < cpiLeg.end(); ++i) { 116 registerWith(*i); 117 } 118 119 for (i = floatingLeg.begin(); i < floatingLeg.end(); ++i) { 120 registerWith(*i); 121 } 122 123 legs_[0] = cpiLeg; 124 legs_[1] = floatingLeg; 125 126 if (type_==Payer) { 127 payer_[0] = 1.0; 128 payer_[1] = -1.0; 129 } else { 130 payer_[0] = -1.0; 131 payer_[1] = 1.0; 132 } 133 134 } 135 136 137 138 //! for simple case sufficient to copy base class setupArguments(PricingEngine::arguments * args) const139 void CPISwap::setupArguments(PricingEngine::arguments* args) const { 140 141 Swap::setupArguments(args); 142 143 CPISwap::arguments* arguments = 144 dynamic_cast<CPISwap::arguments*>(args); 145 146 if (arguments == 0) 147 return; // it's a swap engine... 148 } 149 150 fairRate() const151 Rate CPISwap::fairRate() const { 152 calculate(); 153 QL_REQUIRE(fairRate_ != Null<Rate>(), "result not available"); 154 return fairRate_; 155 } 156 fairSpread() const157 Spread CPISwap::fairSpread() const { 158 calculate(); 159 QL_REQUIRE(fairSpread_ != Null<Spread>(), "result not available"); 160 return fairSpread_; 161 } 162 163 fixedLegNPV() const164 Real CPISwap::fixedLegNPV() const {//FIXME 165 calculate(); 166 QL_REQUIRE(legNPV_[0] != Null<Real>(), "result not available"); 167 return legNPV_[0]; 168 } 169 floatLegNPV() const170 Real CPISwap::floatLegNPV() const {//FIXME 171 calculate(); 172 QL_REQUIRE(legNPV_[1] != Null<Real>(), "result not available"); 173 return legNPV_[1]; 174 } 175 setupExpired() const176 void CPISwap::setupExpired() const { 177 Swap::setupExpired(); 178 legBPS_[0] = legBPS_[1] = 0.0; 179 fairRate_ = Null<Rate>(); 180 fairSpread_ = Null<Spread>(); 181 } 182 fetchResults(const PricingEngine::results * r) const183 void CPISwap::fetchResults(const PricingEngine::results* r) const { 184 static const Spread basisPoint = 1.0e-4; 185 186 // copy from VanillaSwap 187 // works because similarly simple instrument 188 // that we always expect to be priced with a swap engine 189 190 Swap::fetchResults(r); 191 192 const CPISwap::results* results = dynamic_cast<const CPISwap::results*>(r); 193 if (results != 0) { // might be a swap engine, so no error is thrown 194 fairRate_ = results->fairRate; 195 fairSpread_ = results->fairSpread; 196 } else { 197 fairRate_ = Null<Rate>(); 198 fairSpread_ = Null<Spread>(); 199 } 200 201 if (fairRate_ == Null<Rate>()) { 202 // calculate it from other results 203 if (legBPS_[0] != Null<Real>()) 204 fairRate_ = fixedRate_ - NPV_/(legBPS_[0]/basisPoint); 205 } 206 if (fairSpread_ == Null<Spread>()) { 207 // ditto 208 if (legBPS_[1] != Null<Real>()) 209 fairSpread_ = spread_ - NPV_/(legBPS_[1]/basisPoint); 210 } 211 212 } 213 validate() const214 void CPISwap::arguments::validate() const { 215 Swap::arguments::validate(); 216 } 217 reset()218 void CPISwap::results::reset() { 219 Swap::results::reset(); 220 fairRate = Null<Rate>(); 221 fairSpread = Null<Spread>(); 222 } 223 operator <<(std::ostream & out,CPISwap::Type t)224 std::ostream& operator<<(std::ostream& out, 225 CPISwap::Type t) { 226 switch (t) { 227 case CPISwap::Payer: 228 return out << "Payer"; 229 case CPISwap::Receiver: 230 return out << "Receiver"; 231 default: 232 QL_FAIL("unknown CPISwap::Type(" << Integer(t) << ")"); 233 } 234 } 235 236 } 237 238