BondFutureHullWhiteMethod extends BondFutureMethod { public double price(final BondFuture future, final HullWhiteIssuerProviderInterface data, final int nbPoint) { ArgumentChecker.notNull(future, "Future"); ArgumentChecker.notNull(data, "Hull-White data bundle"); final int nbBond = future.getDeliveryBasket().length; final LegalEntity issuer = future.getDeliveryBasket()[0].getIssuerEntity(); final HullWhiteOneFactorPiecewiseConstantParameters parameters = data.getHullWhiteParameters(); final IssuerProviderInterface issuerProvider = data.getIssuerProvider(); final MulticurveProviderInterface multicurvesDecorated = new MulticurveProviderDiscountingDecoratedIssuer(issuerProvider, future.getCurrency(), issuer); final double expiry = future.getNoticeLastTime(); final double delivery = future.getDeliveryLastTime(); final double dfdelivery = data.getIssuerProvider().getDiscountFactor(issuer, delivery); final int nbPtWing = ((int) Math.floor(nbPoint / 20.)); final int nbPtCenter = nbPoint - 2 * nbPtWing; final double prob = 1.0 / (2.0 * nbPtCenter); final double xStart = NORMAL.getInverseCDF(prob); final double[] x = new double[nbPoint]; for (int loopwing = 0; loopwing < nbPtWing; loopwing++) { x[loopwing] = xStart * (1.0 + (nbPtWing - loopwing) / 2.0); x[nbPoint - 1 - loopwing] = -xStart * (1.0 + (nbPtWing - loopwing) / 2.0); } for (int loopcent = 0; loopcent < nbPtCenter; loopcent++) { x[nbPtWing + loopcent] = xStart + loopcent * (-2.0 * xStart) / (nbPtCenter - 1); } final double[][] cfTime = new double[nbBond][]; final double[][] df = new double[nbBond][]; final double[][] alpha = new double[nbBond][]; final double[][] beta = new double[nbBond][]; final double[][] cfaAdjusted = new double[nbBond][]; final double[] e = new double[nbBond]; final double[][] pv = new double[nbPoint][nbBond]; final AnnuityPaymentFixed[] cf = new AnnuityPaymentFixed[nbBond]; for (int loopbnd = 0; loopbnd < nbBond; loopbnd++) { cf[loopbnd] = future.getDeliveryBasket()[loopbnd].accept(CFEC, multicurvesDecorated); final int nbCf = cf[loopbnd].getNumberOfPayments(); cfTime[loopbnd] = new double[nbCf]; df[loopbnd] = new double[nbCf]; alpha[loopbnd] = new double[nbCf]; beta[loopbnd] = new double[nbCf]; cfaAdjusted[loopbnd] = new double[nbCf]; for (int loopcf = 0; loopcf < nbCf; loopcf++) { cfTime[loopbnd][loopcf] = cf[loopbnd].getNthPayment(loopcf).getPaymentTime(); df[loopbnd][loopcf] = issuerProvider.getDiscountFactor(issuer, cfTime[loopbnd][loopcf]); alpha[loopbnd][loopcf] = MODEL.alpha(parameters, 0.0, expiry, delivery, cfTime[loopbnd][loopcf]); beta[loopbnd][loopcf] = MODEL.futuresConvexityFactor(parameters, expiry, cfTime[loopbnd][loopcf], delivery); cfaAdjusted[loopbnd][loopcf] = df[loopbnd][loopcf] / dfdelivery * beta[loopbnd][loopcf] * cf[loopbnd].getNthPayment(loopcf).getAmount() / future.getConversionFactor()[loopbnd]; for (int looppt = 0; looppt < nbPoint; looppt++) { pv[looppt][loopbnd] += cfaAdjusted[loopbnd][loopcf] * Math.exp(-alpha[loopbnd][loopcf] * alpha[loopbnd][loopcf] / 2.0 - alpha[loopbnd][loopcf] * x[looppt]); } } e[loopbnd] = future.getDeliveryBasket()[loopbnd].getAccruedInterest() / future.getConversionFactor()[loopbnd]; for (int looppt = 0; looppt < nbPoint; looppt++) { pv[looppt][loopbnd] -= e[loopbnd]; } } final double[] pvMin = new double[nbPoint]; final int[] indMin = new int[nbPoint]; for (int looppt = 0; looppt < nbPoint; looppt++) { pvMin[looppt] = Double.POSITIVE_INFINITY; for (int loopbnd = 0; loopbnd < nbBond; loopbnd++) { if (pv[looppt][loopbnd] < pvMin[looppt]) { pvMin[looppt] = pv[looppt][loopbnd]; indMin[looppt] = loopbnd; } } } final ArrayList<Double> refx = new ArrayList<>(); final ArrayList<Integer> ctd = new ArrayList<>(); int lastInd = indMin[0]; ctd.add(indMin[0]); for (int looppt = 1; looppt < nbPoint; looppt++) { if (indMin[looppt] != lastInd) { ctd.add(indMin[looppt]); lastInd = indMin[looppt]; refx.add(x[looppt]); } } final int nbInt = ctd.size(); final double[] kappa = new double[nbInt - 1]; double price = 0.0; if (nbInt == 1) { for (int loopcf = 0; loopcf < cfaAdjusted[ctd.get(0)].length; loopcf++) { price += cfaAdjusted[ctd.get(0)][loopcf]; } price -= e[ctd.get(0)]; } else { final BracketRoot bracketer = new BracketRoot(); final double accuracy = 1.0E-8; final RidderSingleRootFinder rootFinder = new RidderSingleRootFinder(accuracy); for (int loopint = 1; loopint < nbInt; loopint++) { final BondDifference cross = new BondDifference(cfaAdjusted[ctd.get(loopint - 1)], alpha[ctd.get(loopint - 1)], e[ctd.get(loopint - 1)], cfaAdjusted[ctd.get(loopint)], alpha[ctd.get(loopint)], e[ctd.get(loopint)]); final double[] range = bracketer.getBracketedPoints(cross, refx.get(loopint - 1) - 0.01, refx.get(loopint - 1) + 0.01); kappa[loopint - 1] = rootFinder.getRoot(cross, range[0], range[1]); } for (int loopcf = 0; loopcf < cfaAdjusted[ctd.get(0)].length; loopcf++) { price += cfaAdjusted[ctd.get(0)][loopcf] * NORMAL.getCDF(kappa[0] + alpha[ctd.get(0)][loopcf]); } price -= e[ctd.get(0)] * NORMAL.getCDF(kappa[0]); for (int loopint = 1; loopint < nbInt - 1; loopint++) { for (int loopcf = 0; loopcf < cfaAdjusted[ctd.get(loopint)].length; loopcf++) { price += cfaAdjusted[ctd.get(loopint)][loopcf] * (NORMAL.getCDF(kappa[loopint] + alpha[ctd.get(loopint)][loopcf]) - NORMAL.getCDF(kappa[loopint - 1] + alpha[ctd.get(loopint)][loopcf])); } price -= e[ctd.get(loopint)] * (NORMAL.getCDF(kappa[loopint]) - NORMAL.getCDF(kappa[loopint - 1])); } for (int loopcf = 0; loopcf < cfaAdjusted[ctd.get(nbInt - 1)].length; loopcf++) { price += cfaAdjusted[ctd.get(nbInt - 1)][loopcf] * (1.0 - NORMAL.getCDF(kappa[nbInt - 2] + alpha[ctd.get(nbInt - 1)][loopcf])); } price -= e[ctd.get(nbInt - 1)] * (1 - NORMAL.getCDF(kappa[nbInt - 2])); } return price; } private  BondFutureHullWhiteMethod(); static BondFutureHullWhiteMethod getInstance(); double price(final BondFuture future, final HullWhiteIssuerProviderInterface data, final int nbPoint); double price(final BondFuture future, final HullWhiteIssuerProviderInterface data); MultipleCurrencyAmount presentValue(final BondFuture future, final HullWhiteIssuerProviderInterface data); MulticurveSensitivity priceCurveSensitivity(final BondFuture future, final HullWhiteIssuerProviderInterface data, final int nbPoint); MulticurveSensitivity priceCurveSensitivity(final BondFuture future, final HullWhiteIssuerProviderInterface data); MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final BondFuture future, final HullWhiteIssuerProviderInterface data);  }
@Test public void price() { final HullWhiteIssuerProviderDiscount hwIssuer6 = new HullWhiteIssuerProviderDiscount(IssuerProviderDiscountDataSets.createIssuerProvider6(), PARAMETERS_HW); final double priceComputed = METHOD_HW.price(BOND_FUTURE_DERIV, hwIssuer6); final double priceExpected = 1.00; assertEquals("Bond future security Discounting Method: price from curves", priceExpected, priceComputed, 5.0E-3); }
@Test(enabled = false) public void performance() { long startTime, endTime; final int nbTest = 1000; double priceFuture = 0.0; startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { priceFuture = METHOD_HW.price(BOND_FUTURE_DERIV, HW_ISSUER); } endTime = System.currentTimeMillis(); System.out.println(nbTest + " price Bond Future Hull-White (Default number of points): " + (endTime - startTime) + " ms"); final int[] nbPoint = new int[] {41, 61, 81, 101, 151, 201, 501 }; final int nbRange = nbPoint.length; final double[] priceRange = new double[nbRange]; for (int looprange = 0; looprange < nbRange; looprange++) { startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { priceRange[looprange] = METHOD_HW.price(BOND_FUTURE_DERIV, HW_ISSUER, nbPoint[looprange]); } endTime = System.currentTimeMillis(); System.out.println(nbTest + " price Bond Future Hull-White: with " + nbPoint[looprange] + " points: " + (endTime - startTime) + " ms - price: " + priceRange[looprange]); } System.out.println("Bond futures - price - Hull-White one factor - delivery option: " + priceFuture); }