32 std::vector<ext::shared_ptr<GeneralizedBlackScholesProcess> > processes,
34 : n_(processes.size()),
35 processes_(
std::move(processes)),
38 QL_REQUIRE(
n_ > 0,
"No Black-Scholes process is given.");
40 "process and correlation matrix must have the same size.");
43 [
this](
const auto& p) { registerWith(p); });
47 const ext::shared_ptr<EuropeanExercise> exercise =
49 QL_REQUIRE(exercise,
"not an European exercise");
50 const Date maturityDate = exercise->lastDate();
52 const ext::shared_ptr<AverageBasketPayoff> avgPayoff =
53 (ext::dynamic_pointer_cast<AverageBasketPayoff>(
arguments_.
payoff) !=
nullptr)
55 : (ext::dynamic_pointer_cast<SpreadBasketPayoff>(
arguments_.
payoff) !=
nullptr)
56 ? ext::make_shared<AverageBasketPayoff>(
57 ext::dynamic_pointer_cast<SpreadBasketPayoff>(
61 : ext::shared_ptr<AverageBasketPayoff>();
63 QL_REQUIRE(avgPayoff,
"average or spread basket payoff expected");
65 const Array weights = avgPayoff->weights();
67 "wrong number of weights arguments in payoff");
75 std::vector< std::tuple<Real, Size, Real, Real, Real> > p;
78 for (
Size i=0; i <
n_; ++i)
79 p.emplace_back(weights[i], i,
s[i], dq[i],
v[i]);
81 const ext::shared_ptr<PlainVanillaPayoff>
payoff =
82 ext::dynamic_pointer_cast<PlainVanillaPayoff>(avgPayoff->basePayoff());
86 if (
payoff->strike() < 0.0) {
87 p.emplace_back(1.0,
n_, -
payoff->strike(), dr0, 0.0);
89 for (
Size i=0; i <
n_; ++i) {
98 const Real strike = std::max(0.0,
payoff->strike());
101 std::sort(p.begin(), p.end(), std::greater<>());
103 const Size M = std::distance(
105 std::lower_bound(p.begin(), p.end(),
Real(0),
106 [](
const auto& p,
const Real& value) ->
bool {
return std::get<0>(p) > value;} )
109 QL_REQUIRE(M > 0,
"at least one positive asset weight must be given");
110 QL_REQUIRE(M < p.size(),
"at least one negative asset weight must be given");
112 const Size N = p.size() - M;
115 Array _s(N+1), _dq(N+1), _v(N+1);
119 for (
Size i=0; i < M; ++i) {
120 vol[i] = std::sqrt(std::get<4>(p[i]));
121 F[i] = std::get<0>(p[i])*std::get<2>(p[i])*std::get<3>(p[i])/dr0;
124 const Real S0 = std::accumulate(
125 p.begin(), p.begin()+M,
Real(0.0),
126 [](
const Real& value,
const auto& p) ->
Real {
127 return value + std::get<0>(p)*std::get<2>(p);
129 const Real F0 = std::accumulate(
F.begin(),
F.end(),
Real(0.0));
133 for (
Size i=0; i < M; ++i)
134 for (
Size j=0; j < M; ++j)
135 v_s += vol[i]*vol[j]*
F[i]*
F[j]
136 *
rho[std::get<1>(p[i])][std::get<1>(p[j])];
139 _s[0] = S0; _dq[0] = dq_S0; _v[0] = v_s;
143 for (
Size i=0; i < N; ++i) {
145 for (
Size j=0; j < M; ++j)
146 rhoHat +=
rho[std::get<1>(p[M+i])][std::get<1>(p[j])]*vol[j]*
F[j];
148 nRho[i+1][0] = nRho[0][i+1]
149 = std::min(1.0, std::max(-1.0, rhoHat/(std::sqrt(v_s)*F0)));
153 _s[0] = std::abs(std::get<0>(p[0])*std::get<2>(p[0]));
154 _dq[0] = std::get<3>(p[0]);
155 _v[0] = std::get<4>(p[0]);
156 for (
Size i=0; i < N+1; ++i)
157 nRho[0][i] = nRho[i][0] =
rho[std::get<1>(p[i])][std::get<1>(p[0])];
160 for (
Size i=0; i < N; ++i) {
161 _s[i+1] = std::abs(std::get<0>(p[M+i])*std::get<2>(p[M+i]));
162 _dq[i+1] = std::get<3>(p[M+i]);
163 _v[i+1] = std::get<4>(p[M+i]);
165 const Size idx = std::get<1>(p[M+i]);
166 for (
Size j=0; j < N; ++j)
167 nRho[i+1][j+1] =
rho[idx][std::get<1>(p[M+j])];
176 const Real fwd = _s[0]*_dq[0] - dr0*strike
177 - std::inner_product(_s.begin()+1, _s.end(), _dq.begin()+1,
Real(0.0));
183 const Real psi = 1.0/
184 (1.0 + std::inner_product(
186 const Real sqrtPsi = std::sqrt(psi);
191 const Real vFv = std::inner_product(
193 const Real J_1 = psi*sqrtPsi*(psi*u*u - 1.0) * vFv * n_uSqrtPsi;
195 const Real vFFv = std::inner_product(
197 const Real J_2 = u*psi*sqrtPsi*n_uSqrtPsi*(
200 - 10.0*psi*psi*psi*u*u + 15*psi*psi)
201 + vFFv * (4*psi*psi*u*u - 12*psi)
204 return J_0 + J_1 - 0.5*J_2;
211 const Array mu = x +
Log(dq/dr) - 0.5 *
v;
214 const Real R = std::accumulate(
222 for (
Size i=0; i < N; ++i)
224 const Array sig10(
rho.row_begin(0)+1,
rho.row_end(0));
230 QL_REQUIRE(sig_xy > 0.0,
"approximation loses validity");
231 const Real sqSig_xy = std::sqrt(sig_xy);
233 const Real a = -0.5/sqSig_xy;
235 for (
Size i=1; i <= N; ++i)
236 for (
Size j=i; j <= N; ++j)
237 E(i-1, j-1) = E(j-1, i-1) =
241 const Matrix F = sqSig11*E*sqSig11;
243 Real trF(0), trF2(0);
244 for (
Size i=0; i < N; ++i) {
248 F.row_begin(i)+i+1,
F.row_end(i),
Real(0),
253 const Real c = -(std::log(R + K) - mu[0])/(
nu[0]*sqSig_xy);
255 const Array d = (sig11Inv10
258 const Array Esig10 = E*sig10;
259 const Matrix Esig11 = E*sig11;
260 const Array sig11d = sig11*
d;
267 for (
Size k=1; k < N+1; ++k)
268 C[k] = c + trF +
nu[k]*sig11d[k-1] +
squared(
nu[k])
272 std::vector<Array> D(N+2);
273 D[0] = sqSig11*(
d + 2*
nu[0]*Esig10);
275 for (
Size k=1; k < N+1; ++k)
279 for (
Size k=0; k < N+2; ++k)
280 std::copy(D[k].begin(), D[k].end(), DM.
row_begin(k));
284 Real npv = dr*std::exp(mu[0] + 0.5*
squared(
nu[0])) *
I(C[0], trF2, DM, DF, 0)
285 - K*dr*
I(C.
back(), trF2, DM, DF, N+1);
287 for (
Size k=1; k <= N; ++k)
288 npv -= dr*std::exp(mu[k] + 0.5*
squared(
nu[k])) * I(C[k], trF2, DM, DF, k);
1-D array used in linear algebra.
const_iterator end() const
Size size() const
dimension of the array
const_iterator begin() const
Cumulative normal distribution function.
void calculate() const override
DengLiZhouBasketEngine(std::vector< ext::shared_ptr< GeneralizedBlackScholesProcess > > processes, Matrix rho)
const std::vector< ext::shared_ptr< GeneralizedBlackScholesProcess > > processes_
static Real I(Real u, Real tF2, const Matrix &D, const Matrix &DF, Size i)
static Real calculate_vanilla_call(const Array &s, DiscountFactor dr, const Array &dq, const Array &v, const Matrix &rho, Time T)
BasketOption::results results_
BasketOption::arguments arguments_
Matrix used in linear algebra.
const_row_iterator row_begin(Size i) const
const_column_iterator column_begin(Size i) const
const_row_iterator row_end(Size i) const
const_column_iterator column_end(Size i) const
Normal distribution function.
ext::shared_ptr< Exercise > exercise
ext::shared_ptr< Payoff > payoff
Deng, Li and Zhou: Closed-Form Approximation for Spread option pricing.
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Option exercise classes and payoff function.
std::function< Real(Real)> b
Real DiscountFactor
discount factor between dates
std::size_t Size
size of a container
ext::shared_ptr< QuantLib::Payoff > payoff
functionals and combinators not included in the STL
Matrix pseudoSqrt(const Matrix &matrix, SalvagingAlgorithm::Type sa)
Array CholeskySolveFor(const Matrix &L, const Array &b)
Matrix CholeskyDecomposition(const Matrix &S, bool flexible)
Array Log(const Array &v)
Array Exp(const Array &v)
Array Sqrt(const Array &v)
Real DotProduct(const Array &v1, const Array &v2)
normal, cumulative and inverse cumulative distributions
ext::shared_ptr< BlackVolTermStructure > v
pseudo square root of a real symmetric matrix