public override void initialize(FloatingRateCoupon coupon) { coupon_ = coupon as CmsSpreadCoupon; Utils.QL_REQUIRE(coupon_ != null, () => "CMS spread coupon needed"); index_ = coupon_.swapSpreadIndex(); gearing_ = coupon_.gearing(); spread_ = coupon_.spread(); fixingDate_ = coupon_.fixingDate(); paymentDate_ = coupon_.date(); // if no coupon discount curve is given just use the discounting curve // from the _first_ swap index. // for double calculation this curve cancels out in the computation, so // e.g. the discounting // swap engine will produce correct results, even if the // couponDiscountCurve is not set here. // only the price member function in this class will be dependent on the // coupon discount curve. today_ = Settings.Instance.evaluationDate(); if (couponDiscountCurve_.empty()) { couponDiscountCurve_ = index_.swapIndex1().exogenousDiscount() ? index_.swapIndex1().discountingTermStructure() : index_.swapIndex1().forwardingTermStructure(); } discount_ = paymentDate_ > couponDiscountCurve_.currentLink().referenceDate() ? couponDiscountCurve_.currentLink().discount(paymentDate_) : 1.0; spreadLegValue_ = spread_ * coupon_.accrualPeriod() * discount_; gearing1_ = index_.gearing1(); gearing2_ = index_.gearing2(); Utils.QL_REQUIRE(gearing1_ > 0.0 && gearing2_ < 0.0, () => "gearing1 (" + gearing1_ + ") should be positive while gearing2 (" + gearing2_ + ") should be negative"); c1_ = new CmsCoupon( coupon_.nominal(), coupon_.date(), coupon_.accrualStartDate(), coupon_.accrualEndDate(), coupon_.fixingDays, index_.swapIndex1(), 1.0, 0.0, coupon_.referencePeriodStart, coupon_.referencePeriodEnd, coupon_.dayCounter(), coupon_.isInArrears()); c2_ = new CmsCoupon( coupon_.nominal(), coupon_.date(), coupon_.accrualStartDate(), coupon_.accrualEndDate(), coupon_.fixingDays, index_.swapIndex2(), 1.0, 0.0, coupon_.referencePeriodStart, coupon_.referencePeriodEnd, coupon_.dayCounter(), coupon_.isInArrears()); c1_.setPricer(cmsPricer1_); c2_.setPricer(cmsPricer2_); if (fixingDate_ > today_) { fixingTime_ = cmsPricer1_.swaptionVolatility().currentLink().timeFromReference( fixingDate_); swapRate1_ = c1_.indexFixing(); swapRate2_ = c2_.indexFixing(); adjustedFixing1_ = c1_.adjustedFixing; adjustedFixing2_ = c2_.adjustedFixing; SwaptionVolatilityStructure swvol = cmsPricer1_.swaptionVolatility(); SwaptionVolatilityCube swcub = swvol as SwaptionVolatilityCube; if (inheritedVolatilityType_ && volType_ == VolatilityType.ShiftedLognormal) { shift1_ = swvol.shift(fixingDate_, index_.swapIndex1().tenor()); shift2_ = swvol.shift(fixingDate_, index_.swapIndex2().tenor()); } if (swcub == null) { // not a cube, just an atm surface given, so we can // not easily convert volatilities and just forbid it Utils.QL_REQUIRE(inheritedVolatilityType_, () => "if only an atm surface is given, the volatility type must be inherited"); vol1_ = swvol.volatility( fixingDate_, index_.swapIndex1().tenor(), swapRate1_); vol2_ = swvol.volatility( fixingDate_, index_.swapIndex2().tenor(), swapRate2_); } else { vol1_ = swcub.smileSection(fixingDate_, index_.swapIndex1().tenor()) .volatility(swapRate1_, volType_, shift1_); vol2_ = swcub.smileSection(fixingDate_, index_.swapIndex2().tenor()) .volatility(swapRate2_, volType_, shift2_); } if (volType_ == VolatilityType.ShiftedLognormal) { mu1_ = 1.0 / fixingTime_ * Math.Log((adjustedFixing1_ + shift1_) / (swapRate1_ + shift1_)); mu2_ = 1.0 / fixingTime_ * Math.Log((adjustedFixing2_ + shift2_) / (swapRate2_ + shift2_)); } // for the normal volatility case we do not need the drifts // but rather use adjusted doubles directly in the integrand rho_ = Math.Max(Math.Min(correlation().currentLink().value(), 0.9999), -0.9999); // avoid division by zero in integrand } else { // fixing is in the past or today adjustedFixing1_ = c1_.indexFixing(); adjustedFixing2_ = c2_.indexFixing(); } }