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/gaussian1djamshidianswaptionengine.hpp>
22 #include <ql/math/solvers1d/brent.hpp>
23 
24 namespace QuantLib {
25 
26     class Gaussian1dJamshidianSwaptionEngine::rStarFinder {
27       public:
rStarFinder(const ext::shared_ptr<Gaussian1dModel> & model,Real nominal,const Date & maturityDate,const Date & valueDate,const std::vector<Date> & fixedPayDates,const std::vector<Real> & amounts,const Size startIndex)28         rStarFinder(const ext::shared_ptr<Gaussian1dModel> &model,
29                     Real nominal, const Date &maturityDate,
30                     const Date &valueDate,
31                     const std::vector<Date> &fixedPayDates,
32                     const std::vector<Real> &amounts, const Size startIndex)
33             : strike_(nominal), maturityDate_(maturityDate),
34               valueDate_(valueDate), startIndex_(startIndex),
35               times_(fixedPayDates), amounts_(amounts), model_(model) {}
36 
operator ()(Rate y) const37         Real operator()(Rate y) const {
38             Real value = strike_;
39             Size size = times_.size();
40             for (Size i = startIndex_; i < size; i++) {
41                 Real dbValue = model_->zerobond(times_[i], maturityDate_, y) /
42                                model_->zerobond(valueDate_, maturityDate_, y);
43                 value -= amounts_[i] * dbValue;
44             }
45             return value;
46         }
47 
48       private:
49         Real strike_;
50         Date maturityDate_, valueDate_;
51         Size startIndex_;
52         std::vector<Date> times_;
53         const std::vector<Real> &amounts_;
54         const ext::shared_ptr<Gaussian1dModel> &model_;
55     };
56 
calculate() const57     void Gaussian1dJamshidianSwaptionEngine::calculate() const {
58 
59         QL_REQUIRE(arguments_.settlementMethod != Settlement::ParYieldCurve,
60                    "cash settled (ParYieldCurve) swaptions not priced with "
61                    "Gaussian1dJamshidianSwaptionEngine");
62 
63         QL_REQUIRE(arguments_.exercise->type() == Exercise::European,
64                    "cannot use the Jamshidian decomposition "
65                    "on exotic swaptions");
66 
67         QL_REQUIRE(arguments_.swap->spread() == 0.0,
68                    "non zero spread (" << arguments_.swap->spread()
69                                        << ") not allowed"); // PC
70 
71         Date referenceDate;
72         DayCounter dayCounter;
73 
74         referenceDate = model_->termStructure()->referenceDate();
75         dayCounter = model_->termStructure()->dayCounter();
76 
77         std::vector<Real> amounts(arguments_.fixedCoupons);
78         amounts.back() += arguments_.nominal;
79 
80         Size startIndex = std::upper_bound(arguments_.fixedResetDates.begin(),
81                                            arguments_.fixedResetDates.end(),
82                                            arguments_.exercise->date(0) - 1) -
83                           arguments_.fixedResetDates.begin();
84         // only consider coupons with start date >= exercise dates
85 
86         rStarFinder finder(*model_, arguments_.nominal,
87                            arguments_.exercise->date(0),
88                            arguments_.fixedResetDates[startIndex],
89                            arguments_.fixedPayDates, amounts, startIndex);
90         Brent s1d;
91         Rate minStrike = -8.0;
92         Rate maxStrike = 8.0;
93         s1d.setMaxEvaluations(10000);
94         s1d.setLowerBound(minStrike);
95         s1d.setUpperBound(maxStrike);
96         Rate rStar = s1d.solve(finder, 1e-8, 0.00, minStrike,
97                                maxStrike); // this is actually yStar
98 
99         Option::Type w =
100             arguments_.type == VanillaSwap::Payer ? Option::Put : Option::Call;
101         Size size = arguments_.fixedCoupons.size();
102 
103         Real value = 0.0;
104         for (Size i = startIndex; i < size; i++) {
105             // Real fixedPayTime =
106             // dayCounter.yearFraction(referenceDate,arguments_.fixedPayDates[i]);
107             Real strike =
108                 model_->zerobond(arguments_.fixedPayDates[i],
109                                  arguments_.exercise->date(0), rStar) /
110                 model_->zerobond(arguments_.fixedResetDates[startIndex],
111                                  arguments_.exercise->date(0), rStar);
112             Real dboValue =
113                 model_->zerobondOption(w, arguments_.exercise->date(0),
114                                        arguments_.fixedResetDates[startIndex],
115                                        arguments_.fixedPayDates[i], strike);
116             value += amounts[i] * dboValue;
117         }
118         results_.value = value;
119     }
120 }
121