QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
blackcalculator.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2003, 2004, 2005, 2006 Ferdinando Ametrano
5 Copyright (C) 2006 StatPro Italia srl
6
7 This file is part of QuantLib, a free-software/open-source library
8 for financial quantitative analysts and developers - http://quantlib.org/
9
10 QuantLib is free software: you can redistribute it and/or modify it
11 under the terms of the QuantLib license. You should have received a
12 copy of the license along with this program; if not, please email
13 <quantlib-dev@lists.sf.net>. The license is also available online at
14 <http://quantlib.org/license.shtml>.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the license for more details.
19*/
20
21#include <ql/pricingengines/blackcalculator.hpp>
22#include <ql/math/distributions/normaldistribution.hpp>
23#include <ql/math/comparison.hpp>
24
25namespace QuantLib {
26
27 class BlackCalculator::Calculator : public AcyclicVisitor,
28 public Visitor<Payoff>,
29 public Visitor<PlainVanillaPayoff>,
30 public Visitor<CashOrNothingPayoff>,
31 public Visitor<AssetOrNothingPayoff>,
32 public Visitor<GapPayoff> {
33 private:
34 BlackCalculator& black_;
35 public:
36 explicit Calculator(BlackCalculator& black) : black_(black) {}
37 void visit(Payoff&) override;
38 void visit(PlainVanillaPayoff&) override;
39 void visit(CashOrNothingPayoff&) override;
40 void visit(AssetOrNothingPayoff&) override;
41 void visit(GapPayoff&) override;
42 };
43
44
45 BlackCalculator::BlackCalculator(const ext::shared_ptr<StrikedTypePayoff>& p,
46 Real forward,
47 Real stdDev,
48 Real discount)
49 : strike_(p->strike()), forward_(forward), stdDev_(stdDev),
50 discount_(discount), variance_(stdDev*stdDev) {
51 initialize(p);
52 }
53
55 Real strike,
56 Real forward,
57 Real stdDev,
58 Real discount)
59 : strike_(strike), forward_(forward), stdDev_(stdDev),
60 discount_(discount), variance_(stdDev*stdDev) {
61 initialize(ext::shared_ptr<StrikedTypePayoff>(new
62 PlainVanillaPayoff(optionType, strike)));
63 }
65 void BlackCalculator::initialize(const ext::shared_ptr<StrikedTypePayoff>& p) {
66 QL_REQUIRE(strike_>=0.0,
67 "strike (" << strike_ << ") must be non-negative");
68 QL_REQUIRE(forward_>0.0,
69 "forward (" << forward_ << ") must be positive");
70 //QL_REQUIRE(displacement_>=0.0,
71 // "displacement (" << displacement_ << ") must be non-negative");
72 QL_REQUIRE(stdDev_>=0.0,
73 "stdDev (" << stdDev_ << ") must be non-negative");
74 QL_REQUIRE(discount_>0.0,
75 "discount (" << discount_ << ") must be positive");
76
77 if (stdDev_>=QL_EPSILON) {
78 if (close(strike_, 0.0)) {
81 cum_d1_ = 1.0;
82 cum_d2_ = 1.0;
83 n_d1_ = 0.0;
84 n_d2_ = 0.0;
85 } else {
86 d1_ = std::log(forward_/strike_)/stdDev_ + 0.5*stdDev_;
87 d2_ = d1_-stdDev_;
89 cum_d1_ = f(d1_);
90 cum_d2_ = f(d2_);
91 n_d1_ = f.derivative(d1_);
92 n_d2_ = f.derivative(d2_);
93 }
94 } else {
95 if (close(forward_, strike_)) {
96 d1_ = 0;
97 d2_ = 0;
98 cum_d1_ = 0.5;
99 cum_d2_ = 0.5;
100 n_d1_ = M_SQRT_2 * M_1_SQRTPI;
101 n_d2_ = M_SQRT_2 * M_1_SQRTPI;
102 } else if (forward_>strike_) {
105 cum_d1_ = 1.0;
106 cum_d2_ = 1.0;
107 n_d1_ = 0.0;
108 n_d2_ = 0.0;
109 } else {
112 cum_d1_ = 0.0;
113 cum_d2_ = 0.0;
114 n_d1_ = 0.0;
115 n_d2_ = 0.0;
116 }
117 }
118
119 x_ = strike_;
120 DxDstrike_ = 1.0;
121
122 // the following one will probably disappear as soon as
123 // super-share will be properly handled
124 DxDs_ = 0.0;
125
126 // this part is always executed.
127 // in case of plain-vanilla payoffs, it is also the only part
128 // which is executed.
129 switch (p->optionType()) {
130 case Option::Call:
131 alpha_ = cum_d1_;// N(d1)
132 DalphaDd1_ = n_d1_;// n(d1)
133 beta_ = -cum_d2_;// -N(d2)
134 DbetaDd2_ = - n_d2_;// -n(d2)
135 break;
136 case Option::Put:
137 alpha_ = -1.0+cum_d1_;// -N(-d1)
138 DalphaDd1_ = n_d1_;// n( d1)
139 beta_ = 1.0-cum_d2_;// N(-d2)
140 DbetaDd2_ = - n_d2_;// -n( d2)
141 break;
142 default:
143 QL_FAIL("invalid option type");
144 }
145
146 // now dispatch on type.
147
148 Calculator calc(*this);
149 p->accept(calc);
150 }
151
152 void BlackCalculator::Calculator::visit(Payoff& p) {
153 QL_FAIL("unsupported payoff type: " << p.name());
154 }
155
156 void BlackCalculator::Calculator::visit(PlainVanillaPayoff&) {}
157
158 void BlackCalculator::Calculator::visit(CashOrNothingPayoff& payoff) {
159 black_.alpha_ = black_.DalphaDd1_ = 0.0;
160 black_.x_ = payoff.cashPayoff();
161 black_.DxDstrike_ = 0.0;
162 switch (payoff.optionType()) {
163 case Option::Call:
164 black_.beta_ = black_.cum_d2_;
165 black_.DbetaDd2_ = black_.n_d2_;
166 break;
167 case Option::Put:
168 black_.beta_ = 1.0-black_.cum_d2_;
169 black_.DbetaDd2_ = -black_.n_d2_;
170 break;
171 default:
172 QL_FAIL("invalid option type");
173 }
174 }
175
176 void BlackCalculator::Calculator::visit(AssetOrNothingPayoff& payoff) {
177 black_.beta_ = black_.DbetaDd2_ = 0.0;
178 switch (payoff.optionType()) {
179 case Option::Call:
180 black_.alpha_ = black_.cum_d1_;
181 black_.DalphaDd1_ = black_.n_d1_;
182 break;
183 case Option::Put:
184 black_.alpha_ = 1.0-black_.cum_d1_;
185 black_.DalphaDd1_ = -black_.n_d1_;
186 break;
187 default:
188 QL_FAIL("invalid option type");
189 }
190 }
191
192 void BlackCalculator::Calculator::visit(GapPayoff& payoff) {
193 black_.x_ = payoff.secondStrike();
194 black_.DxDstrike_ = 0.0;
195 }
196
198 Real result = discount_ * (forward_ * alpha_ + x_ * beta_);
199 return result;
200 }
201
203
204 QL_REQUIRE(spot > 0.0, "positive spot value required: " <<
205 spot << " not allowed");
206
207 Real DforwardDs = forward_ / spot;
208
209 Real temp = stdDev_*spot;
210 Real DalphaDs = DalphaDd1_/temp;
211 Real DbetaDs = DbetaDd2_/temp;
212 Real temp2 = DalphaDs * forward_ + alpha_ * DforwardDs
213 +DbetaDs * x_ + beta_ * DxDs_;
214
215 return discount_ * temp2;
216 }
217
219
220 Real temp = stdDev_*forward_;
221 Real DalphaDforward = DalphaDd1_/temp;
222 Real DbetaDforward = DbetaDd2_/temp;
223 Real temp2 = DalphaDforward * forward_ + alpha_
224 +DbetaDforward * x_; // DXDforward = 0.0
225
226 return discount_ * temp2;
227 }
228
230 Real val = value();
231 Real del = delta(spot);
232 if (val>QL_EPSILON)
233 return del/val*spot;
234 else if (std::fabs(del)<QL_EPSILON)
235 return 0.0;
236 else if (del>0.0)
237 return QL_MAX_REAL;
238 else
239 return QL_MIN_REAL;
240 }
241
243 Real val = value();
244 Real del = deltaForward();
245 if (val>QL_EPSILON)
246 return del/val*forward_;
247 else if (std::fabs(del)<QL_EPSILON)
248 return 0.0;
249 else if (del>0.0)
250 return QL_MAX_REAL;
251 else
252 return QL_MIN_REAL;
253 }
254
256
257 QL_REQUIRE(spot > 0.0, "positive spot value required: " <<
258 spot << " not allowed");
259
260 Real DforwardDs = forward_ / spot;
261
262 Real temp = stdDev_*spot;
263 Real DalphaDs = DalphaDd1_/temp;
264 Real DbetaDs = DbetaDd2_/temp;
265
266 Real D2alphaDs2 = - DalphaDs/spot*(1+d1_/stdDev_);
267 Real D2betaDs2 = - DbetaDs /spot*(1+d2_/stdDev_);
268
269 Real temp2 = D2alphaDs2 * forward_ + 2.0 * DalphaDs * DforwardDs
270 +D2betaDs2 * x_ + 2.0 * DbetaDs * DxDs_;
271
272 return discount_ * temp2;
273 }
274
276
277 Real temp = stdDev_*forward_;
278 Real DalphaDforward = DalphaDd1_/temp;
279 Real DbetaDforward = DbetaDd2_/temp;
280
281 Real D2alphaDforward2 = - DalphaDforward/forward_*(1+d1_/stdDev_);
282 Real D2betaDforward2 = - DbetaDforward /forward_*(1+d2_/stdDev_);
283
284 Real temp2 = D2alphaDforward2 * forward_ + 2.0 * DalphaDforward
285 +D2betaDforward2 * x_; // DXDforward = 0.0
286
287 return discount_ * temp2;
288 }
289
291 Time maturity) const {
292
293 QL_REQUIRE(maturity>=0.0,
294 "maturity (" << maturity << ") must be non-negative");
295 if (close(maturity, 0.0)) return 0.0;
296 return -( std::log(discount_) * value()
297 +std::log(forward_/spot) * spot * delta(spot)
298 +0.5*variance_ * spot * spot * gamma(spot))/maturity;
299 }
300
302 QL_REQUIRE(maturity>=0.0,
303 "negative maturity not allowed");
304
305 Real temp = std::log(strike_/forward_)/variance_;
306 // actually DalphaDsigma / SQRT(T)
307 Real DalphaDsigma = DalphaDd1_*(temp+0.5);
308 Real DbetaDsigma = DbetaDd2_ *(temp-0.5);
309
310 Real temp2 = DalphaDsigma * forward_ + DbetaDsigma * x_;
311
312 return discount_ * std::sqrt(maturity) * temp2;
313
314 }
315
317 QL_REQUIRE(maturity>=0.0,
318 "negative maturity not allowed");
319
320 // actually DalphaDr / T
321 Real DalphaDr = DalphaDd1_/stdDev_;
322 Real DbetaDr = DbetaDd2_/stdDev_;
323 Real temp = DalphaDr * forward_ + alpha_ * forward_ + DbetaDr * x_;
324
325 return maturity * (discount_ * temp - value());
326 }
327
329 QL_REQUIRE(maturity>=0.0,
330 "negative maturity not allowed");
331
332 // actually DalphaDq / T
333 Real DalphaDq = -DalphaDd1_/stdDev_;
334 Real DbetaDq = -DbetaDd2_/stdDev_;
335
336 Real temp = DalphaDq * forward_ - alpha_ * forward_ + DbetaDq * x_;
337
338 return maturity * discount_ * temp;
339 }
340
342
343 Real temp = stdDev_*strike_;
344 Real DalphaDstrike = -DalphaDd1_/temp;
345 Real DbetaDstrike = -DbetaDd2_/temp;
346
347 Real temp2 =
348 DalphaDstrike * forward_ + DbetaDstrike * x_ + beta_ * DxDstrike_;
349
350 return discount_ * temp2;
351 }
352
353
355
356 Real temp = stdDev_*strike_;
357 Real DalphaDstrike = -DalphaDd1_/temp;
358 Real DbetaDstrike = -DbetaDd2_/temp;
359
360 Real D2alphaD2strike = -DalphaDstrike/strike_*(1-d1_/stdDev_);
361 Real D2betaD2strike = -DbetaDstrike /strike_*(1-d2_/stdDev_);
362
363 Real temp2 =
364 D2alphaD2strike * forward_ + D2betaD2strike * x_
365 + 2.0*DbetaDstrike *DxDstrike_;
366
367 return discount_ * temp2;
368 }
369}
Real dividendRho(Time maturity) const
virtual Real delta(Real spot) const
Real vega(Time maturity) const
void initialize(const ext::shared_ptr< StrikedTypePayoff > &p)
BlackCalculator(const ext::shared_ptr< StrikedTypePayoff > &payoff, Real forward, Real stdDev, Real discount=1.0)
virtual Real gamma(Real spot) const
virtual Real elasticity(Real spot) const
virtual Real theta(Real spot, Time maturity) const
Real rho(Time maturity) const
Cumulative normal distribution function.
Plain-vanilla payoff.
Definition: payoffs.hpp:105
#define QL_MAX_REAL
Definition: qldefines.hpp:176
#define QL_EPSILON
Definition: qldefines.hpp:178
#define QL_MIN_REAL
Definition: qldefines.hpp:175
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
Definition: any.hpp:35
bool close(const Quantity &m1, const Quantity &m2, Size n)
Definition: quantity.cpp:163