Package org.jquantlib.testsuite.instruments

Source Code of org.jquantlib.testsuite.instruments.BondTest

/*
Copyright (C) 2008 Richard Gomes
Copyright (C) 2009 John Nichol

This source code is release under the BSD License.

This file is part of JQuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://jquantlib.org/

JQuantLib is free software: you can redistribute it and/or modify it
under the terms of the JQuantLib license.  You should have received a
copy of the license along with this program; if not, please email
<jquant-devel@lists.sourceforge.net>. The license is also available online at
<http://www.jquantlib.org/index.php/LICENSE.TXT>.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the license for more details.

JQuantLib is based on QuantLib. http://quantlib.org/
When applicable, the original copyright notice follows this notice.
*/

/*
Copyright (C) 2003, 2004 Ferdinando Ametrano
Copyright (C) 2005 StatPro Italia srl
Copyright (C) 2005 Joseph Wang

This file is part of QuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://quantlib.org/

QuantLib is free software: you can redistribute it and/or modify it
under the terms of the QuantLib license.  You should have received a
copy of the license along with this program; if not, please email
<quantlib-dev@lists.sf.net>. The license is also available online at
<http://quantlib.org/license.shtml>.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/**
*
* Ported from
* <ul>
* <li>test-suite/americanoption.cpp</li>
* </ul>
*
* @author <Richard Gomes>
*
*/

package org.jquantlib.testsuite.instruments;

import static org.junit.Assert.fail;

import org.jquantlib.QL;
import org.jquantlib.Settings;
import org.jquantlib.cashflow.FixedRateLeg;
import org.jquantlib.cashflow.Leg;
import org.jquantlib.cashflow.SimpleCashFlow;
import org.jquantlib.daycounters.Actual360;
import org.jquantlib.daycounters.ActualActual;
import org.jquantlib.daycounters.Business252;
import org.jquantlib.daycounters.DayCounter;
import org.jquantlib.daycounters.Thirty360;
import org.jquantlib.instruments.Bond;
import org.jquantlib.instruments.FixedRateBond;
import org.jquantlib.instruments.ZeroCouponBond;
import org.jquantlib.pricingengines.PricingEngine;
import org.jquantlib.pricingengines.bond.DiscountingBondEngine;
import org.jquantlib.quotes.Handle;
import org.jquantlib.quotes.SimpleQuote;
import org.jquantlib.termstructures.Compounding;
import org.jquantlib.termstructures.InterestRate;
import org.jquantlib.termstructures.YieldTermStructure;
import org.jquantlib.testsuite.util.Utilities;
import org.jquantlib.time.BusinessDayConvention;
import org.jquantlib.time.Calendar;
import org.jquantlib.time.Date;
import org.jquantlib.time.DateGeneration;
import org.jquantlib.time.Frequency;
import org.jquantlib.time.Month;
import org.jquantlib.time.Period;
import org.jquantlib.time.Schedule;
import org.jquantlib.time.TimeUnit;
import org.jquantlib.time.DateGeneration.Rule;
import org.jquantlib.time.calendars.Brazil;
import org.jquantlib.time.calendars.NullCalendar;
import org.jquantlib.time.calendars.Target;
import org.jquantlib.time.calendars.UnitedStates;
import org.junit.Ignore;
import org.junit.Test;

public class BondTest {

  public BondTest() {
    QL.info("::::: " + this.getClass().getSimpleName() + " :::::");
  }


  @Ignore
  @Test
  //FIXME: http://bugs.jquantlib.org/view.php?id=472
  public void testYield() {
    QL.info("Testing consistency of bond price/yield calculation....");

        final Calendar calendar = new org.jquantlib.time.calendars.Target();
        final Date today = calendar.adjust(Date.todaysDate());
        final double faceAmount = 1000000.0;

    final double tolerance = 1.0e-7;
    final int maxEvaluations = 100;

    final int issueMonths[] = { -24, -18, -12, -6, 0, 6, 12, 18, 24 };
    final int lengths[] = { 3, 5, 10, 15, 20 };
    final int settlementDays = 3;
    final double coupons[] = { 0.02, 0.05, 0.08 };
    final Frequency frequencies[] = { Frequency.Semiannual, Frequency.Annual };
    final DayCounter bondDayCount = new Thirty360();
    final BusinessDayConvention accrualConvention = BusinessDayConvention.Unadjusted;
    final BusinessDayConvention paymentConvention = BusinessDayConvention.ModifiedFollowing;
    final double redemption = 100.0;

    final double yields[] = { 0.03, 0.04, 0.05, 0.06, 0.07 };
    final Compounding compounding[] = { Compounding.Compounded, Compounding.Continuous };

    for (int i = 0; i < (issueMonths).length; i++) {
      for (int j = 0; j < (lengths).length; j++) {
        for (int k = 0; k < (coupons).length; k++) {
          for (int l = 0; l < (frequencies).length; l++) {
            for (int n = 0; n < (compounding).length; n++) {
              final Date dated = calendar.advance(today, issueMonths[i], TimeUnit.Months);
              final Date issue = dated;
              final Date maturity = calendar.advance(issue, lengths[j], TimeUnit.Years);

              final Schedule sch = new Schedule(
                      dated,
                  maturity,
                  new Period(frequencies[l]),
                  calendar,
                  accrualConvention,
                  accrualConvention,
                  DateGeneration.Rule.Backward,
                  false,
                  new Date(),
                  new Date());

              final FixedRateBond bond = new FixedRateBond(
                      settlementDays,
                      faceAmount,
                      sch,
                  new double[] { coupons[k] }, bondDayCount, paymentConvention, redemption, issue);

              for (int m = 0; m < (yields).length; m++) {
                final double price = bond.cleanPrice(yields[m], bondDayCount, compounding[n], frequencies[l]);
                final double calculated = bond.yield(
                        price,
                        bondDayCount,
                        compounding[n],
                        frequencies[l],
                        new Date(),
                        tolerance,
                        maxEvaluations);

                if (Math.abs(yields[m] - calculated) > tolerance) {
                  // the difference might not matter
                  final double price2 = bond.cleanPrice(calculated, bondDayCount, compounding[n], frequencies[l]);
                  if (Math.abs(price - price2) / price > tolerance) {
                                  fail(
                            "yield recalculation failed:\n" + "    issue:     " + issue + "\n"
                        + "    maturity:  " + maturity + "\n" + "    coupon:    " + coupons[k] + "\n"
                        + "    frequency: " + frequencies[l] + "\n\n" + "    yield:  " + yields[m] + " "
                        + (compounding[n] == Compounding.Continuous ? "compounded" : "continuous") + "\n"
                        + "    price:  " + price + "\n" + "    yield': " + (calculated) + "\n"
                        + "    price': " + price2);
                  }
                }
              }
            }
          }
        }
      }
    }
  }

  @Test
  public void testTheoretical() {
    QL.info("Testing theoretical bond price/yield calculation...");

        final Calendar calendar = new org.jquantlib.time.calendars.Target();
        final Date today = calendar.adjust(Date.todaysDate());
        final double faceAmount = 1000000.0;

    final double tolerance = 1.0e-7;
    final int maxEvaluations = 100;

    final int lengths[] = { 3, 5, 10, 15, 20 };
    final int settlementDays = 3;
    final double coupons[] = { 0.02, 0.05, 0.08 };
    final Frequency frequencies[] = { Frequency.Semiannual, Frequency.Annual };
    final DayCounter bondDayCount = new Actual360();
    final BusinessDayConvention accrualConvention = BusinessDayConvention.Unadjusted;
    final BusinessDayConvention paymentConvention = BusinessDayConvention.ModifiedFollowing;
    final double redemption = 100.0;

    final double yields[] = { 0.03, 0.04, 0.05, 0.06, 0.07 };

    for (final int length : lengths) {
      for (final double coupon : coupons) {
        for (final Frequency frequency : frequencies) {

          final Date dated = today;
          final Date issue = dated;
          final Date maturity = calendar.advance(issue, length, TimeUnit.Years);

          final SimpleQuote rate = new SimpleQuote(0.0);
          final Handle<YieldTermStructure> discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, rate, bondDayCount));

          final Schedule sch = new Schedule(
                  dated, maturity,
              new Period(frequency), calendar,
              accrualConvention, accrualConvention,
              Rule.Backward, false);

          final FixedRateBond bond = new FixedRateBond(
                  settlementDays, faceAmount, sch,
              new double[] { coupon },
              bondDayCount, paymentConvention,
              redemption, issue);

          final PricingEngine bondEngine = new DiscountingBondEngine(discountCurve);
          bond.setPricingEngine(bondEngine);

          for (final double yield : yields) {

            rate.setValue(yield);

            final double price = bond.cleanPrice(yield, bondDayCount, Compounding.Continuous, frequency);
            final double calculatedPrice = bond.getCleanPrice();

            if (Math.abs(price-calculatedPrice) > tolerance) {
              fail(
                  "price calculation failed:"
                  + "\n    issue:     " + issue
                  + "\n    maturity:  " + maturity
                  + "\n    coupon:    " + coupon
                  + "\n    frequency: " + frequency + "\n"
                  + "\n    yield:  " + yield
                  + "\n    expected:    " + price
                  + "\n    calculated': " + calculatedPrice
                  + "\n    error':      " + (price-calculatedPrice));
            }

            final double calculatedYield = bond.yield(
                bondDayCount, Compounding.Continuous, frequency,
                tolerance, maxEvaluations);
            if (Math.abs(yield-calculatedYield) > tolerance) {
                            fail(
                  "yield calculation failed:"
                  + "\n    issue:     " + issue
                  + "\n    maturity:  " + maturity
                  + "\n    coupon:    " + coupon
                  + "\n    frequency: " + frequency + "\n"
                  + "\n    yield:  " + yield
                  + "\n    price:    " + price
                  + "\n    yield': " + calculatedYield);
            }
          }
        }
      }
    }
  }

  @Test
  public void testCached() {

    QL.info("Testing bond price/yield calculation against cached values...");

        //final Calendar calendar = new Target();
        // final Date today = calendar.adjust(Date.todaysDate());
        // final Date today = calendar.adjust(new Date(6,Month.June,2007));
        final Date today = new Date(22,Month.November,2004);
        final Settings settings = new Settings();
        settings.setEvaluationDate(today);

        final double faceAmount = 1000000.0;

        // with implicit settlement calculation:

      final Calendar bondCalendar = new NullCalendar();
      final DayCounter bondDayCount = new ActualActual(ActualActual.Convention.ISMA);
      final int settlementDays = 1;

    final Handle<YieldTermStructure> discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.03, new Actual360()));

      // actual market values from the evaluation date

      final Frequency freq = Frequency.Semiannual;
      final Schedule sch1 = new Schedule(new Date(31, Month.October, 2004),
                    new Date(31, Month.October, 2006), new Period(freq), bondCalendar,
                    BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false);

      final FixedRateBond bond1 = new FixedRateBond(settlementDays, faceAmount, sch1,
                          new double[] {0.025},
                          bondDayCount, BusinessDayConvention.ModifiedFollowing,
                          100.0, new Date(1, Month.November, 2004));

    final PricingEngine bondEngine = new DiscountingBondEngine(discountCurve);

      bond1.setPricingEngine(bondEngine);

      final double marketPrice1 = 99.203125;
      final double marketYield1 = 0.02925;

      final Schedule sch2 = new Schedule(new Date(15, Month.November, 2004),
          new Date(15, Month.November, 2009), new Period(freq), bondCalendar,
          BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false);

      final FixedRateBond bond2 = new FixedRateBond(settlementDays, faceAmount, sch2,
                          new double [] {0.035},
                          bondDayCount, BusinessDayConvention.ModifiedFollowing,
                          100.0, new Date(15, Month.November, 2004));

      bond2.setPricingEngine(bondEngine);

      final double marketPrice2 = 99.6875;
      final double marketYield2 = 0.03569;

      // calculated values

      final double cachedPrice1a = 99.204505, cachedPrice2a = 99.687192;
      final double cachedPrice1b = 98.943393, cachedPrice2b = 101.986794;
      final double cachedYield1a = 0.029257,  cachedYield2a = 0.035689;
      final double cachedYield1b = 0.029045,  cachedYield2b = 0.035375;
      final double cachedYield1c = 0.030423,  cachedYield2c = 0.030432;

      // check
      final double tolerance = 1.0e-6;
      double price, yield;

      price = bond1.cleanPrice(marketYield1,
                               bondDayCount, Compounding.Compounded, freq);
      if (Math.abs(price-cachedPrice1a) > tolerance) {
        fail("failed to reproduce cached price:"
                     + "\n    calculated: " + price
                     + "\n    expected:   " + cachedPrice1a
                     + "\n    tolerance:  " + tolerance
                     + "\n    error:      " + (price-cachedPrice1a));
      }

      price = bond1.getCleanPrice();
      if (Math.abs(price-cachedPrice1b) > tolerance) {
        fail("failed to reproduce cached price:"
                     + "\n    calculated: " + price
                     + "\n    expected:   " + cachedPrice1b
                     + "\n    tolerance:  " + tolerance
                     + "\n    error:      " + (price-cachedPrice1b));
      }

      yield = bond1.yield(marketPrice1, bondDayCount, Compounding.Compounded, freq);
      if (Math.abs(yield-cachedYield1a) > tolerance) {
        fail("failed to reproduce cached compounded yield:"
                     + "\n    calculated: " + yield
                     + "\n    expected:   " + cachedYield1a
                     + "\n    tolerance:  " + tolerance
                     + "\n    error:      " + (yield-cachedYield1a));
      }

      yield = bond1.yield(marketPrice1, bondDayCount, Compounding.Continuous, freq);
      if (Math.abs(yield-cachedYield1b) > tolerance) {
        fail("failed to reproduce cached continuous yield:"
                     + "\n    calculated: " + yield
                     + "\n    expected:   " + cachedYield1b
                     + "\n    tolerance:  " + tolerance
                     + "\n    error:      " + (yield-cachedYield1b));
      }

      yield = bond1.yield(bondDayCount, Compounding.Continuous, freq);
      if (Math.abs(yield-cachedYield1c) > tolerance) {
        fail("failed to reproduce cached continuous yield:"
                     + "\n    calculated: " + yield
                     + "\n    expected:   " + cachedYield1c
                     + "\n    tolerance:  " + tolerance
                     + "\n    error:      " + (yield-cachedYield1c));
      }


      price = bond2.cleanPrice(marketYield2, bondDayCount, Compounding.Compounded, freq);
      if (Math.abs(price-cachedPrice2a) > tolerance) {
        fail("failed to reproduce cached price:"
                     + "\n    calculated: " + price
                     + "\n    expected:   " + cachedPrice2a
                     + "\n    tolerance:  " + tolerance
                     + "\n    error:      " + (price-cachedPrice2a));
      }

      price = bond2.getCleanPrice();
      if (Math.abs(price-cachedPrice2b) > tolerance) {
        fail("failed to reproduce cached price:"
                     + "\n    calculated: " + price
                     + "\n    expected:   " + cachedPrice2b
                     + "\n    tolerance:  " + tolerance
                     + "\n    error:      " + (price-cachedPrice2b));
      }

      yield = bond2.yield(marketPrice2, bondDayCount, Compounding.Compounded, freq);
      if (Math.abs(yield-cachedYield2a) > tolerance) {
        fail("failed to reproduce cached compounded yield:"
                     + "\n    calculated: " + yield
                     + "\n    expected:   " + cachedYield2a
                     + "\n    tolerance:  " + tolerance
                     + "\n    error:      " + (yield-cachedYield2a));
      }

      yield = bond2.yield(marketPrice2, bondDayCount, Compounding.Continuous, freq);
      if (Math.abs(yield-cachedYield2b) > tolerance) {
        fail("failed to reproduce cached continuous yield:"
                     + "\n    calculated: " + yield
                     + "\n    expected:   " + cachedYield2b
                     + "\n    tolerance:  " + tolerance
                     + "\n    error:      " + (yield-cachedYield2b));
      }

      yield = bond2.yield(bondDayCount, Compounding.Continuous, freq);
      if (Math.abs(yield-cachedYield2c) > tolerance) {
        fail("failed to reproduce cached continuous yield:"
                     + "\n    calculated: " + yield
                     + "\n    expected:   " + cachedYield2c
                     + "\n    tolerance:  " + tolerance
                     + "\n    error:      " + (yield-cachedYield2c));
      }

      // with explicit settlement date:

      final Schedule sch3 = new Schedule(new Date(30,Month.November,2004),
                    new Date(30,Month.November,2006), new Period(freq),
                    new UnitedStates(UnitedStates.Market.GOVERNMENTBOND),
                    BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false);

      final FixedRateBond bond3 = new FixedRateBond(settlementDays, faceAmount, sch3,
                          new double[] {0.02875},
                          new ActualActual(ActualActual.Convention.ISMA),
                          BusinessDayConvention.ModifiedFollowing,
                          100.0, new Date(30,Month.November,2004));

      bond3.setPricingEngine(bondEngine);

      final double marketYield3 = 0.02997;

      final Date settlementDate = new Date(30,Month.November,2004);
      final double cachedPrice3 = 99.764874;

      price = bond3.cleanPrice(marketYield3,
                               bondDayCount, Compounding.Compounded, freq, settlementDate);
      if (Math.abs(price-cachedPrice3) > tolerance) {
        fail("failed to reproduce cached price:"
                     + "\n    calculated: " + price + ""
                     + "\n    expected:   " + cachedPrice3 + ""
                     + "\n    error:      " + (price-cachedPrice3));
      }

      // this should give the same result since the issue date is the
      // earliest possible settlement date

      settings.setEvaluationDate(new Date(22,Month.November,2004));

      price = bond3.cleanPrice(marketYield3, bondDayCount, Compounding.Compounded, freq);
      if (Math.abs(price-cachedPrice3) > tolerance) {
        fail("failed to reproduce cached price:"
                     + "\n    calculated: " + price + ""
                     + "\n    expected:   " + cachedPrice3 + ""
                     + "\n    error:      " + (price-cachedPrice3));
      }
  }

  @Test
  public void testCachedZero() {

      QL.info("Testing zero-coupon bond prices against cached values...");

        final Calendar calendar = new Target();
        final Date today = calendar.adjust(Date.todaysDate());
        // final Date today = calendar.adjust(new Date(6,Month.June,2007));
      // final Date today = new Date(22,Month.November,2004);
      final Settings settings = new Settings();
      settings.setEvaluationDate(today);

        final double faceAmount = 1000000.0;

      final int settlementDays = 1;

    final Handle<YieldTermStructure> discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.03, new Actual360()));

      final double tolerance = 1.0e-6;

      // plain

      final ZeroCouponBond bond1 = new ZeroCouponBond(settlementDays,
                           new UnitedStates(UnitedStates.Market.GOVERNMENTBOND),
                           faceAmount,
                           new Date(30,Month.November,2008),
                           BusinessDayConvention.ModifiedFollowing,
                           100.0, new Date(30,Month.November,2004));

    final PricingEngine bondEngine = new DiscountingBondEngine(discountCurve);
      bond1.setPricingEngine(bondEngine);

      final double cachedPrice1 = 88.551726;

      double price = bond1.getCleanPrice();
      if (Math.abs(price-cachedPrice1) > tolerance) {
          fail("failed to reproduce cached price:\n"
                     + "    calculated: " + price + "\n"
                     + "    expected:   " + cachedPrice1 + "\n"
                     + "    error:      " + (price-cachedPrice1));
      }

      final ZeroCouponBond bond2 = new ZeroCouponBond(settlementDays,
                           new UnitedStates(UnitedStates.Market.GOVERNMENTBOND),
                           faceAmount,
                           new Date(30,Month.November,2007),
                           BusinessDayConvention.ModifiedFollowing,
                           100.0, new Date(30,Month.November,2004));

      bond2.setPricingEngine(bondEngine);

      final double cachedPrice2 = 91.278949;

      price = bond2.getCleanPrice();
      if (Math.abs(price-cachedPrice2) > tolerance) {
          fail("failed to reproduce cached price:\n"
                     + "    calculated: " + price + "\n"
                     + "    expected:   " + cachedPrice2 + "\n"
                     + "    error:      " + (price-cachedPrice2));
      }

      final ZeroCouponBond bond3 = new ZeroCouponBond(settlementDays,
                           new UnitedStates(UnitedStates.Market.GOVERNMENTBOND),
                           faceAmount,
                           new Date(30,Month.November,2006),
                           BusinessDayConvention.ModifiedFollowing,
                           100.0, new Date(30,Month.November,2004));

      bond3.setPricingEngine(bondEngine);

      final double cachedPrice3 = 94.098006;

      price = bond3.getCleanPrice();
      if (Math.abs(price-cachedPrice3) > tolerance) {
          fail("failed to reproduce cached price:\n"
                     + "    calculated: " + price + "\n"
                     + "    expected:   " + cachedPrice3 + "\n"
                     + "    error:      " + (price-cachedPrice3));
      }
  }

  @Test
  public void testCachedFixed() {

      QL.info("Testing fixed-coupon bond prices against cached values...");

        final Calendar calendar = new Target();
        final Date today = calendar.adjust(Date.todaysDate());
        // final Date today = calendar.adjust(new Date(6,Month.June,2007));
        // final Date today = new Date(22,Month.November,2004);
        final Settings settings = new Settings();
        settings.setEvaluationDate(today);

        final double faceAmount = 1000000.0;

      final int settlementDays = 1;

    final Handle<YieldTermStructure> discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.03, new Actual360()));

      final double tolerance = 1.0e-6;

      // plain

      final Schedule sch = new Schedule(new Date(30,Month.November,2004),
                   new Date(30,Month.November,2008), new Period(Frequency.Semiannual),
                   new UnitedStates(UnitedStates.Market.GOVERNMENTBOND),
                   BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false);

      final FixedRateBond bond1 = new FixedRateBond(settlementDays, faceAmount, sch,
                          new double [] { 0.02875 },
                          new ActualActual(ActualActual.Convention.ISMA),
                          BusinessDayConvention.ModifiedFollowing,
                          100.0, new Date(30,Month.November,2004));

      final PricingEngine bondEngine = new DiscountingBondEngine(discountCurve);
      bond1.setPricingEngine(bondEngine);

      final double cachedPrice1 = 99.298100;

      double price = bond1.getCleanPrice();
      if (Math.abs(price-cachedPrice1) > tolerance) {
          fail("failed to reproduce cached price:\n"
                     + "    calculated: " + price + "\n"
                     + "    expected:   " + cachedPrice1 + "\n"
                     + "    error:      " + (price-cachedPrice1));
      }

      // varying coupons

      final double [] couponRates = new double[] { 0.02875, 0.03, 0.03125, 0.0325 };

      final FixedRateBond bond2 = new FixedRateBond(settlementDays, faceAmount, sch,
                            couponRates,
                            new ActualActual(ActualActual.Convention.ISMA),
                            BusinessDayConvention.ModifiedFollowing,
                            100.0, new Date(30,Month.November,2004));

      bond2.setPricingEngine(bondEngine);

      final double cachedPrice2 = 100.334149;

      price = bond2.getCleanPrice();
      if (Math.abs(price-cachedPrice2) > tolerance) {
          fail("failed to reproduce cached price:\n"
                     + "    calculated: " + price + "\n"
                     + "    expected:   " + cachedPrice2 + "\n"
                     + "    error:      " + (price-cachedPrice2));
      }

      // stub date

      final Schedule sch3 = new Schedule(new Date(30,Month.November,2004),
                    new Date(30,Month.March,2009), new Period(Frequency.Semiannual),
                    new UnitedStates(UnitedStates.Market.GOVERNMENTBOND),
                    BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted,
                    DateGeneration.Rule.Backward, false,
                    new Date(), new Date(30,Month.November,2008));

      final FixedRateBond bond3 = new FixedRateBond(settlementDays, faceAmount, sch3,
                            couponRates, new ActualActual(ActualActual.Convention.ISMA),
                            BusinessDayConvention.ModifiedFollowing,
                            100.0, new Date(30,Month.November,2004));

      bond3.setPricingEngine(bondEngine);

      final double cachedPrice3 = 100.382794;

      price = bond3.getCleanPrice();
      if (Math.abs(price-cachedPrice3) > tolerance) {
          fail("failed to reproduce cached price:\n"
                     + "    calculated: " + price + "\n"
                     + "    expected:   " + cachedPrice3 + "\n"
                     + "    error:      " + (price-cachedPrice3));
      }
  }


//  @Test
//  public void testCachedFloating() {
//
//      QL.info("Testing floating-rate bond prices against cached values...");
//
//      CommonVars vars = new CommonVars();
//
//      Date today = new Date(22,Month.November,2004);
//      Settings settings = new Settings();
//      settings.setEvaluationDate(today);
//
//      int settlementDays = 1;
//
//    Handle<YieldTermStructure> riskFreeRate = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.025, new Actual360()));
//    Handle<YieldTermStructure> discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.03, new Actual360()));
//
//    IborIndex index = new USDLibor(new Period(6,TimeUnit.Months), riskFreeRate);
//      int fixingDays = 1;
//
//      double tolerance = 1.0e-6;
//
//      IborCouponPricer pricer = new BlackIborCouponPricer(new Handle<CapletVolatilityStructure>());
//
//      // plain
//
//      Schedule sch = new Schedule(new Date(30,Month.November,2004),
//                   new Date(30,Month.November,2008),
//                   new Period(Frequency.Semiannual),
//                   new UnitedStates(UnitedStates.Market.GOVERNMENTBOND),
//                   BusinessDayConvention.ModifiedFollowing, BusinessDayConvention.ModifiedFollowing,
//                   DateGeneration.Rule.Backward, false);
//
//      FloatingRateBond bond1 = new FloatingRateBond(settlementDays, faceAmount, sch,
//                             index, new ActualActual(ActualActual.Convention.ISMA),
//                             BusinessDayConvention.ModifiedFollowing, fixingDays,
//                             new Array(), new Array(),
//                             new Array(), new Array(),
//                             false,
//                             100.0, new Date(30,Month.November,2004));
//
//      PricingEngine bondEngine = new DiscountingBondEngine(riskFreeRate);
//      bond1.setPricingEngine(bondEngine);
//
//      PricerSetter.setCouponPricer(bond1.cashflows(),pricer);
//
//
//      double cachedPrice1 = 99.874645;
////      #if defined(QL_USE_INDEXED_COUPON)
////      Real cachedPrice1 = 99.874645;
////      #else
////      Real cachedPrice1 = 99.874646;
////      #endif
//
//
//      double price = bond1.getCleanPrice();
//      if (Math.abs(price-cachedPrice1) > tolerance) {
//          fail("failed to reproduce cached price:\n"
//                     + "    calculated: " + price + "\n"
//                     + "    expected:   " + cachedPrice1 + "\n"
//                     + "    error:      " + (price-cachedPrice1));
//      }
//
//      // different risk-free and discount curve
//
//      FloatingRateBond bond2 = new FloatingRateBond(settlementDays, faceAmount, sch,
//                             index, new ActualActual(ActualActual.Convention.ISMA),
//                             BusinessDayConvention.ModifiedFollowing, fixingDays,
//                             new Array(), new Array(),
//                             new Array(), new Array(),
//                             false,
//                             100.0, new Date(30,Month.November,2004));
//
//      PricingEngine bondEngine2 = new DiscountingBondEngine(discountCurve);
//      bond2.setPricingEngine(bondEngine2);
//
//      PricerSetter.setCouponPricer(bond2.cashflows(),pricer);
//
////      #if defined(QL_USE_INDEXED_COUPON)
////      Real cachedPrice2 = 97.955904;
////      #else
////      Real cachedPrice2 = 97.955904;
////      #endif
//
//      double cachedPrice2 = 97.955904;
//      price = bond2.getCleanPrice();
//      if (Math.abs(price-cachedPrice2) > tolerance) {
//          fail("failed to reproduce cached price:\n"
//                     + "    calculated: " + price + "\n"
//                     + "    expected:   " + cachedPrice2 + "\n"
//                     + "    error:      " + (price-cachedPrice2));
//      }
//
//      // varying spread
//      double [] spreads = new double[] { 0.001, 0.0012, 0.0014, 0.0016 };
//
//      FloatingRateBond bond3 = new FloatingRateBond(settlementDays, faceAmount, sch,
//                             index, new ActualActual(ActualActual.Convention.ISMA),
//                             BusinessDayConvention.ModifiedFollowing, fixingDays,
//                             new Array(), new Array(spreads),
//                             new Array(), new Array(),
//                             false,
//                             100.0, new Date(30,Month.November,2004));
//
//      bond3.setPricingEngine(bondEngine2);
//
//      PricerSetter.setCouponPricer(bond3.cashflows(),pricer);
//
////      #if defined(QL_USE_INDEXED_COUPON)
////      Real cachedPrice3 = 98.495458;
////      #else
////      Real cachedPrice3 = 98.495459;
////      #endif
//
//      double cachedPrice3 = 98.495458;
//      price = bond3.getCleanPrice();
//      if (Math.abs(price-cachedPrice3) > tolerance) {
//          fail("failed to reproduce cached price:\n"
//                     + "    calculated: " + price + "\n"
//                     + "    expected:   " + cachedPrice3 + "\n"
//                     + "    error:      " + (price-cachedPrice3));
//      }
//  }

  @Test
  public void testBrazilianCached() {

      QL.info("Testing Brazilian public bond prices against cached values...");

        final Calendar calendar = new Target();
        // final Date today = calendar.adjust(Date.todaysDate());
      final Date today = calendar.adjust(new Date(6,Month.June,2007));
      final Settings settings = new Settings();
      settings.setEvaluationDate(today);

        //final double faceAmount = 1000000.0;
        final double faceAmount = 1000.0;
        final int settlementDays = 1;

      // NTN-F maturity dates
      final Date [] maturityDates = new Date[6];
      maturityDates[0] = new Date(1,Month.January,2008);
      maturityDates[1] = new Date(1,Month.January,2010);
      maturityDates[2] = new Date(1,Month.July,2010);
      maturityDates[3] = new Date(1,Month.January,2012);
      maturityDates[4] = new Date(1,Month.January,2014);
      maturityDates[5] = new Date(1,Month.January,2017);

      // NTN-F yields
      final double [] yields = new double[6];
      yields[0] = 0.114614;
      yields[1] = 0.105726;
      yields[2] = 0.105328;
      yields[3] = 0.104283;
      yields[4] = 0.103218;
      yields[5] = 0.102948;

      // NTN-F prices
      final double [] prices = new double[6];
      prices[0] = 1034.63031372;
      prices[1] = 1030.09919487;
      prices[2] = 1029.98307160;
      prices[3] = 1028.13585068;
      prices[4] = 1028.33383817;
      prices[5] = 1026.19716497;


      // The tolerance is high because Andima truncate yields
      final double tolerance = 1.0e-4;

      final InterestRate [] couponRates = new InterestRate[1];
      couponRates[0] = new InterestRate(0.1,new Thirty360(),Compounding.Compounded,Frequency.Annual);

      for (int bondIndex = 0; bondIndex < maturityDates.length; bondIndex++) {

          // plain
          final InterestRate yield = new InterestRate(yields[bondIndex],
                             new Business252(new Brazil()),
                             Compounding.Compounded, Frequency.Annual);

          final Schedule schedule = new Schedule(new Date(1,Month.January,2007),
                            maturityDates[bondIndex], new Period(Frequency.Semiannual),
                            new Brazil(Brazil.Market.SETTLEMENT),
                            BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted,
                            DateGeneration.Rule.Backward, false);

          // fixed coupons
          final Leg cashflows =
              new FixedRateLeg(schedule, new Actual360())
              .withNotionals(faceAmount)
              .withCouponRates(couponRates)
              .withPaymentAdjustment(BusinessDayConvention.ModifiedFollowing).Leg();
          // redemption
          cashflows.add(new SimpleCashFlow(faceAmount, cashflows.last().date()));

          final Bond bond = new Bond(settlementDays, new Brazil(Brazil.Market.SETTLEMENT),
                    faceAmount, cashflows.last().date(),
                    new Date(1,Month.January,2007), cashflows);

          final double cachedPrice = prices[bondIndex];

          final double price = faceAmount*bond.dirtyPrice(yield.rate(),
                                                       yield.dayCounter(),
                                                       yield.compounding(),
                                                       yield.frequency(),
                                                       today)/100;
          if (Math.abs(price-cachedPrice) > tolerance) {
              fail("failed to reproduce cached price:\n"
                          + "    calculated: " + price + "\n"
                          + "    expected:   " + cachedPrice + "\n"
                          + "    error:      " + (price-cachedPrice+ "\n"
                          );
          }
      }
  }

}
TOP

Related Classes of org.jquantlib.testsuite.instruments.BondTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.