Class BondPricer

java.lang.Object
com.quantfinlib.rates.BondPricer

public final class BondPricer extends Object
Fixed-coupon bond analytics: price/yield conversion, Macaulay and modified duration, convexity, and DV01. Yields are per-annum with frequency compounding (the bond's coupon frequency); coupons are assumed on a regular schedule with the last payment at maturity.

The risk numbers and what each is for: Macaulay duration is the cash-flow-weighted average time to payment (years; an intuition number); modified duration = Macaulay / (1 + y/f) is the first-order price sensitivity, dP/P ≈ -modDur · dy; DV01 is the same derivative in money terms per 1bp, the number the desk actually hedges, because DV01s add across positions while durations must be value-weighted. Convexity is the second-order term that makes the duration hedge wrong for large moves. It is always in the long bondholder's favor (price rises more than duration predicts when yields fall, drops less when they rise), which is why long-convexity positions cost carry.

The yearsToMaturity functions work in whole coupon periods (no accrued interest, no settlement inside a period): the textbook bond. The date-based functions (dirtyPrice, cleanPrice, accruedInterest, yieldFromCleanPrice) use the street convention with real day counts, including ACT/ACT ICMA. Pricing off a full curve (each cash flow at its own zero rate) is YieldCurve's job; hedging a position against non-parallel curve moves is KeyRateDurations'.

  • Method Summary

    Modifier and Type
    Method
    Description
    static double
    accruedInterest(double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, DayCount dayCount)
     
    static double
    accruedInterest(double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, DayCount dayCount, boolean endOfMonth)
    Accrued interest at settlement: the current period's coupon times the elapsed fraction (ACT/ACT ICMA: actual days over actual days in the period; 30/360 family: 30/360 days over 360/f).
    static double
    accruedInterestExact(double face, double couponRate, int frequency, double yearsToMaturity)
    Accrued interest on the quasi-coupon grid of priceFromYieldExact(double, double, int, double, double): C (1 - w); zero when the maturity is a whole number of periods.
    static double
    cleanPrice(double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, double yield, DayCount dayCount)
     
    static double
    cleanPrice(double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, double yield, DayCount dayCount, boolean endOfMonth)
    Clean price = dirty price minus accrued interest.
    static double
    convexity(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
    Convexity (numeric second derivative of price w.r.t. yield, normalized by price).
    static double
    convexityAnalytic(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
    Analytic convexity on the same whole-period schedule as convexity(double, double, int, double, double): (1/P) d^2P/dy^2 with
    static double
    convexityExact(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
    Analytic convexity on the exact grid, (1/P) sum_k CF_k e_k (e_k + 1) / (f^2 (1 + y/f)^(e_k + 2)), e_k = k - 1 + w.
    static double
    dirtyPrice(double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, double yield, DayCount dayCount)
    static double
    dirtyPrice(double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, double yield, DayCount dayCount, boolean endOfMonth)
    Dirty price per face from a yield, street convention (the formula behind the SIFMA/Bloomberg "street" yield and Excel's price):
    static double
    dv01(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
    Price change for a one-basis-point yield move (positive number).
    static boolean
    isWholePeriods(int frequency, double yearsToMaturity)
    Whether yearsToMaturity * frequency is a whole number of coupon periods (to 1e-9).
    static double
    macaulayDuration(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
    Macaulay duration in years: PV-weighted average time to cash flow.
    static double
    macaulayDurationExact(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
    Macaulay duration in years on the exact grid of priceFromYieldExact(double, double, int, double, double).
    static double
    modifiedDuration(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
    Modified duration: price sensitivity per unit yield change.
    static double
    modifiedDurationExact(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
    Modified duration on the exact grid: Macaulay / (1 + y/f).
    static double
    priceFromCurve(double face, double couponRate, int frequency, double yearsToMaturity, YieldCurve curve)
    Price by discounting each cash flow on a zero curve.
    static double
    priceFromYield(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
    Dirty price per face from a yield (regular schedule, whole periods).
    static double
    priceFromYieldExact(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
    Dirty price from a yield for any (also non-integral) time to maturity, by the street convention: coupons sit on the regular quasi-coupon grid counted back from maturity, the first one w periods away, and a full coupon is paid on it.
    static LocalDate
    settlementDate(LocalDate tradeDate, int lagDays, BusinessCalendar calendar)
    Settlement date from a trade date and settlement lag (e.g.
    static double
    yieldFromCleanPrice(double cleanPrice, double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, DayCount dayCount, boolean endOfMonth)
    Street-convention yield from a clean price (inverse of cleanPrice(double, double, int, java.time.LocalDate, java.time.LocalDate, double, DayCount, boolean)), by bisection on [−90%, 1000%] to full double precision.
    static double
    yieldToMaturity(double price, double face, double couponRate, int frequency, double yearsToMaturity)
    Yield to maturity by bisection (price must be positive).
    static double
    yieldToMaturityExact(double dirtyPrice, double face, double couponRate, int frequency, double yearsToMaturity)
    Yield from a dirty price on the exact grid, by bisection on [-90%, 1000%].

    Methods inherited from class Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • priceFromYield

      public static double priceFromYield(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
      Dirty price per face from a yield (regular schedule, whole periods).
    • priceFromCurve

      public static double priceFromCurve(double face, double couponRate, int frequency, double yearsToMaturity, YieldCurve curve)
      Price by discounting each cash flow on a zero curve.
    • yieldToMaturity

      public static double yieldToMaturity(double price, double face, double couponRate, int frequency, double yearsToMaturity)
      Yield to maturity by bisection (price must be positive).
    • macaulayDuration

      public static double macaulayDuration(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
      Macaulay duration in years: PV-weighted average time to cash flow.
    • modifiedDuration

      public static double modifiedDuration(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
      Modified duration: price sensitivity per unit yield change.
    • convexity

      public static double convexity(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
      Convexity (numeric second derivative of price w.r.t. yield, normalized by price).
    • dv01

      public static double dv01(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
      Price change for a one-basis-point yield move (positive number).
    • convexityAnalytic

      public static double convexityAnalytic(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
      Analytic convexity on the same whole-period schedule as convexity(double, double, int, double, double): (1/P) d^2P/dy^2 with
        d^2P/dy^2 = sum_i CF_i i (i + 1) / (f^2 (1 + y/f)^(i+2))

      The existing convexity(double, double, int, double, double) is a central difference with step 1e-4 and keeps its results; this is the closed form it approximates (they agree to about 1e-7 relative, pinned in the tests).

      Parameters:
      face - face value
      couponRate - annual coupon rate
      frequency - coupons per year
      yearsToMaturity - years to maturity (rounded to whole periods, as in priceFromYield(double, double, int, double, double))
      yield - yield, compounded frequency times a year
      Returns:
      convexity in years squared
    • isWholePeriods

      public static boolean isWholePeriods(int frequency, double yearsToMaturity)
      Whether yearsToMaturity * frequency is a whole number of coupon periods (to 1e-9). When it is not, the whole-period functions (priceFromYield(double, double, int, double, double), macaulayDuration(double, double, int, double, double), convexity(double, double, int, double, double), dv01(double, double, int, double, double), yieldToMaturity(double, double, double, int, double), priceFromCurve(double, double, int, double, YieldCurve)) round to the nearest period: a 2.3-year semi-annual bond is priced as 2.5 years. That rounding is kept for compatibility (release policy: no behaviour changes in 3.x) but its use with non-integral maturities is deprecated since 3.1.0; use the ...Exact functions instead.
      Parameters:
      frequency - coupons per year
      yearsToMaturity - years to maturity
      Returns:
      true when the maturity is a whole number of periods
    • priceFromYieldExact

      public static double priceFromYieldExact(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
      Dirty price from a yield for any (also non-integral) time to maturity, by the street convention: coupons sit on the regular quasi-coupon grid counted back from maturity, the first one w periods away, and a full coupon is paid on it.

      With x = yearsToMaturity * f, n = ceil(x) coupons remain and w = x - (n - 1) in (0, 1]:

        P = sum_{k=1..n} C / (1 + y/f)^(k - 1 + w) + face / (1 + y/f)^(n - 1 + w),   C = face c / f

      When x is whole, w = 1 and this is exactly priceFromYield(double, double, int, double, double). Worked example: 2.3 years semi-annual gives x = 4.6, five coupons, the first 0.6 periods (0.3 years) away; the clean price is this minus accruedInterestExact(double, double, int, double).

      Parameters:
      face - face value
      couponRate - annual coupon rate
      frequency - coupons per year
      yearsToMaturity - years to maturity, any positive value
      yield - yield, compounded frequency times a year
      Returns:
      dirty price
    • accruedInterestExact

      public static double accruedInterestExact(double face, double couponRate, int frequency, double yearsToMaturity)
      Accrued interest on the quasi-coupon grid of priceFromYieldExact(double, double, int, double, double): C (1 - w); zero when the maturity is a whole number of periods.
      Parameters:
      face - face value
      couponRate - annual coupon rate
      frequency - coupons per year
      yearsToMaturity - years to maturity
      Returns:
      accrued interest
    • macaulayDurationExact

      public static double macaulayDurationExact(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
      Macaulay duration in years on the exact grid of priceFromYieldExact(double, double, int, double, double).
      Parameters:
      face - face value
      couponRate - annual coupon rate
      frequency - coupons per year
      yearsToMaturity - years to maturity
      yield - yield, compounded frequency times a year
      Returns:
      Macaulay duration
    • modifiedDurationExact

      public static double modifiedDurationExact(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
      Modified duration on the exact grid: Macaulay / (1 + y/f).
      Parameters:
      face - face value
      couponRate - annual coupon rate
      frequency - coupons per year
      yearsToMaturity - years to maturity
      yield - yield, compounded frequency times a year
      Returns:
      modified duration
    • convexityExact

      public static double convexityExact(double face, double couponRate, int frequency, double yearsToMaturity, double yield)
      Analytic convexity on the exact grid, (1/P) sum_k CF_k e_k (e_k + 1) / (f^2 (1 + y/f)^(e_k + 2)), e_k = k - 1 + w.
      Parameters:
      face - face value
      couponRate - annual coupon rate
      frequency - coupons per year
      yearsToMaturity - years to maturity
      yield - yield, compounded frequency times a year
      Returns:
      convexity in years squared
    • yieldToMaturityExact

      public static double yieldToMaturityExact(double dirtyPrice, double face, double couponRate, int frequency, double yearsToMaturity)
      Yield from a dirty price on the exact grid, by bisection on [-90%, 1000%].
      Parameters:
      dirtyPrice - dirty price
      face - face value
      couponRate - annual coupon rate
      frequency - coupons per year
      yearsToMaturity - years to maturity
      Returns:
      the yield
    • dirtyPrice

      public static double dirtyPrice(double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, double yield, DayCount dayCount, boolean endOfMonth)
      Dirty price per face from a yield, street convention (the formula behind the SIFMA/Bloomberg "street" yield and Excel's price):
        P = Σ_{k=0}^{N−1} C_k / (1 + y/f)^{k + w} + face / (1 + y/f)^{N − 1 + w}

      with w = 1 − (elapsed fraction of the current coupon period) and N the number of coupons left. Coupons are face·c/f for the bond conventions THIRTY_360, THIRTY_E_360, THIRTY_E_360_ISDA and ACT_ACT_ICMA (US Treasuries and most government bonds use ACT/ACT ICMA, where the elapsed fraction is actual days over actual days in the period). Discounting uses the unadjusted coupon dates, as the street convention does: a coupon delayed by a weekend is not discounted for the extra days.

      The schedule is regular, generated backward from maturity (with the end-of-month rule when endOfMonth); odd first coupons are not modelled, so settlement must be after the first coupon's regular period start.

    • dirtyPrice

      public static double dirtyPrice(double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, double yield, DayCount dayCount)
    • accruedInterest

      public static double accruedInterest(double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, DayCount dayCount, boolean endOfMonth)
      Accrued interest at settlement: the current period's coupon times the elapsed fraction (ACT/ACT ICMA: actual days over actual days in the period; 30/360 family: 30/360 days over 360/f).
    • accruedInterest

      public static double accruedInterest(double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, DayCount dayCount)
    • cleanPrice

      public static double cleanPrice(double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, double yield, DayCount dayCount, boolean endOfMonth)
      Clean price = dirty price minus accrued interest.
    • cleanPrice

      public static double cleanPrice(double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, double yield, DayCount dayCount)
    • yieldFromCleanPrice

      public static double yieldFromCleanPrice(double cleanPrice, double face, double couponRate, int frequency, LocalDate settlement, LocalDate maturity, DayCount dayCount, boolean endOfMonth)
      Street-convention yield from a clean price (inverse of cleanPrice(double, double, int, java.time.LocalDate, java.time.LocalDate, double, DayCount, boolean)), by bisection on [−90%, 1000%] to full double precision. Throws when the price has no yield in that range.
    • settlementDate

      public static LocalDate settlementDate(LocalDate tradeDate, int lagDays, BusinessCalendar calendar)
      Settlement date from a trade date and settlement lag (e.g. T+2).