public List <CashFlow> expectedCashflows() { calcBondFactor(); List <CashFlow> expectedcashflows = new List <CashFlow>(); List <double> notionals = new InitializedList <double>(schedule_.Count); notionals[0] = notionals_[0]; for (int i = 0; i < schedule_.Count - 1; ++i) { double currentNotional = notionals[i]; double smm = SMM(schedule_[i]); double prepay = (notionals[i] * bondFactors_[i + 1]) / bondFactors_[i] * smm; double actualamort = currentNotional * (1 - bondFactors_[i + 1] / bondFactors_[i]); notionals[i + 1] = currentNotional - actualamort - prepay; // ADD CashFlow c1 = new VoluntaryPrepay(prepay, schedule_[i + 1]); CashFlow c2 = new AmortizingPayment(actualamort, schedule_[i + 1]); CashFlow c3 = new FixedRateCoupon(schedule_[i + 1], currentNotional, new InterestRate(PassThroughRate_, dCounter_, Compounding.Simple, Frequency.Annual), schedule_[i], schedule_[i + 1]); expectedcashflows.Add(c1); expectedcashflows.Add(c2); expectedcashflows.Add(c3); } notionals[notionals.Count - 1] = 0.0; return(expectedcashflows); }
public override void setupArguments(IPricingEngineArguments args) { base.setupArguments(args); VanillaSwap.Arguments arguments = args as VanillaSwap.Arguments; if (arguments == null) // it's a swap engine... { return; } arguments.type = type_; arguments.nominal = nominal_; List <CashFlow> fixedCoupons = fixedLeg(); arguments.fixedResetDates = new InitializedList <Date>(fixedCoupons.Count); arguments.fixedPayDates = new InitializedList <Date>(fixedCoupons.Count); arguments.fixedCoupons = new InitializedList <double>(fixedCoupons.Count); for (int i = 0; i < fixedCoupons.Count; ++i) { FixedRateCoupon coupon = (FixedRateCoupon)fixedCoupons[i]; arguments.fixedPayDates[i] = coupon.date(); arguments.fixedResetDates[i] = coupon.accrualStartDate(); arguments.fixedCoupons[i] = coupon.amount(); } List <CashFlow> floatingCoupons = floatingLeg(); arguments.floatingResetDates = new InitializedList <Date>(floatingCoupons.Count); arguments.floatingPayDates = new InitializedList <Date>(floatingCoupons.Count); arguments.floatingFixingDates = new InitializedList <Date>(floatingCoupons.Count); arguments.floatingAccrualTimes = new InitializedList <double>(floatingCoupons.Count); arguments.floatingSpreads = new InitializedList <double>(floatingCoupons.Count); arguments.floatingCoupons = new InitializedList <double>(floatingCoupons.Count); for (int i = 0; i < floatingCoupons.Count; ++i) { IborCoupon coupon = (IborCoupon)floatingCoupons[i]; 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(); try { arguments.floatingCoupons[i] = coupon.amount(); } catch { arguments.floatingCoupons[i] = default(double); } } }
public double AmortizationValue(Date d) { // Check Date if (d < _tradeDate || d > _maturityDate) { return(0); } double totAmortized = 0; Date lastDate = _tradeDate; foreach (CashFlow c in cashflows_) { if (c.date() <= d) { lastDate = c.date(); if (c is QLCore.AmortizingPayment) { totAmortized += (c as QLCore.AmortizingPayment).amount(); } } else { break; } } if (lastDate < d) { // lastDate < d let calculate last interest // Base Interest InterestRate r1 = new InterestRate(_couponRate, _dCounter, Compounding.Simple, _payFrequency); FixedRateCoupon c1 = new FixedRateCoupon(d, _faceValue, r1, lastDate, d); double baseInterest = c1.amount(); // InterestRate r2 = new InterestRate(_yield, _dCounter, Compounding.Simple, _payFrequency); FixedRateCoupon c2 = new FixedRateCoupon(d, _marketValue, r2, lastDate, d); double yieldInterest = c2.amount(); totAmortized += Math.Abs(baseInterest - yieldInterest); } if (_isPremium) { return(_marketValue - totAmortized); } else { return(_marketValue + totAmortized); } }
/// <summary> /// CDS quoted as running-spread only /// </summary> /// <param name="side">Whether the protection is bought or sold.</param> /// <param name="notional">Notional value</param> /// <param name="spread">Running spread in fractional units.</param> /// <param name="schedule">Coupon schedule.</param> /// <param name="convention">Business-day convention for payment-date adjustment.</param> /// <param name="dayCounter">Day-count convention for accrual.</param> /// <param name="settlesAccrual">Whether or not the accrued coupon is due in the event of a default.</param> /// <param name="paysAtDefaultTime">If set to true, any payments triggered by a default event are /// due at default time. If set to false, they are due at the end of the accrual period.</param> /// <param name="protectionStart">The first date where a default event will trigger the contract.</param> /// <param name="claim"></param> /// <param name="lastPeriodDayCounter">Day-count convention for accrual in last period</param> /// <param name="rebatesAccrual">The protection seller pays the accrued scheduled current coupon at the start /// of the contract. The rebate date is not provided but computed to be two days after protection start.</param> public CreditDefaultSwap(Protection.Side side, double notional, double spread, Schedule schedule, BusinessDayConvention convention, DayCounter dayCounter, bool settlesAccrual = true, bool paysAtDefaultTime = true, Date protectionStart = null, Claim claim = null, DayCounter lastPeriodDayCounter = null, bool rebatesAccrual = true) { side_ = side; notional_ = notional; upfront_ = null; runningSpread_ = spread; settlesAccrual_ = settlesAccrual; paysAtDefaultTime_ = paysAtDefaultTime; claim_ = claim; protectionStart_ = protectionStart ?? schedule[0]; Utils.QL_REQUIRE(protectionStart_ <= schedule[0] || schedule.rule() == DateGeneration.Rule.CDS || schedule.rule() == DateGeneration.Rule.CDS2015 , () => "protection can not start after accrual"); leg_ = new FixedRateLeg(schedule) .withLastPeriodDayCounter(lastPeriodDayCounter) .withCouponRates(spread, dayCounter) .withNotionals(notional) .withPaymentAdjustment(convention); Date effectiveUpfrontDate = schedule.calendar().advance(protectionStart_, 2, TimeUnit.Days, convention); // '2' is used above since the protection start is assumed to be on trade_date + 1 if (rebatesAccrual) { FixedRateCoupon firstCoupon = leg_[0] as FixedRateCoupon; Date rebateDate = effectiveUpfrontDate; accrualRebate_ = new SimpleCashFlow(firstCoupon.accruedAmount(protectionStart_), rebateDate); } upfrontPayment_ = new SimpleCashFlow(0.0, effectiveUpfrontDate); if (claim_ == null) { claim_ = new FaceValueClaim(); } claim_.registerWith(update); maturity_ = schedule.dates().Last(); }
// other public override void setupArguments(IPricingEngineArguments args) { base.setupArguments(args); YearOnYearInflationSwap.Arguments arguments = args as YearOnYearInflationSwap.Arguments; if (arguments == null) // it's a swap engine... { return; } arguments.type = type_; arguments.nominal = nominal_; List <CashFlow> fixedCoupons = fixedLeg(); 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.Add(coupon.date()); arguments.fixedResetDates.Add(coupon.accrualStartDate()); arguments.fixedCoupons.Add(coupon.amount()); } List <CashFlow> yoyCoupons = yoyLeg(); arguments.yoyResetDates = arguments.yoyPayDates = arguments.yoyFixingDates = new List <Date>(yoyCoupons.Count); arguments.yoyAccrualTimes = new List <double>(yoyCoupons.Count); arguments.yoySpreads = new List <double>(yoyCoupons.Count); arguments.yoyCoupons = new List <double?>(yoyCoupons.Count); for (int i = 0; i < yoyCoupons.Count; ++i) { YoYInflationCoupon coupon = yoyCoupons[i] as YoYInflationCoupon; arguments.yoyResetDates.Add(coupon.accrualStartDate()); arguments.yoyPayDates.Add(coupon.date()); arguments.yoyFixingDates.Add(coupon.fixingDate()); arguments.yoyAccrualTimes.Add(coupon.accrualPeriod()); arguments.yoySpreads.Add(coupon.spread()); try { arguments.yoyCoupons.Add(coupon.amount()); } catch (Exception) { arguments.yoyCoupons.Add(null); } } }
void addEffectiveInterestRateAmortizing() { // Amortizing Schedule Schedule schedule = new Schedule(_tradeDate, _maturityDate, new Period(_payFrequency), _calendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); double currentNominal = _marketValue; Date prevDate = _tradeDate; Date actualDate = _tradeDate; for (int i = 1; i < schedule.Count; ++i) { actualDate = schedule[i]; InterestRate rate = new InterestRate(_yield, _dCounter, Compounding.Simple, Frequency.Annual); InterestRate rate2 = new InterestRate(_couponRate, _dCounter, Compounding.Simple, Frequency.Annual); FixedRateCoupon r, r2; if (i > 1) { r = new FixedRateCoupon(actualDate, currentNominal, rate, prevDate, actualDate, prevDate, actualDate); r2 = new FixedRateCoupon(actualDate, currentNominal, rate2, prevDate, actualDate, prevDate, actualDate, null, _originalPayment); } else { Calendar nullCalendar = new NullCalendar(); Period p1 = new Period(_payFrequency); Date testDate = nullCalendar.advance(actualDate, -1 * p1); r = new FixedRateCoupon(actualDate, currentNominal, rate, testDate, actualDate, prevDate, actualDate); r2 = new FixedRateCoupon(actualDate, currentNominal, rate2, testDate, actualDate, prevDate, actualDate, null, _originalPayment); } double amort = Math.Round(Math.Abs(_originalPayment - r.amount()), 2); AmortizingPayment p = new AmortizingPayment(amort, actualDate); if (_isPremium) { currentNominal -= Math.Abs(amort); } else { currentNominal += Math.Abs(amort); } cashflows_.Add(r2); cashflows_.Add(p); prevDate = actualDate; } // Add single redemption for yield calculation setSingleRedemption(_faceValue, 100, _maturityDate); }
// 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(); } }
/// <summary> /// CDS quoted as upfront and running spread /// </summary> /// <param name="side">Whether the protection is bought or sold.</param> /// <param name="notional"> Notional value</param> /// <param name="upfront">Upfront in fractional units.</param> /// <param name="runningSpread">Running spread in fractional units.</param> /// <param name="schedule">Coupon schedule.</param> /// <param name="convention">Business-day convention for payment-date adjustment.</param> /// <param name="dayCounter">Day-count convention for accrual.</param> /// <param name="settlesAccrual">Whether or not the accrued coupon is due in the event of a default.</param> /// <param name="paysAtDefaultTime">If set to true, any payments triggered by a default event are /// due at default time. If set to false, they are due at the end of the accrual period.</param> /// <param name="protectionStart">The first date where a default event will trigger the contract.</param> /// <param name="upfrontDate">Settlement date for the upfront payment.</param> /// <param name="claim"></param> /// <param name="lastPeriodDayCounter">Day-count convention for accrual in last period</param> /// <param name="rebatesAccrual">The protection seller pays the accrued scheduled current coupon at the start /// of the contract. The rebate date is not provided but computed to be two days after protection start.</param> public CreditDefaultSwap(Protection.Side side, double notional, double upfront, double runningSpread, Schedule schedule, BusinessDayConvention convention, DayCounter dayCounter, bool settlesAccrual = true, bool paysAtDefaultTime = true, Date protectionStart = null, Date upfrontDate = null, Claim claim = null, DayCounter lastPeriodDayCounter = null, bool rebatesAccrual = true) { side_ = side; notional_ = notional; upfront_ = upfront; runningSpread_ = runningSpread; settlesAccrual_ = settlesAccrual; paysAtDefaultTime_ = paysAtDefaultTime; claim_ = claim; protectionStart_ = protectionStart ?? schedule[0]; Utils.QL_REQUIRE(protectionStart_ <= schedule[0] || schedule.rule() == DateGeneration.Rule.CDS , () => "protection can not start after accrual"); leg_ = new FixedRateLeg(schedule) .withLastPeriodDayCounter(lastPeriodDayCounter) .withCouponRates(runningSpread, dayCounter) .withNotionals(notional) .withPaymentAdjustment(convention); // If empty, adjust to T+3 standard settlement, alternatively add // an arbitrary date to the constructor Date effectiveUpfrontDate = upfrontDate == null? schedule.calendar().advance(protectionStart_, 2, TimeUnit.Days, convention) : upfrontDate; // '2' is used above since the protection start is assumed to be // on trade_date + 1 upfrontPayment_ = new SimpleCashFlow(notional * upfront, effectiveUpfrontDate); Utils.QL_REQUIRE(effectiveUpfrontDate >= protectionStart_, () => "upfront can not be due before contract start"); if (rebatesAccrual) { FixedRateCoupon firstCoupon = leg_[0] as FixedRateCoupon; // adjust to T+3 standard settlement, alternatively add // an arbitrary date to the constructor Date rebateDate = effectiveUpfrontDate; accrualRebate_ = new SimpleCashFlow(firstCoupon.accruedAmount(protectionStart_), rebateDate); } if (claim_ == null) { claim_ = new FaceValueClaim(); } claim_.registerWith(update); maturity_ = schedule.dates().Last(); }
public override void calculate() { Date exerciseDate = arguments_.exercise.date(0); // the part of the swap preceding exerciseDate should be truncated // to avoid taking into account unwanted cashflows // for the moment we add a check avoiding this situation VanillaSwap swap = arguments_.swap; double strike = swap.fixedRate; List <CashFlow> fixedLeg = swap.fixedLeg(); FixedRateCoupon firstCoupon = fixedLeg[0] as FixedRateCoupon; Utils.QL_REQUIRE(firstCoupon != null, () => "wrong coupon type"); Utils.QL_REQUIRE(firstCoupon.accrualStartDate() >= exerciseDate, () => "swap start (" + firstCoupon.accrualStartDate() + ") before exercise date (" + exerciseDate + ") not supported in Black swaption engine"); // using the forecasting curve swap.setPricingEngine(new DiscountingSwapEngine(swap.iborIndex().forwardingTermStructure())); double atmForward = swap.fairRate(); // Volatilities are quoted for zero-spreaded swaps. // Therefore, any spread on the floating leg must be removed // with a corresponding correction on the fixed leg. if (swap.spread.IsNotEqual(0.0)) { double correction = swap.spread * Math.Abs(swap.floatingLegBPS() / swap.fixedLegBPS()); strike -= correction; atmForward -= correction; results_.additionalResults["spreadCorrection"] = correction; } else { results_.additionalResults["spreadCorrection"] = 0.0; } results_.additionalResults["strike"] = strike; results_.additionalResults["atmForward"] = atmForward; // using the discounting curve swap.setPricingEngine(new DiscountingSwapEngine(discountCurve_, false)); double annuity = 0; if (arguments_.settlementType == Settlement.Type.Physical || (arguments_.settlementType == Settlement.Type.Cash && arguments_.settlementMethod == Settlement.Method.CollateralizedCashPrice)) { annuity = Math.Abs(swap.fixedLegBPS()) / Const.BASIS_POINT; } else if (arguments_.settlementType == Settlement.Type.Cash && arguments_.settlementMethod == Settlement.Method.ParYieldCurve) { DayCounter dayCount = firstCoupon.dayCounter(); // we assume that the cash settlement date is equal // to the swap start date Date discountDate = model_ == CashAnnuityModel.DiscountCurve ? firstCoupon.accrualStartDate() : discountCurve_.link.referenceDate(); double fixedLegCashBPS = CashFlows.bps(fixedLeg, new InterestRate(atmForward, dayCount, Compounding.Compounded, Frequency.Annual), false, discountDate); annuity = Math.Abs(fixedLegCashBPS / Const.BASIS_POINT) * discountCurve_.link.discount(discountDate); } else { Utils.QL_FAIL("unknown settlement type"); } results_.additionalResults["annuity"] = annuity; double swapLength = vol_.link.swapLength(swap.floatingSchedule().dates().First(), swap.floatingSchedule().dates().Last()); results_.additionalResults["swapLength"] = swapLength; double variance = vol_.link.blackVariance(exerciseDate, swapLength, strike); double displacement = displacement_ == null ? vol_.link.shift(exerciseDate, swapLength) : Convert.ToDouble(displacement_); double stdDev = Math.Sqrt(variance); results_.additionalResults["stdDev"] = stdDev; Option.Type w = (arguments_.type == VanillaSwap.Type.Payer) ? Option.Type.Call : Option.Type.Put; results_.value = new Spec().value(w, strike, atmForward, stdDev, annuity, displacement); double exerciseTime = vol_.link.timeFromReference(exerciseDate); results_.additionalResults["vega"] = new Spec().vega(strike, atmForward, stdDev, exerciseTime, annuity, displacement); }
public override void calculate() { Utils.QL_REQUIRE(numericalFix_ == NumericalFix.None || numericalFix_ == NumericalFix.Taylor, () => "numerical fix must be None or Taylor"); Utils.QL_REQUIRE(accrualBias_ == AccrualBias.HalfDayBias || accrualBias_ == AccrualBias.NoBias, () => "accrual bias must be HalfDayBias or NoBias"); Utils.QL_REQUIRE(forwardsInCouponPeriod_ == ForwardsInCouponPeriod.Flat || forwardsInCouponPeriod_ == ForwardsInCouponPeriod.Piecewise, () => "forwards in coupon period must be Flat or Piecewise"); // it would be possible to handle the cases which are excluded below, // but the ISDA engine is not explicitly specified to handle them, // so we just forbid them too Actual365Fixed dc = new Actual365Fixed(); Actual360 dc1 = new Actual360(); Actual360 dc2 = new Actual360(true); Date evalDate = Settings.Instance.evaluationDate(); // check if given curves are ISDA compatible // (the interpolation is checked below) Utils.QL_REQUIRE(!discountCurve_.empty(), () => "no discount term structure set"); Utils.QL_REQUIRE(!probability_.empty(), () => "no probability term structure set"); Utils.QL_REQUIRE(discountCurve_.link.dayCounter() == dc, () => "yield term structure day counter (" + discountCurve_.link.dayCounter() + ") should be Act/365(Fixed)"); Utils.QL_REQUIRE(probability_.link.dayCounter() == dc, () => "probability term structure day counter (" + probability_.link.dayCounter() + ") should be " + "Act/365(Fixed)"); Utils.QL_REQUIRE(discountCurve_.link.referenceDate() == evalDate, () => "yield term structure reference date (" + discountCurve_.link.referenceDate() + " should be evaluation date (" + evalDate + ")"); Utils.QL_REQUIRE(probability_.link.referenceDate() == evalDate, () => "probability term structure reference date (" + probability_.link.referenceDate() + " should be evaluation date (" + evalDate + ")"); Utils.QL_REQUIRE(arguments_.settlesAccrual, () => "ISDA engine not compatible with non accrual paying CDS"); Utils.QL_REQUIRE(arguments_.paysAtDefaultTime, () => "ISDA engine not compatible with end period payment"); Utils.QL_REQUIRE((arguments_.claim as FaceValueClaim) != null, () => "ISDA engine not compatible with non face value claim"); Date maturity = arguments_.maturity; Date effectiveProtectionStart = Date.Max(arguments_.protectionStart, evalDate + 1); // collect nodes from both curves and sort them List <Date> yDates = new List <Date>(), cDates = new List <Date>(); var castY1 = discountCurve_.link as PiecewiseYieldCurve <Discount, LogLinear>; var castY2 = discountCurve_.link as InterpolatedForwardCurve <BackwardFlat>; var castY3 = discountCurve_.link as InterpolatedForwardCurve <ForwardFlat>; var castY4 = discountCurve_.link as FlatForward; if (castY1 != null) { if (castY1.dates() != null) { yDates = castY1.dates(); } } else if (castY2 != null) { yDates = castY2.dates(); } else if (castY3 != null) { yDates = castY3.dates(); } else if (castY4 != null) { } else { Utils.QL_FAIL("Yield curve must be flat forward interpolated"); } var castC1 = probability_.link as InterpolatedSurvivalProbabilityCurve <LogLinear>; var castC2 = probability_.link as InterpolatedHazardRateCurve <BackwardFlat>; var castC3 = probability_.link as FlatHazardRate; if (castC1 != null) { cDates = castC1.dates(); } else if (castC2 != null) { cDates = castC2.dates(); } else if (castC3 != null) { } else { Utils.QL_FAIL("Credit curve must be flat forward interpolated"); } // Todo check List <Date> nodes = yDates.Union(cDates).ToList(); if (nodes.empty()) { nodes.Add(maturity); } double nFix = (numericalFix_ == NumericalFix.None ? 1E-50 : 0.0); // protection leg pricing (npv is always negative at this stage) double protectionNpv = 0.0; Date d0 = effectiveProtectionStart - 1; double P0 = discountCurve_.link.discount(d0); double Q0 = probability_.link.survivalProbability(d0); Date d1; int result = nodes.FindIndex(item => item > effectiveProtectionStart); for (int it = result; it < nodes.Count; ++it) { if (nodes[it] > maturity) { d1 = maturity; it = nodes.Count - 1; //early exit } else { d1 = nodes[it]; } double P1 = discountCurve_.link.discount(d1); double Q1 = probability_.link.survivalProbability(d1); double fhat = Math.Log(P0) - Math.Log(P1); double hhat = Math.Log(Q0) - Math.Log(Q1); double fhphh = fhat + hhat; if (fhphh < 1E-4 && numericalFix_ == NumericalFix.Taylor) { double fhphhq = fhphh * fhphh; protectionNpv += P0 * Q0 * hhat * (1.0 - 0.5 * fhphh + 1.0 / 6.0 * fhphhq - 1.0 / 24.0 * fhphhq * fhphh + 1.0 / 120 * fhphhq * fhphhq); } else { protectionNpv += hhat / (fhphh + nFix) * (P0 * Q0 - P1 * Q1); } d0 = d1; P0 = P1; Q0 = Q1; } protectionNpv *= arguments_.claim.amount(null, arguments_.notional.Value, recoveryRate_); results_.defaultLegNPV = protectionNpv; // premium leg pricing (npv is always positive at this stage) double premiumNpv = 0.0, defaultAccrualNpv = 0.0; double?accruedAmount = null; for (int i = 0; i < arguments_.leg.Count; ++i) { FixedRateCoupon coupon = arguments_.leg[i] as FixedRateCoupon; Utils.QL_REQUIRE(coupon.dayCounter() == dc || coupon.dayCounter() == dc1 || coupon.dayCounter() == dc2, () => "ISDA engine requires a coupon day counter Act/365Fixed " + "or Act/360 (" + coupon.dayCounter() + ")"); // premium coupons if (!arguments_.leg[i].hasOccurred(evalDate, includeSettlementDateFlows_)) { double x1 = coupon.amount(); double x2 = discountCurve_.link.discount(coupon.date()); double x3 = probability_.link.survivalProbability(coupon.date() - 1); // accrual if (accruedAmount == null) { if (evalDate + 1 == coupon.date()) { accruedAmount = 0.0; premiumNpv -= coupon.accruedPeriod(evalDate + 1) * coupon.nominal() * coupon.rate(); } else { accruedAmount = coupon.accruedPeriod(evalDate + 1) * coupon.nominal() * coupon.rate(); } } premiumNpv += x1 * x2 * x3; } // default accruals if (!new simple_event(coupon.accrualEndDate()) .hasOccurred(effectiveProtectionStart, false)) { Date start = Date.Max(coupon.accrualStartDate(), effectiveProtectionStart) - 1; Date end = coupon.date() - 1; double tstart = discountCurve_.link.timeFromReference(coupon.accrualStartDate() - 1) - (accrualBias_ == AccrualBias.HalfDayBias ? 1.0 / 730.0 : 0.0); List <Date> localNodes = new List <Date>(); localNodes.Add(start); //add intermediary nodes, if any if (forwardsInCouponPeriod_ == ForwardsInCouponPeriod.Piecewise) { foreach (Date node in nodes) { if (node > start && node < end) { localNodes.Add(node); } } //std::vector<Date>::const_iterator it0 = std::upper_bound(nodes.begin(), nodes.end(), start); //std::vector<Date>::const_iterator it1 = std::lower_bound(nodes.begin(), nodes.end(), end); //localNodes.insert(localNodes.end(), it0, it1); } localNodes.Add(end); double defaultAccrThisNode = 0.0; Date firstnode = localNodes.First(); double t0 = discountCurve_.link.timeFromReference(firstnode); P0 = discountCurve_.link.discount(firstnode); Q0 = probability_.link.survivalProbability(firstnode); foreach (Date node in localNodes.Skip(1)) //for (++node; node != localNodes.Last(); ++node) { double t1 = discountCurve_.link.timeFromReference(node); double P1 = discountCurve_.link.discount(node); double Q1 = probability_.link.survivalProbability(node); double fhat = Math.Log(P0) - Math.Log(P1); double hhat = Math.Log(Q0) - Math.Log(Q1); double fhphh = fhat + hhat; if (fhphh < 1E-4 && numericalFix_ == NumericalFix.Taylor) { // see above, terms up to (f+h)^3 seem more than enough, // what exactly is implemented in the standard isda C // code ? double fhphhq = fhphh * fhphh; defaultAccrThisNode += hhat * P0 * Q0 * ((t0 - tstart) * (1.0 - 0.5 * fhphh + 1.0 / 6.0 * fhphhq - 1.0 / 24.0 * fhphhq * fhphh) + (t1 - t0) * (0.5 - 1.0 / 3.0 * fhphh + 1.0 / 8.0 * fhphhq - 1.0 / 30.0 * fhphhq * fhphh)); } else { defaultAccrThisNode += (hhat / (fhphh + nFix)) * ((t1 - t0) * ((P0 * Q0 - P1 * Q1) / (fhphh + nFix) - P1 * Q1) + (t0 - tstart) * (P0 * Q0 - P1 * Q1)); } t0 = t1; P0 = P1; Q0 = Q1; } defaultAccrualNpv += defaultAccrThisNode * arguments_.notional.Value * coupon.rate() * 365.0 / 360.0; } } results_.couponLegNPV = premiumNpv + defaultAccrualNpv; results_.accruedAmountNPV = accruedAmount; // upfront flow npv double upfPVO1 = 0.0; results_.upfrontNPV = 0.0; if (!arguments_.upfrontPayment.hasOccurred( evalDate, includeSettlementDateFlows_)) { upfPVO1 = discountCurve_.link.discount(arguments_.upfrontPayment.date()); if (arguments_.upfrontPayment.amount().IsNotEqual(0.0)) { results_.upfrontNPV = upfPVO1 * arguments_.upfrontPayment.amount(); } } results_.accrualRebateNPV = 0.0; if (arguments_.accrualRebate != null && arguments_.accrualRebate.amount().IsNotEqual(0.0) && !arguments_.accrualRebate.hasOccurred(evalDate, includeSettlementDateFlows_)) { results_.accrualRebateNPV = discountCurve_.link.discount(arguments_.accrualRebate.date()) * arguments_.accrualRebate.amount(); } double upfrontSign = 1; if (arguments_.side == CreditDefaultSwap.Protection.Side.Seller) { results_.defaultLegNPV *= -1.0; results_.accrualRebateNPV *= -1.0; results_.accruedAmountNPV *= -1.0; } else { results_.couponLegNPV *= -1.0; results_.upfrontNPV *= -1.0; } results_.value = results_.defaultLegNPV + results_.couponLegNPV + results_.upfrontNPV + results_.accrualRebateNPV; results_.errorEstimate = null; if (results_.couponLegNPV.IsNotEqual(0.0)) { results_.fairSpread = -results_.defaultLegNPV * arguments_.spread / (results_.couponLegNPV + results_.accruedAmountNPV + results_.accrualRebateNPV); } else { results_.fairSpread = null; } double upfrontSensitivity = upfPVO1 * arguments_.notional.Value; if (upfrontSensitivity.IsNotEqual(0.0)) { results_.fairUpfront = -upfrontSign * (results_.defaultLegNPV + results_.couponLegNPV + results_.accrualRebateNPV) / upfrontSensitivity; } else { results_.fairUpfront = null; } if (arguments_.spread.IsNotEqual(0.0)) { results_.couponLegBPS = results_.couponLegNPV * Const.BASIS_POINT / arguments_.spread; } else { results_.couponLegBPS = null; } if (arguments_.upfront != null && arguments_.upfront.IsNotEqual(0.0)) { results_.upfrontBPS = results_.upfrontNPV * Const.BASIS_POINT / arguments_.upfront; } else { results_.upfrontBPS = null; } }
public CommercialPaper(Type type, double nominal, Schedule fixedSchedule, double fixedRate, DayCounter fixedDayCount, Schedule principalSchedule, BusinessDayConvention?paymentConvention) : base(2) { type_ = type; nominal_ = nominal; fixedSchedule_ = fixedSchedule; fixedRate_ = fixedRate; fixedDayCount_ = fixedDayCount; principalSchedule_ = principalSchedule; if (paymentConvention.HasValue) { paymentConvention_ = paymentConvention.Value; } else { paymentConvention_ = fixedSchedule_.businessDayConvention(); } List <CashFlow> principalLeg = new PricipalLeg(principalSchedule, fixedDayCount) .withNotionals(nominal) .withPaymentAdjustment(paymentConvention_) .withSign(type == Type.Loan ? -1 : 1); // temporary for (int i = 0; i < principalLeg.Count - 1; i++) { Principal p = (Principal)principalLeg[i]; notionals_.Add(p.nominal()); } List <CashFlow> fixedLeg = new FixedRateLeg(fixedSchedule) .withCouponRates(fixedRate, fixedDayCount) .withPaymentAdjustment(paymentConvention_) .withNotionals(notionals_); // Discounting Pricipal notionals_.Clear(); double n; for (int i = 0; i < fixedLeg.Count; i++) { FixedRateCoupon c = (FixedRateCoupon)fixedLeg[i]; n = i > 0 ? notionals_.Last() : c.nominal(); notionals_.Add(n / (1 + (c.rate() * c.dayCounter().yearFraction(c.referencePeriodStart, c.referencePeriodEnd)))); } // New Leg List <CashFlow> discountedFixedLeg = new FixedRateLeg(fixedSchedule) .withCouponRates(fixedRate, fixedDayCount) .withPaymentAdjustment(paymentConvention_) .withNotionals(notionals_); // Adjust Principal Principal p0 = (Principal)principalLeg[0]; p0.setAmount(notionals_.Last()); legs_[0] = discountedFixedLeg; legs_[1] = principalLeg; if (type_ == Type.Loan) { payer_[0] = +1; payer_[1] = -1; } else { payer_[0] = -1; payer_[1] = +1; } }