/// <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(); }
public override void calculate() { Utils.QL_REQUIRE(integrationStep_ != null, () => "null period set"); Utils.QL_REQUIRE(!discountCurve_.empty(), () => "no discount term structure set"); Utils.QL_REQUIRE(!probability_.empty(), () => "no probability term structure set"); Date today = Settings.evaluationDate(); Date settlementDate = discountCurve_.link.referenceDate(); // Upfront Flow NPV. Either we are on-the-run (no flow) // or we are forward start double upfPVO1 = 0.0; if (!arguments_.upfrontPayment.hasOccurred(settlementDate, includeSettlementDateFlows_)) { // date determining the probability survival so we have to pay // the upfront (did not knock out) Date effectiveUpfrontDate = arguments_.protectionStart > probability_.link.referenceDate() ? arguments_.protectionStart : probability_.link.referenceDate(); upfPVO1 = probability_.link.survivalProbability(effectiveUpfrontDate) * discountCurve_.link.discount(arguments_.upfrontPayment.date()); } results_.upfrontNPV = upfPVO1 * arguments_.upfrontPayment.amount(); results_.couponLegNPV = 0.0; results_.defaultLegNPV = 0.0; for (int i = 0; i < arguments_.leg.Count; ++i) { if (arguments_.leg[i].hasOccurred(settlementDate, includeSettlementDateFlows_)) { continue; } FixedRateCoupon coupon = arguments_.leg[i] as FixedRateCoupon; // In order to avoid a few switches, we calculate the NPV // of both legs as a positive quantity. We'll give them // the right sign at the end. Date paymentDate = coupon.date(), startDate = (i == 0 ? arguments_.protectionStart : coupon.accrualStartDate()), endDate = coupon.accrualEndDate(); Date effectiveStartDate = (startDate <= today && today <= endDate) ? today : startDate; double couponAmount = coupon.amount(); double S = probability_.link.survivalProbability(paymentDate); // On one side, we add the fixed rate payments in case of // survival. results_.couponLegNPV += S * couponAmount * discountCurve_.link.discount(paymentDate); // On the other side, we add the payment (and possibly the // accrual) in case of default. Period step = integrationStep_; Date d0 = effectiveStartDate; Date d1 = Date.Min(d0 + step, endDate); double P0 = probability_.link.defaultProbability(d0); double endDiscount = discountCurve_.link.discount(paymentDate); do { double B = arguments_.paysAtDefaultTime ? discountCurve_.link.discount(d1) : endDiscount; double P1 = probability_.link.defaultProbability(d1); double dP = P1 - P0; // accrual... if (arguments_.settlesAccrual) { if (arguments_.paysAtDefaultTime) { results_.couponLegNPV += coupon.accruedAmount(d1) * B * dP; } else { results_.couponLegNPV += couponAmount * B * dP; } } // ...and claim. double claim = arguments_.claim.amount(d1, arguments_.notional.Value, recoveryRate_); results_.defaultLegNPV += claim * B * dP; // setup for next time around the loop P0 = P1; d0 = d1; d1 = Date.Min(d0 + step, endDate); } while (d0 < endDate); } double upfrontSign = 1.0; switch (arguments_.side) { case Protection.Side.Seller: results_.defaultLegNPV *= -1.0; break; case Protection.Side.Buyer: results_.couponLegNPV *= -1.0; results_.upfrontNPV *= -1.0; upfrontSign = -1.0; break; default: Utils.QL_FAIL("unknown protection side"); break; } results_.value = results_.defaultLegNPV + results_.couponLegNPV + results_.upfrontNPV; results_.errorEstimate = null; if (results_.couponLegNPV != 0.0) { results_.fairSpread = -results_.defaultLegNPV * arguments_.spread / results_.couponLegNPV; } else { results_.fairSpread = null; } double upfrontSensitivity = upfPVO1 * arguments_.notional.Value; if (upfrontSensitivity != 0.0) { results_.fairUpfront = -upfrontSign * (results_.defaultLegNPV + results_.couponLegNPV) / upfrontSensitivity; } else { results_.fairUpfront = null; } if (arguments_.spread != 0.0) { results_.couponLegBPS = results_.couponLegNPV * basisPoint / arguments_.spread; } else { results_.couponLegBPS = null; } if (arguments_.upfront.HasValue && arguments_.upfront.Value != 0.0) { results_.upfrontBPS = results_.upfrontNPV * basisPoint / (arguments_.upfront.Value); } else { results_.upfrontBPS = null; } }
/// <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() { Utils.QL_REQUIRE(!discountCurve_.empty(), () => "no discount term structure set"); Utils.QL_REQUIRE(!probability_.empty(), () => "no probability term structure set"); Date today = Settings.evaluationDate(); Date settlementDate = discountCurve_.link.referenceDate(); // Upfront Flow NPV. Either we are on-the-run (no flow) // or we are forward start double upfPVO1 = 0.0; if (!arguments_.upfrontPayment.hasOccurred(settlementDate, includeSettlementDateFlows_)) { // date determining the probability survival so we have to pay // the upfront (did not knock out) Date effectiveUpfrontDate = arguments_.protectionStart > probability_.link.referenceDate() ? arguments_.protectionStart : probability_.link.referenceDate(); upfPVO1 = probability_.link.survivalProbability(effectiveUpfrontDate) * discountCurve_.link.discount(arguments_.upfrontPayment.date()); } results_.upfrontNPV = upfPVO1 * arguments_.upfrontPayment.amount(); results_.couponLegNPV = 0.0; results_.defaultLegNPV = 0.0; for (int i = 0; i < arguments_.leg.Count; ++i) { if (arguments_.leg[i].hasOccurred(settlementDate, includeSettlementDateFlows_)) { continue; } FixedRateCoupon coupon = arguments_.leg[i] as FixedRateCoupon; // In order to avoid a few switches, we calculate the NPV // of both legs as a positive quantity. We'll give them // the right sign at the end. Date paymentDate = coupon.date(), startDate = coupon.accrualStartDate(), endDate = coupon.accrualEndDate(); // this is the only point where it might not coincide if (i == 0) { startDate = arguments_.protectionStart; } Date effectiveStartDate = (startDate <= today && today <= endDate) ? today : startDate; Date defaultDate = // mid-point effectiveStartDate + (endDate - effectiveStartDate) / 2; double S = probability_.link.survivalProbability(paymentDate); double P = probability_.link.defaultProbability(effectiveStartDate, endDate); // on one side, we add the fixed rate payments in case of // survival... results_.couponLegNPV += S * coupon.amount() * discountCurve_.link.discount(paymentDate); // ...possibly including accrual in case of default. if (arguments_.settlesAccrual) { if (arguments_.paysAtDefaultTime) { results_.couponLegNPV += P * coupon.accruedAmount(defaultDate) * discountCurve_.link.discount(defaultDate); } else { // pays at the end results_.couponLegNPV += P * coupon.amount() * discountCurve_.link.discount(paymentDate); } } // on the other side, we add the payment in case of default. double claim = arguments_.claim.amount(defaultDate, arguments_.notional.Value, recoveryRate_); if (arguments_.paysAtDefaultTime) { results_.defaultLegNPV += P * claim * discountCurve_.link.discount(defaultDate); } else { results_.defaultLegNPV += P * claim * discountCurve_.link.discount(paymentDate); } } double upfrontSign = 1.0; switch (arguments_.side) { case Protection.Side.Seller: results_.defaultLegNPV *= -1.0; break; case Protection.Side.Buyer: results_.couponLegNPV *= -1.0; results_.upfrontNPV *= -1.0; upfrontSign = -1.0; break; default: Utils.QL_FAIL("unknown protection side"); break; } results_.value = results_.defaultLegNPV + results_.couponLegNPV + results_.upfrontNPV; results_.errorEstimate = null; if (results_.couponLegNPV != 0.0) { results_.fairSpread = -results_.defaultLegNPV * arguments_.spread / results_.couponLegNPV; } else { results_.fairSpread = null; } double upfrontSensitivity = upfPVO1 * arguments_.notional.Value; if (upfrontSensitivity != 0.0) { results_.fairUpfront = -upfrontSign * (results_.defaultLegNPV + results_.couponLegNPV) / upfrontSensitivity; } else { results_.fairUpfront = null; } if (arguments_.spread != 0.0) { results_.couponLegBPS = results_.couponLegNPV * basisPoint / arguments_.spread.Value; } else { results_.couponLegBPS = null; } if (arguments_.upfront.HasValue && arguments_.upfront.Value != 0.0) { results_.upfrontBPS = results_.upfrontNPV * basisPoint / (arguments_.upfront.Value); } else { results_.upfrontBPS = null; } }