0

How can I implement a function in Java that performs the exact same calculation as Excel's YIELD function ( the docs). I looked at the specification of the YIELD function and tried to implement it myself, but I get different results when using the following inputs:

Settlement: 21/04/2025

Maturity: 08/12/2027

Rate: 0.06875

Price: 94.28

Redemption: 100

Frequency: 1

Gives 9.499084% but I expected 9.723637 %

Here is MY code:

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

public static BigDecimal rendementTitre(
            LocalDate settlementDate,
            LocalDate maturityDate,
            BigDecimal taux,
            BigDecimal prix,
            BigDecimal valeurNominale,
            int frequence,
            MathContext mc,
            BigDecimal tol,
            int maxIter
    ) {
        long daysBetween = ChronoUnit.DAYS.between(settlementDate, maturityDate);
        BigDecimal years = new BigDecimal(daysBetween).divide(BigDecimal.valueOf(365), mc);
        int n = years.multiply(BigDecimal.valueOf(frequence)).setScale(0, RoundingMode.HALF_UP).intValue();
        BigDecimal coupon = valeurNominale.multiply(taux).divide(BigDecimal.valueOf(frequence), mc);

        // Initial guess
        BigDecimal y = taux;

        for (int iter = 0; iter < maxIter; iter++) {
            BigDecimal f = bondPrice(y, n, coupon, valeurNominale, frequence, mc).subtract(prix, mc);
            BigDecimal fPrime = bondPriceDerivative(y, n, coupon, valeurNominale, frequence, mc);

            if (fPrime.abs().compareTo(new BigDecimal("1E-10")) < 0) break;

            BigDecimal yNew = y.subtract(f.divide(fPrime, mc), mc);

            if (y.subtract(yNew).abs().compareTo(tol) < 0) {
                System.out.println("Rendement : " + yNew + " YY%");
                return yNew.multiply(BigDecimal.valueOf(100)).setScale(6, RoundingMode.HALF_UP); // % avec 6 décimales
            }

            y = yNew;
        }

        throw new RuntimeException("La convergence n'a pas été atteinte");
    }

    private static BigDecimal bondPrice(BigDecimal y, int n, BigDecimal C, BigDecimal V, int f, MathContext mc) {
        BigDecimal total = BigDecimal.ZERO;
        BigDecimal onePlusRate = BigDecimal.ONE.add(y.divide(BigDecimal.valueOf(f), mc));

        for (int i = 1; i <= n; i++) {
            BigDecimal denom = onePlusRate.pow(i, mc);
            total = total.add(C.divide(denom, mc), mc);
        }

        BigDecimal lastDenom = onePlusRate.pow(n, mc);
        total = total.add(V.divide(lastDenom, mc), mc);
        return total;
    }

    private static BigDecimal bondPriceDerivative(BigDecimal y, int n, BigDecimal C, BigDecimal V, int f, MathContext mc) {
        BigDecimal total = BigDecimal.ZERO;
        BigDecimal onePlusRate = BigDecimal.ONE.add(y.divide(BigDecimal.valueOf(f), mc));

        for (int i = 1; i <= n; i++) {
            BigDecimal denom = onePlusRate.pow(i + 1, mc);
            BigDecimal term = BigDecimal.valueOf(-i).multiply(C).divide(BigDecimal.valueOf(f), mc).divide(denom, mc);
            total = total.add(term, mc);
        }

        BigDecimal lastTerm = BigDecimal.valueOf(-n).multiply(V).divide(BigDecimal.valueOf(f), mc)
                .divide(onePlusRate.pow(n + 1, mc), mc);
        total = total.add(lastTerm, mc);

        return total;
    }

public static void main(String[] args) {
        LocalDate settlement = LocalDate.now();
        LocalDate maturity = LocalDate.of(2027, 12, 8);

        BigDecimal taux = new BigDecimal("0.06875");
        BigDecimal prix = new BigDecimal("94.28");
        BigDecimal valeurNominale = new BigDecimal("100");

        MathContext mc = new MathContext(20, RoundingMode.HALF_UP);
        BigDecimal tol = new BigDecimal("1E-8");

        BigDecimal rendement = rendementTitre(
                settlement,
                maturity,
                taux,
                prix,
                valeurNominale,
                2,  // Semestriel
                mc,
                tol,
                100
        );

        System.out.println("Rendement : " + rendement + " %");
}
}

with this exemple the consol print 9.499084 %
but the Excel show 9.723637%

New contributor
Cheikh Ibra YADE is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
6
  • Have you looked through Apache Poi? It offers some functions. Commented Apr 21 at 17:33
  • Does YieldToMaturity do it? From JavaMoney project. Commented Apr 21 at 17:37
  • @BasilBourque I don't find in Apache Poi the Excel financial functions like YIELD, YieldToMaturity is different with Excel Yield also Commented Apr 21 at 19:22
  • 2
    When I use excel and use a date equivalent to "aug 12th 2027" I get your observed excel result to 4 significant digits and when using equivalent to "dec 8th 2027" I get a lower value closer to your results. I'm simply suggesting double-check your date processing particularly in excel to be sure you are comparing the same.
    – Computable
    Commented Apr 21 at 20:29
  • @Computable I saw your comment. Just to confirm, I didn’t mix up the dates — I did use August 12th (12/08), not the other way around. Commented Apr 23 at 17:46

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.