/src/quantlib/ql/pricingengines/inflation/inflationcapfloorengines.cpp
Line | Count | Source |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2009 Chris Kenyon |
5 | | |
6 | | This file is part of QuantLib, a free-software/open-source library |
7 | | for financial quantitative analysts and developers - http://quantlib.org/ |
8 | | |
9 | | QuantLib is free software: you can redistribute it and/or modify it |
10 | | under the terms of the QuantLib license. You should have received a |
11 | | copy of the license along with this program; if not, please email |
12 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
13 | | <https://www.quantlib.org/license.shtml>. |
14 | | |
15 | | This program is distributed in the hope that it will be useful, but WITHOUT |
16 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
17 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
18 | | */ |
19 | | |
20 | | |
21 | | #include <ql/pricingengines/blackformula.hpp> |
22 | | #include <ql/pricingengines/inflation/inflationcapfloorengines.hpp> |
23 | | #include <ql/termstructures/volatility/inflation/yoyinflationoptionletvolatilitystructure.hpp> |
24 | | #include <utility> |
25 | | |
26 | | namespace QuantLib { |
27 | | |
28 | | |
29 | | YoYInflationCapFloorEngine::YoYInflationCapFloorEngine( |
30 | | ext::shared_ptr<YoYInflationIndex> index, |
31 | | Handle<YoYOptionletVolatilitySurface> volatility, |
32 | | Handle<YieldTermStructure> nominalTermStructure) |
33 | 0 | : index_(std::move(index)), volatility_(std::move(volatility)), |
34 | 0 | nominalTermStructure_(std::move(nominalTermStructure)) { |
35 | 0 | registerWith(index_); |
36 | 0 | registerWith(volatility_); |
37 | 0 | registerWith(nominalTermStructure_); |
38 | 0 | } |
39 | | |
40 | | |
41 | | void YoYInflationCapFloorEngine::setVolatility( |
42 | 0 | const Handle<YoYOptionletVolatilitySurface> &v) { |
43 | 0 | if (!volatility_.empty()) |
44 | 0 | unregisterWith(volatility_); |
45 | 0 | volatility_ = v; |
46 | 0 | registerWith(volatility_); |
47 | 0 | update(); |
48 | 0 | } |
49 | | |
50 | | |
51 | 0 | void YoYInflationCapFloorEngine::calculate() const { |
52 | | |
53 | | // copy black version then adapt to others |
54 | |
|
55 | 0 | Real value = 0.0; |
56 | 0 | Size optionlets = arguments_.startDates.size(); |
57 | 0 | std::vector<Real> values(optionlets, 0.0); |
58 | 0 | std::vector<Real> stdDevs(optionlets, 0.0); |
59 | 0 | std::vector<Real> forwards(optionlets, 0.0); |
60 | 0 | YoYInflationCapFloor::Type type = arguments_.type; |
61 | |
|
62 | 0 | auto yoyTS = index()->yoyInflationTermStructure(); |
63 | |
|
64 | 0 | Date settlement = nominalTermStructure_->referenceDate(); |
65 | |
|
66 | 0 | for (Size i=0; i<optionlets; ++i) { |
67 | 0 | Date paymentDate = arguments_.payDates[i]; |
68 | 0 | if (paymentDate > settlement) { // discard expired caplets |
69 | 0 | DiscountFactor d = arguments_.nominals[i] * |
70 | 0 | arguments_.gearings[i] * |
71 | 0 | nominalTermStructure_->discount(paymentDate) * |
72 | 0 | arguments_.accrualTimes[i]; |
73 | | |
74 | | // We explicitly have the index and assume that |
75 | | // the fixing is natural, i.e. no convexity adjustment. |
76 | | // If that was required then we would also need |
77 | | // nominal vols in the pricing engine, i.e. a different engine. |
78 | | // This also means that we do not need the coupon to have |
79 | | // a pricing engine to return the swaplet rate and then |
80 | | // the adjusted fixing in the instrument. |
81 | 0 | forwards[i] = yoyTS->yoyRate(arguments_.fixingDates[i],Period(0,Days)); |
82 | 0 | Rate forward = forwards[i]; |
83 | |
|
84 | 0 | Date fixingDate = arguments_.fixingDates[i]; |
85 | 0 | Time sqrtTime = 0.0; |
86 | 0 | if (fixingDate > volatility_->baseDate()){ |
87 | 0 | sqrtTime = std::sqrt( |
88 | 0 | volatility_->timeFromBase(fixingDate)); |
89 | 0 | } |
90 | |
|
91 | 0 | if (type == YoYInflationCapFloor::Cap || type == YoYInflationCapFloor::Collar) { |
92 | 0 | Rate strike = arguments_.capRates[i]; |
93 | 0 | if (sqrtTime>0.0) { |
94 | 0 | stdDevs[i] = std::sqrt( |
95 | 0 | volatility_->totalVariance(fixingDate, strike, Period(0,Days))); |
96 | |
|
97 | 0 | } |
98 | | |
99 | | // sttDev=0 for already-fixed dates so everything on forward |
100 | 0 | values[i] = optionletImpl(Option::Call, strike, |
101 | 0 | forward, stdDevs[i], d); |
102 | 0 | } |
103 | 0 | if (type == YoYInflationCapFloor::Floor || type == YoYInflationCapFloor::Collar) { |
104 | 0 | Rate strike = arguments_.floorRates[i]; |
105 | 0 | if (sqrtTime>0.0) { |
106 | 0 | stdDevs[i] = std::sqrt( |
107 | 0 | volatility_->totalVariance(fixingDate, strike, Period(0,Days))); |
108 | 0 | } |
109 | 0 | Real floorlet = optionletImpl(Option::Put, strike, |
110 | 0 | forward, stdDevs[i], d); |
111 | 0 | if (type == YoYInflationCapFloor::Floor) { |
112 | 0 | values[i] = floorlet; |
113 | 0 | } else { |
114 | | // a collar is long a cap and short a floor |
115 | 0 | values[i] -= floorlet; |
116 | 0 | } |
117 | |
|
118 | 0 | } |
119 | 0 | value += values[i]; |
120 | 0 | } |
121 | 0 | } |
122 | 0 | results_.value = value; |
123 | |
|
124 | 0 | results_.additionalResults["optionletsPrice"] = values; |
125 | 0 | results_.additionalResults["optionletsAtmForward"] = forwards; |
126 | 0 | if (type != YoYInflationCapFloor::Collar) |
127 | 0 | results_.additionalResults["optionletsStdDev"] = stdDevs; |
128 | 0 | } |
129 | | |
130 | | |
131 | | //====================================================================== |
132 | | // pricer implementations |
133 | | //====================================================================== |
134 | | |
135 | | YoYInflationBlackCapFloorEngine::YoYInflationBlackCapFloorEngine( |
136 | | const ext::shared_ptr<YoYInflationIndex>& index, |
137 | | const Handle<YoYOptionletVolatilitySurface>& volatility, |
138 | | const Handle<YieldTermStructure>& nominalTermStructure) |
139 | 0 | : YoYInflationCapFloorEngine(index, volatility, nominalTermStructure) {} |
140 | | |
141 | | |
142 | | Real YoYInflationBlackCapFloorEngine::optionletImpl(Option::Type type, Rate strike, |
143 | | Rate forward, Real stdDev, |
144 | | Real d) const |
145 | 0 | { |
146 | 0 | return blackFormula(type, strike, |
147 | 0 | forward, stdDev, d); |
148 | 0 | } |
149 | | |
150 | | |
151 | | |
152 | | YoYInflationUnitDisplacedBlackCapFloorEngine |
153 | | ::YoYInflationUnitDisplacedBlackCapFloorEngine( |
154 | | const ext::shared_ptr<YoYInflationIndex>& index, |
155 | | const Handle<YoYOptionletVolatilitySurface>& volatility, |
156 | | const Handle<YieldTermStructure>& nominalTermStructure) |
157 | 0 | : YoYInflationCapFloorEngine(index, volatility, nominalTermStructure) {} |
158 | | |
159 | | |
160 | | Real YoYInflationUnitDisplacedBlackCapFloorEngine::optionletImpl( |
161 | | Option::Type type, Rate strike, |
162 | | Rate forward, Real stdDev, |
163 | | Real d) const |
164 | 0 | { |
165 | | // could use displacement parameter in blackFormula but this is clearer |
166 | 0 | return blackFormula(type, strike+1.0, |
167 | 0 | forward+1.0, stdDev, d); |
168 | 0 | } |
169 | | |
170 | | |
171 | | YoYInflationBachelierCapFloorEngine::YoYInflationBachelierCapFloorEngine( |
172 | | const ext::shared_ptr<YoYInflationIndex>& index, |
173 | | const Handle<YoYOptionletVolatilitySurface>& volatility, |
174 | | const Handle<YieldTermStructure>& nominalTermStructure) |
175 | 0 | : YoYInflationCapFloorEngine(index, volatility, nominalTermStructure) {} |
176 | | |
177 | | |
178 | | Real YoYInflationBachelierCapFloorEngine::optionletImpl(Option::Type type, Rate strike, |
179 | | Rate forward, Real stdDev, |
180 | | Real d) const |
181 | 0 | { |
182 | 0 | return bachelierBlackFormula(type, strike, |
183 | 0 | forward, stdDev, d); |
184 | 0 | } |
185 | | |
186 | | } |
187 | | |