20#include <ql/exercise.hpp>
21#include <ql/pricingengines/barrier/analyticdoublebarrierbinaryengine.hpp>
29 static Real PI= 3.14159265358979323846264338327950;
32 class AnalyticDoubleBarrierBinaryEngine_helper
36 AnalyticDoubleBarrierBinaryEngine_helper(
37 const ext::shared_ptr<GeneralizedBlackScholesProcess>& process,
38 const ext::shared_ptr<CashOrNothingPayoff> &payoff,
39 const DoubleBarrierOption::arguments &arguments):
48 Size maxIteration = 100,
49 Real requiredConvergence = 1e-8);
52 Size maxIteration = 1000,
53 Real requiredConvergence = 1e-8);
57 const ext::shared_ptr<GeneralizedBlackScholesProcess>& process_;
58 const ext::shared_ptr<CashOrNothingPayoff> &payoff_;
59 const DoubleBarrierOption::arguments &arguments_;
64 Real AnalyticDoubleBarrierBinaryEngine_helper::payoffAtExpiry(
66 Size maxIteration,
Real requiredConvergence)
69 "positive spot value required");
71 QL_REQUIRE(variance>=0.0,
72 "negative variance not allowed");
74 Time residualTime = process_->time(arguments_.exercise->lastDate());
75 QL_REQUIRE(residualTime>0.0,
76 "expiration time must be > 0");
79 Real cash = payoff_->cashPayoff();
80 Real barrier_lo = arguments_.barrier_lo;
81 Real barrier_hi = arguments_.barrier_hi;
83 Real sigmaq = variance/residualTime;
84 Real r = process_->riskFreeRate()->zeroRate(residualTime,
Continuous,
86 Real q = process_->dividendYield()->zeroRate(residualTime,
90 Real alpha = -0.5 * ( 2*b/sigmaq - 1);
91 Real beta = -0.25 * std::pow(( 2*b/sigmaq - 1), 2) - 2 * r/sigmaq;
92 Real Z = std::log(barrier_hi / barrier_lo);
93 Real factor = ((2*PI*cash)/std::pow(Z,2));
94 Real lo_alpha = std::pow(spot/barrier_lo, alpha);
95 Real hi_alpha = std::pow(spot/barrier_hi, alpha);
97 Real tot = 0, term = 0;
98 for (
Size i = 1 ; i < maxIteration ; ++i)
100 Real term1 = (lo_alpha-std::pow(-1.0, (
int)i)*hi_alpha) /
101 (std::pow(alpha,2)+std::pow(i*PI/Z, 2));
102 Real term2 = std::sin(i*PI/Z * std::log(spot/barrier_lo));
103 Real term3 = std::exp(-0.5*(std::pow(i*PI/Z,2)-beta)*variance);
104 term = factor * i * term1 * term2 * term3;
110 QL_REQUIRE(std::fabs(term) < requiredConvergence,
"serie did not converge sufficiently fast");
113 return std::max(tot, 0.0);
115 Rate discount = process_->riskFreeRate()->discount(
116 arguments_.exercise->lastDate());
117 QL_REQUIRE(discount>0.0,
118 "positive discount required");
119 return std::max(cash * discount - tot, 0.0);
124 Real AnalyticDoubleBarrierBinaryEngine_helper::payoffKIKO(
126 Size maxIteration,
Real requiredConvergence)
129 "positive spot value required");
131 QL_REQUIRE(variance>=0.0,
132 "negative variance not allowed");
134 Time residualTime = process_->time(arguments_.exercise->lastDate());
135 QL_REQUIRE(residualTime>0.0,
136 "expiration time must be > 0");
138 Real cash = payoff_->cashPayoff();
139 Real barrier_lo = arguments_.barrier_lo;
140 Real barrier_hi = arguments_.barrier_hi;
142 std::swap(barrier_lo, barrier_hi);
144 Real sigmaq = variance/residualTime;
145 Real r = process_->riskFreeRate()->zeroRate(residualTime,
Continuous,
147 Real q = process_->dividendYield()->zeroRate(residualTime,
151 Real alpha = -0.5 * ( 2*b/sigmaq - 1);
152 Real beta = -0.25 * std::pow(( 2*b/sigmaq - 1), 2) - 2 * r/sigmaq;
153 Real Z = std::log(barrier_hi / barrier_lo);
154 Real log_S_L = std::log(spot / barrier_lo);
156 Real tot = 0, term = 0;
157 for (
Size i = 1 ; i < maxIteration ; ++i)
159 Real factor = std::pow(i*PI/Z,2)-beta;
160 Real term1 = (beta - std::pow(i*PI/Z,2) * std::exp(-0.5*factor*variance)) / factor;
161 Real term2 = std::sin(i * PI/Z * log_S_L);
162 term = (2.0/(i*PI)) * term1 * term2;
165 tot += 1 - log_S_L / Z;
166 tot *= cash*std::pow(spot/barrier_lo, alpha);
169 QL_REQUIRE(fabs(term) < requiredConvergence,
"serie did not converge sufficiently fast");
171 return std::max(tot, 0.0);
175 ext::shared_ptr<GeneralizedBlackScholesProcess> process)
176 : process_(
std::move(process)) {
184 ext::shared_ptr<AmericanExercise> ex =
185 ext::dynamic_pointer_cast<AmericanExercise>(
187 QL_REQUIRE(ex,
"KIKO/KOKI options must have American exercise");
188 QL_REQUIRE(ex->dates()[0] <=
189 process_->blackVolatility()->referenceDate(),
190 "American option with window exercise not handled yet");
192 ext::shared_ptr<EuropeanExercise> ex =
193 ext::dynamic_pointer_cast<EuropeanExercise>(
195 QL_REQUIRE(ex,
"non-European exercise given");
197 ext::shared_ptr<CashOrNothingPayoff> payoff =
198 ext::dynamic_pointer_cast<CashOrNothingPayoff>(
arguments_.payoff);
199 QL_REQUIRE(payoff,
"a cash-or-nothing payoff must be given");
202 QL_REQUIRE(spot > 0.0,
"negative or null underlying given");
205 process_->blackVolatility()->blackVariance(
211 QL_REQUIRE(barrier_lo>0.0,
212 "positive low barrier value required");
213 QL_REQUIRE(barrier_hi>0.0,
214 "positive high barrier value required");
215 QL_REQUIRE(barrier_lo < barrier_hi,
216 "barrier_lo must be < barrier_hi");
221 "Unsupported barrier type");
224 switch (barrierType) {
226 if (spot <= barrier_lo || spot >= barrier_hi) {
238 if (spot <= barrier_lo || spot >= barrier_hi) {
250 if (spot >= barrier_hi) {
258 }
else if (spot <= barrier_lo) {
270 if (spot <= barrier_lo) {
278 }
else if (spot >= barrier_hi) {
290 AnalyticDoubleBarrierBinaryEngine_helper helper(
process_,
296 results_.
value = helper.payoffAtExpiry(spot, variance, barrierType);
301 results_.
value = helper.payoffKIKO(spot, variance, barrierType);
void calculate() const override
AnalyticDoubleBarrierBinaryEngine(ext::shared_ptr< GeneralizedBlackScholesProcess >)
ext::shared_ptr< GeneralizedBlackScholesProcess > process_
DoubleBarrier::Type barrierType
DoubleBarrierOption::results results_
DoubleBarrierOption::arguments arguments_
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
@ NoFrequency
null frequency
Real Time
continuous quantity with 1-year units
std::size_t Size
size of a container
@ KOKI
lower barrier KI, upper KO