public override void initialize(FloatingRateCoupon coupon) { gearing_ = coupon.gearing(); spread_ = coupon.spread(); accrualPeriod_ = coupon.accrualPeriod(); Utils.QL_REQUIRE(accrualPeriod_.IsNotEqual(0.0), () => "null accrual period"); index_ = coupon.index() as IborIndex; if (index_ == null) { // check if the coupon was right IborCoupon c = coupon as IborCoupon; Utils.QL_REQUIRE(c != null, () => "IborCoupon required"); // coupon was right, index is not Utils.QL_FAIL("IborIndex required"); } Handle <YieldTermStructure> rateCurve = index_.forwardingTermStructure(); Date paymentDate = coupon.date(); if (paymentDate > rateCurve.link.referenceDate()) { discount_ = rateCurve.link.discount(paymentDate); } else { discount_ = 1.0; } spreadLegValue_ = spread_ * accrualPeriod_ * discount_; coupon_ = coupon; }
// 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 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; } } }
// 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]); } } }
// 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(); } } }