114 {
115
116 QL_REQUIRE(
arguments_.exercise->type() == Exercise::European,
"not an European option");
117
118 Option::Type optionType =
arguments_.optionType;
119 Real phi = optionType == Option::Call ? 1.0 : -1.0;
120
122 QL_REQUIRE(strike >= 0, "non-negative strike expected");
123
125
128
129 Real s1 =
process1_->stateVariable()->value();
130 Real s2 =
process2_->stateVariable()->value();
133
134 Real v1 =
process1_->blackVolatility()->blackVol(
136 Real v2 =
process2_->blackVolatility()->blackVol(
138
139 Real riskFreeRate1 =
process1_->riskFreeRate()->zeroRate(
142 Continuous, NoFrequency);
143 Real riskFreeRate2 =
process2_->riskFreeRate()->zeroRate(
146 Continuous, NoFrequency);
147 Real dividendYield1 =
process1_->dividendYield()->zeroRate(
149 process1_->dividendYield()->dayCounter(),
150 Continuous, NoFrequency);
151 Real dividendYield2 =
process2_->dividendYield()->zeroRate(
153 process2_->dividendYield()->dayCounter(),
154 Continuous, NoFrequency);
155
156 Real m1 = riskFreeRate1 - dividendYield1;
157 Real m2 = riskFreeRate2 - dividendYield2;
158
159 Real k = strike;
160
161 Real res = 0.0;
162
163 bool hasBarrier = (
arguments_.knockInPrice != Null<Real>()) || (
arguments_.knockOutPrice != Null<Real>());
165 if (hasBarrier) {
166 Real my = (m2 - 0.5 * v2 * v2) * fixingTime;
167 Real vy = v2 * std::sqrt(fixingTime);
168
169 Real precision = 1.0e-6;
170
171 Real upperBound = Null<Real>();
172 Real lowerBound = Null<Real>();
173 if (
arguments_.knockOutPrice != Null<Real>()) {
174 Real koPrice = fx2 *
arguments_.knockOutPrice;
175
176
177
178 upperBound = (std::log(koPrice / s2) - my) / ( vy * M_SQRT2);
179
180 if (
arguments_.knockInPrice == Null<Real>()) {
181
182 lowerBound = -2 * std::fabs(upperBound);
183 while(
integrand(lowerBound, phi, k, m1, m2, v1, v2, s1, s2, i1, i2, fixingTime) > precision)
184 lowerBound *=2.0;
185 }
186 }
187
188 if (
arguments_.knockInPrice != Null<Real>()) {
190
191
192
193 lowerBound = (std::log(kiPrice / s2) - my) / ( vy * M_SQRT2);
194
195 if (
arguments_.knockOutPrice == Null<Real>()) {
196
197 upperBound = 2 * std::fabs(lowerBound);
198 while(
integrand(upperBound, phi, k, m1, m2, v1, v2, s1, s2, i1, i2, fixingTime) > precision)
199 upperBound *=2.0;
200 }
201 }
202
203 QuantLib::ext::shared_ptr<Integrator> integratorBounded = QuantLib::ext::make_shared<GaussKronrodNonAdaptive>(precision, 1000000, 1.0);
204
205 QL_REQUIRE(upperBound != Null<Real>(), "AnalyticOutperformanceOptionEngine: expected valid upper bound.");
206 QL_REQUIRE(lowerBound != Null<Real>(), "AnalyticOutperformanceOptionEngine: expected valid lower bound.");
207 QL_REQUIRE(upperBound > lowerBound, "incorrect knock in levels provided");
208 integral += (*integratorBounded)(
integrand_f(
this, phi, k, m1, m2, v1, v2, s1, s2, i1, i2, fixingTime), lowerBound, upperBound);
209
210 } else {
211 QuantLib::ext::shared_ptr<GaussianQuadrature> integrator = QuantLib::ext::make_shared<GaussHermiteIntegration>(
integrationPoints_);
213 (*integrator)(
integrand_f(
this, phi, k, m1, m2, v1, v2, s1, s2, i1, i2, fixingTime));
214 }
215
217 DiscountFactor riskFreeDiscount =
219
221
222 Real variance1 =
process1_->blackVolatility()->blackVariance(
224 Real variance2 =
process2_->blackVolatility()->blackVariance(
226 Real
variance = variance1 + variance2 - 2 *
rho(fixingTime) * std::sqrt(variance1)*std::sqrt(variance2);
228 results_.standardDeviation = stdDev;
229
230 results_.additionalResults[
"spot1"] = s1;
231 results_.additionalResults[
"spot2"] = s2;
232 results_.additionalResults[
"fx1"] = fx1;
233 results_.additionalResults[
"fx2"] = fx2;
234 results_.additionalResults[
"blackVol1"] = v1;
235 results_.additionalResults[
"blackVol2"] = v2;
236 results_.additionalResults[
"correlation"] =
rho(fixingTime);
237 results_.additionalResults[
"strike"] = strike;
238 results_.additionalResults[
"residualTime"] = fixingTime;
239 results_.additionalResults[
"riskFreeRate1"] = riskFreeRate1;
240 results_.additionalResults[
"riskFreeRate2"] = riskFreeRate2;
241 results_.additionalResults[
"dividendYield1"] = dividendYield1;
242 results_.additionalResults[
"dividendYield2"] = dividendYield2;
243
244}
const Instrument::results * results_
Real integral(const CrossAssetModel &model, const E &e, const Real a, const Real b)
RandomVariable variance(const RandomVariable &r)
Swap::arguments * arguments_