class DiscountingFixedCouponBondProductPricer {

  public double modifiedDurationFromYield(ResolvedFixedCouponBond bond, LocalDate settlementDate, double yield) {
    ImmutableList<FixedCouponBondPaymentPeriod> payments = bond.getPeriodicPayments();
    int nCoupon = payments.size() - couponIndex(payments, settlementDate);
    FixedCouponBondYieldConvention yieldConv = bond.getYieldConvention();
    if (nCoupon == 1) {
      if (yieldConv.equals(US_STREET) || yieldConv.equals(DE_BONDS)) {
        double couponPerYear = bond.getFrequency().eventsPerYear();
        double factor = factorToNextCoupon(bond, settlementDate);
        return factor / couponPerYear / (1d + factor * yield / couponPerYear);
      }
    }
    if (yieldConv.equals(US_STREET) || yieldConv.equals(GB_BUMP_DMO) || yieldConv.equals(DE_BONDS)) {
      return modifiedDurationFromYieldStandard(bond, settlementDate, yield);
    }
    if (yieldConv.equals(JP_SIMPLE)) {
      LocalDate maturityDate = bond.getUnadjustedEndDate();
      if (settlementDate.isAfter(maturityDate)) {
        return 0d;
      }
      double maturity = bond.getDayCount().relativeYearFraction(settlementDate, maturityDate);
      double num = 1d + bond.getFixedRate() * maturity;
      double den = 1d + yield * maturity;
      double dirtyPrice = dirtyPriceFromCleanPrice(bond, settlementDate, num / den);
      return num * maturity / den / den / dirtyPrice;
    }
    throw new UnsupportedOperationException("The convention " + yieldConv.name() + " is not supported.");
  }

  public  DiscountingFixedCouponBondProductPricer(
      DiscountingFixedCouponBondPaymentPeriodPricer periodPricer,
      DiscountingPaymentPricer nominalPricer);

}