boost::shared_ptr<SmileSection> SwaptionVolCube2::smileSectionImpl(const Date& optionDate, const Period& swapTenor) const { calculate(); Rate atmForward = atmStrike(optionDate, swapTenor); Volatility atmVol = atmVol_->volatility(optionDate, swapTenor, atmForward); Time optionTime = timeFromReference(optionDate); Real exerciseTimeSqrt = std::sqrt(optionTime); std::vector<Real> strikes, stdDevs; strikes.reserve(nStrikes_); stdDevs.reserve(nStrikes_); Time length = swapLength(swapTenor); for (Size i=0; i<nStrikes_; ++i) { strikes.push_back(atmForward + strikeSpreads_[i]); stdDevs.push_back(exerciseTimeSqrt*( atmVol + volSpreadsInterpolator_[i](length, optionTime))); } Real shift = atmVol_->shift(optionTime,length); return boost::shared_ptr<SmileSection>(new InterpolatedSmileSection<Linear>(optionTime, strikes, stdDevs, atmForward, Linear(), Actual365Fixed(), volatilityType(), shift)); }
Real SmileSection::density(Rate strike, Real discount, Real gap) const { Real m = volatilityType() == ShiftedLognormal ? -shift() : -QL_MAX_REAL; Real kl = std::max(strike-gap/2.0,m); Real kr = kl+gap; return (digitalOptionPrice(kl,Option::Call,discount,gap) - digitalOptionPrice(kr,Option::Call,discount,gap)) / gap; }
boost::shared_ptr<SmileSection> SwaptionVolatilityMatrix::smileSectionImpl(Time optionTime, Time swapLength) const { // dummy strike Volatility atmVol = volatilityImpl(optionTime, swapLength, 0.05); return boost::shared_ptr<SmileSection>(new FlatSmileSection( optionTime, atmVol, dayCounter(), Null<Real>(), volatilityType(), shift(optionTime, swapLength, true))); }
Real SmileSection::digitalOptionPrice(Rate strike, Option::Type type, Real discount, Real gap) const { Real m = volatilityType() == ShiftedLognormal ? -shift() : -QL_MAX_REAL; Real kl = std::max(strike-gap/2.0,m); Real kr = kl+gap; return (type==Option::Call ? 1.0 : -1.0) * (optionPrice(kl,type,discount)-optionPrice(kr,type,discount)) / gap; }
Real SmileSection::vega(Rate strike, Real discount) const { Real atm = atmLevel(); QL_REQUIRE(atm != Null<Real>(), "smile section must provide atm level to compute option vega"); if (volatilityType() == ShiftedLognormal) return blackFormulaVolDerivative(strike,atmLevel(), sqrt(variance(strike)), exerciseTime(),discount,shift())*0.01; else QL_FAIL("vega for normal smilesection not yet implemented"); }
Real SmileSection::optionPrice(Rate strike, Option::Type type, Real discount) const { Real atm = atmLevel(); QL_REQUIRE(atm != Null<Real>(), "smile section must provide atm level to compute option price"); // if lognormal or shifted lognormal, // for strike at -shift, return option price even if outside // minstrike, maxstrike interval if (volatilityType() == ShiftedLognormal) return blackFormula(type,strike,atm, fabs(strike+shift()) < QL_EPSILON ? 0.2 : sqrt(variance(strike)),discount,shift()); else return bachelierBlackFormula(type,strike,atm,sqrt(variance(strike)),discount); }
boost::shared_ptr<SmileSection> StrippedOptionletAdapter::smileSectionImpl(Time t) const { std::vector< Rate > optionletStrikes = optionletStripper_->optionletStrikes( 0); // strikes are the same for all times ?! std::vector< Real > stddevs; for (Size i = 0; i < optionletStrikes.size(); i++) { stddevs.push_back(volatilityImpl(t, optionletStrikes[i]) * std::sqrt(t)); } // Extrapolation may be a problem with splines, but since minStrike() // and maxStrike() are set, we assume that no one will use stddevs for // strikes outside these strikes CubicInterpolation::BoundaryCondition bc = optionletStrikes.size() >= 4 ? CubicInterpolation::Lagrange : CubicInterpolation::SecondDerivative; return boost::make_shared< InterpolatedSmileSection< Cubic > >( t, optionletStrikes, stddevs, Null< Real >(), Cubic(CubicInterpolation::Spline, false, bc, 0.0, bc, 0.0), Actual365Fixed(), volatilityType(), displacement()); }
inline Real SwaptionVolatilityStructure::shiftImpl(Time, Time) const { QL_REQUIRE( volatilityType() == ShiftedLognormal, "shift parameter only makes sense for lognormal volatilities"); return 0.0; }