57 {
58
59
60 Real n = 2.0 * std::log(dividendDiscount / riskFreeDiscount) / (
variance);
61 Real m = -2.0 * std::log(riskFreeDiscount) / (
variance);
62 Real bT = std::log(dividendDiscount / riskFreeDiscount);
63
64 Real qu, Su, h, Si;
65 switch (payoff->optionType()) {
66 case Option::Call:
67 qu = (-(n - 1.0) + std::sqrt(((n - 1.0) * (n - 1.0)) + 4.0 * m)) / 2.0;
68 Su = payoff->strike() / (1.0 - 1.0 / qu);
69 h = -(bT + 2.0 * std::sqrt(
variance)) * payoff->strike() / (Su - payoff->strike());
70 Si = payoff->strike() + (Su - payoff->strike()) * (1.0 - std::exp(h));
71 break;
72 case Option::Put:
73 qu = (-(n - 1.0) - std::sqrt(((n - 1.0) * (n - 1.0)) + 4.0 * m)) / 2.0;
74 Su = payoff->strike() / (1.0 - 1.0 / qu);
75 h = (bT - 2.0 * std::sqrt(
variance)) * payoff->strike() / (payoff->strike() - Su);
76 Si = Su + (payoff->strike() - Su) * std::exp(h);
77 break;
78 default:
79 QL_FAIL("unknown option type");
80 }
81
82 Real maxIterations = 100;
83
84 Real Q, LHS, RHS, bi;
85 Real forwardSi = Si * dividendDiscount / riskFreeDiscount;
86 Real d1 = (std::log(forwardSi / payoff->strike()) + 0.5 *
variance) / std::sqrt(
variance);
87 CumulativeNormalDistribution cumNormalDist;
88 Real K = (!close(riskFreeDiscount, 1.0, 1000))
89 ? -2.0 * std::log(riskFreeDiscount) / (
variance * (1.0 - riskFreeDiscount))
91 Real temp = blackFormula(payoff->optionType(), payoff->strike(), forwardSi, std::sqrt(
variance)) * riskFreeDiscount;
92 Real i;
93 switch (payoff->optionType()) {
94 case Option::Call:
95 Q = (-(n - 1.0) + std::sqrt(((n - 1.0) * (n - 1.0)) + 4 * K)) / 2;
96 LHS = Si - payoff->strike();
97 RHS = temp + (1 - dividendDiscount * cumNormalDist(d1)) * Si / Q;
98 bi = dividendDiscount * cumNormalDist(d1) * (1 - 1 / Q) +
99 (1 - dividendDiscount * cumNormalDist.derivative(d1) / std::sqrt(
variance)) / Q;
100 i = 0;
101 while ((std::fabs(LHS - RHS) / payoff->strike()) > tolerance) {
102 if (i > maxIterations)
103 QL_FAIL("Failed to find critical price after " << maxIterations << "iterations.");
104 Si = (payoff->strike() + RHS - bi * Si) / (1 - bi);
105 forwardSi = Si * dividendDiscount / riskFreeDiscount;
106 d1 = (std::log(forwardSi / payoff->strike()) + 0.5 *
variance) / std::sqrt(
variance);
107 LHS = Si - payoff->strike();
108 Real temp2 =
109 blackFormula(payoff->optionType(), payoff->strike(), forwardSi, std::sqrt(
variance)) * riskFreeDiscount;
110 RHS = temp2 + (1 - dividendDiscount * cumNormalDist(d1)) * Si / Q;
111 bi = dividendDiscount * cumNormalDist(d1) * (1 - 1 / Q) +
112 (1 - dividendDiscount * cumNormalDist.derivative(d1) / std::sqrt(
variance)) / Q;
113 i++;
114 }
115 break;
116 case Option::Put:
117 Q = (-(n - 1.0) - std::sqrt(((n - 1.0) * (n - 1.0)) + 4 * K)) / 2;
118 LHS = payoff->strike() - Si;
119 RHS = temp - (1 - dividendDiscount * cumNormalDist(-d1)) * Si / Q;
120 bi = -dividendDiscount * cumNormalDist(-d1) * (1 - 1 / Q) -
121 (1 + dividendDiscount * cumNormalDist.derivative(-d1) / std::sqrt(
variance)) / Q;
122 i = 0;
123 while ((std::fabs(LHS - RHS) / payoff->strike()) > tolerance) {
124 if (i > maxIterations)
125 QL_FAIL("Failed to find critical price after " << maxIterations << "iterations.");
126 Si = (payoff->strike() - RHS + bi * Si) / (1 + bi);
127 forwardSi = Si * dividendDiscount / riskFreeDiscount;
128 d1 = (std::log(forwardSi / payoff->strike()) + 0.5 *
variance) / std::sqrt(
variance);
129 LHS = payoff->strike() - Si;
130 Real temp2 =
131 blackFormula(payoff->optionType(), payoff->strike(), forwardSi, std::sqrt(
variance)) * riskFreeDiscount;
132 RHS = temp2 - (1 - dividendDiscount * cumNormalDist(-d1)) * Si / Q;
133 bi = -dividendDiscount * cumNormalDist(-d1) * (1 - 1 / Q) -
134 (1 + dividendDiscount * cumNormalDist.derivative(-d1) / std::sqrt(
variance)) / Q;
135 i++;
136 }
137 break;
138 default:
139 QL_FAIL("unknown option type");
140 }
141
142 return Si;
143}
RandomVariable variance(const RandomVariable &r)