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, 2008 StatPro Italia srl
6  Copyright (C) 2007, 2008, 2009, 2015 Ferdinando Ametrano
7  Copyright (C) 2007, 2009 Roland Lichters
8  Copyright (C) 2015 Maddalena Zanzi
9  Copyright (C) 2015 Paolo Mazzocchi
10  Copyright (C) 2018 Matthias Lungwitz
11 
12  This file is part of QuantLib, a free-software/open-source library
13  for financial quantitative analysts and developers - http://quantlib.org/
14 
15  QuantLib is free software: you can redistribute it and/or modify it
16  under the terms of the QuantLib license.  You should have received a
17  copy of the license along with this program; if not, please email
18  <quantlib-dev@lists.sf.net>. The license is also available online at
19  <http://quantlib.org/license.shtml>.
20 
21  This program is distributed in the hope that it will be useful, but WITHOUT
22  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
23  FOR A PARTICULAR PURPOSE.  See the license for more details.
24 */
25 
26 #include <ql/termstructures/yield/ratehelpers.hpp>
27 #include <ql/time/imm.hpp>
28 #include <ql/time/asx.hpp>
29 #include <ql/time/calendars/unitedstates.hpp>
30 #include <ql/time/calendars/jointcalendar.hpp>
31 #include <ql/instruments/makevanillaswap.hpp>
32 #include <ql/pricingengines/swap/discountingswapengine.hpp>
33 #include <ql/quote.hpp>
34 #include <ql/currency.hpp>
35 #include <ql/indexes/swapindex.hpp>
36 #include <ql/cashflows/iborcoupon.hpp>
37 #include <ql/time/imm.hpp>
38 #include <ql/utilities/null_deleter.hpp>
39 
40 namespace QuantLib {
41 
FuturesRateHelper(const Handle<Quote> & price,const Date & iborStartDate,Natural lengthInMonths,const Calendar & calendar,BusinessDayConvention convention,bool endOfMonth,const DayCounter & dayCounter,const Handle<Quote> & convAdj,Futures::Type type)42     FuturesRateHelper::FuturesRateHelper(const Handle<Quote>& price,
43                                          const Date& iborStartDate,
44                                          Natural lengthInMonths,
45                                          const Calendar& calendar,
46                                          BusinessDayConvention convention,
47                                          bool endOfMonth,
48                                          const DayCounter& dayCounter,
49                                          const Handle<Quote>& convAdj,
50                                          Futures::Type type)
51     : RateHelper(price), convAdj_(convAdj) {
52         switch (type) {
53           case Futures::IMM:
54             QL_REQUIRE(IMM::isIMMdate(iborStartDate, false),
55                        iborStartDate << " is not a valid IMM date");
56             break;
57           case Futures::ASX:
58             QL_REQUIRE(ASX::isASXdate(iborStartDate, false),
59                        iborStartDate << " is not a valid ASX date");
60             break;
61           default:
62             QL_FAIL("unknown futures type (" << Integer(type) << ")");
63         }
64         earliestDate_ = iborStartDate;
65         maturityDate_ = calendar.advance(iborStartDate, lengthInMonths*Months,
66                                          convention, endOfMonth);
67         yearFraction_ = dayCounter.yearFraction(earliestDate_, maturityDate_);
68         pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
69 
70         registerWith(convAdj_);
71     }
72 
FuturesRateHelper(Real price,const Date & iborStartDate,Natural lengthInMonths,const Calendar & calendar,BusinessDayConvention convention,bool endOfMonth,const DayCounter & dayCounter,Rate convAdj,Futures::Type type)73     FuturesRateHelper::FuturesRateHelper(Real price,
74                                          const Date& iborStartDate,
75                                          Natural lengthInMonths,
76                                          const Calendar& calendar,
77                                          BusinessDayConvention convention,
78                                          bool endOfMonth,
79                                          const DayCounter& dayCounter,
80                                          Rate convAdj,
81                                          Futures::Type type)
82     : RateHelper(price),
83       convAdj_(Handle<Quote>(ext::shared_ptr<Quote>(new SimpleQuote(convAdj))))
84     {
85         switch (type) {
86           case Futures::IMM:
87             QL_REQUIRE(IMM::isIMMdate(iborStartDate, false),
88                 iborStartDate << " is not a valid IMM date");
89             break;
90           case Futures::ASX:
91             QL_REQUIRE(ASX::isASXdate(iborStartDate, false),
92                 iborStartDate << " is not a valid ASX date");
93             break;
94           default:
95             QL_FAIL("unknown futures type (" << Integer(type) << ")");
96         }
97         earliestDate_ = iborStartDate;
98         maturityDate_ = calendar.advance(iborStartDate, lengthInMonths*Months,
99             convention, endOfMonth);
100         yearFraction_ = dayCounter.yearFraction(earliestDate_, maturityDate_);
101         pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
102     }
103 
FuturesRateHelper(const Handle<Quote> & price,const Date & iborStartDate,const Date & iborEndDate,const DayCounter & dayCounter,const Handle<Quote> & convAdj,Futures::Type type)104     FuturesRateHelper::FuturesRateHelper(const Handle<Quote>& price,
105                                          const Date& iborStartDate,
106                                          const Date& iborEndDate,
107                                          const DayCounter& dayCounter,
108                                          const Handle<Quote>& convAdj,
109                                          Futures::Type type)
110     : RateHelper(price), convAdj_(convAdj) {
111         switch (type) {
112           case Futures::IMM:
113             QL_REQUIRE(IMM::isIMMdate(iborStartDate, false),
114                        iborStartDate << " is not a valid IMM date");
115             if (iborEndDate == Date()) {
116                 // advance 3 months
117                 maturityDate_ = IMM::nextDate(iborStartDate, false);
118                 maturityDate_ = IMM::nextDate(maturityDate_, false);
119                 maturityDate_ = IMM::nextDate(maturityDate_, false);
120             }
121             else {
122                 QL_REQUIRE(iborEndDate>iborStartDate,
123                            "end date (" << iborEndDate <<
124                            ") must be greater than start date (" <<
125                            iborStartDate << ")");
126                 maturityDate_ = iborEndDate;
127             }
128             break;
129           case Futures::ASX:
130             QL_REQUIRE(ASX::isASXdate(iborStartDate, false),
131                        iborStartDate << " is not a valid ASX date");
132             if (iborEndDate == Date()) {
133                 // advance 3 months
134                 maturityDate_ = ASX::nextDate(iborStartDate, false);
135                 maturityDate_ = ASX::nextDate(maturityDate_, false);
136                 maturityDate_ = ASX::nextDate(maturityDate_, false);
137             }
138             else {
139                 QL_REQUIRE(iborEndDate>iborStartDate,
140                            "end date (" << iborEndDate <<
141                            ") must be greater than start date (" <<
142                           iborStartDate << ")");
143                 maturityDate_ = iborEndDate;
144             }
145             break;
146           default:
147             QL_FAIL("unknown futures type (" << Integer(type) << ")");
148         }
149         earliestDate_ = iborStartDate;
150         yearFraction_ = dayCounter.yearFraction(earliestDate_, maturityDate_);
151         pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
152 
153         registerWith(convAdj_);
154     }
155 
FuturesRateHelper(Real price,const Date & iborStartDate,const Date & iborEndDate,const DayCounter & dayCounter,Rate convAdj,Futures::Type type)156     FuturesRateHelper::FuturesRateHelper(Real price,
157                                          const Date& iborStartDate,
158                                          const Date& iborEndDate,
159                                          const DayCounter& dayCounter,
160                                          Rate convAdj,
161                                          Futures::Type type)
162     : RateHelper(price),
163       convAdj_(Handle<Quote>(ext::shared_ptr<Quote>(new SimpleQuote(convAdj))))
164     {
165         switch (type) {
166           case Futures::IMM:
167             QL_REQUIRE(IMM::isIMMdate(iborStartDate, false),
168                        iborStartDate << " is not a valid IMM date");
169             if (iborEndDate == Date()) {
170                 // advance 3 months
171                 maturityDate_ = IMM::nextDate(iborStartDate, false);
172                 maturityDate_ = IMM::nextDate(maturityDate_, false);
173                 maturityDate_ = IMM::nextDate(maturityDate_, false);
174             }
175             else {
176                 QL_REQUIRE(iborEndDate>iborStartDate,
177                            "end date (" << iborEndDate <<
178                            ") must be greater than start date (" <<
179                            iborStartDate << ")");
180                 maturityDate_ = iborEndDate;
181             }
182             break;
183           case Futures::ASX:
184             QL_REQUIRE(ASX::isASXdate(iborStartDate, false),
185                 iborStartDate << " is not a valid ASX date");
186             if (iborEndDate == Date()) {
187                 // advance 3 months
188                 maturityDate_ = ASX::nextDate(iborStartDate, false);
189                 maturityDate_ = ASX::nextDate(maturityDate_, false);
190                 maturityDate_ = ASX::nextDate(maturityDate_, false);
191             }
192             else {
193                 QL_REQUIRE(iborEndDate>iborStartDate,
194                            "end date (" << iborEndDate <<
195                            ") must be greater than start date (" <<
196                            iborStartDate << ")");
197                 latestRelevantDate_ = iborEndDate;
198             }
199             break;
200           default:
201             QL_FAIL("unknown futures type (" << Integer(type) << ")");
202         }
203         earliestDate_ = iborStartDate;
204         yearFraction_ = dayCounter.yearFraction(earliestDate_, maturityDate_);
205         pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
206     }
207 
FuturesRateHelper(const Handle<Quote> & price,const Date & iborStartDate,const ext::shared_ptr<IborIndex> & i,const Handle<Quote> & convAdj,Futures::Type type)208     FuturesRateHelper::FuturesRateHelper(const Handle<Quote>& price,
209                                          const Date& iborStartDate,
210                                          const ext::shared_ptr<IborIndex>& i,
211                                          const Handle<Quote>& convAdj,
212                                          Futures::Type type)
213     : RateHelper(price), convAdj_(convAdj) {
214         switch (type) {
215           case Futures::IMM:
216             QL_REQUIRE(IMM::isIMMdate(iborStartDate, false),
217                        iborStartDate << " is not a valid IMM date");
218             break;
219           case Futures::ASX:
220             QL_REQUIRE(ASX::isASXdate(iborStartDate, false),
221                        iborStartDate << " is not a valid ASX date");
222             break;
223           default:
224             QL_FAIL("unknown futures type (" << Integer(type) << ")");
225         }
226         earliestDate_ = iborStartDate;
227         const Calendar& cal = i->fixingCalendar();
228         maturityDate_ = cal.advance(iborStartDate, i->tenor(),
229                                     i->businessDayConvention());
230         yearFraction_ = i->dayCounter().yearFraction(earliestDate_,
231                                                      maturityDate_);
232         pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
233 
234         registerWith(convAdj);
235     }
236 
FuturesRateHelper(Real price,const Date & iborStartDate,const ext::shared_ptr<IborIndex> & i,Rate convAdj,Futures::Type type)237     FuturesRateHelper::FuturesRateHelper(Real price,
238                                          const Date& iborStartDate,
239                                          const ext::shared_ptr<IborIndex>& i,
240                                          Rate convAdj,
241                                          Futures::Type type)
242     : RateHelper(price),
243       convAdj_(Handle<Quote>(ext::shared_ptr<Quote>(new SimpleQuote(convAdj))))
244     {
245         switch (type) {
246           case Futures::IMM:
247             QL_REQUIRE(IMM::isIMMdate(iborStartDate, false),
248                 iborStartDate << " is not a valid IMM date");
249             break;
250           case Futures::ASX:
251             QL_REQUIRE(ASX::isASXdate(iborStartDate, false),
252                 iborStartDate << " is not a valid ASX date");
253             break;
254           default:
255             QL_FAIL("unknown futures type (" << Integer(type) << ")");
256         }
257         earliestDate_ = iborStartDate;
258         const Calendar& cal = i->fixingCalendar();
259         maturityDate_ = cal.advance(iborStartDate, i->tenor(),
260                                     i->businessDayConvention());
261         yearFraction_ = i->dayCounter().yearFraction(earliestDate_,
262                                                      maturityDate_);
263         pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
264     }
265 
impliedQuote() const266     Real FuturesRateHelper::impliedQuote() const {
267         QL_REQUIRE(termStructure_ != 0, "term structure not set");
268         Rate forwardRate = (termStructure_->discount(earliestDate_) /
269             termStructure_->discount(maturityDate_) - 1.0) / yearFraction_;
270         Rate convAdj = convAdj_.empty() ? 0.0 : convAdj_->value();
271         // Convexity, as FRA/futures adjustment, has been used in the
272         // past to take into account futures margining vs FRA.
273         // Therefore, there's no requirement for it to be non-negative.
274         Rate futureRate = forwardRate + convAdj;
275         return 100.0 * (1.0 - futureRate);
276     }
277 
convexityAdjustment() const278     Real FuturesRateHelper::convexityAdjustment() const {
279         return convAdj_.empty() ? 0.0 : convAdj_->value();
280     }
281 
accept(AcyclicVisitor & v)282     void FuturesRateHelper::accept(AcyclicVisitor& v) {
283         Visitor<FuturesRateHelper>* v1 =
284             dynamic_cast<Visitor<FuturesRateHelper>*>(&v);
285         if (v1 != 0)
286             v1->visit(*this);
287         else
288             RateHelper::accept(v);
289     }
290 
DepositRateHelper(const Handle<Quote> & rate,const Period & tenor,Natural fixingDays,const Calendar & calendar,BusinessDayConvention convention,bool endOfMonth,const DayCounter & dayCounter)291     DepositRateHelper::DepositRateHelper(const Handle<Quote>& rate,
292                                          const Period& tenor,
293                                          Natural fixingDays,
294                                          const Calendar& calendar,
295                                          BusinessDayConvention convention,
296                                          bool endOfMonth,
297                                          const DayCounter& dayCounter)
298     : RelativeDateRateHelper(rate) {
299         iborIndex_ = ext::make_shared<IborIndex>("no-fix", // never take fixing into account
300                       tenor, fixingDays,
301                       Currency(), calendar, convention,
302                       endOfMonth, dayCounter, termStructureHandle_);
303         initializeDates();
304     }
305 
DepositRateHelper(Rate rate,const Period & tenor,Natural fixingDays,const Calendar & calendar,BusinessDayConvention convention,bool endOfMonth,const DayCounter & dayCounter)306     DepositRateHelper::DepositRateHelper(Rate rate,
307                                          const Period& tenor,
308                                          Natural fixingDays,
309                                          const Calendar& calendar,
310                                          BusinessDayConvention convention,
311                                          bool endOfMonth,
312                                          const DayCounter& dayCounter)
313     : RelativeDateRateHelper(rate) {
314         iborIndex_ = ext::make_shared<IborIndex>("no-fix", // never take fixing into account
315                       tenor, fixingDays,
316                       Currency(), calendar, convention,
317                       endOfMonth, dayCounter, termStructureHandle_);
318         initializeDates();
319     }
320 
DepositRateHelper(const Handle<Quote> & rate,const ext::shared_ptr<IborIndex> & i)321     DepositRateHelper::DepositRateHelper(const Handle<Quote>& rate,
322                                          const ext::shared_ptr<IborIndex>& i)
323     : RelativeDateRateHelper(rate) {
324         iborIndex_ = i->clone(termStructureHandle_);
325         initializeDates();
326     }
327 
DepositRateHelper(Rate rate,const ext::shared_ptr<IborIndex> & i)328     DepositRateHelper::DepositRateHelper(Rate rate,
329                                          const ext::shared_ptr<IborIndex>& i)
330     : RelativeDateRateHelper(rate) {
331         iborIndex_ = i->clone(termStructureHandle_);
332         initializeDates();
333     }
334 
impliedQuote() const335     Real DepositRateHelper::impliedQuote() const {
336         QL_REQUIRE(termStructure_ != 0, "term structure not set");
337         // the forecast fixing flag is set to true because
338         // we do not want to take fixing into account
339         return iborIndex_->fixing(fixingDate_, true);
340     }
341 
setTermStructure(YieldTermStructure * t)342     void DepositRateHelper::setTermStructure(YieldTermStructure* t) {
343         // do not set the relinkable handle as an observer -
344         // force recalculation when needed---the index is not lazy
345         bool observer = false;
346 
347         ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
348         termStructureHandle_.linkTo(temp, observer);
349 
350         RelativeDateRateHelper::setTermStructure(t);
351     }
352 
initializeDates()353     void DepositRateHelper::initializeDates() {
354         // if the evaluation date is not a business day
355         // then move to the next business day
356         Date referenceDate =
357             iborIndex_->fixingCalendar().adjust(evaluationDate_);
358         earliestDate_ = iborIndex_->valueDate(referenceDate);
359         fixingDate_ = iborIndex_->fixingDate(earliestDate_);
360         maturityDate_ = iborIndex_->maturityDate(earliestDate_);
361         pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
362     }
363 
accept(AcyclicVisitor & v)364     void DepositRateHelper::accept(AcyclicVisitor& v) {
365         Visitor<DepositRateHelper>* v1 =
366             dynamic_cast<Visitor<DepositRateHelper>*>(&v);
367         if (v1 != 0)
368             v1->visit(*this);
369         else
370             RateHelper::accept(v);
371     }
372 
373 
FraRateHelper(const Handle<Quote> & rate,Natural monthsToStart,Natural monthsToEnd,Natural fixingDays,const Calendar & calendar,BusinessDayConvention convention,bool endOfMonth,const DayCounter & dayCounter,Pillar::Choice pillarChoice,Date customPillarDate,bool useIndexedCoupon)374     FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
375                                  Natural monthsToStart,
376                                  Natural monthsToEnd,
377                                  Natural fixingDays,
378                                  const Calendar& calendar,
379                                  BusinessDayConvention convention,
380                                  bool endOfMonth,
381                                  const DayCounter& dayCounter,
382                                  Pillar::Choice pillarChoice,
383                                  Date customPillarDate,
384                                  bool useIndexedCoupon)
385     : RelativeDateRateHelper(rate), periodToStart_(monthsToStart*Months),
386       pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
387         QL_REQUIRE(monthsToEnd>monthsToStart,
388                    "monthsToEnd (" << monthsToEnd <<
389                    ") must be grater than monthsToStart (" << monthsToStart <<
390                    ")");
391         // no way to take fixing into account,
392         // even if we would like to for FRA over today
393         iborIndex_ = ext::make_shared<IborIndex>("no-fix", // correct family name would be needed
394                       (monthsToEnd-monthsToStart)*Months,
395                       fixingDays,
396                       Currency(), calendar, convention,
397                       endOfMonth, dayCounter, termStructureHandle_);
398         pillarDate_ = customPillarDate;
399         initializeDates();
400     }
401 
FraRateHelper(Rate rate,Natural monthsToStart,Natural monthsToEnd,Natural fixingDays,const Calendar & calendar,BusinessDayConvention convention,bool endOfMonth,const DayCounter & dayCounter,Pillar::Choice pillarChoice,Date customPillarDate,bool useIndexedCoupon)402     FraRateHelper::FraRateHelper(Rate rate,
403                                  Natural monthsToStart,
404                                  Natural monthsToEnd,
405                                  Natural fixingDays,
406                                  const Calendar& calendar,
407                                  BusinessDayConvention convention,
408                                  bool endOfMonth,
409                                  const DayCounter& dayCounter,
410                                  Pillar::Choice pillarChoice,
411                                  Date customPillarDate,
412                                  bool useIndexedCoupon)
413     : RelativeDateRateHelper(rate), periodToStart_(monthsToStart*Months),
414       pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
415         QL_REQUIRE(monthsToEnd>monthsToStart,
416                    "monthsToEnd (" << monthsToEnd <<
417                    ") must be grater than monthsToStart (" << monthsToStart <<
418                    ")");
419         // no way to take fixing into account,
420         // even if we would like to for FRA over today
421         iborIndex_ = ext::make_shared<IborIndex>("no-fix", // correct family name would be needed
422                       (monthsToEnd-monthsToStart)*Months,
423                       fixingDays,
424                       Currency(), calendar, convention,
425                       endOfMonth, dayCounter, termStructureHandle_);
426         pillarDate_ = customPillarDate;
427         initializeDates();
428     }
429 
FraRateHelper(const Handle<Quote> & rate,Natural monthsToStart,const ext::shared_ptr<IborIndex> & i,Pillar::Choice pillarChoice,Date customPillarDate,bool useIndexedCoupon)430     FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
431                                  Natural monthsToStart,
432                                  const ext::shared_ptr<IborIndex>& i,
433                                  Pillar::Choice pillarChoice,
434                                  Date customPillarDate,
435                                  bool useIndexedCoupon)
436     : RelativeDateRateHelper(rate), periodToStart_(monthsToStart*Months),
437       pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
438         // take fixing into account
439         iborIndex_ = i->clone(termStructureHandle_);
440         // We want to be notified of changes of fixings, but we don't
441         // want notifications from termStructureHandle_ (they would
442         // interfere with bootstrapping.)
443         iborIndex_->unregisterWith(termStructureHandle_);
444         registerWith(iborIndex_);
445         pillarDate_ = customPillarDate;
446         initializeDates();
447     }
448 
FraRateHelper(Rate rate,Natural monthsToStart,const ext::shared_ptr<IborIndex> & i,Pillar::Choice pillarChoice,Date customPillarDate,bool useIndexedCoupon)449     FraRateHelper::FraRateHelper(Rate rate,
450                                  Natural monthsToStart,
451                                  const ext::shared_ptr<IborIndex>& i,
452                                  Pillar::Choice pillarChoice,
453                                  Date customPillarDate,
454                                  bool useIndexedCoupon)
455     : RelativeDateRateHelper(rate), periodToStart_(monthsToStart*Months),
456       pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
457         // take fixing into account
458         iborIndex_ = i->clone(termStructureHandle_);
459         // see above
460         iborIndex_->unregisterWith(termStructureHandle_);
461         registerWith(iborIndex_);
462         pillarDate_ = customPillarDate;
463         initializeDates();
464     }
465 
FraRateHelper(const Handle<Quote> & rate,Period periodToStart,Natural lengthInMonths,Natural fixingDays,const Calendar & calendar,BusinessDayConvention convention,bool endOfMonth,const DayCounter & dayCounter,Pillar::Choice pillarChoice,Date customPillarDate,bool useIndexedCoupon)466     FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
467                                  Period periodToStart,
468                                  Natural lengthInMonths,
469                                  Natural fixingDays,
470                                  const Calendar& calendar,
471                                  BusinessDayConvention convention,
472                                  bool endOfMonth,
473                                  const DayCounter& dayCounter,
474                                  Pillar::Choice pillarChoice,
475                                  Date customPillarDate,
476                                  bool useIndexedCoupon)
477     : RelativeDateRateHelper(rate), periodToStart_(periodToStart),
478       pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
479         // no way to take fixing into account,
480         // even if we would like to for FRA over today
481         iborIndex_ = ext::make_shared<IborIndex>("no-fix", // correct family name would be needed
482                       lengthInMonths*Months,
483                       fixingDays,
484                       Currency(), calendar, convention,
485                       endOfMonth, dayCounter, termStructureHandle_);
486         pillarDate_ = customPillarDate;
487         initializeDates();
488     }
489 
FraRateHelper(Rate rate,Period periodToStart,Natural lengthInMonths,Natural fixingDays,const Calendar & calendar,BusinessDayConvention convention,bool endOfMonth,const DayCounter & dayCounter,Pillar::Choice pillarChoice,Date customPillarDate,bool useIndexedCoupon)490     FraRateHelper::FraRateHelper(Rate rate,
491                                  Period periodToStart,
492                                  Natural lengthInMonths,
493                                  Natural fixingDays,
494                                  const Calendar& calendar,
495                                  BusinessDayConvention convention,
496                                  bool endOfMonth,
497                                  const DayCounter& dayCounter,
498                                  Pillar::Choice pillarChoice,
499                                  Date customPillarDate,
500                                  bool useIndexedCoupon)
501     : RelativeDateRateHelper(rate), periodToStart_(periodToStart),
502       pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
503         // no way to take fixing into account,
504         // even if we would like to for FRA over today
505         iborIndex_ = ext::make_shared<IborIndex>("no-fix", // correct family name would be needed
506                       lengthInMonths*Months,
507                       fixingDays,
508                       Currency(), calendar, convention,
509                       endOfMonth, dayCounter, termStructureHandle_);
510         pillarDate_ = customPillarDate;
511         initializeDates();
512     }
513 
FraRateHelper(const Handle<Quote> & rate,Period periodToStart,const ext::shared_ptr<IborIndex> & i,Pillar::Choice pillarChoice,Date customPillarDate,bool useIndexedCoupon)514     FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
515                                  Period periodToStart,
516                                  const ext::shared_ptr<IborIndex>& i,
517                                  Pillar::Choice pillarChoice,
518                                  Date customPillarDate,
519                                  bool useIndexedCoupon)
520     : RelativeDateRateHelper(rate), periodToStart_(periodToStart),
521       pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
522         // take fixing into account
523         iborIndex_ = i->clone(termStructureHandle_);
524         // see above
525         iborIndex_->unregisterWith(termStructureHandle_);
526         registerWith(iborIndex_);
527         pillarDate_ = customPillarDate;
528         initializeDates();
529     }
530 
FraRateHelper(Rate rate,Period periodToStart,const ext::shared_ptr<IborIndex> & i,Pillar::Choice pillarChoice,Date customPillarDate,bool useIndexedCoupon)531     FraRateHelper::FraRateHelper(Rate rate,
532                                  Period periodToStart,
533                                  const ext::shared_ptr<IborIndex>& i,
534                                  Pillar::Choice pillarChoice,
535                                  Date customPillarDate,
536                                  bool useIndexedCoupon)
537     : RelativeDateRateHelper(rate), periodToStart_(periodToStart),
538       pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
539         // take fixing into account
540         iborIndex_ = i->clone(termStructureHandle_);
541         // see above
542         iborIndex_->unregisterWith(termStructureHandle_);
543         registerWith(iborIndex_);
544         pillarDate_ = customPillarDate;
545         initializeDates();
546     }
547 
FraRateHelper(const Handle<Quote> & rate,Natural immOffsetStart,Natural immOffsetEnd,const ext::shared_ptr<IborIndex> & i,Pillar::Choice pillarChoice,Date customPillarDate,bool useIndexedCoupon)548     FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
549                                  Natural immOffsetStart,
550                                  Natural immOffsetEnd,
551                                  const ext::shared_ptr<IborIndex>& i,
552                                  Pillar::Choice pillarChoice,
553                                  Date customPillarDate,
554                                  bool useIndexedCoupon)
555     : RelativeDateRateHelper(rate), immOffsetStart_(immOffsetStart), immOffsetEnd_(immOffsetEnd),
556       pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
557         // take fixing into account
558         iborIndex_ = i->clone(termStructureHandle_);
559         // see above
560         iborIndex_->unregisterWith(termStructureHandle_);
561         registerWith(iborIndex_);
562         pillarDate_ = customPillarDate;
563         initializeDates();
564     }
565 
FraRateHelper(Rate rate,Natural immOffsetStart,Natural immOffsetEnd,const ext::shared_ptr<IborIndex> & i,Pillar::Choice pillarChoice,Date customPillarDate,bool useIndexedCoupon)566     FraRateHelper::FraRateHelper(Rate rate,
567                                  Natural immOffsetStart,
568                                  Natural immOffsetEnd,
569                                  const ext::shared_ptr<IborIndex>& i,
570                                  Pillar::Choice pillarChoice,
571                                  Date customPillarDate,
572                                  bool useIndexedCoupon)
573     : RelativeDateRateHelper(rate), immOffsetStart_(immOffsetStart), immOffsetEnd_(immOffsetEnd),
574       pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
575         // take fixing into account
576         iborIndex_ = i->clone(termStructureHandle_);
577         // see above
578         iborIndex_->unregisterWith(termStructureHandle_);
579         registerWith(iborIndex_);
580         pillarDate_ = customPillarDate;
581         initializeDates();
582     }
583 
impliedQuote() const584     Real FraRateHelper::impliedQuote() const {
585         QL_REQUIRE(termStructure_ != 0, "term structure not set");
586         if (useIndexedCoupon_)
587             return iborIndex_->fixing(fixingDate_, true);
588         else
589             return (termStructure_->discount(earliestDate_) /
590                         termStructure_->discount(maturityDate_) -
591                     1.0) /
592                    spanningTime_;
593     }
594 
setTermStructure(YieldTermStructure * t)595     void FraRateHelper::setTermStructure(YieldTermStructure* t) {
596         // do not set the relinkable handle as an observer -
597         // force recalculation when needed---the index is not lazy
598         bool observer = false;
599 
600         ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
601         termStructureHandle_.linkTo(temp, observer);
602 
603         RelativeDateRateHelper::setTermStructure(t);
604     }
605 
606     namespace {
nthImmDate(const Date & asof,const Size n)607         Date nthImmDate(const Date& asof, const Size n) {
608             Date imm = asof;
609             for (Size i = 0; i < n; ++i) {
610                 imm = IMM::nextDate(imm, true);
611             }
612             return imm;
613         }
614     }
615 
initializeDates()616     void FraRateHelper::initializeDates() {
617         // if the evaluation date is not a business day
618         // then move to the next business day
619         Date referenceDate =
620             iborIndex_->fixingCalendar().adjust(evaluationDate_);
621         Date spotDate = iborIndex_->fixingCalendar().advance(
622             referenceDate, iborIndex_->fixingDays()*Days);
623         if (periodToStart_) { // NOLINT(readability-implicit-bool-conversion)
624             earliestDate_ = iborIndex_->fixingCalendar().advance(
625                 spotDate, *periodToStart_, iborIndex_->businessDayConvention(),
626                 iborIndex_->endOfMonth());
627             // maturity date is calculated from spot date
628             maturityDate_ = iborIndex_->fixingCalendar().advance(
629                 spotDate, *periodToStart_ + iborIndex_->tenor(), iborIndex_->businessDayConvention(),
630                 iborIndex_->endOfMonth());
631         } else if ((immOffsetStart_) && (immOffsetEnd_)) { // NOLINT(readability-implicit-bool-conversion)
632             earliestDate_ = iborIndex_->fixingCalendar().adjust(nthImmDate(spotDate, *immOffsetStart_));
633             maturityDate_ = iborIndex_->fixingCalendar().adjust(nthImmDate(spotDate, *immOffsetEnd_));
634         } else {
635             QL_FAIL("neither periodToStart nor immOffsetStart/End given");
636         }
637 
638         if (useIndexedCoupon_)
639             // latest relevant date is calculated from earliestDate_
640             latestRelevantDate_ = iborIndex_->maturityDate(earliestDate_);
641         else {
642             latestRelevantDate_ = maturityDate_;
643             spanningTime_ = iborIndex_->dayCounter().yearFraction(earliestDate_, maturityDate_);
644         }
645 
646         switch (pillarChoice_) {
647           case Pillar::MaturityDate:
648             pillarDate_ = maturityDate_;
649             break;
650           case Pillar::LastRelevantDate:
651             pillarDate_ = latestRelevantDate_;
652             break;
653           case Pillar::CustomDate:
654             // pillarDate_ already assigned at construction time
655             QL_REQUIRE(pillarDate_ >= earliestDate_,
656                        "pillar date (" << pillarDate_ << ") must be later "
657                        "than or equal to the instrument's earliest date (" <<
658                        earliestDate_ << ")");
659             QL_REQUIRE(pillarDate_ <= latestRelevantDate_,
660                        "pillar date (" << pillarDate_ << ") must be before "
661                        "or equal to the instrument's latest relevant date (" <<
662                        latestRelevantDate_ << ")");
663             break;
664           default:
665             QL_FAIL("unknown Pillar::Choice(" << Integer(pillarChoice_) << ")");
666         }
667 
668         latestDate_ = pillarDate_; // backward compatibility
669 
670         fixingDate_ = iborIndex_->fixingDate(earliestDate_);
671     }
672 
accept(AcyclicVisitor & v)673     void FraRateHelper::accept(AcyclicVisitor& v) {
674         Visitor<FraRateHelper>* v1 =
675             dynamic_cast<Visitor<FraRateHelper>*>(&v);
676         if (v1 != 0)
677             v1->visit(*this);
678         else
679             RateHelper::accept(v);
680     }
681 
682 
SwapRateHelper(const Handle<Quote> & rate,const ext::shared_ptr<SwapIndex> & swapIndex,const Handle<Quote> & spread,const Period & fwdStart,const Handle<YieldTermStructure> & discount,Pillar::Choice pillarChoice,Date customPillarDate,bool endOfMonth)683     SwapRateHelper::SwapRateHelper(const Handle<Quote>& rate,
684                                    const ext::shared_ptr<SwapIndex>& swapIndex,
685                                    const Handle<Quote>& spread,
686                                    const Period& fwdStart,
687                                    const Handle<YieldTermStructure>& discount,
688                                    Pillar::Choice pillarChoice,
689                                    Date customPillarDate,
690                                    bool endOfMonth)
691     : RelativeDateRateHelper(rate),
692       settlementDays_(Null<Natural>()),
693       tenor_(swapIndex->tenor()), pillarChoice_(pillarChoice),
694       calendar_(swapIndex->fixingCalendar()),
695       fixedConvention_(swapIndex->fixedLegConvention()),
696       fixedFrequency_(swapIndex->fixedLegTenor().frequency()),
697       fixedDayCount_(swapIndex->dayCounter()),
698       spread_(spread), endOfMonth_(endOfMonth),
699       fwdStart_(fwdStart), discountHandle_(discount) {
700         // take fixing into account
701         iborIndex_ = swapIndex->iborIndex()->clone(termStructureHandle_);
702         // We want to be notified of changes of fixings, but we don't
703         // want notifications from termStructureHandle_ (they would
704         // interfere with bootstrapping.)
705         iborIndex_->unregisterWith(termStructureHandle_);
706 
707         registerWith(iborIndex_);
708         registerWith(spread_);
709         registerWith(discountHandle_);
710 
711         pillarDate_ = customPillarDate;
712         initializeDates();
713     }
714 
SwapRateHelper(const Handle<Quote> & rate,const Period & tenor,const Calendar & calendar,Frequency fixedFrequency,BusinessDayConvention fixedConvention,const DayCounter & fixedDayCount,const ext::shared_ptr<IborIndex> & iborIndex,const Handle<Quote> & spread,const Period & fwdStart,const Handle<YieldTermStructure> & discount,Natural settlementDays,Pillar::Choice pillarChoice,Date customPillarDate,bool endOfMonth)715     SwapRateHelper::SwapRateHelper(const Handle<Quote>& rate,
716                                    const Period& tenor,
717                                    const Calendar& calendar,
718                                    Frequency fixedFrequency,
719                                    BusinessDayConvention fixedConvention,
720                                    const DayCounter& fixedDayCount,
721                                    const ext::shared_ptr<IborIndex>& iborIndex,
722                                    const Handle<Quote>& spread,
723                                    const Period& fwdStart,
724                                    const Handle<YieldTermStructure>& discount,
725                                    Natural settlementDays,
726                                    Pillar::Choice pillarChoice,
727                                    Date customPillarDate,
728                                    bool endOfMonth)
729     : RelativeDateRateHelper(rate),
730       settlementDays_(settlementDays),
731       tenor_(tenor), pillarChoice_(pillarChoice),
732       calendar_(calendar),
733       fixedConvention_(fixedConvention),
734       fixedFrequency_(fixedFrequency),
735       fixedDayCount_(fixedDayCount),
736       spread_(spread), endOfMonth_(endOfMonth),
737       fwdStart_(fwdStart), discountHandle_(discount) {
738 
739         // take fixing into account
740         iborIndex_ = iborIndex->clone(termStructureHandle_);
741         // We want to be notified of changes of fixings, but we don't
742         // want notifications from termStructureHandle_ (they would
743         // interfere with bootstrapping.)
744         iborIndex_->unregisterWith(termStructureHandle_);
745 
746         registerWith(iborIndex_);
747         registerWith(spread_);
748         registerWith(discountHandle_);
749 
750         pillarDate_ = customPillarDate;
751         initializeDates();
752     }
753 
SwapRateHelper(Rate rate,const ext::shared_ptr<SwapIndex> & swapIndex,const Handle<Quote> & spread,const Period & fwdStart,const Handle<YieldTermStructure> & discount,Pillar::Choice pillarChoice,Date customPillarDate,bool endOfMonth)754     SwapRateHelper::SwapRateHelper(Rate rate,
755                                    const ext::shared_ptr<SwapIndex>& swapIndex,
756                                    const Handle<Quote>& spread,
757                                    const Period& fwdStart,
758                                    const Handle<YieldTermStructure>& discount,
759                                    Pillar::Choice pillarChoice,
760                                    Date customPillarDate,
761                                    bool endOfMonth)
762     : RelativeDateRateHelper(rate),
763       settlementDays_(Null<Natural>()),
764       tenor_(swapIndex->tenor()), pillarChoice_(pillarChoice),
765       calendar_(swapIndex->fixingCalendar()),
766       fixedConvention_(swapIndex->fixedLegConvention()),
767       fixedFrequency_(swapIndex->fixedLegTenor().frequency()),
768       fixedDayCount_(swapIndex->dayCounter()),
769       spread_(spread), endOfMonth_(endOfMonth),
770       fwdStart_(fwdStart), discountHandle_(discount) {
771         // take fixing into account
772         iborIndex_ = swapIndex->iborIndex()->clone(termStructureHandle_);
773         // We want to be notified of changes of fixings, but we don't
774         // want notifications from termStructureHandle_ (they would
775         // interfere with bootstrapping.)
776         iborIndex_->unregisterWith(termStructureHandle_);
777 
778         registerWith(iborIndex_);
779         registerWith(spread_);
780         registerWith(discountHandle_);
781 
782         pillarDate_ = customPillarDate;
783         initializeDates();
784     }
785 
SwapRateHelper(Rate rate,const Period & tenor,const Calendar & calendar,Frequency fixedFrequency,BusinessDayConvention fixedConvention,const DayCounter & fixedDayCount,const ext::shared_ptr<IborIndex> & iborIndex,const Handle<Quote> & spread,const Period & fwdStart,const Handle<YieldTermStructure> & discount,Natural settlementDays,Pillar::Choice pillarChoice,Date customPillarDate,bool endOfMonth)786     SwapRateHelper::SwapRateHelper(Rate rate,
787                                    const Period& tenor,
788                                    const Calendar& calendar,
789                                    Frequency fixedFrequency,
790                                    BusinessDayConvention fixedConvention,
791                                    const DayCounter& fixedDayCount,
792                                    const ext::shared_ptr<IborIndex>& iborIndex,
793                                    const Handle<Quote>& spread,
794                                    const Period& fwdStart,
795                                    const Handle<YieldTermStructure>& discount,
796                                    Natural settlementDays,
797                                    Pillar::Choice pillarChoice,
798                                    Date customPillarDate,
799                                    bool endOfMonth)
800     : RelativeDateRateHelper(rate),
801       settlementDays_(settlementDays),
802       tenor_(tenor), pillarChoice_(pillarChoice),
803       calendar_(calendar),
804       fixedConvention_(fixedConvention),
805       fixedFrequency_(fixedFrequency),
806       fixedDayCount_(fixedDayCount),
807       spread_(spread), endOfMonth_(endOfMonth),
808       fwdStart_(fwdStart), discountHandle_(discount) {
809 
810         // take fixing into account
811         iborIndex_ = iborIndex->clone(termStructureHandle_);
812         // We want to be notified of changes of fixings, but we don't
813         // want notifications from termStructureHandle_ (they would
814         // interfere with bootstrapping.)
815         iborIndex_->unregisterWith(termStructureHandle_);
816 
817         registerWith(iborIndex_);
818         registerWith(spread_);
819         registerWith(discountHandle_);
820 
821         pillarDate_ = customPillarDate;
822         initializeDates();
823     }
824 
initializeDates()825     void SwapRateHelper::initializeDates() {
826 
827         // 1. do not pass the spread here, as it might be a Quote
828         //    i.e. it can dinamically change
829         // 2. input discount curve Handle might be empty now but it could
830         //    be assigned a curve later; use a RelinkableHandle here
831         swap_ = MakeVanillaSwap(tenor_, iborIndex_, 0.0, fwdStart_)
832             .withSettlementDays(settlementDays_)
833             .withDiscountingTermStructure(discountRelinkableHandle_)
834             .withFixedLegDayCount(fixedDayCount_)
835             .withFixedLegTenor(Period(fixedFrequency_))
836             .withFixedLegConvention(fixedConvention_)
837             .withFixedLegTerminationDateConvention(fixedConvention_)
838             .withFixedLegCalendar(calendar_)
839             .withFixedLegEndOfMonth(endOfMonth_)
840             .withFloatingLegCalendar(calendar_)
841             .withFloatingLegEndOfMonth(endOfMonth_);
842 
843         earliestDate_ = swap_->startDate();
844         maturityDate_ = swap_->maturityDate();
845 
846         ext::shared_ptr<IborCoupon> lastCoupon =
847             ext::dynamic_pointer_cast<IborCoupon>(swap_->floatingLeg().back());
848         latestRelevantDate_ = std::max(maturityDate_, lastCoupon->fixingEndDate());
849 
850         switch (pillarChoice_) {
851           case Pillar::MaturityDate:
852             pillarDate_ = maturityDate_;
853             break;
854           case Pillar::LastRelevantDate:
855             pillarDate_ = latestRelevantDate_;
856             break;
857           case Pillar::CustomDate:
858             // pillarDate_ already assigned at construction time
859             QL_REQUIRE(pillarDate_ >= earliestDate_,
860                 "pillar date (" << pillarDate_ << ") must be later "
861                 "than or equal to the instrument's earliest date (" <<
862                 earliestDate_ << ")");
863             QL_REQUIRE(pillarDate_ <= latestRelevantDate_,
864                 "pillar date (" << pillarDate_ << ") must be before "
865                 "or equal to the instrument's latest relevant date (" <<
866                 latestRelevantDate_ << ")");
867             break;
868           default:
869             QL_FAIL("unknown Pillar::Choice(" << Integer(pillarChoice_) << ")");
870         }
871 
872         latestDate_ = pillarDate_; // backward compatibility
873 
874     }
875 
setTermStructure(YieldTermStructure * t)876     void SwapRateHelper::setTermStructure(YieldTermStructure* t) {
877         // do not set the relinkable handle as an observer -
878         // force recalculation when needed
879         bool observer = false;
880 
881         ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
882         termStructureHandle_.linkTo(temp, observer);
883 
884         if (discountHandle_.empty())
885             discountRelinkableHandle_.linkTo(temp, observer);
886         else
887             discountRelinkableHandle_.linkTo(*discountHandle_, observer);
888 
889         RelativeDateRateHelper::setTermStructure(t);
890     }
891 
impliedQuote() const892     Real SwapRateHelper::impliedQuote() const {
893         QL_REQUIRE(termStructure_ != 0, "term structure not set");
894         // we didn't register as observers - force calculation
895         swap_->recalculate();
896         // weak implementation... to be improved
897         static const Spread basisPoint = 1.0e-4;
898         Real floatingLegNPV = swap_->floatingLegNPV();
899         Spread spread = spread_.empty() ? 0.0 : spread_->value();
900         Real spreadNPV = swap_->floatingLegBPS()/basisPoint*spread;
901         Real totNPV = - (floatingLegNPV+spreadNPV);
902         Real result = totNPV/(swap_->fixedLegBPS()/basisPoint);
903         return result;
904     }
905 
accept(AcyclicVisitor & v)906     void SwapRateHelper::accept(AcyclicVisitor& v) {
907         Visitor<SwapRateHelper>* v1 =
908             dynamic_cast<Visitor<SwapRateHelper>*>(&v);
909         if (v1 != 0)
910             v1->visit(*this);
911         else
912             RateHelper::accept(v);
913     }
914 
BMASwapRateHelper(const Handle<Quote> & liborFraction,const Period & tenor,Natural settlementDays,const Calendar & calendar,const Period & bmaPeriod,BusinessDayConvention bmaConvention,const DayCounter & bmaDayCount,const ext::shared_ptr<BMAIndex> & bmaIndex,const ext::shared_ptr<IborIndex> & iborIndex)915     BMASwapRateHelper::BMASwapRateHelper(
916                           const Handle<Quote>& liborFraction,
917                           const Period& tenor,
918                           Natural settlementDays,
919                           const Calendar& calendar,
920                           // bma leg
921                           const Period& bmaPeriod,
922                           BusinessDayConvention bmaConvention,
923                           const DayCounter& bmaDayCount,
924                           const ext::shared_ptr<BMAIndex>& bmaIndex,
925                           // libor leg
926                           const ext::shared_ptr<IborIndex>& iborIndex)
927     : RelativeDateRateHelper(liborFraction),
928       tenor_(tenor), settlementDays_(settlementDays),
929       calendar_(calendar),
930       bmaPeriod_(bmaPeriod),
931       bmaConvention_(bmaConvention),
932       bmaDayCount_(bmaDayCount),
933       bmaIndex_(bmaIndex),
934       iborIndex_(iborIndex) {
935         registerWith(iborIndex_);
936         registerWith(bmaIndex_);
937         initializeDates();
938     }
939 
initializeDates()940     void BMASwapRateHelper::initializeDates() {
941         // if the evaluation date is not a business day
942         // then move to the next business day
943         JointCalendar jc(calendar_,
944                          iborIndex_->fixingCalendar());
945         Date referenceDate = jc.adjust(evaluationDate_);
946         earliestDate_ =
947             calendar_.advance(referenceDate, settlementDays_ * Days, Following);
948 
949         Date maturity = earliestDate_ + tenor_;
950 
951         // dummy BMA index with curve/swap arguments
952         ext::shared_ptr<BMAIndex> clonedIndex(new BMAIndex(termStructureHandle_));
953 
954         Schedule bmaSchedule =
955             MakeSchedule().from(earliestDate_).to(maturity)
956                           .withTenor(bmaPeriod_)
957                           .withCalendar(bmaIndex_->fixingCalendar())
958                           .withConvention(bmaConvention_)
959                           .backwards();
960 
961         Schedule liborSchedule =
962             MakeSchedule().from(earliestDate_).to(maturity)
963                           .withTenor(iborIndex_->tenor())
964                           .withCalendar(iborIndex_->fixingCalendar())
965                           .withConvention(iborIndex_->businessDayConvention())
966                           .endOfMonth(iborIndex_->endOfMonth())
967                           .backwards();
968 
969         swap_ = ext::shared_ptr<BMASwap>(new BMASwap(BMASwap::Payer, 100.0,
970                                                 liborSchedule,
971                                                 0.75, // arbitrary
972                                                 0.0,
973                                                 iborIndex_,
974                                                 iborIndex_->dayCounter(),
975                                                 bmaSchedule,
976                                                 clonedIndex,
977                                                 bmaDayCount_));
978         swap_->setPricingEngine(ext::shared_ptr<PricingEngine>(new
979             DiscountingSwapEngine(iborIndex_->forwardingTermStructure())));
980 
981         Date d = calendar_.adjust(swap_->maturityDate(), Following);
982         Weekday w = d.weekday();
983         Date nextWednesday = (w >= 4) ?
984             d + (11 - w) * Days :
985             d + (4 - w) * Days;
986         latestDate_ = clonedIndex->valueDate(
987                          clonedIndex->fixingCalendar().adjust(nextWednesday));
988     }
989 
setTermStructure(YieldTermStructure * t)990     void BMASwapRateHelper::setTermStructure(YieldTermStructure* t) {
991         // do not set the relinkable handle as an observer -
992         // force recalculation when needed
993         bool observer = false;
994 
995         ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
996         termStructureHandle_.linkTo(temp, observer);
997 
998         RelativeDateRateHelper::setTermStructure(t);
999     }
1000 
impliedQuote() const1001     Real BMASwapRateHelper::impliedQuote() const {
1002         QL_REQUIRE(termStructure_ != 0, "term structure not set");
1003         // we didn't register as observers - force calculation
1004         swap_->recalculate();
1005         return swap_->fairLiborFraction();
1006     }
1007 
accept(AcyclicVisitor & v)1008     void BMASwapRateHelper::accept(AcyclicVisitor& v) {
1009         Visitor<BMASwapRateHelper>* v1 =
1010             dynamic_cast<Visitor<BMASwapRateHelper>*>(&v);
1011         if (v1 != 0)
1012             v1->visit(*this);
1013         else
1014             RateHelper::accept(v);
1015     }
1016 
FxSwapRateHelper(const Handle<Quote> & fwdPoint,const Handle<Quote> & spotFx,const Period & tenor,Natural fixingDays,const Calendar & calendar,BusinessDayConvention convention,bool endOfMonth,bool isFxBaseCurrencyCollateralCurrency,const Handle<YieldTermStructure> & coll,const Calendar & tradingCalendar)1017     FxSwapRateHelper::FxSwapRateHelper(const Handle<Quote>& fwdPoint,
1018                                        const Handle<Quote>& spotFx,
1019                                        const Period& tenor,
1020                                        Natural fixingDays,
1021                                        const Calendar& calendar,
1022                                        BusinessDayConvention convention,
1023                                        bool endOfMonth,
1024                                        bool isFxBaseCurrencyCollateralCurrency,
1025                                        const Handle<YieldTermStructure>& coll,
1026                                        const Calendar& tradingCalendar)
1027     : RelativeDateRateHelper(fwdPoint), spot_(spotFx), tenor_(tenor),
1028       fixingDays_(fixingDays), cal_(calendar), conv_(convention),
1029       eom_(endOfMonth),
1030       isFxBaseCurrencyCollateralCurrency_(isFxBaseCurrencyCollateralCurrency),
1031       collHandle_(coll), tradingCalendar_(tradingCalendar) {
1032         registerWith(spot_);
1033         registerWith(collHandle_);
1034 
1035         if (tradingCalendar_.empty())
1036             jointCalendar_ = cal_;
1037         else
1038             jointCalendar_ = JointCalendar(tradingCalendar_, cal_,
1039                                            JoinHolidays);
1040         initializeDates();
1041     }
1042 
initializeDates()1043     void FxSwapRateHelper::initializeDates() {
1044         // if the evaluation date is not a business day
1045         // then move to the next business day
1046         Date refDate = cal_.adjust(evaluationDate_);
1047         earliestDate_ = cal_.advance(refDate, fixingDays_*Days);
1048 
1049         if (!tradingCalendar_.empty()) {
1050             // check if fx trade can be settled in US, if not, adjust it
1051             earliestDate_ = jointCalendar_.adjust(earliestDate_);
1052             latestDate_ = jointCalendar_.advance(earliestDate_, tenor_,
1053                                                  conv_, eom_);
1054         } else {
1055             latestDate_ = cal_.advance(earliestDate_, tenor_, conv_, eom_);
1056         }
1057     }
1058 
impliedQuote() const1059     Real FxSwapRateHelper::impliedQuote() const {
1060         QL_REQUIRE(termStructure_ != 0, "term structure not set");
1061 
1062         QL_REQUIRE(!collHandle_.empty(), "collateral term structure not set");
1063 
1064         DiscountFactor d1 = collHandle_->discount(earliestDate_);
1065         DiscountFactor d2 = collHandle_->discount(latestDate_);
1066         Real collRatio = d1 / d2;
1067         d1 = termStructureHandle_->discount(earliestDate_);
1068         d2 = termStructureHandle_->discount(latestDate_);
1069         Real ratio = d1 / d2;
1070         Real spot = spot_->value();
1071         if (isFxBaseCurrencyCollateralCurrency_) {
1072             return (ratio/collRatio-1)*spot;
1073         } else {
1074             return (collRatio/ratio-1)*spot;
1075         }
1076     }
1077 
setTermStructure(YieldTermStructure * t)1078     void FxSwapRateHelper::setTermStructure(YieldTermStructure* t) {
1079         // do not set the relinkable handle as an observer -
1080         // force recalculation when needed
1081         bool observer = false;
1082 
1083         ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
1084         termStructureHandle_.linkTo(temp, observer);
1085 
1086         collRelinkableHandle_.linkTo(*collHandle_, observer);
1087 
1088         RelativeDateRateHelper::setTermStructure(t);
1089     }
1090 
accept(AcyclicVisitor & v)1091     void FxSwapRateHelper::accept(AcyclicVisitor& v) {
1092         Visitor<FxSwapRateHelper>* v1 =
1093             dynamic_cast<Visitor<FxSwapRateHelper>*>(&v);
1094         if (v1 != 0)
1095             v1->visit(*this);
1096         else
1097             RateHelper::accept(v);
1098     }
1099 
1100 }
1101