21#include <ql/currencies/exchangeratemanager.hpp>
22#include <ql/exercise.hpp>
23#include <ql/math/distributions/normaldistribution.hpp>
24#include <ql/pricingengines/blackformula.hpp>
25#include <ql/math/integrals/gaussianquadratures.hpp>
26#include <ql/math/integrals/simpsonintegral.hpp>
27#include <ql/math/integrals/kronrodintegral.hpp>
37 if (fxIndex->useQuote()) {
38 tmp = fxIndex->fxQuote()->value();
40 tmp = ExchangeRateManager::instance()
41 .lookup(fxIndex->sourceCurrency(), fxIndex->targetCurrency())
48 const ext::shared_ptr<GeneralizedBlackScholesProcess>& process1,
49 const ext::shared_ptr<GeneralizedBlackScholesProcess>& process2,
50 const Handle<CorrelationTermStructure>& correlation, Size integrationPoints)
51 : process1_(process1), process2_(process2), correlationCurve_(correlation), integrationPoints_(integrationPoints) {
56class AnalyticOutperformanceOptionEngine::integrand_f {
60 Real phi, Real k, Real m1, Real m2, Real v1, Real v2, Real s1, Real s2, Real i1, Real i2, Real fixingTime)
61 : pricer(pricer), phi_(phi), k_(k), m1_(m1), m2_(m2), v1_(v1), v2_(v2), s1_(s1), s2_(s2), i1_(i1), i2_(i2), fixingTime_(fixingTime) {}
62 Real operator()(Real x)
const {
63 return pricer->
integrand(x, phi_, k_, m1_, m2_, v1_, v2_, s1_, s2_, i1_, i2_, fixingTime_);
80Real
AnalyticOutperformanceOptionEngine::integrand(
const Real x, Real phi, Real k, Real m1, Real m2, Real v1, Real v2, Real s1, Real s2, Real i1, Real i2, Real fixingTime)
const {
89 CumulativeNormalDistribution cnd;
92 k - b * s2 * std::exp((m2 - 0.5 * v2 * v2) * fixingTime +
93 v2 * std::sqrt(fixingTime) * v);
96 phi * (std::log(a * s1 / h) +
97 (m1 + (0.5 -
rho(fixingTime) *
rho(fixingTime)) * v1 * v1) * fixingTime +
98 rho(fixingTime) * v1 * std::sqrt(fixingTime) * v) /
99 (v1 * std::sqrt(fixingTime * (1.0 -
rho(fixingTime) *
rho(fixingTime)))));
101 phi * (std::log(a * s1 / h) +
102 (m1 - 0.5 * v1 * v1) * fixingTime +
103 rho(fixingTime) * v1 * std::sqrt(fixingTime) * v) /
104 (v1 * std::sqrt(fixingTime * (1.0 -
rho(fixingTime) *
rho(fixingTime)))));
105 Real f = a * phi * s1 *
106 std::exp(m1 * fixingTime -
107 0.5 *
rho(fixingTime) *
rho(fixingTime) * v1 * v1 * fixingTime +
108 rho(fixingTime) * v1 * std::sqrt(fixingTime) * v) *
111 return std::exp(-x * x) * f;
116 QL_REQUIRE(
arguments_.exercise->type() == Exercise::European,
"not an European option");
118 Option::Type optionType =
arguments_.optionType;
119 Real phi = optionType == Option::Call ? 1.0 : -1.0;
122 QL_REQUIRE(strike >= 0,
"non-negative strike expected");
129 Real s1 =
process1_->stateVariable()->value();
130 Real s2 =
process2_->stateVariable()->value();
134 Real v1 =
process1_->blackVolatility()->blackVol(
136 Real v2 =
process2_->blackVolatility()->blackVol(
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);
156 Real m1 = riskFreeRate1 - dividendYield1;
157 Real m2 = riskFreeRate2 - dividendYield2;
163 bool hasBarrier = (
arguments_.knockInPrice != Null<Real>()) || (
arguments_.knockOutPrice != Null<Real>());
166 Real my = (m2 - 0.5 * v2 * v2) * fixingTime;
167 Real
vy = v2 * std::sqrt(fixingTime);
169 Real precision = 1.0e-6;
171 Real upperBound = Null<Real>();
172 Real lowerBound = Null<Real>();
173 if (
arguments_.knockOutPrice != Null<Real>()) {
174 Real koPrice = fx2 *
arguments_.knockOutPrice;
178 upperBound = (std::log(koPrice / s2) - my) / (
vy * M_SQRT2);
180 if (
arguments_.knockInPrice == Null<Real>()) {
182 lowerBound = -2 * std::fabs(upperBound);
183 while(
integrand(lowerBound, phi, k, m1, m2, v1, v2, s1, s2, i1, i2, fixingTime) > precision)
188 if (
arguments_.knockInPrice != Null<Real>()) {
193 lowerBound = (std::log(kiPrice / s2) - my) / (
vy * M_SQRT2);
195 if (
arguments_.knockOutPrice == Null<Real>()) {
197 upperBound = 2 * std::fabs(lowerBound);
198 while(
integrand(upperBound, phi, k, m1, m2, v1, v2, s1, s2, i1, i2, fixingTime) > precision)
203 QuantLib::ext::shared_ptr<Integrator> integratorBounded = QuantLib::ext::make_shared<GaussKronrodNonAdaptive>(precision, 1000000, 1.0);
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);
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));
217 DiscountFactor riskFreeDiscount =
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;
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;
const Instrument::results * results_
Real integral(const CrossAssetModel &model, const E &e, const Real a, const Real b)
RandomVariable variance(const RandomVariable &r)
JY INF index variance component.
Swap::arguments * arguments_