Coverage Report

Created: 2025-09-04 07:11

/src/quantlib/ql/experimental/models/squarerootclvmodel.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2016 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
 <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
/*! \file squarerootclvmodel.cpp
21
    \brief CLV model with a square root kernel process
22
*/
23
24
#include <ql/processes/blackscholesprocess.hpp>
25
#include <ql/processes/squarerootprocess.hpp>
26
#include <ql/math/integrals/gaussianquadratures.hpp>
27
28
#include <ql/experimental/models/squarerootclvmodel.hpp>
29
#include <ql/methods/finitedifferences/utilities/gbsmrndcalculator.hpp>
30
31
#include <boost/math/distributions/non_central_chi_squared.hpp>
32
33
#include <utility>
34
35
namespace QuantLib {
36
    SquareRootCLVModel::SquareRootCLVModel(
37
        const ext::shared_ptr<GeneralizedBlackScholesProcess>& bsProcess,
38
        ext::shared_ptr<SquareRootProcess> sqrtProcess,
39
        std::vector<Date> maturityDates,
40
        Size lagrangeOrder,
41
        Real pMax,
42
        Real pMin)
43
0
    : pMax_(pMax), pMin_(pMin), bsProcess_(bsProcess), sqrtProcess_(std::move(sqrtProcess)),
44
0
      maturityDates_(std::move(maturityDates)), lagrangeOrder_(lagrangeOrder),
45
0
      rndCalculator_(ext::make_shared<GBSMRNDCalculator>(bsProcess)) {}
Unexecuted instantiation: QuantLib::SquareRootCLVModel::SquareRootCLVModel(boost::shared_ptr<QuantLib::GeneralizedBlackScholesProcess> const&, boost::shared_ptr<QuantLib::SquareRootProcess>, std::__1::vector<QuantLib::Date, std::__1::allocator<QuantLib::Date> >, unsigned long, double, double)
Unexecuted instantiation: QuantLib::SquareRootCLVModel::SquareRootCLVModel(boost::shared_ptr<QuantLib::GeneralizedBlackScholesProcess> const&, boost::shared_ptr<QuantLib::SquareRootProcess>, std::__1::vector<QuantLib::Date, std::__1::allocator<QuantLib::Date> >, unsigned long, double, double)
46
47
0
    Real SquareRootCLVModel::cdf(const Date& d, Real k) const {
48
0
        return rndCalculator_->cdf(k, bsProcess_->time(d));
49
0
    }
50
51
52
0
    Real SquareRootCLVModel::invCDF(const Date& d, Real q) const {
53
0
        return rndCalculator_->invcdf(q, bsProcess_->time(d));
54
0
    }
55
56
    std::pair<Real, Real> SquareRootCLVModel::nonCentralChiSquaredParams(
57
0
        const Date& d) const {
58
59
0
        const Time t = bsProcess_->time(d);
60
61
0
        const Real kappa = sqrtProcess_->a();
62
0
        const Real theta = sqrtProcess_->b();
63
0
        const Real sigma = sqrtProcess_->sigma();
64
65
0
        const Real df  = 4*theta*kappa/(sigma*sigma);
66
0
        const Real ncp = 4*kappa*std::exp(-kappa*t)
67
0
            / (sigma*sigma*(1-std::exp(-kappa*t)))*sqrtProcess_->x0();
68
69
0
        return std::make_pair(df, ncp);
70
0
    }
71
72
73
0
    Array SquareRootCLVModel::collocationPointsX(const Date& d) const {
74
75
0
        const std::pair<Real, Real> p = nonCentralChiSquaredParams(d);
76
77
0
        Array x = GaussianQuadrature(lagrangeOrder_,
78
0
            GaussNonCentralChiSquaredPolynomial(p.first, p.second))
79
0
             .x();
80
81
0
        std::sort(x.begin(), x.end());
82
83
0
        const boost::math::non_central_chi_squared_distribution<Real>
84
0
            dist(p.first, p.second);
85
86
0
        const Real xMin = std::max(x.front(),
87
0
            (pMin_ == Null<Real>())
88
0
                ? 0.0 : boost::math::quantile(dist, pMin_));
89
90
0
        const Real xMax = std::min(x.back(),
91
0
            (pMax_ == Null<Real>())
92
0
            ? QL_MAX_REAL : boost::math::quantile(dist, pMax_));
93
94
0
        const Real b = xMin - x.front();
95
0
        const Real a = (xMax - xMin)/(x.back() - x.front());
96
97
0
        for (Real& i : x) {
98
0
            i = a * i + b;
99
0
        }
100
101
0
        return x;
102
0
    }
103
104
0
    Array SquareRootCLVModel::collocationPointsY(const Date& d) const {
105
106
0
        const Array x = collocationPointsX(d);
107
0
        const std::pair<Real, Real> params = nonCentralChiSquaredParams(d);
108
0
        const boost::math::non_central_chi_squared_distribution<Real>
109
0
            dist(params.first, params.second);
110
111
0
        Array s(x.size());
112
0
        for (Size i=0, n=s.size(); i < n; ++i) {
113
0
            const Real q = boost::math::cdf(dist, x[i]);
114
115
0
            s[i] = invCDF(d, q);
116
0
        }
117
118
0
        return s;
119
0
    }
120
121
0
    std::function<Real(Time, Real)> SquareRootCLVModel::g() const {
122
0
        calculate();
123
0
        return g_;
124
0
    }
125
126
0
    void SquareRootCLVModel::performCalculations() const {
127
0
        g_ = std::function<Real(Time, Real)>(MappingFunction(*this));
128
0
    }
129
130
    SquareRootCLVModel::MappingFunction::MappingFunction(
131
        const SquareRootCLVModel& model)
132
0
    : s_(ext::make_shared<Matrix>(
133
0
         model.maturityDates_.size(), model.lagrangeOrder_)),
134
0
      x_(ext::make_shared<Matrix>(
135
0
         model.maturityDates_.size(), model.lagrangeOrder_)) {
136
137
0
        std::vector<Date> maturityDates = model.maturityDates_;
138
0
        std::sort(maturityDates.begin(), maturityDates.end());
139
140
0
        const ext::shared_ptr<GeneralizedBlackScholesProcess>&
141
0
            bsProcess = model.bsProcess_;
142
143
0
        for (Size i=0, n = maturityDates.size(); i < n; ++i) {
144
0
            const Date maturityDate = maturityDates[i];
145
146
0
            const Array x = model.collocationPointsX(maturityDate);
147
0
            const Array y = model.collocationPointsY(maturityDate);
148
149
0
            std::copy(x.begin(), x.end(), x_->row_begin(i));
150
0
            std::copy(y.begin(), y.end(), s_->row_begin(i));
151
152
0
            const Time maturity = bsProcess->time(maturityDate);
153
154
0
            interpl.insert(
155
0
                std::make_pair(maturity,
156
0
                    ext::make_shared<LagrangeInterpolation>(
157
0
                        x_->row_begin(i), x_->row_end(i),
158
0
                        s_->row_begin(i))));
159
0
        }
160
0
    }
161
162
0
    Real SquareRootCLVModel::MappingFunction::operator()(Time t,Real x) const {
163
0
        const auto ge = interpl.lower_bound(t);
164
165
0
        if (close_enough(ge->first, t)) {
166
0
            return (*ge->second)(x, true);
167
0
        }
168
169
0
        QL_REQUIRE(ge != interpl.end() && ge != interpl.begin(),
170
0
             "extrapolation to large or small t is not allowed");
171
172
0
        const Time t1 = ge->first;
173
0
        const Real y1 = (*ge->second)(x, true);
174
175
0
        interpl_type::const_iterator lt = ge;
176
0
        std::advance(lt, -1);
177
178
0
        const Time t0 = lt->first;
179
0
        const Real y0 = (*lt->second)(x, true);
180
181
0
        return y0 + (y1 - y0)/(t1 - t0)*(t - t0);
182
0
    }
183
}