Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
fdmblackscholesop.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2020 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
20
21#include <ql/instruments/payoffs.hpp>
22#include <ql/math/functional.hpp>
23#include <ql/math/comparison.hpp>
24#include <ql/methods/finitedifferences/meshers/fdmmesher.hpp>
25#include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp>
26#include <ql/methods/finitedifferences/operators/secondderivativeop.hpp>
27
28namespace QuantExt {
29
30FdmBlackScholesOp::FdmBlackScholesOp(const ext::shared_ptr<FdmMesher>& mesher,
31 const ext::shared_ptr<GeneralizedBlackScholesProcess>& bsProcess, Real strike,
32 bool localVol, Real illegalLocalVolOverwrite, Size direction,
33 const ext::shared_ptr<FdmQuantoHelper>& quantoHelper, const bool discounting,
34 const bool ensureNonNegativeForwardVariance)
35 : mesher_(mesher), rTS_(bsProcess->riskFreeRate().currentLink()), qTS_(bsProcess->dividendYield().currentLink()),
36 volTS_(bsProcess->blackVolatility().currentLink()),
37 localVol_((localVol) ? bsProcess->localVolatility().currentLink() : ext::shared_ptr<LocalVolTermStructure>()),
38 x_((localVol) ? Array(Exp(mesher->locations(direction))) : Array()), dxMap_(FirstDerivativeOp(direction, mesher)),
39 dxxMap_(SecondDerivativeOp(direction, mesher)), mapT_(direction, mesher), strike_(strike),
40 illegalLocalVolOverwrite_(illegalLocalVolOverwrite), direction_(direction), quantoHelper_(quantoHelper),
41 initialValue_(bsProcess->x0()), discounting_(discounting),
42 ensureNonNegativeForwardVariance_(ensureNonNegativeForwardVariance) {}
43
44void FdmBlackScholesOp::setTime(Time t1, Time t2) {
45 const Rate r = rTS_->forwardRate(t1, t2, Continuous).rate();
46 const Rate q = qTS_->forwardRate(t1, t2, Continuous).rate();
47 Rate discountRate = discounting_ ? r : 0.0;
48
49 if (localVol_) {
50 const ext::shared_ptr<FdmLinearOpLayout> layout = mesher_->layout();
51 const FdmLinearOpIterator endIter = layout->end();
52
53 Array v(layout->size());
54 for (FdmLinearOpIterator iter = layout->begin(); iter != endIter; ++iter) {
55 const Size i = iter.index();
56
57 if (illegalLocalVolOverwrite_ < 0.0) {
58 v[i] = squared(localVol_->localVol(0.5 * (t1 + t2), x_[i], true));
59 } else {
60 try {
61 v[i] = squared(localVol_->localVol(0.5 * (t1 + t2), x_[i], true));
62 } catch (Error&) {
63 v[i] = squared(illegalLocalVolOverwrite_);
64 }
65 }
66 }
67
68 if (quantoHelper_) {
69 mapT_.axpyb(r - q - 0.5 * v - quantoHelper_->quantoAdjustment(Sqrt(v), t1, t2), dxMap_,
70 dxxMap_.mult(0.5 * v), Array(1, -discountRate));
71 } else {
72 mapT_.axpyb(r - q - 0.5 * v, dxMap_, dxxMap_.mult(0.5 * v), Array(1, -discountRate));
73 }
74 } else {
75 Real k1, k2;
76 if (strike_ == Null<Real>()) {
77 k1 = initialValue_ * qTS_->discount(t1) / rTS_->discount(t1);
78 k2 = initialValue_ * qTS_->discount(t2) / rTS_->discount(t2);
79 } else {
80 k1 = k2 = strike_;
81 }
82 Real v = ((close_enough(t2, 0.0) ? 0.0 : volTS_->blackVariance(t2, k2)) -
83 (close_enough(t1, 0.0) ? 0.0 : volTS_->blackVariance(t1, k1))) /
84 (t2 - t1);
86 v = std::max(v, 0.0);
87
88 if (quantoHelper_) {
89 mapT_.axpyb(Array(1, r - q - 0.5 * v) - quantoHelper_->quantoAdjustment(Array(1, std::sqrt(v)), t1, t2),
90 dxMap_, dxxMap_.mult(0.5 * Array(mesher_->layout()->size(), v)), Array(1, -discountRate));
91 } else {
92 mapT_.axpyb(Array(1, r - q - 0.5 * v), dxMap_, dxxMap_.mult(0.5 * Array(mesher_->layout()->size(), v)),
93 Array(1, -discountRate));
94 }
95 }
96}
97
98Size FdmBlackScholesOp::size() const { return 1u; }
99
100Array FdmBlackScholesOp::apply(const Array& u) const { return mapT_.apply(u); }
101
102Array FdmBlackScholesOp::apply_direction(Size direction, const Array& r) const {
103 if (direction == direction_)
104 return mapT_.apply(r);
105 else {
106 Array retVal(r.size(), 0.0);
107 return retVal;
108 }
109}
110
111Array FdmBlackScholesOp::apply_mixed(const Array& r) const {
112 Array retVal(r.size(), 0.0);
113 return retVal;
114}
115
116Array FdmBlackScholesOp::solve_splitting(Size direction, const Array& r, Real dt) const {
117 if (direction == direction_)
118 return mapT_.solve_splitting(r, dt, 1.0);
119 else {
120 Array retVal(r);
121 return retVal;
122 }
123}
124
125Array FdmBlackScholesOp::preconditioner(const Array& r, Real dt) const {
126 return solve_splitting(direction_, r, dt);
127}
128
129#if !defined(QL_NO_UBLAS_SUPPORT)
130 std::vector<QuantLib::SparseMatrix> FdmBlackScholesOp::toMatrixDecomp() const {
131 std::vector<QuantLib::SparseMatrix> retVal(1, mapT_.toMatrix());
132 return retVal;
133}
134#endif
135} // namespace QuantExt
Size size() const override
Array apply_direction(Size direction, const Array &r) const override
Array preconditioner(const Array &r, Real s) const override
std::vector< QuantLib::SparseMatrix > toMatrixDecomp() const override
const TripleBandLinearOp dxxMap_
const ext::shared_ptr< FdmQuantoHelper > quantoHelper_
void setTime(Time t1, Time t2) override
FdmBlackScholesOp(const ext::shared_ptr< FdmMesher > &mesher, const ext::shared_ptr< GeneralizedBlackScholesProcess > &process, Real strike=Null< Real >(), bool localVol=false, Real illegalLocalVolOverwrite=-Null< Real >(), Size direction=0, const ext::shared_ptr< FdmQuantoHelper > &quantoHelper=ext::shared_ptr< FdmQuantoHelper >(), const bool discounting=true, const bool ensureNonNegativeForwardVariance=false)
Array apply_mixed(const Array &r) const override
const ext::shared_ptr< YieldTermStructure > qTS_
const FirstDerivativeOp dxMap_
const ext::shared_ptr< FdmMesher > mesher_
Array solve_splitting(Size direction, const Array &r, Real s) const override
const ext::shared_ptr< YieldTermStructure > rTS_
const ext::shared_ptr< BlackVolTermStructure > volTS_
Array apply(const Array &r) const override
const ext::shared_ptr< LocalVolTermStructure > localVol_
extended version of the QuantLib class, see the documentation for details
Filter close_enough(const RandomVariable &x, const RandomVariable &y)