// other public override void setupArguments(IPricingEngineArguments args) { base.setupArguments(args); AssetSwap.Arguments arguments = args as AssetSwap.Arguments; if (arguments == null) // it's a swap engine... { return; } List <CashFlow> fixedCoupons = bondLeg(); arguments.fixedResetDates = arguments.fixedPayDates = new List <Date>(fixedCoupons.Count); arguments.fixedCoupons = new List <double>(fixedCoupons.Count); for (int i = 0; i < fixedCoupons.Count; ++i) { FixedRateCoupon coupon = fixedCoupons[i] as FixedRateCoupon; arguments.fixedPayDates[i] = coupon.date(); arguments.fixedResetDates[i] = coupon.accrualStartDate(); arguments.fixedCoupons[i] = coupon.amount(); } List <CashFlow> floatingCoupons = floatingLeg(); arguments.floatingResetDates = arguments.floatingPayDates = arguments.floatingFixingDates = new List <Date>(floatingCoupons.Count); arguments.floatingAccrualTimes = new List <double>(floatingCoupons.Count); arguments.floatingSpreads = new List <double>(floatingCoupons.Count); for (int i = 0; i < floatingCoupons.Count; ++i) { FloatingRateCoupon coupon = floatingCoupons[i] as FloatingRateCoupon; arguments.floatingResetDates[i] = coupon.accrualStartDate(); arguments.floatingPayDates[i] = coupon.date(); arguments.floatingFixingDates[i] = coupon.fixingDate(); arguments.floatingAccrualTimes[i] = coupon.accrualPeriod(); arguments.floatingSpreads[i] = coupon.spread(); } }
public override void initialize(FloatingRateCoupon coupon) { coupon_ = coupon as RangeAccrualFloatersCoupon; Utils.QL_REQUIRE(coupon_ != null, () => "range-accrual coupon required"); gearing_ = coupon_.gearing(); spread_ = coupon_.spread(); Date paymentDate = coupon_.date(); IborIndex index = coupon_.index() as IborIndex; Utils.QL_REQUIRE(index != null, () => "invalid index"); Handle <YieldTermStructure> rateCurve = index.forwardingTermStructure(); discount_ = rateCurve.link.discount(paymentDate); accrualFactor_ = coupon_.accrualPeriod(); spreadLegValue_ = spread_ * accrualFactor_ * discount_; startTime_ = coupon_.startTime(); endTime_ = coupon_.endTime(); observationTimes_ = coupon_.observationTimes(); lowerTrigger_ = coupon_.lowerTrigger(); upperTrigger_ = coupon_.upperTrigger(); observationsNo_ = coupon_.observationsNo(); List <Date> observationDates = coupon_.observationsSchedule().dates(); Utils.QL_REQUIRE(observationDates.Count == observationsNo_ + 2, () => "incompatible size of initialValues vector"); initialValues_ = new InitializedList <double>(observationDates.Count, 0.0); Calendar calendar = index.fixingCalendar(); for (int i = 0; i < observationDates.Count; i++) { initialValues_[i] = index.fixing( calendar.advance(observationDates[i], -coupon_.fixingDays, TimeUnit.Days)); } }
public override void setupArguments(IPricingEngineArguments args) { CapFloor.Arguments arguments = args as CapFloor.Arguments; if (arguments == null) { throw new ArgumentException("wrong argument type"); } int n = floatingLeg_.Count; arguments.startDates = new InitializedList <Date>(n); arguments.fixingDates = new InitializedList <Date>(n); arguments.endDates = new InitializedList <Date>(n); arguments.accrualTimes = new InitializedList <double>(n); arguments.forwards = new InitializedList <double?>(n); arguments.nominals = new InitializedList <double>(n); arguments.gearings = new InitializedList <double>(n); arguments.capRates = new InitializedList <double?>(n); arguments.floorRates = new InitializedList <double?>(n); arguments.spreads = new InitializedList <double>(n); arguments.type = type_; Date today = Settings.Instance.evaluationDate(); for (int i = 0; i < n; ++i) { FloatingRateCoupon coupon = floatingLeg_[i] as FloatingRateCoupon; if (coupon == null) { throw new ArgumentException("non-FloatingRateCoupon given"); } arguments.startDates[i] = coupon.accrualStartDate(); arguments.fixingDates[i] = coupon.fixingDate(); arguments.endDates[i] = coupon.date(); // this is passed explicitly for precision arguments.accrualTimes[i] = coupon.accrualPeriod(); // this is passed explicitly for precision... if (arguments.endDates[i] >= today) { // ...but only if needed arguments.forwards[i] = coupon.adjustedFixing; } else { arguments.forwards[i] = null; } arguments.nominals[i] = coupon.nominal(); double spread = coupon.spread(); double gearing = coupon.gearing(); arguments.gearings[i] = gearing; arguments.spreads[i] = spread; if (type_ == CapFloorType.Cap || type_ == CapFloorType.Collar) { arguments.capRates[i] = (capRates_[i] - spread) / gearing; } else { arguments.capRates[i] = null; } if (type_ == CapFloorType.Floor || type_ == CapFloorType.Collar) { arguments.floorRates[i] = (floorRates_[i] - spread) / gearing; } else { arguments.floorRates[i] = null; } } }
public override void initialize(FloatingRateCoupon coupon) { coupon_ = coupon as OvernightIndexedCoupon; Utils.QL_REQUIRE(coupon_ != null, () => "wrong coupon type"); }
public override void initialize(FloatingRateCoupon coupon) { coupon_ = coupon as CmsCoupon; Utils.QL_REQUIRE(coupon_ != null, () => "CMS coupon needed"); gearing_ = coupon_.gearing(); spread_ = coupon_.spread(); fixingDate_ = coupon_.fixingDate(); paymentDate_ = coupon_.date(); SwapIndex swapIndex = coupon_.swapIndex(); rateCurve_ = swapIndex.forwardingTermStructure().link; Date today = Settings.Instance.evaluationDate(); if (paymentDate_ > today) { discount_ = rateCurve_.discount(paymentDate_); } else { discount_ = 1.0; } spreadLegValue_ = spread_ * coupon_.accrualPeriod() * discount_; if (fixingDate_ > today) { swapTenor_ = swapIndex.tenor(); VanillaSwap swap = swapIndex.underlyingSwap(fixingDate_); swapRateValue_ = swap.fairRate(); annuity_ = Math.Abs(swap.fixedLegBPS() / Const.BASIS_POINT); int q = (int)swapIndex.fixedLegTenor().frequency(); Schedule schedule = swap.fixedSchedule(); DayCounter dc = swapIndex.dayCounter(); double startTime = dc.yearFraction(rateCurve_.referenceDate(), swap.startDate()); double swapFirstPaymentTime = dc.yearFraction(rateCurve_.referenceDate(), schedule.date(1)); double paymentTime = dc.yearFraction(rateCurve_.referenceDate(), paymentDate_); double delta = (paymentTime - startTime) / (swapFirstPaymentTime - startTime); switch (modelOfYieldCurve_) { case GFunctionFactory.YieldCurveModel.Standard: gFunction_ = GFunctionFactory.newGFunctionStandard(q, delta, swapTenor_.length()); break; case GFunctionFactory.YieldCurveModel.ExactYield: gFunction_ = GFunctionFactory.newGFunctionExactYield(coupon_); break; case GFunctionFactory.YieldCurveModel.ParallelShifts: { Handle <Quote> nullMeanReversionQuote = new Handle <Quote>(new SimpleQuote(0.0)); gFunction_ = GFunctionFactory.newGFunctionWithShifts(coupon_, nullMeanReversionQuote); } break; case GFunctionFactory.YieldCurveModel.NonParallelShifts: gFunction_ = GFunctionFactory.newGFunctionWithShifts(coupon_, meanReversion_); break; default: Utils.QL_FAIL("unknown/illegal gFunction type"); break; } vanillaOptionPricer_ = new BlackVanillaOptionPricer(swapRateValue_, fixingDate_, swapTenor_, swaptionVolatility().link); } }
// LazyObject interface protected override void performCalculations() { // update dates Date referenceDate = termVolSurface_.referenceDate(); DayCounter dc = termVolSurface_.dayCounter(); BlackCapFloorEngine dummy = new BlackCapFloorEngine( // discounting does not matter here iborIndex_.forwardingTermStructure(), 0.20, dc); for (int i = 0; i < nOptionletTenors_; ++i) { CapFloor temp = new MakeCapFloor(CapFloorType.Cap, capFloorLengths_[i], iborIndex_, 0.04, // dummy strike new Period(0, TimeUnit.Days)) .withPricingEngine(dummy); FloatingRateCoupon lFRC = temp.lastFloatingRateCoupon(); optionletDates_[i] = lFRC.fixingDate(); optionletPaymentDates_[i] = lFRC.date(); optionletAccrualPeriods_[i] = lFRC.accrualPeriod(); optionletTimes_[i] = dc.yearFraction(referenceDate, optionletDates_[i]); atmOptionletRate_[i] = lFRC.indexFixing(); } if (floatingSwitchStrike_ && capFlooMatrixNotInitialized_) { double averageAtmOptionletRate = 0.0; for (int i = 0; i < nOptionletTenors_; ++i) { averageAtmOptionletRate += atmOptionletRate_[i]; } switchStrike_ = averageAtmOptionletRate / nOptionletTenors_; } Handle <YieldTermStructure> discountCurve = discount_.empty() ? iborIndex_.forwardingTermStructure() : discount_; List <double> strikes = new List <double>(termVolSurface_.strikes()); // initialize CapFloorMatrix if (capFlooMatrixNotInitialized_) { for (int i = 0; i < nOptionletTenors_; ++i) { capFloors_[i] = new List <CapFloor>(nStrikes_); } // construction might go here for (int j = 0; j < nStrikes_; ++j) { // using out-of-the-money options CapFloorType capFloorType = strikes[j] < switchStrike_ ? CapFloorType.Floor : CapFloorType.Cap; for (int i = 0; i < nOptionletTenors_; ++i) { if (volatilityType_ == VolatilityType.ShiftedLognormal) { BlackCapFloorEngine engine = new BlackCapFloorEngine(discountCurve, new Handle <Quote>(volQuotes_[i][j]), dc, displacement_); capFloors_[i].Add(new MakeCapFloor(capFloorType, capFloorLengths_[i], iborIndex_, strikes[j], new Period(0, TimeUnit.Days)).withPricingEngine(engine)); } else if (volatilityType_ == VolatilityType.Normal) { BachelierCapFloorEngine engine = new BachelierCapFloorEngine(discountCurve, new Handle <Quote>(volQuotes_[i][j]), dc); capFloors_[i].Add(new MakeCapFloor(capFloorType, capFloorLengths_[i], iborIndex_, strikes[j], new Period(0, TimeUnit.Days)).withPricingEngine(engine)); } else { Utils.QL_FAIL("unknown volatility type: " + volatilityType_); } } } capFlooMatrixNotInitialized_ = false; } for (int j = 0; j < nStrikes_; ++j) { Option.Type optionletType = strikes[j] < switchStrike_ ? Option.Type.Put : Option.Type.Call; double previousCapFloorPrice = 0.0; for (int i = 0; i < nOptionletTenors_; ++i) { capFloorVols_[i, j] = termVolSurface_.volatility(capFloorLengths_[i], strikes[j], true); volQuotes_[i][j].setValue(capFloorVols_[i, j]); capFloorPrices_[i, j] = capFloors_[i][j].NPV(); optionletPrices_[i, j] = capFloorPrices_[i, j] - previousCapFloorPrice; previousCapFloorPrice = capFloorPrices_[i, j]; double d = discountCurve.link.discount(optionletPaymentDates_[i]); double optionletAnnuity = optionletAccrualPeriods_[i] * d; try { if (volatilityType_ == VolatilityType.ShiftedLognormal) { optionletStDevs_[i, j] = Utils.blackFormulaImpliedStdDev(optionletType, strikes[j], atmOptionletRate_[i], optionletPrices_[i, j], optionletAnnuity, displacement_, optionletStDevs_[i, j], accuracy_, maxIter_); } else if (volatilityType_ == VolatilityType.Normal) { optionletStDevs_[i, j] = Math.Sqrt(optionletTimes_[i]) * Utils.bachelierBlackFormulaImpliedVol( optionletType, strikes[j], atmOptionletRate_[i], optionletTimes_[i], optionletPrices_[i, j], optionletAnnuity); } else { Utils.QL_FAIL("Unknown volatility type: " + volatilityType_); } } catch (Exception e) { if (dontThrow_) { optionletStDevs_[i, j] = 0.0; } else { Utils.QL_FAIL("could not bootstrap optionlet:" + "\n type: " + optionletType + "\n strike: " + (strikes[j]) + "\n atm: " + (atmOptionletRate_[i]) + "\n price: " + optionletPrices_[i, j] + "\n annuity: " + optionletAnnuity + "\n expiry: " + optionletDates_[i] + "\n error: " + e.Message); } } optionletVolatilities_[i][j] = optionletStDevs_[i, j] / Math.Sqrt(optionletTimes_[i]); } } }
public void visit(FloatingRateCoupon c) { c.setPricer(pricer_); }
public abstract void initialize(FloatingRateCoupon coupon);
public override void initialize(FloatingRateCoupon coupon) { coupon_ = coupon as AverageBMACoupon; Utils.QL_REQUIRE(coupon_ != null, () => "wrong coupon type"); }
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(); } }
public override void initialize(FloatingRateCoupon coupon) { throw new NotImplementedException(); }
// other public override void setupArguments(IPricingEngineArguments args) { base.setupArguments(args); Arguments arguments = args as Arguments; Utils.QL_REQUIRE(arguments != null, () => "argument type does not match"); arguments.type = type_; arguments.nominal1 = nominal1_; arguments.nominal2 = nominal2_; arguments.index1 = index1_; arguments.index2 = index2_; List <CashFlow> leg1Coupons = leg1(); List <CashFlow> leg2Coupons = leg2(); arguments.leg1ResetDates = arguments.leg1PayDates = arguments.leg1FixingDates = new InitializedList <Date>(leg1Coupons.Count); arguments.leg2ResetDates = arguments.leg2PayDates = arguments.leg2FixingDates = new InitializedList <Date>(leg2Coupons.Count); arguments.leg1Spreads = arguments.leg1AccrualTimes = arguments.leg1Gearings = new InitializedList <double>(leg1Coupons.Count); arguments.leg2Spreads = arguments.leg2AccrualTimes = arguments.leg2Gearings = new InitializedList <double>(leg2Coupons.Count); arguments.leg1Coupons = new InitializedList <double?>(leg1Coupons.Count, null); arguments.leg2Coupons = new InitializedList <double?>(leg2Coupons.Count, null); arguments.leg1IsRedemptionFlow = new InitializedList <bool>(leg1Coupons.Count, false); arguments.leg2IsRedemptionFlow = new InitializedList <bool>(leg2Coupons.Count, false); arguments.leg1CappedRates = arguments.leg1FlooredRates = new InitializedList <double?>(leg1Coupons.Count, null); arguments.leg2CappedRates = arguments.leg2FlooredRates = new InitializedList <double?>(leg2Coupons.Count, null); for (int i = 0; i < leg1Coupons.Count; ++i) { FloatingRateCoupon coupon = leg1Coupons[i] as FloatingRateCoupon; if (coupon != null) { arguments.leg1AccrualTimes[i] = coupon.accrualPeriod(); arguments.leg1PayDates[i] = coupon.date(); arguments.leg1ResetDates[i] = coupon.accrualStartDate(); arguments.leg1FixingDates[i] = coupon.fixingDate(); arguments.leg1Spreads[i] = coupon.spread(); arguments.leg1Gearings[i] = coupon.gearing(); try { arguments.leg1Coupons[i] = coupon.amount(); } catch (Exception) { arguments.leg1Coupons[i] = null; } CappedFlooredCoupon cfcoupon = leg1Coupons[i] as CappedFlooredCoupon; if (cfcoupon != null) { arguments.leg1CappedRates[i] = cfcoupon.cap(); arguments.leg1FlooredRates[i] = cfcoupon.floor(); } } else { CashFlow cashflow = leg1Coupons[i] as CashFlow; int j = arguments.leg1PayDates.FindIndex(x => x == cashflow.date()); Utils.QL_REQUIRE(j != -1, () => "nominal redemption on " + cashflow.date() + "has no corresponding coupon"); int jIdx = j; // Size jIdx = j - arguments->leg1PayDates.begin(); arguments.leg1IsRedemptionFlow[i] = true; arguments.leg1Coupons[i] = cashflow.amount(); arguments.leg1ResetDates[i] = arguments.leg1ResetDates[jIdx]; arguments.leg1FixingDates[i] = arguments.leg1FixingDates[jIdx]; arguments.leg1AccrualTimes[i] = 0.0; arguments.leg1Spreads[i] = 0.0; arguments.leg1Gearings[i] = 1.0; arguments.leg1PayDates[i] = cashflow.date(); } } for (int i = 0; i < leg2Coupons.Count; ++i) { FloatingRateCoupon coupon = leg2Coupons[i] as FloatingRateCoupon; if (coupon != null) { arguments.leg2AccrualTimes[i] = coupon.accrualPeriod(); arguments.leg2PayDates[i] = coupon.date(); arguments.leg2ResetDates[i] = coupon.accrualStartDate(); arguments.leg2FixingDates[i] = coupon.fixingDate(); arguments.leg2Spreads[i] = coupon.spread(); arguments.leg2Gearings[i] = coupon.gearing(); try { arguments.leg2Coupons[i] = coupon.amount(); } catch (Exception) { arguments.leg2Coupons[i] = null; } CappedFlooredCoupon cfcoupon = leg2Coupons[i] as CappedFlooredCoupon; if (cfcoupon != null) { arguments.leg2CappedRates[i] = cfcoupon.cap(); arguments.leg2FlooredRates[i] = cfcoupon.floor(); } } else { CashFlow cashflow = leg2Coupons[i] as CashFlow; int j = arguments.leg2PayDates.FindIndex(x => x == cashflow.date()); Utils.QL_REQUIRE(j != -1, () => "nominal redemption on " + cashflow.date() + "has no corresponding coupon"); int jIdx = j; // j - arguments->leg2PayDates.begin(); arguments.leg2IsRedemptionFlow[i] = true; arguments.leg2Coupons[i] = cashflow.amount(); arguments.leg2ResetDates[i] = arguments.leg2ResetDates[jIdx]; arguments.leg2FixingDates[i] = arguments.leg2FixingDates[jIdx]; arguments.leg2AccrualTimes[i] = 0.0; arguments.leg2Spreads[i] = 0.0; arguments.leg2Gearings[i] = 1.0; arguments.leg2PayDates[i] = cashflow.date(); } } }
public override void initialize(FloatingRateCoupon coupon) { coupon_ = coupon as CmsCoupon; Utils.QL_REQUIRE(coupon_ != null, () => "CMS coupon needed"); gearing_ = coupon_.gearing(); spread_ = coupon_.spread(); fixingDate_ = coupon_.fixingDate(); paymentDate_ = coupon_.date(); swapIndex_ = coupon_.swapIndex(); forwardCurve_ = swapIndex_.forwardingTermStructure(); if (swapIndex_.exogenousDiscount()) { discountCurve_ = swapIndex_.discountingTermStructure(); } else { discountCurve_ = forwardCurve_; } // if no coupon discount curve is given just use the discounting curve // from the swap index. for rate 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_ = QLCore.Settings.Instance.evaluationDate(); if (paymentDate_ > today_ && !couponDiscountCurve_.empty()) { couponDiscountRatio_ = couponDiscountCurve_.link.discount(paymentDate_) / discountCurve_.link.discount(paymentDate_); } else { couponDiscountRatio_ = 1.0; } spreadLegValue_ = spread_ * coupon_.accrualPeriod() * discountCurve_.link.discount(paymentDate_) * couponDiscountRatio_; if (fixingDate_ > today_) { swapTenor_ = swapIndex_.tenor(); swap_ = swapIndex_.underlyingSwap(fixingDate_); swapRateValue_ = swap_.fairRate(); annuity_ = 1.0E4 * Math.Abs(swap_.fixedLegBPS()); SmileSection sectionTmp = swaptionVolatility().link.smileSection(fixingDate_, swapTenor_); // adjust bounds by section's shift shiftedLowerBound_ = settings_.lowerRateBound_ - sectionTmp.shift(); shiftedUpperBound_ = settings_.upperRateBound_ - sectionTmp.shift(); // if the section does not provide an atm level, we enhance it to // have one, no need to exit with an exception ... if (sectionTmp.atmLevel() == null) { smileSection_ = new AtmSmileSection(sectionTmp, swapRateValue_); } else { smileSection_ = sectionTmp; } // compute linear model's parameters double gx = 0.0, gy = 0.0; for (int i = 0; i < swap_.fixedLeg().Count; i++) { Coupon c = swap_.fixedLeg()[i] as Coupon; double yf = c.accrualPeriod(); Date d = c.date(); double pv = yf * discountCurve_.link.discount(d); gx += pv * GsrG(d); gy += pv; } double gamma = gx / gy; Date lastd = swap_.fixedLeg().Last().date(); a_ = discountCurve_.link.discount(paymentDate_) * (gamma - GsrG(paymentDate_)) / (discountCurve_.link.discount(lastd) * GsrG(lastd) + swapRateValue_ * gy * gamma); b_ = discountCurve_.link.discount(paymentDate_) / gy - a_ * swapRateValue_; } }
//! Constructors //! general constructor public DigitalCoupon(FloatingRateCoupon underlying, double?callStrike = null, Position.Type callPosition = Position.Type.Long, bool isCallATMIncluded = false, double?callDigitalPayoff = null, double?putStrike = null, Position.Type putPosition = Position.Type.Long, bool isPutATMIncluded = false, double?putDigitalPayoff = null, DigitalReplication replication = null) : base(underlying.date(), underlying.nominal(), underlying.accrualStartDate(), underlying.accrualEndDate(), underlying.fixingDays, underlying.index(), underlying.gearing(), underlying.spread(), underlying.referencePeriodStart, underlying.referencePeriodEnd, underlying.dayCounter(), underlying.isInArrears()) { if (replication == null) { replication = new DigitalReplication(); } underlying_ = underlying; callCsi_ = 0.0; putCsi_ = 0.0; isCallATMIncluded_ = isCallATMIncluded; isPutATMIncluded_ = isPutATMIncluded; isCallCashOrNothing_ = false; isPutCashOrNothing_ = false; callLeftEps_ = replication.gap() / 2.0; callRightEps_ = replication.gap() / 2.0; putLeftEps_ = replication.gap() / 2.0; putRightEps_ = replication.gap() / 2.0; hasPutStrike_ = false; hasCallStrike_ = false; replicationType_ = replication.replicationType(); Utils.QL_REQUIRE(replication.gap() > 0.0, () => "Non positive epsilon not allowed"); if (putStrike == null) { Utils.QL_REQUIRE(putDigitalPayoff == null, () => "Put Cash rate non allowed if put strike is null"); } if (callStrike == null) { Utils.QL_REQUIRE(callDigitalPayoff == null, () => "Call Cash rate non allowed if call strike is null"); } if (callStrike != null) { Utils.QL_REQUIRE(callStrike >= 0.0, () => "negative call strike not allowed"); hasCallStrike_ = true; callStrike_ = callStrike.GetValueOrDefault(); Utils.QL_REQUIRE(callStrike_ >= replication.gap() / 2.0, () => "call strike < eps/2"); switch (callPosition) { case Position.Type.Long: callCsi_ = 1.0; break; case Position.Type.Short: callCsi_ = -1.0; break; default: Utils.QL_FAIL("unsupported position type"); break; } if (callDigitalPayoff != null) { callDigitalPayoff_ = callDigitalPayoff.GetValueOrDefault(); isCallCashOrNothing_ = true; } } if (putStrike != null) { Utils.QL_REQUIRE(putStrike >= 0.0, () => "negative put strike not allowed"); hasPutStrike_ = true; putStrike_ = putStrike.GetValueOrDefault(); switch (putPosition) { case Position.Type.Long: putCsi_ = 1.0; break; case Position.Type.Short: putCsi_ = -1.0; break; default: Utils.QL_FAIL("unsupported position type"); break; } if (putDigitalPayoff != null) { putDigitalPayoff_ = putDigitalPayoff.GetValueOrDefault(); isPutCashOrNothing_ = true; } } switch (replicationType_) { case Replication.Type.Central: // do nothing break; case Replication.Type.Sub: if (hasCallStrike_) { switch (callPosition) { case Position.Type.Long: callLeftEps_ = 0.0; callRightEps_ = replication.gap(); break; case Position.Type.Short: callLeftEps_ = replication.gap(); callRightEps_ = 0.0; break; default: Utils.QL_FAIL("unsupported position type"); break; } } if (hasPutStrike_) { switch (putPosition) { case Position.Type.Long: putLeftEps_ = replication.gap(); putRightEps_ = 0.0; break; case Position.Type.Short: putLeftEps_ = 0.0; putRightEps_ = replication.gap(); break; default: Utils.QL_FAIL("unsupported position type"); break; } } break; case Replication.Type.Super: if (hasCallStrike_) { switch (callPosition) { case Position.Type.Long: callLeftEps_ = replication.gap(); callRightEps_ = 0.0; break; case Position.Type.Short: callLeftEps_ = 0.0; callRightEps_ = replication.gap(); break; default: Utils.QL_FAIL("unsupported position type"); break; } } if (hasPutStrike_) { switch (putPosition) { case Position.Type.Long: putLeftEps_ = 0.0; putRightEps_ = replication.gap(); break; case Position.Type.Short: putLeftEps_ = replication.gap(); putRightEps_ = 0.0; break; default: Utils.QL_FAIL("unsupported position type"); break; } } break; default: Utils.QL_FAIL("unsupported position type"); break; } underlying.registerWith(update); }
// Factory - for Leg generators public virtual CashFlow factory(FloatingRateCoupon underlying, double?callStrike, Position.Type callPosition, bool isCallATMIncluded, double?callDigitalPayoff, double?putStrike, Position.Type putPosition, bool isPutATMIncluded, double?putDigitalPayoff, DigitalReplication replication) { return(new DigitalCoupon(underlying, callStrike, callPosition, isCallATMIncluded, callDigitalPayoff, putStrike, putPosition, isPutATMIncluded, putDigitalPayoff, replication)); }