public static double simpleDuration(Leg leg, InterestRate y, bool includeSettlementDateFlows, Date settlementDate, Date npvDate) { if (leg.empty()) { return(0.0); } if (settlementDate == null) { settlementDate = Settings.Instance.evaluationDate(); } if (npvDate == null) { npvDate = settlementDate; } double P = 0.0; double dPdy = 0.0; double t = 0.0; Date lastDate = npvDate; DayCounter dc = y.dayCounter(); for (int i = 0; i < leg.Count; ++i) { if (leg[i].hasOccurred(settlementDate, includeSettlementDateFlows)) { continue; } double c = leg[i].amount(); if (leg[i].tradingExCoupon(settlementDate)) { c = 0.0; } t += getStepwiseDiscountTime(leg[i], dc, npvDate, lastDate); double B = y.discountFactor(t); P += c * B; dPdy += t * c * B; lastDate = leg[i].date(); } if (P.IsEqual(0.0)) // no cashflows { return(0.0); } return(dPdy / P); }
// NPV of the cash flows. // The NPV is the sum of the cash flows, each discounted // according to the given constant interest rate. The result // is affected by the choice of the interest-rate compounding // and the relative frequency and day counter. public static double npv(Leg leg, InterestRate yield, bool includeSettlementDateFlows, Date settlementDate = null, Date npvDate = null) { if (leg.empty()) { return(0.0); } if (settlementDate == null) { settlementDate = Settings.Instance.evaluationDate(); } if (npvDate == null) { npvDate = settlementDate; } double npv = 0.0; double discount = 1.0; Date lastDate = npvDate; DayCounter dc = yield.dayCounter(); for (int i = 0; i < leg.Count; ++i) { if (leg[i].hasOccurred(settlementDate, includeSettlementDateFlows)) { continue; } double amount = leg[i].amount(); if (leg[i].tradingExCoupon(settlementDate)) { amount = 0.0; } double b = yield.discountFactor(getStepwiseDiscountTime(leg[i], dc, npvDate, lastDate)); discount *= b; lastDate = leg[i].date(); npv += amount * discount; } return(npv); }
public static double modifiedDuration(Leg leg, InterestRate y, bool includeSettlementDateFlows, Date settlementDate, Date npvDate) { if (leg.empty()) { return(0.0); } if (settlementDate == null) { settlementDate = Settings.Instance.evaluationDate(); } if (npvDate == null) { npvDate = settlementDate; } double P = 0.0; double t = 0.0; double dPdy = 0.0; double r = y.rate(); int N = (int)y.frequency(); Date lastDate = npvDate; DayCounter dc = y.dayCounter(); for (int i = 0; i < leg.Count; ++i) { if (leg[i].hasOccurred(settlementDate, includeSettlementDateFlows)) { continue; } double c = leg[i].amount(); if (leg[i].tradingExCoupon(settlementDate)) { c = 0.0; } t += getStepwiseDiscountTime(leg[i], dc, npvDate, lastDate); double B = y.discountFactor(t); P += c * B; switch (y.compounding()) { case Compounding.Simple: dPdy -= c * B * B * t; break; case Compounding.Compounded: dPdy -= c * t * B / (1 + r / N); break; case Compounding.Continuous: dPdy -= c * B * t; break; case Compounding.SimpleThenCompounded: if (t <= 1.0 / N) { dPdy -= c * B * B * t; } else { dPdy -= c * t * B / (1 + r / N); } break; default: Utils.QL_FAIL("unknown compounding convention (" + y.compounding() + ")"); break; } lastDate = leg[i].date(); } if (P.IsEqual(0.0)) // no cashflows { return(0.0); } return(-dPdy / P); // reverse derivative sign }
//! Cash-flow convexity public static double convexity(Leg leg, InterestRate yield, bool includeSettlementDateFlows, Date settlementDate = null, Date npvDate = null) { if (leg.empty()) { return(0.0); } if (settlementDate == null) { settlementDate = Settings.Instance.evaluationDate(); } if (npvDate == null) { npvDate = settlementDate; } DayCounter dc = yield.dayCounter(); double P = 0.0; double t = 0.0; double d2Pdy2 = 0.0; double r = yield.rate(); int N = (int)yield.frequency(); Date lastDate = npvDate; for (int i = 0; i < leg.Count; ++i) { if (leg[i].hasOccurred(settlementDate, includeSettlementDateFlows)) { continue; } double c = leg[i].amount(); if (leg[i].tradingExCoupon(settlementDate)) { c = 0.0; } t += getStepwiseDiscountTime(leg[i], dc, npvDate, lastDate); double B = yield.discountFactor(t); P += c * B; switch (yield.compounding()) { case Compounding.Simple: d2Pdy2 += c * 2.0 * B * B * B * t * t; break; case Compounding.Compounded: d2Pdy2 += c * B * t * (N * t + 1) / (N * (1 + r / N) * (1 + r / N)); break; case Compounding.Continuous: d2Pdy2 += c * B * t * t; break; case Compounding.SimpleThenCompounded: if (t <= 1.0 / N) { d2Pdy2 += c * 2.0 * B * B * B * t * t; } else { d2Pdy2 += c * B * t * (N * t + 1) / (N * (1 + r / N) * (1 + r / N)); } break; default: Utils.QL_FAIL("unknown compounding convention (" + yield.compounding() + ")"); break; } lastDate = leg[i].date(); } if (P.IsEqual(0.0)) { // no cashflows return(0.0); } return(d2Pdy2 / P); }