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