FdmHestonEquityPart::FdmHestonEquityPart( const boost::shared_ptr<FdmMesher>& mesher, const boost::shared_ptr<YieldTermStructure>& rTS, const boost::shared_ptr<YieldTermStructure>& qTS, const boost::shared_ptr<FdmQuantoHelper>& quantoHelper, const boost::shared_ptr<LocalVolTermStructure>& leverageFct) : varianceValues_(0.5*mesher->locations(1)), dxMap_ (FirstDerivativeOp(0, mesher)), dxxMap_(SecondDerivativeOp(0, mesher).mult(0.5*mesher->locations(1))), mapT_ (0, mesher), mesher_(mesher), rTS_(rTS), qTS_(qTS), quantoHelper_(quantoHelper), leverageFct_(leverageFct) { // on the boundary s_min and s_max the second derivative // d^2V/dS^2 is zero and due to Ito's Lemma the variance term // in the drift should vanish. boost::shared_ptr<FdmLinearOpLayout> layout = mesher_->layout(); FdmLinearOpIterator endIter = layout->end(); for (FdmLinearOpIterator iter = layout->begin(); iter != endIter; ++iter) { if ( iter.coordinates()[0] == 0 || iter.coordinates()[0] == layout->dim()[0]-1) { varianceValues_[iter.index()] = 0.0; } } volatilityValues_ = Sqrt(2*varianceValues_); }
FdmHestonHullWhiteOp::FdmHestonHullWhiteOp( const boost::shared_ptr<FdmMesher>& mesher, const boost::shared_ptr<HestonProcess>& hestonProcess, const boost::shared_ptr<HullWhiteProcess>& hwProcess, Real equityShortRateCorrelation) : v0_(hestonProcess->v0()), kappa_(hestonProcess->kappa()), theta_(hestonProcess->theta()), sigma_(hestonProcess->sigma()), rho_(hestonProcess->rho()), hwModel_(new HullWhite(hestonProcess->riskFreeRate(), hwProcess->a(), hwProcess->sigma())), hestonCorrMap_(SecondOrderMixedDerivativeOp(0, 1, mesher) .mult(rho_*sigma_*mesher->locations(1))), equityIrCorrMap_(SecondOrderMixedDerivativeOp(0, 2, mesher) .mult(Sqrt(mesher->locations(1)) * hwProcess->sigma() * equityShortRateCorrelation)), dyMap_(SecondDerivativeOp(1u, mesher) .mult(0.5*sigma_*sigma_*mesher->locations(1)) .add(FirstDerivativeOp(1, mesher) .mult(kappa_*(theta_ - mesher->locations(1))))), dxMap_(mesher, hwModel_, hestonProcess->dividendYield().currentLink()), hullWhiteOp_(mesher, hwModel_, 2) { QL_REQUIRE( equityShortRateCorrelation*equityShortRateCorrelation + hestonProcess->rho()*hestonProcess->rho() <= 1.0, "correlation matrix has negative eigenvalues"); }
FdmZabrUnderlyingPart::FdmZabrUnderlyingPart(const boost::shared_ptr<FdmMesher>& mesher, const Real beta, const Real nu, const Real rho, const Real gamma) : forwardValues_(mesher->locations(0)), volatilityValues_(mesher->locations(1)), mapT_ (SecondDerivativeOp(0, mesher).mult(0.5*volatilityValues_*volatilityValues_*Pow(Abs(forwardValues_),2.0*beta))), mesher_(mesher) { }
FdmHestonHullWhiteEquityPart::FdmHestonHullWhiteEquityPart( const boost::shared_ptr<FdmMesher>& mesher, const boost::shared_ptr<HullWhite>& hwModel, const boost::shared_ptr<YieldTermStructure>& qTS) : x_(mesher->locations(2)), varianceValues_(0.5*mesher->locations(1)), dxMap_ (FirstDerivativeOp(0, mesher)), dxxMap_(SecondDerivativeOp(0, mesher).mult(0.5*mesher->locations(1))), mapT_ (0, mesher), hwModel_(hwModel), mesher_ (mesher), qTS_(qTS) { // on the boundary s_min and s_max the second derivative // d²V/dS² is zero and due to Ito's Lemma the variance term // in the drift should vanish. const boost::shared_ptr<FdmLinearOpLayout> layout = mesher_->layout(); const FdmLinearOpIterator endIter = layout->end(); for (FdmLinearOpIterator iter = layout->begin(); iter != endIter; ++iter) { if ( iter.coordinates()[0] == 0 || iter.coordinates()[0] == layout->dim()[0]-1) { varianceValues_[iter.index()] = 0.0; } } volatilityValues_ = Sqrt(2*varianceValues_); }
FdmHestonHullWhiteVariancePart::FdmHestonHullWhiteVariancePart( const boost::shared_ptr<FdmMesher>& mesher, Real sigma, Real kappa, Real theta) : dyMap_(SecondDerivativeOp(1, mesher) .mult(0.5*sigma*sigma*mesher->locations(1)) .add(FirstDerivativeOp(1, mesher) .mult(kappa*(theta - mesher->locations(1))))) { }
FdmZabrVolatilityPart::FdmZabrVolatilityPart( const ext::shared_ptr<FdmMesher> &mesher, const Real beta, const Real nu, const Real rho, const Real gamma) : volatilityValues_(mesher->locations(1)), forwardValues_(mesher->locations(0)), mapT_(SecondDerivativeOp(1, mesher).mult( 0.5 * nu * nu * Pow(volatilityValues_, 2.0 * gamma))), mesher_(mesher) {}
FdmHestonVariancePart::FdmHestonVariancePart( const boost::shared_ptr<FdmMesher>& mesher, const boost::shared_ptr<YieldTermStructure>& rTS, Real sigma, Real kappa, Real theta) : dyMap_(SecondDerivativeOp(1, mesher) .mult(0.5*sigma*sigma*mesher->locations(1)) .add(FirstDerivativeOp(1, mesher) .mult(kappa*(theta - mesher->locations(1))))), mapT_(1, mesher), rTS_(rTS) { }
FdmHestonHullWhiteRatesPart::FdmHestonHullWhiteRatesPart( const boost::shared_ptr<FdmMesher>& mesher, const boost::shared_ptr<HullWhiteProcess>& hwProcess) : rates_(mesher->locations(2)), dzMap_(FirstDerivativeOp(2, mesher)), dzzMap_(SecondDerivativeOp(2, mesher) .mult(0.5*hwProcess->sigma()*hwProcess->sigma() *Array(mesher->layout()->size(), 1.)) .add(-mesher->locations(2))), mapT_(2, mesher), hwProcess_(hwProcess) { }
FdmHullWhiteOp::FdmHullWhiteOp( const boost::shared_ptr<FdmMesher>& mesher, const boost::shared_ptr<HullWhite>& model, Size direction) : direction_(direction), x_(mesher->locations(direction)), dzMap_(FirstDerivativeOp(direction, mesher).mult(-x_*model->a()).add( SecondDerivativeOp(direction, mesher) .mult(0.5*model->sigma()*model->sigma() *Array(mesher->layout()->size(), 1.0)))), mapT_(direction, mesher), model_(model) { }
FdmHestonFwdOp::FdmHestonFwdOp( const boost::shared_ptr<FdmMesher>& mesher, const boost::shared_ptr<HestonProcess>& process, FdmSquareRootFwdOp::TransformationType type) : type_ (type), kappa_(process->kappa()), theta_(process->theta()), sigma_(process->sigma()), rho_ (process->rho()), v0_ (process->v0()), rTS_ (process->riskFreeRate().currentLink()), qTS_ (process->dividendYield().currentLink()), varianceValues_(0.5*mesher->locations(1)), dxMap_ (new FirstDerivativeOp(0, mesher)), dxxMap_(new ModTripleBandLinearOp(TripleBandLinearOp( SecondDerivativeOp(0, mesher).mult(0.5*mesher->locations(1))))), mapX_ (new TripleBandLinearOp(0, mesher)), mapY_ (new FdmSquareRootFwdOp(mesher,kappa_,theta_,sigma_, 1, type)), correlation_(new NinePointLinearOp( SecondOrderMixedDerivativeOp(0, 1, mesher) .mult(rho_*sigma_*mesher->locations(1)))) { const boost::shared_ptr<FdmLinearOpLayout> layout = mesher->layout(); if (type_ == FdmSquareRootFwdOp::Plain) { // zero flux boundary condition const Size n = layout->dim()[1]; const Real alpha = 2*rho_*mapY_->v(0)/sigma_*mapY_->f0(); const Real beta = 2*rho_*mapY_->v(n)/sigma_*mapY_->f1(); ModTripleBandLinearOp fDx(FirstDerivativeOp(0, mesher)); const FdmLinearOpIterator endIter = layout->end(); for (FdmLinearOpIterator iter = layout->begin(); iter != endIter; ++iter) { if (iter.coordinates()[1] == 0) { const Size idx = iter.index(); dxxMap_->upper()[idx] += alpha*fDx.upper()[idx]; dxxMap_->diag()[idx] += alpha*fDx.diag()[idx]; dxxMap_->lower()[idx] += alpha*fDx.lower()[idx]; } else if (iter.coordinates()[1] == n-1) { const Size idx = iter.index(); dxxMap_->upper()[idx] += beta*fDx.upper()[idx]; dxxMap_->diag()[idx] += beta*fDx.diag()[idx]; dxxMap_->lower()[idx] += beta*fDx.lower()[idx]; } } } }
FdmG2Op::FdmG2Op( const boost::shared_ptr<FdmMesher>& mesher, const boost::shared_ptr<G2>& model, Size direction1, Size direction2) : direction1_(direction1), direction2_(direction2), x_(mesher->locations(direction1)), y_(mesher->locations(direction2)), dxMap_(FirstDerivativeOp(direction1, mesher).mult(-x_*model->a()).add( SecondDerivativeOp(direction1, mesher) .mult(0.5*model->sigma()*model->sigma() *Array(mesher->layout()->size(), 1.0)))), dyMap_(FirstDerivativeOp(direction2, mesher).mult(-y_*model->b()).add( SecondDerivativeOp(direction2, mesher) .mult(0.5*model->eta()*model->eta() *Array(mesher->layout()->size(), 1.0)))), corrMap_(SecondOrderMixedDerivativeOp(direction1, direction2, mesher) .mult(Array(mesher->layout()->size(), model->rho()*model->sigma()*model->eta()))), mapX_(direction1, mesher), mapY_(direction2, mesher), model_(model) { }
FdmExtendedOrnsteinUhlenbackOp::FdmExtendedOrnsteinUhlenbackOp( const boost::shared_ptr<FdmMesher>& mesher, const boost::shared_ptr<ExtendedOrnsteinUhlenbeckProcess>& process, const boost::shared_ptr<YieldTermStructure>& rTS, const FdmBoundaryConditionSet& bcSet, Size direction) : mesher_ (mesher), process_ (process), rTS_ (rTS), bcSet_ (bcSet), direction_(direction), x_ (mesher->locations(direction)), dxMap_ (direction, mesher), dxxMap_ (SecondDerivativeOp(direction, mesher) .mult(0.5*square<Real>()(process_->volatility()) *Array(mesher->layout()->size(), 1.))), mapX_ (direction, mesher) { }
FdmBlackScholesOp::FdmBlackScholesOp( const boost::shared_ptr<FdmMesher>& mesher, const boost::shared_ptr<GeneralizedBlackScholesProcess> & bsProcess, Real strike, bool localVol, Real illegalLocalVolOverwrite, Size direction) : mesher_(mesher), rTS_ (bsProcess->riskFreeRate().currentLink()), qTS_ (bsProcess->dividendYield().currentLink()), volTS_ (bsProcess->blackVolatility().currentLink()), localVol_((localVol) ? bsProcess->localVolatility().currentLink() : boost::shared_ptr<LocalVolTermStructure>()), x_ ((localVol) ? Array(Exp(mesher->locations(direction))) : Array()), dxMap_ (FirstDerivativeOp(direction, mesher)), dxxMap_(SecondDerivativeOp(direction, mesher)), mapT_ (direction, mesher), strike_(strike), illegalLocalVolOverwrite_(illegalLocalVolOverwrite), direction_(direction) { }
FdmDupire1dOp::FdmDupire1dOp(const boost::shared_ptr<FdmMesher> &mesher, const Array &localVolatility) : mesher_(mesher), localVolatility_(localVolatility), mapT_(SecondDerivativeOp(0, mesher) .mult(0.5 * localVolatility * localVolatility)) {}