1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2006, 2007, 2014 Ferdinando Ametrano
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20#include <ql/instruments/makecms.hpp>
21#include <ql/instruments/swap.hpp>
22#include <ql/pricingengines/swap/discountingswapengine.hpp>
23#include <ql/cashflows/iborcoupon.hpp>
24#include <ql/cashflows/cashflows.hpp>
25#include <ql/cashflows/couponpricer.hpp>
26#include <ql/indexes/swapindex.hpp>
27#include <ql/indexes/iborindex.hpp>
28#include <ql/time/schedule.hpp>
29#include <ql/time/daycounters/actual360.hpp>
30
31namespace QuantLib {
32
33 MakeCms::MakeCms(const Period& swapTenor,
34 const ext::shared_ptr<SwapIndex>& swapIndex,
35 const ext::shared_ptr<IborIndex>& iborIndex,
36 Spread iborSpread,
37 const Period& forwardStart)
38 : swapTenor_(swapTenor), swapIndex_(swapIndex), iborIndex_(iborIndex), iborSpread_(iborSpread),
39 useAtmSpread_(false), forwardStart_(forwardStart),
40
41 cmsSpread_(0.0), cmsGearing_(1.0), cmsCap_(Null<Real>()), cmsFloor_(Null<Real>()),
42
43
44 cmsCalendar_(swapIndex->fixingCalendar()), floatCalendar_(iborIndex->fixingCalendar()),
45 payCms_(true), nominal_(1.0), cmsTenor_(3 * Months), floatTenor_(iborIndex->tenor()),
46 cmsConvention_(ModifiedFollowing), cmsTerminationDateConvention_(ModifiedFollowing),
47 floatConvention_(iborIndex->businessDayConvention()),
48 floatTerminationDateConvention_(iborIndex->businessDayConvention()),
49 cmsRule_(DateGeneration::Backward), floatRule_(DateGeneration::Backward),
50 cmsEndOfMonth_(false), floatEndOfMonth_(false),
51
52 cmsDayCount_(Actual360()), floatDayCount_(iborIndex->dayCounter()),
53 // arbitrary choice:
54 // engine_(new DiscountingSwapEngine(iborIndex->termStructure())),
55 engine_(new DiscountingSwapEngine(swapIndex->forwardingTermStructure())) {}
56
57
58 MakeCms::MakeCms(const Period& swapTenor,
59 const ext::shared_ptr<SwapIndex>& swapIndex,
60 Spread iborSpread,
61 const Period& forwardStart)
62 : swapTenor_(swapTenor), swapIndex_(swapIndex), iborIndex_(swapIndex->iborIndex()),
63 iborSpread_(iborSpread), useAtmSpread_(false), forwardStart_(forwardStart),
64
65 cmsSpread_(0.0), cmsGearing_(1.0), cmsCap_(Null<Real>()), cmsFloor_(Null<Real>()),
66
67
68 cmsCalendar_(swapIndex->fixingCalendar()), floatCalendar_(iborIndex_->fixingCalendar()),
69 payCms_(true), nominal_(1.0), cmsTenor_(3 * Months), floatTenor_(iborIndex_->tenor()),
70 cmsConvention_(ModifiedFollowing), cmsTerminationDateConvention_(ModifiedFollowing),
71 floatConvention_(iborIndex_->businessDayConvention()),
72 floatTerminationDateConvention_(iborIndex_->businessDayConvention()),
73 cmsRule_(DateGeneration::Backward), floatRule_(DateGeneration::Backward),
74 cmsEndOfMonth_(false), floatEndOfMonth_(false),
75
76 cmsDayCount_(Actual360()), floatDayCount_(iborIndex_->dayCounter()),
77 engine_(new DiscountingSwapEngine(swapIndex->forwardingTermStructure())) {}
78
79
80 MakeCms::operator Swap() const {
81 ext::shared_ptr<Swap> swap = *this;
82 return *swap;
83 }
84
85 MakeCms::operator ext::shared_ptr<Swap>() const {
86
87 Date startDate;
88 if (effectiveDate_ != Date())
89 startDate = effectiveDate_;
90 else {
91 Natural fixingDays = iborIndex_->fixingDays();
92 Date refDate = Settings::instance().evaluationDate();
93 // if the evaluation date is not a business day
94 // then move to the next business day
95 refDate = floatCalendar_.adjust(refDate);
96 Date spotDate = floatCalendar_.advance(date: refDate,
97 period: fixingDays*Days);
98 startDate = spotDate+forwardStart_;
99 }
100
101 Date terminationDate = startDate+swapTenor_;
102
103 Schedule cmsSchedule(startDate, terminationDate,
104 cmsTenor_, cmsCalendar_,
105 cmsConvention_,
106 cmsTerminationDateConvention_,
107 cmsRule_, cmsEndOfMonth_,
108 cmsFirstDate_, cmsNextToLastDate_);
109
110 Schedule floatSchedule(startDate, terminationDate,
111 floatTenor_, floatCalendar_,
112 floatConvention_,
113 floatTerminationDateConvention_,
114 floatRule_ , floatEndOfMonth_,
115 floatFirstDate_, floatNextToLastDate_);
116
117 Leg cmsLeg = CmsLeg(cmsSchedule, swapIndex_)
118 .withNotionals(notional: nominal_)
119 .withPaymentDayCounter(cmsDayCount_)
120 .withPaymentAdjustment(cmsConvention_)
121 .withFixingDays(fixingDays: swapIndex_->fixingDays())
122 .withGearings(gearing: cmsGearing_)
123 .withSpreads(spread: cmsSpread_)
124 .withCaps(cap: cmsCap_)
125 .withFloors(floor: cmsFloor_);
126 if (couponPricer_ != nullptr)
127 setCouponPricer(leg: cmsLeg, couponPricer_);
128
129 Rate usedSpread = iborSpread_;
130 if (useAtmSpread_) {
131 QL_REQUIRE(!iborIndex_->forwardingTermStructure().empty(),
132 "null term structure set to this instance of " <<
133 iborIndex_->name());
134 QL_REQUIRE(!swapIndex_->forwardingTermStructure().empty(),
135 "null term structure set to this instance of " <<
136 swapIndex_->name());
137 QL_REQUIRE(couponPricer_,
138 "no CmsCouponPricer set (yet)");
139 Leg floatLeg = IborLeg(floatSchedule, iborIndex_)
140 .withNotionals(notional: nominal_)
141 .withPaymentDayCounter(floatDayCount_)
142 .withPaymentAdjustment(floatConvention_)
143 .withFixingDays(fixingDays: iborIndex_->fixingDays());
144
145 Swap temp(cmsLeg, floatLeg);
146 temp.setPricingEngine(engine_);
147
148 Real npv = temp.legNPV(j: 0)+temp.legNPV(j: 1);
149
150 usedSpread = -npv/temp.legBPS(j: 1)*1e-4;
151 } else {
152 QL_REQUIRE(usedSpread != Null<Spread>(),
153 "null spread set");
154 }
155
156 Leg floatLeg = IborLeg(floatSchedule, iborIndex_)
157 .withNotionals(notional: nominal_)
158 .withPaymentDayCounter(floatDayCount_)
159 .withPaymentAdjustment(floatConvention_)
160 .withFixingDays(fixingDays: iborIndex_->fixingDays())
161 .withSpreads(spread: usedSpread);
162
163 ext::shared_ptr<Swap> swap;
164 if (payCms_)
165 swap = ext::make_shared<Swap>(args&: cmsLeg, args&: floatLeg);
166 else
167 swap = ext::make_shared<Swap>(args&: floatLeg, args&: cmsLeg);
168 swap->setPricingEngine(engine_);
169 return swap;
170 }
171
172 MakeCms& MakeCms::receiveCms(bool flag) {
173 payCms_ = !flag;
174 return *this;
175 }
176
177 MakeCms& MakeCms::withNominal(Real n) {
178 nominal_ = n;
179 return *this;
180 }
181
182 MakeCms&
183 MakeCms::withEffectiveDate(const Date& effectiveDate) {
184 effectiveDate_ = effectiveDate;
185 return *this;
186 }
187
188 MakeCms& MakeCms::withDiscountingTermStructure(
189 const Handle<YieldTermStructure>& discountingTermStructure) {
190 engine_ = ext::make_shared<DiscountingSwapEngine>(args: discountingTermStructure);
191 return *this;
192 }
193
194 MakeCms& MakeCms::withCmsCouponPricer(
195 const ext::shared_ptr<CmsCouponPricer>& couponPricer) {
196 couponPricer_ = couponPricer;
197 return *this;
198 }
199
200 MakeCms& MakeCms::withCmsLegTenor(const Period& t) {
201 cmsTenor_ = t;
202 return *this;
203 }
204
205 MakeCms&
206 MakeCms::withCmsLegCalendar(const Calendar& cal) {
207 cmsCalendar_ = cal;
208 return *this;
209 }
210
211 MakeCms&
212 MakeCms::withCmsLegConvention(BusinessDayConvention bdc) {
213 cmsConvention_ = bdc;
214 return *this;
215 }
216
217 MakeCms&
218 MakeCms::withCmsLegTerminationDateConvention(BusinessDayConvention bdc) {
219 cmsTerminationDateConvention_ = bdc;
220 return *this;
221 }
222
223 MakeCms& MakeCms::withCmsLegRule(DateGeneration::Rule r) {
224 cmsRule_ = r;
225 return *this;
226 }
227
228 MakeCms& MakeCms::withCmsLegEndOfMonth(bool flag) {
229 cmsEndOfMonth_ = flag;
230 return *this;
231 }
232
233 MakeCms& MakeCms::withCmsLegFirstDate(const Date& d) {
234 cmsFirstDate_ = d;
235 return *this;
236 }
237
238 MakeCms&
239 MakeCms::withCmsLegNextToLastDate(const Date& d) {
240 cmsNextToLastDate_ = d;
241 return *this;
242 }
243
244 MakeCms&
245 MakeCms::withCmsLegDayCount(const DayCounter& dc) {
246 cmsDayCount_ = dc;
247 return *this;
248 }
249
250 MakeCms& MakeCms::withFloatingLegTenor(const Period& t) {
251 floatTenor_ = t;
252 return *this;
253 }
254
255 MakeCms&
256 MakeCms::withFloatingLegCalendar(const Calendar& cal) {
257 floatCalendar_ = cal;
258 return *this;
259 }
260
261 MakeCms&
262 MakeCms::withFloatingLegConvention(BusinessDayConvention bdc) {
263 floatConvention_ = bdc;
264 return *this;
265 }
266
267 MakeCms&
268 MakeCms::withFloatingLegTerminationDateConvention(BusinessDayConvention bdc) {
269 floatTerminationDateConvention_ = bdc;
270 return *this;
271 }
272
273 MakeCms& MakeCms::withFloatingLegRule(DateGeneration::Rule r) {
274 floatRule_ = r;
275 return *this;
276 }
277
278 MakeCms& MakeCms::withFloatingLegEndOfMonth(bool flag) {
279 floatEndOfMonth_ = flag;
280 return *this;
281 }
282
283 MakeCms&
284 MakeCms::withFloatingLegFirstDate(const Date& d) {
285 floatFirstDate_ = d;
286 return *this;
287 }
288
289 MakeCms&
290 MakeCms::withFloatingLegNextToLastDate(const Date& d) {
291 floatNextToLastDate_ = d;
292 return *this;
293 }
294
295 MakeCms&
296 MakeCms::withFloatingLegDayCount(const DayCounter& dc) {
297 floatDayCount_ = dc;
298 return *this;
299 }
300
301 MakeCms& MakeCms::withAtmSpread(bool flag) {
302 useAtmSpread_ = flag;
303 return *this;
304 }
305
306}
307

source code of quantlib/ql/instruments/makecms.cpp

Morty Proxy This is a proxified and sanitized view of the page, visit original site.