static void Main(string[] args) { DateTime timer = DateTime.Now; /********************* *** MARKET DATA *** *********************/ Calendar calendar = new TARGET(); Date settlementDate = new Date(18, Month.September, 2008); // must be a business day settlementDate = calendar.adjust(settlementDate); int fixingDays = 3; int settlementDays = 3; Date todaysDate = calendar.advance(settlementDate, -fixingDays, TimeUnit.Days); // nothing to do with Date::todaysDate Settings.setEvaluationDate(todaysDate); Console.WriteLine("Today: {0}, {1}", todaysDate.DayOfWeek, todaysDate); Console.WriteLine("Settlement date: {0}, {1}", settlementDate.DayOfWeek, settlementDate); // Building of the bonds discounting yield curve /********************* *** RATE HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. // Common data // ZC rates for the short end double zc3mQuote=0.0096; double zc6mQuote=0.0145; double zc1yQuote=0.0194; Quote zc3mRate = new SimpleQuote(zc3mQuote); Quote zc6mRate = new SimpleQuote(zc6mQuote); Quote zc1yRate = new SimpleQuote(zc1yQuote); DayCounter zcBondsDayCounter = new Actual365Fixed(); RateHelper zc3m = new DepositRateHelper(new Handle<Quote>(zc3mRate), new Period(3, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); RateHelper zc6m = new DepositRateHelper(new Handle<Quote>(zc6mRate), new Period(6, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); RateHelper zc1y = new DepositRateHelper(new Handle<Quote>(zc1yRate), new Period(1, TimeUnit.Years), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); // setup bonds double redemption = 100.0; const int numberOfBonds = 5; Date[] issueDates = { new Date (15, Month.March, 2005), new Date (15, Month.June, 2005), new Date (30, Month.June, 2006), new Date (15, Month.November, 2002), new Date (15, Month.May, 1987) }; Date[] maturities = { new Date (31, Month.August, 2010), new Date (31, Month.August, 2011), new Date (31, Month.August, 2013), new Date (15, Month.August, 2018), new Date (15, Month.May, 2038) }; double[] couponRates = { 0.02375, 0.04625, 0.03125, 0.04000, 0.04500 }; double[] marketQuotes = { 100.390625, 106.21875, 100.59375, 101.6875, 102.140625 }; List<SimpleQuote> quote = new List<SimpleQuote>(); for (int i=0; i<numberOfBonds; i++) { SimpleQuote cp = new SimpleQuote(marketQuotes[i]); quote.Add(cp); } List<RelinkableHandle<Quote>> quoteHandle = new InitializedList<RelinkableHandle<Quote>>(numberOfBonds); for (int i=0; i<numberOfBonds; i++) { quoteHandle[i].linkTo(quote[i]); } // Definition of the rate helpers List<FixedRateBondHelper> bondsHelpers = new List<FixedRateBondHelper>(); for (int i=0; i<numberOfBonds; i++) { Schedule schedule = new Schedule(issueDates[i], maturities[i], new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBondHelper bondHelper = new FixedRateBondHelper(quoteHandle[i], settlementDays, 100.0, schedule, new List<double>() { couponRates[i] }, new ActualActual(ActualActual.Convention.Bond), BusinessDayConvention.Unadjusted, redemption, issueDates[i]); bondsHelpers.Add(bondHelper); } /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = new ActualActual(ActualActual.Convention.ISDA); double tolerance = 1.0e-15; // A depo-bond curve List<RateHelper> bondInstruments = new List<RateHelper>(); // Adding the ZC bonds to the curve for the short end bondInstruments.Add(zc3m); bondInstruments.Add(zc6m); bondInstruments.Add(zc1y); // Adding the Fixed rate bonds to the curve for the long end for (int i=0; i<numberOfBonds; i++) { bondInstruments.Add(bondsHelpers[i]); } YieldTermStructure bondDiscountingTermStructure = new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, bondInstruments, termStructureDayCounter, new List<Handle<Quote>>(), new List<Date>(), tolerance); // Building of the Libor forecasting curve // deposits double d1wQuote=0.043375; double d1mQuote=0.031875; double d3mQuote=0.0320375; double d6mQuote=0.03385; double d9mQuote=0.0338125; double d1yQuote=0.0335125; // swaps double s2yQuote=0.0295; double s3yQuote=0.0323; double s5yQuote=0.0359; double s10yQuote=0.0412; double s15yQuote=0.0433; /******************** *** QUOTES *** ********************/ // SimpleQuote stores a value which can be manually changed; // other Quote subclasses could read the value from a database // or some kind of data feed. // deposits Quote d1wRate = new SimpleQuote(d1wQuote); Quote d1mRate = new SimpleQuote(d1mQuote); Quote d3mRate = new SimpleQuote(d3mQuote); Quote d6mRate = new SimpleQuote(d6mQuote); Quote d9mRate = new SimpleQuote(d9mQuote); Quote d1yRate = new SimpleQuote(d1yQuote); // swaps Quote s2yRate = new SimpleQuote(s2yQuote); Quote s3yRate = new SimpleQuote(s3yQuote); Quote s5yRate = new SimpleQuote(s5yQuote); Quote s10yRate = new SimpleQuote(s10yQuote); Quote s15yRate = new SimpleQuote(s15yQuote); /********************* *** RATE HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. // deposits DayCounter depositDayCounter = new Actual360(); RateHelper d1w = new DepositRateHelper( new Handle<Quote>(d1wRate), new Period(1, TimeUnit.Weeks), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d1m = new DepositRateHelper( new Handle<Quote>(d1mRate), new Period(1, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d3m = new DepositRateHelper( new Handle<Quote>(d3mRate), new Period(3, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d6m = new DepositRateHelper( new Handle<Quote>(d6mRate), new Period(6, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d9m = new DepositRateHelper( new Handle<Quote>(d9mRate), new Period(9, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d1y = new DepositRateHelper( new Handle<Quote>(d1yRate), new Period(1, TimeUnit.Years), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); // setup swaps Frequency swFixedLegFrequency =Frequency.Annual; BusinessDayConvention swFixedLegConvention = BusinessDayConvention.Unadjusted; DayCounter swFixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European); IborIndex swFloatingLegIndex = new Euribor6M(); Period forwardStart = new Period(1, TimeUnit.Days); RateHelper s2y = new SwapRateHelper( new Handle<Quote>(s2yRate), new Period(2, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); RateHelper s3y = new SwapRateHelper( new Handle<Quote>(s3yRate), new Period(3, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); RateHelper s5y = new SwapRateHelper( new Handle<Quote>(s5yRate), new Period(5, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); RateHelper s10y = new SwapRateHelper( new Handle<Quote>(s10yRate), new Period(10, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); RateHelper s15y = new SwapRateHelper( new Handle<Quote>(s15yRate), new Period(15, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 // A depo-swap curve List<RateHelper> depoSwapInstruments = new List<RateHelper>(); depoSwapInstruments.Add(d1w); depoSwapInstruments.Add(d1m); depoSwapInstruments.Add(d3m); depoSwapInstruments.Add(d6m); depoSwapInstruments.Add(d9m); depoSwapInstruments.Add(d1y); depoSwapInstruments.Add(s2y); depoSwapInstruments.Add(s3y); depoSwapInstruments.Add(s5y); depoSwapInstruments.Add(s10y); depoSwapInstruments.Add(s15y); YieldTermStructure depoSwapTermStructure = new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoSwapInstruments, termStructureDayCounter, new List<Handle<Quote> >(), new List<Date>(), tolerance); // Term structures that will be used for pricing: // the one used for discounting cash flows RelinkableHandle<YieldTermStructure> discountingTermStructure = new RelinkableHandle<YieldTermStructure>(); // the one used for forward rate forecasting RelinkableHandle<YieldTermStructure> forecastingTermStructure = new RelinkableHandle<YieldTermStructure>(); /********************* * BONDS TO BE PRICED * **********************/ // Common data double faceAmount = 100; // Pricing engine IPricingEngine bondEngine = new DiscountingBondEngine(discountingTermStructure); // Zero coupon bond ZeroCouponBond zeroCouponBond = new ZeroCouponBond( settlementDays, new UnitedStates(UnitedStates.Market.GovernmentBond), faceAmount, new Date(15, Month.August,2013), BusinessDayConvention.Following, 116.92, new Date(15, Month.August,2003)); zeroCouponBond.setPricingEngine(bondEngine); // Fixed 4.5% US Treasury Note Schedule fixedBondSchedule = new Schedule(new Date(15, Month.May, 2007), new Date(15,Month.May,2017), new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond fixedRateBond = new FixedRateBond( settlementDays, faceAmount, fixedBondSchedule, new List<double>() { 0.045 }, new ActualActual(ActualActual.Convention.Bond), BusinessDayConvention.ModifiedFollowing, 100.0, new Date(15, Month.May, 2007)); fixedRateBond.setPricingEngine(bondEngine); // Floating rate bond (3M USD Libor + 0.1%) // Should and will be priced on another curve later... RelinkableHandle<YieldTermStructure> liborTermStructure = new RelinkableHandle<YieldTermStructure>(); IborIndex libor3m = new USDLibor(new Period(3, TimeUnit.Months), liborTermStructure); libor3m.addFixing(new Date(17, Month.July, 2008),0.0278625); Schedule floatingBondSchedule = new Schedule(new Date(21, Month.October, 2005), new Date(21, Month.October, 2010), new Period(Frequency.Quarterly), new UnitedStates(UnitedStates.Market.NYSE), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, true); FloatingRateBond floatingRateBond = new FloatingRateBond( settlementDays, faceAmount, floatingBondSchedule, libor3m, new Actual360(), BusinessDayConvention.ModifiedFollowing, 2, // Gearings new List<double>() { 1.0 }, // Spreads new List<double>() { 0.001 }, // Caps new List<double>(), // Floors new List<double>(), // Fixing in arrears true, 100.0, new Date(21, Month.October, 2005)); floatingRateBond.setPricingEngine(bondEngine); // Coupon pricers IborCouponPricer pricer = new BlackIborCouponPricer(); // optionLet volatilities double volatility = 0.0; Handle<OptionletVolatilityStructure> vol; vol = new Handle<OptionletVolatilityStructure>( new ConstantOptionletVolatility( settlementDays, calendar, BusinessDayConvention.ModifiedFollowing, volatility, new Actual365Fixed())); pricer.setCapletVolatility(vol); Utils.setCouponPricer(floatingRateBond.cashflows(),pricer); // Yield curve bootstrapping forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(bondDiscountingTermStructure); // We are using the depo & swap curve to estimate the future Libor rates liborTermStructure.linkTo(depoSwapTermStructure); /*************** * BOND PRICING * ****************/ // write column headings int[] widths = { 18, 10, 10, 10 }; Console.WriteLine("{0,18}{1,10}{2,10}{3,10}", "", "ZC", "Fixed", "Floating"); string separator = " | "; int width = widths[0] + widths[1] + widths[2] + widths[3]; string rule = "".PadLeft(width, '-'), dblrule = "".PadLeft(width, '='); string tab = "".PadLeft(8, ' '); Console.WriteLine(rule); Console.WriteLine("Net present value".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.NPV(), fixedRateBond.NPV(), floatingRateBond.NPV()); Console.WriteLine("Clean price".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.cleanPrice(), fixedRateBond.cleanPrice(), floatingRateBond.cleanPrice()); Console.WriteLine("Dirty price".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.dirtyPrice(), fixedRateBond.dirtyPrice(), floatingRateBond.dirtyPrice()); Console.WriteLine("Accrued coupon".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.accruedAmount(), fixedRateBond.accruedAmount(), floatingRateBond.accruedAmount()); Console.WriteLine("Previous coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", "N/A", fixedRateBond.previousCoupon(), floatingRateBond.previousCoupon()); Console.WriteLine("Next coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", "N/A", fixedRateBond.nextCoupon(), floatingRateBond.nextCoupon()); Console.WriteLine("Yield".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", zeroCouponBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), fixedRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual)); Console.WriteLine(); // Other computations Console.WriteLine("Sample indirect computations (for the floating rate bond): "); Console.WriteLine(rule); Console.WriteLine("Yield to Clean Price: {0:n2}", floatingRateBond.cleanPrice(floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), new Actual360(), Compounding.Compounded, Frequency.Annual, settlementDate)); Console.WriteLine("Clean Price to Yield: {0:0.00%}", floatingRateBond.yield(floatingRateBond.cleanPrice(),new Actual360(), Compounding.Compounded, Frequency.Annual, settlementDate)); /* "Yield to Price" "Price to Yield" */ Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.WriteLine(); Console.Write("Press any key to continue ..."); Console.ReadKey(); }
public void testImpliedValue() { // Testing implied bond value against asset-swap fair price with null spread CommonVars vars = new CommonVars(); Calendar bondCalendar = new TARGET(); int settlementDays = 3; int fixingDays = 2; bool payFixedRate = true; bool parAssetSwap = true; bool inArrears = false; // Fixed Underlying bond (Isin: DE0001135275 DBR 4 01/04/37) // maturity doesn't occur on a business day Schedule fixedBondSchedule1 = new Schedule( new Date(4,Month.January,2005), new Date(4,Month.January,2037), new Period(Frequency.Annual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); Bond fixedBond1 = new FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule1, new List<double>(){0.04}, new ActualActual(ActualActual.Convention.ISDA), BusinessDayConvention.Following, 100.0, new Date(4,Month.January,2005)); IPricingEngine bondEngine = new DiscountingBondEngine(vars.termStructure); IPricingEngine swapEngine = new DiscountingSwapEngine(vars.termStructure); fixedBond1.setPricingEngine(bondEngine); double fixedBondPrice1 = fixedBond1.cleanPrice(); AssetSwap fixedBondAssetSwap1 = new AssetSwap(payFixedRate, fixedBond1, fixedBondPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); fixedBondAssetSwap1.setPricingEngine(swapEngine); double fixedBondAssetSwapPrice1 = fixedBondAssetSwap1.fairCleanPrice(); double tolerance = 1.0e-13; double error1 = Math.Abs(fixedBondAssetSwapPrice1-fixedBondPrice1); if (error1>tolerance) { Assert.Fail("wrong zero spread asset swap price for fixed bond:" + "\n bond's clean price: " + fixedBondPrice1 + "\n asset swap fair price: " + fixedBondAssetSwapPrice1 + "\n error: " + error1 + "\n tolerance: " + tolerance); } // Fixed Underlying bond (Isin: IT0006527060 IBRD 5 02/05/19) // maturity occurs on a business day Schedule fixedBondSchedule2 = new Schedule( new Date(5,Month.February,2005), new Date(5,Month.February,2019), new Period(Frequency.Annual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); Bond fixedBond2 = new FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule2, new List<double>(){0.05}, new Thirty360(Thirty360.Thirty360Convention.BondBasis), BusinessDayConvention.Following, 100.0, new Date(5,Month.February,2005)); fixedBond2.setPricingEngine(bondEngine); double fixedBondPrice2 = fixedBond2.cleanPrice(); AssetSwap fixedBondAssetSwap2 = new AssetSwap(payFixedRate, fixedBond2, fixedBondPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); fixedBondAssetSwap2.setPricingEngine(swapEngine); double fixedBondAssetSwapPrice2 = fixedBondAssetSwap2.fairCleanPrice(); double error2 = Math.Abs(fixedBondAssetSwapPrice2-fixedBondPrice2); if (error2>tolerance) { Assert.Fail("wrong zero spread asset swap price for fixed bond:" + "\n bond's clean price: " + fixedBondPrice2 + "\n asset swap fair price: " + fixedBondAssetSwapPrice2 + "\n error: " + error2 + "\n tolerance: " + tolerance); } // FRN Underlying bond (Isin: IT0003543847 ISPIM 0 09/29/13) // maturity doesn't occur on a business day Schedule floatingBondSchedule1 = new Schedule( new Date(29,Month.September,2003), new Date(29,Month.September,2013), new Period(Frequency.Semiannual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); Bond floatingBond1 = new FloatingRateBond(settlementDays, vars.faceAmount, floatingBondSchedule1, vars.iborIndex, new Actual360(), BusinessDayConvention.Following, fixingDays, new List<double>(){1}, new List<double>(){0.0056}, new List<double>(), new List<double>(), inArrears, 100.0, new Date(29,Month.September,2003)); floatingBond1.setPricingEngine(bondEngine); Utils.setCouponPricer(floatingBond1.cashflows(), vars.pricer); vars.iborIndex.addFixing(new Date(27,Month.March,2007), 0.0402); double floatingBondPrice1 = floatingBond1.cleanPrice(); AssetSwap floatingBondAssetSwap1 = new AssetSwap(payFixedRate, floatingBond1, floatingBondPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); floatingBondAssetSwap1.setPricingEngine(swapEngine); double floatingBondAssetSwapPrice1 = floatingBondAssetSwap1.fairCleanPrice(); double error3 = Math.Abs(floatingBondAssetSwapPrice1-floatingBondPrice1); if (error3>tolerance) { Assert.Fail("wrong zero spread asset swap price for floater:" + "\n bond's clean price: " + floatingBondPrice1 + "\n asset swap fair price: " + floatingBondAssetSwapPrice1 + "\n error: " + error3 + "\n tolerance: " + tolerance); } // FRN Underlying bond (Isin: XS0090566539 COE 0 09/24/18) // maturity occurs on a business day Schedule floatingBondSchedule2 = new Schedule( new Date(24,Month.September,2004), new Date(24,Month.September,2018), new Period(Frequency.Semiannual), bondCalendar, BusinessDayConvention.ModifiedFollowing, BusinessDayConvention.ModifiedFollowing, DateGeneration.Rule.Backward, false); Bond floatingBond2 = new FloatingRateBond( settlementDays, vars.faceAmount, floatingBondSchedule2, vars.iborIndex, new Actual360(), BusinessDayConvention.ModifiedFollowing, fixingDays, new List<double>(){1}, new List<double>(){0.0025}, new List<double>(), new List<double>(), inArrears, 100.0, new Date(24,Month.September,2004)); floatingBond2.setPricingEngine(bondEngine); Utils.setCouponPricer(floatingBond2.cashflows(), vars.pricer); vars.iborIndex.addFixing( new Date(22,Month.March,2007), 0.04013); double currentCoupon=0.04013+0.0025; double floatingCurrentCoupon= floatingBond2.nextCouponRate(); double error4= Math.Abs(floatingCurrentCoupon-currentCoupon); if (error4>tolerance) { Assert.Fail("wrong current coupon is returned for floater bond:" + "\n bond's calculated current coupon: " + currentCoupon + "\n current coupon asked to the bond: " + floatingCurrentCoupon + "\n error: " + error4 + "\n tolerance: " + tolerance); } double floatingBondPrice2 = floatingBond2.cleanPrice(); AssetSwap floatingBondAssetSwap2 = new AssetSwap(payFixedRate,floatingBond2, floatingBondPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); floatingBondAssetSwap2.setPricingEngine(swapEngine); double floatingBondAssetSwapPrice2 = floatingBondAssetSwap2.fairCleanPrice(); double error5 = Math.Abs(floatingBondAssetSwapPrice2-floatingBondPrice2); if (error5>tolerance) { Assert.Fail("wrong zero spread asset swap price for floater:" + "\n bond's clean price: " + floatingBondPrice2 + "\n asset swap fair price: " + floatingBondAssetSwapPrice2 + "\n error: " + error5 + "\n tolerance: " + tolerance); } // CMS Underlying bond (Isin: XS0228052402 CRDIT 0 8/22/20) // maturity doesn't occur on a business day Schedule cmsBondSchedule1 = new Schedule( new Date(22,Month.August,2005), new Date(22,Month.August,2020), new Period(Frequency.Annual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); Bond cmsBond1 = new CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule1, vars.swapIndex, new Thirty360(), BusinessDayConvention.Following, fixingDays, new List<double>(){1.0}, new List<double>(){0.0}, new List<double>(){0.055}, new List<double>(){0.025}, inArrears, 100.0, new Date(22,Month.August,2005)); cmsBond1.setPricingEngine(bondEngine); Utils.setCouponPricer(cmsBond1.cashflows(), vars.cmspricer); vars.swapIndex.addFixing( new Date(18,Month.August,2006), 0.04158); double cmsBondPrice1 = cmsBond1.cleanPrice(); AssetSwap cmsBondAssetSwap1 = new AssetSwap(payFixedRate, cmsBond1, cmsBondPrice1, vars.iborIndex, vars.spread, null,vars.iborIndex.dayCounter(), parAssetSwap); cmsBondAssetSwap1.setPricingEngine(swapEngine); double cmsBondAssetSwapPrice1 = cmsBondAssetSwap1.fairCleanPrice(); double error6 = Math.Abs(cmsBondAssetSwapPrice1-cmsBondPrice1); if (error6>tolerance) { Assert.Fail("wrong zero spread asset swap price for cms bond:" + "\n bond's clean price: " + cmsBondPrice1 + "\n asset swap fair price: " + cmsBondAssetSwapPrice1 + "\n error: " + error6 + "\n tolerance: " + tolerance); } // CMS Underlying bond (Isin: XS0218766664 ISPIM 0 5/6/15) // maturity occurs on a business day Schedule cmsBondSchedule2 = new Schedule( new Date(06,Month.May,2005), new Date(06,Month.May,2015), new Period(Frequency.Annual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); Bond cmsBond2 = new CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule2, vars.swapIndex, new Thirty360(), BusinessDayConvention.Following, fixingDays, new List<double>(){0.84}, new List<double>(){0.0}, new List<double>(), new List<double>(), inArrears, 100.0, new Date(06,Month.May,2005)); cmsBond2.setPricingEngine(bondEngine); Utils.setCouponPricer(cmsBond2.cashflows(), vars.cmspricer); vars.swapIndex.addFixing( new Date(04,Month.May,2006), 0.04217); double cmsBondPrice2 = cmsBond2.cleanPrice(); AssetSwap cmsBondAssetSwap2 = new AssetSwap(payFixedRate,cmsBond2, cmsBondPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); cmsBondAssetSwap2.setPricingEngine(swapEngine); double cmsBondAssetSwapPrice2 = cmsBondAssetSwap2.fairCleanPrice(); double error7 = Math.Abs(cmsBondAssetSwapPrice2-cmsBondPrice2); if (error7>tolerance) { Assert.Fail("wrong zero spread asset swap price for cms bond:" + "\n bond's clean price: " + cmsBondPrice2 + "\n asset swap fair price: " + cmsBondAssetSwapPrice2 + "\n error: " + error7 + "\n tolerance: " + tolerance); } // Zero Coupon bond (Isin: DE0004771662 IBRD 0 12/20/15) // maturity doesn't occur on a business day Bond zeroCpnBond1 = new ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount, new Date(20,Month.December,2015), BusinessDayConvention.Following, 100.0, new Date(19,Month.December,1985)); zeroCpnBond1.setPricingEngine(bondEngine); double zeroCpnBondPrice1 = zeroCpnBond1.cleanPrice(); AssetSwap zeroCpnAssetSwap1 = new AssetSwap(payFixedRate,zeroCpnBond1, zeroCpnBondPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); zeroCpnAssetSwap1.setPricingEngine(swapEngine); double zeroCpnBondAssetSwapPrice1 = zeroCpnAssetSwap1.fairCleanPrice(); double error8 = Math.Abs(cmsBondAssetSwapPrice1-cmsBondPrice1); if (error8>tolerance) { Assert.Fail("wrong zero spread asset swap price for zero cpn bond:" + "\n bond's clean price: " + zeroCpnBondPrice1 + "\n asset swap fair price: " + zeroCpnBondAssetSwapPrice1 + "\n error: " + error8 + "\n tolerance: " + tolerance); } // Zero Coupon bond (Isin: IT0001200390 ISPIM 0 02/17/28) // maturity occurs on a business day Bond zeroCpnBond2 = new ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount, new Date(17,Month.February,2028), BusinessDayConvention.Following, 100.0, new Date(17,Month.February,1998)); zeroCpnBond2.setPricingEngine(bondEngine); double zeroCpnBondPrice2 = zeroCpnBond2.cleanPrice(); AssetSwap zeroCpnAssetSwap2 = new AssetSwap(payFixedRate, zeroCpnBond2, zeroCpnBondPrice2, vars.iborIndex, vars.spread, null,vars.iborIndex.dayCounter(), parAssetSwap); zeroCpnAssetSwap2.setPricingEngine(swapEngine); double zeroCpnBondAssetSwapPrice2 = zeroCpnAssetSwap2.fairCleanPrice(); double error9 = Math.Abs(cmsBondAssetSwapPrice2-cmsBondPrice2); if (error9>tolerance) { Assert.Fail("wrong zero spread asset swap price for zero cpn bond:" + "\n bond's clean price: " + zeroCpnBondPrice2 + "\n asset swap fair price: " + zeroCpnBondAssetSwapPrice2 + "\n error: " + error9 + "\n tolerance: " + tolerance); } }
public void testSpecializedBondVsGenericBondUsingAsw() { // Testing asset-swap prices and spreads for specialized bond against equivalent generic bond... CommonVars vars = new CommonVars(); Calendar bondCalendar = new TARGET(); int settlementDays = 3; int fixingDays = 2; bool payFixedRate = true; bool parAssetSwap = true; bool inArrears = false; // Fixed bond (Isin: DE0001135275 DBR 4 01/04/37) // maturity doesn't occur on a business day Date fixedBondStartDate1 = new Date(4,Month.January,2005); Date fixedBondMaturityDate1 = new Date(4,Month.January,2037); Schedule fixedBondSchedule1 = new Schedule(fixedBondStartDate1, fixedBondMaturityDate1, new Period(Frequency.Annual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); List<CashFlow> fixedBondLeg1 = new FixedRateLeg(fixedBondSchedule1) .withCouponRates(0.04, new ActualActual(ActualActual.Convention.ISDA)) .withNotionals(vars.faceAmount); Date fixedbondRedemption1 = bondCalendar.adjust(fixedBondMaturityDate1, BusinessDayConvention.Following); fixedBondLeg1.Add(new SimpleCashFlow(100.0, fixedbondRedemption1)); // generic bond Bond fixedBond1 = new Bond(settlementDays, bondCalendar, vars.faceAmount, fixedBondMaturityDate1, fixedBondStartDate1, fixedBondLeg1); IPricingEngine bondEngine = new DiscountingBondEngine(vars.termStructure); IPricingEngine swapEngine = new DiscountingSwapEngine(vars.termStructure); fixedBond1.setPricingEngine(bondEngine); // equivalent specialized fixed rate bond Bond fixedSpecializedBond1 = new FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule1, new List<double>{0.04}, new ActualActual(ActualActual.Convention.ISDA), BusinessDayConvention.Following, 100.0, new Date(4,Month.January,2005)); fixedSpecializedBond1.setPricingEngine(bondEngine); double fixedBondPrice1 = fixedBond1.cleanPrice(); double fixedSpecializedBondPrice1 = fixedSpecializedBond1.cleanPrice(); AssetSwap fixedBondAssetSwap1 = new AssetSwap(payFixedRate, fixedBond1, fixedBondPrice1, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); fixedBondAssetSwap1.setPricingEngine(swapEngine); AssetSwap fixedSpecializedBondAssetSwap1 = new AssetSwap(payFixedRate, fixedSpecializedBond1, fixedSpecializedBondPrice1, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); fixedSpecializedBondAssetSwap1.setPricingEngine(swapEngine); double fixedBondAssetSwapPrice1 = fixedBondAssetSwap1.fairCleanPrice(); double fixedSpecializedBondAssetSwapPrice1 = fixedSpecializedBondAssetSwap1.fairCleanPrice(); double tolerance = 1.0e-13; double error1 = Math.Abs(fixedBondAssetSwapPrice1-fixedSpecializedBondAssetSwapPrice1); if (error1>tolerance) { Assert.Fail("wrong clean price for fixed bond:" + "\n generic fixed rate bond's clean price: " + fixedBondAssetSwapPrice1 + "\n equivalent specialized bond's clean price: " + fixedSpecializedBondAssetSwapPrice1 + "\n error: " + error1 + "\n tolerance: " + tolerance); } // market executable price as of 4th sept 2007 double fixedBondMktPrice1= 91.832; AssetSwap fixedBondASW1 = new AssetSwap(payFixedRate, fixedBond1, fixedBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); fixedBondASW1.setPricingEngine(swapEngine); AssetSwap fixedSpecializedBondASW1 = new AssetSwap(payFixedRate, fixedSpecializedBond1, fixedBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); fixedSpecializedBondASW1.setPricingEngine(swapEngine); double fixedBondASWSpread1 = fixedBondASW1.fairSpread(); double fixedSpecializedBondASWSpread1 = fixedSpecializedBondASW1.fairSpread(); double error2 = Math.Abs(fixedBondASWSpread1-fixedSpecializedBondASWSpread1); if (error2>tolerance) { Assert.Fail("wrong asw spread for fixed bond:" + "\n generic fixed rate bond's asw spread: " + fixedBondASWSpread1 + "\n equivalent specialized bond's asw spread: " + fixedSpecializedBondASWSpread1 + "\n error: " + error2 + "\n tolerance: " + tolerance); } //Fixed bond (Isin: IT0006527060 IBRD 5 02/05/19) //maturity occurs on a business day Date fixedBondStartDate2 = new Date(5,Month.February,2005); Date fixedBondMaturityDate2 = new Date(5,Month.February,2019); Schedule fixedBondSchedule2= new Schedule(fixedBondStartDate2, fixedBondMaturityDate2, new Period(Frequency.Annual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); List<CashFlow> fixedBondLeg2 = new FixedRateLeg(fixedBondSchedule2) .withCouponRates(0.05, new Thirty360(Thirty360.Thirty360Convention.BondBasis)) .withNotionals(vars.faceAmount); Date fixedbondRedemption2 = bondCalendar.adjust(fixedBondMaturityDate2, BusinessDayConvention.Following); fixedBondLeg2.Add(new SimpleCashFlow(100.0, fixedbondRedemption2)); // generic bond Bond fixedBond2 = new Bond(settlementDays, bondCalendar, vars.faceAmount, fixedBondMaturityDate2, fixedBondStartDate2, fixedBondLeg2); fixedBond2.setPricingEngine(bondEngine); // equivalent specialized fixed rate bond Bond fixedSpecializedBond2 = new FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule2, new List<double>{ 0.05}, new Thirty360(Thirty360.Thirty360Convention.BondBasis), BusinessDayConvention.Following, 100.0, new Date(5,Month.February,2005)); fixedSpecializedBond2.setPricingEngine(bondEngine); double fixedBondPrice2 = fixedBond2.cleanPrice(); double fixedSpecializedBondPrice2 = fixedSpecializedBond2.cleanPrice(); AssetSwap fixedBondAssetSwap2 = new AssetSwap(payFixedRate, fixedBond2, fixedBondPrice2, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); fixedBondAssetSwap2.setPricingEngine(swapEngine); AssetSwap fixedSpecializedBondAssetSwap2 = new AssetSwap(payFixedRate, fixedSpecializedBond2, fixedSpecializedBondPrice2, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); fixedSpecializedBondAssetSwap2.setPricingEngine(swapEngine); double fixedBondAssetSwapPrice2 = fixedBondAssetSwap2.fairCleanPrice(); double fixedSpecializedBondAssetSwapPrice2 = fixedSpecializedBondAssetSwap2.fairCleanPrice(); double error3 = Math.Abs(fixedBondAssetSwapPrice2-fixedSpecializedBondAssetSwapPrice2); if (error3>tolerance) { Assert.Fail("wrong clean price for fixed bond:" + "\n generic fixed rate bond's clean price: " + fixedBondAssetSwapPrice2 + "\n equivalent specialized bond's clean price: " + fixedSpecializedBondAssetSwapPrice2 + "\n error: " + error3 + "\n tolerance: " + tolerance); } // market executable price as of 4th sept 2007 double fixedBondMktPrice2= 102.178; AssetSwap fixedBondASW2 = new AssetSwap(payFixedRate, fixedBond2, fixedBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); fixedBondASW2.setPricingEngine(swapEngine); AssetSwap fixedSpecializedBondASW2 = new AssetSwap(payFixedRate, fixedSpecializedBond2, fixedBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); fixedSpecializedBondASW2.setPricingEngine(swapEngine); double fixedBondASWSpread2 = fixedBondASW2.fairSpread(); double fixedSpecializedBondASWSpread2 = fixedSpecializedBondASW2.fairSpread(); double error4 = Math.Abs(fixedBondASWSpread2-fixedSpecializedBondASWSpread2); if (error4>tolerance) { Assert.Fail("wrong asw spread for fixed bond:" + "\n generic fixed rate bond's asw spread: " + fixedBondASWSpread2 + "\n equivalent specialized bond's asw spread: " + fixedSpecializedBondASWSpread2 + "\n error: " + error4 + "\n tolerance: " + tolerance); } //FRN bond (Isin: IT0003543847 ISPIM 0 09/29/13) //maturity doesn't occur on a business day Date floatingBondStartDate1 = new Date(29,Month.September,2003); Date floatingBondMaturityDate1 = new Date(29,Month.September,2013); Schedule floatingBondSchedule1= new Schedule(floatingBondStartDate1, floatingBondMaturityDate1, new Period(Frequency.Semiannual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); List<CashFlow> floatingBondLeg1 = new IborLeg(floatingBondSchedule1, vars.iborIndex) .withPaymentDayCounter(new Actual360()) .withFixingDays(fixingDays) .withSpreads(0.0056) .inArrears(inArrears) .withNotionals(vars.faceAmount); Date floatingbondRedemption1 = bondCalendar.adjust(floatingBondMaturityDate1, BusinessDayConvention.Following); floatingBondLeg1.Add(new SimpleCashFlow(100.0, floatingbondRedemption1)); // generic bond Bond floatingBond1 = new Bond(settlementDays, bondCalendar, vars.faceAmount, floatingBondMaturityDate1, floatingBondStartDate1, floatingBondLeg1); floatingBond1.setPricingEngine(bondEngine); // equivalent specialized floater Bond floatingSpecializedBond1 = new FloatingRateBond(settlementDays, vars.faceAmount, floatingBondSchedule1, vars.iborIndex, new Actual360(), BusinessDayConvention.Following, fixingDays, new List<double>{1}, new List<double>{0.0056}, new List<double>(), new List<double>(), inArrears, 100.0, new Date(29,Month.September,2003)); floatingSpecializedBond1.setPricingEngine(bondEngine); Utils.setCouponPricer(floatingBond1.cashflows(), vars.pricer); Utils.setCouponPricer(floatingSpecializedBond1.cashflows(), vars.pricer); vars.iborIndex.addFixing(new Date(27,Month.March,2007), 0.0402); double floatingBondPrice1 = floatingBond1.cleanPrice(); double floatingSpecializedBondPrice1= floatingSpecializedBond1.cleanPrice(); AssetSwap floatingBondAssetSwap1= new AssetSwap(payFixedRate, floatingBond1, floatingBondPrice1, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); floatingBondAssetSwap1.setPricingEngine(swapEngine); AssetSwap floatingSpecializedBondAssetSwap1= new AssetSwap(payFixedRate, floatingSpecializedBond1, floatingSpecializedBondPrice1, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); floatingSpecializedBondAssetSwap1.setPricingEngine(swapEngine); double floatingBondAssetSwapPrice1 = floatingBondAssetSwap1.fairCleanPrice(); double floatingSpecializedBondAssetSwapPrice1 = floatingSpecializedBondAssetSwap1.fairCleanPrice(); double error5 = Math.Abs(floatingBondAssetSwapPrice1-floatingSpecializedBondAssetSwapPrice1); if (error5>tolerance) { Assert.Fail("wrong clean price for frnbond:" + "\n generic frn rate bond's clean price: " + floatingBondAssetSwapPrice1 + "\n equivalent specialized bond's price: " + floatingSpecializedBondAssetSwapPrice1 + "\n error: " + error5 + "\n tolerance: " + tolerance); } // market executable price as of 4th sept 2007 double floatingBondMktPrice1= 101.33; AssetSwap floatingBondASW1= new AssetSwap(payFixedRate, floatingBond1, floatingBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); floatingBondASW1.setPricingEngine(swapEngine); AssetSwap floatingSpecializedBondASW1= new AssetSwap(payFixedRate, floatingSpecializedBond1, floatingBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); floatingSpecializedBondASW1.setPricingEngine(swapEngine); double floatingBondASWSpread1 = floatingBondASW1.fairSpread(); double floatingSpecializedBondASWSpread1 = floatingSpecializedBondASW1.fairSpread(); double error6 = Math.Abs(floatingBondASWSpread1-floatingSpecializedBondASWSpread1); if (error6>tolerance) { Assert.Fail("wrong asw spread for fixed bond:" + "\n generic frn rate bond's asw spread: " + floatingBondASWSpread1 + "\n equivalent specialized bond's asw spread: " + floatingSpecializedBondASWSpread1 + "\n error: " + error6 + "\n tolerance: " + tolerance); } //FRN bond (Isin: XS0090566539 COE 0 09/24/18) //maturity occurs on a business day Date floatingBondStartDate2 = new Date(24,Month.September,2004); Date floatingBondMaturityDate2 = new Date(24,Month.September,2018); Schedule floatingBondSchedule2= new Schedule(floatingBondStartDate2, floatingBondMaturityDate2, new Period(Frequency.Semiannual), bondCalendar, BusinessDayConvention.ModifiedFollowing, BusinessDayConvention.ModifiedFollowing, DateGeneration.Rule.Backward, false); List<CashFlow> floatingBondLeg2 = new IborLeg(floatingBondSchedule2, vars.iborIndex) .withPaymentDayCounter(new Actual360()) .withFixingDays(fixingDays) .withSpreads(0.0025) .inArrears(inArrears) .withPaymentAdjustment(BusinessDayConvention.ModifiedFollowing) .withNotionals(vars.faceAmount); Date floatingbondRedemption2 = bondCalendar.adjust(floatingBondMaturityDate2, BusinessDayConvention.ModifiedFollowing); floatingBondLeg2.Add(new SimpleCashFlow(100.0, floatingbondRedemption2)); // generic bond Bond floatingBond2 = new Bond(settlementDays, bondCalendar, vars.faceAmount, floatingBondMaturityDate2, floatingBondStartDate2,floatingBondLeg2); floatingBond2.setPricingEngine(bondEngine); // equivalent specialized floater Bond floatingSpecializedBond2 = new FloatingRateBond(settlementDays, vars.faceAmount, floatingBondSchedule2, vars.iborIndex, new Actual360(), BusinessDayConvention.ModifiedFollowing, fixingDays, new List<double>{1}, new List<double>{0.0025}, new List<double>(), new List<double>(), inArrears, 100.0, new Date(24,Month.September,2004)); floatingSpecializedBond2.setPricingEngine(bondEngine); Utils.setCouponPricer(floatingBond2.cashflows(), vars.pricer); Utils.setCouponPricer(floatingSpecializedBond2.cashflows(), vars.pricer); vars.iborIndex.addFixing(new Date(22,Month.March,2007), 0.04013); double floatingBondPrice2 = floatingBond2.cleanPrice(); double floatingSpecializedBondPrice2= floatingSpecializedBond2.cleanPrice(); AssetSwap floatingBondAssetSwap2= new AssetSwap(payFixedRate, floatingBond2, floatingBondPrice2, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); floatingBondAssetSwap2.setPricingEngine(swapEngine); AssetSwap floatingSpecializedBondAssetSwap2= new AssetSwap(payFixedRate, floatingSpecializedBond2, floatingSpecializedBondPrice2, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); floatingSpecializedBondAssetSwap2.setPricingEngine(swapEngine); double floatingBondAssetSwapPrice2 = floatingBondAssetSwap2.fairCleanPrice(); double floatingSpecializedBondAssetSwapPrice2 = floatingSpecializedBondAssetSwap2.fairCleanPrice(); double error7 = Math.Abs(floatingBondAssetSwapPrice2-floatingSpecializedBondAssetSwapPrice2); if (error7>tolerance) { Assert.Fail("wrong clean price for frnbond:" + "\n generic frn rate bond's clean price: " + floatingBondAssetSwapPrice2 + "\n equivalent specialized frn bond's price: " + floatingSpecializedBondAssetSwapPrice2 + "\n error: " + error7 + "\n tolerance: " + tolerance); } // market executable price as of 4th sept 2007 double floatingBondMktPrice2 = 101.26; AssetSwap floatingBondASW2= new AssetSwap(payFixedRate, floatingBond2, floatingBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); floatingBondASW2.setPricingEngine(swapEngine); AssetSwap floatingSpecializedBondASW2= new AssetSwap(payFixedRate, floatingSpecializedBond2, floatingBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); floatingSpecializedBondASW2.setPricingEngine(swapEngine); double floatingBondASWSpread2 = floatingBondASW2.fairSpread(); double floatingSpecializedBondASWSpread2 = floatingSpecializedBondASW2.fairSpread(); double error8 = Math.Abs(floatingBondASWSpread2-floatingSpecializedBondASWSpread2); if (error8>tolerance) { Assert.Fail("wrong asw spread for frn bond:" + "\n generic frn rate bond's asw spread: " + floatingBondASWSpread2 + "\n equivalent specialized bond's asw spread: " + floatingSpecializedBondASWSpread2 + "\n error: " + error8 + "\n tolerance: " + tolerance); } // CMS bond (Isin: XS0228052402 CRDIT 0 8/22/20) // maturity doesn't occur on a business day Date cmsBondStartDate1 = new Date(22,Month.August,2005); Date cmsBondMaturityDate1 = new Date(22,Month.August,2020); Schedule cmsBondSchedule1= new Schedule(cmsBondStartDate1, cmsBondMaturityDate1, new Period(Frequency.Annual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); List<CashFlow> cmsBondLeg1 = new CmsLeg(cmsBondSchedule1, vars.swapIndex) .withPaymentDayCounter(new Thirty360()) .withFixingDays(fixingDays) .withCaps(0.055) .withFloors(0.025) .inArrears(inArrears) .withNotionals(vars.faceAmount); Date cmsbondRedemption1 = bondCalendar.adjust(cmsBondMaturityDate1, BusinessDayConvention.Following); cmsBondLeg1.Add(new SimpleCashFlow(100.0, cmsbondRedemption1)); // generic cms bond Bond cmsBond1 = new Bond(settlementDays, bondCalendar, vars.faceAmount, cmsBondMaturityDate1, cmsBondStartDate1, cmsBondLeg1); cmsBond1.setPricingEngine(bondEngine); // equivalent specialized cms bond Bond cmsSpecializedBond1 = new CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule1, vars.swapIndex, new Thirty360(), BusinessDayConvention.Following, fixingDays, new List<double>{1.0}, new List<double>{0.0}, new List<double>{0.055}, new List<double>{0.025}, inArrears, 100.0, new Date(22,Month.August,2005)); cmsSpecializedBond1.setPricingEngine(bondEngine); Utils.setCouponPricer(cmsBond1.cashflows(), vars.cmspricer); Utils.setCouponPricer(cmsSpecializedBond1.cashflows(), vars.cmspricer); vars.swapIndex.addFixing(new Date(18,Month.August,2006), 0.04158); double cmsBondPrice1 = cmsBond1.cleanPrice(); double cmsSpecializedBondPrice1 = cmsSpecializedBond1.cleanPrice(); AssetSwap cmsBondAssetSwap1= new AssetSwap(payFixedRate,cmsBond1, cmsBondPrice1, vars.iborIndex, vars.nonnullspread, null,vars.iborIndex.dayCounter(), parAssetSwap); cmsBondAssetSwap1.setPricingEngine(swapEngine); AssetSwap cmsSpecializedBondAssetSwap1= new AssetSwap(payFixedRate,cmsSpecializedBond1, cmsSpecializedBondPrice1, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); cmsSpecializedBondAssetSwap1.setPricingEngine(swapEngine); double cmsBondAssetSwapPrice1 = cmsBondAssetSwap1.fairCleanPrice(); double cmsSpecializedBondAssetSwapPrice1 = cmsSpecializedBondAssetSwap1.fairCleanPrice(); double error9 = Math.Abs(cmsBondAssetSwapPrice1-cmsSpecializedBondAssetSwapPrice1); if (error9>tolerance) { Assert.Fail("wrong clean price for cmsbond:" + "\n generic bond's clean price: " + cmsBondAssetSwapPrice1 + "\n equivalent specialized cms rate bond's price: " + cmsSpecializedBondAssetSwapPrice1 + "\n error: " + error9 + "\n tolerance: " + tolerance); } double cmsBondMktPrice1 = 87.02;// market executable price as of 4th sept 2007 AssetSwap cmsBondASW1= new AssetSwap(payFixedRate, cmsBond1, cmsBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); cmsBondASW1.setPricingEngine(swapEngine); AssetSwap cmsSpecializedBondASW1= new AssetSwap(payFixedRate, cmsSpecializedBond1, cmsBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); cmsSpecializedBondASW1.setPricingEngine(swapEngine); double cmsBondASWSpread1 = cmsBondASW1.fairSpread(); double cmsSpecializedBondASWSpread1 = cmsSpecializedBondASW1.fairSpread(); double error10 = Math.Abs(cmsBondASWSpread1-cmsSpecializedBondASWSpread1); if (error10>tolerance) { Assert.Fail("wrong asw spread for cm bond:" + "\n generic cms rate bond's asw spread: " + cmsBondASWSpread1 + "\n equivalent specialized bond's asw spread: " + cmsSpecializedBondASWSpread1 + "\n error: " + error10 + "\n tolerance: " + tolerance); } //CMS bond (Isin: XS0218766664 ISPIM 0 5/6/15) //maturity occurs on a business day Date cmsBondStartDate2 = new Date(06,Month.May,2005); Date cmsBondMaturityDate2 = new Date(06,Month.May,2015); Schedule cmsBondSchedule2= new Schedule(cmsBondStartDate2, cmsBondMaturityDate2, new Period(Frequency.Annual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); List<CashFlow> cmsBondLeg2 = new CmsLeg(cmsBondSchedule2, vars.swapIndex) .withPaymentDayCounter(new Thirty360()) .withFixingDays(fixingDays) .withGearings(0.84) .inArrears(inArrears) .withNotionals(vars.faceAmount); Date cmsbondRedemption2 = bondCalendar.adjust(cmsBondMaturityDate2, BusinessDayConvention.Following); cmsBondLeg2.Add(new SimpleCashFlow(100.0, cmsbondRedemption2)); // generic bond Bond cmsBond2 = new Bond(settlementDays, bondCalendar, vars.faceAmount, cmsBondMaturityDate2, cmsBondStartDate2, cmsBondLeg2); cmsBond2.setPricingEngine(bondEngine); // equivalent specialized cms bond Bond cmsSpecializedBond2 = new CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule2, vars.swapIndex, new Thirty360(), BusinessDayConvention.Following, fixingDays, new List<double>{0.84}, new List<double>{0.0}, new List<double>(), new List<double>(), inArrears, 100.0, new Date(06,Month.May,2005)); cmsSpecializedBond2.setPricingEngine(bondEngine); Utils.setCouponPricer(cmsBond2.cashflows(), vars.cmspricer); Utils.setCouponPricer(cmsSpecializedBond2.cashflows(), vars.cmspricer); vars.swapIndex.addFixing(new Date(04,Month.May,2006), 0.04217); double cmsBondPrice2 = cmsBond2.cleanPrice(); double cmsSpecializedBondPrice2 = cmsSpecializedBond2.cleanPrice(); AssetSwap cmsBondAssetSwap2= new AssetSwap(payFixedRate,cmsBond2, cmsBondPrice2, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); cmsBondAssetSwap2.setPricingEngine(swapEngine); AssetSwap cmsSpecializedBondAssetSwap2= new AssetSwap(payFixedRate,cmsSpecializedBond2, cmsSpecializedBondPrice2, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); cmsSpecializedBondAssetSwap2.setPricingEngine(swapEngine); double cmsBondAssetSwapPrice2 = cmsBondAssetSwap2.fairCleanPrice(); double cmsSpecializedBondAssetSwapPrice2 = cmsSpecializedBondAssetSwap2.fairCleanPrice(); double error11 = Math.Abs(cmsBondAssetSwapPrice2-cmsSpecializedBondAssetSwapPrice2); if (error11>tolerance) { Assert.Fail("wrong clean price for cmsbond:" + "\n generic bond's clean price: " + cmsBondAssetSwapPrice2 + "\n equivalent specialized cms rate bond's price: " + cmsSpecializedBondAssetSwapPrice2 + "\n error: " + error11 + "\n tolerance: " + tolerance); } double cmsBondMktPrice2 = 94.35;// market executable price as of 4th sept 2007 AssetSwap cmsBondASW2= new AssetSwap(payFixedRate, cmsBond2, cmsBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); cmsBondASW2.setPricingEngine(swapEngine); AssetSwap cmsSpecializedBondASW2= new AssetSwap(payFixedRate, cmsSpecializedBond2, cmsBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); cmsSpecializedBondASW2.setPricingEngine(swapEngine); double cmsBondASWSpread2 = cmsBondASW2.fairSpread(); double cmsSpecializedBondASWSpread2 = cmsSpecializedBondASW2.fairSpread(); double error12 = Math.Abs(cmsBondASWSpread2-cmsSpecializedBondASWSpread2); if (error12>tolerance) { Assert.Fail("wrong asw spread for cm bond:" + "\n generic cms rate bond's asw spread: " + cmsBondASWSpread2 + "\n equivalent specialized bond's asw spread: " + cmsSpecializedBondASWSpread2 + "\n error: " + error12 + "\n tolerance: " + tolerance); } // Zero-Coupon bond (Isin: DE0004771662 IBRD 0 12/20/15) // maturity doesn't occur on a business day Date zeroCpnBondStartDate1 = new Date(19,Month.December,1985); Date zeroCpnBondMaturityDate1 = new Date(20,Month.December,2015); Date zeroCpnBondRedemption1 = bondCalendar.adjust(zeroCpnBondMaturityDate1, BusinessDayConvention.Following); List<CashFlow> zeroCpnBondLeg1 = new List<CashFlow>{new SimpleCashFlow(100.0, zeroCpnBondRedemption1)}; // generic bond Bond zeroCpnBond1 = new Bond(settlementDays, bondCalendar, vars.faceAmount, zeroCpnBondMaturityDate1, zeroCpnBondStartDate1, zeroCpnBondLeg1); zeroCpnBond1.setPricingEngine(bondEngine); // specialized zerocpn bond Bond zeroCpnSpecializedBond1= new ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount, new Date(20,Month.December,2015), BusinessDayConvention.Following, 100.0, new Date(19,Month.December,1985)); zeroCpnSpecializedBond1.setPricingEngine(bondEngine); double zeroCpnBondPrice1 = zeroCpnBond1.cleanPrice(); double zeroCpnSpecializedBondPrice1 = zeroCpnSpecializedBond1.cleanPrice(); AssetSwap zeroCpnBondAssetSwap1= new AssetSwap(payFixedRate,zeroCpnBond1, zeroCpnBondPrice1, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); zeroCpnBondAssetSwap1.setPricingEngine(swapEngine); AssetSwap zeroCpnSpecializedBondAssetSwap1= new AssetSwap(payFixedRate, zeroCpnSpecializedBond1, zeroCpnSpecializedBondPrice1, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); zeroCpnSpecializedBondAssetSwap1.setPricingEngine(swapEngine); double zeroCpnBondAssetSwapPrice1 = zeroCpnBondAssetSwap1.fairCleanPrice(); double zeroCpnSpecializedBondAssetSwapPrice1 = zeroCpnSpecializedBondAssetSwap1.fairCleanPrice(); double error13 = Math.Abs(zeroCpnBondAssetSwapPrice1-zeroCpnSpecializedBondAssetSwapPrice1); if (error13>tolerance) { Assert.Fail("wrong clean price for zerocpn bond:" + "\n generic zero cpn bond's clean price: " + zeroCpnBondAssetSwapPrice1 + "\n specialized equivalent bond's price: " + zeroCpnSpecializedBondAssetSwapPrice1 + "\n error: " + error13 + "\n tolerance: " + tolerance); } // market executable price as of 4th sept 2007 double zeroCpnBondMktPrice1 = 72.277; AssetSwap zeroCpnBondASW1= new AssetSwap(payFixedRate, zeroCpnBond1,zeroCpnBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); zeroCpnBondASW1.setPricingEngine(swapEngine); AssetSwap zeroCpnSpecializedBondASW1= new AssetSwap(payFixedRate, zeroCpnSpecializedBond1, zeroCpnBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); zeroCpnSpecializedBondASW1.setPricingEngine(swapEngine); double zeroCpnBondASWSpread1 = zeroCpnBondASW1.fairSpread(); double zeroCpnSpecializedBondASWSpread1 = zeroCpnSpecializedBondASW1.fairSpread(); double error14 = Math.Abs(zeroCpnBondASWSpread1-zeroCpnSpecializedBondASWSpread1); if (error14>tolerance) { Assert.Fail("wrong asw spread for zeroCpn bond:" + "\n generic zeroCpn bond's asw spread: " + zeroCpnBondASWSpread1 + "\n equivalent specialized bond's asw spread: " + zeroCpnSpecializedBondASWSpread1 + "\n error: " + error14 + "\n tolerance: " + tolerance); } // Zero Coupon bond (Isin: IT0001200390 ISPIM 0 02/17/28) // maturity doesn't occur on a business day Date zeroCpnBondStartDate2 = new Date(17,Month.February,1998); Date zeroCpnBondMaturityDate2 = new Date(17,Month.February,2028); Date zerocpbondRedemption2 = bondCalendar.adjust(zeroCpnBondMaturityDate2, BusinessDayConvention.Following); List<CashFlow> zeroCpnBondLeg2 = new List<CashFlow>{new SimpleCashFlow(100.0, zerocpbondRedemption2)}; // generic bond Bond zeroCpnBond2 = new Bond(settlementDays, bondCalendar, vars.faceAmount, zeroCpnBondMaturityDate2, zeroCpnBondStartDate2, zeroCpnBondLeg2); zeroCpnBond2.setPricingEngine(bondEngine); // specialized zerocpn bond Bond zeroCpnSpecializedBond2 = new ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount, new Date(17,Month.February,2028), BusinessDayConvention.Following, 100.0, new Date(17,Month.February,1998)); zeroCpnSpecializedBond2.setPricingEngine(bondEngine); double zeroCpnBondPrice2 = zeroCpnBond2.cleanPrice(); double zeroCpnSpecializedBondPrice2 = zeroCpnSpecializedBond2.cleanPrice(); AssetSwap zeroCpnBondAssetSwap2= new AssetSwap(payFixedRate,zeroCpnBond2, zeroCpnBondPrice2, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); zeroCpnBondAssetSwap2.setPricingEngine(swapEngine); AssetSwap zeroCpnSpecializedBondAssetSwap2= new AssetSwap(payFixedRate, zeroCpnSpecializedBond2, zeroCpnSpecializedBondPrice2, vars.iborIndex, vars.nonnullspread, null, vars.iborIndex.dayCounter(), parAssetSwap); zeroCpnSpecializedBondAssetSwap2.setPricingEngine(swapEngine); double zeroCpnBondAssetSwapPrice2 = zeroCpnBondAssetSwap2.fairCleanPrice(); double zeroCpnSpecializedBondAssetSwapPrice2 = zeroCpnSpecializedBondAssetSwap2.fairCleanPrice(); double error15 = Math.Abs(zeroCpnBondAssetSwapPrice2 -zeroCpnSpecializedBondAssetSwapPrice2); if (error15>tolerance) { Assert.Fail("wrong clean price for zerocpn bond:" + "\n generic zero cpn bond's clean price: " + zeroCpnBondAssetSwapPrice2 + "\n equivalent specialized bond's price: " + zeroCpnSpecializedBondAssetSwapPrice2 + "\n error: " + error15 + "\n tolerance: " + tolerance); } // market executable price as of 4th sept 2007 double zeroCpnBondMktPrice2 = 72.277; AssetSwap zeroCpnBondASW2= new AssetSwap(payFixedRate, zeroCpnBond2,zeroCpnBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); zeroCpnBondASW2.setPricingEngine(swapEngine); AssetSwap zeroCpnSpecializedBondASW2= new AssetSwap(payFixedRate, zeroCpnSpecializedBond2, zeroCpnBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); zeroCpnSpecializedBondASW2.setPricingEngine(swapEngine); double zeroCpnBondASWSpread2 = zeroCpnBondASW2.fairSpread(); double zeroCpnSpecializedBondASWSpread2 = zeroCpnSpecializedBondASW2.fairSpread(); double error16 = Math.Abs(zeroCpnBondASWSpread2-zeroCpnSpecializedBondASWSpread2); if (error16>tolerance) { Assert.Fail("wrong asw spread for zeroCpn bond:" + "\n generic zeroCpn bond's asw spread: " + zeroCpnBondASWSpread2 + "\n equivalent specialized bond's asw spread: " + zeroCpnSpecializedBondASWSpread2 + "\n error: " + error16 + "\n tolerance: " + tolerance); } }
public void testZSpread() { // Testing clean and dirty price with null Z-spread against theoretical prices... CommonVars vars = new CommonVars(); Calendar bondCalendar = new TARGET(); int settlementDays = 3; int fixingDays = 2; bool inArrears = false; // Fixed bond (Isin: DE0001135275 DBR 4 01/04/37) // maturity doesn't occur on a business day Schedule fixedBondSchedule1 = new Schedule(new Date(4,Month.January,2005), new Date(4,Month.January,2037), new Period(Frequency.Annual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); Bond fixedBond1 = new FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule1, new List<double>{0.04}, new ActualActual(ActualActual.Convention.ISDA), BusinessDayConvention.Following, 100.0, new Date(4,Month.January,2005)); IPricingEngine bondEngine = new DiscountingBondEngine(vars.termStructure); fixedBond1.setPricingEngine(bondEngine); double fixedBondImpliedValue1 = fixedBond1.cleanPrice(); Date fixedBondSettlementDate1= fixedBond1.settlementDate(); // standard market conventions: // bond's frequency + coumpounding and daycounter of the YC... double fixedBondCleanPrice1 = BondFunctions.cleanPrice( fixedBond1, vars.termStructure, vars.spread, new Actual365Fixed(), vars.compounding, Frequency.Annual, fixedBondSettlementDate1); double tolerance = 1.0e-13; double error1 = Math.Abs(fixedBondImpliedValue1-fixedBondCleanPrice1); if (error1>tolerance) { Assert.Fail("wrong clean price for fixed bond:" + "\n market asset swap spread: " + fixedBondImpliedValue1 + "\n par asset swap spread: " + fixedBondCleanPrice1 + "\n error: " + error1 + "\n tolerance: " + tolerance); } // Fixed bond (Isin: IT0006527060 IBRD 5 02/05/19) // maturity occurs on a business day Schedule fixedBondSchedule2 = new Schedule(new Date(5,Month.February,2005), new Date(5,Month.February,2019), new Period(Frequency.Annual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); Bond fixedBond2 = new FixedRateBond(settlementDays, vars.faceAmount, fixedBondSchedule2, new List<double>{0.05}, new Thirty360(Thirty360.Thirty360Convention.BondBasis), BusinessDayConvention.Following, 100.0, new Date(5,Month.February,2005)); fixedBond2.setPricingEngine(bondEngine); double fixedBondImpliedValue2 = fixedBond2.cleanPrice(); Date fixedBondSettlementDate2= fixedBond2.settlementDate(); // standard market conventions: // bond's frequency + coumpounding and daycounter of the YieldCurve double fixedBondCleanPrice2 = BondFunctions.cleanPrice(fixedBond2, vars.termStructure, vars.spread, new Actual365Fixed(), vars.compounding, Frequency.Annual, fixedBondSettlementDate2); double error3 = Math.Abs(fixedBondImpliedValue2-fixedBondCleanPrice2); if (error3>tolerance) { Assert.Fail("wrong clean price for fixed bond:" + "\n market asset swap spread: " + fixedBondImpliedValue2 + "\n par asset swap spread: " + fixedBondCleanPrice2 + "\n error: " + error3 + "\n tolerance: " + tolerance); } // FRN bond (Isin: IT0003543847 ISPIM 0 09/29/13) // maturity doesn't occur on a business day Schedule floatingBondSchedule1 = new Schedule(new Date(29,Month.September,2003), new Date(29,Month.September,2013), new Period(Frequency.Semiannual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); Bond floatingBond1 = new FloatingRateBond(settlementDays, vars.faceAmount, floatingBondSchedule1, vars.iborIndex, new Actual360(), BusinessDayConvention.Following, fixingDays, new List<double>{1}, new List<double>{0.0056}, new List<double>(), new List<double>(), inArrears, 100.0, new Date(29,Month.September,2003)); floatingBond1.setPricingEngine(bondEngine); Utils.setCouponPricer(floatingBond1.cashflows(), vars.pricer); vars.iborIndex.addFixing(new Date(27,Month.March,2007), 0.0402); double floatingBondImpliedValue1 = floatingBond1.cleanPrice(); // standard market conventions: // bond's frequency + coumpounding and daycounter of the YieldCurve double floatingBondCleanPrice1 = BondFunctions.cleanPrice(floatingBond1, vars.termStructure, vars.spread, new Actual365Fixed(), vars.compounding, Frequency.Semiannual, fixedBondSettlementDate1); double error5 = Math.Abs(floatingBondImpliedValue1-floatingBondCleanPrice1); if (error5>tolerance) { Assert.Fail("wrong clean price for fixed bond:" + "\n market asset swap spread: " + floatingBondImpliedValue1 + "\n par asset swap spread: " + floatingBondCleanPrice1 + "\n error: " + error5 + "\n tolerance: " + tolerance); } // FRN bond (Isin: XS0090566539 COE 0 09/24/18) // maturity occurs on a business day Schedule floatingBondSchedule2 = new Schedule(new Date(24,Month.September,2004), new Date(24,Month.September,2018), new Period(Frequency.Semiannual), bondCalendar, BusinessDayConvention.ModifiedFollowing, BusinessDayConvention.ModifiedFollowing, DateGeneration.Rule.Backward, false); Bond floatingBond2 = new FloatingRateBond(settlementDays, vars.faceAmount, floatingBondSchedule2, vars.iborIndex, new Actual360(), BusinessDayConvention.ModifiedFollowing, fixingDays, new List<double>{1}, new List<double>{0.0025}, new List<double>(), new List<double>(), inArrears, 100.0, new Date(24,Month.September,2004)); floatingBond2.setPricingEngine(bondEngine); Utils.setCouponPricer(floatingBond2.cashflows(), vars.pricer); vars.iborIndex.addFixing(new Date(22,Month.March,2007), 0.04013); double floatingBondImpliedValue2 = floatingBond2.cleanPrice(); // standard market conventions: // bond's frequency + coumpounding and daycounter of the YieldCurve double floatingBondCleanPrice2 = BondFunctions.cleanPrice(floatingBond2, vars.termStructure, vars.spread, new Actual365Fixed(), vars.compounding, Frequency.Semiannual, fixedBondSettlementDate1); double error7 = Math.Abs(floatingBondImpliedValue2-floatingBondCleanPrice2); if (error7>tolerance) { Assert.Fail("wrong clean price for fixed bond:" + "\n market asset swap spread: " + floatingBondImpliedValue2 + "\n par asset swap spread: " + floatingBondCleanPrice2 + "\n error: " + error7 + "\n tolerance: " + tolerance); } //// CMS bond (Isin: XS0228052402 CRDIT 0 8/22/20) //// maturity doesn't occur on a business day Schedule cmsBondSchedule1 = new Schedule(new Date(22,Month.August,2005), new Date(22,Month.August,2020), new Period(Frequency.Annual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); Bond cmsBond1 = new CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule1, vars.swapIndex, new Thirty360(), BusinessDayConvention.Following, fixingDays, new List<double>{1.0}, new List<double>{0.0}, new List<double>{0.055}, new List<double>{0.025}, inArrears, 100.0, new Date(22,Month.August,2005)); cmsBond1.setPricingEngine(bondEngine); Utils.setCouponPricer(cmsBond1.cashflows(), vars.cmspricer); vars.swapIndex.addFixing(new Date(18,Month.August,2006), 0.04158); double cmsBondImpliedValue1 = cmsBond1.cleanPrice(); Date cmsBondSettlementDate1= cmsBond1.settlementDate(); // standard market conventions: // bond's frequency + coumpounding and daycounter of the YieldCurve double cmsBondCleanPrice1 = BondFunctions.cleanPrice(cmsBond1, vars.termStructure, vars.spread, new Actual365Fixed(), vars.compounding, Frequency.Annual, cmsBondSettlementDate1); double error9 = Math.Abs(cmsBondImpliedValue1-cmsBondCleanPrice1); if (error9>tolerance) { Assert.Fail("wrong clean price for fixed bond:" + "\n market asset swap spread: " + cmsBondImpliedValue1 + "\n par asset swap spread: " + cmsBondCleanPrice1 + "\n error: " + error9 + "\n tolerance: " + tolerance); } // CMS bond (Isin: XS0218766664 ISPIM 0 5/6/15) // maturity occurs on a business day Schedule cmsBondSchedule2 = new Schedule(new Date(06,Month.May,2005), new Date(06,Month.May,2015), new Period(Frequency.Annual), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); Bond cmsBond2 = new CmsRateBond(settlementDays, vars.faceAmount, cmsBondSchedule2, vars.swapIndex, new Thirty360(), BusinessDayConvention.Following, fixingDays, new List<double>{0.84}, new List<double>{0.0}, new List<double>(), new List<double>(), inArrears, 100.0, new Date(06,Month.May,2005)); cmsBond2.setPricingEngine(bondEngine); Utils.setCouponPricer(cmsBond2.cashflows(), vars.cmspricer); vars.swapIndex.addFixing(new Date(04,Month.May,2006), 0.04217); double cmsBondImpliedValue2 = cmsBond2.cleanPrice(); Date cmsBondSettlementDate2= cmsBond2.settlementDate(); // standard market conventions: // bond's frequency + coumpounding and daycounter of the YieldCurve double cmsBondCleanPrice2 = BondFunctions.cleanPrice(cmsBond2, vars.termStructure, vars.spread, new Actual365Fixed(), vars.compounding, Frequency.Annual, cmsBondSettlementDate2); double error11 = Math.Abs(cmsBondImpliedValue2-cmsBondCleanPrice2); if (error11>tolerance) { Assert.Fail("wrong clean price for fixed bond:" + "\n market asset swap spread: " + cmsBondImpliedValue2 + "\n par asset swap spread: " + cmsBondCleanPrice2 + "\n error: " + error11 + "\n tolerance: " + tolerance); } // Zero-Coupon bond (Isin: DE0004771662 IBRD 0 12/20/15) // maturity doesn't occur on a business day Bond zeroCpnBond1 = new ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount, new Date(20,Month.December,2015), BusinessDayConvention.Following, 100.0, new Date(19,Month.December,1985)); zeroCpnBond1.setPricingEngine(bondEngine); double zeroCpnBondImpliedValue1 = zeroCpnBond1.cleanPrice(); Date zeroCpnBondSettlementDate1= zeroCpnBond1.settlementDate(); // standard market conventions: // bond's frequency + coumpounding and daycounter of the YieldCurve double zeroCpnBondCleanPrice1 = BondFunctions.cleanPrice(zeroCpnBond1,vars.termStructure, vars.spread, new Actual365Fixed(), vars.compounding, Frequency.Annual, zeroCpnBondSettlementDate1); double error13 = Math.Abs(zeroCpnBondImpliedValue1-zeroCpnBondCleanPrice1); if (error13>tolerance) { Assert.Fail("wrong clean price for zero coupon bond:" + "\n zero cpn implied value: " + zeroCpnBondImpliedValue1 + "\n zero cpn price: " + zeroCpnBondCleanPrice1 + "\n error: " + error13 + "\n tolerance: " + tolerance); } // Zero Coupon bond (Isin: IT0001200390 ISPIM 0 02/17/28) // maturity doesn't occur on a business day Bond zeroCpnBond2 = new ZeroCouponBond(settlementDays, bondCalendar, vars.faceAmount, new Date(17,Month.February,2028), BusinessDayConvention.Following, 100.0, new Date(17,Month.February,1998)); zeroCpnBond2.setPricingEngine(bondEngine); double zeroCpnBondImpliedValue2 = zeroCpnBond2.cleanPrice(); Date zeroCpnBondSettlementDate2= zeroCpnBond2.settlementDate(); // standard market conventions: // bond's frequency + coumpounding and daycounter of the YieldCurve double zeroCpnBondCleanPrice2 = BondFunctions.cleanPrice(zeroCpnBond2,vars.termStructure, vars.spread, new Actual365Fixed(), vars.compounding, Frequency.Annual, zeroCpnBondSettlementDate2); double error15 = Math.Abs(zeroCpnBondImpliedValue2-zeroCpnBondCleanPrice2); if (error15>tolerance) { Assert.Fail("wrong clean price for zero coupon bond:" + "\n zero cpn implied value: " + zeroCpnBondImpliedValue2 + "\n zero cpn price: " + zeroCpnBondCleanPrice2 + "\n error: " + error15 + "\n tolerance: " + tolerance); } }
public void testCachedFloating() { // "Testing floating-rate bond prices against cached values..."); CommonVars vars = new CommonVars(); Date today = new Date(22, Month.November, 2004); Settings.setEvaluationDate(today); int settlementDays = 1; var riskFreeRate = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.025, new Actual360())); var 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<OptionletVolatilityStructure>()); // 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, vars.faceAmount, sch, index, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, fixingDays, new List<double>(), new List<double>(), new List<double>(), new List<double>(), false, 100.0, new Date(30, Month.November, 2004)); IPricingEngine bondEngine = new DiscountingBondEngine(riskFreeRate); bond1.setPricingEngine(bondEngine); Utils.setCouponPricer(bond1.cashflows(), pricer); #if QL_USE_INDEXED_COUPON double cachedPrice1 = 99.874645; #else double cachedPrice1 = 99.874646; #endif double price = bond1.cleanPrice(); if (Math.Abs(price - cachedPrice1) > tolerance) { Assert.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, vars.faceAmount, sch, index, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, fixingDays, new List<double>(), new List<double>(), new List<double>(), new List<double>(), false, 100.0, new Date(30, Month.November, 2004)); IPricingEngine bondEngine2 = new DiscountingBondEngine(discountCurve); bond2.setPricingEngine(bondEngine2); Utils.setCouponPricer(bond2.cashflows(), pricer); #if QL_USE_INDEXED_COUPON double cachedPrice2 = 97.955904; #else double cachedPrice2 = 97.955904; #endif price = bond2.cleanPrice(); if (Math.Abs(price - cachedPrice2) > tolerance) { Assert.Fail("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice2 + "\n" + " error: " + (price - cachedPrice2)); } // varying spread InitializedList<double> spreads = new InitializedList<double>(4); spreads[0] = 0.001; spreads[1] = 0.0012; spreads[2] = 0.0014; spreads[3] = 0.0016; FloatingRateBond bond3 = new FloatingRateBond(settlementDays, vars.faceAmount, sch, index, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, fixingDays, new List<double>(), spreads, new List<double>(), new List<double>(), false, 100.0, new Date(30, Month.November, 2004)); bond3.setPricingEngine(bondEngine2); Utils.setCouponPricer(bond3.cashflows(), pricer); #if QL_USE_INDEXED_COUPON double cachedPrice3 = 98.495458; #else double cachedPrice3 = 98.495459; #endif price = bond3.cleanPrice(); if (Math.Abs(price - cachedPrice3) > tolerance) { Assert.Fail("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice3 + "\n" + " error: " + (price - cachedPrice3)); } }