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) 2007 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 /*! \file forwardengine.hpp 22 \brief Forward (strike-resetting) vanilla-option engine 23 */ 24 25 #ifndef quantlib_forward_engine_hpp 26 #define quantlib_forward_engine_hpp 27 28 #include <ql/instruments/forwardvanillaoption.hpp> 29 #include <ql/instruments/vanillaoption.hpp> 30 #include <ql/processes/blackscholesprocess.hpp> 31 #include <ql/termstructures/volatility/equityfx/impliedvoltermstructure.hpp> 32 #include <ql/termstructures/yield/impliedtermstructure.hpp> 33 #include <ql/instruments/payoffs.hpp> 34 #include <ql/exercise.hpp> 35 36 namespace QuantLib { 37 38 //! %Forward engine for vanilla options 39 /*! \ingroup forwardengines 40 41 \test 42 - the correctness of the returned value is tested by 43 reproducing results available in literature. 44 - the correctness of the returned greeks is tested by 45 reproducing numerical derivatives. 46 */ 47 template <class Engine> 48 class ForwardVanillaEngine 49 : public GenericEngine<ForwardOptionArguments<VanillaOption::arguments>, 50 VanillaOption::results> { 51 public: 52 ForwardVanillaEngine( 53 const ext::shared_ptr<GeneralizedBlackScholesProcess>&); 54 void calculate() const; 55 protected: 56 void setup() const; 57 void getOriginalResults() const; 58 ext::shared_ptr<GeneralizedBlackScholesProcess> process_; 59 mutable ext::shared_ptr<Engine> originalEngine_; 60 mutable VanillaOption::arguments* originalArguments_; 61 mutable const VanillaOption::results* originalResults_; 62 }; 63 64 65 // template definitions 66 67 template <class Engine> ForwardVanillaEngine(const ext::shared_ptr<GeneralizedBlackScholesProcess> & process)68 ForwardVanillaEngine<Engine>::ForwardVanillaEngine( 69 const ext::shared_ptr<GeneralizedBlackScholesProcess>& process) 70 : process_(process) { 71 registerWith(process_); 72 } 73 74 75 template <class Engine> setup() const76 void ForwardVanillaEngine<Engine>::setup() const { 77 78 ext::shared_ptr<StrikedTypePayoff> argumentsPayoff = 79 ext::dynamic_pointer_cast<StrikedTypePayoff>( 80 this->arguments_.payoff); 81 QL_REQUIRE(argumentsPayoff, "wrong payoff given"); 82 83 ext::shared_ptr<StrikedTypePayoff> payoff( 84 new PlainVanillaPayoff(argumentsPayoff->optionType(), 85 this->arguments_.moneyness * 86 process_->x0())); 87 88 // maybe the forward value is "better", in some fashion 89 // the right level is needed in order to interpolate 90 // the vol 91 Handle<Quote> spot = process_->stateVariable(); 92 QL_REQUIRE(spot->value() >= 0.0, "negative or null underlting given"); 93 Handle<YieldTermStructure> dividendYield( 94 ext::shared_ptr<YieldTermStructure>( 95 new ImpliedTermStructure(process_->dividendYield(), 96 this->arguments_.resetDate))); 97 Handle<YieldTermStructure> riskFreeRate( 98 ext::shared_ptr<YieldTermStructure>( 99 new ImpliedTermStructure(process_->riskFreeRate(), 100 this->arguments_.resetDate))); 101 // The following approach is ok if the vol is at most 102 // time dependant. It is plain wrong if it is asset dependant. 103 // In the latter case the right solution would be stochastic 104 // volatility or at least local volatility (which unfortunately 105 // implies an unrealistic time-decreasing smile) 106 Handle<BlackVolTermStructure> blackVolatility( 107 ext::shared_ptr<BlackVolTermStructure>( 108 new ImpliedVolTermStructure(process_->blackVolatility(), 109 this->arguments_.resetDate))); 110 111 ext::shared_ptr<GeneralizedBlackScholesProcess> fwdProcess( 112 new GeneralizedBlackScholesProcess(spot, dividendYield, 113 riskFreeRate, 114 blackVolatility)); 115 116 originalEngine_ = ext::shared_ptr<Engine>(new Engine(fwdProcess)); 117 originalEngine_->reset(); 118 119 originalArguments_ = 120 dynamic_cast<VanillaOption::arguments*>( 121 originalEngine_->getArguments()); 122 QL_REQUIRE(originalArguments_, "wrong engine type"); 123 originalResults_ = 124 dynamic_cast<const VanillaOption::results*>( 125 originalEngine_->getResults()); 126 QL_REQUIRE(originalResults_, "wrong engine type"); 127 128 originalArguments_->payoff = payoff; 129 originalArguments_->exercise = this->arguments_.exercise; 130 131 originalArguments_->validate(); 132 } 133 134 template <class Engine> calculate() const135 void ForwardVanillaEngine<Engine>::calculate() const { 136 setup(); 137 originalEngine_->calculate(); 138 getOriginalResults(); 139 } 140 141 template <class Engine> getOriginalResults() const142 void ForwardVanillaEngine<Engine>::getOriginalResults() const { 143 144 DayCounter rfdc = process_->riskFreeRate()->dayCounter(); 145 DayCounter divdc = process_->dividendYield()->dayCounter(); 146 Time resetTime = rfdc.yearFraction( 147 process_->riskFreeRate()->referenceDate(), 148 this->arguments_.resetDate); 149 DiscountFactor discQ = process_->dividendYield()->discount( 150 this->arguments_.resetDate); 151 152 this->results_.value = discQ * originalResults_->value; 153 // I need the strike derivative here ... 154 if (originalResults_->delta != Null<Real>() && 155 originalResults_->strikeSensitivity != Null<Real>()) { 156 this->results_.delta = discQ * (originalResults_->delta + 157 this->arguments_.moneyness * 158 originalResults_->strikeSensitivity); 159 } 160 this->results_.gamma = 0.0; 161 this->results_.theta = process_->dividendYield()-> 162 zeroRate(this->arguments_.resetDate, divdc, Continuous, NoFrequency) 163 * this->results_.value; 164 if (originalResults_->vega != Null<Real>()) 165 this->results_.vega = discQ * originalResults_->vega; 166 if (originalResults_->rho != Null<Real>()) 167 this->results_.rho = discQ * originalResults_->rho; 168 if (originalResults_->dividendRho != Null<Real>()) { 169 this->results_.dividendRho = - resetTime * this->results_.value 170 + discQ * originalResults_->dividendRho; 171 } 172 } 173 174 } 175 176 177 #endif 178