39#include <ql/experimental/coupons/cmsspreadcoupon.hpp>
40#include <ql/math/integrals/kronrodintegral.hpp>
41#include <ql/pricingengines/blackformula.hpp>
42#include <ql/termstructures/volatility/swaption/swaptionvolcube.hpp>
44#include <boost/make_shared.hpp>
52class LognormalCmsSpreadPricer::integrand_f {
53 const LognormalCmsSpreadPricer* pricer;
56 explicit integrand_f(
const LognormalCmsSpreadPricer* pricer) : pricer(pricer) {}
57 Real operator()(Real x)
const {
return pricer->integrand(x); }
61 const Handle<QuantExt::CorrelationTermStructure>& correlation,
62 const Handle<YieldTermStructure>& couponDiscountCurve,
63 const Size integrationPoints,
64 const boost::optional<VolatilityType> volatilityType,
65 const Real shift1,
const Real shift2)
72 QL_REQUIRE(integrationPoints >= 4,
"at least 4 integration points should be used (" << integrationPoints <<
")");
73 integrator_ = QuantLib::ext::make_shared<GaussHermiteIntegration>(integrationPoints);
75 cnd_ = QuantLib::ext::make_shared<CumulativeNormalDistribution>(0.0, 1.0);
77 if (volatilityType == boost::none) {
78 QL_REQUIRE(shift1 == Null<Real>() && shift2 == Null<Real>(),
79 "if volatility type is inherited, no shifts should be "
82 volType_ = cmsPricer->swaptionVolatility()->volatilityType();
84 shift1_ = shift1 == Null<Real>() ? 0.0 : shift1;
85 shift2_ = shift2 == Null<Real>() ? 0.0 : shift2;
111 return std::exp(-x * x) * f;
118 Real s = M_SQRT2 * x;
123 ? std::max(beta, 0.0)
126 return std::exp(-x * x) * f;
131 coupon_ =
dynamic_cast<const CmsSpreadCoupon*
>(&coupon);
132 QL_REQUIRE(
coupon_,
"CMS spread coupon needed");
149 today_ = QuantLib::Settings::instance().evaluationDate();
153 ?
index_->swapIndex1()->discountingTermStructure()
154 :
index_->swapIndex1()->forwardingTermStructure();
167 c1_ = QuantLib::ext::shared_ptr<CmsCoupon>(
172 c2_ = QuantLib::ext::shared_ptr<CmsCoupon>(
190 QuantLib::ext::shared_ptr<SwaptionVolatilityStructure> swvol = *
cmsPricer_->swaptionVolatility();
191 QuantLib::ext::shared_ptr<SwaptionVolatilityCube> swcub = QuantLib::ext::dynamic_pointer_cast<SwaptionVolatilityCube>(swvol);
202 "type must be inherited");
229 phi_ = optionType == Option::Call ? 1.0 : -1.0;
255 res += 1.0 / M_SQRTPI * (*integrator_)(
integrand_f(
this));
262 res = bachelierBlackFormula(
optionType_, strike, forward, stddev, 1.0);
base pricer for vanilla CMS spread coupons with a correlation surface
virtual Real capletPrice(Rate effectiveCap) const override
virtual Rate floorletRate(Rate effectiveFloor) const override
QuantLib::ext::shared_ptr< CmsCoupon > c1_
void initialize(const FloatingRateCoupon &coupon) override
QuantLib::ext::shared_ptr< GaussianQuadrature > integrator_
Real integrand_normal(const Real) const
QuantLib::ext::shared_ptr< CmsCoupon > c2_
QuantLib::ext::shared_ptr< CmsCouponPricer > cmsPricer_
bool inheritedVolatilityType_
QuantLib::ext::shared_ptr< SwapSpreadIndex > index_
QuantLib::ext::shared_ptr< CumulativeNormalDistribution > cnd_
Handle< YieldTermStructure > couponDiscountCurve_
const CmsSpreadCoupon * coupon_
virtual Rate swapletRate() const override
LognormalCmsSpreadPricer(const QuantLib::ext::shared_ptr< CmsCouponPricer > cmsPricer, const Handle< QuantExt::CorrelationTermStructure > &correlation, const Handle< YieldTermStructure > &couponDiscountCurve=Handle< YieldTermStructure >(), const Size IntegrationPoints=16, const boost::optional< VolatilityType > volatilityType=boost::none, const Real shift1=Null< Real >(), const Real shift2=Null< Real >())
virtual Real floorletPrice(Rate effectiveFloor) const override
virtual Real swapletPrice() const override
Real integrand(const Real) const
Real optionletPrice(Option::Type optionType, Real strike) const
virtual Rate capletRate(Rate effectiveCap) const override
cms spread coupon pricer as in Brigo, Mercurio, 13.6.2, with extensions for shifted lognormal and nor...
Filter close_enough(const RandomVariable &x, const RandomVariable &y)