1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 3 /* 4 Copyright (C) 2001, 2002, 2003 Sadruddin Rejeb 5 Copyright (C) 2013 Peter Caspers 6 7 This file is part of QuantLib, a free-software/open-source library 8 for financial quantitative analysts and developers - http://quantlib.org/ 9 10 QuantLib is free software: you can redistribute it and/or modify it 11 under the terms of the QuantLib license. You should have received a 12 copy of the license along with this program; if not, please email 13 <quantlib-dev@lists.sf.net>. The license is also available online at 14 <http://quantlib.org/license.shtml>. 15 16 This program is distributed in the hope that it will be useful, but WITHOUT 17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 FOR A PARTICULAR PURPOSE. See the license for more details. 19 */ 20 21 #include <ql/pricingengines/swaption/jamshidianswaptionengine.hpp> 22 #include <ql/math/solvers1d/brent.hpp> 23 24 namespace QuantLib { 25 26 class JamshidianSwaptionEngine::rStarFinder { 27 public: rStarFinder(const ext::shared_ptr<OneFactorAffineModel> & model,Real nominal,Time maturity,Time valueTime,const std::vector<Time> & fixedPayTimes,const std::vector<Real> & amounts)28 rStarFinder(const ext::shared_ptr<OneFactorAffineModel>& model, 29 Real nominal, 30 Time maturity, 31 Time valueTime, 32 const std::vector<Time>& fixedPayTimes, 33 const std::vector<Real>& amounts) 34 : strike_(nominal), maturity_(maturity), valueTime_(valueTime), times_(fixedPayTimes), amounts_(amounts), model_(model) {} 35 operator ()(Rate x) const36 Real operator()(Rate x) const { 37 Real value = strike_; 38 Real B = model_->discountBond(maturity_, valueTime_, x); 39 Size size = times_.size(); 40 for (Size i=0; i<size; i++) { 41 Real dbValue = 42 model_->discountBond(maturity_, times_[i], x) / B; 43 value -= amounts_[i]*dbValue; 44 } 45 return value; 46 } 47 private: 48 Real strike_; 49 Time maturity_,valueTime_; 50 std::vector<Time> times_; 51 const std::vector<Real>& amounts_; 52 const ext::shared_ptr<OneFactorAffineModel>& model_; 53 }; 54 calculate() const55 void JamshidianSwaptionEngine::calculate() const { 56 57 QL_REQUIRE(arguments_.settlementMethod != Settlement::ParYieldCurve, 58 "cash settled (ParYieldCurve) swaptions not priced with " 59 "JamshidianSwaptionEngine"); 60 61 QL_REQUIRE(arguments_.exercise->type() == Exercise::European, 62 "cannot use the Jamshidian decomposition " 63 "on exotic swaptions"); 64 65 QL_REQUIRE(arguments_.swap->spread() == 0.0, "non zero spread (" << arguments_.swap->spread() << ") not allowed"); // PC 66 67 Date referenceDate; 68 DayCounter dayCounter; 69 70 ext::shared_ptr<TermStructureConsistentModel> tsmodel = 71 ext::dynamic_pointer_cast<TermStructureConsistentModel>(*model_); 72 if (tsmodel != 0) { 73 referenceDate = tsmodel->termStructure()->referenceDate(); 74 dayCounter = tsmodel->termStructure()->dayCounter(); 75 } else { 76 referenceDate = termStructure_->referenceDate(); 77 dayCounter = termStructure_->dayCounter(); 78 } 79 80 std::vector<Real> amounts(arguments_.fixedCoupons); 81 amounts.back() += arguments_.nominal; 82 83 Real maturity = dayCounter.yearFraction(referenceDate, 84 arguments_.exercise->date(0)); 85 86 std::vector<Time> fixedPayTimes(arguments_.fixedPayDates.size()); 87 Time valueTime = dayCounter.yearFraction(referenceDate,arguments_.fixedResetDates[0]); 88 for (Size i=0; i<fixedPayTimes.size(); i++) 89 fixedPayTimes[i] = dayCounter.yearFraction(referenceDate, 90 arguments_.fixedPayDates[i]); 91 92 rStarFinder finder(*model_, arguments_.nominal, maturity, valueTime, 93 fixedPayTimes, amounts); 94 Brent s1d; 95 Rate minStrike = -10.0; 96 Rate maxStrike = 10.0; 97 s1d.setMaxEvaluations(10000); 98 s1d.setLowerBound(minStrike); 99 s1d.setUpperBound(maxStrike); 100 Rate rStar = s1d.solve(finder, 1e-8, 0.05, minStrike, maxStrike); 101 102 Option::Type w = arguments_.type==VanillaSwap::Payer ? 103 Option::Put : Option::Call; 104 Size size = arguments_.fixedCoupons.size(); 105 106 Real value = 0.0; 107 Real B = model_->discountBond(maturity, valueTime, rStar); 108 for (Size i=0; i<size; i++) { 109 Real fixedPayTime = 110 dayCounter.yearFraction(referenceDate, 111 arguments_.fixedPayDates[i]); 112 Real strike = model_->discountBond(maturity, 113 fixedPayTime, 114 rStar) / B; 115 // Looks like the swaption decomposed into individual options adjusted for maturity. Each individual option is valued by Hull-White (or other one-factor model). 116 Real dboValue = model_->discountBondOption( 117 w, strike, maturity, valueTime, 118 fixedPayTime); 119 value += amounts[i]*dboValue; 120 } 121 results_.value = value; 122 } 123 124 } 125 126