private double calculateSinglePeriodAccrualOnDefault( CdsCoupon coupon, double effectiveStart, double[] integrationPoints, YieldTermStructure yieldCurve, PiecewiseconstantHazardRate creditCurve) { double start = Math.Max(coupon.getEffStart(), effectiveStart); if (start >= coupon.getEffEnd()) { return(0.0); //this coupon has already expired } double[] knots = DoublesScheduleGenerator.truncateSetInclusive(start, coupon.getEffEnd(), integrationPoints); double t = knots[0]; double ht0 = creditCurve.getRT_(t); double rt0 = yieldCurve.getRT_(t); double b0 = Math.Exp(-rt0 - ht0); // this is the risky discount factor double t0 = t - coupon.getEffStart() + _omega; double pv = 0.0; int nItems = knots.Length; for (int j = 1; j < nItems; ++j) { t = knots[j]; double ht1 = creditCurve.getRT_(t); double rt1 = yieldCurve.getRT_(t); double b1 = Math.Exp(-rt1 - ht1); double dt = knots[j] - knots[j - 1]; double dht = ht1 - ht0; double drt = rt1 - rt0; double dhrt = dht + drt; double tPV; double t1 = t - coupon.getEffStart() + _omega; if (Math.Abs(dhrt) < 1e-5) { tPV = dht * b0 * (t0 * Maths.Epsilon.epsilon(-dhrt) + dt * Maths.Epsilon.epsilonP(-dhrt)); } else { tPV = dht / dhrt * (t0 * b0 - t1 * b1 + dt / dhrt * (b0 - b1)); } t0 = t1; pv += tPV; ht0 = ht1; rt0 = rt1; b0 = b1; } return(coupon.getYFRatio() * pv); }
public PremiumLegElement(double protectionStart, CdsCoupon coupon, YieldTermStructure yieldCurve, int creditCurveKnot, double[] knots, AccrualOnDefaultFormulae formula) : base(coupon, yieldCurve, creditCurveKnot) { _coupon = coupon; _creditCurveKnot = creditCurveKnot; _formula = formula; if (formula == AccrualOnDefaultFormulae.ORIGINAL_ISDA) { _omega = 1.0 / 730; } else { _omega = 0.0; } _knots = DoublesScheduleGenerator.truncateSetInclusive(Math.Max(_coupon.getEffStart(), protectionStart), _coupon.getEffEnd(), knots); _n = _knots.Length; _rt = new double[_n]; _p = new double[_n]; for (int i = 0; i < _n; i++) { _rt[i] = yieldCurve.getRT_(_knots[i]); _p[i] = Math.Exp(-_rt[i]); } }
private double[] accOnDefault(PiecewiseconstantHazardRate creditCurve) { double t = _knots[0]; double[] htAndSense = creditCurve.getRTandSensitivity(t, _creditCurveKnot); double ht0 = htAndSense[0]; double rt0 = _rt[0]; double p0 = _p[0]; double q0 = Math.Exp(-ht0); double b0 = p0 * q0; // this is the risky discount factor double dqdr0 = -htAndSense[1] * q0; double t0 = t - _coupon.getEffStart() + _omega; double pv = 0.0; double pvSense = 0.0; for (int j = 1; j < _n; ++j) { t = _knots[j]; htAndSense = creditCurve.getRTandSensitivity(t, _creditCurveKnot); double ht1 = htAndSense[0]; double rt1 = _rt[j]; double p1 = _p[j]; double q1 = Math.Exp(-ht1); double b1 = p1 * q1; double dqdr1 = -htAndSense[1] * q1; double dt = _knots[j] - _knots[j - 1]; double dht = ht1 - ht0; double drt = rt1 - rt0; double dhrt = dht + drt; double tPV; double tPvSense; double t1 = t - _coupon.getEffStart() + _omega; if (Math.Abs(dhrt) < 1e-5) { double e = Maths.Epsilon.epsilon(-dhrt); double eP = Maths.Epsilon.epsilonP(-dhrt); double ePP = Maths.Epsilon.epsilonPP(-dhrt); double w1 = t0 * e + dt * eP; double w2 = t0 * eP + dt * ePP; double dPVdq0 = p0 * ((1 + dhrt) * w1 - dht * w2); double dPVdq1 = b0 / q1 * (-w1 + dht * w2); tPV = dht * b0 * w1; tPvSense = dPVdq0 * dqdr0 + dPVdq1 * dqdr1; } else { double w1 = dt / dhrt; double w2 = dht / dhrt; double w3 = (t0 + w1) * b0 - (t1 + w1) * b1; double w4 = (1 - w2) / dhrt; double w5 = w1 / dhrt * (b0 - b1); double dPVdq0 = w4 * w3 / q0 + w2 * ((t0 + w1) * p0 - w5 / q0); double dPVdq1 = w4 * w3 / q1 + w2 * ((t1 + w1) * p1 - w5 / q1); tPV = dht / dhrt * (t0 * b0 - t1 * b1 + dt / dhrt * (b0 - b1)); tPvSense = dPVdq0 * dqdr0 - dPVdq1 * dqdr1; } t0 = t1; pv += tPV; pvSense += tPvSense; ht0 = ht1; rt0 = rt1; p0 = p1; q0 = q1; b0 = b1; dqdr0 = dqdr1; } return(new double[] { _coupon.getYFRatio() *pv, _coupon.getYFRatio() *pvSense }); }
private double calculateSinglePeriodAccrualOnDefaultCreditSensitivity( CdsCoupon coupon, double effStart, double[] integrationPoints, YieldTermStructure yieldCurve, PiecewiseconstantHazardRate creditCurve, int creditCurveNode) { double start = Math.Max(coupon.getEffStart(), effStart); if (start >= coupon.getEffEnd()) { return(0.0); } double[] knots = DoublesScheduleGenerator.truncateSetInclusive(start, coupon.getEffEnd(), integrationPoints); double t = knots[0]; double ht0 = creditCurve.getRT_(t); double rt0 = yieldCurve.getRT_(t); double p0 = Math.Exp(-rt0); double q0 = Math.Exp(-ht0); double b0 = p0 * q0; // this is the risky discount factor double dqdr0 = creditCurve.getSingleNodeDiscountFactorSensitivity(t, creditCurveNode); double t0 = t - coupon.getEffStart() + _omega; double pvSense = 0.0; int nItems = knots.Length; for (int j = 1; j < nItems; ++j) { t = knots[j]; double ht1 = creditCurve.getRT_(t); double rt1 = yieldCurve.getRT_(t); double p1 = Math.Exp(-rt1); double q1 = Math.Exp(-ht1); double b1 = p1 * q1; double dqdr1 = creditCurve.getSingleNodeDiscountFactorSensitivity(t, creditCurveNode); double dt = knots[j] - knots[j - 1]; double dht = ht1 - ht0; double drt = rt1 - rt0; double dhrt = dht + drt + 1e-50; // to keep consistent with ISDA c code double tPvSense; // TODO once the maths is written up in a white paper, check these formula again, // since tests again finite difference could miss some subtle error if (_formula == AccrualOnDefaultFormulae.MARKIT_FIX) { if (Math.Abs(dhrt) < 1e-5) { double eP = Maths.Epsilon.epsilonP(-dhrt); double ePP = Maths.Epsilon.epsilonPP(-dhrt); double dPVdq0 = p0 * dt * ((1 + dht) * eP - dht * ePP); double dPVdq1 = b0 * dt / q1 * (-eP + dht * ePP); tPvSense = dPVdq0 * dqdr0 + dPVdq1 * dqdr1; } else { double w1 = (b0 - b1) / dhrt; double w2 = w1 - b1; double w3 = dht / dhrt; double w4 = dt / dhrt; double w5 = (1 - w3) * w2; double dPVdq0 = w4 / q0 * (w5 + w3 * (b0 - w1)); double dPVdq1 = w4 / q1 * (w5 + w3 * (b1 * (1 + dhrt) - w1)); tPvSense = dPVdq0 * dqdr0 - dPVdq1 * dqdr1; } } else { double t1 = t - coupon.getEffStart() + _omega; if (Math.Abs(dhrt) < 1e-5) { double e = Maths.Epsilon.epsilon(-dhrt); double eP = Maths.Epsilon.epsilonP(-dhrt); double ePP = Maths.Epsilon.epsilonPP(-dhrt); double w1 = t0 * e + dt * eP; double w2 = t0 * eP + dt * ePP; double dPVdq0 = p0 * ((1 + dht) * w1 - dht * w2); double dPVdq1 = b0 / q1 * (-w1 + dht * w2); tPvSense = dPVdq0 * dqdr0 + dPVdq1 * dqdr1; } else { double w1 = dt / dhrt; double w2 = dht / dhrt; double w3 = (t0 + w1) * b0 - (t1 + w1) * b1; double w4 = (1 - w2) / dhrt; double w5 = w1 / dhrt * (b0 - b1); double dPVdq0 = w4 * w3 / q0 + w2 * ((t0 + w1) * p0 - w5 / q0); double dPVdq1 = w4 * w3 / q1 + w2 * ((t1 + w1) * p1 - w5 / q1); tPvSense = dPVdq0 * dqdr0 - dPVdq1 * dqdr1; } t0 = t1; } pvSense += tPvSense; ht0 = ht1; rt0 = rt1; p0 = p1; q0 = q1; b0 = b1; dqdr0 = dqdr1; } return(coupon.getYFRatio() * pvSense); }