1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*
4  Copyright (C) 2007 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 /*! \file analyticbsmhullwhiteengine.hpp
21     \brief analytic Black-Scholes engines including stochastic interest rates
22 */
23 
24 #include <ql/pricingengines/vanilla/analyticbsmhullwhiteengine.hpp>
25 #include <ql/pricingengines/vanilla/analyticeuropeanengine.hpp>
26 #include <ql/termstructures/volatility/equityfx/blackvoltermstructure.hpp>
27 
28 namespace QuantLib {
29 
30     namespace {
31 
32         class ShiftedBlackVolTermStructure : public BlackVolTermStructure {
33           public:
ShiftedBlackVolTermStructure(Real varianceOffset,const Handle<BlackVolTermStructure> & volTS)34             ShiftedBlackVolTermStructure(
35                 Real varianceOffset,
36                 const Handle<BlackVolTermStructure> & volTS)
37                 : BlackVolTermStructure(volTS->referenceDate(),
38                                         volTS->calendar(),
39                                         Following,
40                                         volTS->dayCounter()),
41                   varianceOffset_(varianceOffset),
42                   volTS_(volTS) { }
43 
minStrike() const44             Real minStrike() const { return volTS_->minStrike(); }
maxStrike() const45             Real maxStrike() const { return volTS_->maxStrike(); }
maxDate() const46             Date maxDate() const   { return volTS_->maxDate(); }
47 
48           protected:
blackVarianceImpl(Time t,Real strike) const49             Real blackVarianceImpl(Time t, Real strike) const {
50                 return volTS_->blackVariance(t, strike, true)+varianceOffset_;
51             }
blackVolImpl(Time t,Real strike) const52             Volatility blackVolImpl(Time t, Real strike) const {
53                 Time nonZeroMaturity = (t==0.0 ? 0.00001 : t);
54                 Real var = blackVarianceImpl(nonZeroMaturity, strike);
55                 return std::sqrt(var/nonZeroMaturity);
56             }
57           private:
58             const Real varianceOffset_;
59             const Handle<BlackVolTermStructure> volTS_;
60         };
61     }
62 
AnalyticBSMHullWhiteEngine(Real equityShortRateCorrelation,const ext::shared_ptr<GeneralizedBlackScholesProcess> & process,const ext::shared_ptr<HullWhite> & model)63     AnalyticBSMHullWhiteEngine::AnalyticBSMHullWhiteEngine(
64              Real equityShortRateCorrelation,
65              const ext::shared_ptr<GeneralizedBlackScholesProcess>& process,
66              const ext::shared_ptr<HullWhite> & model)
67     : GenericModelEngine<HullWhite,
68                          VanillaOption::arguments,
69                          VanillaOption::results>(model),
70       rho_(equityShortRateCorrelation), process_(process) {
71         registerWith(process_);
72     }
73 
calculate() const74     void AnalyticBSMHullWhiteEngine::calculate() const {
75 
76         QL_REQUIRE(process_->x0() > 0.0, "negative or null underlying given");
77 
78         const ext::shared_ptr<StrikedTypePayoff> payoff =
79             ext::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff);
80         QL_REQUIRE(payoff, "non-striked payoff given");
81 
82         const ext::shared_ptr<Exercise> exercise = arguments_.exercise;
83 
84         Time t = process_->riskFreeRate()->dayCounter().yearFraction(
85                                     process_->riskFreeRate()->referenceDate(),
86                                     exercise->lastDate());
87 
88         const Real a = model_->params()[0];
89         const Real sigma = model_->params()[1];
90         const Real eta =
91             process_->blackVolatility()->blackVol(exercise->lastDate(),
92                                                   payoff->strike());
93 
94         Real varianceOffset;
95         if (a*t > std::pow(QL_EPSILON, 0.25)) {
96             const Real v = sigma*sigma/(a*a)
97                 *(t + 2/a*std::exp(-a*t) - 1/(2*a)*std::exp(-2*a*t) - 3/(2*a));
98             const Real mu = 2*rho_*sigma*eta/a*(t-1/a*(1-std::exp(-a*t)));
99 
100             varianceOffset = v + mu;
101         }
102         else {
103             // low-a algebraic limit
104             const Real v = sigma*sigma*t*t*t*(1/3.0-0.25*a*t+7/60.0*a*a*t*t);
105             const Real mu = rho_*sigma*eta*t*t*(1-a*t/3.0+a*a*t*t/12.0);
106 
107             varianceOffset = v + mu;
108         }
109 
110         Handle<BlackVolTermStructure> volTS(
111              ext::shared_ptr<BlackVolTermStructure>(
112               new ShiftedBlackVolTermStructure(varianceOffset,
113                                                process_->blackVolatility())));
114 
115         ext::shared_ptr<GeneralizedBlackScholesProcess> adjProcess(
116                 new GeneralizedBlackScholesProcess(process_->stateVariable(),
117                                                    process_->dividendYield(),
118                                                    process_->riskFreeRate(),
119                                                    volTS));
120 
121         ext::shared_ptr<AnalyticEuropeanEngine> bsmEngine(
122                                       new AnalyticEuropeanEngine(adjProcess));
123 
124         VanillaOption(payoff, exercise).setupArguments(
125                                                    bsmEngine->getArguments());
126         bsmEngine->calculate();
127 
128         results_ = *dynamic_cast<const OneAssetOption::results*>(
129                                                     bsmEngine->getResults());
130     }
131 }
132