1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2002, 2003, 2004 Ferdinando Ametrano
5 Copyright (C) 2002, 2003 RiskMap srl
6 Copyright (C) 2003, 2004, 2005, 2007 StatPro Italia srl
7 Copyright (C) 2005 Joseph Wang
8
9 This file is part of QuantLib, a free-software/open-source library
10 for financial quantitative analysts and developers - http://quantlib.org/
11
12 QuantLib is free software: you can redistribute it and/or modify it
13 under the terms of the QuantLib license. You should have received a
14 copy of the license along with this program; if not, please email
15 <quantlib-dev@lists.sf.net>. The license is also available online at
16 <http://quantlib.org/license.shtml>.
17
18 This program is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 FOR A PARTICULAR PURPOSE. See the license for more details.
21*/
22
23#include <ql/pricingengines/vanilla/fdvanillaengine.hpp>
24#include <ql/instruments/payoffs.hpp>
25#include <ql/exercise.hpp>
26#include <ql/grid.hpp>
27#include <ql/instruments/oneassetoption.hpp>
28#include <ql/methods/finitedifferences/bsmoperator.hpp>
29#include <ql/methods/finitedifferences/bsmtermoperator.hpp>
30
31namespace QuantLib {
32
33 const Real FDVanillaEngine::safetyZoneFactor_ = 1.1;
34
35 void FDVanillaEngine::setGridLimits() const {
36 setGridLimits(process_->stateVariable()->value(),
37 getResidualTime());
38 ensureStrikeInGrid();
39 }
40
41 void FDVanillaEngine::setupArguments(
42 const PricingEngine::arguments* a) const {
43 const auto* args = dynamic_cast<const OneAssetOption::arguments*>(a);
44 QL_REQUIRE(args, "incorrect argument type");
45 exerciseDate_ = args->exercise->lastDate();
46 payoff_ = args->payoff;
47 }
48
49 void FDVanillaEngine::setGridLimits(Real center, Time t) const {
50 QL_REQUIRE(center > 0.0, "negative or null underlying given");
51 QL_REQUIRE(t > 0.0, "negative or zero residual time");
52 center_ = center;
53 Size newGridPoints = safeGridPoints(gridPoints: gridPoints_, residualTime: t);
54 QL_DEPRECATED_DISABLE_WARNING
55 if (newGridPoints > intrinsicValues_.size()) {
56 intrinsicValues_ = SampledCurve(newGridPoints);
57 }
58 QL_DEPRECATED_ENABLE_WARNING
59
60 Real volSqrtTime = std::sqrt(x: process_->blackVolatility()
61 ->blackVariance(t, strike: center_));
62
63 // the prefactor fine tunes performance at small volatilities
64 Real prefactor = 1.0 + 0.02/volSqrtTime;
65 Real minMaxFactor = std::exp(x: 4.0 * prefactor * volSqrtTime);
66 sMin_ = center_/minMaxFactor; // underlying grid min value
67 sMax_ = center_*minMaxFactor; // underlying grid max value
68 }
69
70 void FDVanillaEngine::ensureStrikeInGrid() const {
71 // ensure strike is included in the grid
72 ext::shared_ptr<StrikedTypePayoff> striked_payoff =
73 ext::dynamic_pointer_cast<StrikedTypePayoff>(r: payoff_);
74 if (!striked_payoff)
75 return;
76 Real requiredGridValue = striked_payoff->strike();
77
78 if(sMin_ > requiredGridValue/safetyZoneFactor_){
79 sMin_ = requiredGridValue/safetyZoneFactor_;
80 // enforce central placement of the underlying
81 sMax_ = center_/(sMin_/center_);
82 }
83 if(sMax_ < requiredGridValue*safetyZoneFactor_){
84 sMax_ = requiredGridValue*safetyZoneFactor_;
85 // enforce central placement of the underlying
86 sMin_ = center_/(sMax_/center_);
87 }
88 }
89
90 void FDVanillaEngine::initializeInitialCondition() const {
91 QL_DEPRECATED_DISABLE_WARNING
92 intrinsicValues_.setLogGrid(min: sMin_, max: sMax_);
93 intrinsicValues_.sample(f: *payoff_);
94 QL_DEPRECATED_ENABLE_WARNING
95 }
96
97 void FDVanillaEngine::initializeOperator() const {
98 QL_DEPRECATED_DISABLE_WARNING
99 if (timeDependent_) {
100 finiteDifferenceOperator_ = BSMTermOperator(intrinsicValues_.grid(),
101 process_, getResidualTime());
102 } else {
103 const YieldTermStructure& R = **(process_->riskFreeRate());
104 Rate r = R.zeroRate(d: exerciseDate_, resultDayCounter: R.dayCounter(), comp: Continuous);
105 const YieldTermStructure& Q = **(process_->dividendYield());
106 Rate q = Q.zeroRate(d: exerciseDate_, resultDayCounter: Q.dayCounter(), comp: Continuous);
107
108 ext::shared_ptr<StrikedTypePayoff> striked_payoff =
109 ext::dynamic_pointer_cast<StrikedTypePayoff>(r: payoff_);
110 Real K = striked_payoff != nullptr ? striked_payoff->strike() : process_->x0();
111 Volatility sigma =
112 process_->blackVolatility()->blackVol(d: exerciseDate_, strike: K);
113
114 finiteDifferenceOperator_ = BSMOperator(intrinsicValues_.grid(),
115 r, q, sigma);
116 }
117 QL_DEPRECATED_ENABLE_WARNING
118 }
119
120 void FDVanillaEngine::initializeBoundaryConditions() const {
121 QL_DEPRECATED_DISABLE_WARNING
122 BCs_[0] = ext::shared_ptr<bc_type>(new NeumannBC(
123 intrinsicValues_.value(i: 1)-
124 intrinsicValues_.value(i: 0),
125 NeumannBC::Lower));
126 BCs_[1] = ext::shared_ptr<bc_type>(new NeumannBC(
127 intrinsicValues_.value(i: intrinsicValues_.size()-1) -
128 intrinsicValues_.value(i: intrinsicValues_.size()-2),
129 NeumannBC::Upper));
130 QL_DEPRECATED_ENABLE_WARNING
131 }
132
133 Time FDVanillaEngine::getResidualTime() const {
134 return process_->time(exerciseDate_);
135 }
136
137 // safety check to be sure we have enough grid points.
138 Size FDVanillaEngine::safeGridPoints(Size gridPoints,
139 Time residualTime) const {
140 static const Size minGridPoints = 10;
141 static const Size minGridPointsPerYear = 2;
142 return std::max(a: gridPoints,
143 b: residualTime > 1.0 ?
144 static_cast<Size>((minGridPoints +
145 (residualTime-1.0) *
146 minGridPointsPerYear))
147 : minGridPoints);
148 }
149
150}
151

source code of quantlib/ql/pricingengines/vanilla/fdvanillaengine.cpp