QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
andreasenhugevolatilityinterpl.cpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2017, 2018 Klaus Spanderen
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>
22#include <ql/math/array.hpp>
35#include <ql/timegrid.hpp>
36#include <ql/utilities/null.hpp>
37#include <cmath>
38#include <limits>
39#include <utility>
40
41namespace QuantLib {
42
43 namespace {
44
45 struct close_enough_to {
48 explicit close_enough_to(Real y, Size n=42) : y(y), n(n) {}
49 bool operator()(Real x) const { return close_enough(x, y, n); }
50 };
51
52 }
53
54 class AndreasenHugeCostFunction : public CostFunction {
55 public:
56 AndreasenHugeCostFunction(
57 Array marketNPVs,
58 Array marketVegas,
59 Array lnMarketStrikes,
60 Array previousNPVs,
61 const ext::shared_ptr<FdmMesherComposite>& mesher,
62 Time dT,
64 : marketNPVs_(std::move(marketNPVs)), marketVegas_(std::move(marketVegas)),
65 lnMarketStrikes_(std::move(lnMarketStrikes)), previousNPVs_(std::move(previousNPVs)),
66 mesher_(mesher), nGridPoints_(mesher->layout()->size()), dT_(dT),
67 interpolationType_((lnMarketStrikes_.size() > 1) ?
68 interpolationType :
69 AndreasenHugeVolatilityInterpl::PiecewiseConstant),
70 dxMap_(FirstDerivativeOp(0, mesher_)), dxxMap_(SecondDerivativeOp(0, mesher_)),
71 d2CdK2_(dxMap_.mult(Array(mesher->layout()->size(), -1.0)).add(dxxMap_)),
72 mapT_(0, mesher_) {}
73
74 Array d2CdK2(const Array& c) const {
75 return d2CdK2_.apply(c);
76 }
77
78 Array solveFor(Time dT, const Array& sig, const Array& b) const {
79
80 Array x(lnMarketStrikes_.size());
81 Interpolation sigInterpl;
82
83 switch (interpolationType_) {
85 sigInterpl = CubicNaturalSpline(
86 lnMarketStrikes_.begin(), lnMarketStrikes_.end(),
87 sig.begin());
88 break;
90 sigInterpl = LinearInterpolation(
91 lnMarketStrikes_.begin(), lnMarketStrikes_.end(),
92 sig.begin());
93 break;
95 for (Size i=0; i < x.size()-1; ++i)
96 x[i] = 0.5*(lnMarketStrikes_[i] + lnMarketStrikes_[i+1]);
97 x.back() = lnMarketStrikes_.back();
98
99 sigInterpl = BackwardFlatInterpolation(
100 x.begin(), x.end(), sig.begin());
101 break;
102 default:
103 QL_FAIL("unknown interpolation type");
104 }
105
106 Array z(mesher_->layout()->size());
107 for (const auto& iter : *mesher_->layout()) {
108 const Size i = iter.index();
109 const Real lnStrike = mesher_->location(iter, 0);
110
111 const Real vol = sigInterpl(
112 std::min(std::max(lnStrike, lnMarketStrikes_.front()),
113 lnMarketStrikes_.back()), true);
114
115 z[i] = 0.5*vol*vol;
116 }
117
118 mapT_.axpyb(z, dxMap_, dxxMap_.mult(-z), Array());
119 return mapT_.mult(Array(z.size(), dT)).solve_splitting(b, 1.0);
120
121 }
122
123 Array apply(const Array& c) const {
124 return -mapT_.apply(c);
125 }
126
127 Array values(const Array& sig) const override {
128 Array newNPVs = solveFor(dT_, sig, previousNPVs_);
129
130 const std::vector<Real>& gridPoints =
131 mesher_->getFdm1dMeshers().front()->locations();
132
133 const MonotonicCubicNaturalSpline interpl(
134 gridPoints.begin(), gridPoints.end(), newNPVs.begin());
135
136 Array retVal(lnMarketStrikes_.size());
137 for (Size i=0; i < retVal.size(); ++i) {
138 const Real strike = lnMarketStrikes_[i];
139 retVal[i] = interpl(strike) - marketNPVs_[i];
140 }
141 return retVal;
142 }
143
144 Array vegaCalibrationError(const Array& sig) const {
145 return values(sig)/marketVegas_;
146 }
147
148 Array initialValues() const {
149 return Array(lnMarketStrikes_.size(), 0.25);
150 }
151
152
153 private:
154 const Array marketNPVs_, marketVegas_;
155 const Array lnMarketStrikes_, previousNPVs_;
156 const ext::shared_ptr<FdmMesherComposite> mesher_;
157 const Size nGridPoints_;
158 const Time dT_;
160 interpolationType_;
161
162 const FirstDerivativeOp dxMap_;
163 const TripleBandLinearOp dxxMap_;
164 const TripleBandLinearOp d2CdK2_;
165 mutable TripleBandLinearOp mapT_;
166 };
167
168 class CombinedCostFunction : public CostFunction {
169 public:
170 CombinedCostFunction(ext::shared_ptr<AndreasenHugeCostFunction> putCostFct,
171 ext::shared_ptr<AndreasenHugeCostFunction> callCostFct)
172 : putCostFct_(std::move(putCostFct)), callCostFct_(std::move(callCostFct)) {}
173
174 Array values(const Array& sig) const override {
175 if ((putCostFct_ != nullptr) && (callCostFct_ != nullptr)) {
176 const Array pv = putCostFct_->values(sig);
177 const Array cv = callCostFct_->values(sig);
178
179 Array retVal(pv.size() + cv.size());
180 std::copy(pv.begin(), pv.end(), retVal.begin());
181 std::copy(cv.begin(), cv.end(), retVal.begin() + cv.size());
182
183 return retVal;
184 } else if (putCostFct_ != nullptr)
185 return putCostFct_->values(sig);
186 else if (callCostFct_ != nullptr)
187 return callCostFct_->values(sig);
188 else
189 QL_FAIL("internal error: cost function not set");
190 }
191
192 Array initialValues() const {
193 if ((putCostFct_ != nullptr) && (callCostFct_ != nullptr))
194 return 0.5*( putCostFct_->initialValues()
195 + callCostFct_->initialValues());
196 else if (putCostFct_ != nullptr)
197 return putCostFct_->initialValues();
198 else if (callCostFct_ != nullptr)
199 return callCostFct_->initialValues();
200 else
201 QL_FAIL("internal error: cost function not set");
202 }
203
204 private:
205 const ext::shared_ptr<AndreasenHugeCostFunction> putCostFct_;
206 const ext::shared_ptr<AndreasenHugeCostFunction> callCostFct_;
207 };
208
209
211 const CalibrationSet& calibrationSet,
212 Handle<Quote> spot,
215 InterpolationType interplationType,
216 CalibrationType calibrationType,
217 Size nGridPoints,
218 Real _minStrike,
219 Real _maxStrike,
220 ext::shared_ptr<OptimizationMethod> optimizationMethod,
221 const EndCriteria& endCriteria)
222 : spot_(std::move(spot)), rTS_(std::move(rTS)), qTS_(std::move(qTS)),
223 interpolationType_(interplationType), calibrationType_(calibrationType),
224 nGridPoints_(nGridPoints), minStrike_(_minStrike), maxStrike_(_maxStrike),
225 optimizationMethod_(std::move(optimizationMethod)), endCriteria_(endCriteria) {
226 QL_REQUIRE(nGridPoints > 2 && !calibrationSet.empty(), "undefined grid or calibration set");
227
228 std::set<Real> strikes;
229 std::set<Date> expiries;
230
231 calibrationSet_.reserve(calibrationSet.size());
232 for (const auto& i : calibrationSet) {
233
234 const ext::shared_ptr<Exercise> exercise = i.first->exercise();
235
236 QL_REQUIRE(exercise->type() == Exercise::European,
237 "European option required");
238
239 const Date expiry = exercise->lastDate();
240 expiries.insert(expiry);
241
242 const ext::shared_ptr<PlainVanillaPayoff> payoff =
243 ext::dynamic_pointer_cast<PlainVanillaPayoff>(i.first->payoff());
244
245 QL_REQUIRE(payoff, "plain vanilla payoff required");
246
247 const Real strike = payoff->strike();
248 strikes.insert(strike);
249
250 calibrationSet_.emplace_back(ext::make_shared<VanillaOption>(payoff, exercise), i.second);
251
252 registerWith(i.second);
253 }
254
255 strikes_.assign(strikes.begin(), strikes.end());
256 expiries_.assign(expiries.begin(), expiries.end());
257
258 dT_.resize(expiries_.size());
259 expiryTimes_.resize(expiries_.size());
260
261 calibrationMatrix_ = std::vector< std::vector<Size> >(
262 expiries.size(), std::vector<Size>(strikes.size(), Null<Size>()));
263
264 for (Size i=0; i < calibrationSet.size(); ++i) {
265 const Date expiry =
266 calibrationSet[i].first->exercise()->lastDate();
267
268 const Size l = std::distance(expiries.begin(), expiries.lower_bound(expiry));
269
270 const Real strike =
271 ext::dynamic_pointer_cast<PlainVanillaPayoff>(
272 calibrationSet[i].first->payoff())->strike();
273
274 const Size k = std::distance(strikes_.begin(),
275 std::find_if(strikes_.begin(), strikes_.end(),
276 close_enough_to(strike)));
277
278 calibrationMatrix_[l][k] = i;
279 }
280
284 }
285
286 ext::shared_ptr<AndreasenHugeCostFunction>
288 Size iExpiry, Option::Type optionType,
289 const Array& previousNPVs) const {
290
292 && ( (calibrationType_ == Call && optionType ==Option::Put)
293 || (calibrationType_ == Put && optionType ==Option::Call)))
294 return ext::shared_ptr<AndreasenHugeCostFunction>();
295
296 const Time expiryTime = expiryTimes_[iExpiry];
297
298 const DiscountFactor discount = rTS_->discount(expiryTime);
299 const Real fwd = spot_->value()*qTS_->discount(expiryTime)/discount;
300
301 Size null = Null<Size>();
302 const Size nOptions = std::count_if(
303 calibrationMatrix_[iExpiry].begin(),
304 calibrationMatrix_[iExpiry].end(),
305 [=](Size n){ return n != null; });
306
307 Array lnMarketStrikes(nOptions),
308 marketNPVs(nOptions), marketVegas(nOptions);
309
310 // calculate undiscounted market prices
311 for (Size j=0, k=0; j < strikes_.size(); ++j) {
312 const Size idx = calibrationMatrix_[iExpiry][j];
313
314 if (idx != null) {
315
316 const Volatility vol = calibrationSet_[idx].second->value();
317 const Real stdDev = vol*std::sqrt(expiryTime);
318
319 const BlackCalculator calculator(
320 optionType, strikes_[j], fwd, stdDev, discount);
321
322 const Real npv = calculator.value();
323 const Real vega = calculator.vega(expiryTime);
324
325 marketNPVs[k] = npv/(discount*fwd);
326 marketVegas[k] = vega/(discount*fwd);
327 lnMarketStrikes[k++] = std::log(strikes_[j]/fwd);
328 }
329 }
330
331 return ext::make_shared<AndreasenHugeCostFunction>(
332 marketNPVs,
333 marketVegas,
334 lnMarketStrikes,
335 previousNPVs,
336 mesher_,
337 dT_[iExpiry],
339 }
340
341
344 "max strike must be greater than min strike");
345
346 const DayCounter dc = rTS_->dayCounter();
347 for (Size i=0; i < expiryTimes_.size(); ++i) {
348 expiryTimes_[i] =
349 dc.yearFraction(rTS_->referenceDate(), expiries_[i]);
350 dT_[i] = expiryTimes_[i] - ( (i==0)? 0.0 : expiryTimes_[i-1]);
351 }
352
353 mesher_ =
354 ext::make_shared<FdmMesherComposite>(
355 ext::make_shared<Concentrating1dMesher>(
356 std::log(minStrike()/spot_->value()),
357 std::log(maxStrike()/spot_->value()),
359 std::pair<Real, Real>(0.0, 0.025)));
360
361 gridPoints_ = mesher_->locations(0);
362 gridInFwd_ = Exp(gridPoints_)*spot_->value();
363
364 localVolCache_.clear();
365 calibrationResults_.clear();
366
367 avgError_ = 0.0;
368 minError_ = std::numeric_limits<Real>::max();
369 maxError_ = 0.0;
370
371 calibrationResults_.reserve(expiries_.size());
372
373 Array npvPuts(nGridPoints_);
374 Array npvCalls(nGridPoints_);
375
376 for (Size i=0; i < nGridPoints_; ++i) {
377 const Real strike = std::exp(gridPoints_[i]);
378 npvPuts[i] = PlainVanillaPayoff(Option::Put, strike)(1.0);
379 npvCalls[i]= PlainVanillaPayoff(Option::Call, strike)(1.0);
380 }
381
382 for (Size i=0; i < expiries_.size(); ++i) {
383 const ext::shared_ptr<AndreasenHugeCostFunction> putCostFct =
384 buildCostFunction(i, Option::Put, npvPuts);
385 const ext::shared_ptr<AndreasenHugeCostFunction> callCostFct =
386 buildCostFunction(i, Option::Call, npvCalls);
387
388 CombinedCostFunction costFunction(putCostFct, callCostFct);
389
390 PositiveConstraint positiveConstraint;
391 Problem problem(costFunction,
392 positiveConstraint, costFunction.initialValues());
393
394 optimizationMethod_->minimize(problem, endCriteria_);
395
396 const Array& sig = problem.currentValue();
397
398 const SingleStepCalibrationResult calibrationResult = {
399 npvPuts, npvCalls, sig,
400 (calibrationType_ == Call)? callCostFct : putCostFct
401 };
402
403 calibrationResults_.push_back(calibrationResult);
404
405 Array vegaDiffs(sig.size());
406 switch (calibrationType_) {
407 case CallPut: {
408 const Array vegaPutDiffs =
409 putCostFct->vegaCalibrationError(sig);
410 const Array vegaCallDiffs =
411 callCostFct->vegaCalibrationError(sig);
412
413 const Real fwd = spot_->value()*
414 qTS_->discount(expiryTimes_[i])/rTS_->discount(expiryTimes_[i]);
415
416 for (Size j=0; j < vegaDiffs.size(); ++j)
417 vegaDiffs[j] = std::fabs(
418 (fwd > gridInFwd_[j])? vegaPutDiffs[j] : vegaCallDiffs[j]);
419 }
420 break;
421 case Put:
422 vegaDiffs = Abs(putCostFct->vegaCalibrationError(sig));
423 break;
424 case Call:
425 vegaDiffs = Abs(callCostFct->vegaCalibrationError(sig));
426 break;
427 default:
428 QL_FAIL("unknown calibration type");
429 }
430
431 avgError_ +=
432 std::accumulate(vegaDiffs.begin(), vegaDiffs.end(), Real(0.0));
433 minError_ = std::min(minError_,
434 *std::min_element(vegaDiffs.begin(), vegaDiffs.end()));
435 maxError_ = std::max(maxError_,
436 *std::max_element(vegaDiffs.begin(), vegaDiffs.end()));
437
438 if (putCostFct != nullptr)
439 npvPuts = putCostFct->solveFor(dT_[i], sig, npvPuts);
440 if (callCostFct != nullptr)
441 npvCalls= callCostFct->solveFor(dT_[i], sig, npvCalls);
442 }
443
444 avgError_ /= calibrationSet_.size();
445 }
446
448 return expiries_.back();
449 }
450
452 return (minStrike_ == Null<Real>())
453 ? 1/8.0*strikes_.front() : minStrike_;
454 }
455
457 return (maxStrike_ == Null<Real>())
458 ? 8.0*strikes_.back() : maxStrike_;
459 }
460
462 return spot_->value()*qTS_->discount(t)/rTS_->discount(t);
463 }
464
467 return rTS_;
468 }
469
470 ext::tuple<Real, Real, Real>
472 calculate();
473
474 return ext::make_tuple(minError_, maxError_, avgError_);
475 }
476
478 return std::min<Size>(expiryTimes_.size()-1,
479 std::distance(expiryTimes_.begin(),
480 std::upper_bound(
481 expiryTimes_.begin(), expiryTimes_.end(), t)));
482 }
483
485 Real strike, const TimeValueCacheType::const_iterator& f) const {
486
487 const Real fwd = ext::get<0>(f->second);
488 const Real k = std::log(strike / fwd);
489
490 const Real s = std::max(gridPoints_[1],
491 std::min(*(gridPoints_.end()-2), k));
492
493 return (*(ext::get<2>(f->second)))(s);
494 }
495
497 Time t, Option::Type optionType) const {
498
499 const Size iu = getExerciseTimeIdx(t);
500
501 return calibrationResults_[iu].costFunction->solveFor(
502 (iu == 0) ? t : t-expiryTimes_[iu-1],
503 calibrationResults_[iu].sigmas,
504 (optionType == Option::Call)? calibrationResults_[iu].callNPVs
505 : calibrationResults_[iu].putNPVs);
506 }
507
509 Time t, Real strike, Option::Type optionType) const {
510
511 TimeValueCacheType::const_iterator f = priceCache_.find(t);
512
513 const DiscountFactor df = rTS_->discount(t);
514
515 if (f != priceCache_.end()) {
516 const Real fwd = ext::get<0>(f->second);
517
518 Real price = getCacheValue(strike, f);
519
520 if (optionType == Option::Put
522 price = price + strike/fwd - 1.0;
523 else if (optionType == Option::Call && calibrationType_ == Put)
524 price = 1.0 - strike/fwd + price;
525
526 return price*df*fwd;
527 }
528
529 calculate();
530
531
532 ext::shared_ptr<Array> prices(
533 ext::make_shared<Array>(gridPoints_));
534
535 switch (calibrationType_) {
536 case Put:
537 (*prices) = getPriceSlice(t, Option::Put);
538 break;
539 case Call:
540 case CallPut:
541 (*prices) = getPriceSlice(t, Option::Call);
542 break;
543 default:
544 QL_FAIL("unknown calibration type");
545 }
546
547 Real fwd = spot_->value()*qTS_->discount(t)/df;
548
549 priceCache_[t] = ext::make_tuple(
550 fwd, prices,
551 ext::make_shared<CubicNaturalSpline>(
553 prices->begin()+1));
554
555 return this->optionPrice(t, strike, optionType);
556 }
557
559 Time t, Option::Type optionType) const {
560
561 const Size iu = getExerciseTimeIdx(t);
562
563 const Array& previousNPVs =
564 (optionType == Option::Call)? calibrationResults_[iu].callNPVs
565 : calibrationResults_[iu].putNPVs;
566
567 const ext::shared_ptr<AndreasenHugeCostFunction> costFunction
568 = calibrationResults_[iu].costFunction;
569
570 const Time dt = (iu == 0) ? t : t-expiryTimes_[iu-1];
571 const Array& sig = calibrationResults_[iu].sigmas;
572
573 const Array cAtJ = costFunction->solveFor(dt, sig, previousNPVs);
574
575 const Array dCdT =
576 costFunction->solveFor(dt, sig,
577 costFunction->apply(
578 costFunction->solveFor(dt, sig, previousNPVs)));
579
580 const Array d2CdK2 = costFunction->d2CdK2(cAtJ);
581
582 Array localVol = Sqrt(2*dCdT/d2CdK2);
583
584 for (Size i=1; i < localVol.size()-1; ++i)
585 if (!std::isfinite(localVol[i]) || localVol[i] < 0.0)
586 localVol[i] = 0.25;
587
588 return localVol;
589 }
590
592 const {
593 TimeValueCacheType::const_iterator f = localVolCache_.find(t);
594
595 if (f != localVolCache_.end())
596 return getCacheValue(strike, f);
597
598 calculate();
599
600 ext::shared_ptr<Array> localVol(
601 ext::make_shared<Array>(gridPoints_.size()));
602
603 switch (calibrationType_) {
604 case CallPut: {
605 const Array putLocalVol = getLocalVolSlice(t, Option::Put);
606 const Array callLocalVol = getLocalVolSlice(t, Option::Call);
607
608 for (Size i=0, n=localVol->size(); i < n; ++i)
609 (*localVol)[i] =
610 (gridPoints_[i] > 0.0)? callLocalVol[i] : putLocalVol[i];
611 }
612 break;
613 case Put:
614 (*localVol) = getLocalVolSlice(t, Option::Put);
615 break;
616 case Call:
617 (*localVol) = getLocalVolSlice(t, Option::Call);
618 break;
619 default:
620 QL_FAIL("unknown calibration type");
621 }
622
623 Real fwd = spot_->value()*qTS_->discount(t)/rTS_->discount(t);
624
625 localVolCache_[t] = ext::make_tuple(
626 fwd, localVol,
627 ext::make_shared<LinearInterpolation>(
629 localVol->begin()+1));
630
631 return this->localVol(t, strike);
632 }
633}
Andreasen-Huge local volatility calibration and interpolation.
1-D array used in linear algebra.
backward-flat interpolation between discrete points
Black-formula calculator class.
ext::tuple< Real, Real, Real > calibrationError() const
Array getPriceSlice(Time t, Option::Type optionType) const
Array getLocalVolSlice(Time t, Option::Type optionType) const
std::vector< std::pair< ext::shared_ptr< VanillaOption >, ext::shared_ptr< Quote > > > CalibrationSet
Real getCacheValue(Real strike, const TimeValueCacheType::const_iterator &f) const
AndreasenHugeVolatilityInterpl(const CalibrationSet &calibrationSet, Handle< Quote > spot, Handle< YieldTermStructure > rTS, Handle< YieldTermStructure > qTS, InterpolationType interpolationType=CubicSpline, CalibrationType calibrationType=Call, Size nGridPoints=500, Real minStrike=Null< Real >(), Real maxStrike=Null< Real >(), ext::shared_ptr< OptimizationMethod > optimizationMethod=ext::shared_ptr< OptimizationMethod >(new LevenbergMarquardt), const EndCriteria &endCriteria=EndCriteria(500, 100, 1e-12, 1e-10, 1e-10))
ext::shared_ptr< AndreasenHugeCostFunction > buildCostFunction(Size iExpiry, Option::Type optionType, const Array &previousNPVs) const
std::vector< SingleStepCalibrationResult > calibrationResults_
const ext::shared_ptr< OptimizationMethod > optimizationMethod_
Real optionPrice(Time t, Real strike, Option::Type optionType) const
const Handle< YieldTermStructure > & riskFreeRate() const
1-D array used in linear algebra.
Definition: array.hpp:52
const_iterator end() const
Definition: array.hpp:511
Size size() const
dimension of the array
Definition: array.hpp:495
const_iterator begin() const
Definition: array.hpp:503
Black 1976 calculator class.
Real vega(Time maturity) const
Concrete date class.
Definition: date.hpp:125
day counter class
Definition: daycounter.hpp:44
Time yearFraction(const Date &, const Date &, const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date()) const
Returns the period between two dates as a fraction of year.
Definition: daycounter.hpp:128
Criteria to end optimization process:
Definition: endcriteria.hpp:40
Shared handle to an observable.
Definition: handle.hpp:41
virtual void calculate() const
Definition: lazyobject.hpp:253
template class providing a null value for a given type.
Definition: null.hpp:76
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:228
Plain-vanilla payoff.
Definition: payoffs.hpp:105
Constraint imposing positivity to all arguments
Definition: constraint.hpp:92
Constrained optimization problem.
Definition: problem.hpp:42
const Array & currentValue() const
current value of the local minimum
Definition: problem.hpp:81
floating-point comparisons
One-dimensional grid mesher concentrating around critical points.
cubic interpolation between discrete points
const DefaultType & t
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Definition: errors.hpp:92
Option exercise classes and payoff function.
ext::function< Real(Real)> b
const ext::shared_ptr< YieldTermStructure > rTS_
memory layout of a fdm linear operator
FdmMesher which is a composite of Fdm1dMesher.
const ext::shared_ptr< FdmMesher > mesher_
first derivative linear operator
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
std::size_t Size
size of a container
Definition: types.hpp:58
ext::shared_ptr< QuantLib::Payoff > payoff
Array apply(const Array &x, const ext::function< Real(Real)> &f)
Definition: any.hpp:35
Array Abs(const Array &v)
Definition: array.hpp:833
Array Exp(const Array &v)
Definition: array.hpp:875
Array Sqrt(const Array &v)
Definition: array.hpp:847
bool close_enough(const Quantity &m1, const Quantity &m2, Size n)
Definition: quantity.cpp:182
STL namespace.
null values
second derivative operator
discrete time grid
tridiagonal operator
Vanilla option on a single asset.
Interest-rate term structure.