Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
lgmconvolutionsolver.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2019 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/math/distributions/normaldistribution.hpp>
22
23namespace QuantExt {
24
25//! Numerical convolution solver for the LGM model
26/*! Reference: Hagan, Methodology for callable swaps and Bermudan
27 exercise into swaptions
28*/
29
30LgmConvolutionSolver::LgmConvolutionSolver(const QuantLib::ext::shared_ptr<LinearGaussMarkovModel>& model, const Real sy,
31 const Size ny, const Real sx, const Size nx)
32 : model_(model), nx_(nx) {
33
34 // precompute weights
35
36 // number of x, y grid points > 0
37 mx_ = static_cast<Size>(floor(sx * static_cast<Real>(nx)) + 0.5);
38 my_ = static_cast<Size>(floor(sy * static_cast<Real>(ny)) + 0.5);
39
40 // y-grid spacing
41 h_ = 1.0 / static_cast<Real>(ny);
42
43 // weights for convolution in the rollback step
44 CumulativeNormalDistribution N;
45 NormalDistribution G;
46
47 y_.resize(2 * my_ + 1); // x-coordinate / standard deviation of x
48 w_.resize(2 * my_ + 1); // probability weight around y-grid point i
49 for (int i = 0; i <= 2 * my_; i++) {
50 y_[i] = h_ * (i - my_);
51 if (i == 0 || i == 2 * my_)
52 w_[i] = (1. + y_[0] / h_) * N(y_[0] + h_) - y_[0] / h_ * N(y_[0]) + (G(y_[0] + h_) - G(y_[0])) / h_;
53 else
54 w_[i] = (1. + y_[i] / h_) * N(y_[i] + h_) - 2. * y_[i] / h_ * N(y_[i]) -
55 (1. - y_[i] / h_) * N(y_[i] - h_) // opposite sign in the paper
56 + (G(y_[i] + h_) - 2. * G(y_[i]) + G(y_[i] - h_)) / h_;
57 // w_[i] might be negative due to numerical errors
58 if (w_[i] < 0.0) {
59 QL_REQUIRE(w_[i] > -1.0E-10, "LgmConvolutionSolver: negative w (" << w_[i] << ") at i=" << i);
60 w_[i] = 0.0;
61 }
62 }
63}
64
65std::vector<Real> LgmConvolutionSolver::stateGrid(const Real t) const {
66 if (close_enough(t, 0.0))
67 return std::vector<Real>(2 * mx_ + 1, 0.0);
68 std::vector<Real> x(2 * mx_ + 1);
69 Real dx = std::sqrt(model_->parametrization()->zeta(t)) / static_cast<Real>(nx_);
70 for (int k = 0; k <= 2 * mx_; ++k) {
71 x[k] = dx * (k - mx_);
72 }
73 return x;
74}
75
76} // namespace QuantExt
LgmConvolutionSolver(const QuantLib::ext::shared_ptr< LinearGaussMarkovModel > &model, const Real sy, const Size ny, const Real sx, const Size nx)
Numerical convolution solver for the LGM model.
std::vector< Real > stateGrid(const Real t) const
QuantLib::ext::shared_ptr< LinearGaussMarkovModel > model_
numeric convolution solver for the LGM model
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
JY INF index sigma component.