1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*
4  Copyright (C) 2007 Giorgio Facchinetti
5  Copyright (C) 2007 Cristina Duminuco
6  Copyright (C) 2010, 2011 Ferdinando Ametrano
7  Copyright (C) 2017 Joseph Jeisman
8  Copyright (C) 2017 Fabrice Lecuyer
9 
10  This file is part of QuantLib, a free-software/open-source library
11  for financial quantitative analysts and developers - http://quantlib.org/
12 
13  QuantLib is free software: you can redistribute it and/or modify it
14  under the terms of the QuantLib license.  You should have received a
15  copy of the license along with this program; if not, please email
16  <quantlib-dev@lists.sf.net>. The license is also available online at
17  <http://quantlib.org/license.shtml>.
18 
19  This program is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21  FOR A PARTICULAR PURPOSE.  See the license for more details.
22 */
23 
24 #include <ql/cashflows/iborcoupon.hpp>
25 #include <ql/cashflows/couponpricer.hpp>
26 #include <ql/cashflows/capflooredcoupon.hpp>
27 #include <ql/cashflows/cashflowvectors.hpp>
28 #include <ql/indexes/interestrateindex.hpp>
29 #include <ql/termstructures/yieldtermstructure.hpp>
30 
31 namespace QuantLib {
32 
33     bool IborCoupon::constructorWasNotCalled_ = true;
34 
35 #ifndef QL_USE_INDEXED_COUPON
36     bool IborCoupon::usingAtParCoupons_ = true;
37 #else
38     bool IborCoupon::usingAtParCoupons_ = false;
39 #endif
40 
createAtParCoupons()41     void IborCoupon::createAtParCoupons() {
42         QL_ASSERT(constructorWasNotCalled_,
43                   "Cannot call this method after the first IborCoupon was created.");
44         usingAtParCoupons_ = true;
45     }
46 
createIndexedCoupons()47     void IborCoupon::createIndexedCoupons() {
48         QL_ASSERT(constructorWasNotCalled_,
49                   "Cannot call this method after the first IborCoupon was created.");
50         usingAtParCoupons_ = false;
51     }
52 
IborCoupon(const Date & paymentDate,Real nominal,const Date & startDate,const Date & endDate,Natural fixingDays,const ext::shared_ptr<IborIndex> & iborIndex,Real gearing,Spread spread,const Date & refPeriodStart,const Date & refPeriodEnd,const DayCounter & dayCounter,bool isInArrears,const Date & exCouponDate)53     IborCoupon::IborCoupon(const Date& paymentDate,
54                            Real nominal,
55                            const Date& startDate,
56                            const Date& endDate,
57                            Natural fixingDays,
58                            const ext::shared_ptr<IborIndex>& iborIndex,
59                            Real gearing,
60                            Spread spread,
61                            const Date& refPeriodStart,
62                            const Date& refPeriodEnd,
63                            const DayCounter& dayCounter,
64                            bool isInArrears,
65                            const Date& exCouponDate)
66     : FloatingRateCoupon(paymentDate, nominal, startDate, endDate,
67                          fixingDays, iborIndex, gearing, spread,
68                          refPeriodStart, refPeriodEnd,
69                          dayCounter, isInArrears, exCouponDate),
70       iborIndex_(iborIndex) {
71         constructorWasNotCalled_ = false;
72 
73         fixingDate_ = fixingDate();
74 
75         const Calendar& fixingCalendar = index_->fixingCalendar();
76         Natural indexFixingDays = index_->fixingDays();
77 
78         fixingValueDate_ = fixingCalendar.advance(
79             fixingDate_, indexFixingDays, Days);
80 
81         if (usingAtParCoupons_) {
82             if (isInArrears_)
83                 fixingEndDate_ = index_->maturityDate(fixingValueDate_);
84             else { // par coupon approximation
85                 Date nextFixingDate = fixingCalendar.advance(
86                     accrualEndDate_, -static_cast<Integer>(fixingDays_), Days);
87                 fixingEndDate_ = fixingCalendar.advance(
88                     nextFixingDate, indexFixingDays, Days);
89                 // make sure the estimation period contains at least one day
90                 fixingEndDate_ = std::max(fixingEndDate_, fixingValueDate_ + 1);
91             }
92         } else {
93             fixingEndDate_ = index_->maturityDate(fixingValueDate_);
94         }
95 
96         const DayCounter& dc = index_->dayCounter();
97         spanningTime_ = dc.yearFraction(fixingValueDate_,
98                                         fixingEndDate_);
99         QL_REQUIRE(spanningTime_>0.0,
100                    "\n cannot calculate forward rate between " <<
101                    fixingValueDate_ << " and " << fixingEndDate_ <<
102                    ":\n non positive time (" << spanningTime_ <<
103                    ") using " << dc.name() << " daycounter");
104     }
105 
indexFixing() const106     Rate IborCoupon::indexFixing() const {
107 
108         /* instead of just returning index_->fixing(fixingValueDate_)
109            its logic is duplicated here using a specialized iborIndex
110            forecastFixing overload which
111            1) allows to save date/time recalculations, and
112            2) takes into account par coupon needs
113         */
114         Date today = Settings::instance().evaluationDate();
115 
116         if (fixingDate_>today)
117             return iborIndex_->forecastFixing(fixingValueDate_,
118                                               fixingEndDate_,
119                                               spanningTime_);
120 
121         if (fixingDate_<today ||
122             Settings::instance().enforcesTodaysHistoricFixings()) {
123             // do not catch exceptions
124             Rate result = index_->pastFixing(fixingDate_);
125             QL_REQUIRE(result != Null<Real>(),
126                        "Missing " << index_->name() << " fixing for " << fixingDate_);
127             return result;
128         }
129 
130         try {
131             Rate result = index_->pastFixing(fixingDate_);
132             if (result!=Null<Real>())
133                 return result;
134             else
135                 ;   // fall through and forecast
136         } catch (Error&) {
137                 ;   // fall through and forecast
138         }
139         return iborIndex_->forecastFixing(fixingValueDate_,
140                                           fixingEndDate_,
141                                           spanningTime_);
142     }
143 
accept(AcyclicVisitor & v)144     void IborCoupon::accept(AcyclicVisitor& v) {
145         Visitor<IborCoupon>* v1 =
146             dynamic_cast<Visitor<IborCoupon>*>(&v);
147         if (v1 != 0)
148             v1->visit(*this);
149         else
150             FloatingRateCoupon::accept(v);
151     }
152 
153 
154 
IborLeg(const Schedule & schedule,const ext::shared_ptr<IborIndex> & index)155     IborLeg::IborLeg(const Schedule& schedule,
156                      const ext::shared_ptr<IborIndex>& index)
157     : schedule_(schedule), index_(index),
158       paymentAdjustment_(Following),
159       paymentLag_(0), paymentCalendar_(Calendar()),
160       inArrears_(false), zeroPayments_(false),
161       exCouponPeriod_(Period()), exCouponCalendar_(Calendar()),
162 	  exCouponAdjustment_(Unadjusted), exCouponEndOfMonth_(false) {}
163 
withNotionals(Real notional)164     IborLeg& IborLeg::withNotionals(Real notional) {
165         notionals_ = std::vector<Real>(1,notional);
166         return *this;
167     }
168 
withNotionals(const std::vector<Real> & notionals)169     IborLeg& IborLeg::withNotionals(const std::vector<Real>& notionals) {
170         notionals_ = notionals;
171         return *this;
172     }
173 
withPaymentDayCounter(const DayCounter & dayCounter)174     IborLeg& IborLeg::withPaymentDayCounter(const DayCounter& dayCounter) {
175         paymentDayCounter_ = dayCounter;
176         return *this;
177     }
178 
withPaymentAdjustment(BusinessDayConvention convention)179     IborLeg& IborLeg::withPaymentAdjustment(BusinessDayConvention convention) {
180         paymentAdjustment_ = convention;
181         return *this;
182     }
183 
withPaymentLag(Natural lag)184     IborLeg& IborLeg::withPaymentLag(Natural lag) {
185         paymentLag_ = lag;
186         return *this;
187     }
188 
withPaymentCalendar(const Calendar & cal)189     IborLeg& IborLeg::withPaymentCalendar(const Calendar& cal) {
190         paymentCalendar_ = cal;
191         return *this;
192     }
193 
withFixingDays(Natural fixingDays)194     IborLeg& IborLeg::withFixingDays(Natural fixingDays) {
195         fixingDays_ = std::vector<Natural>(1,fixingDays);
196         return *this;
197     }
198 
withFixingDays(const std::vector<Natural> & fixingDays)199     IborLeg& IborLeg::withFixingDays(const std::vector<Natural>& fixingDays) {
200         fixingDays_ = fixingDays;
201         return *this;
202     }
203 
withGearings(Real gearing)204     IborLeg& IborLeg::withGearings(Real gearing) {
205         gearings_ = std::vector<Real>(1,gearing);
206         return *this;
207     }
208 
withGearings(const std::vector<Real> & gearings)209     IborLeg& IborLeg::withGearings(const std::vector<Real>& gearings) {
210         gearings_ = gearings;
211         return *this;
212     }
213 
withSpreads(Spread spread)214     IborLeg& IborLeg::withSpreads(Spread spread) {
215         spreads_ = std::vector<Spread>(1,spread);
216         return *this;
217     }
218 
withSpreads(const std::vector<Spread> & spreads)219     IborLeg& IborLeg::withSpreads(const std::vector<Spread>& spreads) {
220         spreads_ = spreads;
221         return *this;
222     }
223 
withCaps(Rate cap)224     IborLeg& IborLeg::withCaps(Rate cap) {
225         caps_ = std::vector<Rate>(1,cap);
226         return *this;
227     }
228 
withCaps(const std::vector<Rate> & caps)229     IborLeg& IborLeg::withCaps(const std::vector<Rate>& caps) {
230         caps_ = caps;
231         return *this;
232     }
233 
withFloors(Rate floor)234     IborLeg& IborLeg::withFloors(Rate floor) {
235         floors_ = std::vector<Rate>(1,floor);
236         return *this;
237     }
238 
withFloors(const std::vector<Rate> & floors)239     IborLeg& IborLeg::withFloors(const std::vector<Rate>& floors) {
240         floors_ = floors;
241         return *this;
242     }
243 
inArrears(bool flag)244     IborLeg& IborLeg::inArrears(bool flag) {
245         inArrears_ = flag;
246         return *this;
247     }
248 
withZeroPayments(bool flag)249     IborLeg& IborLeg::withZeroPayments(bool flag) {
250         zeroPayments_ = flag;
251         return *this;
252     }
253 
withExCouponPeriod(const Period & period,const Calendar & cal,BusinessDayConvention convention,bool endOfMonth)254 	IborLeg& IborLeg::withExCouponPeriod(const Period& period,
255                                          const Calendar& cal,
256                                          BusinessDayConvention convention,
257                                          bool endOfMonth) {
258         exCouponPeriod_ = period;
259         exCouponCalendar_ = cal;
260         exCouponAdjustment_ = convention;
261         exCouponEndOfMonth_ = endOfMonth;
262         return *this;
263 	}
264 
operator Leg() const265     IborLeg::operator Leg() const {
266 
267         Leg leg = FloatingLeg<IborIndex, IborCoupon, CappedFlooredIborCoupon>(
268                          schedule_, notionals_, index_, paymentDayCounter_,
269                          paymentAdjustment_, fixingDays_, gearings_, spreads_,
270                          caps_, floors_, inArrears_, zeroPayments_, paymentLag_, paymentCalendar_,
271 			             exCouponPeriod_, exCouponCalendar_, exCouponAdjustment_, exCouponEndOfMonth_);
272 
273         if (caps_.empty() && floors_.empty() && !inArrears_) {
274             ext::shared_ptr<IborCouponPricer> pricer(new BlackIborCouponPricer);
275             setCouponPricer(leg, pricer);
276         }
277 
278         return leg;
279     }
280 
281 }
282