QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
kahalesmilesection.hpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2013 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
20/*! \file kahalesmilesection.hpp
21 \brief Arbitrage free smile section using a C^1 inter- and extrapolation
22 method proposed by Kahale, see
23 http://www.risk.net/data/Pay_per_view/risk/technical/2004/0504_tech_option2.pdf
24 Exponential extrapolation for high strikes can be used alternatively to avoid
25 a too slowly decreasing call price function. Note that in the leftmost
26 interval and right from the last grid point the input smile is always
27 replaced by the extrapolating functional forms, so if you are sure that the
28 input smile is globally arbitrage free and you do not want to change it in
29 these strike regions you should not use this class at all.
30 Input smile sections with a shift are handled accordingly, normal input
31 smile section are not possible though.
32*/
33
34#ifndef quantlib_kahale_smile_section_hpp
35#define quantlib_kahale_smile_section_hpp
36
41#include <boost/math/distributions/normal.hpp>
42#include <vector>
43#include <utility>
44
45// numerical constants, still experimental
46#define QL_KAHALE_FMAX QL_MAX_REAL
47#define QL_KAHALE_SMAX 5.0
48#define QL_KAHALE_ACC 1E-12
49#define QL_KAHALE_EPS QL_EPSILON
50
51namespace QuantLib {
52
54
55 public:
56 struct cFunction {
57 // this is just a helper class where we do not want virtual
58 // functions
60 : f_(f), s_(s), a_(a), b_(b), exponential_(false) {}
61 cFunction(Real a, Real b) : a_(a), b_(b), exponential_(true) {}
62 Real operator()(Real k) const {
63 if (exponential_)
64 return std::exp(-a_ * k + b_);
65 if (s_ < QL_EPSILON)
66 return std::max(f_ - k, 0.0) + a_ * k + b_;
67 boost::math::normal_distribution<Real> normal;
68 Real d1 = std::log(f_ / k) / s_ + s_ / 2.0;
69 Real d2 = d1 - s_;
70 return f_ * boost::math::cdf(normal, d1) -
71 k * boost::math::cdf(normal, d2) + a_ * k + b_;
72 }
74 const bool exponential_;
75 };
76
77 struct aHelper {
78 aHelper(Real k0, Real k1, Real c0, Real c1, Real c0p, Real c1p)
79 : k0_(k0), k1_(k1), c0_(c0), c1_(c1), c0p_(c0p), c1p_(c1p) {}
80 Real operator()(Real a) const {
81 boost::math::normal_distribution<Real> normal;
82 Real d20 = boost::math::quantile(normal, -c0p_ + a);
83 Real d21 = boost::math::quantile(normal, -c1p_ + a);
84 Real alpha = (d20 - d21) / (std::log(k0_) - std::log(k1_));
85 Real beta = d20 - alpha * std::log(k0_);
86 s_ = -1.0 / alpha;
87 f_ = std::exp(s_ * (beta + s_ / 2.0));
88 QL_REQUIRE(f_ < QL_KAHALE_FMAX, "dummy"); // this is caught
89 cFunction cTmp(f_, s_, a, 0.0);
90 b_ = c0_ - cTmp(k0_);
91 cFunction c(f_, s_, a, b_);
92 return c(k1_) - c1_;
93 }
95 mutable Real s_, f_, b_;
96 };
97
98 struct sHelper {
99 sHelper(Real k0, Real c0, Real c0p) : k0_(k0), c0_(c0), c0p_(c0p) {}
101 s = std::max(s, 0.0);
102 boost::math::normal_distribution<Real> normal;
103 Real d20 = boost::math::quantile(normal, -c0p_);
104 f_ = k0_ * std::exp(s * d20 + s * s / 2.0);
105 QL_REQUIRE(f_ < QL_KAHALE_FMAX, "dummy"); // this is caught
106 cFunction c(f_, s, 0.0, 0.0);
107 return c(k0_) - c0_;
108 }
110 mutable Real f_;
111 };
112
113 struct sHelper1 {
114 sHelper1(Real k1, Real c0, Real c1, Real c1p)
115 : k1_(k1), c0_(c0), c1_(c1), c1p_(c1p) {}
117 s = std::max(s, 0.0);
118 boost::math::normal_distribution<Real> normal;
119 Real d21 = boost::math::quantile(normal, -c1p_);
120 f_ = k1_ * std::exp(s * d21 + s * s / 2.0);
121 QL_REQUIRE(f_ < QL_KAHALE_FMAX, "dummy"); // this is caught
122 b_ = c0_ - f_;
123 cFunction c(f_, s, 0.0, b_);
124 return c(k1_) - c1_;
125 }
127 mutable Real f_, b_;
128 };
129
130 KahaleSmileSection(const ext::shared_ptr<SmileSection>& source,
131 Real atm = Null<Real>(),
132 bool interpolate = false,
133 bool exponentialExtrapolation = false,
134 bool deleteArbitragePoints = false,
135 const std::vector<Real>& moneynessGrid = std::vector<Real>(),
136 Real gap = 1.0E-5,
137 int forcedLeftIndex = -1,
138 int forcedRightIndex = QL_MAX_INTEGER);
139
140 Real minStrike() const override { return -shift(); }
141 Real maxStrike() const override { return QL_MAX_REAL; }
142 Real atmLevel() const override { return f_; }
143 const Date& exerciseDate() const override { return source_->exerciseDate(); }
144 Time exerciseTime() const override { return source_->exerciseTime(); }
145 const DayCounter& dayCounter() const override { return source_->dayCounter(); }
146 const Date& referenceDate() const override { return source_->referenceDate(); }
147 VolatilityType volatilityType() const override { return source_->volatilityType(); }
148 Real shift() const override { return source_->shift(); }
149
150 Real leftCoreStrike() const { return k_[leftIndex_]; }
151 Real rightCoreStrike() const { return k_[rightIndex_]; }
152
153 std::pair<Size, Size> coreIndices() const {
154 return std::make_pair(leftIndex_, rightIndex_);
155 }
156
157 Real optionPrice(Rate strike,
159 Real discount = 1.0) const override;
160
161 protected:
162 Volatility volatilityImpl(Rate strike) const override;
163
164 private:
165 Size index(Rate strike) const;
166 void compute();
167 ext::shared_ptr<SmileSection> source_;
168 std::vector<Real> moneynessGrid_, k_, c_;
170 const Real gap_;
172 std::vector<ext::shared_ptr<cFunction> > cFunctions_;
175 ext::shared_ptr<SmileSectionUtils> ssutils_;
176 };
177}
178
179#endif
Black formula.
Brent 1-D solver.
Concrete date class.
Definition: date.hpp:125
day counter class
Definition: daycounter.hpp:44
Time exerciseTime() const override
std::pair< Size, Size > coreIndices() const
const Date & exerciseDate() const override
const Date & referenceDate() const override
std::vector< ext::shared_ptr< cFunction > > cFunctions_
VolatilityType volatilityType() const override
ext::shared_ptr< SmileSectionUtils > ssutils_
ext::shared_ptr< SmileSection > source_
Size index(Rate strike) const
const DayCounter & dayCounter() const override
Real optionPrice(Rate strike, Option::Type type=Option::Call, Real discount=1.0) const override
Volatility volatilityImpl(Rate strike) const override
template class providing a null value for a given type.
Definition: null.hpp:76
interest rate volatility smile section
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
ext::function< Real(Real)> b
#define QL_MAX_REAL
Definition: qldefines.hpp:176
#define QL_EPSILON
Definition: qldefines.hpp:178
#define QL_MAX_INTEGER
Definition: qldefines.hpp:174
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
Real Volatility
volatility
Definition: types.hpp:78
Real Rate
interest rates
Definition: types.hpp:70
std::size_t Size
size of a container
Definition: types.hpp:58
#define QL_KAHALE_FMAX
Definition: any.hpp:35
Real beta
Definition: sabr.cpp:200
Real alpha
Definition: sabr.cpp:200
Smile section base class.
Additional utilities for smile sections.
aHelper(Real k0, Real k1, Real c0, Real c1, Real c0p, Real c1p)
cFunction(Real f, Real s, Real a, Real b)
sHelper1(Real k1, Real c0, Real c1, Real c1p)