/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (C) 2002, 2003, 2004 Ferdinando Ametrano Copyright (C) 2007 StatPro Italia srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ /*! \file forwardengine.hpp \brief Forward (strike-resetting) option engine */ #ifndef quantlib_forward_engine_hpp #define quantlib_forward_engine_hpp #include #include #include #include #include namespace QuantLib { //! %Arguments for forward (strike-resetting) option calculation template class ForwardOptionArguments : public ArgumentsType { public: ForwardOptionArguments() : moneyness(Null()), resetDate(Null()) {} void validate() const; Real moneyness; Date resetDate; }; //! %Forward-engine base class /*! \ingroup forwardengines \test - the correctness of the returned value is tested by reproducing results available in literature. - the correctness of the returned greeks is tested by reproducing numerical derivatives. */ template class ForwardEngine : public GenericEngine, ResultsType> { public: ForwardEngine(const boost::shared_ptr >&); void setOriginalArguments() const; void calculate() const; void getOriginalResults() const; protected: boost::shared_ptr > originalEngine_; ArgumentsType* originalArguments_; const ResultsType* originalResults_; }; // template definitions template void ForwardOptionArguments::validate() const { ArgumentsType::validate(); QL_REQUIRE(moneyness != Null(), "null moneyness given"); QL_REQUIRE(moneyness > 0.0, "negative or zero moneyness given"); QL_REQUIRE(resetDate != Null(), "null reset date given"); QL_REQUIRE(resetDate >= Settings::instance().evaluationDate(), "reset date in the past"); QL_REQUIRE(this->exercise->lastDate() > resetDate, "reset date later or equal to maturity"); } template ForwardEngine::ForwardEngine( const boost::shared_ptr >& originalEngine) : originalEngine_(originalEngine) { QL_REQUIRE(originalEngine_, "null engine"); originalResults_ = dynamic_cast(originalEngine_->getResults()); originalArguments_ = dynamic_cast(originalEngine_->getArguments()); } template void ForwardEngine::setOriginalArguments() const { boost::shared_ptr argumentsPayoff = boost::dynamic_pointer_cast( this->arguments_.payoff); QL_REQUIRE(argumentsPayoff, "wrong payoff given"); boost::shared_ptr process = boost::dynamic_pointer_cast( this->arguments_.stochasticProcess); QL_REQUIRE(process, "Black-Scholes process required"); boost::shared_ptr payoff( new PlainVanillaPayoff(argumentsPayoff->optionType(), this->arguments_.moneyness * process->stateVariable()->value())); originalArguments_->payoff = payoff; // maybe the forward value is "better", in some fashion // the right level is needed in order to interpolate // the vol Handle spot = process->stateVariable(); Handle dividendYield( boost::shared_ptr( new ImpliedTermStructure(process->dividendYield(), this->arguments_.resetDate))); Handle riskFreeRate( boost::shared_ptr( new ImpliedTermStructure(process->riskFreeRate(), this->arguments_.resetDate))); // The following approach is ok if the vol is at most // time dependant. It is plain wrong if it is asset dependant. // In the latter case the right solution would be stochastic // volatility or at least local volatility (which unfortunately // implies an unrealistic time-decreasing smile) Handle blackVolatility( boost::shared_ptr( new ImpliedVolTermStructure(process->blackVolatility(), this->arguments_.resetDate))); originalArguments_->stochasticProcess = boost::shared_ptr( new GeneralizedBlackScholesProcess(spot, dividendYield, riskFreeRate, blackVolatility)); originalArguments_->exercise = this->arguments_.exercise; originalArguments_->validate(); } template void ForwardEngine::calculate() const { originalEngine_->reset(); setOriginalArguments(); originalEngine_->calculate(); getOriginalResults(); } template void ForwardEngine::getOriginalResults() const { boost::shared_ptr process = boost::dynamic_pointer_cast( this->arguments_.stochasticProcess); DayCounter rfdc = process->riskFreeRate()->dayCounter(); DayCounter divdc = process->dividendYield()->dayCounter(); Time resetTime = rfdc.yearFraction( process->riskFreeRate()->referenceDate(), this->arguments_.resetDate); DiscountFactor discQ = process->dividendYield()->discount( this->arguments_.resetDate); this->results_.value = discQ * originalResults_->value; // I need the strike derivative here ... this->results_.delta = discQ * (originalResults_->delta + this->arguments_.moneyness * originalResults_->strikeSensitivity); this->results_.gamma = 0.0; this->results_.theta = process->dividendYield()-> zeroRate(this->arguments_.resetDate, divdc, Continuous, NoFrequency) * this->results_.value; this->results_.vega = discQ * originalResults_->vega; this->results_.rho = discQ * originalResults_->rho; this->results_.dividendRho = - resetTime * this->results_.value + discQ * originalResults_->dividendRho; } } #endif