QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
markovfunctional.hpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2013, 2018 Peter Caspers
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 <http://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
24#ifndef quantlib_markovfunctional_hpp
25#define quantlib_markovfunctional_hpp
26
27#include <ql/math/interpolation.hpp>
28#include <ql/models/shortrate/onefactormodels/gaussian1dmodel.hpp>
29#include <ql/processes/mfstateprocess.hpp>
30#include <ql/termstructures/volatility/optionlet/optionletvolatilitystructure.hpp>
31#include <ql/termstructures/volatility/smilesection.hpp>
32#include <ql/termstructures/volatility/swaption/swaptionvolstructure.hpp>
33#include <utility>
34
35namespace QuantLib {
36
100
101 public:
102
104 public:
105 virtual Real inverseDigitalCall(Real price, Real discount = 1.0) const = 0;
106 };
107
109 public:
110 virtual ~CustomSmileFactory() = default;
111 virtual ext::shared_ptr<CustomSmileSection>
112 smileSection(const ext::shared_ptr<SmileSection>& source, Real atm) const = 0;
113 };
114
116
117 // NoPayoffExtrapolation overrides ExtrapolatePayoffFlat
121 AdjustYts = 1 << 1,
124 KahaleSmile = 1 << 4,
128 SabrSmile = 1 << 8,
129 CustomSmile = 1 << 9
130 };
131
133
134 ModelSettings(Size yGridPoints,
135 Real yStdDevs,
136 Size gaussHermitePoints,
137 Real digitalGap,
138 Real marketRateAccuracy,
139 Real lowerRateBound,
140 Real upperRateBound,
141 int adjustments,
142 std::vector<Real> smileMoneyCheckpoints = std::vector<Real>(),
143 ext::shared_ptr<CustomSmileFactory> customSmileFactory =
144 ext::shared_ptr<CustomSmileFactory>())
145 : yGridPoints_(yGridPoints), yStdDevs_(yStdDevs),
146 gaussHermitePoints_(gaussHermitePoints), digitalGap_(digitalGap),
147 marketRateAccuracy_(marketRateAccuracy), lowerRateBound_(lowerRateBound),
148 upperRateBound_(upperRateBound), adjustments_(adjustments),
149 smileMoneynessCheckpoints_(std::move(smileMoneyCheckpoints)),
150 customSmileFactory_(std::move(customSmileFactory)) {}
151
152 void validate() {
153
156
157 if ((adjustments_ & KahaleSmile) != 0 &&
160 }
161
162 QL_REQUIRE((adjustments_ & SabrSmile) == 0 ||
163 (adjustments_ & KahaleSmile) == 0 ||
165 ,
166 "Only one of KahaleSmile, SabrSmile and CustomSmile"
167 "can be specified at the same time");
168 QL_REQUIRE(yGridPoints_ > 0, "At least one grid point ("
169 << yGridPoints_
170 << ") for the state process "
171 "discretization must be "
172 "given");
173 QL_REQUIRE(yStdDevs_ > 0.0,
174 "Multiple of standard deviations covered by state "
175 "process discretization ("
176 << yStdDevs_ << ") must be positive");
177 QL_REQUIRE(gaussHermitePoints_ > 0,
178 "Number of gauss hermite integration points ("
179 << gaussHermitePoints_ << ") must be positive");
180 QL_REQUIRE(digitalGap_ > 0.0, "Digital gap ("
181 << digitalGap_
182 << ") must be positive");
183 QL_REQUIRE(marketRateAccuracy_ > 0.0,
184 "Market rate accuracy (" << marketRateAccuracy_
185 << ") must be positive");
186 QL_REQUIRE(
187 (adjustments_ & KahaleSmile) == 0 || lowerRateBound_ == 0.0,
188 "If Kahale extrapolation is used, the lower rate bound ("
189 << lowerRateBound_ << ") must be zero.");
190 QL_REQUIRE(
192 "Lower rate bound ("
194 << ") must be strictly less than upper rate bound ("
195 << upperRateBound_ << ")");
196 QL_REQUIRE(((adjustments_ & CustomSmile) == 0) ||
198 "missing CustomSmileFactoy");
199 }
200
202 yGridPoints_ = n;
203 return *this;
204 }
206 yStdDevs_ = s;
207 return *this;
208 }
211 return *this;
212 }
214 digitalGap_ = d;
215 return *this;
216 }
219 return *this;
220 }
222 upperRateBound_ = u;
223 return *this;
224 }
226 lowerRateBound_ = l;
227 return *this;
228 }
230 adjustments_ = a;
231 return *this;
232 }
234 adjustments_ |= a;
235 return *this;
236 }
238 adjustments_ &= ~a;
239 return *this;
240 }
241 ModelSettings &withSmileMoneynessCheckpoints(const std::vector<Real>& m) {
243 return *this;
244 }
245 ModelSettings &withCustomSmileFactory(const ext::shared_ptr<CustomSmileFactory>& f) {
247 return *this;
248 }
249
256 std::vector<Real> smileMoneynessCheckpoints_;
257 ext::shared_ptr<CustomSmileFactory> customSmileFactory_;
258 };
259
263 std::vector<Date> paymentDates_;
264 std::vector<Real> yearFractions_;
267 ext::shared_ptr<SmileSection> smileSection_;
268 ext::shared_ptr<SmileSection> rawSmileSection_;
271 };
272
273// utility macro to write messages to the model outputs
274
275#define QL_MFMESSAGE(o, message) \
276 { \
277 std::ostringstream os; \
278 os << message; \
279 o.messages_.push_back(os.str()); \
280 }
281
283 bool dirty_;
285 std::vector<Date> expiries_;
286 std::vector<Period> tenors_;
287 std::vector<Real> atm_;
288 std::vector<Real> annuity_;
289 std::vector<Real> adjustmentFactors_;
290 std::vector<Real> digitalsAdjustmentFactors_;
291 std::vector<std::string> messages_;
292 std::vector<std::vector<Real> > smileStrikes_;
293 std::vector<std::vector<Real> > marketRawCallPremium_;
294 std::vector<std::vector<Real> > marketRawPutPremium_;
295 std::vector<std::vector<Real> > marketCallPremium_;
296 std::vector<std::vector<Real> > marketPutPremium_;
297 std::vector<std::vector<Real> > modelCallPremium_;
298 std::vector<std::vector<Real> > modelPutPremium_;
299 std::vector<std::vector<Real> > marketVega_;
300 std::vector<Real> marketZerorate_;
301 std::vector<Real> modelZerorate_;
302 };
303
304 // Constructor for a swaption smile calibrated model
306 Real reversion,
307 std::vector<Date> volstepdates,
308 std::vector<Real> volatilities,
309 const Handle<SwaptionVolatilityStructure>& swaptionVol,
310 const std::vector<Date>& swaptionExpiries,
311 const std::vector<Period>& swaptionTenors,
312 const ext::shared_ptr<SwapIndex>& swapIndexBase,
314
315 // Constructor for a caplet smile calibrated model
317 Real reversion,
318 std::vector<Date> volstepdates,
319 std::vector<Real> volatilities,
321 const std::vector<Date>& capletExpiries,
322 ext::shared_ptr<IborIndex> iborIndex,
324
325 const ModelSettings &modelSettings() const { return modelSettings_; }
326 const ModelOutputs &modelOutputs() const;
327
328 const Date &numeraireDate() const { return numeraireDate_; }
329 const Time &numeraireTime() const { return numeraireTime_; }
330
331 const Array &volatility() const { return sigma_.params(); }
332
333 void calibrate(const std::vector<ext::shared_ptr<CalibrationHelper> >& helpers,
334 OptimizationMethod& method,
337 const std::vector<Real>& weights = std::vector<Real>(),
338 const std::vector<bool>& fixParameters = std::vector<bool>()) override {
339
340 CalibratedModel::calibrate(helpers, method, endCriteria, constraint, weights,
341 fixParameters.empty() ? FixedFirstVolatility() :
342 fixParameters);
343 }
344
345 void calibrate(const std::vector<ext::shared_ptr<BlackCalibrationHelper> >& helpers,
346 OptimizationMethod& method,
349 const std::vector<Real>& weights = std::vector<Real>(),
350 const std::vector<bool>& fixParameters = std::vector<bool>()) {
351
352 std::vector<ext::shared_ptr<CalibrationHelper> > tmp(helpers.size());
353 for (Size i=0; i<helpers.size(); ++i)
354 tmp[i] = ext::static_pointer_cast<CalibrationHelper>(helpers[i]);
355
356 calibrate(tmp, method, endCriteria, constraint, weights, fixParameters);
357 }
358
359 void update() override { LazyObject::update(); }
360
361 // returns the indices of the af region from the last smile update
362 std::vector<std::pair<Size, Size> > arbitrageIndices() const {
363 calculate();
364 return arbitrageIndices_;
365 }
366
367 // forces the indices of the af region (useful for sensitivity calculation)
368 // if an empty vector is given, the dynamic calculation is used again
369 void forceArbitrageIndices(const std::vector<std::pair<Size,Size> >& indices) {
370 forcedArbitrageIndices_ = indices;
371 this->update();
372 }
373
374 protected:
375 Real numeraireImpl(Time t, Real y, const Handle<YieldTermStructure>& yts) const override;
376
377 Real
378 zerobondImpl(Time T, Time t, Real y, const Handle<YieldTermStructure>& yts) const override;
379
380 void generateArguments() override {
381 // if calculate triggers performCalculations, updateNumeraireTabulations
382 // is called twice. If we can not check the lazy object status this seem
383 // hard to avoid though.
384 calculate();
387 }
388
389 void performCalculations() const override {
391 updateTimes();
392 updateSmiles();
394 }
395
396 std::vector<bool> FixedFirstVolatility() const {
397 std::vector<bool> c(volatilities_.size(), false);
398 c[0] = true;
399 return c;
400 }
401
402 private:
403
404 void initialize();
405 void updateTimes() const;
406 void updateTimes1() const;
407 void updateTimes2() const;
408
409 void updateSmiles() const;
410 void updateNumeraireTabulation() const;
411
412 void makeSwaptionCalibrationPoint(const Date &expiry,
413 const Period &tenor);
414 void makeCapletCalibrationPoint(const Date &expiry);
415
416 Real marketSwapRate(const Date& expiry,
417 const CalibrationPoint& p,
418 Real digitalPrice,
419 Real guess = 0.03,
420 Real shift = 0.0) const;
421 Real marketDigitalPrice(const Date& expiry,
422 const CalibrationPoint& p,
423 const Option::Type& type,
424 Real strike) const;
425
426 Array deflatedZerobondArray(Time T, Time t, const Array& y) const;
427 Array numeraireArray(Time t, const Array& y) const;
428 Array zerobondArray(Time T, Time t, const Array& y) const;
429
430 Real deflatedZerobond(Time T, Time t = 0.0, Real y = 0.0) const;
431
432 // the following methods (tagged internal) are indended only to produce
433 // the volatility diagnostics in the model outputs
434 // due to the special convention of the instruments used for numeraire
435 // calibration there is on direct way to use the usual pricing engines
436 // for this purpose
437
439 const Date& fixing,
440 const Date& referenceDate = Null<Date>(),
441 Real y = 0.0,
442 bool zeroFixingDays = false,
443 ext::shared_ptr<IborIndex> iborIdx = ext::shared_ptr<IborIndex>()) const;
444
445 Real
446 swapRateInternal(const Date& fixing,
447 const Period& tenor,
448 const Date& referenceDate = Null<Date>(),
449 Real y = 0.0,
450 bool zeroFixingDays = false,
451 ext::shared_ptr<SwapIndex> swapIdx = ext::shared_ptr<SwapIndex>()) const;
452
454 const Date& fixing,
455 const Period& tenor,
456 const Date& referenceDate = Null<Date>(),
457 Real y = 0.0,
458 bool zeroFixingDays = false,
459 ext::shared_ptr<SwapIndex> swapIdx = ext::shared_ptr<SwapIndex>()) const;
460
462 const Option::Type& type,
463 const Date& expiry,
464 Rate strike,
465 const Date& referenceDate = Null<Date>(),
466 Real y = 0.0,
467 bool zeroFixingDays = false,
468 ext::shared_ptr<IborIndex> iborIdx = ext::shared_ptr<IborIndex>()) const;
469
471 const Option::Type& type,
472 const Date& expiry,
473 const Period& tenor,
474 Rate strike,
475 const Date& referenceDate = Null<Date>(),
476 Real y = 0.0,
477 bool zeroFixingDays = false,
478 const ext::shared_ptr<SwapIndex>& swapIdx = ext::shared_ptr<SwapIndex>()) const;
479
481 public:
482 ZeroHelper(const MarkovFunctional *model, const Date &expiry,
483 const CalibrationPoint &p, const Real marketPrice)
484 : model_(model), marketPrice_(marketPrice), expiry_(expiry),
485 p_(p) {}
486 Real operator()(Real strike) const {
487 Real modelPrice = model_->marketDigitalPrice(
488 expiry_, p_, Option::Call, strike);
489 return modelPrice - marketPrice_;
490 };
493 const Date &expiry_;
495 };
496
499
501
502 ext::shared_ptr<Matrix> discreteNumeraire_;
503 // vector of interpolated numeraires in y direction for all calibration
504 // times
505 std::vector<ext::shared_ptr<Interpolation> > numeraire_;
506
509
510 std::vector<Date> volstepdates_;
511 mutable std::vector<Time> volsteptimes_;
512 mutable Array volsteptimesArray_; // FIXME this is redundant (just a copy of
513 // volsteptimes_)
514 std::vector<Real> volatilities_;
515
518
521
523 std::vector<Period> swaptionTenors_;
524 ext::shared_ptr<SwapIndex> swapIndexBase_;
525 ext::shared_ptr<IborIndex> iborIndex_;
526
527 mutable std::map<Date, CalibrationPoint> calibrationPoints_;
528 mutable std::vector<Real> times_;
530
533
534 mutable std::vector<std::pair<Size,Size> > arbitrageIndices_;
535 std::vector<std::pair<Size,Size> > forcedArbitrageIndices_;
536 };
537
538 std::ostream &operator<<(std::ostream &out,
540}
541
542#endif
1-D array used in linear algebra.
Definition: array.hpp:52
Calibrated model class.
Definition: model.hpp:86
EndCriteria::Type endCriteria() const
Returns end criteria result.
Definition: model.hpp:113
const ext::shared_ptr< Constraint > & constraint() const
Definition: model.hpp:160
virtual void calibrate(const std::vector< ext::shared_ptr< CalibrationHelper > > &, OptimizationMethod &method, const EndCriteria &endCriteria, const Constraint &constraint=Constraint(), const std::vector< Real > &weights=std::vector< Real >(), const std::vector< bool > &fixParameters=std::vector< bool >())
Calibrate to a set of market instruments (usually caps/swaptions)
Definition: model.cpp:75
Base constraint class.
Definition: constraint.hpp:35
Concrete date class.
Definition: date.hpp:125
Criteria to end optimization process:
Definition: endcriteria.hpp:40
void performCalculations() const override
Shared handle to an observable.
Definition: handle.hpp:41
virtual void calculate() const
Definition: lazyobject.hpp:253
void update() override
Definition: lazyobject.hpp:188
virtual ext::shared_ptr< CustomSmileSection > smileSection(const ext::shared_ptr< SmileSection > &source, Real atm) const =0
virtual Real inverseDigitalCall(Real price, Real discount=1.0) const =0
ZeroHelper(const MarkovFunctional *model, const Date &expiry, const CalibrationPoint &p, const Real marketPrice)
std::vector< Date > volstepdates_
Real zerobondImpl(Time T, Time t, Real y, const Handle< YieldTermStructure > &yts) const override
void calibrate(const std::vector< ext::shared_ptr< BlackCalibrationHelper > > &helpers, OptimizationMethod &method, const EndCriteria &endCriteria, const Constraint &constraint=Constraint(), const std::vector< Real > &weights=std::vector< Real >(), const std::vector< bool > &fixParameters=std::vector< bool >())
void performCalculations() const override
std::vector< std::pair< Size, Size > > arbitrageIndices() const
Array zerobondArray(Time T, Time t, const Array &y) const
const ModelOutputs & modelOutputs() const
Handle< SwaptionVolatilityStructure > swaptionVol_
void forceArbitrageIndices(const std::vector< std::pair< Size, Size > > &indices)
ext::shared_ptr< SwapIndex > swapIndexBase_
Real swapRateInternal(const Date &fixing, const Period &tenor, const Date &referenceDate=Null< Date >(), Real y=0.0, bool zeroFixingDays=false, ext::shared_ptr< SwapIndex > swapIdx=ext::shared_ptr< SwapIndex >()) const
std::vector< std::pair< Size, Size > > forcedArbitrageIndices_
Real swapAnnuityInternal(const Date &fixing, const Period &tenor, const Date &referenceDate=Null< Date >(), Real y=0.0, bool zeroFixingDays=false, ext::shared_ptr< SwapIndex > swapIdx=ext::shared_ptr< SwapIndex >()) const
Handle< OptionletVolatilityStructure > capletVol_
Array deflatedZerobondArray(Time T, Time t, const Array &y) const
std::map< Date, CalibrationPoint > calibrationPoints_
ext::shared_ptr< IborIndex > iborIndex_
ext::shared_ptr< Matrix > discreteNumeraire_
Real marketDigitalPrice(const Date &expiry, const CalibrationPoint &p, const Option::Type &type, Real strike) const
const Array & volatility() const
const Date & numeraireDate() const
Real swaptionPriceInternal(const Option::Type &type, const Date &expiry, const Period &tenor, Rate strike, const Date &referenceDate=Null< Date >(), Real y=0.0, bool zeroFixingDays=false, const ext::shared_ptr< SwapIndex > &swapIdx=ext::shared_ptr< SwapIndex >()) const
Real deflatedZerobond(Time T, Time t=0.0, Real y=0.0) const
void makeCapletCalibrationPoint(const Date &expiry)
std::vector< Period > swaptionTenors_
std::vector< Date > swaptionExpiries_
std::vector< ext::shared_ptr< Interpolation > > numeraire_
std::vector< Date > capletExpiries_
std::vector< Real > volatilities_
std::vector< std::pair< Size, Size > > arbitrageIndices_
std::vector< bool > FixedFirstVolatility() const
Array numeraireArray(Time t, const Array &y) const
void makeSwaptionCalibrationPoint(const Date &expiry, const Period &tenor)
const ModelSettings & modelSettings() const
Real marketSwapRate(const Date &expiry, const CalibrationPoint &p, Real digitalPrice, Real guess=0.03, Real shift=0.0) const
Real forwardRateInternal(const Date &fixing, const Date &referenceDate=Null< Date >(), Real y=0.0, bool zeroFixingDays=false, ext::shared_ptr< IborIndex > iborIdx=ext::shared_ptr< IborIndex >()) const
std::vector< Time > volsteptimes_
Real capletPriceInternal(const Option::Type &type, const Date &expiry, Rate strike, const Date &referenceDate=Null< Date >(), Real y=0.0, bool zeroFixingDays=false, ext::shared_ptr< IborIndex > iborIdx=ext::shared_ptr< IborIndex >()) const
Real numeraireImpl(Time t, Real y, const Handle< YieldTermStructure > &yts) const override
const Time & numeraireTime() const
void calibrate(const std::vector< ext::shared_ptr< CalibrationHelper > > &helpers, OptimizationMethod &method, const EndCriteria &endCriteria, const Constraint &constraint=Constraint(), const std::vector< Real > &weights=std::vector< Real >(), const std::vector< bool > &fixParameters=std::vector< bool >()) override
Calibrate to a set of market instruments (usually caps/swaptions)
template class providing a null value for a given type.
Definition: null.hpp:76
Abstract class for constrained optimization method.
Definition: method.hpp:36
Base class for model arguments.
Definition: parameter.hpp:38
const Array & params() const
Definition: parameter.hpp:50
interest rate volatility smile section
const Handle< YieldTermStructure > & termStructure() const
Definition: model.hpp:77
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
Real Rate
interest rates
Definition: types.hpp:70
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
std::ostream & operator<<(std::ostream &out, GFunctionFactory::YieldCurveModel type)
STL namespace.
ext::shared_ptr< SmileSection > smileSection_
ext::shared_ptr< SmileSection > rawSmileSection_
std::vector< std::vector< Real > > modelPutPremium_
std::vector< std::vector< Real > > marketPutPremium_
std::vector< std::vector< Real > > smileStrikes_
std::vector< std::vector< Real > > modelCallPremium_
std::vector< std::vector< Real > > marketVega_
std::vector< std::vector< Real > > marketCallPremium_
std::vector< std::vector< Real > > marketRawCallPremium_
std::vector< std::vector< Real > > marketRawPutPremium_
ModelSettings & withCustomSmileFactory(const ext::shared_ptr< CustomSmileFactory > &f)
ModelSettings(Size yGridPoints, Real yStdDevs, Size gaussHermitePoints, Real digitalGap, Real marketRateAccuracy, Real lowerRateBound, Real upperRateBound, int adjustments, std::vector< Real > smileMoneyCheckpoints=std::vector< Real >(), ext::shared_ptr< CustomSmileFactory > customSmileFactory=ext::shared_ptr< CustomSmileFactory >())
ext::shared_ptr< CustomSmileFactory > customSmileFactory_
ModelSettings & withSmileMoneynessCheckpoints(const std::vector< Real > &m)