QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
bivariatestudenttdistribution.cpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2014 Michal Kaut
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 <http://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
21
22namespace QuantLib {
23
24 namespace {
25
26 Real epsilon = 1.0e-8;
27
28 Real sign(Real val) {
29 return val == 0.0 ? 0.0
30 : (val < 0.0 ? -1.0 : 1.0);
31 }
32
33 /* unlike the atan2 function in C++ that gives results in
34 [-pi,pi], this returns a value in [0, 2*pi]
35 */
36 Real arctan(Real x, Real y) {
37 Real res = std::atan2(x, y);
38 return res >= 0.0 ? res : res + 2 * M_PI;
39 }
40
41 // function x(m,h,k) defined on top of page 155
42 Real f_x(Real m, Real h, Real k, Real rho) {
43 Real unCor = 1 - rho*rho;
44 Real sub = std::pow(h - rho * k, 2);
45 Real denom = sub + unCor * (m + k*k);
46 if (denom < epsilon)
47 return 0.0; // limit case for rho = +/-1.0
48 return sub / (sub + unCor * (m + k*k));
49 }
50
51 // this calculates the cdf
52 Real P_n(Real h, Real k, Natural n, Real rho) {
53 Real unCor = 1.0 - rho*rho;
54
55 Real div = 4 * std::sqrt(n * M_PI);
56 Real xHK = f_x(n, h, k, rho);
57 Real xKH = f_x(n, k, h, rho);
58 Real divH = 1 + h*h / n;
59 Real divK = 1 + k*k / n;
60 Real sgnHK = sign(h - rho * k);
61 Real sgnKH = sign(k - rho * h);
62
63 if (n % 2 == 0) { // n is even, equation (10)
64 // first line of (10)
65 Real res = arctan(std::sqrt(unCor), -rho) / M_TWOPI;
66
67 // second line of (10)
68 Real dgM = 2 * (1 - xHK); // multiplier for dgj
69 Real gjM = sgnHK * 2 / M_PI; // multiplier for g_j
70 // initializations for j = 1:
71 Real f_j = std::sqrt(M_PI / divK);
72 Real g_j = 1 + gjM * arctan(std::sqrt(xHK), std::sqrt(1 - xHK));
73 Real sum = f_j * g_j;
74 if (n >= 4) {
75 // different formulas for j = 2:
76 f_j *= 0.5 / divK; // (2 - 1.5) / (Real) (2 - 1) / divK;
77 Real dgj = gjM * std::sqrt(xHK * (1 - xHK));
78 g_j += dgj;
79 sum += f_j * g_j;
80 // and then the loop for the rest of the j's:
81 for (Natural j = 3; j <= n / 2; ++j) {
82 f_j *= (j - 1.5) / (Real) (j - 1) / divK;
83 dgj *= (Real) (j - 2) / (2 * j - 3) * dgM;
84 g_j += dgj;
85 sum += f_j * g_j;
86 }
87 }
88 res += k / div * sum;
89
90 // third line of (10)
91 dgM = 2 * (1 - xKH);
92 gjM = sgnKH * 2 / M_PI;
93 // initializations for j = 1:
94 f_j = std::sqrt(M_PI / divH);
95 g_j = 1 + gjM * arctan(std::sqrt(xKH), std::sqrt(1 - xKH));
96 sum = f_j * g_j;
97 if (n >= 4) {
98 // different formulas for j = 2:
99 f_j *= 0.5 / divH; // (2 - 1.5) / (Real) (2 - 1) / divK;
100 Real dgj = gjM * std::sqrt(xKH * (1 - xKH));
101 g_j += dgj;
102 sum += f_j * g_j;
103 // and then the loop for the rest of the j's:
104 for (Natural j = 3; j <= n / 2; ++j) {
105 f_j *= (j - 1.5) / (Real) (j - 1) / divH;
106 dgj *= (Real) (j - 2) / (2 * j - 3) * dgM;
107 g_j += dgj;
108 sum += f_j * g_j;
109 }
110 }
111 res += h / div * sum;
112 return res;
113
114 } else { // n is odd, equation (11)
115 // first line of (11)
116 Real hk = h * k;
117 Real hkcn = hk + rho * n;
118 Real sqrtExpr = std::sqrt(h*h - 2 * rho * hk + k*k + n * unCor);
119 Real res = arctan(std::sqrt(Real(n)) * (-(h + k) * hkcn - (hk - n) * sqrtExpr),
120 (hk - n) * hkcn - n * (h + k) * sqrtExpr ) / M_TWOPI;
121
122 if (n > 1) {
123 // second line of (11)
124 Real mult = (1 - xHK) / 2;
125 // initializations for j = 1:
126 Real f_j = 2 / std::sqrt(M_PI) / divK;
127 Real dgj = sgnHK * std::sqrt(xHK);
128 Real g_j = 1 + dgj;
129 Real sum = f_j * g_j;
130 // and then the loop for the rest of the j's:
131 for (Natural j = 2; j <= (n - 1) / 2; ++j) {
132 f_j *= (Real) (j - 1) / (j - 0.5) / divK;
133 dgj *= (Real) (2 * j - 3) / (j - 1) * mult;
134 g_j += dgj;
135 sum += f_j * g_j;
136 }
137 res += k / div * sum;
138
139 // third line of (11)
140 mult = (1 - xKH) / 2;
141 // initializations for j = 1:
142 f_j = 2 / std::sqrt(M_PI) / divH;
143 dgj = sgnKH * std::sqrt(xKH);
144 g_j = 1 + dgj;
145 sum = f_j * g_j;
146 // and then the loop for the rest of the j's:
147 for (Natural j = 2; j <= (n - 1) / 2; ++j) {
148 f_j *= (Real) (j - 1) / (j - 0.5) / divH;
149 dgj *= (Real) (2 * j - 3) / (j - 1) * mult;
150 g_j += dgj;
151 sum += f_j * g_j;
152 }
153 res += h / div * sum;
154 }
155 return res;
156 }
157 }
158
159 }
160
161
164 Real rho)
165 : n_(n), rho_(rho) {}
166
168 Real y) const {
169 return P_n(x, y, n_, rho_);
170 }
171
172}
Bivariate Student t-distribution.
QL_REAL Real
real number
Definition: types.hpp:50
unsigned QL_INTEGER Natural
positive integer
Definition: types.hpp:43
Real rho
#define M_TWOPI
#define M_PI
Definition: any.hpp:35