Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
crcirpp.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
19#include <iostream>
20
21#include <boost/math/distributions.hpp>
22#include <boost/math/distributions/non_central_chi_squared.hpp>
23#include <ql/math/interpolations/loginterpolation.hpp>
24#include <ql/termstructures/credit/interpolatedsurvivalprobabilitycurve.hpp>
25#include <ql/time/daycounters/actualactual.hpp>
26
28
29namespace QuantExt {
30
31namespace {
32Real nccs(const Real df, const Real ncp, const Real x, const bool cumulative) {
33 QL_REQUIRE(std::isfinite(df) && df > 0, "CrCirpp::density(): illegal df=" << df);
34 // boost
35 boost::math::non_central_chi_squared_distribution<> d(df, ncp);
36 return cumulative ? cdf(d, x) : pdf(d, x);
37 // ql (use density from boost, there is none in ql?)
38 // return cumulative ? NonCentralCumulativeChiSquareDistribution(df, ncp)(x) : pdf(d, x);
39}
40} // namespace
41
43 const QuantLib::ext::shared_ptr<CrCirppParametrization>& parametrization)
44 : parametrization_(parametrization) {
45
46 // FIXME hardcoded discretisation schema
48 QuantLib::ext::make_shared<CrCirppStateProcess>(this, CrCirppStateProcess::Discretization::BrigoAlfonsi);
49 QL_REQUIRE(stateProcess_ != NULL, "stateProcess has null pointer in CrCirpp ctor!");
50
51 arguments_.resize(4);
52 arguments_[0] = parametrization_->parameter(0);
53 arguments_[1] = parametrization_->parameter(1);
54 arguments_[2] = parametrization_->parameter(2);
55 arguments_[3] = parametrization_->parameter(3);
56 registerWith(parametrization_->termStructure());
57}
58
59Handle<DefaultProbabilityTermStructure> CrCirpp::defaultCurve(std::vector<Date> dateGrid) const {
60 if (parametrization_->shifted()) {
61 QL_REQUIRE(!parametrization_->termStructure().empty(), "default curve not set");
62 QL_REQUIRE(dateGrid.size() == 0, "dateGrid without effect for shifted model");
63 return parametrization_->termStructure();
64 } else {
65 // build one on the fly
66 Date today = Settings::instance().evaluationDate();
67 std::vector<Real> survivalProbabilities(1, 1.0);
68 std::vector<Date> dates;
69 DayCounter tsDayCounter = Actual365Fixed();
70 if (dateGrid.size() > 0) {
71 QL_REQUIRE(dateGrid.front() == today, "front date must be today");
72 dates = dateGrid;
73 } else {
74 dates.push_back(today);
75 // up to one year in monthly steps
76 for (Size i = 1; i <= 12; i++)
77 dates.push_back(today + i * Months);
78 // starts in year two annually
79 for (Size i = 2; i <= 10; i++)
80 dates.push_back(today + i * Years);
81 }
82 for (Size i = 1; i < dates.size(); i++) {
83 Real t = tsDayCounter.yearFraction(today, dates[i]);
84 survivalProbabilities.push_back(survivalProbability(0.0, t, parametrization_->y0(t)));
85 }
86 QuantLib::ext::shared_ptr<DefaultProbabilityTermStructure> defaultCurve(
87 new InterpolatedSurvivalProbabilityCurve<LogLinear>(dates, survivalProbabilities, tsDayCounter));
88 defaultCurve->enableExtrapolation();
89 return Handle<DefaultProbabilityTermStructure>(defaultCurve);
90 }
91}
92
93Real CrCirpp::A(Real t, Real T) const {
94 Real kappa = parametrization_->kappa(t);
95 Real theta = parametrization_->theta(t);
96 Real sigma = parametrization_->sigma(t);
97 Real sigma2 = sigma * sigma;
98 Real h = sqrt(kappa * kappa + 2.0 * sigma2);
99
100 Real nominator = 2.0 * h * exp((kappa + h) * (T - t) / 2.0);
101 Real denominator = 2.0 * h + (kappa + h) * (exp((T - t) * h) - 1.0);
102 Real exponent = 2.0 * kappa * theta / sigma2;
103
104 Real value = std::pow((nominator / denominator), exponent);
105
106 return value;
107}
108
109Real CrCirpp::B(Real t, Real T) const {
110
111 Real kappa = parametrization_->kappa(t);
112 Real sigma = parametrization_->sigma(t);
113 Real sigma2 = sigma * sigma;
114 Real h = sqrt(kappa * kappa + 2.0 * sigma2);
115
116 Real nominator = 2.0 * (exp((T - t) * h) - 1.0);
117 Real denominator = 2.0 * h + (kappa + h) * (exp((T - t) * h) - 1.0);
118
119 Real value = nominator / denominator;
120
121 return value;
122}
123
124Real CrCirpp::zeroBond(Real t, Real T, Real y) const { return A(t, T) * exp(-B(t, T) * y); }
125
126Real CrCirpp::survivalProbability(Real t, Real T, Real y) const {
127 Real P_Cir = zeroBond(t, T, y); // A(t,T) * exp(-B(t,T) * y);
128 if (parametrization_->shifted()) {
129 Probability SP_t = parametrization_->termStructure()->survivalProbability(t);
130 // std::cout<<" SP_t " << SP_t << std::endl;
131 Probability SP_T = parametrization_->termStructure()->survivalProbability(T);
132 // std::cout<<" SP_T " << SP_T << std::endl;
133 // std::cout<<" y0 " << parametrization_->y0(t) << std::endl;
134 Real A_bar = (SP_T * A(0, t) * exp(-B(0, t) * parametrization_->y0(t))) /
135 (SP_t * A(0, T) * exp(-B(0, T) * parametrization_->y0(t)));
136 // std::cout<<"A_bar " <<A_bar<< std::endl;
137 return A_bar * P_Cir;
138 } else
139 return P_Cir;
140}
141
142Real CrCirpp::density(Real x, Real t) {
143
144 Real kappa = parametrization_->kappa(t);
145 Real theta = parametrization_->theta(t);
146 Real sigma = parametrization_->sigma(t);
147 Real y0 = parametrization_->y0(t);
148 Real sigma2 = sigma * sigma;
149
150 Real c = 4 * kappa / (sigma2 * (1 - exp(-kappa * t)));
151 // degrees of freedom
152 Real df = 4 * kappa * theta / (sigma2);
153 // non-central parameter
154 Real ncp = c * y0 * exp(-kappa * t);
155
156 return c * nccs(df, ncp, c * x, false);
157}
158
159Real CrCirpp::cumulative(Real x, Real t) {
160
161 Real kappa = parametrization_->kappa(t);
162 Real theta = parametrization_->theta(t);
163 Real sigma = parametrization_->sigma(t);
164 Real y0 = parametrization_->y0(t);
165 Real sigma2 = sigma * sigma;
166
167 Real c = 4 * kappa / (sigma2 * (1 - exp(-kappa * t)));
168 // degrees of freedom
169 Real df = 4 * kappa * theta / (sigma2);
170 // non-central parameter
171 Real ncp = c * y0 * exp(-kappa * t);
172
173 return c * nccs(df, ncp, c * x, true);
174}
175
176Real CrCirpp::densityForwardMeasure(Real x, Real t) {
177
178 Real kappa = parametrization_->kappa(t);
179 Real theta = parametrization_->theta(t);
180 Real sigma = parametrization_->sigma(t);
181 Real y0 = parametrization_->y0(t);
182 Real sigma2 = sigma * sigma;
183
184 Real h = sqrt(kappa * kappa + 2.0 * sigma2);
185 Real rho = 2 * h / (sigma2 * (exp(h * t) - 1));
186 // q(t,s) in Brigo-Mercuri in (3.28)
187 Real c = 2 * (rho + (kappa + h) / sigma2 + 0.0); // 0.0 stands for the B term which is neglectible
188 // degrees of freedom
189 Real df = 4 * kappa * theta / (sigma2);
190 // non-central parameter
191 // delta(t,s) in Brigo-Mercurio in (3.28)
192 Real ncp = 4 * (rho * rho * y0 * exp(h * t)) / c;
193
194 return c * nccs(df, ncp, c * x, false);
195}
196
197// Brigo-Mercurio 2nd Edition, page 67
199
200 Real kappa = parametrization_->kappa(t);
201 Real theta = parametrization_->theta(t);
202 Real sigma = parametrization_->sigma(t);
203 Real y0 = parametrization_->y0(t);
204 Real sigma2 = sigma * sigma;
205 Real h = sqrt(kappa * kappa + 2.0 * sigma2);
206 Real rho = 2 * h / (sigma2 * (exp(h * t) - 1));
207
208 // q(t,s) in Brigo-Mercurii (3.28)
209 Real c = 2 * (rho + (kappa + h) / sigma2 + 0.0); // 0.0 stands for the B term which is neglectible
210 // degrees of freedom
211 Real df = 4 * kappa * theta / (sigma2);
212 // non-central parameter
213 // delta(t,s) in Brigo-Mercurio in (3.28)
214 Real ncp = 4 * (rho * rho * y0 * exp(h * t)) / c;
215
216 return c * nccs(df, ncp, c * x, true);
217}
218
219// Brigo-Mercurio (3.26) and (3.78)
220Real CrCirpp::zeroBondOption(Real eval_t, Real expiry_T, Real maturity_tau, Real strike_k, Real y_t,
221 Real w) {
222
223 Real value = 0.0;
224 Real kappa = parametrization_->kappa(eval_t);
225 Real theta = parametrization_->theta(eval_t);
226 Real sigma = parametrization_->sigma(eval_t);
227 Real y0 = parametrization_->y0(eval_t);
228 Real sigma2 = sigma * sigma;
229
230 Real h = sqrt(kappa * kappa + 2.0 * sigma2);
231 Real rho = 2.0 * h / (sigma2 * (exp(h * (expiry_T - eval_t)) - 1.0));
232 Real Psi = (kappa + h) / sigma2;
233
234 Probability SP_T;
235 Probability SP_tau;
236 if (parametrization_->shifted()) {
237 SP_T = parametrization()->termStructure()->survivalProbability(expiry_T);
238 SP_tau = parametrization()->termStructure()->survivalProbability(maturity_tau);
239 } else {
240 SP_T = survivalProbability(0.0, expiry_T, y0);
241 SP_tau = survivalProbability(0.0, maturity_tau, y0);
242 }
243
244 Real r_hat = 1.0 / B(expiry_T, maturity_tau) *
245 (log(A(expiry_T, maturity_tau) / strike_k) -
246 log((SP_T * A(0.0, maturity_tau) * exp(-B(0.0, maturity_tau) * y0)) /
247 (SP_tau * A(0.0, expiry_T) * exp(-B(0.0, expiry_T) * y0))));
248
249 Real denom = rho + Psi + B(expiry_T, maturity_tau);
250 Real df = 4.0 * kappa * theta / sigma2;
251 Real ncp = 2.0 * rho * rho * y_t * exp(h * (expiry_T - eval_t)) / denom;
252 QL_REQUIRE(std::isfinite(df) && df > 0, "CrCirpp::zeroBondOption(): illegal df="
253 << df << ", kappa=" << kappa << ", theta= " << theta
254 << ", sigma=" << sigma);
255
256 value += nccs(df, ncp, 2 * r_hat * denom, true) * SP_tau;
257
258 denom = rho + Psi;
259 // df unchanged
260 ncp = 2 * rho * rho * y_t * exp(h * (expiry_T - eval_t)) / denom;
261
262 value -= nccs(df, ncp, 2 * r_hat * denom, true) * SP_T * strike_k;
263
264 if (w < 0.0) {
265 // PUT via put-call-paritiy
266 // C - P = S_M(T) - S_M(t)*K
267 // P = C - S_M(T) + S_M(t)*K
268 value -= SP_tau - SP_T * strike_k;
269 }
270
271 return value;
272}
273
274} // namespace QuantExt
Real density(Real x, Real t)
Definition: crcirpp.cpp:142
Real zeroBondOption(Real eval_t, Real expiry_T, Real maturity_tau, Real strike_k, Real y_t, Real w)
Definition: crcirpp.cpp:220
Real A(Real t, Real T) const
Definition: crcirpp.cpp:93
Real densityForwardMeasure(Real x, Real t)
Definition: crcirpp.cpp:176
Real cumulativeForwardMeasure(Real x, Real t)
Definition: crcirpp.cpp:198
Real zeroBond(Real t, Real T, Real y) const
Definition: crcirpp.cpp:124
Real cumulative(Real x, Real t)
Definition: crcirpp.cpp:159
QuantLib::ext::shared_ptr< CrCirppParametrization > parametrization_
Definition: crcirpp.hpp:77
QuantLib::ext::shared_ptr< CrCirppStateProcess > stateProcess_
Definition: crcirpp.hpp:78
Handle< DefaultProbabilityTermStructure > defaultCurve(std::vector< Date > dateGrid=std::vector< Date >()) const
Definition: crcirpp.cpp:59
Real B(Real t, Real T) const
Definition: crcirpp.cpp:109
CrCirpp(const QuantLib::ext::shared_ptr< CrCirppParametrization > &parametrization)
Definition: crcirpp.cpp:42
Real survivalProbability(Real t, Real T, Real y) const
Definition: crcirpp.cpp:126
const QuantLib::ext::shared_ptr< CrCirppParametrization > parametrization() const
Definition: crcirpp.hpp:88
DefaultProbabilityTermStructure based on interpolation of survival probabilities.
std::vector< QuantLib::ext::shared_ptr< Parameter > > arguments_
Real value(const Array &params, const std::vector< QuantLib::ext::shared_ptr< CalibrationHelper > > &)
CIR++ credit model class.
RandomVariable sqrt(RandomVariable x)
CompiledFormula exp(CompiledFormula x)
CompiledFormula log(CompiledFormula x)