public void testMarketASWSpread() { // Testing relationship between market asset swap and par asset swap... CommonVars vars = new CommonVars(); Calendar bondCalendar = new TARGET(); int settlementDays = 3; int fixingDays = 2; bool payFixedRate = true; bool parAssetSwap = true; bool mktAssetSwap = false; 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 fixedBondMktPrice1 = 89.22 ; // market price observed on 7th June 2007 double fixedBondMktFullPrice1=fixedBondMktPrice1+fixedBond1.accruedAmount(); AssetSwap fixedBondParAssetSwap1 = new AssetSwap(payFixedRate, fixedBond1, fixedBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); fixedBondParAssetSwap1.setPricingEngine(swapEngine); double fixedBondParAssetSwapSpread1 = fixedBondParAssetSwap1.fairSpread(); AssetSwap fixedBondMktAssetSwap1 = new AssetSwap(payFixedRate, fixedBond1, fixedBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), mktAssetSwap); fixedBondMktAssetSwap1.setPricingEngine(swapEngine); double fixedBondMktAssetSwapSpread1 = fixedBondMktAssetSwap1.fairSpread(); double tolerance = 1.0e-13; double error1 = Math.Abs(fixedBondMktAssetSwapSpread1- 100*fixedBondParAssetSwapSpread1/fixedBondMktFullPrice1); if (error1>tolerance) { Assert.Fail("wrong asset swap spreads for fixed bond:" + "\n market ASW spread: " + fixedBondMktAssetSwapSpread1 + "\n par ASW spread: " + fixedBondParAssetSwapSpread1 + "\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 fixedBondMktPrice2 = 99.98 ; // market price observed on 7th June 2007 double fixedBondMktFullPrice2=fixedBondMktPrice2+fixedBond2.accruedAmount(); AssetSwap fixedBondParAssetSwap2 = new AssetSwap(payFixedRate, fixedBond2, fixedBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); fixedBondParAssetSwap2.setPricingEngine(swapEngine); double fixedBondParAssetSwapSpread2 = fixedBondParAssetSwap2.fairSpread(); AssetSwap fixedBondMktAssetSwap2 = new AssetSwap(payFixedRate, fixedBond2, fixedBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), mktAssetSwap); fixedBondMktAssetSwap2.setPricingEngine(swapEngine); double fixedBondMktAssetSwapSpread2 = fixedBondMktAssetSwap2.fairSpread(); double error2 = Math.Abs(fixedBondMktAssetSwapSpread2- 100*fixedBondParAssetSwapSpread2/fixedBondMktFullPrice2); if (error2>tolerance) { Assert.Fail("wrong asset swap spreads for fixed bond:" + "\n market ASW spread: " + fixedBondMktAssetSwapSpread2 + "\n par ASW spread: " + fixedBondParAssetSwapSpread2 + "\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); // market price observed on 7th June 2007 double floatingBondMktPrice1 = 101.64 ; double floatingBondMktFullPrice1 = floatingBondMktPrice1+floatingBond1.accruedAmount(); AssetSwap floatingBondParAssetSwap1 = new AssetSwap(payFixedRate, floatingBond1, floatingBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); floatingBondParAssetSwap1.setPricingEngine(swapEngine); double floatingBondParAssetSwapSpread1 = floatingBondParAssetSwap1.fairSpread(); AssetSwap floatingBondMktAssetSwap1= new AssetSwap(payFixedRate, floatingBond1, floatingBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), mktAssetSwap); floatingBondMktAssetSwap1.setPricingEngine(swapEngine); double floatingBondMktAssetSwapSpread1 = floatingBondMktAssetSwap1.fairSpread(); double error3 = Math.Abs(floatingBondMktAssetSwapSpread1- 100*floatingBondParAssetSwapSpread1/floatingBondMktFullPrice1); if (error3>tolerance) { Assert.Fail("wrong asset swap spreads for floating bond:" + "\n market ASW spread: " + floatingBondMktAssetSwapSpread1 + "\n par ASW spread: " + floatingBondParAssetSwapSpread1 + "\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); // market price observed on 7th June 2007 double floatingBondMktPrice2 = 101.248 ; double floatingBondMktFullPrice2 = floatingBondMktPrice2+floatingBond2.accruedAmount(); AssetSwap floatingBondParAssetSwap2= new AssetSwap(payFixedRate, floatingBond2, floatingBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); floatingBondParAssetSwap2.setPricingEngine(swapEngine); double floatingBondParAssetSwapSpread2 = floatingBondParAssetSwap2.fairSpread(); AssetSwap floatingBondMktAssetSwap2 = new AssetSwap(payFixedRate, floatingBond2, floatingBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), mktAssetSwap); floatingBondMktAssetSwap2.setPricingEngine(swapEngine); double floatingBondMktAssetSwapSpread2 = floatingBondMktAssetSwap2.fairSpread(); double error4 = Math.Abs(floatingBondMktAssetSwapSpread2- 100*floatingBondParAssetSwapSpread2/floatingBondMktFullPrice2); if (error4>tolerance) { Assert.Fail("wrong asset swap spreads for floating bond:" + "\n market ASW spread: " + floatingBondMktAssetSwapSpread2 + "\n par ASW spread: " + floatingBondParAssetSwapSpread2 + "\n error: " + error4 + "\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 cmsBondMktPrice1 = 88.45 ; // market price observed on 7th June 2007 double cmsBondMktFullPrice1 = cmsBondMktPrice1+cmsBond1.accruedAmount(); AssetSwap cmsBondParAssetSwap1 = new AssetSwap(payFixedRate, cmsBond1, cmsBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); cmsBondParAssetSwap1.setPricingEngine(swapEngine); double cmsBondParAssetSwapSpread1 = cmsBondParAssetSwap1.fairSpread(); AssetSwap cmsBondMktAssetSwap1 = new AssetSwap(payFixedRate, cmsBond1, cmsBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), mktAssetSwap); cmsBondMktAssetSwap1.setPricingEngine(swapEngine); double cmsBondMktAssetSwapSpread1 = cmsBondMktAssetSwap1.fairSpread(); double error5 = Math.Abs(cmsBondMktAssetSwapSpread1- 100*cmsBondParAssetSwapSpread1/cmsBondMktFullPrice1); if (error5>tolerance) { Assert.Fail("wrong asset swap spreads for cms bond:" + "\n market ASW spread: " + cmsBondMktAssetSwapSpread1 + "\n par ASW spread: " + cmsBondParAssetSwapSpread1 + "\n error: " + error5 + "\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 cmsBondMktPrice2 = 94.08 ; // market price observed on 7th June 2007 double cmsBondMktFullPrice2 = cmsBondMktPrice2+cmsBond2.accruedAmount(); AssetSwap cmsBondParAssetSwap2 = new AssetSwap(payFixedRate, cmsBond2, cmsBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); cmsBondParAssetSwap2.setPricingEngine(swapEngine); double cmsBondParAssetSwapSpread2 = cmsBondParAssetSwap2.fairSpread(); AssetSwap cmsBondMktAssetSwap2 = new AssetSwap(payFixedRate, cmsBond2, cmsBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), mktAssetSwap); cmsBondMktAssetSwap2.setPricingEngine(swapEngine); double cmsBondMktAssetSwapSpread2 = cmsBondMktAssetSwap2.fairSpread(); double error6 = Math.Abs(cmsBondMktAssetSwapSpread2- 100*cmsBondParAssetSwapSpread2/cmsBondMktFullPrice2); if (error6>tolerance) { Assert.Fail("wrong asset swap spreads for cms bond:" + "\n market ASW spread: " + cmsBondMktAssetSwapSpread2 + "\n par ASW spread: " + cmsBondParAssetSwapSpread2 + "\n error: " + error6 + "\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); // market price observed on 12th June 2007 double zeroCpnBondMktPrice1 = 70.436 ; double zeroCpnBondMktFullPrice1 = zeroCpnBondMktPrice1+zeroCpnBond1.accruedAmount(); AssetSwap zeroCpnBondParAssetSwap1 = new AssetSwap(payFixedRate,zeroCpnBond1, zeroCpnBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); zeroCpnBondParAssetSwap1.setPricingEngine(swapEngine); double zeroCpnBondParAssetSwapSpread1 = zeroCpnBondParAssetSwap1.fairSpread(); AssetSwap zeroCpnBondMktAssetSwap1 = new AssetSwap(payFixedRate,zeroCpnBond1, zeroCpnBondMktPrice1, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), mktAssetSwap); zeroCpnBondMktAssetSwap1.setPricingEngine(swapEngine); double zeroCpnBondMktAssetSwapSpread1 = zeroCpnBondMktAssetSwap1.fairSpread(); double error7 = Math.Abs(zeroCpnBondMktAssetSwapSpread1- 100*zeroCpnBondParAssetSwapSpread1/zeroCpnBondMktFullPrice1); if (error7>tolerance) { Assert.Fail("wrong asset swap spreads for zero cpn bond:" + "\n market ASW spread: " + zeroCpnBondMktAssetSwapSpread1 + "\n par ASW spread: " + zeroCpnBondParAssetSwapSpread1 + "\n error: " + error7 + "\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); // Real zeroCpnBondPrice2 = zeroCpnBond2->cleanPrice(); // market price observed on 12th June 2007 double zeroCpnBondMktPrice2 = 35.160 ; double zeroCpnBondMktFullPrice2 = zeroCpnBondMktPrice2+zeroCpnBond2.accruedAmount(); AssetSwap zeroCpnBondParAssetSwap2 = new AssetSwap(payFixedRate,zeroCpnBond2, zeroCpnBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), parAssetSwap); zeroCpnBondParAssetSwap2.setPricingEngine(swapEngine); double zeroCpnBondParAssetSwapSpread2 = zeroCpnBondParAssetSwap2.fairSpread(); AssetSwap zeroCpnBondMktAssetSwap2 = new AssetSwap(payFixedRate,zeroCpnBond2, zeroCpnBondMktPrice2, vars.iborIndex, vars.spread, null, vars.iborIndex.dayCounter(), mktAssetSwap); zeroCpnBondMktAssetSwap2.setPricingEngine(swapEngine); double zeroCpnBondMktAssetSwapSpread2 = zeroCpnBondMktAssetSwap2.fairSpread(); double error8 = Math.Abs(zeroCpnBondMktAssetSwapSpread2- 100*zeroCpnBondParAssetSwapSpread2/zeroCpnBondMktFullPrice2); if (error8>tolerance) { Assert.Fail("wrong asset swap spreads for zero cpn bond:" + "\n market ASW spread: " + zeroCpnBondMktAssetSwapSpread2 + "\n par ASW spread: " + zeroCpnBondParAssetSwapSpread2 + "\n error: " + error8 + "\n tolerance: " + tolerance); } }
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 testSpecializedBondVsGenericBond() { // Testing clean and dirty prices for specialized bond against equivalent generic bond... CommonVars vars = new CommonVars(); Calendar bondCalendar = new TARGET(); int settlementDays = 3; int fixingDays = 2; bool inArrears = false; // Fixed Underlying 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); 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 fixedBondTheoValue1 = fixedBond1.cleanPrice(); double fixedSpecializedBondTheoValue1 = fixedSpecializedBond1.cleanPrice(); double tolerance = 1.0e-13; double error1 = Math.Abs(fixedBondTheoValue1-fixedSpecializedBondTheoValue1); if (error1>tolerance) { Assert.Fail("wrong clean price for fixed bond:" + "\n specialized fixed rate bond's theo clean price: " + fixedBondTheoValue1 + "\n generic equivalent bond's theo clean price: " + fixedSpecializedBondTheoValue1 + "\n error: " + error1 + "\n tolerance: " + tolerance); } double fixedBondTheoDirty1 = fixedBondTheoValue1+fixedBond1.accruedAmount(); double fixedSpecializedTheoDirty1 = fixedSpecializedBondTheoValue1+ fixedSpecializedBond1.accruedAmount(); double error2 = Math.Abs(fixedBondTheoDirty1-fixedSpecializedTheoDirty1); if (error2>tolerance) { Assert.Fail("wrong dirty price for fixed bond:" + "\n specialized fixed rate bond's theo dirty price: " + fixedBondTheoDirty1 + "\n generic equivalent bond's theo dirty price: " + fixedSpecializedTheoDirty1 + "\n error: " + error2 + "\n tolerance: " + tolerance); } // Fixed Underlying 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 fixedBondTheoValue2 = fixedBond2.cleanPrice(); double fixedSpecializedBondTheoValue2 = fixedSpecializedBond2.cleanPrice(); double error3 = Math.Abs(fixedBondTheoValue2-fixedSpecializedBondTheoValue2); if (error3>tolerance) { Assert.Fail("wrong clean price for fixed bond:" + "\n specialized fixed rate bond's theo clean price: " + fixedBondTheoValue2 + "\n generic equivalent bond's theo clean price: " + fixedSpecializedBondTheoValue2 + "\n error: " + error3 + "\n tolerance: " + tolerance); } double fixedBondTheoDirty2 = fixedBondTheoValue2+ fixedBond2.accruedAmount(); double fixedSpecializedBondTheoDirty2 = fixedSpecializedBondTheoValue2+ fixedSpecializedBond2.accruedAmount(); double error4 = Math.Abs(fixedBondTheoDirty2-fixedSpecializedBondTheoDirty2); if (error4>tolerance) { Assert.Fail("wrong dirty price for fixed bond:" + "\n specialized fixed rate bond's dirty clean price: " + fixedBondTheoDirty2 + "\n generic equivalent bond's theo dirty price: " + fixedSpecializedBondTheoDirty2 + "\n error: " + error4 + "\n tolerance: " + tolerance); } // FRN Underlying 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 floatingBondTheoValue1 = floatingBond1.cleanPrice(); double floatingSpecializedBondTheoValue1 = floatingSpecializedBond1.cleanPrice(); double error5 = Math.Abs(floatingBondTheoValue1- floatingSpecializedBondTheoValue1); if (error5>tolerance) { Assert.Fail("wrong clean price for fixed bond:" + "\n generic fixed rate bond's theo clean price: " + floatingBondTheoValue1 + "\n equivalent specialized bond's theo clean price: " + floatingSpecializedBondTheoValue1 + "\n error: " + error5 + "\n tolerance: " + tolerance); } double floatingBondTheoDirty1 = floatingBondTheoValue1+ floatingBond1.accruedAmount(); double floatingSpecializedBondTheoDirty1 = floatingSpecializedBondTheoValue1+ floatingSpecializedBond1.accruedAmount(); double error6 = Math.Abs(floatingBondTheoDirty1- floatingSpecializedBondTheoDirty1); if (error6>tolerance) { Assert.Fail("wrong dirty price for frn bond:" + "\n generic frn bond's dirty clean price: " + floatingBondTheoDirty1 + "\n equivalent specialized bond's theo dirty price: " + floatingSpecializedBondTheoDirty1 + "\n error: " + error6 + "\n tolerance: " + tolerance); } // FRN Underlying 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 floatingBondTheoValue2 = floatingBond2.cleanPrice(); double floatingSpecializedBondTheoValue2 = floatingSpecializedBond2.cleanPrice(); double error7 = Math.Abs(floatingBondTheoValue2-floatingSpecializedBondTheoValue2); if (error7>tolerance) { Assert.Fail("wrong clean price for floater bond:" + "\n generic floater bond's theo clean price: " + floatingBondTheoValue2 + "\n equivalent specialized bond's theo clean price: " + floatingSpecializedBondTheoValue2 + "\n error: " + error7 + "\n tolerance: " + tolerance); } double floatingBondTheoDirty2 = floatingBondTheoValue2+ floatingBond2.accruedAmount(); double floatingSpecializedTheoDirty2 = floatingSpecializedBondTheoValue2+ floatingSpecializedBond2.accruedAmount(); double error8 = Math.Abs(floatingBondTheoDirty2-floatingSpecializedTheoDirty2); if (error8>tolerance) { Assert.Fail("wrong dirty price for floater bond:" + "\n generic floater bond's theo dirty price: " + floatingBondTheoDirty2 + "\n equivalent specialized bond's theo dirty price: " + floatingSpecializedTheoDirty2 + "\n error: " + error8 + "\n tolerance: " + tolerance); } // CMS Underlying 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 cmsBondTheoValue1 = cmsBond1.cleanPrice(); double cmsSpecializedBondTheoValue1 = cmsSpecializedBond1.cleanPrice(); double error9 = Math.Abs(cmsBondTheoValue1-cmsSpecializedBondTheoValue1); if (error9>tolerance) { Assert.Fail("wrong clean price for cms bond:" + "\n generic cms bond's theo clean price: " + cmsBondTheoValue1 + "\n equivalent specialized bond's theo clean price: " + cmsSpecializedBondTheoValue1 + "\n error: " + error9 + "\n tolerance: " + tolerance); } double cmsBondTheoDirty1 = cmsBondTheoValue1+cmsBond1.accruedAmount(); double cmsSpecializedBondTheoDirty1 = cmsSpecializedBondTheoValue1+ cmsSpecializedBond1.accruedAmount(); double error10 = Math.Abs(cmsBondTheoDirty1-cmsSpecializedBondTheoDirty1); if (error10>tolerance) { Assert.Fail("wrong dirty price for cms bond:" + "\n generic cms bond's theo dirty price: " + cmsBondTheoDirty1 + "\n specialized cms bond's theo dirty price: " + cmsSpecializedBondTheoDirty1 + "\n error: " + error10 + "\n tolerance: " + tolerance); } // CMS Underlying 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 cmsBondTheoValue2 = cmsBond2.cleanPrice(); double cmsSpecializedBondTheoValue2 = cmsSpecializedBond2.cleanPrice(); double error11 = Math.Abs(cmsBondTheoValue2-cmsSpecializedBondTheoValue2); if (error11>tolerance) { Assert.Fail("wrong clean price for cms bond:" + "\n generic cms bond's theo clean price: " + cmsBondTheoValue2 + "\n cms bond's theo clean price: " + cmsSpecializedBondTheoValue2 + "\n error: " + error11 + "\n tolerance: " + tolerance); } double cmsBondTheoDirty2 = cmsBondTheoValue2+cmsBond2.accruedAmount(); double cmsSpecializedBondTheoDirty2 = cmsSpecializedBondTheoValue2+cmsSpecializedBond2.accruedAmount(); double error12 = Math.Abs(cmsBondTheoDirty2-cmsSpecializedBondTheoDirty2); if (error12>tolerance) { Assert.Fail("wrong dirty price for cms bond:" + "\n generic cms bond's dirty price: " + cmsBondTheoDirty2 + "\n specialized cms bond's theo dirty price: " + cmsSpecializedBondTheoDirty2 + "\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 zeroCpnBondTheoValue1 = zeroCpnBond1.cleanPrice(); double zeroCpnSpecializedBondTheoValue1 = zeroCpnSpecializedBond1.cleanPrice(); double error13 = Math.Abs(zeroCpnBondTheoValue1-zeroCpnSpecializedBondTheoValue1); if (error13>tolerance) { Assert.Fail("wrong clean price for zero coupon bond:" + "\n generic zero bond's clean price: " + zeroCpnBondTheoValue1 + "\n specialized zero bond's clean price: " + zeroCpnSpecializedBondTheoValue1 + "\n error: " + error13 + "\n tolerance: " + tolerance); } double zeroCpnBondTheoDirty1 = zeroCpnBondTheoValue1+ zeroCpnBond1.accruedAmount(); double zeroCpnSpecializedBondTheoDirty1 = zeroCpnSpecializedBondTheoValue1+ zeroCpnSpecializedBond1.accruedAmount(); double error14 = Math.Abs(zeroCpnBondTheoDirty1-zeroCpnSpecializedBondTheoDirty1); if (error14>tolerance) { Assert.Fail("wrong dirty price for zero bond:" + "\n generic zerocpn bond's dirty price: " + zeroCpnBondTheoDirty1 + "\n specialized zerocpn bond's clean price: " + zeroCpnSpecializedBondTheoDirty1 + "\n error: " + error14 + "\n tolerance: " + tolerance); } // Zero Coupon bond (Isin: IT0001200390 ISPIM 0 02/17/28) // maturity occurs 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 zeroCpnBondTheoValue2 = zeroCpnBond2.cleanPrice(); double zeroCpnSpecializedBondTheoValue2 = zeroCpnSpecializedBond2.cleanPrice(); double error15 = Math.Abs(zeroCpnBondTheoValue2 -zeroCpnSpecializedBondTheoValue2); if (error15>tolerance) { Assert.Fail("wrong clean price for zero coupon bond:" + "\n generic zerocpn bond's clean price: " + zeroCpnBondTheoValue2 + "\n specialized zerocpn bond's clean price: " + zeroCpnSpecializedBondTheoValue2 + "\n error: " + error15 + "\n tolerance: " + tolerance); } double zeroCpnBondTheoDirty2 = zeroCpnBondTheoValue2+ zeroCpnBond2.accruedAmount(); double zeroCpnSpecializedBondTheoDirty2 = zeroCpnSpecializedBondTheoValue2+ zeroCpnSpecializedBond2.accruedAmount(); double error16 = Math.Abs(zeroCpnBondTheoDirty2-zeroCpnSpecializedBondTheoDirty2); if (error16>tolerance) { Assert.Fail("wrong dirty price for zero coupon bond:" + "\n generic zerocpn bond's dirty price: " + zeroCpnBondTheoDirty2 + "\n specialized zerocpn bond's dirty price: " + zeroCpnSpecializedBondTheoDirty2 + "\n error: " + error16 + "\n tolerance: " + tolerance); } }