Coverage Report

Created: 2025-11-04 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/math/statistics/gaussianstatistics.hpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2003 Ferdinando Ametrano
5
 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
6
7
 This file is part of QuantLib, a free-software/open-source library
8
 for financial quantitative analysts and developers - http://quantlib.org/
9
10
 QuantLib is free software: you can redistribute it and/or modify it
11
 under the terms of the QuantLib license.  You should have received a
12
 copy of the license along with this program; if not, please email
13
 <quantlib-dev@lists.sf.net>. The license is also available online at
14
 <https://www.quantlib.org/license.shtml>.
15
16
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
*/
20
21
/*! \file gaussianstatistics.hpp
22
    \brief statistics tool for gaussian-assumption risk measures
23
*/
24
25
#ifndef quantlib_gaussian_statistics_h
26
#define quantlib_gaussian_statistics_h
27
28
#include <ql/math/distributions/normaldistribution.hpp>
29
#include <ql/math/statistics/generalstatistics.hpp>
30
31
namespace QuantLib {
32
33
    //! Statistics tool for gaussian-assumption risk measures
34
    /*! This class wraps a somewhat generic statistic tool and adds
35
        a number of gaussian risk measures (e.g.: value-at-risk, expected
36
        shortfall, etc.) based on the mean and variance provided by
37
        the underlying statistic tool.
38
    */
39
    template<class Stat>
40
    class GenericGaussianStatistics : public Stat {
41
      public:
42
        typedef typename Stat::value_type value_type;
43
0
        GenericGaussianStatistics() = default;
44
        explicit GenericGaussianStatistics(const Stat& s) : Stat(s) {}
45
        //! \name Gaussian risk measures
46
        //@{
47
        /*! returns the downside variance, defined as
48
            \f[ \frac{N}{N-1} \times \frac{ \sum_{i=1}^{N}
49
                \theta \times x_i^{2}}{ \sum_{i=1}^{N} w_i} \f],
50
            where \f$ \theta \f$ = 0 if x > 0 and
51
            \f$ \theta \f$ =1 if x <0
52
        */
53
        Real gaussianDownsideVariance() const {
54
            return gaussianRegret(0.0);
55
        }
56
57
        /*! returns the downside deviation, defined as the
58
            square root of the downside variance.
59
        */
60
        Real gaussianDownsideDeviation() const {
61
            return std::sqrt(gaussianDownsideVariance());
62
        }
63
64
        /*! returns the variance of observations below target
65
            \f[ \frac{\sum w_i (min(0, x_i-target))^2 }{\sum w_i}. \f]
66
67
            See Dembo, Freeman "The Rules Of Risk", Wiley (2001)
68
        */
69
        Real gaussianRegret(Real target) const;
70
71
72
        /*! gaussian-assumption y-th percentile, defined as the value x
73
            such that \f[ y = \frac{1}{\sqrt{2 \pi}}
74
                                      \int_{-\infty}^{x} \exp (-u^2/2) du \f]
75
        */
76
        Real gaussianPercentile(Real percentile) const;
77
        Real gaussianTopPercentile(Real percentile) const;
78
79
        //! gaussian-assumption Potential-Upside at a given percentile
80
        Real gaussianPotentialUpside(Real percentile) const;
81
82
        //! gaussian-assumption Value-At-Risk at a given percentile
83
        Real gaussianValueAtRisk(Real percentile) const;
84
85
        //! gaussian-assumption Expected Shortfall at a given percentile
86
        /*! Assuming a gaussian distribution it
87
            returns the expected loss in case that the loss exceeded
88
            a VaR threshold,
89
90
            \f[ \mathrm{E}\left[ x \;|\; x < \mathrm{VaR}(p) \right], \f]
91
92
            that is the average of observations below the
93
            given percentile \f$ p \f$.
94
            Also know as conditional value-at-risk.
95
96
            See Artzner, Delbaen, Eber and Heath,
97
            "Coherent measures of risk", Mathematical Finance 9 (1999)
98
        */
99
        Real gaussianExpectedShortfall(Real percentile) const;
100
101
        //! gaussian-assumption Shortfall (observations below target)
102
        Real gaussianShortfall(Real target) const;
103
104
        //! gaussian-assumption Average Shortfall (averaged shortfallness)
105
        Real gaussianAverageShortfall(Real target) const;
106
        //@}
107
    };
108
109
    //! default gaussian statistic tool
110
    typedef GenericGaussianStatistics<GeneralStatistics> GaussianStatistics;
111
112
113
    //! Helper class for precomputed distributions
114
    class StatsHolder {
115
      public:
116
        typedef Real value_type;
117
        StatsHolder(Real mean,
118
                    Real standardDeviation)
119
0
                    : mean_(mean), standardDeviation_(standardDeviation) {}
120
        ~StatsHolder() = default;
121
0
        Real mean() const { return mean_; }
122
0
        Real standardDeviation() const { return standardDeviation_; }
123
      private:
124
        Real mean_, standardDeviation_;
125
    };
126
127
128
    // inline definitions
129
130
    template<class Stat>
131
    inline
132
    Real GenericGaussianStatistics<Stat>::gaussianRegret(Real target) const {
133
        Real m = this->mean();
134
        Real std = this->standardDeviation();
135
        Real variance = std*std;
136
        CumulativeNormalDistribution gIntegral(m, std);
137
        NormalDistribution g(m, std);
138
        Real firstTerm = variance + m*m - 2.0*target*m + target*target;
139
        Real alfa = gIntegral(target);
140
        Real secondTerm = m - target;
141
        Real beta = variance*g(target);
142
        Real result = alfa*firstTerm - beta*secondTerm;
143
        return result/alfa;
144
    }
145
146
    /*! \pre percentile must be in range (0%-100%) extremes excluded */
147
    template<class Stat>
148
    inline Real GenericGaussianStatistics<Stat>::gaussianPercentile(
149
                                                     Real percentile) const {
150
151
        QL_REQUIRE(percentile>0.0,
152
                   "percentile (" << percentile << ") must be > 0.0");
153
        QL_REQUIRE(percentile<1.0,
154
                   "percentile (" << percentile << ") must be < 1.0");
155
156
        InverseCumulativeNormal gInverse(Stat::mean(),
157
                                         Stat::standardDeviation());
158
        return gInverse(percentile);
159
    }
160
161
    /*! \pre percentile must be in range (0%-100%) extremes excluded */
162
    template<class Stat>
163
    inline Real GenericGaussianStatistics<Stat>::gaussianTopPercentile(
164
                                                     Real percentile) const {
165
166
        return gaussianPercentile(1.0-percentile);
167
    }
168
169
    /*! \pre percentile must be in range [90%-100%) */
170
    template<class Stat>
171
    inline Real GenericGaussianStatistics<Stat>::gaussianPotentialUpside(
172
                                                    Real percentile) const {
173
174
        QL_REQUIRE(percentile<1.0 && percentile>=0.9,
175
                   "percentile (" << percentile << ") out of range [0.9, 1)");
176
177
        Real result = gaussianPercentile(percentile);
178
        // potential upside must be a gain, i.e., floored at 0.0
179
        return std::max<Real>(result, 0.0);
180
    }
181
182
183
    /*! \pre percentile must be in range [90%-100%) */
184
    template<class Stat>
185
    inline Real GenericGaussianStatistics<Stat>::gaussianValueAtRisk(
186
                                                    Real percentile) const {
187
188
        QL_REQUIRE(percentile<1.0 && percentile>=0.9,
189
                   "percentile (" << percentile << ") out of range [0.9, 1)");
190
191
        Real result = gaussianPercentile(1.0-percentile);
192
        // VAR must be a loss
193
        // this means that it has to be MIN(dist(1.0-percentile), 0.0)
194
        // VAR must also be a positive quantity, so -MIN(*)
195
        return -std::min<Real>(result, 0.0);
196
    }
197
198
199
    /*! \pre percentile must be in range [90%-100%) */
200
    template<class Stat>
201
    inline Real GenericGaussianStatistics<Stat>::gaussianExpectedShortfall(
202
                                                    Real percentile) const {
203
        QL_REQUIRE(percentile<1.0 && percentile>=0.9,
204
                   "percentile (" << percentile << ") out of range [0.9, 1)");
205
206
        Real m = this->mean();
207
        Real std = this->standardDeviation();
208
        InverseCumulativeNormal gInverse(m, std);
209
        Real var = gInverse(1.0-percentile);
210
        NormalDistribution g(m, std);
211
        Real result = m - std*std*g(var)/(1.0-percentile);
212
        // expectedShortfall must be a loss
213
        // this means that it has to be MIN(result, 0.0)
214
        // expectedShortfall must also be a positive quantity, so -MIN(*)
215
        return -std::min<Real>(result, 0.0);
216
    }
217
218
219
    template<class Stat>
220
    inline Real GenericGaussianStatistics<Stat>::gaussianShortfall(
221
                                                        Real target) const {
222
        CumulativeNormalDistribution gIntegral(this->mean(),
223
                                               this->standardDeviation());
224
        return gIntegral(target);
225
    }
226
227
228
    template<class Stat>
229
    inline Real GenericGaussianStatistics<Stat>::gaussianAverageShortfall(
230
                                                        Real target) const {
231
        Real m = this->mean();
232
        Real std = this->standardDeviation();
233
        CumulativeNormalDistribution gIntegral(m, std);
234
        NormalDistribution g(m, std);
235
        return ( (target-m) + std*std*g(target)/gIntegral(target) );
236
    }
237
238
}
239
240
241
#endif