QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
Loading...
Searching...
No Matches
fdndimblackscholesvanillaengine.cpp
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) 2024 Klaus Spanderen
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#include <ql/exercise.hpp>
33#include <boost/preprocessor/iteration/local.hpp>
34#include <utility>
35
36namespace QuantLib {
37
38 namespace detail {
39 class FdmPCABasketInnerValue: public FdmInnerValueCalculator {
40 public:
41 FdmPCABasketInnerValue(
42 ext::shared_ptr<BasketPayoff> payoff,
43 ext::shared_ptr<FdmMesher> mesher,
44 Array logS0, const Array& vols,
45 std::vector<ext::shared_ptr<YieldTermStructure>> qTS,
46 ext::shared_ptr<YieldTermStructure> rTS,
47 Matrix Q, Array l)
48 : n_(logS0.size()),
49 payoff_(std::move(payoff)),
50 mesher_(std::move(mesher)),
51 logS0_(std::move(logS0)), v_(vols*vols),
52 qTS_(std::move(qTS)),
53 rTS_(std::move(rTS)),
54 Q_(std::move(Q)), l_(std::move(l)),
55 cachedT_(Null<Real>()),
56 qf_(n_) { }
57
58 Real innerValue(const FdmLinearOpIterator& iter, Time t) override {
59 if (!close_enough(t, cachedT_)) {
60 rf_ = rTS_->discount(t);
61 for (Size i=0; i < n_; ++i)
62 qf_[i] = qTS_[i]->discount(t);
63 }
64 Array x(n_);
65 for (Size i=0; i < n_; ++i)
66 x[i] = mesher_->location(iter, i);
67
68 const Array S = Exp(Q_*x - 0.5*v_*t + logS0_)*qf_/rf_;
69
70 return (*payoff_)(S);
71 }
72 Real avgInnerValue(const FdmLinearOpIterator& iter, Time t) override {
73 return innerValue(iter, t);
74 }
75
76 private:
77 const Size n_;
78 const ext::shared_ptr<BasketPayoff> payoff_;
79 const ext::shared_ptr<FdmMesher> mesher_;
80 const Array logS0_, v_;
81 const std::vector<ext::shared_ptr<YieldTermStructure>> qTS_;
82 const ext::shared_ptr<YieldTermStructure> rTS_;
83 const Matrix Q_;
84 const Array l_;
85 Time cachedT_;
86 Array qf_;
88 };
89 }
90
92 std::vector<ext::shared_ptr<GeneralizedBlackScholesProcess> > processes,
93 Matrix rho,
94 std::vector<Size> xGrids,
95 Size tGrid, Size dampingSteps,
96 const FdmSchemeDesc& schemeDesc)
97 : processes_(std::move(processes)),
98 rho_(std::move(rho)),
99 xGrids_(std::move(xGrids)),
100 tGrid_(tGrid),
101 dampingSteps_(dampingSteps),
102 schemeDesc_(schemeDesc) {
103
104 QL_REQUIRE(!processes_.empty(), "no Black-Scholes process is given.");
106 && rho_.size1() == processes_.size(),
107 "correlation matrix has the wrong size.");
108 QL_REQUIRE(xGrids_.size() == 1 || xGrids_.size() == processes_.size(),
109 "wrong number of xGrids is given.");
110
111 std::for_each(processes_.begin(), processes_.end(),
112 [this](const auto& p) { registerWith(p); });
113 }
114
116 std::vector<ext::shared_ptr<GeneralizedBlackScholesProcess> > processes,
117 Matrix rho, Size xGrid, Size tGrid, Size dampingSteps,
118 const FdmSchemeDesc& schemeDesc)
120 std::move(processes), std::move(rho), std::vector<Size>(1, xGrid), tGrid, dampingSteps, schemeDesc)
121 {}
122
123
125 #ifndef PDE_MAX_SUPPORTED_DIM
126 #define PDE_MAX_SUPPORTED_DIM 4
127 #endif
129 "This engine does not support " << processes_.size() << " underlyings. "
130 << "Max number of underlyings is " << PDE_MAX_SUPPORTED_DIM << ". "
131 << "Please change preprocessor constant PDE_MAX_SUPPORTED_DIM and recompile "
132 << "if a larger number of underlyings is needed.");
133
134 const Date maturityDate = arguments_.exercise->lastDate();
135 const Time maturity = processes_[0]->time(maturityDate);
136 const Real sqrtT = std::sqrt(maturity);
137
139 const Array s = pExtractor.getSpot();
140 const Array dq = pExtractor.getDividendYieldDf(maturityDate);
141 const Array stdDev = Sqrt(pExtractor.getBlackVariance(maturityDate));
142 const Array vols = stdDev / sqrtT;
143
144 const SymmetricSchurDecomposition schur(
145 getCovariance(vols.begin(), vols.end(), rho_));
146 const Matrix& Q = schur.eigenvectors();
147 const Array& l = schur.eigenvalues();
148
149 const Real eps = 1e-4;
150 std::vector<ext::shared_ptr<Fdm1dMesher> > meshers;
151
152 for (Size i=0; i < processes_.size(); ++i) {
153 const Size xGrid = (xGrids_.size() > 1)
154 ? xGrids_[i]
155 : std::max(Size(4), Size(xGrids_[0]*std::pow(l[i]/l[0], 0.1)));
156 QL_REQUIRE(xGrid >= 4, "minimum grid size is four");
157
158 const Real xStepStize = (1.0-2*eps)/(xGrid-1);
159
160 std::vector<Real> x(xGrid);
161 for (Size j=0; j < xGrid; ++j)
162 x[j] = 1.3*std::sqrt(l[i])*sqrtT
163 *InverseCumulativeNormal()(eps + j*xStepStize);
164
165 meshers.emplace_back(ext::make_shared<Predefined1dMesher>(x));
166 }
167
168 const ext::shared_ptr<FdmMesherComposite> mesher =
169 ext::make_shared<FdmMesherComposite>(meshers);
170
171 const ext::shared_ptr<BasketPayoff> payoff
172 = ext::dynamic_pointer_cast<BasketPayoff>(arguments_.payoff);
173 QL_REQUIRE(payoff, "basket payoff expected");
174
175 const ext::shared_ptr<YieldTermStructure> rTS =
176 processes_[0]->riskFreeRate().currentLink();
177
178 std::vector<ext::shared_ptr<YieldTermStructure>> qTS(processes_.size());
179 for (Size i=0; i < processes_.size(); ++i)
180 qTS[i] = processes_[i]->dividendYield().currentLink();
181
182 const ext::shared_ptr<FdmInnerValueCalculator> calculator =
183 ext::make_shared<detail::FdmPCABasketInnerValue>(
184 payoff, mesher,
185 Log(s), stdDev/sqrtT,
186 qTS, rTS,
187 Q, l
188 );
189
190 const ext::shared_ptr<FdmStepConditionComposite> conditions
193 mesher, calculator,
194 rTS->referenceDate(), rTS->dayCounter());
195
196 const FdmBoundaryConditionSet boundaries;
197 const FdmSolverDesc solverDesc
198 = { mesher, boundaries, conditions, calculator,
199 maturity, tGrid_, dampingSteps_ };
200
201 const bool isEuropean =
202 ext::dynamic_pointer_cast<EuropeanExercise>(arguments_.exercise) != nullptr;
203 const ext::shared_ptr<FdmWienerOp> op =
204 ext::make_shared<FdmWienerOp>(
205 mesher,
206 (isEuropean)? ext::shared_ptr<YieldTermStructure>() : rTS,
207 l);
208
209 switch(processes_.size()) {
210 #define BOOST_PP_LOCAL_MACRO(n) \
211 case n : \
212 results_.value = ext::make_shared<FdmNdimSolver<n>>( \
213 solverDesc, schemeDesc_, op)->interpolateAt( \
214 std::vector<Real>(processes_.size(), 0.0)); \
215 break;
216 #define BOOST_PP_LOCAL_LIMITS (1, PDE_MAX_SUPPORTED_DIM)
217 #include BOOST_PP_LOCAL_ITERATE()
218 default:
219 QL_FAIL("Not implemented for " << processes_.size() << " processes");
220 }
221
222 if (isEuropean)
223 results_.value *= pExtractor.getInterestRateDf(maturityDate);
224 }
225}
Black-Scholes processes.
1-D array used in linear algebra.
Definition: array.hpp:52
const_iterator end() const
Definition: array.hpp:499
const_iterator begin() const
Definition: array.hpp:491
Concrete date class.
Definition: date.hpp:125
static ext::shared_ptr< FdmStepConditionComposite > vanillaComposite(const DividendSchedule &schedule, const ext::shared_ptr< Exercise > &exercise, const ext::shared_ptr< FdmMesher > &mesher, const ext::shared_ptr< FdmInnerValueCalculator > &calculator, const Date &refDate, const DayCounter &dayCounter)
n-dimensional finite-differences Black Scholes vanilla option engine
FdndimBlackScholesVanillaEngine(std::vector< ext::shared_ptr< GeneralizedBlackScholesProcess > > processes, Matrix rho, std::vector< Size > xGrids, Size tGrid=50, Size dampingSteps=0, const FdmSchemeDesc &schemeDesc=FdmSchemeDesc::Douglas())
const std::vector< ext::shared_ptr< GeneralizedBlackScholesProcess > > processes_
Inverse cumulative normal distribution function.
Matrix used in linear algebra.
Definition: matrix.hpp:41
Size size2() const
Definition: matrix.hpp:516
Size size1() const
Definition: matrix.hpp:512
ext::shared_ptr< Exercise > exercise
Definition: option.hpp:65
ext::shared_ptr< Payoff > payoff
Definition: option.hpp:64
symmetric threshold Jacobi algorithm.
Array getDividendYieldDf(const Date &maturityDate) const
DiscountFactor getInterestRateDf(const Date &maturityDate) const
Array getBlackVariance(const Date &maturityDate) const
const DefaultType & t
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Definition: errors.hpp:92
Option exercise classes and payoff function.
const ext::shared_ptr< YieldTermStructure > rTS_
layer of abstraction to calculate the inner value
FdmMesher which is a composite of Fdm1dMesher.
composite of fdm step conditions
#define PDE_MAX_SUPPORTED_DIM
Finite-Differences n-dimensional Black-Scholes vanilla option engine.
const ext::shared_ptr< FdmMesher > mesher_
const ext::shared_ptr< Payoff > payoff_
Covariance matrix calculation.
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
Real DiscountFactor
discount factor between dates
Definition: types.hpp:66
std::size_t Size
size of a container
Definition: types.hpp:58
Real rho
ext::shared_ptr< QuantLib::Payoff > payoff
Definition: any.hpp:37
std::vector< ext::shared_ptr< Dividend > > DividendSchedule
Array Log(const Array &v)
Definition: array.hpp:849
Matrix getCovariance(DataIterator stdDevBegin, DataIterator stdDevEnd, const Matrix &corr, Real tolerance=1.0e-12)
Calculation of covariance from correlation and standard deviations.
Array Exp(const Array &v)
Definition: array.hpp:863
Array Sqrt(const Array &v)
Definition: array.hpp:835
bool close_enough(const Quantity &m1, const Quantity &m2, Size n)
Definition: quantity.cpp:182
OperatorTraits< FdmLinearOp >::bc_set FdmBoundaryConditionSet
STL namespace.
normal, cumulative and inverse cumulative distributions
One-dimensional mesher build from a given set of points.
Eigenvalues/eigenvectors of a real symmetric matrix.
helper class to extract underlying, volatility etc from a vector of processes