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