/* -*- 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 quantoengine.hpp \brief Quanto option engine */ #ifndef quantlib_quanto_engine_hpp #define quantlib_quanto_engine_hpp #include #include #include #include namespace QuantLib { //! %Arguments for quanto option calculation template class QuantoOptionArguments : public ArgumentsType { public: QuantoOptionArguments() : correlation(Null()) {} void validate() const; Real correlation; Handle foreignRiskFreeTS; Handle exchRateVolTS; }; //! %Results from quanto option calculation template class QuantoOptionResults : public ResultsType { public: QuantoOptionResults() { reset() ;} void reset() { ResultsType::reset(); qvega = qrho = qlambda = Null(); } Real qvega; Real qrho; Real qlambda; }; //! Quanto engine base class /*! \warning for the time being, this engine will only work with simple Black-Scholes processes (i.e., no Merton.) \ingroup quantoengines \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 QuantoEngine : public GenericEngine, QuantoOptionResults > { public: QuantoEngine(const boost::shared_ptr >&); void calculate() const; /*! Access to the arguments of the underlying engine is needed as this engine is not able to set them completely. When necessary, it must be done by the instrument: see QuantoForwardVanillaOption for an example. */ ArgumentsType* underlyingArgs() const { return originalArguments_; } protected: boost::shared_ptr > originalEngine_; ArgumentsType* originalArguments_; const ResultsType* originalResults_; }; // template definitions template void QuantoOptionArguments::validate() const { ArgumentsType::validate(); QL_REQUIRE(!foreignRiskFreeTS.empty(), "null foreign risk free term structure"); QL_REQUIRE(!exchRateVolTS.empty(), "null exchange rate vol term structure"); QL_REQUIRE(correlation != Null(), "null correlation given"); } template QuantoEngine::QuantoEngine( const boost::shared_ptr >& originalEngine) : originalEngine_(originalEngine) { QL_REQUIRE(originalEngine_, "null engine"); originalResults_ = dynamic_cast(originalEngine_->getResults()); originalArguments_ = dynamic_cast(originalEngine_->getArguments()); } template void QuantoEngine::calculate() const { // ATM exchangeRate level needed here Real exchangeRateATMlevel = 1.0; originalEngine_->reset(); // determine strike from payoff boost::shared_ptr payoff = boost::dynamic_pointer_cast( this->arguments_.payoff); QL_REQUIRE(payoff, "non-striked payoff given"); Real strike = payoff->strike(); originalArguments_->payoff = this->arguments_.payoff; boost::shared_ptr process = boost::dynamic_pointer_cast( this->arguments_.stochasticProcess); QL_REQUIRE(process, "Black-Scholes process required"); Handle spot = process->stateVariable(); Handle riskFreeRate = process->riskFreeRate(); // dividendTS needs modification Handle dividendYield( boost::shared_ptr( new QuantoTermStructure(process->dividendYield(), process->riskFreeRate(), this->arguments_.foreignRiskFreeTS, process->blackVolatility(), strike, this->arguments_.exchRateVolTS, exchangeRateATMlevel, this->arguments_.correlation))); Handle blackVol = process->blackVolatility(); originalArguments_->stochasticProcess = boost::shared_ptr( new GeneralizedBlackScholesProcess(spot, dividendYield, riskFreeRate, blackVol)); originalArguments_->exercise = this->arguments_.exercise; originalArguments_->validate(); originalEngine_->calculate(); this->results_.value = originalResults_->value; this->results_.delta = originalResults_->delta; this->results_.gamma = originalResults_->gamma; this->results_.theta = originalResults_->theta; this->results_.rho = originalResults_->rho + originalResults_->dividendRho; this->results_.dividendRho = originalResults_->dividendRho; Volatility exchangeRateFlatVol = this->arguments_.exchRateVolTS->blackVol( this->arguments_.exercise->lastDate(), exchangeRateATMlevel); this->results_.vega = originalResults_->vega + this->arguments_.correlation * exchangeRateFlatVol * originalResults_->dividendRho; Volatility volatility = process->blackVolatility()->blackVol( this->arguments_.exercise->lastDate(), process->stateVariable()->value()); this->results_.qvega = this->arguments_.correlation * process->blackVolatility()->blackVol( this->arguments_.exercise->lastDate(), process->stateVariable()->value()) * originalResults_->dividendRho; this->results_.qrho = - originalResults_->dividendRho; this->results_.qlambda = exchangeRateFlatVol * volatility * originalResults_->dividendRho; } } #endif