Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
cvaspreadsensitivitycalculator.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/*! \file orea/aggregation/dimcalculator.hpp
20 \brief Dynamic Initial Margin calculator base class
21 \ingroup analytics
22*/
23
25
26namespace ore {
27namespace analytics {
28
30 const vector<Real>& epe, const vector<Date>& dates,
31 const Handle<DefaultProbabilityTermStructure>& dts,
32 const Real& recovery,
33 const Handle<YieldTermStructure>& yts,
34 const vector<Period>& shiftTenors, Real shiftSize)
35 : key_(key), asof_(asof), epe_(epe), dates_(dates), dts_(dts), recovery_(recovery), yts_(yts),
36 shiftTenors_(shiftTenors), shiftSize_(shiftSize) {
37 shiftTimes_ = vector<Real>(shiftTenors.size(), 0.0);
38 hazardRateSensitivities_ = vector<Real>(shiftTenors.size(), 0.0);
39 cdsSpreadSensitivities_ = vector<Real>(shiftTenors.size(), 0.0);
40 for (Size i = 0; i < shiftTenors_.size(); ++i)
41 shiftTimes_[i] = dts_->timeFromReference(asof_ + shiftTenors_[i]);
42
43 Real cvaBase = cva();
44 Array input(shiftTenors_.size(), 0.0);
45 for (Size i = 0; i < shiftTenors_.size(); ++i) {
46 Real cvaShifted = cva(true, i);
47 hazardRateSensitivities_[i] = cvaShifted - cvaBase;
48 input[i] = hazardRateSensitivities_[i];
49 }
50 DLOG("CVA Calculator key=" << key_ << " cvaBase=" << cvaBase);
51
52 jacobi_ = Matrix(shiftTenors_.size(), shiftTenors_.size(), 0.0);
53 for (Size i = 0; i < shiftTenors_.size(); ++i) {
54 Real cdsSpreadBase = fairCdsSpread(i);
55 DLOG("CVA Calculator key=" << key_ << " fairSpread[" << i << "]=" << cdsSpreadBase);
56 Real row = 0.0;
57 for (Size j = 0; j <= i; ++j) {
58 Real cdsSpread = fairCdsSpread(i, true, j);
59 jacobi_[j][i] = (cdsSpread - cdsSpreadBase) / shiftSize_;
60 row += jacobi_[j][i];
61 DLOG("CVA Calculator key=" << key_ << " jacobi[" << j << "][" << i << "]=" << jacobi_[j][i]);
62 }
63 DLOG("CVA Calculator key=" << key_ << " jacobi column[" << i << "]=" << row);
64 }
65
66 Array output = inverse(jacobi_) * input;
67 for (Size i = 0; i < shiftTenors_.size(); ++i)
68 cdsSpreadSensitivities_[i] = output[i];
69}
70
71Real CVASpreadSensitivityCalculator::survivalProbability(Time t, bool shift, Size index) {
72 if (shift == false)
73 return dts_->survivalProbability(t);
74
75 QL_REQUIRE(index < shiftTimes_.size(), "index " << index << " out of range");
76 Real t2 = shiftTimes_[index];
77 Real t1 = index == 0 ? 0.0 : shiftTimes_[index - 1];
78 bool lastBucket = index == shiftTimes_.size() - 1 ? true : false;
79 if (t < t1)
80 return dts_->survivalProbability(t);
81 else if (t < t2) {
82 return dts_->survivalProbability(t) * exp(-shiftSize_ * (t - t1));
83 } else { // t >= t2
84 if (!lastBucket)
85 return dts_->survivalProbability(t) * exp(-shiftSize_ * (t2 - t1));
86 else
87 return dts_->survivalProbability(t) * exp(-shiftSize_ * (t - t1));
88 }
89}
90
91Real CVASpreadSensitivityCalculator::survivalProbability(Date d, bool shift, Size index) {
92 Real t = dts_->timeFromReference(d);
93 return survivalProbability(t, shift, index);
94}
95
96Real CVASpreadSensitivityCalculator::cva(bool shift, Size index) {
97 Real sum = 0.0;
98 for (Size j = 0; j < dates_.size(); ++j) {
99 Date d0 = j == 0 ? asof_ : dates_[j - 1];
100 Date d1 = dates_[j];
101 Real s0 = survivalProbability(d0, shift, index);
102 Real s1 = survivalProbability(d1, shift, index);
103 Real increment = (1.0 - recovery_) * (s0 - s1) * epe_[j + 1];
104 sum += increment;
105 }
106 DLOG("CVA Calculator key=" << key_ << " shift=" << shift << " index=" << index << " cva=" << sum);
107 return sum;
108}
109
110Real CVASpreadSensitivityCalculator::fairCdsSpread(Size term, bool shift, Size index) {
111 // not following the CDS2015 date rule, but a CDS with 6m periods, paying at period ends, no rebate
112 QL_REQUIRE(term < shiftTimes_.size(), "term " << term << " out of range");
113 Real T = shiftTimes_[term];
114 Real dt = 0.5;
115 Size n = Size(floor(T / dt + 0.5));
116 QL_REQUIRE(fabs(T - dt * n) < 0.1 * dt, "shift term is not a multiple of 6M");
117 Real enumerator = 0.0, denominator = 0.0;
118 for (Size i = 1; i <= n; ++i) {
119 Real t0 = dt * (i - 1);
120 Real t1 = dt * i;
121 Real s0 = survivalProbability(t0, shift, index);
122 Real s1 = survivalProbability(t1, shift, index);
123 Real dis = yts_->discount(t1);
124 enumerator += (s0 - s1) * dis;
125 denominator += dt * s1 * dis;
126 }
127 return (1.0 - recovery_) * enumerator / denominator;
128}
129
130} // namespace analytics
131} // namespace ore
CVASpreadSensitivityCalculator(const std::string &key, const Date &asof, const vector< Real > &epe, const vector< Date > &dates, const Handle< DefaultProbabilityTermStructure > &dts, const Real &recovery, const Handle< YieldTermStructure > &yts, const vector< Period > &shiftTenors, Real shiftSize=0.0001)
Real fairCdsSpread(Size term, bool shift=false, Size index=0)
Fair CDS Spread calculation with and without shifted hazard rates.
#define DLOG(text)
RandomVariable exp(RandomVariable x)
QuantLib::SparseMatrix inverse(QuantLib::SparseMatrix m)
Real sum(const Cash &c, const Cash &d)
Date asof(14, Jun, 2018)