QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
analyticdoublebarrierengine.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2015 Thema Consulting SA
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20#include <ql/exercise.hpp>
21#include <ql/pricingengines/barrier/analyticdoublebarrierengine.hpp>
22#include <ql/pricingengines/blackcalculator.hpp>
23#include <utility>
24
25namespace QuantLib {
26
28 ext::shared_ptr<GeneralizedBlackScholesProcess> process, int series)
29 : process_(std::move(process)), series_(series) {
31 }
32
34
35 QL_REQUIRE(arguments_.exercise->type() == Exercise::European,
36 "this engine handles only european options");
37
38 ext::shared_ptr<PlainVanillaPayoff> payoff =
39 ext::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff);
40 QL_REQUIRE(payoff, "non-plain payoff given");
41
42 Real strike = payoff->strike();
43 QL_REQUIRE(strike>0.0,
44 "strike must be positive");
45
46 Real spot = underlying();
47 QL_REQUIRE(spot > 0.0, "negative or null underlying given");
48 QL_REQUIRE(!triggered(spot), "barrier(s) already touched");
49
51
52 if (triggered(spot)) {
53 if (barrierType == DoubleBarrier::KnockIn)
54 results_.value = vanillaEquivalent(); // knocked in
55 else
56 results_.value = 0.0; // knocked out
57 } else {
58 switch (payoff->optionType()) {
59 case Option::Call:
60 switch (barrierType) {
63 break;
66 break;
69 QL_FAIL("unsupported double-barrier type: "
70 << barrierType);
71 default:
72 QL_FAIL("unknown double-barrier type: "
73 << barrierType);
74 }
75 break;
76 case Option::Put:
77 switch (barrierType) {
80 break;
83 break;
86 QL_FAIL("unsupported double-barrier type: "
87 << barrierType);
88 default:
89 QL_FAIL("unknown double-barrier type: "
90 << barrierType);
91 }
92 break;
93 default:
94 QL_FAIL("unknown type");
95 }
96 }
97 }
98
99
101 return process_->x0();
102 }
103
105 ext::shared_ptr<PlainVanillaPayoff> payoff =
106 ext::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff);
107 QL_REQUIRE(payoff, "non-plain payoff given");
108 return payoff->strike();
109 }
110
112 return process_->time(arguments_.exercise->lastDate());
113 }
114
116 return process_->blackVolatility()->blackVol(residualTime(), strike());
117 }
118
120 return volatility() * volatility();
121 }
122
124 return volatility() * std::sqrt(residualTime());
125 }
126
128 return arguments_.barrier_lo;
129 }
130
132 return arguments_.barrier_hi;
133 }
134
136 return process_->riskFreeRate()->zeroRate(residualTime(), Continuous,
138 }
139
141 return process_->riskFreeRate()->discount(residualTime());
142 }
143
145 return process_->dividendYield()->zeroRate(residualTime(),
147 }
148
150 return process_->dividendYield()->discount(residualTime());
151 }
152
154 return riskFreeRate() - dividendYield();
155 }
156
158 // Call KI equates to vanilla - callKO
159 ext::shared_ptr<StrikedTypePayoff> payoff =
160 ext::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff);
161 Real forwardPrice = underlying() * dividendDiscount() / riskFreeDiscount();
162 BlackCalculator black(payoff, forwardPrice, stdDeviation(), riskFreeDiscount());
163 Real vanilla = black.value();
164 if (vanilla < 0.0)
165 vanilla = 0.0;
166 return vanilla;
167 }
168
170 // N.B. for flat barriers mu3=mu1 and mu2=0
171 Real mu1 = 2 * costOfCarry() / volatilitySquared() + 1;
172 Real bsigma = (costOfCarry() + volatilitySquared() / 2.0) * residualTime() / stdDeviation();
173
174 Real acc1 = 0;
175 Real acc2 = 0;
176 for (int n = -series_ ; n <= series_ ; ++n) {
177 Real L2n = std::pow(barrierLo(), 2 * n);
178 Real U2n = std::pow(barrierHi(), 2 * n);
179 Real d1 = std::log( underlying()* U2n / (strike() * L2n) ) / stdDeviation() + bsigma;
180 Real d2 = std::log( underlying()* U2n / (barrierHi() * L2n) ) / stdDeviation() + bsigma;
181 Real d3 = std::log( std::pow(barrierLo(), 2 * n + 2) / (strike() * underlying() * U2n) ) / stdDeviation() + bsigma;
182 Real d4 = std::log( std::pow(barrierLo(), 2 * n + 2) / (barrierHi() * underlying() * U2n) ) / stdDeviation() + bsigma;
183
184 acc1 += std::pow( std::pow(barrierHi(), n) / std::pow(barrierLo(), n), mu1 ) *
185 (f_(d1) - f_(d2)) -
186 std::pow( std::pow(barrierLo(), n+1) / (std::pow(barrierHi(), n) * underlying()), mu1 ) *
187 (f_(d3) - f_(d4));
188
189 acc2 += std::pow( std::pow(barrierHi(), n) / std::pow(barrierLo(), n), mu1-2) *
190 (f_(d1 - stdDeviation()) - f_(d2 - stdDeviation())) -
191 std::pow( std::pow(barrierLo(), n+1) / (std::pow(barrierHi(), n) * underlying()), mu1-2 ) *
192 (f_(d3-stdDeviation()) - f_(d4-stdDeviation()));
193 }
194
195 Real rend = std::exp(-dividendYield() * residualTime());
196 Real kov = underlying() * rend * acc1 - strike() * riskFreeDiscount() * acc2;
197 return std::max(0.0, kov);
198 }
199
201 // Call KI equates to vanilla - callKO
202 return std::max(0.0, vanillaEquivalent() - callKO());
203 }
204
206 Real mu1 = 2 * costOfCarry() / volatilitySquared() + 1;
207 Real bsigma = (costOfCarry() + volatilitySquared() / 2.0) * residualTime() / stdDeviation();
208
209 Real acc1 = 0;
210 Real acc2 = 0;
211 for (int n = -series_ ; n <= series_ ; ++n) {
212 Real L2n = std::pow(barrierLo(), 2 * n);
213 Real U2n = std::pow(barrierHi(), 2 * n);
214 Real y1 = std::log( underlying()* U2n / (std::pow(barrierLo(), 2 * n + 1)) ) / stdDeviation() + bsigma;
215 Real y2 = std::log( underlying()* U2n / (strike() * L2n) ) / stdDeviation() + bsigma;
216 Real y3 = std::log( std::pow(barrierLo(), 2 * n + 2) / (barrierLo() * underlying() * U2n) ) / stdDeviation() + bsigma;
217 Real y4 = std::log( std::pow(barrierLo(), 2 * n + 2) / (strike() * underlying() * U2n) ) / stdDeviation() + bsigma;
218
219 acc1 += std::pow( std::pow(barrierHi(), n) / std::pow(barrierLo(), n), mu1-2) *
220 (f_(y1 - stdDeviation()) - f_(y2 - stdDeviation())) -
221 std::pow( std::pow(barrierLo(), n+1) / (std::pow(barrierHi(), n) * underlying()), mu1-2 ) *
222 (f_(y3-stdDeviation()) - f_(y4-stdDeviation()));
223
224 acc2 += std::pow( std::pow(barrierHi(), n) / std::pow(barrierLo(), n), mu1 ) *
225 (f_(y1) - f_(y2)) -
226 std::pow( std::pow(barrierLo(), n+1) / (std::pow(barrierHi(), n) * underlying()), mu1 ) *
227 (f_(y3) - f_(y4));
228
229 }
230
231 Real rend = std::exp(-dividendYield() * residualTime());
232 Real kov = strike() * riskFreeDiscount() * acc1 - underlying() * rend * acc2;
233 return std::max(0.0, kov);
234 }
235
237 // Put KI equates to vanilla - putKO
238 return std::max(0.0, vanillaEquivalent() - putKO());
239 }
240
241
242}
243
ext::shared_ptr< GeneralizedBlackScholesProcess > process_
AnalyticDoubleBarrierEngine(ext::shared_ptr< GeneralizedBlackScholesProcess > process, int series=5)
Black 1976 calculator class.
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:228
@ NoFrequency
null frequency
Definition: frequency.hpp:37
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
Real DiscountFactor
discount factor between dates
Definition: types.hpp:66
Real Volatility
volatility
Definition: types.hpp:78
Real Rate
interest rates
Definition: types.hpp:70
Definition: any.hpp:35
STL namespace.
@ KOKI
lower barrier KI, upper KO